本文转载自:http://blog.csdn.net/u012406115/article/details/72232535

一、         漏洞概述

CVE漏洞链接:http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2015-7547

披露/发现时间:2015-07-13    提交时间:2016-02-17

漏洞等级:高  漏洞类别 缓冲区溢出

漏洞概述:该漏洞是Glibc中的DNS解析器中存在基于栈的缓冲区溢出漏洞,glibc是GNU发布的libc库,即c运行库。glibc是linux系统中最底层的api,几乎其它任何运行库都会依赖于glibc。glibc除了封装linux操作系统所提供的系统服务外,它本身也提供了许多其它一些必要功能服务的实现。当在程序中调用Getaddrinfo函数时,攻击者自定义域名或是通过中间人攻击利用该漏洞控制用户系统。比如攻击者向用户发送带有指向恶意域名的链接的邮件,一旦用户点击该链接,攻击者构造合法的DNS请求时、以过大的DNS数据回应便会形成堆栈缓存区溢出并执行远程代码,达到完全控制用户操作系统。通过该漏洞直接批量获取大量主机权限。

影响范围:该漏洞影响Glibc 2.9以后的所有版本,Debian、Red Hat以及更多其它Linux发行版,只要glibc版本大于2.9就会受到该溢出漏洞影响。不过虽然可以进行远程执行攻击,攻击者还需要解决绕过ASLR系统安全机制。

二、   POC环境配置

为了深入分析该漏洞首先对poc的源码的执行环境进行配置,主要是可以触发的该漏洞glibc库的编译,以及对应的服务器配置和POC源码编译与运行

Poc:在github上:https://github.com/fjserna/CVE-2015-7547

1.gilbc下载与编译

由于一般主机的glibc的库是已经修复过该漏洞的,而且系统自带的glibc是发行版的,所以在编译的是时候选用了优化参数 -O2,所以在调试的过程中会出现变量被优化无法读取以及代码运行的时候与源码的行数对不上的情况。所以需要自行下载一个glibc库进行测试。这里我组下载了2.20版本。

首先为了可以使用gdb对glibc的跟踪调试,需要执行下面两个安装指令如下:

sudo apt-get install libc6-dbg   sudo apt-get source libc6-dev

然后下载glibc2.9以后的一个版本的glibc就行,这里我下载版本是2.20版本。

Glibc的下载链接:http://ftp.gnu.org/gnu/glibc/

然后编译的时候要特别注意首先要加载到/usr/local/目录下新建的目录才能安装而且要使用O1进行编译否则默认O2会进行优化无法对应调试源码。执行如下命令进行配置:

/opt/glibc220/(下载解压缩的glibc的目录)configure --prefix=/usr/local/glibc220/ --enable-debugCFLAGS="-g -O1" CPPFLAGS = "-g -O1"

不过第一次会报错,百度以后发现必须要到/usr/local/glibc220/下去执行才可以。

但继续安装又报了如下的错,按提示再安装gawk,容易配置成功。在configure执行完成之后在直接make&&make install安装就好了。

2.poc程序的编译与环境配置

该漏洞是由于接受的DNS数据缓存溢出导致的,所以POC分为两个部分一个是模拟的恶意DNS服务器py文件,用于发送过长的字符串,另一个client客户端c文件负责调用Getaddrinfo函数接受数据触发溢出。由于服务器程序编写绑定是127.0.0.1,所以需要修改本地DNS配置文件/etc/resolv.conf。将域名服务器nameserver改为127.0.0.1。需要补充一点的是Ubuntu系统定时会重置这个文件所以每次运行之前需要检查这个文件是不是127.0.0.1。

然后执行如下命令指定我自己下载存在该漏洞的glibc2.20库去编译客户端源文件。

需要特别注意的是红字的部分还需要去指定动态库加载器,否则调试的时候会有问题无法对应到源码进行逐步调试。

gcc -O0 CVE-2015-7547-client.c -o client2-g -Wl,-rpath=/usr/local/glibc-220/lib -Wl,--dynamic-linker=/usr/local/glibc-220/lib/ld-linux.so.2

编译完成后可以通过ldd命令进行检查是否用的库我自己编译的2.20版本的库

三、         漏洞成因分析

1.     寻找漏洞溢出点

为了分析漏洞产生的原因首先就要定位到漏洞最后真正溢出点,我并没有去查看网上的博客去直接获得触发对应的缓冲区变量和函数,而是尝试自己去寻找追踪函数的调用过程发现触发点的。

首先我再开启服务器端py文件不断去发送超长的字符串。然后第一次gdb先直接运行客户端程序,如下图所示,产生的段溢出的错误。并且发现问题发生在res_query函数res_query.c 264代码上。

