D-LINK-DIR815栈溢出分析
前言
D-LINK DIR645/DIR815都存在的一个洞,这里选择815的固件进行分析。
漏洞分析
下载固件,binwalk解压,定位到hedwig.cgi,发现是个符号链接指向cgibin,把该文件拷出分析。
main函数根据启动时的参数确定,形如./cgibin /hedwig.cgi
的启动方式对应进入hedwigcgi_main的处理逻辑。
1 | int __cdecl main(int argc, const char **argv, const char **envp) |
hedwigcgi_main是漏洞存在的函数,其获取数据的方式基本都是通过getenv从环境变量中获取,比如REQUEST_METHOD
这个字段,这点和我们之前遇到的httpd通过http请求不同。
继续往下看,需要校验REQUEST_METHOD=POST
,通过sess_get_uid函数获取环境变量中的uid保存到v6,在sess_get_uid函数中需要给出HTTP_COOKIE
和REMOTE_ADDR
,所有通过环境变量获取的字符串会通过sobj_add_string
拼接起来返回给上层函数.
sprintf不会限制拷贝的字节数,输入过长的uid造成栈溢出。之后需要创建一个/var/tmp/temp.xml
文件且赋予可写权限,在下面还有一个sprintf存在溢出,这里我们只拿第一个做利用。
1 | int hedwigcgi_main() |
1 | int __fastcall sess_get_uid(int a1) |
漏洞利用
sprintf函数以零字节为截断符,cgibin的代码段地址为0x0040xxxx,高位必然存在零字节截断,因而无法通过代码段构造rop,这里模拟真机环境下的无地址随机化,使用用户态的qemu-mipsel-static启动固件。假如可以拿到真机,开放ssh服务,通过gdbserver+gdb即可调试真机,cgibin的固件地址可以通过gdb调试得到(系统关闭随机化)。
1 | #/bin/bash |
首先需要确定溢出的偏移,在gdb调试到sprintf时使用cyclic 2000
生成payload,set {char [2002]} 0x42e0d8 = ""
将目标地址的内容强制修改为cyclic字符串,最后使用cyclic -l 61616c6b
确定偏移为1043.
观察函数退出时的汇编,可以控制s0-s7,fp和ra。
1 | .text:00409A28 lw $ra, 0x4E4($sp) |
寻找可控参数寄存器a0/a1/a2
的寄存器,找到#0x00022760 : move $t9, $s1 ; move $a0, $s5 ; move $a1, $zero ; move $a2, $zero ; jalr $t9 ; move $a3, $s6
这样一个完美的gadget,由于system函数末尾为零字节,改为调用execve函数。system函数会启动一个新进程,保留旧进程;而execve函数拿bash进程替换原进程。
exp.py
1 | #coding=utf-8 |