红队策略:使用 ADSI接口和反射型 DLL 枚举 Active Directory

1,178 阅读10分钟
原文链接: www.anquanke.com

 

0x00 前言

在当前 Powershell 和 .NET 受到严格监视的环境下,结合使用 C/C++ 和 Active Directory 服务接口(ADSI)在 Cobalt Strike 中对 Active Directory 进行枚举,这或许是个不错的选择。

想象一下,当你正在使用 TIBER-EU 框架CBEST 框架或其他用于红队评估的框架,最终设法进入目标网络。在做了一系列的准备工作,Payload 和 C2 通道成功绕过目标网络的安全措施后,我们该如何进行下一步工作呢?例如怎么确保在探测 Active Directory 时所使用的工具,不会触发反病毒软件或相对应的策略( 例如 AMSI 或脚本块日志记录)呢?

本篇文章介绍了一下方案:

  • 为什么在某些情况下要避免使用基于 Powershell 和 C# 编写的工具?
  • 如何结合使用 C/C++ 和 ADSI 实现类似 PowerView 和 SharpView 的 Active Directory枚举工具?
  • 如何使用反射型 DLL 将此功能嵌入到你最喜欢的 C2 框架/后渗透工具包中。

 

0x01 为什么不使用 Powershell

现在有很多使用 Powershell 编写,可用于对 Active Directory 进行信息获取(枚举)的工具,在之前,使用 Powershell 编写工具一直是一个标准(最著名的是 PowerView),但随着 Powershell 5 的引入,引入了新的光学检测系统(Optical Detection Systems)、反恶意软件扫描界面(AMSI)和脚本块日志记录等一系列的功能系统,倍受蓝队的青睐。如果能正确使用这些新引入的功能系统,蓝队将可以获取到红队使用 Powershell 的详细使用情况。所以我们就不可能因被记录了恶意操作而丢失好不容易建立的权限,这个风险不值得。

即使绕过了 AMSI ,我们还得去攻克如何绕过脚本块日志记录。这通常是需要修改注册表,并且还可以使用 Sysmon 之类的工具进行检测。现在,在许多成熟的环境中,使用 Powershell 进行攻击行为并不是 OPSEC 安全的选择标准。

 

0x02 改用 .NET

在 Powershell 5 中为了蓝队引入了光学组件后,许多红队参与者都意识到不能再使用 Powershell 进行测试了。而且现在很多 Powershell 编写的工具已经使用 .NET/C# 进行重写了,那么为什么不直接使用 C# 呢?

.NET反射库 的提供的 Assembly.Load 方法很有趣,它的出现能够为红队提供更多的便捷。这种方法允许从内存中直接加载 .NET 程序集,而不需要落地任何的文件。所以,我们可以将 C# 编译的工具打包转换成 Byte[] 的数据格式,并使用 Load(Byte[]) 的方法从内存中调用该工具。就像 Cobalt Strike Metasploit 这两款工具中的 execute-assembly 一样,是通过 CLR 将 exe/dll 注入到进程中,并使用该方法在进程中反射加载和执行注入的 C# 程序。

在过去的这段时间里,很多 powershell 工具移植到 C#,主要原因就是因为出现了这些功能。而在本篇文章中提到的 SharpView 就是一个 powershell 移植到 C# 的绝佳的例子。

但是,Microsoft 也注意到了这样的移植样例,所以最近通过将 AMSI 集成到最新的 .NET 版本(v4.8) 中。所以蓝队可以在 CLR 准备调用 byte[] 时,通过 AMSI 扫描此数组数据,判断是否为恶意 C# 程序。这对于蓝队来说作用很大,但是对于红队来说并不是一个友好的消息。

至于绕过 AMSI,已经有很多的案例可以参考,尽管这些方法适用于最新版的 .NET 版本中,但是不能否认的是: C#/.NET 的拉锯战已经开始了。蓝队已经开始尝试利用 hook CLR 和使用 Windows 事件跟踪(ETW)等方法捕获滥用 .NET 的技术。很难想象,未来的 .NET tradecraft 将变得越来越复杂。

0x03 使用 C/C++

那么,如果我们使用 C/C++ 作为编写这些具有攻击性的工具呢?你可能担心这些工具需要放置再目标磁盘上,因为使用 Powershell/C#,可以使用 assembly.load 等方法直接将工具加载到内存中。也许我们也可以使用 C/C++ 来实现类似的功能:以反射方法将已编译的 C/C++ 程序注入到内存中。你可以有很多种选择,我当前最喜欢的是:

我认为本片文章的大多数阅读者都是熟悉反射型 DLL 注入技术的,如果不熟悉,为建议你去阅读 Stephen Fewer’s Github 页面上的概述

 

0x04 Active Directory 服务接口(ADSI)

我们回到前面提到的用例:枚举 Active Directory。我们希望在枚举 AD 信息的时候不会触发 AMSI 或者是不留下明显的事件日志(伪造事件日志内容),让我们看看使用 C/C++ 是否可以做到这一点。同时对 powerview 和 sharpview 之类的工具保持更多的关注。要与 Active Directory 进行对接并枚举其对象属性,我们可以使用 Active Directory 服务接口(ADSI),那么 ADSI 到底是什么?

Active Directory 服务接口(ADSI)*)是一组 COM 接口,用于访问来自不同网络提供商的目录服务的功能。独立软件供应商和开发人员可以使用 ADSI 对其产品和应用程序进行目录启用”

听起来很不错,让我们看看是否可以在 C/C++ 中构建自己的 Active Directory 枚举工具。为此我们可以阅读 MSDN 上面的文档,并尝试编写一个程序。但是,Microsoft 的 Github 上为我们提供了很优秀的示例,并使用这些示例开发我们自己的客户端(无需重新造轮子)。然我们看看下面的示例: QueryUsers

