上周,据报道,一个exp(漏洞利用)被用来传播ROKRAT恶意软件。有趣的是,Flash exp“销声匿迹”了一段时间,现在又出现,在被一个APT组织利用。我们不禁想知道发生了什么变化,以及这个最新exp的原理。
在这篇文章中,我们将先介绍一个旧的Flash exp,然后了解这个最新的样本如何绕过Flash环境中的一些防御措施。
先来看看之前一个影响Flash防御措施的漏洞,CVE-2015-5119,通常被称为Hacking Team Flash 0day。
早在2015年7月,Hacking Team遭遇了一次数据泄露,一些内部电子邮件、应用程序源码和exp被公开,其中包含针对一个Flash 16的远程代码执行漏洞(即CVE-2015-5119)的exp。
该漏洞类型为“Use-After-Free”,意味着在没有更新对象引用的情况下内存被释放给Flash使用。来看一个可以触发漏洞的示例:
查看Flash的源码,我们可以了解产生这个漏洞的原因。首先,有一个长度为0xfa0的ByteArray,我们给它分配一个对象。查看相应的源码,会看到“ByteArrayObject :: setUintProperty”负责处理这个任务:
例子中“value”参数是一个对象引用,被传递给检查类型的“AvmCore :: integer”函数:
然后参数被传递给“number”方法:
我们的对象被传递给“AvmCore :: atomToScriptObject”,它将该值转换回“ScriptObject”:
最后,调用“valueOf”属性:
现在我们理解了这个漏洞,下面来看看它是如何被利用的。
在利用这种Flash漏洞时,我们想用一个对象来填充释放的内存,并且允许我们控制执行或修改内存…输入Vector.<uint>。Vector对象非常简单,初始化方法如下:
初始化后,对象将包含以下内存布局:
可以在ActionScript中使用以下代码检索Vector.<uint>的长度:
该矢量的内容通过以下方式检索:
现在要修改“Length”属性,我们发现有一个相当强大的R/W(读/写)原语。例如,如果能用0xFFFFFFFF填充“Length”属性的内存,我们就可以操控任意内存。
更新exp来展示这一点:
我们采取了以下步骤:
这导致了内存的任意读/写,使用户能够编写shellcode并强制执行。
在2015年7月16日发布的一篇帖子中,Google Project Zero参考了Hacking Team的exp,并宣布他们已经与Adobe合作推出了一些强化Flash的方法。完整的帖子可在这里找到,其中介绍了3种强化方法:
在这三种对抗方法中,上述的修改Vector.<uint>的length属性的技术,有两种方法可以对抗。首先,Vectors被移动到一个单独的内存区域,与任何可能允许篡改“length”属性的潜在溢出隔离。其次,在Vector对象中引入了一些检查,以确保如果“length”属性被修改,运行时将检测到这种修改并暂停执行。
这种长度验证方法是以XOR key实现的。与stack-canaries类似,Vector对象中的一些属性与一个key异或,并存储结果值,这是一个检测损坏数据的简单方法。
对抗措施发布后,事情似乎平静下来。然而,一个新的漏洞出现了,CVE-2018-4878。
该漏洞的细节未公开,与许多安全研究人员一样,我们抓取了一个恶意软件的样本,并开始对样本进行逆向分析。
获取SWF文件并反汇编,我们发现在加载SWF时,会向C2服务器发出请求:
响应中包含一个key,该key可解密嵌入的SWF exp:
不幸的是,过程到此搁置。我们分析的所有样本中看到C2服务器都无法访问,意味着我们无法恢复100字节的XOR解密key来分析该exp。此外,那些幸运地拥有解密key的人不太愿意与他人分享,也就是说我们能做的只有等待细节被披露。
慢慢地细节开始被公开,以编辑过的部分截图和与该漏洞相关的帖子的形式出现,但没有显示获得R/W原语的路径。经过几个熬夜工作之后,我们能够重建漏洞并了解绕过对抗措施的一些情况。
首先,我们看看如何用一个简单的实例触发漏洞:
漏洞存在于DRMManager的“initialize”调用中,需要一个继承DRMOperationCompleteListener接口的对象。 在可以使用之前,通过将“this.listener”设置为NULL来释放对象,强制分配的内存由garbage collector(垃圾收集器)释放。
接下来,我们分配一个DRMOperationCompleteListener对象,并在“danglingpointer”变量中保存对其的引用。 这个对象被释放,但是“danglingpointer”变量仍然引用其内存,这意味着形成了一个use-after-free条件。
继续查看所披露的exp,我们看到加了一个计时器:
该计时器调用一个新的函数检查UAF条件:
这个定时器用于定期检查我们的“danglingpointer”对象是否已释放,并且现在指向已释放的内存。最终情况就是,允许我们用另一个对象填充这个空闲空间。
在这一点上,情况变得有点朦胧。在我们发现的截图和示例中,似乎都没有分享生成填充此内存的对象的类(“Mem_Arr” 类)的细节。但是,我们确实找到了利用此漏洞的方法,重新让我们理解了该类的行为,但是如果你有该恶意软件的样本,我们有兴趣知道你和我们对该恶意软件漏洞利用分析的匹配度。
从网上的讨论中知道,用于控制Flash的原语是一个ByteArray,意味着我们要用一个ByteArray对象填充释放的内存:
但问题是我们知道由于大小的差异,ByteArray可能不会被分配到释放的DRMOperationCompleteListener对象的内存位置。然而,我们可以创建一个新的继承ByteArray类的类并添加其他属性来扩展对象的大小。为此,我们创建一个新的类“Mem_Arr”:
此外,修改“MyListener”对象以包含更多属性:
原因是为了确保“MyListener”和“Mem_Arr”对象的大小相似,从而允许我们用“Mem_Arr”替换释放的“MyListener”对象内存。
我们还将更新“uafcheck”函数,从“Mem_Arr”对象中转储内存,以确保我们处于正确的方向上:
现在,执行此SWF,会发现我们的跟踪日志包含以下内容:
第一眼看起来像DWORD的随机序列,我们看看具体是什么。首先,我们看到“0x31”的值,实际上这是更新的ByteArray/Mem_Arr对象的“position”属性值。
查看ByteArray类的源码,我们知道ByteArray由以下属性组成:
其中一个属性是“m_position”,它包含“position”属性,这意味着我们处于正确的方向上,现在有能力操纵ByteArray的底层内存。
实际上使我们感兴趣的是在“m_buffer”属性中发现的一个指向包含以下内容的Buffer对象的指针:
这里我们看到Google Project Zero引入的对抗措施之一,一些用作XOR检查值的属性。 我们需要通过解引用(dereference)m_buffer的地址来访问此结构。
为此,我们添加了一个新的类:
并从我们的Mem_Arr类添加了对这个类的引用:
这里的想法是通过悬挂指针指向“m_buffer”地址来设置“Mem_Arr”对象的“o1”属性,然后通过“Modify”类来解引用对象。更新“o1”属性如下:
执行时,看见返回如下的记录:
这里可以清楚地看到ByteArray的长度为0x512,再次表明我们处于正确的方向。用这些值覆盖ByteArray对象:
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!
最后于 2018-3-4 00:49
被SpearMint编辑
,原因: