Ret2text漏洞是一种攻击技术,它通过覆盖函数的返回地址,使程序的执行流跳转到程序自身的可执行文本段中预设的“gadgets”代码片段,以此绕过某些安全机制并执行攻击者的代码。
前提知识
什么是ret2text
ret2text,即return to text,意思是劫持函数返回地址为程序本身就有的代码(.text),进而控制程序执行后门函数,拿到shell。
strcpy函数溢出
当源字符串的长度大于目标缓冲区时,
strcpy函数会复制整个源字符串,导致栈溢出。strcpy函数原型
char* strcpy(char* destination,const char* source); |
ret2text题目类型
第一种是直接劫持返回地址为system("/bin/sh")的地址。
第二种比第一种稍微复杂了一些,虽然有system函数但是参数不是我们想要的 ,而在程序的其他地方也能找到/bin/sh字符串。这时就需要利用一些gadget给system函数传参。而64位程序和32位程序二者的传参方式也不同。
64位程序和32位程序在函数传参上的不同
32位程序函数传参时,使用栈来传递参数(如_cdecl和_stdcall),参数从右往左压入栈,然后执行call指令跳转到要执行的函数的位置。因此我们攻击时只需构造一个栈结构即可。
64位程序函数传参时,先使用寄存器来存储参数,一共有6个存放参数的寄存器分别为rdi,rsi,rdx,rcx,r8,r9,当参数大于6个时多余的参数才通过栈传递。
gadget
gadget通常是以ret结尾的指令序列,如pop rdi ; ret,用于设置寄存器的值。在这里,我们用pop rdi ; ret把/bin/sh放入rdi寄存器中。
例题
例题1:buu jarvisoj_level0
拿到题目后先checksec level0命令检查一下保护,PIE和canary都没开,开了NX(堆栈不执行)保护。该程序为64位。
canary保护:函数开始执行的时候会先往栈里插入canary值,当函数真正返回的时候会验证canary值是否合法,如果不合法就停止程序运行。可以防止栈溢出覆盖返回地址。

定义数组buf[128],read函数读取,且0x200uLL大于128,可以栈溢出。通过下图

计算偏移量,为0x80+8


该题是第一种类型,直接溢出并劫持返回地址为system函数地址0x400596,即可。

最后exp
from pwn import * |
得到flag

例题2:buu jarvisoj_level2_x64
拿到题目后先检查一下保护,PIE和canary都没开,开了NX。

把题目放入ida里,查看

定义了一个数组buf[128],有read函数0x200uLL明显大于128,可以栈溢出。计算偏移量,为0x80+8

有system函数还是两个,但是参数都不是我们想要的。再查看一下字符串(shift+F12)


很好,有/bin/sh点进去查看地址,为0x600a90,随便选一个system的地址为0x400603

我们要做的就是通过pop rdi;ret把/bin/sh传参给system函数,通过ROPgadget --binary level2_x64 | grep "pop rdi"命令得到pop rdi ; ret地址,如下

最后exp
from pwn import * |
得到flag。

例题3:buu jarvisoj_level2
前面几步都同上,我就不再多说。
如下,system的地址0x0804849e,偏移量0x88+4


|
得到flag。
