D-Link Dir-645 路由器溢出漏洞分析 参考链接 《揭秘家用路由器0day漏洞挖掘技术》漏洞分析笔记(二) :: Cougar — Blog (c0ug4r.top)
roberto.greyhats.it/advisories/20130801-dlink-dir645.txt
固件下载&分离 固件版本DIR645A1_FW103B11
下载地址: http://files.dlink.com.au/products/DIR-645/REV_A/Firmware/DIR645_FW103B11/DIR645A1_FW103B11.zip
分离固件 :
➜ 11 binwalk -e DIR645A1_FW103B11.bin ..... ➜ _DIR645A1_FW103B11.bin.extracted ls squashfs-root bin dev etc home htdocs include lib mnt proc sbin sys tmp usr var www
漏洞分析 该漏洞是CGI脚本在处理authentication.cgi
请求,来读取POST参数中的”password”参数的值时造成的缓冲区溢出
➜ squashfs-root find . |grep authentication.cgi ./htdocs/web/authentication.cgi ./htdocs/web/webfa_authentication.cgi
而authentication.cgi -> /htdocs/cgibin
根据漏洞描述可以找到authenticationcgi_main
函数,从而进行分析
首先是区分不同的操作,authentication.cgi => 0
REQUEST_METHOD = getenv("REQUEST_METHOD" ); memset (v60, 0 , sizeof (v60)); memset (v66, 0 , sizeof (v66)); memset (v57, 0 , sizeof (v57)); auth = divide_authentication(*argv);
接着判断REQUEST_METHOD
是否为GET
if ( !strcmp (REQUEST_METHOD, "GET" ) )
判断REQUEST_METHOD
是否为GET
if ( strcmp (REQUEST_METHOD, "POST" ) )
在POST方法中,读取内容
if ( !CONTENT_TYPE || !CONTENT_LENGTH || (CONTENT_LENGTH_INT = atoi(CONTENT_LENGTH), IO = fileno(stdin ), read(IO, CONTENT_BUF, CONTENT_LENGTH_INT) < 0 ) || (CONTENT_BUF[CONTENT_LENGTH_INT] = 0 , Get_HTTP_COOKIE((int )v66) < 0 ) ) { LABEL_51: v9 = 5 ; goto LABEL_96; }
这里可以看到,CONTENT_LENGTH_INT
来自我们传入的内容而非系统指定, 则read(IO, CONTENT_BUF, CONTENT_LENGTH_INT)
可能造成溢出
LABEL_96
处进行返回包内容的判断,v9等于{\"RESULT\": \"FAIL\", \"REASON\": \"ERR_GET_UENTRY\"}
接着对CONTENT_BUF的内容进行判读,判断是否存在id=
或password=
,存在则进行读取
haystack = CONTENT_BUF; dest = (char *)v66; point2id_password = (const char **)&::point2id_password; for ( i = 0 ; i != 2 ; ++i ) { v24 = *point2id_password; v25 = strstr (haystack, *point2id_password); v26 = &v25[strlen (v24)]; v27 = v26; while ( 1 ) { v28 = *v27; if ( v28 == '&' ) break ; ++v27; if ( !v28 ) { --v27; break ; } } v29 = v27 - v26; if ( i ) { if ( i != 1 ) goto LABEL_51; strncpy ((char *)&v66[32 ], v26, v27 - v26); *((_BYTE *)&v66[32 ] + v29) = 0 ; } else { strncpy (dest, v26, v27 - v26); *((_BYTE *)v66 + v29) = 0 ; } ++point2id_password; }
这里可以看到strncpy
出27 - 26
这个长度实际也是可以控制进行溢出的, 但从v66
溢出到$ra
太远,可能影响其他寄存器导致程序奔溃
从上我们可以根据分析得到如下攻击思路
动态分析 根据上述漏洞分析,我们首先需要确定偏移量
➜ squashfs-root python3 patternLocOffset.py -c -l 1160 -f offset [*] Create pattern string contains 2000 characters ok! [+] output to offset ok! [+] take time: 0.0016 s
使用 2000,发现会覆盖$a1
后导致程序崩溃,于是减少长度到 1160 调试脚本
#!/bin/bash INPUT="$1 " PORT="23946" LEN=$(echo -n "$INPUT " | wc -c) cp $(which qemu-mipsel-static) ./qemu echo $INPUT | chroot ./ ./qemu -E CONTENT_LENGTH=$LEN -E CONTENT_TYPE="application/x-www-form-urlencoded" -E REQUEST_METHOD="POST" -E REQUEST_URI="/authentication.cgi" -E REMOTE_ADDR="127.0.0.1" -g $PORT /htdocs/web/authentication.cgirm -rf ./qemu
计算得偏移为1050
➜ squashfs-root python3 patternLocOffset.py -s 0x42316A42 -l 1160 [*] Create pattern string contains 1160 characters ok! [*] No exact matches, looking for likely candidates... [+] Possible match at offset 1053 (adjusted another-endian) [+] take time: 0.0003 s
且栈布局为
padding:1014 $s0~$s7 $fp $ra
ROP链构造 与D-Link DIR-815 路由器多次溢出漏洞分析 | Lantern’s 小站 相同
其他 该固件多个地方存在漏洞,详情查看roberto.greyhats.it/advisories/20130801-dlink-dir645.txt