译者注:直接英译中后语句太过拗口,在不改变原意的情况下做了些许调整
原文:1day to 0day(CVE-2022-30024) on TP-Link TL-WR841N
TP-Link TL-WR841N 设备中的漏洞
漏洞 | 描述 |
---|---|
CVE-2020-8423 | 数据解析 |
CVE-2022-24355 | 文件扩展名处理 |
CVE-2022-30024 | 数据分配 |
CVE-2020-8423
描述
TP-LINK厂商,其TL-WR841N V10型号的路由器存在一漏洞,已分配CVE编号为 CVE-2020-8423。
型号为 TL-WR841N v10的 TP-LINK 路由器设备的漏洞被指定为 ID CVE-2020-8423。经过身份验证的攻击者,通过向 wifi 网络配置发送 GET 请求,可在设备上实现远程代码执行。
固件
Firmware version: 3.16.9 Build 150310.
漏洞分析
在进入漏洞点之前,我将分析 Dispatcher()
函数,以理解程序是如何分配函数来处理其功能的。
当一个REQUEST提交时,httpGenListDataGet()
函数将被调用并返回一个 LIST_ENTRY
指针,其指向了一个函数指针列表,这些函数用来处理对应的URL。
然后,程序将调用httpGenListFuncGet()
函数来返回列表中的某个函数指针,并检查该函数对应处理的URL是否出现在REQUEST中。
若检查通过,则将调用该函数,否则继续从列表中取回函数指针并检查URL,重复此过程直至检查通过。
程序通过httpRpmConfigAdd()
函数,为每个URL分配具体的处理函数。
说的有点多,接下来将关注点放在漏洞分析上。
在stringModify()
函数中处理某些字符时,错误发生了。该函数在遇到 \, /, <,> "
等字符时,会添加\
来转义,或者在下个字符不是 \n
和 \r
时,添加字符串<br>
,重复执行此操作,直至缓冲区满。
问题在于向dst缓冲区添加字符串<br>
,数据增加了4个字节,但程序只处理了1个字节。
因此,只要找到一个调用此函数的位置,其src缓冲区来自用户输入,此漏洞就很可能触发。
发现了 writePageParamSet()
函数,它有一个创建页面的函数(即httpPrintf),还有一个缓冲区dst[512]
,将传递给 stringModify()
函数来存放处理后的字符。
在地址 0x45FA94
处,我们发现了一个回调函数,用来处理包含/userRpm/popupSiteSurveyRpm.htm
字符串的URL。
该函数将接收GET请求的参数,并调用漏洞函数。
可通过 ssid 参数来控制该漏洞。
漏洞验证
使用 Payload = "/%0a" * 0x55 + "A" * 100
.
设置断点并观察。
漏洞已被验证,$ra
寄存器的值已被改变,此外 $s0, $s1, $s2
三个寄存器的值也被覆盖。
Exploit
检查后发现程序没有启动任何保护机制,因此可将shellcode注入到栈空间来执行任意代码。
对于MIPS架构有个问题,在执行 shellcode 之前需要清除 Icache
缓存。为了解决这个问题,需要控制程序执行流,使其跳入Sleep()
函数。
在一个历史exp中(here),发现一条Rop链,其采用的库与本程序使用的库相匹配。不过还需要简单调整一下。
修复shellcode
我使用了一个shellcode(here),但并不奏效。
通过调试,发现当shellcode传递给stringModify()
函数时,如果其包含字节 \x3c, \x3e, \x2f, \x22, \x5c
,程序将在 \x5c\x3c
或 \x5c\x3e
之前面添加1字节的\x5c
,因此破坏了原有的shellcode。
检查这个 shellcode,发现其包含2个坏字节 \x3c
和\x2f
。我将修改此shellcode,通过指令替换的方式,来删除这些坏字节。
修复字节 0x3c
这个字节位于 lui
指令中,按作者的逻辑,将保存4个字节到栈上。
修改 lui
指令为 li
指令,保存2个字节到栈上,而非原本的4个。
修复字节 0x2f
在这个命令字符串中,包含了0x3c
和 0x2f
这两个坏字节,要将字符串//bin/sh
放置到栈上。
使用 li
指令来移除 0x3c
,可使用包含立即数的 xori
指令来移除 0x2f
。
通过此种方式修改shellcode后,可获取此路由器的控制权。
下一步要去检测此设备的整个固件,在此我发现了更多的1day和0day漏洞。
CVE-2022-24355
漏洞信息
发现的第一个 1day 漏洞为 CVE-2022-24355(critical等级)。其允许网络攻击者在未经认证的情况下,通过缓冲区溢出漏洞来执行任意代码。我的队友已分析了此漏洞(here ),故在此不再赘述。
CVE-2022-30024
漏洞描述
这是一个基于栈的缓冲区溢出,存在于二进制程序httpd(提供web服务)的ipAddrDispose
函数中。漏洞发生在将 GET 请求的参数值分配给栈变量的过程中,该过程允许用户向栈内存中输入大量数据,而这些数据攻击者可控。
发现错误
首先,来到容易理解的 ping 功能点处。
发送字符串aaaaaaaaa....aaa
,检查程序是否可溢出崩溃,结果在UI中只可以输入50个字符,就得到报错ping request could not find host ….. Please check the name and try again.
好像什么都没有发生,继续寻找此功能的处理函数,并进行逆向。
打开burpsuite,得到URL包含 /userRpm/PingIframeRpm.htm
字符串的请求
打开 IDA寻找此URL字符串,在地址0x44A530
处找到处理此URL的函数。
调用 httpGetEnv
函数来获取ping_addr, doType, isNew
的值,其通过GET请求的参数来传递。
调用ipAddrDispose
函数并传参ping _addr
,漏洞就发生在这。
初始化一个52字节大小的栈变量 buf_ip
,其接收并保存ping_addr
中的每个字符,直至字符串结尾。
问题在于,ping_addr
的长度并没有在代码中验证处理,仅仅在web UI中做了限制,可以很容易的通过burpsuite来绕过。
在burpsuite中进行测试,输入大约200个”a”字符来作为 ping_addr
,结果程序崩溃了。返回地址即$ra
寄存器的值被覆盖了,因此可确定漏洞存在。
编写了一个简单的python脚本来触发此漏洞,结果不出所料。
Exploit
接下来的目标是对设备进行RCE。此设备没有启用任何的保护机制,ASLR也是关闭状态,因此可控制 $ra 寄存器,使其跳入shellcode来执行代码并接管设备。
查看程序开头和结尾的汇编语句,找栈变量buf_ip
的位置,可计算覆盖到$ra
的偏移,即(0xD4 + 8) - (0xD4 – 0xA0) = 168 bytes
,同时,也可以控制另外两个寄存器$s0
和 $s1
。
为了便于理解,作图如下:
在MIPS架构中,不可以直接跳到shellcode去执行代码,必须先通过跳转到 sleep()
函数来清除 Icache
缓存即 Instruction cache
。既然是相同的固件,我将采用上述同样的ROP链。
构建完整的ROP链,如下可见栈空间的布局
最终,我们可成功通过此栈溢出漏洞控制设备。因为进行了固件模拟,所以反弹shell时会打印日志,真实的设备上不会如此。
我发现这个漏洞存在于 TL-WR841N V12及以下版本中,并分配编号CVE-2022-30024。用户应该从 TP-Link 官方网站下载最新的固件来更新补丁。https://www.tp-link.com/en/support/download/tl-wr841n/v12/#Firmware
时间线
- 14/04/2022:向他们发送漏洞报告
- 27/04/2022:TP-Link安全团队发我一份修改后的固件来检查
- 04/08/2022:TP-Link发布了新固件
发表评论
您还未登录,请先登录。
登录