结束与ExploitShield的“热恋”——Trail of Bits博客
Andrew Ruef
2012年10月29日
恶意软件, 缓解措施
ExploitShield被宣传为提供“针对所有已知和未知0day漏洞利用的保护,在传统杀毒和安全产品失败的地方保护用户”。我发现这一主张非常非凡且令人兴奋!软件应用程序中的漏洞对全球计算机用户来说都是真实存在的问题。到目前为止,我们在提供实际技术帮助个人用户防御软件漏洞方面做得相当糟糕。
在我看来,微软通过其增强缓解体验工具包(EMET)取得了最好的进展。EMET改变了操作系统的行为,增加了攻击者产生有效漏洞利用所需付出的努力。有博客文章详细记录了EMET的功能。
总的来说,我认为那些公开其方法的系统比“秘密配方”系统更值得信赖。EMET非常公开其方法,而ExploitShield则隐藏它们,试图通过隐匿获得额外的安全性。
我分析了ExploitShield系统和技术,分析结果如下。总结来说,该系统非常可预测,攻击者可以轻松研究并调整攻击以克服它,而且实现本身创造了新的攻击面。经过这次分析,我认为该系统无法帮助个人或组织防御任何有能力编写自己漏洞利用(0day或其他)的攻击者。
注意事项
我进行的分析是针对他们的“浏览器”版本。他们的“企业”版本中可能有更高级的东西,我诚然无法确定,因为我没有见过。然而,根据我分析的实现“基调”以及其中的实现缺陷,我怀疑这种可能性,并认为“企业”版本只是“更多相同的东西”。我欢迎被证明是错误的。
初步分析
通常我们可以使用一些优秀且免费的工具来了解软件的足迹。我喜欢使用GMER来实现这一点。GMER调查整个系统,并使用交叉视图技术来识别对运行程序进行的补丁。
如果你还记得,从ExploitShield的营销信息中,我们看到弹出框看起来像这样:
[截图描述:弹出框显示路径信息]
这个截图中有一些提示,例如,为什么指定了路径?如果这真的在阻止“漏洞利用”,难道不应该在指定文件系统上的路径之前就阻止吗?
在以下部分,我将按阶段介绍我的分析,涉及ExploitShield的组件或概念。
ExploitShield使用设备驱动程序
ExploitShield系统的一个组件是设备驱动程序。该设备驱动程序使用操作系统支持的机制(PsSetCreateProcessNotifyRoutine)在操作系统启动进程时接收通知。
每次进程启动时,设备驱动程序检查该进程,并可选地将其自己的用户模式代码模块加载到启动的进程中。加载用户模式代码模块的标准取决于启动的进程是否是ExploitShield保护的进程。
用户模式组件
用户模式组件似乎仅用于钩取/绕道特定函数。
函数钩取行为,也称为函数绕道,涉及修改函数的开头,使得当调用该函数时,改为调用另一个函数。MS Research关于Detours的论文相当全面地解释了这个概念。
函数钩取通常用作实现应用程序检查器或参考监视器的方式。安全系统可以绕道一个函数,例如CreateProcessA,并对CreateProcessA的参数做出基于启发式的决策。如果启发式表明行为可疑,安全系统可以采取一些行动,例如使对CreateProcessA的调用失败或终止进程。
钩取的函数
ExploitShield似乎主要通过绕道以下方法发挥作用:
- WinExec
- CreateProcessW/A
- CreateFileW/A
- ShellExecute
- UrlDownloadToFileW/A
- UrlDownloadToCacheFileW/A
在这里,我们可以理解ExploitShield作者所说的“在研究数千个漏洞利用后,ZeroVulnerabilityLabs开发了一种创新的专利待批技术,能够检测受保护的应用程序是否被恶意利用”时的意思。这些是shellcode常用于丢弃和执行其他程序的函数!
函数钩取行为
每个函数实现一个直接的启发式。在调用任何过程(在x86上)之前,过程完成后返回的地址被推送到堆栈上。每个钩取从堆栈中检索返回地址,并询问有关返回地址属性的问题。
地址的页面权限是RX(读-执行)吗? 地址是否位于加载模块的边界内?
如果这两个测试中的任何一个失败,ExploitShield报告它发现了漏洞利用!
术语混淆
漏洞:漏洞是软件的一种属性,允许某种信任违规。漏洞的定义非常广泛。内存损坏漏洞对计算机安全产生了如此大的影响,以至于很多时候,“漏洞”被简单地用作“内存损坏漏洞”的简写,然而其他类型的漏洞确实存在,例如信息泄露漏洞或身份验证绕过漏洞。信息泄露漏洞有时可能比内存损坏漏洞对个人隐私更糟糕。
漏洞利用:漏洞利用是使用漏洞来影响某些行动的软件或过程,通常是执行有效载荷。
有效载荷:攻击者创建的软件,在漏洞被用于危害系统后执行。
我相信当ExploitShield使用术语“漏洞利用”时,他们实际上是指“有效载荷”。
ExploitShield的好日子
那么ExploitShield按预期运行的具体情况是怎样的?让我们来看一下,抽象出具体使用哪个漏洞利用的细节:
用户被欺骗导航到攻击者控制的恶意网页。他们不能为此受到太多责备,他们只需要犯一次这个错误,访问可能是攻击者入侵合法网站并使用它提供恶意软件的结果。
该网页包含用户浏览器中漏洞的漏洞利用。网页浏览器加载包含漏洞利用的文档,并开始解析和处理漏洞利用文档。
漏洞利用文档中的数据已被修改,使得解析文档的程序做了一些坏事。假设漏洞利用说服网页浏览器做的是用漏洞利用也提供的数据的地址覆盖存储在内存中某处的函数指针。接下来,易受攻击的程序调用这个函数指针。
现在,网页浏览器执行漏洞利用提供的代码。此时,网页浏览器已被利用。用户正在运行攻击者/漏洞利用提供的代码。此时,任何事情都可能发生。注意我们如何已经完成了这个过程的“利用”阶段,而ExploitShield尚未进入画面。
执行的代码调用其中一个钩取的函数,例如WinExec。对于这个例子,假设执行的代码是从堆上的页面调用的,因此其权限是RWX(读-写-执行)。
如果攻击者不知道ExploitShield在那里,并且它没有全局代表性到对攻击者构成大问题,那么ExploitShield是很好的。如果攻击者知道它在那里,并且关心,他们可以轻松绕过它。
ExploitShield的坏日子
如果攻击者知道ExploitShield,创建不触发ExploitShield监视的警报的漏洞利用需要多少努力?我认为根本不需要太多努力。立即想到两种可能性:
使用(非常)原始的ROP(返回导向编程)形式。识别加载模块中的ret指令,并将其作为返回地址推送到堆栈上。在此之前将你的返回地址推送到堆栈上。ExploitShield进行的检查将通过。
使用等效于其中一个钩取函数但不是钩取函数的函数。如果CreateProcess被钩取,使用NtCreateProcess代替。
这两种方法都会击败我在ExploitShield中发现的保护。此外,这些技术将在没有ExploitShield的系统上运行,这意味着如果攻击者关心在ExploitShield存在时绕过它,他们只需要做一次实现这些绕过的工作。
隐匿并不总是坏事
“通过隐匿实现安全”的原则经常被安全书呆子引用为安全系统应避免的负面属性。然而,只要防御系统保持隐匿或不可预测,隐匿实际上使系统更安全。基于隐匿的防御技术的困难在于找到可以以低成本进行的隐匿更改,并且攻击者在其被破坏之前无法适应,或者当其隐匿性受到损害时可以以非常低的成本更改的更改。
例如,考虑微软的PatchGuard。PatchGuard通过在检测到修改时崩溃来“保护”系统。PatchGuard的操作被隐藏,并未由微软发布。只要PatchGuard的操作被隐藏和保密,它就可以通过在检测到rootkit所做的修改时使系统崩溃来保护系统。
然而,PatchGuard经常被安全研究人员逆向工程和研究。每次研究人员坐下来意图绕过PatchGuard时,他们都取得了成功。有趣的是接下来发生的事情:在未来的某个时候,微软悄悄发布了一个更新,改变了PatchGuard的行为,使得它仍然实现在检测到修改时使系统崩溃的目标,但不易受到安全研究人员创建的攻击。
在这种情况下,隐匿是有效的。微软制作一个新的PatchGuard非常便宜,实际上内核团队可能有十个“在板凳上”等待当前部署的版本被解剖和绕过。这将内核从静态目标转变为移动目标。隐匿是有效的,因为改变机制是微软主动进行的,更改既便宜又有效,并且攻击者无法轻易准备避免这些更改。
ExploitShield引入的更改非常脆弱,不能轻易修改。也许如果ExploitShield是一个引擎,可以快速提供各种运行时更改并在每个应用程序中随机变化,这种动态会有所不同。
一些实现问题
正确实现HIPS是一项大量工作!到处都有棘手的工程决策要做,作为作者,你将自己介入一个非常棘手的安全情况。ExploitShield做出了一些不必要的实现决策。
IOCTL接口
驱动程序暴露了一个所有用户都可以访问的接口。传统Windows驱动程序的最佳实践要求只有应该访问它的用户才能访问驱动程序的接口。然而,ExploitShield接口对整个系统可访问,包括无特权用户。
驱动程序处理发送给它的消息。我没有完全发现这些消息的类型或格式,但IOCTL处理代码充满了可能犯细微错误的机会。IOCTL处理代码中存在的任何错误都可能导致内核级漏洞,这将危及整个系统的安全性。
这个接口创造了额外的攻击面。
钩取逻辑
每个钩取调用一个例程来检查返回地址是否位于加载的模块中。该例程使用一个全局模块列表,该列表仅通过调用EnumerateLoadedModules并使用程序员提供的回调填充一次。ExploitShield检索加载模块列表的方法中有两个错误。
第一个错误是,在填充全局列表的关键部分周围显然没有互斥。多个线程可以同时调用CreateProcessA,因此理论上用户模式逻辑可能使自己处于不一致状态。
第二个错误是模块仅枚举一次。一旦调用了EnumerateLoadedModules,一个全局标志被设置为true,然后EnumerateLoadedModules再也不会被调用。如果系统观察到对CreateProcess的调用,然后随后加载了一个新模块,并且该模块有对CreateProcess的调用,安全系统将错误地将该模块标记为尝试利用。
这些缺陷都不会使用户面临任何额外危险,它们只是表明编程实践不佳。
为什么完全使用钩取?
在ExploitShield的实现中,一个特别令人困惑的决定是完全使用钩取!对于ExploitShield关心的每个事件(进程创建和文件写入),NT内核中存在强大的回调基础设施。确实,传统防病毒软件的作者经常因过度使用钩取而降低系统稳定性,以至于微软非常强烈地鼓励他们使用这个内核内监视API。
ExploitShield使用不必要的危险编程实践来实现通过使用合法系统服务可能实现的效果,可能暴露出对他们旨在保护的平台缺乏理解。
ExploitShield成功的不可能性
ExploitShield能做什么来改变这种动态?问题是,不多。像这样的防御系统完全依赖于隐匿。一旦被攻击者研究,这些系统就失去了价值。对于像这样的软件,一个问题是反馈循环不会通知安全软件的作者或用户攻击者已经适应了安全系统。另一个问题是系统的隐匿性难以维持。软件必须被客户使用,因此必须在某种意义上可用,如果它对客户可用,它很可能也可供攻击者研究。
我们有什么希望?
需要注意的是,EMET在一个重要方面与ExploitShield不同:EMET旨在破坏利用程序的行为,而ExploitShield旨在破坏在系统上执行有效载荷的行为。这些可能看起来是细微的差别,但可以在“攻击者有多少有效的选择”方面做出区分。当涉及到执行有效载荷时,攻击者的选择几乎是无限的,因为他们已经在执行任意代码。
在这方面,EMET通常不基于隐匿。EMET的作者非常愿意详细讨论他们实施的不同缓解策略,而ExploitShield的作者尚未这样做。
总的来说,我认为如果防御技术对程序或运行时行为做出确定性更改,攻击将失败,直到它适应这种技术。攻击的有效性依赖于技术的隐匿性,以及更改是否影响漏洞、漏洞利用或有效载荷。如果攻击无法适应修改后的环境,那么缓解措施的隐匿性就无关紧要。
然而,如果技术不是隐匿的,而是不可预测的,会怎样?如果有一种防御技术会随机调整系统实现行为,同时保留程序所体验的系统语义行为,会怎样?需要的是识别系统的属性,如果更改,会影响攻击的功能,但不会改变程序的功能。
当这些属性随机变化时,攻击者的选择更少。也许他们知道一个可以超越任何实现细节排列的漏洞。如果他们不知道,然而,他们的攻击是否会成功完全取决于机会。
结论
ExploitShield是一个时间胶囊,包含了2004年最好的基于主机的安全技术。在我看来,它并不代表计算机安全格局的有意义变化。使用的技术完全依赖于隐匿和保密,需要很少的工作来克服,并且只影响计算机攻击的后期阶段,即有效载荷,而不是漏洞利用。
与其他防御技术相比,ExploitShield相形见绌。它使用实施不佳的技术,这些技术针对攻击的阶段,需要攻击者很少的适应来克服。一旦ExploitShield获得足够的市场吸引力,恶意软件作者和漏洞利用编写者将自动化绕过它的技术。
ExploitShield甚至通过安装一个内核模式驱动程序来增加你的攻击面,该驱动程序将处理系统上任何用户发送的消息。该内核模式驱动程序中的任何缺陷都可能导致在你的系统中引入权限提升错误。
它用于查找shellcode的检测逻辑并非完全有缺陷,它包含一个可能导致一些误报的实现错误,然而通常情况是,对运行时库函数的调用,其返回地址不在加载模块的边界内,是可疑的。这个检测签名的问题在于它可以轻松修改以实现相同的效果。此外,这个检测签名并不新颖,HIPS产品已经实施这个检查很长时间了。
这是一个遗憾,因为在我看来,这类软件仍然有一些严重的创新空间……
如果你喜欢这篇文章,分享它: Twitter LinkedIn GitHub Mastodon Hacker News
页面内容
A Bad Day for ExploitShield
Obscurity Isn’t Always Bad
The IOCTL Interface
The Hook Logic
Why Hook At All?
Recent Posts
Investigate your dependencies with Deptective
Buckle up, Buttercup, AIxCC’s scored round is underway!
Maturing your smart contracts beyond private key risk
Unexpected security footguns in Go’s parsers
What we learned reviewing one of the first DKLs
23 libraries from Silence Laboratories
© 2025 Trail of Bits.
Generated with Hugo and Mainroad theme.