RealWorld CTF 5th ShellFind 分析

2023-01-27 12:00:56

前言

RealWorld CTF 5th 裡的一道iot-pwn,根據真實裝置韌體改編而成,覺得題目貼近iot實戰且很有意思,故在此記錄一下復現過程。

題目分析

題目描述

Hello Hacker.
You don't know me, but I know you.
I want to play a game. Here's what happens if you lose.
The device you are watching is hooked into your Saturday and Sunday.
When the timer in the back goes off,
your curiosity will be permanently ripped open.
Think of it like a reverse bear trap.
Here, I'll show you.
There is only one UDP service to shell the device.
It's in the stomach of your cold firmware.
Look around Hacker. Know that I'm not lying.
Better hurry up.
Shell or out, make your choice.

從中可以看出漏洞大概率存在於UDP服務中。

韌體分析

拿到手的是一個bin包,解壓出來可以得到一個完整的檔案系統。相比於常規pwn題單一的二進位制而言,我們首先要做的是尋找漏洞檔案。既然是真實裝置改編那我們就可以先在網上找一找官方韌體並嘗試下載最新版本。

下載到官方的韌體後,可以採取bindiff等方法去找被修改過的二進位制檔案。可以初步判定漏洞應該是出在ipfind程式中。

並且發現此韌體為mips大端,且可疑漏洞檔案沒開保護。

韌體模擬

我是直接用qemu去模擬的這個韌體,當然也可以嘗試用FirmAEfirmadynefirmware-analysis-plus等工具去進行模擬。我的qemu啟動指令碼如下:

sudo ifconfig ens33 down
sudo brctl addbr br0
sudo brctl addif br0 ens33
sudo ifconfig br0 0.0.0.0 promisc up
sudo ifconfig ens33 0.0.0.0 promisc up
sudo dhclient br0
sudo tunctl -t tap0
sudo brctl addif br0 tap0
sudo ifconfig tap0 0.0.0.0 promisc up
sudo ifconfig tap0 192.168.2.100/24 up
sudo 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,macaddr=00:16:3e:00:00:01 \
    -net tap,ifname=tap0,script=no,downscript=no \
    -nographic

啟動完成之後用scp把韌體包、gdbserver、完整的busybox等傳上去。之後用如下命令切換到韌體包根目錄進行操作:

mount -t proc /proc ./squashfs-root/proc
mount -o bind /dev ./squashfs-root/dev
chroot ./squashfs-root/ sh

之後通過/etc/rc.d/rcS初始化服務。

啟動完成之後通過./busybox-mips netstat -pantu去檢視開放的埠及對應的二進位制檔案。

可以看到我們之前分析的可疑檔案ipfind正是UDP服務。

值得注意的是我們用ps去檢視程序發現執行的是/usr/sbin/ipfind br0這個命令,但我qemu的有效網路卡是eth0,這樣以後我們會發現無法使用gdbserver進行偵錯,故我們要殺死該程序,並執行/usr/sbin/ipfind eth0 &,這樣我們就可以使用gdbserver進行愉快的偵錯了。

漏洞檔案分析

首先是建立socket通訊並繫結到62720埠,與剛才看到的埠一致。

接著從client端接收資料,並進行一系列的操作。之後會對資料進行一個判斷,以此來確定是否進入sub_40172C函數sub_4013F4函數

sub_40172C函數

想進入這個函數我們可以逆出來他所需接受的內容開頭應該為:

header1 = b"FIVI"
header1+= b"\x00\x00\x00\x00"
header1+= b"\x0A\x01\x00\x00"
header1+= b"\x00\x00\x00\x00"
header1+= b"\x00"
header1+= b"\xFF\xFF\xFF\xFF\xFF\xFF"
header1+= b"\x00\x00"
header1+= b"\x00\x00\x00\x00"

這個函數會呼叫sub_400E50得到net_get_hwaddr(ifname, a1 + 17),實際上就是mac addrqemu啟動時可以進行設定,之後列印出來對比一下即可),並把它傳送到client端。這個值對於我們進入第二個函數必不可少。

sub_4013F4函數

想進入這個函數我們可以逆出來它所需接受的內容開頭應該為:

header2 = b"FIVI"
header2+= b"\x00\x00\x00\x00"
header2+= b"\x0A\x02\x00\x00"
header2+= b"\x00\x00\x00\x00"
header2+= b"\x00"
header2+= mac
header2+= b"\x00\x00"
header2+= b"\x8E\x00\x00\x00"

進入這個函數後,我們即可找到我們的漏洞函數sub_400F50,這個函數有兩次base64 decode,第二次解碼時會發生緩衝區溢位。

漏洞利用

因為沒開保護,我們佈置好rop跳到shellcode上即可。但是我們由於沒有libc地址,我們需要花費一定時間在ipfind這個檔案裡去找gadgets進行利用。

