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

CVE-2014-1767 漏洞分析

1. 简介

该漏洞是由于Windows的afd.sys驱动在对系统内存的管理操作中,存在着悬垂指针的问题。在特定情况下攻击者可以通过该悬垂指针造成内存的double free漏洞。

实现对漏洞的有效利用,攻击者利用成功可导致权限提升。afd.sys是内核用来管理socket的模块。

影响的系统包括(32bit & 64 bit):

   Windows Server 2003

Windows Vista

Windows Server 2008

Windows 7

Windows 8 & Windows 8.1

Windows Server 2012

测试环境:

Win7 32bit

下面对漏洞成因做简单分析。

注:本文是以分析思路来写的,并不是总结性的。所以会有些绕,想了解漏洞成因,请直接看最后的流程分析。

2.漏洞分析

2.1 "POC"

POC主要做了这么两件事:

1. 初始化了一个本地socket连接。

2. 给这个socket发送了两个控制码:0x1207F和0x120C3。

2.2 First Crash

将编译好的程序放在虚拟机中运行,触发漏洞之后的BSOD:

显示的信息为BAD_POOL_CALLER,BugCheck 0xc2。

设置双机调试后,触发BSOD,部分windbg输出的信息:

调用堆栈:

目前,我们可以知道:

出问题的是afd.sys模块,漏洞的类型为double free,free 的对象是Mdl,并且发生崩溃时存在这样的调用关系:

afd!AfdTransmitPacketsà afd!AfdTliGetTpInfoà afd!AfdReturnTpInfoànt!IoFreeMdl

2.3 Second Crash?

对afd.sys开启Special Pool后,再次运行POC,但是却没有发生崩溃,这有点奇怪。可是我们必须找到切入点,对问题Mdl对象进行回溯,然后搞清楚整个流程,锁定问题。

未开启Special Pool时,我们知道最后崩溃时的函数调用关系,或许可以对afd!AfdReturnTpInfo下断点,若此时也调用了该函数,可能会获得一些信息。但首先我们要搞清楚POC向afd.sys发送的两个控制码所对应的内核函数。

要找到这个对应关系,有这样的调试技巧:用户层的IoControl消息到都会被内核包装成IRP包,发送给对应驱动的IRP_MJ_DEVICE_CONTROL例程来处理,IRP_MJ_DEVICE_CONTROL例程会根据控制码来选择对应的函数。

感谢Windbg为我们提供了这样的功能:

这样就可以得到afd.sys对应的IRP_MJ_DEVICE_CONTROL例程为afd!AfdDispatchDeviceControl,利用IDA对该函数简单分析后,其大致流程如下:

设置如下两个断点:

再次运行POC,便可以得到两个控制码所对应的内核函数:

0x1207F:afd!AfdTransmitFile

0x120C3:afd!AfdTransmitPackets

接下来对上面提到的afd!AfdReturnTpInfo下断点,此时对afd.sys仍然开启了Special pool。看看有啥惊喜。

运行POC,待其断下来之后,对释放的Mdl进行跟踪:

咦,此时调用afd!AfdReturnTpInfo的并不是afd!AfdTransmitPackets,而是afd!AfdTransmitFile。好像还不能明白发生了什么,先记录下此时Mdl分配和释放的相关函数调用关系:

分配:afd!AfdTransmitFile+0x170à nt!VerifierIoAllocateMdl

释放:afd!AfdTransmitFile+0x5a3à afd!AfdReturnTpInfo+0xadxà nt!IoFreeMdl

nt!VerifierIoAllocateMdl这个函数有点奇怪,正常情况都是调用nt!IoAllocateMdl来分配Mdl的空间,IDA中此时也是调用的IoAllocateMdl,这是否是导致开启special pool后不崩溃的原因?这个问题还有待考证。

接着再看,在函数afd!AfdReturnTpInfo内,Mdl=[edi+0ch],所以利用同样的方法,在windbg中查看edi的分配释放记录:

记录下关于edi的函数的调用关系:

AfdTransmitFileàAfdTliGetTpInfoàExAllocateFromNPagedLookasideListàAfdAllocateTpInfo

