首页 > 安全 > 网络安全 > 正文
逆向安全系列:Use After Free漏洞浅析
2017-01-12       个评论      
收藏    我要投稿

一、前言

逆向安全系列:Use After Free漏洞浅析。想着接下来要写一个use after free的小总结,刚好碰巧最近的湖湘杯2016的一题----game利用use after free可以解出来。这题是自己第一次在比较正式的比赛中做出pwn题,做这题的时间花了不少,效率不高,但自己还是蛮开心的,后面回头做hctf2016的fheap这题,也可以用uaf解出来,game这题题目的复杂度稍微高一点,描述起来有点难,下面主要是用hctf的这道题来给大家讲述原理。对于uaf漏洞,搜了下,uaf漏洞在浏览器中存在很多,有兴趣的同学可以自己去查查。

二、uaf原理

uaf漏洞产生的主要原因是释放了一个堆块后,并没有将该指针置为NULL,这样导致该指针处于悬空的状态,同样被释放的内存如果被恶意构造数据,就有可能会被利用。先上一段代码给大家一个直观印象再具体解释。

#include

#include

typedef void (*func_ptr)(char *);

void evil_fuc(char command[])

{

system(command);

}

void echo(char content[])

{

printf("%s",content);

}

int main()

{

func_ptr *p1=(int*)malloc(4*sizeof(int));

printf("malloc addr: %p\n",p1);

p1[3]=echo;

p1[3]("hello world\n");

free(p1); //在这里free了p1,但并未将p1置空,导致后续可以再使用p1指针

p1[3]("hello again\n"); //p1指针未被置空,虽然free了,但仍可使用.

func_ptr *p2=(int*)malloc(4*sizeof(int));//malloc在free一块内存后,再次申请同样大小的指针会把刚刚释放的内存分配出来.

printf("malloc addr: %p\n",p2);

printf("malloc addr: %p\n",p1);//p2与p1指针指向的内存为同一地址

p2[3]=evil_fuc; //在这里将p1指针里面保存的echo函数指针覆盖成为了evil_func指针.

p1[3]("whoami");

return 0;

}

这段代码在32位系统下执行。通过这段代码可以大概将uaf的利用过程小结为以下过程:

1、申请一段空间,并将其释放,释放后并不将指针置为空,因此这个指针仍然可以使用,把这个指针简称为p1。

2、申请空间p2,由于malloc分配的过程使得p2指向的空间为刚刚释放的p1指针的空间,构造恶意的数据将这段内存空间布局好,即覆盖了p1中的数据。

3、利用p1,一般多有一个函数指针,由于之前已使用p2将p1中的数据给覆盖了,所以此时的数据既是我们可控制的,即可能存在劫持函数流的情况。

三、hctf2016--fheap

uaf原理还比较简单,下面就是具体的实践了,这个漏洞复杂一些的话就和double free这些其他的堆的常见利用方法合起来一起出题,具体的可以看bctf2015的freenote。不过fheap这题用uaf直接就解决了。还有就是湖湘杯2016的game题,和fheap基本上是一样的,这题大家跟出来了的话可以去做下game试下。先介绍fheap的功能。

A、程序功能

\

程序提供的功能比较简单,总共两个功能:

1、create string

\

输入create 后,接着输入size,后输入具体的字符串。相关的数据结构则是:先申请0x20字节的堆块存储结构,如果输入的字符串长度大于0xf,则另外申请对应长度的空间存储字符串,否则直接存储在之前申请的0x20字节的前16字节处,在最后,会将相关free函数的地址存储在堆存储结构的后八字节处。相关示意图描绘如下:

\

2、delete string

调用存储在结构体里的free_func这个指针来释放堆,由于在释放以后没有将指针置空,出现了释放后仍可利用的现象,即uaf。

\

B、查看防护机制

首先查看开启的安全机制

\

可以看到开启了PIE,在解题的过程中还需要绕过PIE,PIE是指代码段的地址也会随机化,不过低两位的字节是固定的,利用这一点我们可以来泄露出程序的地址。

C、利用思路

总思路:首先是利用uaf,利用堆块之间申请与释放的步骤,形成对free_func指针的覆盖。从而达到劫持程序流的目的。具体来说,先申请的是三个字符创小于0xf的堆块,并将其释放。此时fastbin中空堆块的单链表结构如下左图,紧接着再申请一个字符串长度为0x20的字符串,此时,申请出来的堆中的数据会如下右图,此时后面申请出来的堆块与之前申请出来的1号堆块为同一内存空间,这时候输入的数据就能覆盖到1号堆块中的free_func指针,指向我们需要执行的函数,随后再调用1号堆块的free_func函数,即实现了劫持函数流的目的。

\

1、绕过PIE,在能劫持函数流之后,首先是泄露出程序的地址以绕过PIE,具体的方法是将free_func指针的最低位覆盖成"\x2d",变成去执行fputs函数,最后变成去打印出free_func的地址,从而得到程序的基地址等。

\

2、泄露system函数地址,首先有了程序的地址后,可以得到printf函数的plt地址,从而想办法在栈中部署数据,使用格式化字符串打印出我们需要的地址中的内容,使用DynELF模块去泄露地址,具体可以看安全客之前有人写的一篇文章---借助DynELF实现无libc的漏洞利用小结。从而泄露出system函数的地址。

点击复制链接 与好友分享!回本站首页
上一篇:DeriaLock勒索木马最新变种分析
下一篇:Python 格式化字符串漏洞(Django为例)
相关文章
图文推荐
文章
推荐
热门新闻

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训
版权所有: 红黑联盟--致力于做实用的IT技术学习网站