美文网首页
ROP骚操作总结

ROP骚操作总结

作者: cceb9d5a8577 | 来源:发表于2018-07-07 18:39 被阅读165次

    0x01

    如果给的二进制文件采取的是静态连接,就可以直接通过ROPgadget 来直接构造ropchain
    命令为 ROPgadget --binary rop(文件名) --ropchain,比如hackme中pwn的rop那道题目就是这样,直接可以用这个命令生成rop链从而直接getshell,不过需要注意的是如果用这种方法则需要在py脚本中加上

    from struct import pack  
    

    其实通过看它生成的ROP链大概也是能猜出是用了systemcall的方法



    这个方法的好处是可以一梭子搞定exp不用自己想,但是局限性太大了,基本上只有弱智题才会这样用静态链接的,所以常规的操作还是自己撸代码好一点,下面就是自己用systemcall方法写的exp:


    0x02

    如果用rop进行systemcall的操作,那必定要用到系统中断号:int 0x80,所以我们在想要用这种方法的时候,先用ROPgadget查找一下有没有这个gadget,如果没有果断放弃,另想其他操作

    0x03

    最常规的rop,就是利用像pop。。。。ret这样的gadget都是用来写入数据到寄存器的

    pop reg + ret
    pop reg + pop reg + ret
    pop reg + pop reg + pop reg + ret

    写入数据到内存:
    mov [reg],reg + ret
    mov [reg+xxx],reg + ret

    调用函数,跳转函数
    jmp xxx + ret
    call xxx + ret
    int 0x08
    leave + ret(在进行栈迁移的时候会用到的gadget)

    算数,逻辑运算
    add reg,reg + ret
    and reg,reg + ret
    xor reg1,reg2 + ret#reg1与reg2进行异或运算,结果存入reg1中
    xchg reg1,reg2 + ret#交换reg1和reg2的内容
    注意异或运算xor有个有趣的地方:
    1、如果xor自身则是将寄存器清空为零,
    2、仅仅xor就可以实现reg间的写入操作:
    用一个xor自身清空寄存器A,接着让寄存器B去xor寄存器A,把结果存在寄存器A,就相当于把B赋值給A,这样不需要mov或者pop就实现了寄存器间的值传递

    0x04

    使用one_gadget 工具可以一梭子getshell

    one-gadget RCE 是在 libc 中存在的一些执行 execve('/bin/sh', NULL, NULL) 的片段。当我们知道 libc 的版本,并且可以通过信息泄露得到 libc 的基址,则可以通过控制 EIP 执行该 gadget 来获得 shell。这个方法的优点是不需要控制调用函数的参数,在 64 位程序中,也就是 rdi、rsi、rdx 等寄存器的值。

    可以使用工具 one_gadget 很方便地查找 one-gadget

    如果给出了lib文件,就可以直接用命令:one_gagdet [libc库]
    找到相对应的一梭子getshell函数
    如果没有给出,则需要通过泄漏出的libc基址偏移,然后在https://libc.blukat.me/?q=puts%3Ae140&l=libc6-i386_2.23-0ubuntu10_amd64中找到对应的libc版本,从而使用one_gadget

    0x05

    libc_scu_init gadget
    有的时候在64位的程序中,我们需要控制rdi,rsi,rdx寄存器去控制函数的参数,尤其是一些像write(),read()这样的三参数函数,我们就需要用到一波特殊的gadget:

    libc_csu_init中我们主要利用了以下寄存器

    利用尾部代码控制了rbx,rbp,r12,r13,r14,r15。
    利用中间部分的代码控制了rdx,rsi,edi。
    通常这样构造的rop链也特别的长,所以一般写成封装函数,调用的时候比较方便

    def csu(rbx, rbp, r12, r13, r14, r15, last):
        # pop rbx,rbp,r12,r13,r14,r15
        # rbx should be 0,
        # rbp should be 1,enable not to jump
        # r12 should be the function we want to call
        # rdi=edi=r15d
        # rsi=r14
        # rdx=r13
        payload = 'a' * 0x80 + fakeebp  #填充垃圾字符串
        payload += p64(csu_end_addr) + p64(rbx) + p64(rbp) + p64(r12) + p64(
            r13) + p64(r14) + p64(r15)
        payload += p64(csu_front_addr)
        payload += 'a' * 0x38
        payload += p64(last)
        sh.send(payload)
        sleep(1)
    

    0x06

    srop

    如果想进行syscall的操作,但是又没有找到int 0x80 的系统中断gadget,那么就可能是需要用到srop这个操作了:
    简单的说,srop是利用一个sigreturn系统调用进行操作的,进程在调用sigreturn的时候会保存现场(各个寄存器的值)到用户的栈里面,执行完后,又会从栈里面取出之前存入的那一份数据,从而恢复各个寄存器的值,这里我们可以构造一个假的数据扔进栈,然后再调用sigreturn,从而达到操控程序执行流程的目的

    32位的sigreturn的调用号为77,64位的系统调用号为15。

    原理理解不算很难,重在于实际的操作,下面一些的学习博客:
    http://www.freebuf.com/articles/network/87447.html
    https://ctf-wiki.github.io/ctf-wiki/pwn/stackoverflow/advanced_rop/#srop

    相关文章

      网友评论

          本文标题:ROP骚操作总结

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