而在函数afd!AfdReturnTpInfo中,edi=[esi+20h],同样的方法:

咦,怎么会和edi的结果一样?根据此时的函数调用,来看看afd!AfdTliGetTpInfo这个函数:

从这段IDA截图,根据微软的匈牙利命名法,可以知道函数afd! AfdReturnTpInfo中的edi为TpInfoElement,esi=TpInfo。并且TpInfoElementArray=*(DWORD*)(TpInfo+20h),sizeof(TpInfoElement)=0x18。

稍作总结一下我们所知道的:IoControl=0x1207F时,会调用afd!AfdTransmitFile,afd!AfdTransmitFile会调用afd!AfdTliGetTpInfo分配一个TpInfo,接着会调用nt!IoAllocateMdl分配一个Mdl,然后会从TpInfo结构中得到这个Mdl,并释放掉。

接着用windbg使用系统继续运行,windbg再也没有断下来,有一点忧伤。再次查看崩溃时的函数调用关系,将断点的位置提前到afd!AfdReturnTpInfo开始的时候。然后IoControl=0x120C3时,断点断下来后,利用windbg跟踪此时的esi:

这个调用关系看起来十分的眼熟,和IoControl=0x1207F时除了对应的内核函数不同,其他调用简直一模一样!那么我们来看看此时是如果避开了释放Mdl的流程。

利用windbg单步跟踪一下,发现其在afd!AfdReturnTpInfo+0x69处,由于[esi+28h]=0,跳转到另一条不执行释放Mdl的流程了。

而此时esi=TpInfo,我们可以猜测TpInfo结构另一个成员:TpInfo+28h=TpInfoElementCount。

好了,现在对整个流程有一个粗略的了解了。再回看一下漏洞的描述,"Mdl double free",那么可以大胆的猜测一下:double free 的Mdl就是afd!AfdTransmitFile所创建的Mdl!

2.4 大胆的假设

关闭special pool,设置如下两个断点:

记录下afd! AfdTransmitFile所创建的Mdl的地址,和最后调用afd!AfdTransmitPackets时释放Mdl地址做比较。

我们惊奇的发现,这两个地址是一样的!也就是最后afd!AfdTransmitPackets流程中释放的Mdl正是afd!AfdTransmitFile所创建的Mdl!

这样我们对整个流程又有了进一步的了解:

IoControl=0x1207F,对应的内核函数afd!AfdTransmitFile会创建TpInfo结构,分配一个Mdl并将地址存入到TpInfo结构的TpInfoElementArray中,接着其会调用afd!AfdReturnTpInfo释放掉Mdl。

IoControl=0x120C3,对应的内核函数afd!AfdTransmitPackets会从TpInfo取出Mdl,而这个Mdl正好是afd!AfdTransmitFile已经释放掉了的,此时afd!AfdTransmitPackets会尝试对其进行第二次释放。然后就BSOD。

目前有一个大大的疑问:为什么afd!AfdTransmitPackets流程中释放的就那么巧的就是afd!AfdTransmitFile所创建的那个Mdl?内核中pool的分配和释放时刻都在发生,为何会恰好得到那一块pool?

看来,得要去分析一下TpInfo分配和释放相关的一些东西了。

2.5一些函数

通过上面的分析,我们知道了一些和TpInfo分配和释放相关的函数:

ExAllocateFromNPagedLookasideList,AfdTliGetTpInfo,AfdAllocateTpInfo,AfdReturnTpInfo,ExFreeToNPagedLookasideList,AfdTransmitFile和AfdTransmitPackets。

结合静态和动态分析,将POC流程走的这个几个函数分析出来,特别留意和POC的关系。这个没啥好说的了,就直接把逆出来的伪C代码贴出来,然后加以解释了。

再说第一个函数之前,介绍一下IRP和IO_Stack_Location,比如IOControl=0x120C3时:

函数AfdTransmitPackets开始时候的ecx就是IRP:

红框内的值是否看起来有一点眼熟?回头看看POC,这正是第二次DeviceIoControl的部分参数。IRP的结构微软一直藏着掖着的,公开的部分结构也比较模糊。