QueryUsers : 向 Active Directory 域分区查询和指定过滤器匹配的用户对象。
该示例使用 IDirectorySearch 执行搜索。

使用此代码,我们可以搜索特定用户或所有用户,并返回所有标识用户的所有属性。因此,这段代码可以总结如下:

  1. ADSI 是基于 COM 构建的,因此我们需要使用 CoInitialize() 函数在程序内初始化 COM;
  2. 接下来,我们使用 ADsOpenObject()LDAP rootDSE 进行绑定,因此我们可以收集有关 AD 的信息,并使用返回的 IADs COM 对象获取 defaultNamingContext
  3. 当拥有 defaultNamingContext 时,我们可以再次使用 ADsOpenObject() 对 Domain 容器进行绑定,使用它并返回 IDirectorySearch COM接口,该接口可用于对 Active Directory 的查询/搜索;
  4. 调用 FindUsers() 函数时,它将基于函数参数和以下字符串构造一个 LDAP 过滤器“(&(objectClass=user)(objectCategory=person)%s)”。如果我们为改程序提供以下搜索过滤器参数:“(sAMAccountName=Administrator)”,那么我们的 LDAP 过滤器实则为:(&(objectClass=user)(objectCategory=person) (sAMAccountName=Administrator))”
  5. 使用 ADS_SEARCHPREF_INFO 结构作为搜索首选项;
  6. 执行 IDirectorySearch 对象中的 ExecuteSearch 方法,该方法应基于我们的 LDAP 过滤器,并返回所有结果;
  7. 最后,使用 GetFirstRowGetNextColumnNameGetColumnGetNextRow 方法遍历结果,输出特定的用户属性

有了对这段代码的解释,以及有关 ADSI 编程接口的一些知识后,我们可以继续使用 C/C++ 构建我们自己定义的枚举程序。

 

0x05 集成到常用的 C2 框架

如何将这种使用 C/C++ 编写的工具集成到平时使用的 C2/后渗透框架中呢?例如,Cobalt Strike 就是一款非常受欢迎的红队模拟对抗框架的工具包。 Cobalt Strike 具有用于代码/DLL 注入的多个功能选项,并且具有功能强大的脚本语言,可用于扩展和修改 Cobalt Strike 客户端。例如:如果你要在内存中反射执行 C/C++ 编写的 DLL,并且可以为其提供参数,则 bdllspawn 功能就是一个很好的实现。

对于 Metasploit,请阅读 documentation on reflective DLL injection,或者,如果要使用反射执行 C/C++ 编写的工具,可以使用 Donut 模块。

建立自己的 C2 框架?将你最喜欢的 shellcode 注入技术与 Donut 或 sRDI 结合使用,也可开盒即食。你可能需要看看 pinjectra,也许可以给你带来注入方面的灵感。

 

0x06 POC 枚举验证

作为验证,我们开发了一种基于 ADSI 和反射型DLL 的Active Directory 枚举工具,可以在 Cobalt Strike 中适用,该工具叫 Recon-AD,目前由七个 Reflective DLL 和对应的 AggressorScript 组成。

该工具包括以下功能:

  • Recon-AD-Domain: 查询域信息(包括域名、GUID、站点名称、密码策略、域控列表等)
  • Recon-AD-Users: 查询用户对象和相应的属性
  • Recon-AD-Groups: 查询组对象和相应的属性
  • Recon-AD-Computers: 查询计算机对象和相应的属性
  • Recon-AD-SPNs: 查询配置了服务主体名称(SPN)的用户对象并显示有用的属性
  • Recon-AD-AllLocalGroups: 在计算机是上查询所有本地组和组成员
  • Recon-AD-LocalGroups: 在计算机上查询特定的本地组和组成员(默认 Administrators 组)

以下截图显示了如何使用该工具的一些示例:

  • Github Recon-AD 下载工具,并在 Cobalt Strike 中在家 CNA 脚本
  • 使用 Recon-AD-Domain 显示本地机器的 Domain 信息
  • 要列出 Domain Admins 组的属性信息,可以使用 Recon-AD-Groups Domain Admins 命令

  • 要列出指定 用户的属性,可以使用 Recon-AD-User username 命令

此外,还有一个命令可以让你枚举计算机对象,该命令列出所以启用 SPN 的用户账号,并使用 WinNT ADSI 提供程序枚举远程计算机上的本地组。我们计划很快发布更多有用的枚举选项。

 

0x07 结论

高级的内存扫描技术和 hook API 检测内存中反射型DLL 注入的功能选项,是一个优秀的 EDR 应该具备的能力。如果在你的目标环境中发现有存在使用 EDR 之类的高级检测软件,则你可能需要对 Cobalt Strike 做一些拓展,旨在帮助你绕过内存检测

新的监视器和光学防御系统正在应用于较新的 Microsoft 操作系统和安全产品中,这应有助于蓝队在检测其环境的恶意行为。尽管长期以来,后渗透中比较中意使用 powershell,但现在红队方面,已经逐渐使用别的编程语言(.NET)进行替换。当前,.NET 是后渗透中最受欢迎的编程语言,但是目前 Microsoft 正通过添加一系列的组件,来缓解.NET 在后渗透的作用。时间将为我们证明 .NET 在后渗透阶段能够活跃多长时间。

在本文中,我们介绍了 Active Directory 服务接口(ADSI)编程接口以及如何将其与 C/C++ 结合编程,最后通过 Cobalt Strike 使用并枚举 AD 信息。