ret2xx
随着NX保护的开启,以往直接向栈或者堆上直接注入代码的方式难以继续发挥效果。所以攻击者们也提出来相应的方法来绕过保护,目前主要是ROP(Return Oriented Programming),其主要思想是在栈缓冲区溢出的基础上,利用程序中已有的小片段(gadgets)来改变某些寄存器或者变量的值,从而控制程序的执行流程。所谓gadgets就是以ret结尾的指令序列,通过这些指令序列,我们可以修改某些地址的内容,方便控制程序的执行流程。
之所以称之为ROP,是因为核心在于利用了指令集中的ret指令,改变了指令流的执行顺序。
ROP攻击一般得满足如下条件:
1、程序存在溢出,并且可以控制返回地址
2、可以找到满足条件的gadgets以及相应的gadgets的地址
如果gadgets每次的地址是不固定的,那我们就需要想办法动态获取对应的地址了。
ret2text
即控制程序的执行程序本身已有的代码(.text)。这种攻击方法是一种笼统的描述。我们控制执行程序已有的代码的时候也可以控制程序执行好几段不相邻的程序已有的代码(也就是gadgets),这就是我们所要说的ROP。
构造payload
32位
padding+覆盖ebp(比如'b'*4)+覆盖返回地址(比如已有的ret system_plt或者是后门函数)+函数调用的返回地址(随便一个或者返回主函数)+system函数的参数(ptr_binsh)
64位
成因和32位的一致,利用思路也一致。
区别:64位函数调用传参先使用寄存器(依次为rdi,rsi,rdx,rcx,r8,r9)当参数超过6葛时再使用栈。
思路:覆盖返回地址为system_plt,并根据64位的参数传递规则设置参数/bin/sh
如何设置rdi指向binsh?
可以使用pop rdi;ret 代码片段设置rdi
如何找到pop rdi;ret?
可以使用工具ropper帮助寻找gadget
ret2shellcode
即控制程序执行shellcode代码。shellcode指的是用于完成某个功能的汇编代码,常见的功能主要是获取目标系统的shell。一般来说,shellcode需要我们自己填充。这其实是另外一种典型的利用方法,即此时我们需要自己去填充一些可执行的代码。
ret2syscall
即控制程序执行系统调用,获取shell
gets函数存在栈溢出,且长度没有限制,直到读到0x0A。但是,程序中没有backdoor、system函数、/bin/sh字符串
思路:由于是静态编译程序会存在int 0x80,可以使用中断调用系统函数
1、read(0,bss+0x100,8)读入/bin/sh
2、execve(bss+0x100,0,0)getshell
为了实现上面的调用需要寻找gadget
1、int 0x80;ret
2、pop eax;ret
3、pop ebx;ret
4、pop ecx;ret
5、pop edx;ret
对于静态生成的程序可以使用ropper和ROPgadget来直接生成ropchain
ropper --file 文件 --chain execveropper --file 文件 --chain execve (推荐)
ROPgadget --binary 文件 --ropchain
ret2libc
即控制函数去执行libc中的函数,通常是返回至某个函数的plt处或者函数的具体位置(即函数对应的got表项的内容)。一般情况下,我们会选择执行system("/bin/sh"),故而此时我们需要知道system函数的地址。
ret2csu
在64位程序中,函数的前6个参数是通过寄存器传递的但是大多时候,我们很难找到每一个寄存器对应的gadgets。这个时候,我们可以利用x64下的_libc_csu_init
中的gadgets。这个函数是用来对libc进行初始化操作的,而一般的程序都会调用libc函数,所以这个函数一定会存在。
总结
ret2xx是根据ROP的gadgets的来源进行分类
1、ret2text是利用程序本身的gadgets
2、ret2shellcode是利用输入的shellcode
3、ret2syscall是利用syscall的gadgets
4、ret2libc是利用libc当中存在的gadgets
5、ret2csu是程序编译时存在的gadget