IO_Stack_Location位置IRP+60h位置,其结构很简单但是因为有一个union结构的存在,显得很多,此时Parameters对应的是DeviceIoControl,结构如下:

此时IO_Stack_Location的内存:

其中的Type3InputBuffer成员是用来存储DeviceIoControl中InputBuffer的内容,位于IO_Stack_Location+0x10的位置。

AfdTransmitFile

1. 检查用户层DeviceIoControl中InputBufferSize是否大于30h。

2. 对IoStackLocation->Type3InputBuffer做一些有效性检查。

3. 调用AfdTliGetTpInfo分配一个TpInfo结构。

4. 根据VirtualAddress和Length创建一个Mdl(此时VirtualAddress和Length的值是从Type3InputBuffer得到的,分别对应的是inbuf1[6]和inbuf1[7]),并将其地址写入到TpElementArray的合适位置。

5. 调用函数MmProbeAndLockPages准备操作这块Mdl,但是此时因为要映射的地址无效(VirtualAddress=0x13371337),触发异常,调用AfdReturnTpInfo释放TpInfo。

AfdTliGetTpInfo

1. 设置异常处理模块,发生异常会调用AfdReturnInfo函数。

2. 调用ExAllocateFromNPagedLookasideList函数从Lookaside List为TpInfo分配一块pool。

3. 判断tpElementCount是否大于3,大于则会为TpElementArray更多的空间,否则就直接用TpInfo的空间了。

这里的nCount是通过用户层DeviceIoControl的InputBuffer获得,位于InputBuffer[2]。

来解释一下此时的Lookaside,可以看到其是一个定值为0x874ff428,这表明其是一个Dedicated Lookaside Lists,相当于专用的Lookaside 。用windbg查看这个Lookaside:

可以看到,刚开始的时候这个Lookaside为空。

Lookaside的分配和释放算法是理解为何会得到同一个Mdl的关键所在,来看一下:

首先是分配算法,流程如下:

1. 记录分配的次数。

2. 尝试从Lookaside卸载下一个ListEntry。第一次的IOControl,Lookaside为空,所以会进入到下一步的流程。

3. 尝试失败,调用Lookaside的分配函数重新分配一块pool。

接着是释放算法:

流程:

1. 记录释放的次数。

2. 如果此时Lookaside的Depth小于Lookaside的MaxDepth,则会将参数中的ListEntry加入到Lookaside中,否则进入下一步。

3. 记录释放失败的次数,调用Lookaside对应的释放函数。

在来看看TpInfo的分配和释放函数:

分配函数没有什么好说的,下面是释放函数:

流程:

1. 遍历TpInfo的TpElementArray数组,释放Mdl。

2. flags(第二个参数)为0,调用AfdFreeTpInfo释放TpInfo,否则调用ExFreeToNPagedLookasideList。

好了,现在还剩最后一个函数,IOControl=0x000120c3对应的AfdTransmitPackets函数:

流程:

1. 对IRP和IoStackLocation做有效性检查。

2. (IoStackLocation->InputBufferLength)>0x10。

3. InputBuffer[0]!=0,InputBuffer[1]<=0x0AAAAAAA。这点解释了POC中inbuf2的值。

4. 调用AfdTliGetTpInfo()。

2.6 流程分析

现在是时候做一个总结了,整个漏洞的流程如下。

POC创建了一个以socket为基础的本地网络连接,调用DeviceIoControl向socket对象分别发送两个控制码0x1207F和0x120C3,这两次控制码分别对应afd.sys的AfdTransmitFile和AfdTransmitPackets。

IOControl=0x1207F

1. AfdTransmitFile会调用AfdTliGetTpInfo来获得一个TpInfo结构,AfdTliGetTpInfo会尝试从Dedicated Lookaside Lists获得一个ListEntry,但是由于此时这个Lookaside为空,所以调用AfdAllocateTpInfo函数重新分配了一块pool给TpInfo使用。

2. 接着AfdTransmitFile根据用户层传递过来的VirtualAddress=0x13371337和Length来创建一个Mdl,用来和用户层交互,并将这个Mdl的地址保存到TpInfo结构中的TpElementArray数组中。

