欢迎来到 黑吧安全网 聚焦网络安全前沿资讯,精华内容,交流技术心得!

看我如何一步步将基于堆的 AMSI 绕过做到接近完美

来源:本站整理 作者:佚名 时间:2019-10-06 TAG: 我要投稿

这篇博文描述了如何在 Excel 中实现使用 VBA (Visual Basic for Applications) 绕过微软的AMSI (Antimalware Scan Interface)。 与其他的绕过思路不同的是,这种方法不使用硬编码的偏移量或操作码,而是识别堆上的关键数据并对其进行修改。 其他研究人员以前也提到过基于堆的绕过,但在撰写本文时,还没有可用的公共 PoC。 这篇博文将为读者提供关于 AMSI 实现的一些见解,以及一种绕过它的通用方法。
引言
自从微软推出 AMSI 实现以来,已经发布了许多关于绕过其实现机制的文章。 白色代码(Code White)安全团队实施红队的使用场景,其中网络钓鱼扮演了重要角色。 网络钓鱼通常与微软 Office 有关,具体来说是与用 VBA 编写的恶意脚本有关。 根据微软的 AMSI,还包括放入 MS Office 文档中的 VBA 代码。 这一事实促使我在今年早些时候做了一些研究。 已经对 AMSI 是否以及如何在 MS Office Excel 环境中被击败进行了评估。
在过去几年已经有人发表了几种不同的方法来绕过 AMSI。 以下链接是曾被我用作启发或参考的资料:
·https://modexp.wordpress.com/2019/06/03/disable-amsi-wldp-dotnet 列出了许多其他的 writeups 并实现了一个很好的基于数据的方法
·https://outflank.nl/blog/2019/04/17/bypassing-amsi-for-vba/ 用于 VBA 的 AMSI 绕过技术
上面的列表中的第一篇文章也提到了基于堆的方法。 独立于这些记载,Code White 的方法恰恰使用了这个想法。 在撰写本文期间,还没有实现这一想法的公开代码。 这是写这篇博文的另一个动机。 将这种绕过技术移植到 MS Excel /VBA 中显示了一些有待解决的难题。 以下各章按时间顺序展示了 Code White 实现的演变过程:
·用 C 语言实现我们自己的 AMSI 客户端,以便拥有一个调试平台
·理解 AMSI API 是如何工作的
·在我们自己的客户端中绕过 AMSI
·将这种方法移植到 VBA 中
·改进绕过思路
·改进绕过思路-使其能在生产环境中就绪
实现我们自己的 AMSI 客户端
为了简化调试,我们将用 C 语言实现我们自己的一个小的 AMSI 客户端,它会触发对恶意字符串 amsiutils 的扫描。 这个字符串被标记为 evil,因为马特 · 格雷伯的 AMSI 绕过方式用到了这个字符串。扫描这个简单的字符串指示了一个简单的方法来检查 AMSI 是否工作,并验证我们的绕过思路是否可行。 sinn3r 的 github 上可以找到一个即时使用的 AMSI 客户端。这段代码为我们提供了一个很好的起点,同时也包含了一些重要的提示,比如本地组策略中的前置条件。
我们将使用 Microsoft Visual Studio Community 2017 实现我们自己的测试客户端。在第一步中,我们得到两个函数,amsiInit()和amsiScan(),不要与amsi.dll 的导出函数混淆在一起。稍后,我们将添加另一个函数amsiByPass(),该函数会执行如其名称所暗示的功能。请在这个 gist 中查看最终的代码和绕过方式。

运行该程序会生成以下输出:

这意味着我们的amsiutils 被认为是恶意的字符串。 现在我们可以开始进行绕过研究了。
理解 AMSI 的结构
正如我们所承诺的那样,我们希望实现一个基于堆的绕过。 但为什么是基于堆的呢?
首先,我们必须理解,使用 AMSI API 需要初始化一个所谓的 AMSI 上下文(HAMSICONTEXT)。 必须使用函数 AMSIInitialize ()初始化此上下文。 每当我们想要扫描某些内容时,例如通过调用 AMSIScanBuffer() ,我们必须将上下文作为第一个参数进行传递。 如果此上下文背后的数据无效,相关的 AMSI 函数将调用失败。 这就是我们所追求的,但我们会在稍后再谈到这一点。
看一下 HAMSICONTEXT,我们将看到这个类型被预处理器解析为以下内容:

所以我们在这里得到的是一个指向一个叫做 HAMSICONTEXT 的结构体的指针。 让我们通过在客户端中打印“ amsiContext”的内存地址来查看这个指针指向的位置。 这将使我们能够使用 windbg 检查其内容:

变量本身的地址是0x16a144(注意我们这里是个32位的程序) ,它的内容是0x16c8b10,这就是它指向的位置。 在地址0x16c8b10处,我们看到一些内存,以标识有效 AMSI 上下文的 ASCII 字符‘AMSI'作为开头。 内存字段下面的输出是通过’!address’打印当前进程的内存布局。

在这里,我们可以看到地址0x16c8b10被分配到一个区域,从0x16c0000到0x16df0000,这个区域被标识为“堆”。 OK,这意味着AmsiInitialize() 为我们提供了一个指向堆上的结构体的指针。使用 IDA 对 AMSIInitialize() 进行更深入的研究后,提供了一些这个方面的证据:

函数使用特定的COM API——CoTaskMemAlloc ()分配16个字节(10h)。 后者是堆的抽象层。 可以点击这里及这里了解详情。 在分配缓冲区之后,魔法词 0x49534D41被写到块的开头,这就是我们用 ASCII 表示的‘ AMSI’。

[1] [2] [3] [4]  下一页

【声明】:黑吧安全网(http://www.myhack58.com)登载此文出于传递更多信息之目的,并不代表本站赞同其观点和对其真实性负责,仅适于网络安全技术爱好者学习研究使用,学习中请遵循国家相关法律法规。如有问题请联系我们,联系邮箱admin@myhack58.com,我们会在最短的时间内进行处理。
  • 最新更新
    • 相关阅读
      • 本类热门
        • 最近下载