这时我进一步想既然是缓冲区溢出的段错误肯定是由于该缓冲区溢出覆盖了原有的返回地址,所以如果这时栈上最后一条函数地址就应该是溢出缓冲区申请的函数,因为栈上函数地址的存储顺序是按调用顺序进行,所以由于栈的是向上生长的溢出的缓冲区只能覆盖栈上自己的函数地址和调用该函数之前的函数的地址。这时我调用一个bt看一下栈如上图最后的红圈所示就可以推测出该溢出的缓冲区是在_nss_dns_gethostbyname4_r申请的。后续会进行验证之前的函数地址都被覆盖0x42也就是B。

这时看一下抓包的wireshark果然服务器发了一个很长字符串的B。

通过我上一步分析可以知道程序停在res_query函数上于是重新运行在resquery上打一个断点再去查看栈就可以获取程序崩溃前完整的调用程序流如下图所示:

但实际到底为什么发生了溢出真实的溢出点是不是程序崩溃的位置呢,需要进一步分析这里我先不追踪溢出的缓冲区,只是从刚才的崩溃来分析再下一部分再验证,通过gdb告诉我程序崩溃是res_query.c文件的264行于是对应找到该源码。如下图最后的红圈所示,发现是验证hp和hp2的时候发生了错误,推测应该是溢出覆盖了这两个变量的值于是需要继续追踪分析找到lib_res_nesend函数的参数影响了hp和hp1。由于函数参数在栈上是连续的所以去追踪该函数。

于是我继续追踪libc_res_nesend函数的参数发现send_dg和send_vc会影响这个函数的所有参数如下图所示:

然后我再单步调试nsend函数发现是先执行send_dg再执行了send_vc。这样我就先得到了完整的溢出触发的流程整体如下图所示:

2.成因具体分析

2.1 缓冲区变量跟踪

通过上面的分析只是推测出了溢出发生的函数触发流程,本节要通过之前的函数分析流程还具体分析到底是哪个变量指向缓冲区发生了溢出,为什么会发生溢出,同时这里也可以验证我之前的推测的触发过程是不是正确的。

通过上一节一开始的分析推测出这个栈空间应该是在_nss_dns_gethostbyname4_r函数发生的于是我断点在这个函数单步跟踪一下。如下图所示,果然发现了host_buffer.buf申请了2048字节的栈空间记录其栈的地址,而且发现ans2p这个变量(之前分析了这个变量赋值给hp2指针最终导致了崩溃)的地址只和栈底差了0xbfffea58-(0xbfffe210+2048)只有72个字节,也从侧面说明了很可能就是这个缓冲区溢出导致了覆盖了这个变量的地址。

于是逐步追踪这个host_buffer.buf地址,对应nsearch函数的answer变量再到nquery函数的answer变量再到nsend函数的ans变量,长度变量最后对应nsend函数的anssizp变量。

2.2 send_vc和send_dg逻辑分析

然后需要注意的是send_vc和send_dg传入的是对应变量的地址从如下的nsend函数定义和对应send_dg参数使用可以看出如下表所示

定义:int__libc_res_nsend(res_state statp, const u_char *buf, int buflen,

const u_char *buf2, int buflen2,

u_char *ans, int anssiz, u_char **ansp, u_char **ansp2,

int *nansp2, int *resplen2, int *ansp2_malloced)

调用:n = send_dg(statp, buf, buflen, buf2, buflen2,

&ans, &anssiz, &terrno,

ns, &v_circuit, &gotsomewhere, ansp,

ansp2, nansp2, resplen2, ansp2_malloced);

定义:send_dg(res_state statp,

const u_char *buf, int buflen, const u_char *buf2, int buflen2,

u_char **ansp, ,//指针的指针int *anssizp

int *terrno, int ns, int *v_circuit, int *gotsomewhere, u_char **anscp,

u_char **ansp2, int *anssizp2, int *resplen2, int *ansp2_malloced)

于是需要继续追踪send_dg和send_vc函数的ansp(2048字节的缓冲区)和anssizp(2048字节的长度)这些变量内部的赋值与传递关系寻找最终的溢出触发位置。

由于DNS协议TCP和UDP都用到了。其中大数据包和域名系统间的消息传递用TCP即调用send_vc函数,一般的域名查询服务调用UDP即send_dg函数。

在POC中首先服务器发一个2500UDP包,所以客户端会先调用send_dg函数。去除调一些与关心变量无关的程序,通过gdb单步跟踪发现其核心的实际执行的关键代码和逻辑如下图所示。

