最近看到了关于TL-Link 一个古老的路由器 WR841n 的漏洞披露文章,都是关于缓冲区溢出的漏洞,虽然设备老,但是漏洞的发现过程都挺有学习价值的。在平时对设备的漏洞挖掘过程中,可能会比较倾向于对设备的工作流程进行分析,然后逆向一些关键的函数和代码,在这些代码和函数中,找到可能存在的漏洞函数,拿缓冲区溢出漏洞来说,会分析strcpy、sprintf 、strcat、gets 诸如此类的函数,查看局部变量在拷贝字符串的时候是否对字符串的长度进行限制。但是比较少的对通过指针或者地址的拷贝字符串的方式进行分析,通过指针拷贝字符串也经常的会出现缓冲区溢出漏洞。接下来我将WR841n 设备中存在的三个缓冲区溢出的漏洞进行分析,记录,整理。所以这是一篇学习记录的文章。漏洞的披露链接在参考章节。
固件版本: 3.16.9 Build 150310(https://www.tp-link.com/vn/support/download/tl-wr841n/v10/#Firmware)
首先通过main 函数调用httpd() 和 httpBasicRpmInit() 函数对设备的http服务进行初始化,这个函数会将设备的一些功能进行初始化,并且路由器的相关http 功能处理的函数在这个函数中进行配置,初始化。
在httpd() 函数初始化的时候,会创建httpServerCreate()函数,来用以创建http Server,
在经过 httpServerCreate() -->sub_4F5CD0 --> httpDispatcher() 之后。会经过httpDispatcher()函数,这个函数会处理为各个不同的url 调用httpGenListFuncGet()函数进行函数注册绑定,以保证传入的request 请求数据包中的url 有对应的注册函数进行处理传入的对应数据包。
最终httpRpmConfAdd 函数会获取 request_url 对应的函数指针,然后调用函数。
具体的使用方式如httpPingIframeInit()函数。
该函数在遇到字符\、/、<、>"时添加字符\,或者如果下一个字符不是\n和\r,则添加<br>,当缓冲区满时进程将停止。
现在我们要考虑是的stringModify() 那里会被调用并可以传入字符串,查看交叉引用可以看到writepageParamSet()函数在调用。
然后继续查看writepageParamSet() 函数的交叉引用,可以看到在sub_45FA94() line 308 中传入v53 变量中的字符串。
在这个函数的line 240 会获取ssid 的值。然后将值复制给v53。
这个产生的原因 isAddrDispose()在处理ping_addr 的时候对ping value 长度的限制设置并没有起到效果,这种问题在缓冲区溢出中是很常见的,我们可以看到在 line28 行会对 ping value 的调用strlen 进行计算长度。这个长度的大小在于我们输入value 的大小而确定的,比如我输入一千多个字符,那么这个len_ping_addr 长度就是一千。
这就造成了在line 35 中并没有起到对输入字符长度起到任何的作用。在line 32~line 40 中是将ping value 的字符逐个传递给v23局部变量,而v23 定义的数据大小仅仅为52个字节 。因此会造成又一个buffer overflow
这个函数会在sub_44A530() 中进行处理,
当请求的url中是“ /userRpm/PingIframeRpm.htm ” 时,httpGetEnv() 会获取ping_addr 的value 。
然后回调用 isAddrDispose() 函数来处理 ping_addr 的value,也就是我们前面分析过程了。
前面我们知道了httpRpmConfAdd 函数会根据请求数据包的url 中的路径来确定调用相应的注册函数,在httpd初始化的时候,会把httpRpmFS() 函数和 url 的字符串"/loginFs/","/fs/" 进行绑定并注册函数。接下来分析httpRmpFs函数是如何处理请求URL 中带有"/loginFs/" 的数据包。
首先会函数的形参a1 是获取到的请求数据包,然后回获取到数据包的header 信息以及数据包的中的url,然后和/tmp/或者/web/文件路径进行拼接,判断是否是这两个文件夹中的文件,在判断的过程中,还做了过滤“..” ,以免请求的文件url 存在路径穿越的漏洞。
接下来程序会走到sub_4EE210函数中。
函数 sub_4EE210() 通过创建指向文件路径末尾的指针来查找文件扩展名之后,该点将向后移动,直到遇到“.”字符。最后,sub_4EE210() 会一个接一个地复制‘.’之后的所有字符,直到遇到空字节,复制的字符将更改为大写字母并保存到堆栈中。在我们的例子中,passwd 没有文件扩展名,指针向后移动,传递文件路径,到达保存的请求头区域,只有在遇到 Referer 部分的 ip 地址中的最后一个“.”时才停止,结果,将其复制到堆栈并覆盖保存的寄存器值之后的所有内容。 sub_4EE210() 完成后,这些值被弹回寄存器并导致程序崩溃。
我们来到函数sub_4EE2210() 中,这个本来是为了提取文件后缀的。但是由于首先会判断v2 的值是为空。我们知道v2 的值是 /tmp/loginfs/passwd ,接下来在line 21 获取文件路径的指针,然后一直往指针在往低地址移动,匹配是否有 “.” 。找到了之后就会把 "." 字符的下一个字符地址赋给v4。其实由于file_path 中是passwd ,因此没有 " . " 字符,因此会继续移动指针,会导致指针移动到 header 中 referer 中的 url中的 "."。因此会获取referer 中“.” 的下一个指针地址给v4。并且在line28 的循环中将后面的每个字符进行转成大写字母,然后写入到file_extension 从而造成了 buffer overflow。
在分析前面的漏洞的时候,看到获取ssid 的值,这一段代码中,strncpy 函数会造成缓冲区溢出的漏洞,因为在v22 将ssid 的值复制给v53 的过程中,复制的字符串的长度是由v21 进行设置的,而v21 字符的数量恰好是我们可以输入的。因此复制给v53的字符串我们可以自己控制,当输入的字符串长度超过了局部变量v53 分配的内存大小的收,就会造成缓冲区溢出的漏洞,和前面CVE-2022-30024 中ping_addr 是一样的。由于手头上没有这一款设备,因此如果有设备的师傅,希望能帮忙验证一下。
这三个漏洞的成因都是通过在指针拷贝和处理字符串的时候,并没有考虑内存的问题,比如CVE-2020-8423 漏洞在转义字符的之后,并没有对转义后的字符串进行长度的限制。在CVE-2022-3024漏洞中,ping_addr的长度限制没有固定,反而是由传入的参数进行计算。
https://blog.viettelcybersecurity.com/1day-to-0day-on-tl-link-tl-wr841n/
https://blog.viettelcybersecurity.com/tp-link-tl-wr940n-httpd-httprpmfs-stack-based-buffer-overflow-remote-code-execution-vulnerability/
C program 通过指针复制字符串
https://cloud.tencent.com/developer/article/1687616
end
招新小广告
ChaMd5 Venom 招收大佬入圈
新成立组IOT+工控+样本分析 长期招新