论坛首页 安全编程开发区 阅读主题

[原创]小米AX9000路由器CVE-2023-26315漏洞复现

163 浏览 2 回复
#1 楼主 2026-06-01 21:09:04
本文参考 winmt 师傅的文章,复现其挖掘的小米 AX9000 路由器命令执行漏洞。本文大幅简化了分析流程,梳理并总结了所需工具与操作指令,旨在帮助读者快速完成该路由器的qemu仿真与漏洞复现。国家信息安全漏洞共享平台
CVE 记录:CVE-2023-26315固件下载地址:固件下载
qemu-ARM64内核环境下载地址: qemu搭建ARM64环境 | XiDP拆解固件过程如下完成之后就可以启动我们已经配置好的qemu虚拟机(需要手动配置ip地址)设置之后尝试ping一下主机来验证ip地址来查看是否设置成功为了能够跳过小米路由器的初始化这里需要patch其中的文件
patch的文件为/squashfs-root/usr/sbin/sysapihttpd
找到如图所示部分进行修改将 CBZ 修改为 CBNZ
patch之后替换掉原本的文件随后使用scp传入qemu虚拟机中使用这个方法会出现一个问题,明明使用root用户传输密码是对的,但是它就是显示不对,这是并不是密码的缘故而是ssh禁止了使用root用户登入
我们需要做一个修改,否则后续依旧只能使用普通用户来传输很麻烦在root用户下使用下面指令修改ssh配置文件 修改完毕之后重启ssh服务然后再次使用上述scp指令就可以进行传输了之后就可以准备启动httpd服务
执行下面几个指令(这里是按照wimmt师傅文章中的内容做了一个总结,只需要按照顺序复制粘贴到qemu虚拟机中就可以成功启动小米路由器的仿真)执行之后就可以访问 192.168.122.130
它会自动定位到这里路由器的初始化配置页面
因为初始化部分和硬件相关所以我们需要想个办法绕过
也就是执行下面这两个指令设置好之后再次访问就可以绕过初始化配置,直接跳转到登入页面
注意这里是重新访问,不是刷新界面
由于我们复现的CVE-2023-26315是一个授权认证后的漏洞,因此我们需要设置登录密码以登录进后台拿到token的值所以下面我们需要尝试登入它
阅读它的web页面源码来查看它的密码的加密逻辑是什么
F12之后查看web内容,分别在440行和1722行可以看到 由此可以看出,我们的用户名是固定为admin,而密码是通过一个叫 oldPwd()函数 加密之后的结果。
这个 oldPwd()函数 将用户提交的密码和一个固定的key = a2ffa5c9be07488bbb04a3a47d3c5f6a组合之后使用sha1哈希进行一个加密下面我们假设我们设置的用户密码为 xidp
那么我们需要给account.common.admin这个uci配置为sha1(xidpa2ffa5c9be07488bbb04a3a47d3c5f6a) 那么我们使用下面指令来设置密码 下面就可以成功使用密码xidp登入了
也是进入到这个界面发现这个小米路由器AX9000的造型看起来有点酷
本来想淘宝买一个看看能不能实机打一下,淘宝看了一下价格感觉还是算了o(╥﹏╥)o
这里先简单使用winmt师傅的PoC来演示漏洞效果,随后再介绍漏洞成因这里先对着这个小米路由器的配置界面抓个包,得到我们现在的token值
抓包得到的内容如下可以得知我们的token=26a8470f16d4a0c8a03a8e503549b3ee然后qemu虚拟机启动这两个服务接着编写我们的PoC,如下所示(我本来是想拿shell的,但是尝试几次之后都没有连接上,不知道什么原因,为了展示命令执行成功,我将指令换成了创建文件666666)接着运行我们的脚本
到这里就算是成功复现了,我们可以直接使用指令退出我们的qemu虚拟机了复现成功之后我们再来看我们这命令执行漏洞具体产生的原因是什么
小米路由器的前端是使用Lua来编写的,而且其中存放的Lua文件并不是源码而是已经编译后的二进制文件,同时小米对Lua的解释器做了魔改。但是没有关系github上已经有了专门针对小米路由器Lua的反编译工具: NyaMisty/unluac_miwifi由于需要反编译的数量比较多,所以我们简单写一个脚本来批量反编译修改脚本下面我们打开反编译的 /usr/lib/lua/luci/controller/api/xqdatacenter.lua
可以看到大致如下内容当然这样的可读性依旧不是很高,我们可以使用ai工具来帮助我们增加可读性
ai解析过后的内容大致如下分析结果可知/api/xqdatacenter/request这个API端点需要用户登录认证,并且用户名被设置为 admin,sysauth_authenticator = "jsonauth"即当token不存在或错误时,通过authenticator.jsonauth函数进行登录验证对于具体的入口来说,定义entry{}内的第五个参数flag位为0x01(或&0x01=1)代表不需要鉴权,这里/api/xqdatacenter/request这个入口没有设置flag位,因此表示需要鉴权。下面来看 tunnelRequest 这个函数函数主要作用是会对传入payload字段内的JSON数据用binaryBase64Enc函数进行Base64编码处理,然后拼接入THRIFT_TUNNEL_TO_DATACENTER所指代的命令中并执行关键问题在于使用formvalue_unsafe函数获取payload字段内容,未过滤危险字符。而formvalue函数中是有用hackCheck过滤危险字符的。这里可能是开发者考虑到Json格式的数据当中可能会用到某些字符所以不能直接过滤,但也没有进一步去做针对于Json的危险字符过滤,给了我们可趁之机。在/usr/lib/lua/xiaoqiang/common/XQConfigs.lua中,可以找到THRIFT_TUNNEL_TO_DATACENTER的相关定义也就是最后执行的东西是 thrifttunnel 0 base64(raw_payload)
所以下面我们就来看看这个/usr/sbin/thriftunnel二进制文件这里我们直接进入这个叫sub_AB08的函数,它是thriftunnel的主要程序内容也就是说它检查程序调用参数是不是三个显然我们的 thrifttunnel 0 base64_string 符合要求sub_1B6FC函数的作用是复制它将 *(a2 + 16) 也就是 argv[2] 的内容复制到 11 中,说通俗点就是将 base64_string 的内容复制到 v11 中这里先判断了一下 v11 是否为空,不为空就会进入 if,依旧复制 base64_string 的内容到 v13 中,然后作为第一个参数被传入sub_1B9B0函数中,而sub_1B9B0函数的第二个参数v11此时是空串这里不再进入 sub_1B9B0函数 继续讲解,它的逻辑较为简单,结合ai分析可以知道它的功能大致就是 解开base64编码,然后将结果存放在 v12 中接下来是个 switch
显然我们传入的 argv[1] = 0, 所以我们会进入 case 0 中也就是随后会执行 sub_1BAE0函数
而这里的 v12[0] 按照我们的分析,它应该是

...(已截断)

---
来源: 看雪论坛
原文链接: https://bbs.kanxue.com/thread-289037.htm
#2 2026-06-01 21:09:04
感谢分享。解答下你提到的困惑,可以这样:首先确定这里socket用的apache::thrift框架,然后就grep -r "TSocket"匹配这个字符串,定位到少量的二进制文件(除去库文件),然后拖进IDA挨个看一下相关函数或者search一下9090的16进制来定位。
#3 2026-06-01 21:09:04
winmt


感谢分享。解答下你提到的困惑,可以这样:首先确定这里socket用的apache::thrift框架,然后就grep -r "TSocket"匹配这个字符串,定位到少量的二进制文件 ...

看师傅的文章学到了很多,很高兴收到师傅的回复,感谢师傅的解答

请登录后参与讨论

立即登录 注册账号