我們想要跳轉到shellcode上執行,那麼我們就需要可以洩露棧地址的gadget,於是我們找到了如下的gadget來洩露棧地址:

.text:004013D0 sub_4013D0:                              # CODE XREF: sub_4013F4+9C↓p
.text:004013D0                                          # sub_4013F4+160↓p ...
.text:004013D0
.text:004013D0 var_8           = -8
.text:004013D0 arg_4           =  4
.text:004013D0 arg_8           =  8
.text:004013D0 arg_C           =  0xC
.text:004013D0
.text:004013D0                 addiu   $sp, -0x10
.text:004013D4                 sw      $a1, 0x10+arg_4($sp)
.text:004013D8                 sw      $a2, 0x10+arg_8($sp)
.text:004013DC                 sw      $a3, 0x10+arg_C($sp)
.text:004013E0                 addiu   $v0, $sp, 0x10+arg_4
.text:004013E4                 sw      $v0, 0x10+var_8($sp)
.text:004013E8                 addiu   $sp, 0x10
.text:004013EC                 jr      $ra
.text:004013F0                 nop

這個gadget可以控制v0為棧地址,我們向上交叉參照找到一個既能控制ra又不改變v0gadget下:

.text:00401F98                 jal     sub_4013D0
.text:00401F9C                 li      $a0, aCanTGetHelloSo  # "Can't get hello socket\n"
.text:00401FA0                 b       loc_4020B4
.text:00401FA4                 nop

.text:004020B4 loc_4020B4:                              # CODE XREF: sub_401DF4+1AC↑j
.text:004020B4                                          # sub_401DF4+238↑j ...
.text:004020B4                 lw      $ra, 0x7C+var_s8($sp)
.text:004020B8                 lw      $s1, 0x7C+var_s4($sp)
.text:004020BC                 lw      $s0, 0x7C+var_s0($sp)
.text:004020C0                 jr      $ra
.text:004020C4                 addiu   $sp, 0x88

但是在走這條gadget之前我們得先恢復gp暫存器,並且還要考慮到a1,a2,a3暫存器對棧的影響,最好可以控制為nop指令,以免對剛才洩露出來的棧地址上指令造成影響。

.text:00401218                 lw      $gp, 0x9C+var_8C($sp)
.text:0040121C                 la      $t9, close
.text:00401220                 jalr    $t9 ; close
.text:00401224                 move    $a0, $s0         # fd
.text:00401228                 move    $v0, $zero
.text:0040122C
.text:0040122C loc_40122C:                              # CODE XREF: sub_401120+80↑j
.text:0040122C                                          # sub_401120+A0↑j
.text:0040122C                 lw      $ra, 0x9C+var_s8($sp)
.text:00401230                 lw      $s1, 0x9C+var_s4($sp)
.text:00401234                 lw      $s0, 0x9C+var_s0($sp)
.text:00401238                 jr      $ra
.text:0040123C                 addiu   $sp, 0xA8

接著可以找到如下gadget使得可以跳轉到S0暫存器存指向的地址中:

.text:004027C0 loc_4027C0:                              # CODE XREF: sub_402790+3C↓j
.text:004027C0                 jalr    $t9
.text:004027C4                 nop
.text:004027C8
.text:004027C8 loc_4027C8:                              # CODE XREF: sub_402790+28↑j
.text:004027C8                 lw      $t9, 0($s0)
.text:004027CC                 bne     $t9, $s1, loc_4027C0
.text:004027D0                 addiu   $s0, -4
.text:004027D4                 lw      $ra, 0x1C+var_s8($sp)
.text:004027D8                 lw      $s1, 0x1C+var_s4($sp)
.text:004027DC                 lw      $s0, 0x1C+var_s0($sp)
.text:004027E0                 jr      $ra
.text:004027E4                 addiu   $sp, 0x28

最後找一個可以把v0賦給任意地址,並且可以控制s0gadget即可:

.text:00400F28                 sw      $v0, 0xD($s0)
.text:00400F2C
.text:00400F2C loc_400F2C:                              # CODE XREF: sub_400E50+CC↑j
.text:00400F2C                 la      $v0, ifname
.text:00400F30                 lw      $a0, (ifname - 0x413138)($v0)
.text:00400F34                 la      $t9, net_get_hwaddr
.text:00400F38                 jalr    $t9 ; net_get_hwaddr
.text:00400F3C                 addiu   $a1, $s0, 0x11
.text:00400F40                 lw      $ra, 0x20+var_s4($sp)
.text:00400F44                 lw      $s0, 0x20+var_s0($sp)
.text:00400F48                 jr      $ra
.text:00400F4C                 addiu   $sp, 0x28

exploit效果

完整exploit見:https://github.com/fxc233/CTF/blob/main/IOT/RealWorldCTF-5th-ShellFind/exp.py

參考文章

https://mp.weixin.qq.com/s/Wb7SMy8AHtiv71kroHEHsQ

文章首發:ChaMd5 微信公眾號