RG-EW3000GX 从触摸到攻陷

u-boot绕过命令执行IOT多功能调试器
2026-08-19 08:11
247815

基本信息概述

产品:AX3000 双频WI-Fi6无线路由器

产品型号:RG-EW3000GX

固件版本:ReyeeOS 1.380.2222;EW_3.0(1)B11P380,Release(12222219)

UART固件提取

前期准备

首先摸到真机先暴力拆掉,然后焊接杜邦线 GND TX RX

配合USB 转 TTL 串口模块进行串口调试 ,那么本次就使用最新研发的 iot多功能调试板 其中的UART调试功能

图片.png

非常的贴心,还准备了网卡功能,对于我这轻薄本没有网口接口太友好了。

以往我们在遇到板子上面没有显示TX RX 又或者还得边插边调,他这个有个特别好用的点,你不用管谁接TX,谁接RX ,直接俩根线连URAT0或URAT1就可以了

图片.png

本次就插UART0进行串口调试

手动工作做好后,现在用MobaXterm 进行串口调试

图片.png

因为无脑插上去的,因为RX和TX没有对上,没有输出日志信息

图片.png

连接规则

GND  --------------->  GND
TX   --------------->  RX
RX   --------------->  TX

这个时候只需要按一下UART0 交换按钮 ,他会自动切换RX TX,按一下马上就对上了,真的特别简单好用

图片.png

图片.png

已经打印信息了

启动信息分析

MTD分区信息

图片.png

观察启动信息其中就有选项 0 可以进入u-boot

图片.png

最后正常执行会到登录认证

图片.png

但是我又不知道设置的啥密码,弱口令又进不去

先进入u-boot 再观察观察,重新上电 狂按0进入

图片.png

按help 看看有没有可用指令

图片.png

其实像tftpboot bootm md 等可利用的命令都挺多的,但是我们直接暴力绕过u-boot进入shell 才更方便,这里我们的思路是把u-boot传给内核系统执行的启动参数 bootargs 加个init=/bin/sh 绕过

简单描述下绕过流程

bootargs 是 U-Boot(引导程序)传给 Linux 内核的启动参数
u-boot --> 把内核加载到内存 --> 其中把bootargs传给内核读取执行 --> 执行init=/bin/sh --> shell

绕过u-boot改密码

setenv bootargs 'console=ttyS0,115200n8 init=/bin/sh'
mtkboardboot

图片.png

进入shell ,接下来我们要做几件事

#挂载虚拟文件系统
mount -t sysfs sysfs /sys
mount -t tmpfs tmpfs /dev

#喂看门狗,不喂的话过了30秒就会重启后面挂载一系列操作就会白搞,所以先搞这个
#查看看门狗设备号
cat /sys/class/watchdog/watchdog0/dev

图片.png

拿到251:0

mknod /dev/watchdog c 251 0

挂载 /proc 定位 rootfs_data 可写数据分区

mount -t proc proc /proc
cat /proc/mtd

图片.png

找到对应的 mtd9 ,接下来 手动挂载 Overlay 文件系统并 chroot 进入真实系统环境

mount -t tmpfs tmpfs /tmp
mkdir -p /tmp/ov /tmp/root

# 创建 mtdblock9 设备节点并挂载 rootfs_data 分区(jffs2)到 /tmp/ov
mknod /dev/mtdblock9 b 31 9 
mount -t jffs2 /dev/mtdblock9 /tmp/ov

#挂载 OverlayFS
mount -t overlay overlay -o lowerdir=/,upperdir=/tmp/ov/upper,workdir=/tmp/ov/work /tmp/root

chroot /tmp/root /bin/sh

图片.png

sync && umount /tmp/root && umount /tmp/ov && sync
reboot -f

把内存中的缓存数据写入flash,然后卸载 前面挂载的俩个文件系统,然后再次同步写入flash 确保保存成功

提取固件

图片.png

临时关闭内核日志输出,不然太烦了

echo 0 > /proc/sys/kernel/printk

配置网络

ip addr

图片.png

可以看到网桥 br-wan 也就是 10.44.77.254 ,拿到路由器ip ,那么接下来根据10.44.77.0网段 去配置ip

windows主机

图片.png

虚拟机

sudo ifconfig ens33 10.44.77.200/24 up

图片.png

测试连通

图片.png

查找固件

mount -t proc proc /proc	
cat /proc/mtd

图片.png

可以看到 我们需要的 mtd6 "firmware" 分区 15KB左右 ,接下来就是对这个分区

查看可使用的命令

ls /bin

图片.png

有dd命令 配合 nc 传

dd if=/dev/mtd6 of=/tmp/firmware.bin bs=1M

#虚拟机
nc -l -p 1314 > firmware.bin
#路由器
nc 10.44.77.200 1314 < /tmp/firmware.bin

图片.png

没毛,接下里binwalk 提取下文件系统

binwalk -Me firmware.bin

图片.png

启动项分析

老规矩先从 /etc/inittab

图片.png

系统初始化最先执行 /etc/init.d/rcS ,没有找到该文件再往下找/etc/rc.common

图片.png

/etc/rc.d/S*,紧跟查看

/etc/rc.d/S50lighttpd

图片.png

这里就能很明显发现前端是 /usr/sbin/lighttpd ,对应的配置文件是 /etc/lighttpd/lighttpd.conf

启动的方法是/usr/sbin/lighttpd -D -f /etc/lighttpd/lighttpd.conf ,这里都明确说明

