Firmware image: flashdump.bin (8 MB, MIPS 32-bit little-endian, MediaTek MT7628)
I picked up an XL-B1310L dual-band router and wanted to see what was running inside. The device presents a LuCI web interface on 192.168.188.1, advertises itself with hostname pro, and identifies as a CST+8 timezone device, which puts manufacture somewhere in China. What follows is a full static teardown of the flash dump.
Getting the Firmware
The image came off the device as a single 8 MB flash dump. Binwalk identified the layout:
- U-Boot at
0x00000(bootloader) - LZMA-compressed kernel at
0x50040 - JFFS2 overlay at
0x5D0000(the writable configuration partition) - Scattered xz/zlib blobs (compressed kernel modules and libraries)
The interesting material is all in the JFFS2 overlay. That is where user configuration, credentials, and the web interface live. After extraction:
/jffs2-root/ -- writable overlay (JFFS2, offset 0x5D0000)
Two notable ELF binaries were also present at offsets 0x4FF9D6 and 0x510A96 in the flash, identified as:
/4FF9D6– lighttpd 1.4.45 (confirmed via version string"lighttpd/1.4.45 (ssl) (Oct 16 2022 22:42:09)"inmain())/510A96– iptables (confirmed viaiptc_*,ip6tc_*,xtables_*imports)
The U-Boot environment block was also readable and contained a few surprises. More on that below.
Filesystem Recon
Before touching the binaries I went through every config file in the overlay by hand.
Plaintext Admin Credentials and Telnet
# /jffs2-root/etc/config/control
option username 'admin'
option password '1234'
option telnet '1'
The web interface admin password is stored in plaintext in control. It is 1234. Telnet is also enabled (option telnet '1'), meaning an unauthenticated shell is available to anyone on the LAN without even needing the web password. This is the single worst finding in the image.
LuCI RPC Daemon Password
# /jffs2-root/etc/config/rpcd
config login
option username 'admin'
option password '$p$admin'
list read '*'
list write '*'
The $p$ prefix is OpenWrt’s rpcd pseudo-hash scheme. It is not actually a hash, the value after the prefix is the plaintext password. The admin password for the LuCI JSON-RPC interface is admin. Full read and write access granted.
Shadow File Whiteout – Passwordless Root
$ ls -la jffs2-root/etc/shadow
c--------- 1 root root 0, 0 shadow
The shadow file is an OverlayFS whiteout (character device 0,0). In an OverlayFS mount this deletes the underlying shadow file, leaving /etc/shadow absent at runtime. The passwd file still contains root:x:0:0:..., where x means “look in shadow”, but there is no shadow to look in. The result is that the root account has no password on the running system.
Combined with the telnet service enabled above, this means telnet 192.168.188.1 from the LAN, then pressing enter at the password prompt, gives root.
SSH: Root Password Login Enabled
# /jffs2-root/etc/config/dropbear
config dropbear
option PasswordAuth 'on'
option RootPasswordAuth 'on'
option Port '22'
Dropbear SSH is running with root password authentication enabled. Since root has no shadow entry, the account is unlocked with an empty password. Any SSH client can connect as root with no password.
WiFi Credentials – Plaintext PSK
# /jffs2-root/etc/wireless/mt7628/mt7628.dat
SSID1=tp58-PRO-2.4G7612
WPAPSK1=20102010
RADIUS_Key=ralink
# /jffs2-root/etc/wireless/mt7612/mt7612.dat
ApCliEnable=1
ApCliSsid=tp58
ApCliBssid=58:41:20:3f:09:aa
ApCliWPAPSK=20102010
The 2.4 GHz AP PSK is 20102010 in plaintext. The default RADIUS shared secret is ralink, a hardcoded MediaTek SDK default that ships with every Ralink/MediaTek reference design. More interesting is the MT7612 client bridge config: ApCliEnable=1 means this device is configured to connect as a wireless client to an upstream AP. The upstream SSID is tp58, BSSID 58:41:20:3f:09:aa, PSK 20102010. An attacker who reads this config can stand up an evil-twin AP with the same SSID, BSSID (MAC-spoofable), and PSK to intercept the router’s upstream traffic.
Firewall
# /jffs2-root/etc/config/firewall (LAN zone)
config zone
option name lan
option input ACCEPT
option output ACCEPT
option forward ACCEPT
The LAN zone accepts all inbound traffic. Every service on every port is reachable from any LAN host.
Boot Services
From ucitrack the following services start at boot:
network, firewall, dnsmasq, dropbear, httpd (lighttpd),
fstab, qos, luci_splash, miniupnpd, ntpclient, samba, tinyproxy, lan_wan_nat
Both samba and tinyproxy are running, expanding the attack surface further. Tinyproxy running on the LAN can be abused as a pivot point.
U-Boot Environment
bootcmd=tftp
bootdelay=2
serverip=10.10.10.4
ipaddr=10.10.10.123
ethaddr=00:AA:BB:CC:DD:10
The bootloader has a 2-second delay before executing bootcmd, which is set to tftp. If a TFTP server is running at 10.10.10.4 on the local network, U-Boot will attempt to fetch and boot a network image on every power cycle – no serial interruption required.
Binary Analysis
Binary Protections
Both ELF binaries score as poorly as possible on standard hardening checks:
| Binary | NX | Stack Canary | PIE | RELRO | FORTIFY |
|---|---|---|---|---|---|
/4FF9D6 (lighttpd) |
Yes | No | No | No | No |
/510A96 (iptables) |
Yes | No | No | No | No |
NX is the only protection present. No stack canary means any stack buffer overflow goes straight to exploitation. No PIE means the binary loads at a fixed address every time. No RELRO means the GOT is writable, a write primitive redirects any function call.
lighttpd 1.4.45 – Known CVEs
| CVE | CVSS | Description |
|---|---|---|
| CVE-2019-11072 | 9.8 | Signed integer overflow in http_request_parse() via Content-Length. Heap corruption, potential RCE. |
| CVE-2018-19052 | 7.5 | Path traversal in mod_alias. Alias prefix bypass via encoded path separators allows unauthenticated file read. |
CVE-2019-11072 is directly relevant here. The function http_request_parse (decompiled at 0x004142f4) reads Content-Length with strtoll() and stores the result as a signed 64-bit value. There is no upper bound check before the value enters downstream allocation arithmetic:
// From http_request_parse, ~0x004153e0
long long content_length = strtoll(content_length_buf->ptr, &end, 10);
if ((*end != '\0') || (content_length < 0)) {
// rejects obviously negative values
goto error;
}
// no upper bound check -- INT64_MAX passes here
*(long long *)(con + 0x130) = content_length;
With a fixed binary base address and writable GOT, a heap corruption from this path has a clear path to code execution.
I also decompiled and annotated the MD5 block transform used for HTTP Digest authentication (FUN_004204f8 / md5_block_transform at 0x004204f8), identified by the RFC 1321 round constants (0xd76aa478, -0x173848aa, etc.), and the config file tokenizer (FUN_00410338 / configfile_lexer at 0x00410338). These are saved with cleaned decompilation in the project’s AI Cleaned view.
OpenSSL 1.0.x – End of Life
lighttpd links libssl.so.1.0.0 and libcrypto.so.1.0.0. OpenSSL 1.0.x reached end-of-life on December 31, 2019. Selected CVEs:
| CVE | CVSS | Description |
|---|---|---|
| CVE-2021-3711 | 9.8 | SM2 decryption buffer overflow – code execution |
| CVE-2022-0778 | 7.5 | Infinite loop in BN_mod_sqrt() – DoS |
| CVE-2020-1967 | 7.5 | NULL pointer in SSL_check_chain – DoS |
| CVE-2019-1551 | 5.3 | rsaz_512_sqr overflow – RSA key recovery |
66 CVEs total assigned after the last 1.0.2 release. None will ever receive a patch.
dnsmasq ~2.80 – DNSpooq and KeyTrap
dnsmasq carries the full DNSpooq vulnerability set (JSOF, January 2021) plus two later high-severity issues:
| CVE | CVSS | Description |
|---|---|---|
| CVE-2020-25681 | 8.1 | Heap overflow in sort_rrset() DNSSEC – RCE from WAN |
| CVE-2020-25682 | 8.1 | Heap overflow in extract_name() DNSSEC – RCE from WAN |
| CVE-2023-50387 | 7.5 | KeyTrap: CPU exhaustion via crafted DNSSEC response |
| CVE-2022-0934 | 7.5 | Single-byte UAF via crafted DHCP packet – DoS |
| CVE-2020-25683/87 | 5.9 | DNSSEC heap overflow variants |
| CVE-2020-25684/85/86 | 3.7 | Transaction ID entropy reduction – cache poisoning amplifiers |
CVE-2020-25681 and CVE-2020-25682 are reachable from the WAN: the router forwards DNS queries to an upstream resolver, and a malicious upstream response triggers the overflow in dnsmasq’s DNSSEC validation code. CVE-2023-50387 (KeyTrap) allows a single crafted DNS response to peg the router’s CPU at near-100% until the query times out.
The three cache poisoning amplifiers (CVE-2020-25684/85/86) combine to reduce effective DNS transaction ID entropy from 16 bits to roughly 14 bits, making a Kaminsky-style off-path cache poisoning attack practical.
miniupnpd ~2.1 – NULL Pointer Dereferences
| CVE | CVSS | Description |
|---|---|---|
| CVE-2019-12108 | 7.5 | NULL pointer dereference in GetOutboundPinholeTimeout (int_port) |
| CVE-2019-12109 | 7.5 | NULL pointer dereference in GetOutboundPinholeTimeout (rem_port) |
| CVE-2019-12111 | 7.5 | NULL pointer dereference in copyIPv6IfDifferent |
All three are denial-of-service: a crafted UPnP request from the LAN crashes miniupnpd. Since miniupnpd is not supervised by a watchdog in this firmware, the UPnP service goes down permanently until the router is rebooted.
Vulnerability Summary
CRITICAL – Plaintext Admin Credentials + Telnet (CVSS 10.0)
/etc/config/control stores admin:1234 in plaintext and sets telnet '1'. Anyone on the LAN can telnet to the router and authenticate with these credentials. No exploitation tooling required.
CWE-256 (Unprotected Storage of Credentials), CWE-306 (Missing Authentication for Critical Function)
CRITICAL – Passwordless Root Account (CVSS 10.0)
The OverlayFS whiteout on /etc/shadow removes the shadow password database at runtime. The root account in /etc/passwd references a shadow entry that does not exist, making root passwordless. Combined with telnet and SSH root login enabled, this is an instant root shell.
CWE-521 (Weak Password Requirements), CWE-732 (Incorrect Permission Assignment)
CRITICAL – Plaintext WiFi PSK and Hardcoded RADIUS Key (CVSS 8.8)
WPAPSK1=20102010 is stored in plaintext. The RADIUS shared secret RADIUS_Key=ralink is the MediaTek SDK default present in every reference design.
CWE-256 (Unprotected Storage of Credentials), CWE-798 (Use of Hard-coded Credentials)
HIGH – LuCI rpcd Plaintext Password (CVSS 8.8)
$p$admin is not a hash. The plaintext password is admin. Full read/write access to all UCI namespaces from any LAN host.
CWE-256 (Unprotected Storage of Credentials)
HIGH – Dropbear SSH Root Password Authentication (CVSS 8.1)
SSH root login with password authentication is enabled. With root being passwordless, ssh root@192.168.188.1 with an empty password delivers a shell.
CWE-306 (Missing Authentication for Critical Function)
HIGH – lighttpd CVE-2019-11072: Signed Integer Overflow (CVSS 9.8)
Content-Length parsing accepts values up to INT64_MAX with no upper bound check. Downstream truncation and overflow in 32-bit arithmetic creates heap corruption. No stack canary or PIE on the binary.
CWE-190 (Integer Overflow)
HIGH – lighttpd CVE-2018-19052: mod_alias Path Traversal (CVSS 7.5)
Alias prefix bypass via URL-encoded path separators. lighttpd runs as root. Arbitrary file read from an unauthenticated request.
CWE-22 (Path Traversal)
HIGH – OpenSSL 1.0.x End-of-Life (CVSS up to 9.8)
66 unpatched CVEs. CVE-2021-3711 (buffer overflow, code execution) is directly applicable to the HTTPS endpoint.
CWE-1104 (Use of Unmaintained Third-Party Components)
HIGH – dnsmasq DNSpooq Heap Overflows (CVSS 8.1)
CVE-2020-25681 and CVE-2020-25682 allow RCE via crafted DNSSEC responses from a compromised upstream resolver. Reachable from WAN without any credentials.
CWE-122 (Heap-based Buffer Overflow)
HIGH – No Binary Exploit Mitigations (CVSS 7.0)
NX only. Every memory corruption finding in lighttpd or dnsmasq is significantly easier to weaponize without canaries, PIE, or RELRO.
CWE-693 (Protection Mechanism Failure)
MEDIUM – Evil-Twin AP via Hardcoded Upstream BSSID + PSK (CVSS 6.5)
Client bridge config contains upstream AP BSSID and PSK. An attacker with these values can impersonate the upstream AP and intercept all WAN traffic.
CWE-798 (Use of Hard-coded Credentials)
MEDIUM – KeyTrap DNS DoS (CVSS 7.5)
CVE-2023-50387 pegs the CPU at near-100% from a single crafted DNS packet. Repeatable indefinitely. Denies internet connectivity to all LAN clients.
CWE-400 (Uncontrolled Resource Consumption)
MEDIUM – miniupnpd NULL Pointer Dereferences (CVSS 7.5)
Three CVEs (CVE-2019-12108/09/11) in the UPnP daemon allow any LAN host to crash the service with a crafted UPnP request.
CWE-476 (NULL Pointer Dereference)
MEDIUM – U-Boot TFTP Boot Attack (CVSS 5.7)
bootcmd=tftp, bootdelay=2, serverip=10.10.10.4. Physical access delivers a U-Boot shell in 2 seconds. Network-adjacent: a TFTP server at 10.10.10.4 automatically delivers firmware on every power cycle.
CWE-276 (Incorrect Default Permissions)
MEDIUM – Firewall Accepts All LAN Input (CVSS 5.3)
LAN zone input ACCEPT. Every service is reachable from every LAN host with no restriction.
CWE-1188 (Insecure Default Initialization)
Remediation
| Finding | Fix |
|---|---|
| Plaintext credentials in control | Remove telnet; store passwords as salted SHA-512 hashes |
| Shadow whiteout / passwordless root | Restore shadow file with a strong root password; disable root login over telnet/SSH |
| WiFi PSK plaintext | Generate per-device credentials at manufacturing; do not store PSK in plaintext |
| RADIUS key “ralink” | Replace with a randomly generated per-device secret |
| rpcd \$p\$ plaintext | Use a proper hash scheme; force password change on first boot |
| lighttpd 1.4.45 | Upgrade to >= 1.4.76 |
| OpenSSL 1.0.x | Replace with OpenSSL 3.x or LibreSSL |
| dnsmasq 2.80 | Upgrade to >= 2.90; disable DNSSEC if not required |
| miniupnpd 2.1 | Upgrade to >= 2.3.6; disable UPnP if not required |
| No binary hardening | Recompile with -fstack-protector-strong -fpie -pie -Wl,-z,relro,-z,now |
| U-Boot TFTP | Set bootdelay=0; change bootcmd to flash-only boot |
| Firewall LAN ACCEPT | Implement per-service accept rules; default LAN policy to DROP |
The Shortest Path to Root
From any device on the LAN:
$ telnet 192.168.188.1
pro login: admin
Password: 1234
root@pro:~# id
uid=0(root) gid=0(root) groups=0(root)
Or over SSH:
$ ssh root@192.168.188.1
root@192.168.188.1's password: [empty -- press Enter]
root@pro:~# id
uid=0(root) gid=0(root) groups=0(root)
Both paths require no tooling beyond a standard terminal and deliver a root shell in under five seconds.
Closing Thoughts
The most dangerous combination here is the plaintext admin:1234 in control, telnet enabled by default, and the shadow whiteout giving root a blank password. Three separate unforced errors that stack into an instant root shell from the LAN. Any device connected to this router – a laptop, a phone, a smart TV – can gain root without any exploitation skills or tooling.
The firmware is based on the MediaTek MT7628 SDK reference design, and several of the issues (RADIUS key ralink, the TFTP bootcmd, the default WiFi PSK) are SDK defaults that were never overridden for production. This is a common pattern with ODM/white-label router firmware: the vendor ships the SDK reference config, changes the branding, and calls it done.
On the library side, the combination of EOL OpenSSL 1.0.x, unpatched dnsmasq 2.80, and no binary exploit mitigations means that any of the reachable CVEs has a lower exploitation bar than it would on a hardened device. CVE-2020-25681 in dnsmasq is particularly concerning: it is reachable from the WAN without any credentials, requires no prior access to the device, and the heap overflow lands in a binary with no canary or ASLR.
All findings were identified through static analysis of the firmware image only.