Pwn学习随笔( 七 )

  • got //查看got表
  • hexdump //像IDA那样显示数据 , 带字符串
  • Return Oriented Programming缓冲区溢出攻击的普遍发生给计算机系统造成了许多麻烦 。现代的编译器和操作系统实现了许多机制,以避免遭受这样的攻击,限制入侵者通过缓冲区溢出攻击获得系统控制的方式 。
    【Pwn学习随笔】Performing code-injection attacks on program RTARGET is much more difficult than it is for CTARGET, because it uses two techniques to thwart such attacks:
    • It uses randomization so that the stack positions differ from one run to another. This makes it impossible to determine where your injected code will be located. 开启了PIE 保护(栈随机化)
    • It marks the section of memory holding the stack as nonexecutable, so even if you could set the program counter to the start of your injected code, the program would fail with a segmentation fault. 开启了NX保护(栈中数据不可执行)
    • 此外,还有一种栈保护 , 如果栈中开启Canary found,金丝雀值,在栈返回的地址前面加入一段固定数据,栈返回时会检查该数据是否改变 。那么就不能用直接用溢出的方法覆盖栈中返回地址,而且要通过改写指针与局部变量、leak canary、overwrite canary的方法来绕过
    The strategy with ROP is to identify byte sequences within an existing program that consist of one or more instructions followed by the instruction ret. Such a segment is referred to as a gadget
    ROPgadget
    ROP是用来绕过NX保护的,开启 NX 保护的话,栈、堆的内存空间就没有执行权限了,直接向栈或者堆上直接注入代码的攻击方式就无效了 。
    ROP的主要思想是在栈缓冲区溢出的基础上,利用程序中已有的小片段 (gadgets) 来改变某些寄存器或者变量的值,从而控制程序的执行流程 。所谓 gadgets 就是以 ret 结尾的指令序列,通过这些指令序列 , 我们可以修改某些地址的内容,方便控制程序的执行流程 。
    ROP 攻击一般得满足如下条件
    • 程序存在溢出,并且可以控制返回地址 。
    • 可以找到满足条件的 gadgets 以及相应 gadgets 的地址 。
    • 如果 gadgets 每次的地址是不固定的 , 那我们就需要想办法动态获取对应的地址了 。‘
    ROP其实就是利用已存在的代码执行出我们想要的效果,如下图所示,分为多个gadget,每一个gadget都是一段指令序列,最后以ret指令(0xc3)结尾 , 多个gadget中的指令形成一条利用链,一个gadget可以利用编译器生成的对应于汇编语言的代码,事实上,可能会有很多有用的gadgets,但是还不足以实现一些重要的操作,比如正常的指令序列是不会在ret 指令前出现pop %edi指令的 。幸运的是,在一个面向字节的指令集,比如x86-64,通常可以通过从指令字节序指令的其他部分提取出我们想要的指令 。
    Pwn学习随笔

    文章插图
    下面举个例子来详细说明ROP与之前的Buffer overflow有什么区别,我们不关心栈地址在哪,只需要看有没有可以利用的指令
    我们可以在程序的汇编代码中找到这样的代码:
    0000000000400f15 <setval_210>:400f15: c7 07 d4 48 89 c7 movl $0xc78948d4,(%rdi)400f1b: c3 retq这段代码的本意是
    void setval_210(unsigned *p){*p = 3347663060U;}这样一个函数,但是通过观察我们可以发现,汇编代码的最后部分:48 89 c7 c3又可以代表
    movq %rax, %rdiret这两条指令(指令的编码可以见讲义中的附录) 。
    第1行的movq指令可以作为攻击代码的一部分来使用,那么我们怎么去执行这个代码呢?我们知道这个函数的入口地址是0x400f15 , 这个地址也是这条指令的地址 。我们可以通过计算得出48 89 c7 c3这条指令的首地址是0x400f18,我们只要把这个地址存放在栈中 , 在执行ret指令的时候就会跳转到这个地址,执行48 89 c7 c3编码的指令 。同时 , 我们可以注意到这个指令的最后是c3编码的是ret指令,利用这一点 , 我们就可以把多个这样的指令地址依次放在栈中,每次ret之后就会去执行栈中存放的下一个地址指向的指令 , 只要合理地放置这些地址,我们就可以执行我们想要执行的命令从而达到攻击的目的 。

    推荐阅读