可以看到实际中第一次运行的时候在第一个判断的满足情况下,thisansp为空所以会赋值anscp指向空间也就是这两个指针的地址是一样的,注意此时anscp指向的空间是NULL。同时thisansp的值赋值为ansszip根据之前的分析该值为缓冲区长度2048。所以其在第二个判断的时候该长度小于MAXPACKET(65536)同时anscp是有地址的。所以满足条件下执行下面的代码块。或重新分配一个65536的堆空间给thisansp,注意到此时thisansp和anscp地址是一致的,所以anscp被指向到了65536的一个堆空间。如下图所示:

最后该函数会调用recvfrom在65536的实际堆缓冲区但标识其长度为2048,去接受服务器的数据所以此时并不会触发溢出。但是注意到anscp指向65536的堆缓冲区而ansp还是指向2048字节的栈缓冲区。

然后这3个变量又继续传递给了send_vc函数。我继续单步根据去分析其执行逻辑,发现其利用goto语句循环执行两遍的接受客户端数据的程序,但是会根据条件判断执行不同的程序路径,最终导致了溢出。关键的代码和执行路径我也画了一个图如下所示:

第一次会满足判断条件执行中间的路径,cp=thisansp=anscp指向65536的堆空间如下图所示所以第一次读取数据不会发生溢出。

但是接受程序会循环等待第二次数据,这时会执行右边的路径分支。使thisansp最终等于ansp的栈空间2048个字节,而该程序以为缓冲区长度为65536的大小,所以允许接受数据包的长度可以大于2048没有改变如下图所示。这里POC服务发送的2302个字节大小的数据最终导致了溢出。

可以看到对应地址的缓冲区都被覆盖成了0x42(B)。这也最终验证了我在第一部分推测的漏洞触发流程,通过跟踪对应的缓冲区最终发现了该缓冲区溢出,如下图所示红色标识的变量为溢出的缓冲区指针在调用一层层函数中对应的变量,可以很清楚的看出触发流程。

四、         漏洞可利用分析

由于程序有ASLR和DEP保护,最终并没有实际进行ROP等实际利用的攻击实验。该部分主要分析栈的结构和程序中的一些验证如何绕过的分析和测试。

栈溢出漏洞的关键就是覆盖函数返回地址使其执行攻击者想执行的代码的地址。于是我去查看申请溢出缓冲区的函数nss_dns_gethostbyname4_r的地址。在刚进入该函数后查看esp对应的位置开始的4个字节就是刚刚压入堆栈的该函数的返回地址,如下图所示红圈旁边的4个字节的返回地址是0xb7f14c68存储在红圈地址0xbfffea7c的位置。

可以看出该返回的地址和我申请缓冲区的地址0xbfffe210相差了2156个字节如下图所示,但是我经过前面的分析知道程序在_libc_res_nquery函数返回后验证hp和hp1的时候发生了段错误,说明在覆盖缓冲区的时候要绕过这些参数检查才能真正的利用成功。

于是我改变POC程序,让服务器发生小于等于2048个字节的数据,这时再跟踪程序到验证的地方找到hp和hp2的内容。如下图所示这时再查看缓冲区下界到返回地址之间的栈空间可以找到对应的hp和hp2如下图红圈所示。这时就可以知道hp和hp2的位置在0xbfffea58和5c的位置。

进一步跟踪程序发现在libc_res_nsearch的函数返回后会对answerp2_malloc检查是否为空。非空的话会释放ans2p仍然出错。

所以获取ans2p的地址如下图所示填充成0,就可以跳过检查。

但还是出错了所以说明hp后面的参数还是有用的,重新画一下栈的空间修如下所示:

所以重新设置服务器端发送的数据如下图所示,把原来的参数原样填进去。

终于不再报错,说明可以进去覆盖返回地址的攻击了。

五、         漏洞补丁分析

我进一步分析了该漏洞补丁程序其中有许多的补丁版本这里只说明一种可以查到源码的。其中关键就是对send_dg和send_vc的修改对send_vc修改如下图所示:

注释掉了ansp=ansp,同时当thisansp为空的条件下增加了上图绿框中的代码,重新开辟65536的堆空间给CP,这样就不会发生溢出。

同时补丁对send_dg修改如下,使thisanssizp的长度与thisansp的大小对应。

