What Makes This One Serious
A lot of router CVEs get filed as weakly worded information disclosure issues and then forgotten. This one is different because the exposed data was not passive telemetry. The affected wizard handlers surfaced identity and access material that had downstream security meaning in ISP-operated environments. The PPPoE identifier was not just an account detail. In the deployment model I documented during disclosure, it could function as the hidden administrator password.
The result is a layered failure: route misclassification in firmware, secret exposure through setup handlers, and an operational credential scheme that turned leaked subscriber data into privileged access.
Exploit Path
My disclosure focused on two wizard handlers: wizard_pppoe_lua.lua and wizard_wlan_config_lua.lua. One returns PPPoE-related information. The other exposes wireless configuration and also accepts a password retrieval action by POST. That matters because these are not cosmetic onboarding pages. They behave like privileged backend endpoints routed through a weak setup surface.
GET /wizard_page/wizard_pppoe_lua.lua
GET /wizard_page/wizard_wlan_config_lua.lua
POST /wizard_page/wizard_wlan_config_lua.lua
IF_ACTION=GetPassword
&_InstID_PASS=DEV.WIFI.AP1.PSK1
&PASSTYPE=PSK
POST /wizard_page/wizard_wlan_config_lua.lua HTTP/1.1
Host: router-ip
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
X-Requested-With: XMLHttpRequest
IF_ACTION=GetPassword&_InstID_PASS=DEV.WIFI.AP1.PSK1&PASSTYPE=PSK
HTTP/1.1 200 OK
Content-Type: application/xml
<ajax_response>
<IF_ERRORSTR>SUCC</IF_ERRORSTR>
<ParaName>KeyPassphrase</ParaName>
<ParaValue>[REDACTED-WIFI-PASSWORD]</ParaValue>
</ajax_response>
The same pattern applies to the PPPoE and WLAN information handlers: unauthenticated requests return structured XML containing values that should have remained behind an authenticated configuration boundary. The examples above are intentionally redacted, but they reflect the response shape I documented during disclosure and used in the extraction scripts.
The accompanying repository includes a bulk PoC script, zte_zxhn_h168n_bulk_poc.py, which reads a host list and checks the exposed wizard endpoints for the PPPoE, SSID, and Wi-Fi passphrase fields shown here.
I also documented a browser-delivered chain in which a victim is lured through a rogue access point or captive portal flow, then returned to router context where attacker-controlled code queries the exposed handler and exfiltrates the Wi-Fi passphrase. Even if that specific chain is deployment-dependent, the root issue is stable: secret-bearing routes were reachable through a setup whitelist that should never have governed them.
Root Cause Analysis
Firmware files show a helper named pro_urlsafe_IsWhiteList(pageName), a lookup against OBJ_WEB_QUICKSETUP_ID, and a branch on QuickSetupEnable that appears to whitelist wizard_pppoe_lua.lua and wizard_wlan_config_lua.lua.
WizardTable = cmapi.getinst("OBJ_WEB_QUICKSETUP_ID", "")
WizardFlag = WizardTable.QuickSetupEnable
if WizardFlag == "0" then
whitelist["wizardFrame_finishAction.lua"] = 1
whitelist["wizard_pppoe_lua.lua"] = 1
whitelist["wizard_wlan_config_lua.lua"] = 1
end
Filename routing was used as an authorization primitive.
The visible logic suggests access is granted because a page name appears in a whitelist, not because the handler is authorized to disclose its data. That is the first architectural mistake. A route category is not a permission model.
Setup UI and privileged data handlers were treated as the same class of object.
The whitelisted items are not harmless onboarding fragments. They resolve live configuration state, and one explicitly supports a password-returning action. The firmware collapses presentation logic and secret retrieval into the same accessibility bucket.
Global setup state replaced per-request privilege checks.
A single flag such as QuickSetupEnable is far too coarse to control access to configuration secrets. Once the device interprets itself as being in a setup-permitted state, every route attached to that state inherits reachability, regardless of sensitivity.
The endpoint appears not to enforce an internal second gate.
The POST password retrieval path is decisive here. Even if setup pages are temporarily reachable, a secret-bearing action should still validate session state or capability at handler level. The observed behavior indicates excessive trust in route-level allowlisting.
The exploit chain becomes critical because the leaked data is security-significant.
Reusing PPPoE usernames as admin passwords is an ISP-side practice, but the firmware made that practice exploitable by leaking the identifier through a route that should never have exposed it. The router converted an already-fragile secret into a harvestable one.
Visual Proof
The local evidence set is enough to show both the design failure and the operational impact. One image captures the whitelist branch itself. Another shows harvested router data at scale. Taken together, they make the underlying exploit chain concrete without needing a playback artifact.
wizard_pppoe_lua.lua and wizard_wlan_config_lua.lua into a setup-allowed path.
Disclosure Timeline
The underlying disclosure trail is unusually clear and gives the case a strong factual backbone. The dates below are drawn from my correspondence with ZTE and from the public advisory record.
Initial disclosure sent to ZTE PSIRT describing unauthenticated wizard-page access, PPPoE leakage, and Wi-Fi password retrieval.
Follow-up notes that the exposed functionality appears capable of modifying settings, not only reading them.
ZTE confirms the vulnerability exists in H168N V3.5 and offers an XX bounty.
ZTE communicates a 3.5 Low rating using AV:A/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:N.
ZTE states it will not disclose or assign the CVE until the vulnerability is fixed.
ZTE publishes its bulletin and lists V3.5.0_EG1T10_ETS as the resolved version.
ZTE informs me that CVE-2021-21735 has been assigned.
ZTE confirms payout completion after I resubmitted the case through YesWeHack.
Severity Split
The scoring disagreement is not a minor paperwork detail. It reflects two different mental models of the bug. ZTE treated it like a constrained adjacency-bound information leak. NVD treated it like a remotely relevant confidentiality failure with high-impact exposure. The second reading is closer to the practical reality shown by the exploit path.
ZTE View
3.5 Low with adjacent network vector and low confidentiality impact. This reads like a narrow exposure scenario.
NVD View
6.5 Medium with network vector and high confidentiality impact. This better matches a case where leaked data can materially unlock admin and WLAN access.
In practice, the strongest interpretation is not determined by label alone but by what the exposed handlers actually return and how those values are used in the field. Here, the information disclosure label understates the operational blast radius.