Linksys WRT54G路由器溢出漏洞分析——运行环境修复

Linksys WRT54G路由器溢出漏洞分析——运行环境修复

1-、漏洞介绍

Linksys WRT54G是一款SOHO无线路由器,在功能、稳定性、双天线信号覆盖能力方面都得到了用户的认可。它还支持第三方固件,从而使其功能更加强大。

Linksys WRT54G v2版本的路由器曝出过一个漏洞,CVE编号为CVE-2005-2799。该漏洞存在于路由器Web服务器程序HTTPDapply.cgi处理脚本中,由于对发送的POST请求没有设置足够的边界与内容长度检查,当未经认证的远程攻击者向路由器的apply.cgi页面发送内容长度大于10000字节的POST请求时,就可以触发缓冲区溢出。这个漏洞会允许未经认证的用户在受影响的路由器上以root权限执行任意命令。

 

2WRT54G固件漏洞研究

2.1 WRT54G httpd服务器模糊测试:

firmadyne许你还能运行路由器防火墙,使用burpesuite测试apply.cgi请求可以导致httpd服务崩溃。说明该请求存在bug

配置好参数后,点击start attack开始攻击,在攻击串超过10000httpd服务器崩溃。

 

 

2.2 修复运行环境

当我们使用模拟器(QEMU)运行路由器中的Web服务器时,遇到一个问题——模拟器缺乏硬件的模拟,导致程序无法执行。而需要执行的Web服务器就是应用程序试图采用NVRAM中的信息来配置参数,但由于找不到设备导致了错误的发生。在路由器中,常见的NVRAM动态库libnvram.so提供了nvram_get()函数和nvram_set()函数来获取和设置配置参数。入股使用模拟器运行应用程序,会在调用nvram_get()函数时失败,导致应用程序无法运行(因为模拟器中没有NVRAM)。使用如下命令运行HTTPD

 

在运行的过程中可以看到,程序报错,提示找不到/dev/nvram文件或目录,且实用netstat命令查看当前系统开放的端口时没有发现80端口,Web服务器启动失败。

2.2.1修复NVRAM

使用zcutlip的一个nvram-faker来修复NVRAMNvram-faker虽然是一个简单的动态库,但可以使用LD_PRELOAD劫持libnvram库中的函数调用。只需要向一个ini的配置文件中写出合理的NVRAM配置,就可以使Web服务器程序运行。

2.2.2 修改nvram-faker增加劫持函数

原始fork函数会启动很多子进程导致程序调试复杂,所以需要劫持它,简化调试。

增加劫持get_mac_from_ip,修改nvram-faker.h文件添加fork函数;

修改nvram-faker.c添加fork\get_mac_from_ip函数。

2.2.3 编译nvram-faker

编译好之后,会在/nvram-faker目录下生成一个名为libnvram-faker.so的动态库。然后将libnvram-faker.so和同目录下的nvram.ini复制到WRT54G路由器的根文件系统中。由于libnvram-faker.so使用了共享库编译,所以还需要将mipsel-linux-gcc交叉编译环境中lib库下的libgcc_s.so.1复制到WRT54G路由器的根文件系统中。

2.2.4 修复HTTPD执行环境

HTTPD在运行时需要对/var目录下的某些文件进行操作,而这些文件是在Linux启动过程中才会产生的,因此编写了prepare.sh脚本修改HTTPD执行环境。

编写run_cgi.sh脚本提供两种方法执行HTTPD,一种是不需要调试器介入直接运行程序的执行模式,另一种是开放1234调试接口等等调试器链接。在QEMU环境中模拟执行HTTPD时,使用LD_PRELOAD环境变量加载libnvram-faker.so劫持函数调用,修复因硬件缺失导致的运行错误。

 

2.3 漏洞成因分析

运行prepare.sh脚本,修复HTTPD执行环节;

使用run_cgi.sh脚本调试模式执行HTTPD,等待调试器链接;

使用IDA加载HTTPD,进行远程附加调试。待HTTPD服务器开启后,在Windows下运行测试脚本wrt54g-test.py

可以看到,Ubuntu中的HTTPD程序已经崩溃了。阅读崩溃部分的代码,发现程序希望将0写入0x41419851(0x41414141+0x5710)处时造成错误。其原因是:系统找不到0x41419851这块内存,而0x41414141是我们发送的伪造数据,0x5710正好是伪造的POST参数的总长度。

从汇编代码中可以看到,崩溃现场在do_apply_post函数的代码段中。从命令上可以知道,该函数的功能是处理applyPOST参数。

下面,我们看一下崩溃现场附近的代码,分析造成漏洞的真正原因,

do_apply_post函数偏移0x3C处的伪代码如下:

 

读取长度为content-length的所有POST数据到post_buf,如果读取的POST数据长度不为0,就计算post_buf中数据的长度。

这里的content-lengthPOST参数的长度,在调用do_apply_post函数时并没有进行校验,而该长度在使用读取数据进入内存时也没有进行校验就直接都去了POST参数,因此导致了缓冲区溢出。

而产生缓冲区溢出的内存post_buf位于HTTPD.data段中。在应用程序中,.data段用于存放已初始化的全局变量,这里的post_buf大小为0x2710字节(10000字节)。

现在我们已经弄清楚了漏洞的原理。该漏洞在接收超过10000字节的来自攻击者伪造的数据包时,由于在do_apply_post函数调用前后没有验证POST数据的长度,而在do_apply_post函数中使用了自定义的wfread()函数,并调用了fread()系统函数,直接将伪造的超长POST数据全部富之岛大小为10000字节的全局变量post_buf中,所以导致了缓冲区溢出。

 

2.4 漏洞利用

生成POCwrt54g_POC.py

利用流程:

01 打开网页,访问网关(路由器)。网关是192.168.1.1,浏览器访问192.168.1.1,登录WRT54G路由器,在首页上可以看到当前路由器的型号和固件版本。

02 使用nc命令在192.168.1.100上打开4444端口监听,命令为”nc -lp 4444”。

03 执行测试脚本,命令为”wrt54g_POC.py 192.168.1.1”。

04 控制路由器,执行任意命令。

猜你喜欢

转载自blog.csdn.net/weixin_40602516/article/details/80958646