CVE-2015-7547漏洞分析从原因到利用到补丁(非常适合小白)【转】的更多相关文章

  1. 【转+自己研究】新姿势之Docker Remote API未授权访问漏洞分析和利用

    0x00 概述 最近提交了一些关于 docker remote api 未授权访问导致代码泄露.获取服务器root权限的漏洞,造成的影响都比较严重,比如 新姿势之获取果壳全站代码和多台机器root权限 ...

  2. MyuCMS_V2.1漏洞分析

    前言 在CNVD看到一个MyuCMS的一个任意文件删除漏洞.然后去搜了下这个CMS,发现官网公告显示在V2.2.3版本修复了CNVD提供的多处漏洞. 怀着好奇的心里,去CNVD搜了下这个CMS,结果发 ...

  3. CVE-2014-1767 漏洞分析(2015.1)

    CVE-2014-1767 漏洞分析 1. 简介 该漏洞是由于Windows的afd.sys驱动在对系统内存的管理操作中,存在着悬垂指针的问题.在特定情况下攻击者可以通过该悬垂指针造成内存的doubl ...

  4. 漏洞分析:CVE 2021-3156

    漏洞分析:CVE 2021-3156 漏洞简述 漏洞名称:sudo堆溢出本地提权 漏洞编号:CVE-2021-3156 漏洞类型:堆溢出 漏洞影响:本地提权 利用难度:较高 基础权限:需要普通用户权限 ...

  5. Java反序列化漏洞分析

    相关学习资料 http://www.freebuf.com/vuls/90840.html https://security.tencent.com/index.php/blog/msg/97 htt ...

  6. CVE-2016-10190 FFmpeg Http协议 heap buffer overflow漏洞分析及利用

    作者:栈长@蚂蚁金服巴斯光年安全实验室 -------- 1. 背景 FFmpeg是一个著名的处理音视频的开源项目,非常多的播放器.转码器以及视频网站都用到了FFmpeg作为内核或者是处理流媒体的工具 ...

  7. Elasticsearch 核心插件Kibana 本地文件包含漏洞分析(CVE-2018-17246)

    不久前Elasticsearch发布了最新安全公告, Elasticsearch Kibana 6.4.3之前版本和5.6.13之前版本中的Console插件存在严重的本地文件包含漏洞可导致拒绝服务攻 ...

  8. 看个AV也中招之cve-2010-2553漏洞分析

    试想:某一天,你的基友给你了一个视频文件,号称是陈老师拍的苍老师的老师题材的最新电影.avi,你满心欢喜,在确定文件格式确实为avi格式后,愉快的脱下裤子准备欣赏,打开后却发现什么也没有,而随后你的基 ...

  9. ref:Java安全之反序列化漏洞分析(简单-朴实)

    ref:https://mp.weixin.qq.com/s?__biz=MzIzMzgxOTQ5NA==&mid=2247484200&idx=1&sn=8f3201f44e ...

随机推荐

  1. linux下面MySQL变量修改及生效

    今天在访问mysql项目的时候突然报500错误,没有找到连接,因此想到mysql的连接时间. mysql> show global variables; 主要就是连接时间是28800(8小时), ...

  2. BestCoder Round #25 1002 Harry And Magic Box [dp]

    传送门 Harry And Magic Box Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/ ...

  3. 有向图tarjan算法求连通分量的粗浅讲解、证明, // hdu1269

    打算开始重新复习一遍相关算法.对于有向图tarjan算法,通过学习过很多说法,结合自己的理解,下面给出算法自己的观点. 算法总模型是一个dfs,结合一个stack(存放当前尚未形成SCC的点集合),记 ...

  4. 将数字转换成Excel表头格式的字母序号

    /**     * 从0开始算起,0-25转A-Z     * @param num     * @return  Character.valueOf((char)((num-1)+65))+&quo ...

  5. meta标签集

    html中的meta总结: 0.声明文档使用的字符编码: <meta charset='utf-8'/> 1.优先使用 IE 最新版本和 Chrome : <meta http-eq ...

  6. 纯Java实现定时任务(转)

    第一种: import java.util.Timer; import java.util.TimerTask; /** * * 于第一种方式相比,优势 1>当启动和去取消任务时可以控制 2&g ...

  7. Win10激活Office2013的技巧

    原文:http://www.xitongzhijia.net/xtjc/20150720/53252.html KMSpico Win10激活工具 是一款能激活Win8/Win8.1/win10/Of ...

  8. 【js html】对于<img>图片的引用填充,src可以给什么值?

    平时多见的<img>的使用,常见于如下: <img class="img-responsive img-rounded" src="static/img ...

  9. 数据库官方在线文档列表(mysql, postgreSQL)

    1. mysql http://dev.mysql.com/doc/ 2. postgreSQL https://www.postgresql.org/docs/

  10. Python奇技

    本文目录 1. 显示有限的接口到外部 2. with的魔力 3. filter的用法 4. 一行作判断 5. 装饰器之单例 6. staticmethod装饰器 7. property装饰器 8. i ...