3. AfdTransmitFile接着调用MmProbeAndLockPages函数,准备对申请的Mdl进行操作,但是由于无效的地址(VirtualAddress=0x13371337),程序进入到异常处理的流程中。

4. 异常处理流程会调用AfdReturnTpInfo函数,AfdReturnTpInfo函数遍历TpInfo结构的TpElementArray数组,将Mdl释放掉。接着其会调用ExFreeToNPagedLookasideList释放刚创建的TpInfo。

5. 但是因为此时这个Lookaside很"闲",ExFreeToNPagedLookasideList不会将TpInfo释放掉,而是将其挂载到Dedicated Lookaside List中去。但此时TpInfo所在pool数据还保留着,并没有清空,当然也包括已经释放掉的Mdl地址,成了一个dangling pointer,这里就埋下了隐患。这是第一次free的地方。

第一次IoControl的操作主要就是放置一个dangling pointer到Dedicated Lookaside Lists中。

第二次IoControl对这个dangling pointer进行二次释放。

IOControl=0x120C3

1. 接下来AfdTransmitPackets同样会调用AfdTliGetTpInfo创建一个TpInfo结构。AfdTliGetTpInfo会调用ExAllocateFromNPagedLookasideList,尝试从Dedicated Lookaside Lists获得ListEntry。因为此时的Dedicated Lookaside Lists不为空,所以会从中卸载一个ListEntry给TpInfo使用,而此时Lookaside就只有一个上一次AfdTransmitFile函数放入的ListEntry,所以这个ListEntry正好是响应上一个控制码所放进去的那个!

2. 接着AfdTliGetTpInfo会从用户层输入inbuf2[1]获得值0x0AAAAAAA,作为TpElementCount,接下来会创建一个0x0AAAAAAA*0x18=0xFFFFFFF0大小的pool,这显然太大了,所以会再一次的进去到异常处理的操作。

3. 异常处理会调用AfdReturnTpInfo,其会遍历TpInfo尝试释放掉Mdl。因为此时的TpInfo所在的pool正是" dangling pointer",而Mdl已经被释放过一次了,这时发生double-free。

4. 然后发生BSOD。

2.7.总结

此漏洞被2014年黑客奥斯卡评为最佳提权漏洞,因为其从Windows上的内核级漏洞绕过Windows 8.1上的IE11沙箱。关于漏洞成因流程有两个比较有意思的地方:

1. 两次使内核函数进入到异常处理流程。

2. 两次从Lookaside得到的pool地址相同。

3. 参考

http://www.secniu.com/cve-2014-1767-afd-sys-double-free-vulnerability-analysis-and-exploit/

http://www.siberas.de/papers/Pwn2Own_2014_AFD.sys_privilege_escalation.pdf

时间: 2024-10-27 07:56:16

CVE-2014-1767 漏洞分析(2015.1)的相关文章

qemu毒液漏洞分析(2015.9)

0x00背景 安全娱乐圈媒体Freebuf对该漏洞的有关报道: 提供的POC没有触发崩溃,在MJ0011的博客给出了修改后可以使qemu崩溃的poc.详见: http://blogs.360.cn/blog/venom-%E6%AF%92%E6%B6%B2%E6%BC%8F%E6%B4%9E%E5%88%86%E6%9E%90%EF%BC%88qemu-kvm-cve%E2%80%902015%E2%80%903456%EF%BC%89/ 0x01漏洞重现 注:qemu的用户交互性体验相对于vm

2015年11月数据安全漏洞分析报告

报告核心观点 1.千帆过尽,SQL注入仍"不改" 2.本月金融业漏洞增长尤为突出 3.11月常见数据泄露原因分析 4.解决弱口令安全建议 报告正文 2015年11月,安华每日安全资讯总结发布了126个数据泄密高危漏洞,这些漏洞分别来自乌云.补天.漏洞盒子等平台,涉及8个行业,公司机构.互联 网.交通运输.教育.金融.能源.运营商.政府.漏洞类型涉及,SQL注入.系统漏洞.弱口令等7类,其中SQL注入仍然是漏洞类型的重灾区. 千帆过尽,SQL注入仍"不改" 数据安全问

