CVE-2021-35036 • Zyxel Credential Exposure Super-Admin Password Leak Affecting Zyxel CPE/ONT/LTE Fleet The issue was first reported against VMG3625-T50B firmware V5.50(ABTL.0)b2k and later expanded into a broader product-line issue: authenticated low-privilege sessions could reach backend DAL endpoints that returned administrator, supervisor, FTPS, and TR-069 secrets in cleartext. Later Zyxel advisories expanded the scope well beyond a single ISP-customized router image. By Mina Zekry Independent vulnerability research and firmware analysis Repo write-up, generator, lab bundle GitHub zyxel-cve-2021-35036-super-admin-password-leak LinkedIn Mina Zekry X monxresearch Medium @monxresearch Initial report: October 2021 Public advisory: September 27, 2022 Primary CWE: CWE-312 Impact Privilege escalation by disclosure User-level access was enough to recover passwords for higher-privilege local accounts and management services. Scope Shared management stack The firmware tree shows the exposure lived in shared libzcfg_fe_dal management code, not in a one-off UI template. Lesson Presentation masking is not access control Several later fixes merely hid values in CLI or TR-98 presentation paths after the backend had already loaded the raw secrets. What Was Reported Original finding A user -privileged account could browse directly to: /cgi-bin/DAL?oid=login_privilege /cgi-bin/DAL?oid=tr69 and obtain cleartext values for local accounts and TR-069 credentials. Disclosure material also shows a related /getDefaultInformation response leaking default passwords for root , supervisor , admin , admin1 , and ftps . The issue was not just that secrets existed in storage. An authenticated low-privilege session could retrieve them through ordinary web-facing DAL handlers. Intercept evidence captured during disclosure. Public scope From one ISP image to a larger fleet Zyxel first assigned the CVE for VMG3625-T50B , but its later public advisory broadened affected scope across multiple product families. DSL / Ethernet CPE: VMG3625-T50B, VMG3927-T50K, VMG8623-T50B, VMG8825-T50K, EMG3525-T50B, EMG5523-T50B, EMG5723-T50K, DX3301-T0, DX5401-B0, EX5401-B0, EX5501-B0 Fiber ONT: AX7501-B series, EP240P, PMG5617GA, PMG5622GA, PMG5317-T20B, PMG5617-T20B2, PM7300-T0 4G / 5G CPE: LTE3301-PLUS, LTE5388 family, LTE7480 family, LTE7490-M804, NR5101, NR7101, NR7102 That matters because the exposed code belongs to a shared management framework, which matches the later vendor-side scope expansion. Root Cause Why the leak existed 1. Login privilege GET returned raw passwords In the firmware source, zcfgFeDal_LoginPrivilege_Get iterates through RDM_OID_ZY_LOG_CFG_GP_ACCOUNT and copies each account's Password field directly into the outgoing JSON array. json_object_object_add (paramJobj, "Username" , JSON_OBJ_COPY ( json_object_object_get (loginPrivilegeObj, "Username" ))); json_object_object_add (paramJobj, "Password" , JSON_OBJ_COPY ( json_object_object_get (loginPrivilegeObj, "Password" ))); The DAL command registration then exposes login_privilege as edit|get with an empty privilege string, even though the inline comment still says root_only . 2. TR-069 GET copied the whole management object The TR-069 DAL getter uses a generic copy path across the management parameter list. That includes Password and ConnectionRequestPassword , which are copied out unless another layer explicitly strips them. else { json_object_object_add (pramJobj, paraName, JSON_OBJ_COPY ( json_object_object_get (mgmtJobj, paraName))); } The corresponding DAL registration exposes tr69 as get|edit . 3. Cosmetic hiding arrived after the backend exposure Later patches show Zyxel masking values in display code by printing ******** for ACS and SIP passwords. That is a UI / CLI presentation fix, not a backend access-control fix. printf ( "%-45s %s\n" , "ACS Password" , "********" ); 4. Subsequent metadata fixes confirm the sensitivity Other later patches add PARAMETER_ATTR_PASSWORD to fields like Password , ConnectionRequestPassword , DefaultPassword , and PasswordHash . That change acknowledges these values should not have been returned verbatim in getter flows. Timeline Disclosure path October 5, 2021 The issue is reported to Zyxel as a cleartext credential exposure reachable from a low-privilege account. October 18, 2021 Zyxel assigns CVE-2021-35036 for the VMG3625-T50B case. March 2022 Planned disclosure is delayed again while patches are prepared. September 27, 2022 Zyxel notifies the researcher that the CVE and advisory will be published. September 28, 2022 Zyxel confirms public advisory publication and Hall of Fame acknowledgment. Genpass Lab The VMG8825 genpass clue The repository also includes an adapted copy of the public Zyxel VMG8825-T50 keygen work by boginw , tailored for the VMG8825-B50B because the original version did not fit this router model directly. It demonstrates that password material was embedded in reusable vendor logic and could be regenerated from device identity inputs instead of being treated like narrowly scoped operator secrets. run-qemu.bat launches the ARM guest, rootfs.ext2 carries the extracted filesystem, and the tracked adapted-runtime/opt/genpass/genpass wrapper is the B50B-specific version included in the repository. That wrapper accepts serials whose fifth character is V , Y , or H before calling into vendor password-generation code under /opt/zyxel . Launch the emulator from the repo with .\zyxel-vmg8825-b50b-keygen-lab\run-qemu.bat . At the guest login, authenticate with root / root . Run genpass S182V12345678 to derive the supervisor and admin password families from a sample modem serial. # host PS> .\zyxel-vmg8825-b50b-keygen-lab\run-qemu.bat # inside the bundled emulator root@VMG8825-B50B-emul:~# genpass S182V12345678 Old algorithm supervisor password.............. 789630c0 New algorithm supervisor password.............. dEfczwP8Sy ... additional admin and Wi-Fi outputs continue below That does not prove CVE-2021-35036 by itself, but it reinforces the design pattern behind the analysis: password material was treated as reusable product data that multiple components could fetch, transform, display, or restore. Once the DAL layer exposed those backing objects too broadly, the rest of the stack never had a chance. Reverse Engineering How genpass works internally 1. The shell script is only a front-end Reverse engineering starts with the extracted genpass shell wrapper, not the password algorithm itself. The script validates the serial format, exports it as SERIAL , sets LD_LIBRARY_PATH to Zyxel's extracted libraries, preloads libhook.so , and then invokes the real worker binary: /opt/genpass/getpassword . That matters because the visible script does not derive passwords on its own. It acts as an execution harness that feeds controlled input into vendor code that was originally meant to run inside the router environment. 2. libhook.so replaces the router's serial source The small preload library is the most revealing part of the setup. Static analysis of its exported symbols shows that it overrides zyUtilIGetSerialNumber and zcfgBeCommonIsApplyRandomSupervisorPasswordNewAlgorithm . In the first hook, the code calls getenv("SERIAL") . If the environment variable is present, it copies that value into the caller's buffer. If not, it falls back to the original function via dlsym(RTLD_NEXT, "zyUtilIGetSerialNumber") . In the second hook, it simply returns 1 , forcing the "new random supervisor password" path on during emulation. 3. getpassword is an orchestrator, not the algorithm String and symbol analysis of getpassword shows that it dynamically resolves the real generators at runtime. Its string table contains libzcfg_be.so , libzcfg_be_wind.so , zcfgBeCommonGenKeyBySerialNumMethod2 , zcfgBeCommonGenKeyBySerialNumMethod3 , zcfgBeCommonGenKeyBySerialNumConfigLength , zcfgBeCommonGenKeyBySerialNumConfigLengthOld , and zcfgBeWlanGenDefaultKey . That is a strong indicator that the binary does not embed one monolithic algorithm. Instead, it loads vendor library entry points, asks them for the required buffer sizes, invokes multiple generation routines, and prints the results under labels such as old/new supervisor, old/new admin, WIND-specific admin variants, and several Wi-Fi key families. 4. The emulator recreates enough of the firmware to make the vendor code run The reason this works in QEMU is that the extracted filesystem still contains the same userland and shared objects the original firmware expected. The wrapper points LD_LIBRARY_PATH at Zyxel's library directories, the preload hook substitutes missing hardware-derived state, and the vendor password functions execute as if they were running on the device. From a reverse-engineering perspective, that makes genpass a harness around reusable product logic rather than a standalone cracking tool. The lab setup does not reimplement Zyxel's algorithms; it restores just enough runtime context to call them directly. 5. The supervisor routines are deterministic and portable Disassembly of zcfgBeCommonGenKeyBySerialNumMethod2 and zcfgBeCommonGenKeyBySerialNumMethod3 shows two exact supervisor paths. Method2 computes MD5(serial) , renders each digest byte as vendor-style hex where one-nibble bytes are duplicated instead of zero-padded, hashes that string again, and then samples every third character to build the old supervisor password. Method3 reuses that same double-hash stream, uppercases it, derives a 16-bit seed from bytes 1 and 2 of MD5(serial) , increments the seed until a ten-slot mod-3 schedule contains uppercase, lowercase, and digit classes, and then maps each sampled byte into safe alphabets with explicit substitutions for I , O , l , o , 1 , and 0 . That is why the generator can be ported cleanly into browser JavaScript: the firmware logic is deterministic and table driven, not server backed. Exact Browser Port Supervisor generator for Method2 and Method3 Generate Replay Method3 This widget is
The vulnerability CVE-2021-35036 (CVSS 6.5) in Zyxel CPE/ONT/LTE devices allows authenticated low-privilege users to escalate privileges by directly querying backend DAL endpoints, which return cleartext super-admin, FTPS, and TR-069 credentials. Affected firmware versions are numerous and product-specific, such as Zyxel AX7501-B0 firmware before version 5.17(abpc.2)c0 and Zyxel EMG3525-T50B firmware before version 5.50(abpm.7)c0. The fix requires upgrading each affected product to its specific patched firmware version listed in the NVD data.