再看下 /etc/lighttpd/lighttpd.conf

图片.png

开始这部分 加载功能模块其中 mod_unifyframe 就是锐捷自定义模块,定义了网站根目录 /www/ ,包括默认首页

这里定义了 CGI 映射关系,当url匹配到 /cgi-bin/luci 默认 走 /www/cgi-bin/luci 执行 ,匹配到.lua 就交给 /usr/bin/lua 去解释执行。

当匹配到 路径单独匹配到 uri.path 和 requst.pathinfo 同时满足的话就由mod_unifyframe 模块接管处理。

现在针对 自定义模块进行查找下

图片.png

init.d下面unifyframe-sgi

图片.png

USE_PROCD=1 表示它运行在 procd 下,procd依赖 ubusd 总线 ,还得启动 ./sbin/ubusd

/usr/sbin/unifyframe-sgi.elf 后端主程序,建 socket

/usr/sbin/uf_ubus_call.elf ubus 代理

启动锐捷 Web 后端服务(unifyframe-sgi.elf + uf_ubus_call.elf),建立 socket 通信并支持 ubus 调用。

漏洞挖掘

直接真机测试

图片.png

图片.png

漏洞一

unifyframe-sgi.elf 内置插件模块 configChangecc_set(0x414D58)→ uf_get_url_config 把用户提交的 data.url存在命令注入

把 /usr/sbin/unifyframe-sgi.elf 丢进ida,定位函数 module_init_configChange

图片.png

这里看几个关键动作,它设置模块名为configChange ,然后绑定的是 sub_414D58 ,双击进入

图片.png

获取三个参数 url ,module , function 的值 ,其中url的值给到string

图片.png
这里往下走其实还是做了一丢丢检测 ,检查 string 是否包含 $( 或反引号。然后通过snprintf 进行拼接,最后交给ufm_popen也就是popen执行命令

POST /cgi-bin/luci/api/cmd?auth=这里填认证后的token HTTP/1.1
Host: 10.44.77.254
Content-Length: 202
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.0.0 Safari/537.36
Accept: application/json, text/plain, */*
Content-Type: application/json;charset=UTF-8
Origin: http://10.44.77.254
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Connection: keep-alive

暂不公开

执行

image.png

漏洞二

dev_config user_list_note 模块 name 字段命令注入

首先先定位没有安全检测的

grep -c "param_safety_check" usr/local/lua/dev_config/*.lua

图片.png

主要就是先看这些为0的,然后再结合是否有相关危险函数的

grep -n "os.execute\|io.popen\|luci.sys.exec\|luci.sys.call\|forkExec" \
       usr/local/lua/dev_config/dev_mode.lua \
       usr/local/lua/dev_config/hwnat.lua \
       usr/local/lua/dev_config/mesh.lua \
       usr/local/lua/dev_config/repeater_config.lua \
       usr/local/lua/dev_config/repeater_hostrouter.lua \
       usr/local/lua/dev_config/user_list_note.lua

图片.png

这里其实就是找可控参数,像dev_mode.lua 几乎就是全是固定字符串的execute ,我们进一步缩小到比如 os.execute(cmd) 类似可控的位置去做分析,比如该漏洞 user_list_note.lua

gedit usr/local/lua/dev_config/user_list_note.lua

图片.png

这里就有很明显命令注入的特征了,接下里就是着重去看下sync_list 也就是 child_data ,接着往上翻分析child_guard_packaged_data

图片.png

这里就是说存在相同的mac 才 存入 child_data ,这样才满足能执行到下面 child_guard_sync 里面的 os.execute(cmd),那么就可以利用可控参数name进行注入。

接下里整个思路就是先注册一个儿童mac,然后利用相同的mac,进行name注入。现在第一步就需要去知道怎么注册

gedit ./usr/local/lua/dev_config/child_guard.lua

请求入口

图片.png

图片.png

图片.png

这里有说明如果是已存在的mac只能注册一次只能改字段,不存在就table.inset 重新设置 ,

最好会生成写入到配置文件里 持久化

图片.png

废话不多说先上exp

先注册

POST /cgi-bin/luci/api/cmd?auth=这里填认证后的token  HTTP/1.1
Host: 10.44.77.254
Content-Length: 122
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.0.0 Safari/537.36
Accept: application/json, text/plain, */*
Content-Type: application/json;charset=UTF-8
Origin: http://10.44.77.254
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Connection: keep-alive

暂不公开

后利用

POST /cgi-bin/luci/api/cmd?auth=这里填认证后的token HTTP/1.1
Host: 10.44.77.254
Content-Length: 157
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.0.0 Safari/537.36
Accept: application/json, text/plain, */*
Content-Type: application/json;charset=UTF-8
Origin: http://10.44.77.254
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Connection: keep-alive

暂不公开

image.png

分享到

参与评论

0 / 200

全部评论 6

用户tvRtpwsA的头像
漂漂漂漂漂漂漂
2026-08-21 09:07
KDEV的头像
厉害啊,修改boot参数绕过登录!
2026-08-21 01:39
皮皮先生的头像
学长
2026-08-21 03:41
kris的头像
写的好,可以分享一下固件包吗,想研究一下
2026-08-21 00:01
皮皮先生的头像
请查收
2026-08-21 03:41
能混的头像
这工具好方便🐂
2026-08-20 03:37
Legion_的头像
牛🤬,大佬带飞
2026-08-20 02:58
烟雨江叶的头像
666
2026-08-19 09:14
投稿
签到
联系我们
关于我们