Java反序列化漏洞分析

相关学习资料 http://www.freebuf.com/vuls/90840.html https://security.tencent.com/index.php/blog/msg/97 http://www.tuicool.com/articles/ZvMbIne http://www.freebuf.com/vuls/86566.html http://sec.chinabyte.com/435/13618435.shtml http://www.myhack58.com/Articl

比葫芦娃还可怕的百度全系APP SDK漏洞 - WormHole虫洞漏洞分析报告 (转载)

瘦蛟舞 · 2015/11/02 10:50 作者:瘦蛟舞,蒸米 ”You can’t have a back door in the software because you can’t have a back door that’s only for the good guys.“ - Apple CEO Tim Cook ”你不应该给软件装后门因为你不能保证这个后门只有好人能够使用.” – 苹果CEO 库克 0x00 序 最早接触网络安全的人一定还记得当年RPC冲击波,WebDav等远程攻

PHPCMS \phpcms\modules\member\index.php 用户登陆SQL注入漏洞分析

catalog 1. 漏洞描述 2. 漏洞触发条件 3. 漏洞影响范围 4. 漏洞代码分析 5. 防御方法 6. 攻防思考 1. 漏洞描述2. 漏洞触发条件 0x1: POC http://localhost/phpcms_v9/index.php?m=member&c=index&a=login dosubmit=1&username=phpcms&password=123456%26username%3d%2527%2bunion%2bselect%2b%25272%2

手游类App安全防破解攻略-先来做个漏洞分析吧

2014年6月初,爱加密高调推出免费自动化App安全检测平台,这是国内首家自动化智能App安全检测平台,也是爱加密推出的一个重磅产品,甚至在目前整个互联网行业,包括移动互联网行业还没有这样智能完善的服务平台出现,其应用方向和行业前景相当乐观.       只需一键,专业简单,让风险漏洞无处遁形 目前来说,移动应用开发者众多,他们可能不知道自己的应用是否安全,是否容易被他人破解进行二次打包.出于此类需求,爱加密推出爱加密免费漏洞分析平台.该平台集成了目前黑客最常用的各种破解方法与思路,模拟黑客攻击

App漏洞分析,爱加密全网首推智能安全检测

2014年6月初,爱加密高调推出免费自动化App安全检测平台,这是国内首家自动化App安全检测平台,也是爱加密推出的一个重磅产品.作为国内首家免费自动化App安全检测平台,在目前整个互联网行业,包括移动互联网行业还没有这样的服务平台出现,行业前景相当乐观. 文章参考:www.ijiami.cn 只需一键,专业简单,让风险漏洞无处遁形 爱加密漏洞分析平台的推出旨在打造一个服务于移动互联网开发者的安全服务平台,同时也给整个移动互联网安全领域带来一份保障.目前移动应用开发者越来越多,他们不知道自己的应

再见,2014;您好,2015!

再见,2014:您好,2015! 光阴似箭,日月如梭,蓦然回首,时光已经走到了年末岁尾之时.在钟声敲响那一刻,我们是否有太多难舍的记忆片段呢?回首即将过去的2014这一年,有起伏,有黯然失色,也有笑意盎然…… 2014年,作为一名普通的学生,踏踏实实的学习着,虽然没有取得值得炫耀的成绩,工作中也没有出现大的失误.在此,我要感谢各位领导和同事们对我的关心与照顾,感谢各位老师对我的支持与信任,让我在一年里学到不少知识和人生的道理,使我在生活中过得充实与快乐,特别是在我遇到困难时.心理纠结时,各位老师

PCMan FTP Server缓冲区溢出漏洞分析与利用

简要介绍 这个软件是台湾国立阳明大学医学系的一个学生在大四的时候写的,这个漏洞是有CVE的(CVE-2013-4730),软件应该还挺普及的,这是一个缓冲区溢出漏洞 具体exp可以点这里 实验用poc(其实这里直接对USER命令溢出都是可以的,即不用知道账号密码即可远程代码执行,USER命令的buf距离返回地址是2000) import socket as s from sys import argv # if(len(argv) != 4): print "USAGE: %s host <