引言

哈希传递(Pass-the-hash)是一种非常古老的技术,最初由 Paul Ashton 在1997年发布的。尽管如此,“哈希传递”的存在已经超过了10年。 它在大多数勒索软件攻击中被大量使用,比如在马斯特里赫特大学(University of Maastricht)。但为什么这仍然是个问题呢?

首先,让我们对这种攻击有一个高层次的概述。 Pass-the-hash 是一种技术,攻击者在获得本地管理员权限之后,通过这种技术从被入侵的工作站或服务器上的内存中捕获 NT (LM) 哈希。 使用这些被盗用的凭据,他们可以代表受到威胁的用户打开一个新的身份验证会话,以后还可以这样做。 使用 PsExec、 WinRM、 RDP 等按照该用户的侧向移动。

对于 Pass-the-Hash 攻击并没有真正的修复,因为它利用了 SSO (Single-Sign On)协议。 任何使用 SSO 的系统都容易受到类似的攻击,比如 PtH。 因为大多数组织都使用活动目录作为其身份服务,而 AD 将 SSO 作为其主要特性。这意味着许多组织必须处理这个问题,否则,它们就不能很好地抵御“传递哈希”攻击。

SSO 是一个身份验证过程,允许用户使用一组凭据登录,以访问网络上的资源,而无需再次输入密码。

假设你以用户 Bob (DBA)的身份登录,并希望访问 SQL 服务器上的 SQL 数据库。 而不是再次输入你的密码。 你只需要点击“连接”。

按下连接按钮后。 你已经进入并且可以访问所有被监听的 SQL 数据库。

你不必再次键入密码的原因是,因为 Windows 将你的凭据缓存在内存中,以提供 SSO 体验。

这也是为什么你不能完全防止哈希传递攻击,因为这意味着你必须干掉单点登录。 然而,因为很难防止这种攻击,这并不意味着你对此无能为力。 事实上,微软已经在这方面提供了很多指导,可以减轻这种攻击。

凭证存取 -T1003

在攻击者可以执行传递哈希攻击之前。首先需要获得凭证,并且所有凭据都存储在 LSASS 进程内存中,因此每次用户登录时,他或她的凭证被缓存在内存中,以提供我们前面讨论过的 SSO 体验。 当用户登录到一台机器时,无论是通过 RDP 本地登录,还是通过 Runas 在另一个帐户下执行操作,凭证都会被缓存。

下面是一个示例,其中我们从 WINDOWS2012 机器上的内存中提取凭据。

现在让我们假设我们已经设法欺骗 Alice 登录到我们已经入侵的机器上,那么会发生什么呢?

因为Alice已经登录了我们的跳板机器。 她的凭据已经丢失,这意味着我们现在可以从内存中提取凭据并开始模拟 Alice 以代表她访问资源。

哈希传递 – T1705

我们现在已经从 Alice 那里获得了凭据,因此我们现在可以开始执行 哈希传递攻击以模拟她并代表她访问所有资源。

现在,由于 Alice 可以访问 FILESERVER,我们可以作为用户 Alice 横向移动到这个服务器。

由于我们对 FILESERVER 拥有完全的管理特权,现在我们也可以将凭据转储到这台服务器上。

现在我们已经设法从 Bob 那里获得了凭据,因为他最近登录了这个服务器。 Bob 是域管理员,所以如果我们模仿Bob。 我们可以接触到任何东西。

与前面一样,我们现在要执行哈希传递攻击来模拟 Bob 并代表他访问资源。

数据外泄

例如,我们现在可以横向移动到域控制器服务器,它也被称为最关键的服务器,因为它拥有每个用户和计算机的所有凭证。

访问域控制器是一回事,但是攻击者的最终目标是泄露数据。攻击者并不关心他们是否成为DA或访问DC。当数据泄露时,它会影响你的生意。

这是一个例子,我们可以访问 SQL 服务器,因为我们已经是 Domain Admin(域管理员),但是正如前面所说的。 DA 无关紧要,重要的是数据。 下面是存储在硬盘驱动器上的所有 SQL 数据库的示例。 也许这些数据对我们有很大的价值,如果这些数据泄露出去,可能会对我们的业务造成影响。

检测

检测凭证访问和哈希传递技术一直是相当困难的。 如果真像我们想的那么简单。 那么大多数组织就已经有了适当的检测规则。

一个伟大的事情是,微软发布了 Defender ATP,这是一个 EDR 解决方案,利用了云的力量。 如果你必须选择一个 EDR 解决方案。 我建议选择Defender ATP。 这是一个很好的解决方案,可以提高所有端点的可见性,并且使你的生活更加容易,因为你可以通过门户获得无时间的警报。

下面是我们从 LSASS 进程内存中提取凭据之后收到的一个示例。

上面的警报与另一个事件有关,即哈希传递。

建议

第一件事是确保你做了基本的工作,也就是确保所有的 IT 管理员对他们的管理任务有一个单独的帐户,并且如果你想要完美地完成这些任务的话。 甚至建议使用单独的加固工作站来执行所有管理任务。

缓解哈希传递攻击的最佳方法是查看微软管理层模型——这是一种安全模型,通过确保较高层不能登录较低层来减轻凭证盗窃,反之亦然。

· 第0层=可以访问网络上所有关键服务器的域管理员或同等级别的管理员

· 第1层=服务器管理员/系统管理员,他们可以访问重要的服务器,但不是“关键”的

· 第2层=工作站管理员/帮助台,可以访问客户的工作站,但不能访问第1层和第0层管理员的独立的加固工作站

现在你可能想知道,当你实现这个层模型时,它看起来是什么样的。 也许你还想知道你的组织是否有安全措施来减轻哈希传递。

部署管理层模型可能需要一段时间,但这是值得的。 这是一个关于在 AD 中如何设计一个层模型的例子。

我们创建了一些OU,在这些OU中。它包含不同的对象。作为一个例子。在第0层OU,我们有不同的子OU。你可以看到设备和第0层服务器。在设备OU中,它包含你的域管理员或同等人员的独立加固工作站。在第0层服务器中,它包含最关键的服务器对象,比如域控制器、Azure AD Connect、ADFS、PKI、SCCM等等。

现在有另一个 OU 叫做 Tier 1,它包含了不同的子 OU,以及设备和 Tier 1 服务器。 在设备 OU 中,它包含服务器管理员的独立硬化工作站和第一层服务器 OU。 它包含所有重要的服务器,但不是关键的。

在你指定之后。 一个 GPO 需要被创建和链接到设备 & 第1层(Tier 1)服务器 OU,这个 GPO 拒绝域管理员和等价物的登录权(第0层管理员)。

在这里你可以看到,我已经创建了一个 GPO 与拒绝登录权限的设备和第一层服务器。 所有0级管理员不能登录到第1层管理员设备或第1层服务器。

· 拒绝从网络访问此计算机

· 拒绝作为批处理作业登录

· 拒绝作为服务登录

· 拒绝本地登录

· 拒绝通过远程桌面服务登录

让我们验证我们不能登录到第1层资产。 例如,我们正在尝试登录第1层中的 FILESERVER。 访问被拒绝,因为我们的 GPO 拒绝了登录访问。

现在,当我们试图使用 PsExec 登录到文件服务器时,我们也会被拒绝。

最后,但并非最不重要。 还有第二层,它包含了客户端的所有工作站。 此层由帮助台/工作站管理员管理。

现在创建另一个 GPO ,但这一次这个 GPO 需要拒绝登录权限。 我们必须指定,第0层和第1层管理员都不允许登录客户的工作站和第2层管理员的单独工作站。

· 拒绝从网络访问此计算机

· 拒绝作为批处理作业登录

· 拒绝作为服务登录

· 拒绝本地登录

· 拒绝通过远程桌面服务登录

现在,当我们试图将RDP作为第0/1层管理员发送到客户机的工作站时,我们的访问将被拒绝,因为客户的工作站位于第2层区域。

我经常看到的几个例子,可能会导致层模型绕过,是链接到0层资产的GPO,来自第1层的用户可以修改它的设置。 确保所有链接到域对象的 GPO 和所有0级资产都由0级管理员管理。

另外,如果你在域管理员中有服务帐户,并且这些服务帐户作为具有 DA 特权的服务器上的服务运行,那么最好知道这一点。 这意味着你需要将该服务器视为一个第0层资产。

总结

管理层模型(Administrative Tier Model)是一个很好的安全架构,可以防止凭证被盗用,因为较高的层不能登录较低的层,反之亦然,这意味着例如域管理员的凭证永远不能在打印服务器或客户机的工作站上公开。 没有什么是完美的,但部署层模型和在所有工作站和服务器上安装 Defender ATP 将使攻击者更加困难。

如果你没有任何类似的安全措施,如上所示。 我们可能得出结论,你根本没有实现哈希传递攻击的缓解措施,这没有关系,但是现在是时候实现它了。

参考资料

缓解哈希传递攻击(PtH)和其他凭证窃取攻击,第1版和第2版

微软提出的管理层模型

微软 Defender ATP 高级威胁保护

引言

哈希传递(Pass-the-hash)是一种非常古老的技术,最初由 Paul Ashton 在1997年发布的。尽管如此,“哈希传递”的存在已经超过了10年。 它在大多数勒索软件攻击中被大量使用,比如在马斯特里赫特大学(University of Maastricht)。但为什么这仍然是个问题呢?

首先,让我们对这种攻击有一个高层次的概述。 Pass-the-hash 是一种技术,攻击者在获得本地管理员权限之后,通过这种技术从被入侵的工作站或服务器上的内存中捕获 NT (LM) 哈希。 使用这些被盗用的凭据,他们可以代表受到威胁的用户打开一个新的身份验证会话,以后还可以这样做。 使用 PsExec、 WinRM、 RDP 等按照该用户的侧向移动。

对于 Pass-the-Hash 攻击并没有真正的修复,因为它利用了 SSO (Single-Sign On)协议。 任何使用 SSO 的系统都容易受到类似的攻击,比如 PtH。 因为大多数组织都使用活动目录作为其身份服务,而 AD 将 SSO 作为其主要特性。这意味着许多组织必须处理这个问题,否则,它们就不能很好地抵御“传递哈希”攻击。

SSO 是一个身份验证过程,允许用户使用一组凭据登录,以访问网络上的资源,而无需再次输入密码。

假设你以用户 Bob (DBA)的身份登录,并希望访问 SQL 服务器上的 SQL 数据库。 而不是再次输入你的密码。 你只需要点击“连接”。

按下连接按钮后。 你已经进入并且可以访问所有被监听的 SQL 数据库。

你不必再次键入密码的原因是,因为 Windows 将你的凭据缓存在内存中,以提供 SSO 体验。

这也是为什么你不能完全防止哈希传递攻击,因为这意味着你必须干掉单点登录。 然而,因为很难防止这种攻击,这并不意味着你对此无能为力。 事实上,微软已经在这方面提供了很多指导,可以减轻这种攻击。

凭证存取 -T1003

在攻击者可以执行传递哈希攻击之前。首先需要获得凭证,并且所有凭据都存储在 LSASS 进程内存中,因此每次用户登录时,他或她的凭证被缓存在内存中,以提供我们前面讨论过的 SSO 体验。 当用户登录到一台机器时,无论是通过 RDP 本地登录,还是通过 Runas 在另一个帐户下执行操作,凭证都会被缓存。

下面是一个示例,其中我们从 WINDOWS2012 机器上的内存中提取凭据。

现在让我们假设我们已经设法欺骗 Alice 登录到我们已经入侵的机器上,那么会发生什么呢?

因为Alice已经登录了我们的跳板机器。 她的凭据已经丢失,这意味着我们现在可以从内存中提取凭据并开始模拟 Alice 以代表她访问资源。

哈希传递 – T1705

我们现在已经从 Alice 那里获得了凭据,因此我们现在可以开始执行 哈希传递攻击以模拟她并代表她访问所有资源。

现在,由于 Alice 可以访问 FILESERVER,我们可以作为用户 Alice 横向移动到这个服务器。

由于我们对 FILESERVER 拥有完全的管理特权,现在我们也可以将凭据转储到这台服务器上。

现在我们已经设法从 Bob 那里获得了凭据,因为他最近登录了这个服务器。 Bob 是域管理员,所以如果我们模仿Bob。 我们可以接触到任何东西。

与前面一样,我们现在要执行哈希传递攻击来模拟 Bob 并代表他访问资源。

数据外泄

例如,我们现在可以横向移动到域控制器服务器,它也被称为最关键的服务器,因为它拥有每个用户和计算机的所有凭证。

访问域控制器是一回事,但是攻击者的最终目标是泄露数据。攻击者并不关心他们是否成为DA或访问DC。当数据泄露时,它会影响你的生意。

这是一个例子,我们可以访问 SQL 服务器,因为我们已经是 Domain Admin(域管理员),但是正如前面所说的。 DA 无关紧要,重要的是数据。 下面是存储在硬盘驱动器上的所有 SQL 数据库的示例。 也许这些数据对我们有很大的价值,如果这些数据泄露出去,可能会对我们的业务造成影响。

检测

检测凭证访问和哈希传递技术一直是相当困难的。 如果真像我们想的那么简单。 那么大多数组织就已经有了适当的检测规则。

一个伟大的事情是,微软发布了 Defender ATP,这是一个 EDR 解决方案,利用了云的力量。 如果你必须选择一个 EDR 解决方案。 我建议选择Defender ATP。 这是一个很好的解决方案,可以提高所有端点的可见性,并且使你的生活更加容易,因为你可以通过门户获得无时间的警报。

下面是我们从 LSASS 进程内存中提取凭据之后收到的一个示例。

上面的警报与另一个事件有关,即哈希传递。

建议

第一件事是确保你做了基本的工作,也就是确保所有的 IT 管理员对他们的管理任务有一个单独的帐户,并且如果你想要完美地完成这些任务的话。 甚至建议使用单独的加固工作站来执行所有管理任务。

缓解哈希传递攻击的最佳方法是查看微软管理层模型——这是一种安全模型,通过确保较高层不能登录较低层来减轻凭证盗窃,反之亦然。

· 第0层=可以访问网络上所有关键服务器的域管理员或同等级别的管理员

· 第1层=服务器管理员/系统管理员,他们可以访问重要的服务器,但不是“关键”的

· 第2层=工作站管理员/帮助台,可以访问客户的工作站,但不能访问第1层和第0层管理员的独立的加固工作站

现在你可能想知道,当你实现这个层模型时,它看起来是什么样的。 也许你还想知道你的组织是否有安全措施来减轻哈希传递。

部署管理层模型可能需要一段时间,但这是值得的。 这是一个关于在 AD 中如何设计一个层模型的例子。

我们创建了一些OU,在这些OU中。它包含不同的对象。作为一个例子。在第0层OU,我们有不同的子OU。你可以看到设备和第0层服务器。在设备OU中,它包含你的域管理员或同等人员的独立加固工作站。在第0层服务器中,它包含最关键的服务器对象,比如域控制器、Azure AD Connect、ADFS、PKI、SCCM等等。

现在有另一个 OU 叫做 Tier 1,它包含了不同的子 OU,以及设备和 Tier 1 服务器。 在设备 OU 中,它包含服务器管理员的独立硬化工作站和第一层服务器 OU。 它包含所有重要的服务器,但不是关键的。

在你指定之后。 一个 GPO 需要被创建和链接到设备 & 第1层(Tier 1)服务器 OU,这个 GPO 拒绝域管理员和等价物的登录权(第0层管理员)。

在这里你可以看到,我已经创建了一个 GPO 与拒绝登录权限的设备和第一层服务器。 所有0级管理员不能登录到第1层管理员设备或第1层服务器。

· 拒绝从网络访问此计算机

· 拒绝作为批处理作业登录

· 拒绝作为服务登录

· 拒绝本地登录

· 拒绝通过远程桌面服务登录

让我们验证我们不能登录到第1层资产。 例如,我们正在尝试登录第1层中的 FILESERVER。 访问被拒绝,因为我们的 GPO 拒绝了登录访问。

现在,当我们试图使用 PsExec 登录到文件服务器时,我们也会被拒绝。

最后,但并非最不重要。 还有第二层,它包含了客户端的所有工作站。 此层由帮助台/工作站管理员管理。

现在创建另一个 GPO ,但这一次这个 GPO 需要拒绝登录权限。 我们必须指定,第0层和第1层管理员都不允许登录客户的工作站和第2层管理员的单独工作站。

· 拒绝从网络访问此计算机

· 拒绝作为批处理作业登录

· 拒绝作为服务登录

· 拒绝本地登录

· 拒绝通过远程桌面服务登录

现在,当我们试图将RDP作为第0/1层管理员发送到客户机的工作站时,我们的访问将被拒绝,因为客户的工作站位于第2层区域。

我经常看到的几个例子,可能会导致层模型绕过,是链接到0层资产的GPO,来自第1层的用户可以修改它的设置。 确保所有链接到域对象的 GPO 和所有0级资产都由0级管理员管理。

另外,如果你在域管理员中有服务帐户,并且这些服务帐户作为具有 DA 特权的服务器上的服务运行,那么最好知道这一点。 这意味着你需要将该服务器视为一个第0层资产。

总结

管理层模型(Administrative Tier Model)是一个很好的安全架构,可以防止凭证被盗用,因为较高的层不能登录较低的层,反之亦然,这意味着例如域管理员的凭证永远不能在打印服务器或客户机的工作站上公开。 没有什么是完美的,但部署层模型和在所有工作站和服务器上安装 Defender ATP 将使攻击者更加困难。

如果你没有任何类似的安全措施,如上所示。 我们可能得出结论,你根本没有实现哈希传递攻击的缓解措施,这没有关系,但是现在是时候实现它了。

参考资料

缓解哈希传递攻击(PtH)和其他凭证窃取攻击,第1版和第2版

微软提出的管理层模型

微软 Defender ATP 高级威胁保护

摘要

在我的文章《攻击 AzureAzure AD PowerZure 介绍》中,我提供了几种攻击 Azure AzureAD 的策略、技术和过程(TTPs) ,并发布了利用 PowerZure 来自动化操作其中的一些内容。 我坚信,当一个新的战术或工具开发出来后,防守指南应该遵循以帮助蓝队从这些战术或工具中获得安全感。 不幸的是,Azure 对于发生在 Azure 内部的操作的日志记录能力还有很多不足之处。

本文的目的是对 Azure 内部的原生活动日志服务功能进行概述,并深入探讨如何检测我上一篇文章中列出的许多 TTPs,以及关于如何从活动日志服务中获取更多细节的建议,而不仅仅是显示在‘ summary’选项卡上的内容。

概览

每当一个操作在 Azure 中完成,一个事件就会生成并保存在活动日志服务中。 在活动日志中,用户可以看到所有操作并应用基本过滤器(时间跨度、严重性等) 日志中的操作(事件)是根据操作的状态分离出来的,即事件何时开始、何时更新、何时结束等等。 为了查看该操作中的其他子事件,用户必须单击该事件,然后其他状态事件将填充。 这很重要,因为围绕操作的细节取决于状态。

image.png

1: 单击第一个事件会显示一个子事件

例如,当一个用户被分配到一个角色(例如 contributor)时,会启动一个创建事件的操作,但是缺少必要的细节。

image.png

2: Azure 中为角色分配创建的初始事件

一旦操作完成,另一个子事件会被创建,然后公开必要的细节。

 image.png

3: 单击子事件时会显示更多的详细信息

在本例中,“ Message”字段包含添加到角色的用户的用户名,与不包含此信息的原始事件相比较。

警报

可以从活动日志中直接配置警报。 每当一个操作发生时,Azure 都会给出一个选项,一旦你点击了这个事件,就可以为这个操作创建一个警报。

 image.png

4: 基于事件创建新警报的选项

在创建规则时,可以选择更改条件。 当保留默认条件时,它是一个非常常见的条件,如图5所示:

image.png 

5: 条件被设置为成功的任何信息级的事件。 这将产生几个良性警报

条件可以通过点击垃圾桶图标和点击条件下的添加来改变。

 image.png

6: Runbooks 的警报条件

从这里,可以将警报操作设置为几个选项。

 image.png

7: 警报选项

细节决定一切,是吗?

获取一个常规事件对于警报非常有用,但是对于分析人员来说,拥有与该事件相关的细节是非常关键的,比如谁开始了操作,操作的目标对象是什么,等等。 不幸的是,有几个操作报告的细节信息很少。

命令执行

在虚拟机上运行命令时,会创建一个事件,但是没有记录运行的命令。

image.png 

8: VM 上运行命令的事件中返回的所有内容

摘要选项卡显示了命令的执行时间和执行者,但是为了查看执行时 VM 的名称,用户必须进入 JSON 选项卡并查看‘ id’属性才能查看事件的作用域。

 image.png

9: 作用域路径中 VM 的名称

无论何时向 Windows 虚拟机发出命令,Azure 都将输入的命令作为 PowerShell 脚本存储在内部端点上

C:\Packages\Plugins\Microsoft.CPlat.Core.RunCommandWindows\1.1.3\Downloads

如果攻击者没有删除脚本,这就允许分析人员可能看到在虚拟机上运行了哪些命令。 当然,我总是建议你使用额外的防御工具,并在组策略中对这些端点启用脚本块日志记录。

钥匙库

由于其用途,钥匙库在 Azure 中非常敏感。 它们可以存储证书、密码和密钥,因此它们也应该受到严密的访问监控。 进入钥匙库不会产生事件,也不会泄露密钥。 这就是这个资源与以角色为基础的存取控制的预期目的; Azure 而言,如果用户访问他们有权访问的资源,它就不值得记录事件。 钥匙库仅限于其所有者,由所有者编辑访问策略,允许其他用户访问该钥匙库。 但是,作为全局参与者(Global Contributor),用户可以编辑任何钥匙库的权限并允许自己访问该钥匙库。 这确实会产生一个事件,更新钥匙库

 image.png

钥匙库更新时的日志

事件摘要显示了谁更新了保险库的权限,但是保险库的名称在 JSON 输出中而不是摘要中。

 image.png

10: JSON 选项卡中的作用域显示了库名称

这样做的主要问题是,它没有显示谁被添加到访问策略中。 因此,确定谁被添加的唯一方法,就是进入每个保险库并确定访问策略上的所有用户是否都应该在那里。

Runbooks

PowerZure 中,一个利用 Runbook 优势的函数是 Create-Backdoor 这是通过创建一个 Runbook 来实现的,该 Runbook 将提供一个新帐户,并在执行时将其分配给 Contributor 角色。 它不是自动执行,而是生成一个 Webhook URI,这个 URI 可以传递到 Execute-Backdoor,这个 Execute-Backdoor 将根据需要运行 Runbook 这需要管理员角色,因为只有管理员可以在 Azure AD 中创建用户。 幸运的是,创建 Runbook 会生成几个事件,因此可以直接检测这些事件。 第一个关键事件,是创建 Runbook,然后创建 Webhook,然后生成该 Webhook URI

 image.png

11: PowerZure “ Create-Backdoor”的操作序列

这样做的问题是,‘event initiated by’字段是不正确的。 如果 Runbook 是从命令行创建的,则该字段始终由租户管理员(而不是实际创建 Runbook 的人)填充。 为了确保我的头脑清醒,我用三个不同的帐户测试了它,每次事件由我的管理帐户发起,即使它没有登录到任何地方。

 image.png

12: 由字段启动的事件显示了通过 CLI 创建 Webhook Runbook 时的租户管理员,而不是实际用户

截止 2020124日,这个 bug 已经提交给微软,我现在正在等待他们的回复。

分组任务

即使本地活动目录(AD) AzureAD 同步,也不可能将用户添加到本地 AD 组。 然而,将用户添加到 Azure Azure 组中并不会在活动日志下生成事件。 Azuread 有自己的事件查看器,称为审计日志。 这确实提供了操作的必要细节,但是在 AzureAD 中不能为这些事件配置警报,除非正在使用 Log Analytics 服务,并且 AzureAD 被配置为向 Log Analytics 发送日志。 然后警报将不得不从日志分析生成,而不是 AzureAD 的审计日志。

虚拟机磁盘

如果攻击者侵入了一个全局参与者(Global Contributor)的帐户,他们可能会生成一个下载 VM 磁盘的链接。 这可以通过操作名获取磁盘 SAS URI”检测到。 摘要或 JSON 选项卡中没有显示链接,磁盘是否实际下载也没有显示链接。 只创建一个泛型事件,除了磁盘名之外没有其他详细信息。

防御方法

由于 Azure 使用了以角色为基础的存取控制访问控制(RBAC) ,它应该被视为类似于本地 AD 组成员,这意味着它应该遵循最少特权访问的方法。 Global Contributor 角色分配给用户可以为用户提供大量的访问和执行能力。 建议检查在 Azure 中哪些角色实际上是操作所必需的。 Azure 包含许多全球角色之外的内置角色,可以在这里查看。 此外,定制角色的创建可能更适合企业的需要。

遵循最低特权访问的方法,Azure 确实提供了特权身份管理(Privileged Identity ManagementPIM)服务,但是要付出一定的代价,但是我们强烈推荐这种服务。

组织希望尽量减少能够访问安全信息或资源的人数,因为这样可以减少恶意行为者获得该访问权限的机会,或者减少授权用户无意中影响敏感资源的机会。 然而,用户仍然需要在 Azure AD Azure Office 365 SaaS 应用程序中执行特权操作。 组织可以向用户提供对 Azure 资源和 Azure AD 的即时(JIT)特权访问。 有必要监督这些用户使用管理员权限所做的事情。 ——微软

PIM 类似于特权访问管理(Privileged Access ManagementPAM)解决方案,它只在需要时提供管理或特权访问。 PIM 可以在每个资源的基础上使用。 PIM 面板中,有三个类别: 合格的、活动的和过期的。合格意味着用户可以请求访问该资源上的该角色。 活动意味着用户主动拥有该角色并且不需要批准。 过期意味着不再允许用户请求对该角色的访问,并且不再拥有该角色。

 image.png

13: ‘ Contrib’用户允许请求对资源的 contributor 角色的访问

例如,如果一个用户为了一个虚拟机资源被添加到 PIM 中,并且有资格请求访问 Contributor 角色,那么该用户只需要请求激活该虚拟机的特权,而不必为所有其他用户这样做。 由于角色是层次化的,如果将 PIM 放在订阅上,那么它将影响该订阅中的所有资源。 使用 PIM,默认情况下不允许请求被批准。

 image.png

14: 角色的默认激活设置

这意味着默认情况下,用户可以随时激活他们的角色。

然而,PIM 的日志记录在活动日志中有适当的详细说明。

image.png

15: 当用户激活他们的 PIM 控制角色时的事件摘要。Reader 激活了角色‘Contributor’为订阅‘ Azure Test’

最后的想法

Azure  提供了一些额外的服务,可以让你对资源中的操作有更深入的了解,比如 Log Analytics Azure Sentinel,然而 Azure 本身的操作日志记录并不完美。 希望微软能在活动日志中实现更多的细节,这样维护者就可以了解事件的全貌,而不需要额外的努力。

摘要

在我的文章《攻击 AzureAzure AD PowerZure 介绍》中,我提供了几种攻击 Azure AzureAD 的策略、技术和过程(TTPs) ,并发布了利用 PowerZure 来自动化操作其中的一些内容。 我坚信,当一个新的战术或工具开发出来后,防守指南应该遵循以帮助蓝队从这些战术或工具中获得安全感。 不幸的是,Azure 对于发生在 Azure 内部的操作的日志记录能力还有很多不足之处。

本文的目的是对 Azure 内部的原生活动日志服务功能进行概述,并深入探讨如何检测我上一篇文章中列出的许多 TTPs,以及关于如何从活动日志服务中获取更多细节的建议,而不仅仅是显示在‘ summary’选项卡上的内容。

概览

每当一个操作在 Azure 中完成,一个事件就会生成并保存在活动日志服务中。 在活动日志中,用户可以看到所有操作并应用基本过滤器(时间跨度、严重性等) 日志中的操作(事件)是根据操作的状态分离出来的,即事件何时开始、何时更新、何时结束等等。 为了查看该操作中的其他子事件,用户必须单击该事件,然后其他状态事件将填充。 这很重要,因为围绕操作的细节取决于状态。

image.png

1: 单击第一个事件会显示一个子事件

例如,当一个用户被分配到一个角色(例如 contributor)时,会启动一个创建事件的操作,但是缺少必要的细节。

image.png

2: Azure 中为角色分配创建的初始事件

一旦操作完成,另一个子事件会被创建,然后公开必要的细节。

 image.png

3: 单击子事件时会显示更多的详细信息

在本例中,“ Message”字段包含添加到角色的用户的用户名,与不包含此信息的原始事件相比较。

警报

可以从活动日志中直接配置警报。 每当一个操作发生时,Azure 都会给出一个选项,一旦你点击了这个事件,就可以为这个操作创建一个警报。

 image.png

4: 基于事件创建新警报的选项

在创建规则时,可以选择更改条件。 当保留默认条件时,它是一个非常常见的条件,如图5所示:

image.png 

5: 条件被设置为成功的任何信息级的事件。 这将产生几个良性警报

条件可以通过点击垃圾桶图标和点击条件下的添加来改变。

 image.png

6: Runbooks 的警报条件

从这里,可以将警报操作设置为几个选项。

 image.png

7: 警报选项

细节决定一切,是吗?

获取一个常规事件对于警报非常有用,但是对于分析人员来说,拥有与该事件相关的细节是非常关键的,比如谁开始了操作,操作的目标对象是什么,等等。 不幸的是,有几个操作报告的细节信息很少。

命令执行

在虚拟机上运行命令时,会创建一个事件,但是没有记录运行的命令。

image.png 

8: VM 上运行命令的事件中返回的所有内容

摘要选项卡显示了命令的执行时间和执行者,但是为了查看执行时 VM 的名称,用户必须进入 JSON 选项卡并查看‘ id’属性才能查看事件的作用域。

 image.png

9: 作用域路径中 VM 的名称

无论何时向 Windows 虚拟机发出命令,Azure 都将输入的命令作为 PowerShell 脚本存储在内部端点上

C:\Packages\Plugins\Microsoft.CPlat.Core.RunCommandWindows\1.1.3\Downloads

如果攻击者没有删除脚本,这就允许分析人员可能看到在虚拟机上运行了哪些命令。 当然,我总是建议你使用额外的防御工具,并在组策略中对这些端点启用脚本块日志记录。

钥匙库

由于其用途,钥匙库在 Azure 中非常敏感。 它们可以存储证书、密码和密钥,因此它们也应该受到严密的访问监控。 进入钥匙库不会产生事件,也不会泄露密钥。 这就是这个资源与以角色为基础的存取控制的预期目的; Azure 而言,如果用户访问他们有权访问的资源,它就不值得记录事件。 钥匙库仅限于其所有者,由所有者编辑访问策略,允许其他用户访问该钥匙库。 但是,作为全局参与者(Global Contributor),用户可以编辑任何钥匙库的权限并允许自己访问该钥匙库。 这确实会产生一个事件,更新钥匙库

 image.png

钥匙库更新时的日志

事件摘要显示了谁更新了保险库的权限,但是保险库的名称在 JSON 输出中而不是摘要中。

 image.png

10: JSON 选项卡中的作用域显示了库名称

这样做的主要问题是,它没有显示谁被添加到访问策略中。 因此,确定谁被添加的唯一方法,就是进入每个保险库并确定访问策略上的所有用户是否都应该在那里。

Runbooks

PowerZure 中,一个利用 Runbook 优势的函数是 Create-Backdoor 这是通过创建一个 Runbook 来实现的,该 Runbook 将提供一个新帐户,并在执行时将其分配给 Contributor 角色。 它不是自动执行,而是生成一个 Webhook URI,这个 URI 可以传递到 Execute-Backdoor,这个 Execute-Backdoor 将根据需要运行 Runbook 这需要管理员角色,因为只有管理员可以在 Azure AD 中创建用户。 幸运的是,创建 Runbook 会生成几个事件,因此可以直接检测这些事件。 第一个关键事件,是创建 Runbook,然后创建 Webhook,然后生成该 Webhook URI

 image.png

11: PowerZure “ Create-Backdoor”的操作序列

这样做的问题是,‘event initiated by’字段是不正确的。 如果 Runbook 是从命令行创建的,则该字段始终由租户管理员(而不是实际创建 Runbook 的人)填充。 为了确保我的头脑清醒,我用三个不同的帐户测试了它,每次事件由我的管理帐户发起,即使它没有登录到任何地方。

 image.png

12: 由字段启动的事件显示了通过 CLI 创建 Webhook Runbook 时的租户管理员,而不是实际用户

截止 2020124日,这个 bug 已经提交给微软,我现在正在等待他们的回复。

分组任务

即使本地活动目录(AD) AzureAD 同步,也不可能将用户添加到本地 AD 组。 然而,将用户添加到 Azure Azure 组中并不会在活动日志下生成事件。 Azuread 有自己的事件查看器,称为审计日志。 这确实提供了操作的必要细节,但是在 AzureAD 中不能为这些事件配置警报,除非正在使用 Log Analytics 服务,并且 AzureAD 被配置为向 Log Analytics 发送日志。 然后警报将不得不从日志分析生成,而不是 AzureAD 的审计日志。

虚拟机磁盘

如果攻击者侵入了一个全局参与者(Global Contributor)的帐户,他们可能会生成一个下载 VM 磁盘的链接。 这可以通过操作名获取磁盘 SAS URI”检测到。 摘要或 JSON 选项卡中没有显示链接,磁盘是否实际下载也没有显示链接。 只创建一个泛型事件,除了磁盘名之外没有其他详细信息。

防御方法

由于 Azure 使用了以角色为基础的存取控制访问控制(RBAC) ,它应该被视为类似于本地 AD 组成员,这意味着它应该遵循最少特权访问的方法。 Global Contributor 角色分配给用户可以为用户提供大量的访问和执行能力。 建议检查在 Azure 中哪些角色实际上是操作所必需的。 Azure 包含许多全球角色之外的内置角色,可以在这里查看。 此外,定制角色的创建可能更适合企业的需要。

遵循最低特权访问的方法,Azure 确实提供了特权身份管理(Privileged Identity ManagementPIM)服务,但是要付出一定的代价,但是我们强烈推荐这种服务。

组织希望尽量减少能够访问安全信息或资源的人数,因为这样可以减少恶意行为者获得该访问权限的机会,或者减少授权用户无意中影响敏感资源的机会。 然而,用户仍然需要在 Azure AD Azure Office 365 SaaS 应用程序中执行特权操作。 组织可以向用户提供对 Azure 资源和 Azure AD 的即时(JIT)特权访问。 有必要监督这些用户使用管理员权限所做的事情。 ——微软

PIM 类似于特权访问管理(Privileged Access ManagementPAM)解决方案,它只在需要时提供管理或特权访问。 PIM 可以在每个资源的基础上使用。 PIM 面板中,有三个类别: 合格的、活动的和过期的。合格意味着用户可以请求访问该资源上的该角色。 活动意味着用户主动拥有该角色并且不需要批准。 过期意味着不再允许用户请求对该角色的访问,并且不再拥有该角色。

 image.png

13: ‘ Contrib’用户允许请求对资源的 contributor 角色的访问

例如,如果一个用户为了一个虚拟机资源被添加到 PIM 中,并且有资格请求访问 Contributor 角色,那么该用户只需要请求激活该虚拟机的特权,而不必为所有其他用户这样做。 由于角色是层次化的,如果将 PIM 放在订阅上,那么它将影响该订阅中的所有资源。 使用 PIM,默认情况下不允许请求被批准。

 image.png

14: 角色的默认激活设置

这意味着默认情况下,用户可以随时激活他们的角色。

然而,PIM 的日志记录在活动日志中有适当的详细说明。

image.png

15: 当用户激活他们的 PIM 控制角色时的事件摘要。Reader 激活了角色‘Contributor’为订阅‘ Azure Test’

最后的想法

Azure  提供了一些额外的服务,可以让你对资源中的操作有更深入的了解,比如 Log Analytics Azure Sentinel,然而 Azure 本身的操作日志记录并不完美。 希望微软能在活动日志中实现更多的细节,这样维护者就可以了解事件的全貌,而不需要额外的努力。

在2020年,SpecterOps 检测团队成员正在努力将他们发表的博客文章中提到的概念与Fidelity 漏斗联系起来。 Fidelity 漏斗是一个模型,SpecterOps 使用它来处理为了成功检测和补救攻击所必须经历的阶段。我们希望这能帮助读者理解这篇文章在他们整个检测程序中的位置。本文的重点是一个战略,可以适用于检测阶段的漏斗。

image.png

引言

这是 SpecterOps 检测团队发表的包括多个部分博客系列文章的第一篇。 本系列文章的目标是介绍和讨论基础检测工程的概念。 为了使这些概念尽可能地易于使用,我们将整个系列文章的重点放在 Kerberos 煅烧攻击上。 关注这个技术可以让读者专注于每篇文章中提出的策略,而不用担心技术本身的细节。 这篇文章的重点是一个我们称之为“能力抽象”的概念,其思想是,攻击者的工具仅仅是攻击能力的抽象,检测工程师必须了解在构建检测逻辑时如何评估抽象。

什么是抽象?

你可能想知道我说的“抽象”是什么意思,在本文的上下文中,抽象是一个概念,通过这个概念,实现细节对用户是隐藏的或自动化的。 抽象通常表现在被称为抽象层的层中,这些层系统地隐藏了复杂性,每个层提供了一个比上一个更表面的接口。 抽象是一个重要的设计元素,因为技术产品通常面向的用户基础从根本上不理解产品是如何工作的,但仍然可以从技术的使用中获益。 最终,抽象的主要目标之一就是隐藏事物复杂的内部工作机制,使它更容易被更广泛的受众接受。

抽象的第二个原因是简化与技术的交互。 在信息技术中,我们经常说,“如果你不得不多做一次,那就把它自动化。” 类似地,攻击者可能希望在其可接受的 OPSEC 约束范围内尽可能地简化其攻击过程。 我们可以从敌人使用的工具中看到这个概念。 每个工具都以公共接口的形式提供了一定程度的抽象,供操作符使用。

我相信,如果我们可以剥离抽象层来理解基本的攻击,我们就可以对检测攻击技术的最佳方法做出更明智的决定。

什么是 Kerberos 煅烧攻击?

在深入到能力抽象这个“兔子洞”之前,我想花一些时间讨论一下 kerberos 煅烧攻击。 在宏观意义上,Kerberos 煅烧是一种攻击技术,它允许攻击者将 Kerberos 票据授予服务票据(TGS 票据)转换为密码。 在微观(更详细)级别上,Kerberos 身份验证使用服务主体名称(SPN)唯一地标识服务实例。 每个 SPN 都将一个服务实例(比如 web 服务器、 SQL Server 等)关联到一个服务登录帐户。 要对远程系统进行身份验证,用户必须为 SPN 标识的目标服务请求 TGS 票据。 TGS 票证的一部分是使用与目标 SPN 关联的服务登录帐户的密码散列加密的。 对于 Kerberoast 攻击,攻击者提取出加密部分并尝试暴力破解该部分,直到成功为止。 一旦成功解密票据,他们就知道服务登录帐户的密码,可以假定该帐户的身份,并登录到该帐户可以访问的任何系统。

如果你有兴趣在继续之前更深入地挖掘 Kerberos 演示,我建议你查看 Tim Medin 的 Attacking Kerberos: Kicking the Guard Dog of Hades 的演示视频,他介绍了这个概念(幻灯片可以在这里找到)。 此外,harmj0y 已经写了一些关于这个话题的博客文章,特别是他的无  Mimikatz 的 Kerberos 煅烧攻击的文章,他的文章中有很多链接到许多其他关于这个话题的来源。

Kerberos 煅烧攻击的抽象

在整个讨论过程中,这篇文章使用了一个被称为“抽象图”的可视化图形,目的是帮助读者在讨论抽象层时了解它们之间的关系。其思想是在我们发现抽象层时揭示和跟踪它们。至此,我们还没有研究Kerberos 煅烧攻击,所以下面的初始抽象图是空的。

image.png

让我们开始吧!

工具

重要的是要考虑到攻击工具代表了最表面的抽象层; 然而,快速回顾一下公开共享的检测逻辑就会发现,维护者通常将检测工程的工作集中在特定于工具的签名上。 这些表面的检测本身并不是不好的,但在没有进一步的上下文数据的情况下,容易出现盲点(漏报)。评估抽象在攻击技术中的作用的目标是为检测工程工作提供信息。这个过程可以帮助避免错误的否定,了解潜在的遥测需求,了解新的攻击实现,并确定何时检测方法能够充分覆盖我们的目标技术。

Invoke-Kerberoast

Invoke-Kerberoast 是一个 PowerShell 高级函数,允许攻击者为目标帐户请求 Kerberos 服务票证。 除了请求服务票证,Invoke-Kerberoast 还提取票证的加密部分,并以一种可以使用流行的密码破解工具如 John the Ripper 和 Hashcat 离线破解的格式返回。 下面是在测试域中执行 Invoke-Kerberoast 请求票证的示例。

 image.png

Invoke-Kerberoast 执行

此时,kerberos 煅烧攻击的透视图仅限于一个工具(Invoke-Kerberoast)。 让我们用 Invoke-Kerberoast 来更新这个抽象图:

        image.png

在考虑到当前对这个问题的有限认识,对于检测工程师来说,为 Invoke-Kerberoast 创建一个简单的检测并收工是很常见的。 在这个抽象层中为 Invoke-Kerberoast 构建的检测可能集中在 PowerShell 函数名(Invoke-Kerberoast)、代码中的字符串(“@harmj0y”) ,甚至是脚本本身的密码散列。 这些都是伟大的第一步,忽略这些简单的检测是愚蠢的,但是当一个新的工具被释放来完成相同的攻击技术时会发生什么呢?

Rubeus 执行的 Kerberos 煅烧攻击

Rubeus 是一个包含许多滥用 Kerberos 功能的实用程序,但是“kerberoast”命令与 Kerberos 煅烧攻击特别相关。 事实证明,Rubeus 的 kerberoast 命令在功能上等同于 Invoke-Kerberoast,但其包装方式略有不同。

 image.png

Rubeus kerberoast 执行

现在可以更新抽象图,将 Rubeus 的 kerberoast 命令包含到工具层。

image.png

尽管 Invoke-Kerberoast 是用 PowerShell 编写的,而 Rubeus 是用 C# 编写的,但是正因为如此,它们在如何实现检测方面可能存在差异。 例如,PowerShell 函数名和 Invoke-Kerberoast 的加密散列与检测 Rubeus 无关。 相反,检测工程师可能专注于为命令行参数编写签名,或者可能使用 Rubeus 的加密散列创建其他检测。

正如你可以想象的那样,这种方法的可伸缩性非常差,因为 Kerberos 煅烧攻击 可能存在无限的工具实现变种。 相反,可以将工具视为最肤浅的抽象层,并深入研究 Invoke-Kerberoast 和 Rubeus 的实际功能。

托管代码

在这个过程中,已经确定了两个独特的 Kerberos 煅烧攻击利用工具。 现在重要的是要考虑 Invoke-Kerberoast和 Rubeus kerberoast 有什么共同点。 熟悉 PowerShell 和 C# 的人可能会记得,这两种语言都是构建在 .Net 框架之上,它本身就是一个抽象概念,它允许程序员专注于功能而不用担心复杂的编程主题,如内存管理、安全性、可移植性等。 记住这一点,当在托管代码层进行评估时,可以合理地预期这两个工具可能会显示一些相似之处。 通过比较从 Invoke-Kerberoast 和 Rubeus 请求服务票证的代码,可以发现它们都依赖于对 KerberosRequestorSecurityToken .NET 类 的构造函数重载的调用,如下所示:

 image.png

Invoke-Kerberoast 调用 KerberosRequestorSecurityToken 的构造函数

 image.png

Rubeus 调用 KerberosRequestorSecurityToken 的构造函数

正如你所看到的,虽然这些工具是用不同的语言编写的,但它们最终都依赖于 KerberosRequestorSecurityToken 类。 理论上,如果可以构建一个检测方法来关注这个特定类的使用,那么就可以实现使用单一方法检测两个工具。

是时候为“托管代码”的抽象图添加一个新层了,注意,这个层有一个条目,涵盖了两个工具实现。

image.png

希望剥离抽象的价值开始变得清晰起来。 然而,重要的是要注意,虽然剥离抽象层允许更广泛或全面的检测,这也意味着检测可能失去精确度,这导致产生更高的误报的可能性。 例如,.NET中的KerberosRequestorSecurityToken类的合法用例是什么?分析师如何区分合法使用和恶意使用? 这是我的一个同事将在未来的博客文章中更深入讨论的话题。

Windows API 函数

假设你编写了一个检测逻辑,来检测当KerberosRequestorSecurityToken .NET类被使用出发告警。 你是否应该停下来考虑 ,将 Kerberos 煅烧攻击视为一个已经解决的问题? 如果有人使用不与 .NET 交互的语言编写 Kerberos 煅烧攻击利用工具会发生什么? 也许他们决定用 C++ 编写。 那么,正如前面提到的,. Net 本身就是一个抽象层,所以让我们深入挖掘一下,看看底下发生了什么。

幸运的是 .Net 是开源的,所以源代码(.Net 参考源代码)是容易访问的。 使用引用源,检测工程师可以深入研究 KerberosRequestorSecurityToken 类的实现,以了解它在底层是如何工作的。 经过一番调查,我们发现 Invoke-Kerberos 和 Rubeus 的 kerberoast 命令所使用的 KerberosRequestorSecurityToken 类的功能(构造函数)是在 security32.dll 的两个 Windows API 函数上构建的,即 AcquireCredentialsHandleInitializeSecurityContext

Windows API 是一组函数,允许程序员以预定义和文档化的方式与操作系统交互。 可以把它们看作是另一个抽象层,规定了软件如何与硬件组件(如内存、网络接口或输入设备)进行交互。 理论上,攻击者也可以调用 InitializeSecurityContext 而无需通过 KerberosRequestorSecurityToken  .Net 类。

下面的截图来自于  .Net 引用源,显示了  .Net 通过名为 Platform Invoke (P/Invoke)的概念实现了 AcquireCredentialsHandleW 和 I InitializeSecurityContextW

image.png

.NET 引用源 — AcquireCredentialsHandleW

image.png

.NET 引用源 — InitializeSecurityContextW Net

因此,这个函数提供了另一个层次,检测工程师可以在这个层次中构建检测逻辑。

 image.png

一个合理的假设是,使用非 .Net语言编写的Kerberos 煅烧攻击工具也会使用InitializeSecurityContext API函数。让我们看看用C++编写的一个工具,看看这个假设是否正确。

几乎信息安全领域的每个人都熟悉 mimikatz 这个工具,它允许攻击者从内存中转储明文密码。 很少有人知道 mimikatz 是一个复杂的工具,它提供了许多功能,其中之一就是能够为 kerberos 煅烧攻击请求任意的服务票证。 下面的图片显示了 mimikatz 被用来请求与我们使用Invoke-Kerberoast和Rubeus请求的相同的服务票据。。

image.png

Mimikatz kerberos::ask 命令执行

Mimikatz 的 kerberos::ask 命令现在可以添加到支持 kerberos 煅烧攻击工具列表中,如下所示:

image.png

现在,检测工程师如何确定 mimikatz 是否基于 InitializeSecurityContext? mimikatz 工具是开源的,因此可以检查源代码,看看 mimimikatz 是否调用了 InitializeSecurityContext。

查看 kerberos::ask 命令的源代码,你会发现它是由 kuhl_m_kerberos_ask 函数实现的。

image.png

kuhl_m_kerberos_ask 函数调用一个名为 LsaCallKerberosPackage 的函数。

image.png

LsaCallKerberosPackage 函数最后调用一个名为 LsaCallAuthenticationPackage 的 Windows API 函数。

image.png

看来这个逻辑上的假设是不正确的。 Mimimitz 没有调用 InitializeSecurityContext,而是调用了 LsaCallAuthenticationPackage。 似乎至少有两个 Windows API 函数可以请求服务票据。 让我们花一点时间来更新我们的抽象图。

 image.png

现在你可能知道下一个需要回答的问题了! 在 InitializeSecurityContext 和 LsaCallAuthenticationPackage 之间有共同点吗?

远程过程调用

看起来至少有2个 Windows API 函数可以用来请求服务票证,但是这些 API 函数会在下面汇聚成一个共享的抽象层吗? 为了帮助解决这个问题,我与 Matt Graeber (@mattifestation)一起分析了 security.dll (两个函数都存在的库)。 在我们的分析过程中,我们发现 InitializeSecurityContext 和 LsaCallAuthenticationPackage 都进行了 RPC 调用。 进一步检查表明,这两个 API 函数与 RPC 接口交互,UUID 为4f32adc8-6052-4a04-8701-293ccf2096f0。

在 Google 上快速搜索 UUID,返回了 Matt Nelson 的(@enigma0x3) GitHub 摘要,其中他列出了机器上的所有 RPC 接口。 下面的屏幕截图显示了所讨论的 RPC 接口是由 sspisrv.dll 实现的。

image.png

如果你有兴趣更深入地了解这是如何发现的,可以看看 Adam Chester (@_xpn_)的优秀文章“探索 Mimikatz 第二部分”。 在他的文章中,Adam 解释了他是如何检查了一个与我们遇到的非常类似的情况,这个情况涉及 mimikatz 的安全支持提供者(Security Support Provider)能力的内部工作。

现在可以在抽象图中添加一个新的“RPC”层,以显示 InitializeSecurityContext 和 LsaCallAuthenticationPackage 最终如何依赖于幕后相同的 RPC 调用。

image.png

网络协议

你可能会问自己,“难道攻击者不必先调用我们讨论过的 API 函数之一来发出网络请求吗? ” 答案可以在我们的老朋友 Rubeus 那里找到。 Rubeus 有许多专注于滥用 Kerberos 协议的功能。 “ kerberoast”功能在前面已经介绍过了,但是另一个名为“asktgs”的命令允许攻击者通过构建原始的 TGS-REQ 包并解析原始的 TGS-REP 响应来请求服务票证。 可以把这看作是 Kerberos 煅烧攻击可持续的,本地的,手动式的人肉方法。 如下图所示:

 image.png

Rubeus asktgs 命令执行

在此必须更新抽象图,以便在工具层包含 Rubeus 的 asktgs。 不幸的是,这个实现与迄今为止所发现的任何抽象层都没有重叠。 这听起来像是一个更深入挖掘的机会!

 image.png

从根本上讲,Kerberos 是一种网络身份验证协议,用户通过一个称为 Kerberos 密钥分发中心(KDC)的中心实体进行身份验证。 Kerberos 煅烧攻击需要请求一个服务票据或多个服务票据,以方便离线密码破解。 要发出这个请求,必须建立从客户机到 KDC 的网络连接,并且网络请求必须采用票据授予服务请求的形式(TGS-REQ)。

下面是 Invoke-Kerberoast,Rubeus kerberoast, mimikatz 的 kerberos::ask 和 Rubeus asktgs 的数据包。 请注意,虽然数据包在捕获中存在细微差别,但每个工具都发出了相同的 TGS-REQ 请求,并在下面的每张图片中突出显示。

 image.png

Wireshark 捕获的 Invoke-Kerberoast 数据包

image.png 

Wireshark 捕获的 Rubeus kerberoast 数据包

 image.png

Wireshark 捕获的 Mimikatz kerberos::ask 数据包

 image.png

Wireshark 捕获的 Rubeus asktgs 数据包

抽象图通过添加覆盖所有 Kerberos 煅烧攻击实现的网络协议层来完成。 请记住,尽管 RPC 和网络协议层对 kerberos 煅烧攻击的实现更具包容性,但它们对合法活动也更具包容性。 简单地说,在较低的抽象层上构建检测并不总是理想的。 

image.png

请记住,这个抽象图可能不会考虑 Kerberos 煅烧攻击所涉及的每一个可能的抽象。 你能想到任何额外的抽象层吗? 如果有,请在评论中分享你的想法!

总结

我经常听到攻击者在谈论,了解他们的攻击工具如何工作是多么重要,但是我很少从我的从事防御工作的圈子中听到类似的观点。 我经常看到一个检测工程师从表面上看待攻击工具。理解攻击性能力是如何被抽象出来的,为检测工程师提供了一个机会,以一种明智的方式来评估他们的检测方法。我相信,通过花更多的时间来理解工具从我们身边抽象出来的技术,我们将能够提高标准,不仅检测我们所知道的,而且也检测我们所不知道的。能力抽象只是你可以添加到你的检测工程工具箱中的一个工具。

本系列的下一篇文章将解释在不同的抽象层上理解检测的优缺点的策略,以及如何利用一个抽象图来确定分层检测逻辑的最有效方法,从而创建一个全面的检测方法。

在2020年,SpecterOps 检测团队成员正在努力将他们发表的博客文章中提到的概念与Fidelity 漏斗联系起来。 Fidelity 漏斗是一个模型,SpecterOps 使用它来处理为了成功检测和补救攻击所必须经历的阶段。我们希望这能帮助读者理解这篇文章在他们整个检测程序中的位置。本文的重点是一个战略,可以适用于检测阶段的漏斗。

image.png

引言

这是 SpecterOps 检测团队发表的包括多个部分博客系列文章的第一篇。 本系列文章的目标是介绍和讨论基础检测工程的概念。 为了使这些概念尽可能地易于使用,我们将整个系列文章的重点放在 Kerberos 煅烧攻击上。 关注这个技术可以让读者专注于每篇文章中提出的策略,而不用担心技术本身的细节。 这篇文章的重点是一个我们称之为“能力抽象”的概念,其思想是,攻击者的工具仅仅是攻击能力的抽象,检测工程师必须了解在构建检测逻辑时如何评估抽象。

什么是抽象?

你可能想知道我说的“抽象”是什么意思,在本文的上下文中,抽象是一个概念,通过这个概念,实现细节对用户是隐藏的或自动化的。 抽象通常表现在被称为抽象层的层中,这些层系统地隐藏了复杂性,每个层提供了一个比上一个更表面的接口。 抽象是一个重要的设计元素,因为技术产品通常面向的用户基础从根本上不理解产品是如何工作的,但仍然可以从技术的使用中获益。 最终,抽象的主要目标之一就是隐藏事物复杂的内部工作机制,使它更容易被更广泛的受众接受。

抽象的第二个原因是简化与技术的交互。 在信息技术中,我们经常说,“如果你不得不多做一次,那就把它自动化。” 类似地,攻击者可能希望在其可接受的 OPSEC 约束范围内尽可能地简化其攻击过程。 我们可以从敌人使用的工具中看到这个概念。 每个工具都以公共接口的形式提供了一定程度的抽象,供操作符使用。

我相信,如果我们可以剥离抽象层来理解基本的攻击,我们就可以对检测攻击技术的最佳方法做出更明智的决定。

什么是 Kerberos 煅烧攻击?

在深入到能力抽象这个“兔子洞”之前,我想花一些时间讨论一下 kerberos 煅烧攻击。 在宏观意义上,Kerberos 煅烧是一种攻击技术,它允许攻击者将 Kerberos 票据授予服务票据(TGS 票据)转换为密码。 在微观(更详细)级别上,Kerberos 身份验证使用服务主体名称(SPN)唯一地标识服务实例。 每个 SPN 都将一个服务实例(比如 web 服务器、 SQL Server 等)关联到一个服务登录帐户。 要对远程系统进行身份验证,用户必须为 SPN 标识的目标服务请求 TGS 票据。 TGS 票证的一部分是使用与目标 SPN 关联的服务登录帐户的密码散列加密的。 对于 Kerberoast 攻击,攻击者提取出加密部分并尝试暴力破解该部分,直到成功为止。 一旦成功解密票据,他们就知道服务登录帐户的密码,可以假定该帐户的身份,并登录到该帐户可以访问的任何系统。

如果你有兴趣在继续之前更深入地挖掘 Kerberos 演示,我建议你查看 Tim Medin 的 Attacking Kerberos: Kicking the Guard Dog of Hades 的演示视频,他介绍了这个概念(幻灯片可以在这里找到)。 此外,harmj0y 已经写了一些关于这个话题的博客文章,特别是他的无  Mimikatz 的 Kerberos 煅烧攻击的文章,他的文章中有很多链接到许多其他关于这个话题的来源。

Kerberos 煅烧攻击的抽象

在整个讨论过程中,这篇文章使用了一个被称为“抽象图”的可视化图形,目的是帮助读者在讨论抽象层时了解它们之间的关系。其思想是在我们发现抽象层时揭示和跟踪它们。至此,我们还没有研究Kerberos 煅烧攻击,所以下面的初始抽象图是空的。

image.png

让我们开始吧!

工具

重要的是要考虑到攻击工具代表了最表面的抽象层; 然而,快速回顾一下公开共享的检测逻辑就会发现,维护者通常将检测工程的工作集中在特定于工具的签名上。 这些表面的检测本身并不是不好的,但在没有进一步的上下文数据的情况下,容易出现盲点(漏报)。评估抽象在攻击技术中的作用的目标是为检测工程工作提供信息。这个过程可以帮助避免错误的否定,了解潜在的遥测需求,了解新的攻击实现,并确定何时检测方法能够充分覆盖我们的目标技术。

Invoke-Kerberoast

Invoke-Kerberoast 是一个 PowerShell 高级函数,允许攻击者为目标帐户请求 Kerberos 服务票证。 除了请求服务票证,Invoke-Kerberoast 还提取票证的加密部分,并以一种可以使用流行的密码破解工具如 John the Ripper 和 Hashcat 离线破解的格式返回。 下面是在测试域中执行 Invoke-Kerberoast 请求票证的示例。

 image.png

Invoke-Kerberoast 执行

此时,kerberos 煅烧攻击的透视图仅限于一个工具(Invoke-Kerberoast)。 让我们用 Invoke-Kerberoast 来更新这个抽象图:

        image.png

在考虑到当前对这个问题的有限认识,对于检测工程师来说,为 Invoke-Kerberoast 创建一个简单的检测并收工是很常见的。 在这个抽象层中为 Invoke-Kerberoast 构建的检测可能集中在 PowerShell 函数名(Invoke-Kerberoast)、代码中的字符串(“@harmj0y”) ,甚至是脚本本身的密码散列。 这些都是伟大的第一步,忽略这些简单的检测是愚蠢的,但是当一个新的工具被释放来完成相同的攻击技术时会发生什么呢?

Rubeus 执行的 Kerberos 煅烧攻击

Rubeus 是一个包含许多滥用 Kerberos 功能的实用程序,但是“kerberoast”命令与 Kerberos 煅烧攻击特别相关。 事实证明,Rubeus 的 kerberoast 命令在功能上等同于 Invoke-Kerberoast,但其包装方式略有不同。

 image.png

Rubeus kerberoast 执行

现在可以更新抽象图,将 Rubeus 的 kerberoast 命令包含到工具层。

image.png

尽管 Invoke-Kerberoast 是用 PowerShell 编写的,而 Rubeus 是用 C# 编写的,但是正因为如此,它们在如何实现检测方面可能存在差异。 例如,PowerShell 函数名和 Invoke-Kerberoast 的加密散列与检测 Rubeus 无关。 相反,检测工程师可能专注于为命令行参数编写签名,或者可能使用 Rubeus 的加密散列创建其他检测。

正如你可以想象的那样,这种方法的可伸缩性非常差,因为 Kerberos 煅烧攻击 可能存在无限的工具实现变种。 相反,可以将工具视为最肤浅的抽象层,并深入研究 Invoke-Kerberoast 和 Rubeus 的实际功能。

托管代码

在这个过程中,已经确定了两个独特的 Kerberos 煅烧攻击利用工具。 现在重要的是要考虑 Invoke-Kerberoast和 Rubeus kerberoast 有什么共同点。 熟悉 PowerShell 和 C# 的人可能会记得,这两种语言都是构建在 .Net 框架之上,它本身就是一个抽象概念,它允许程序员专注于功能而不用担心复杂的编程主题,如内存管理、安全性、可移植性等。 记住这一点,当在托管代码层进行评估时,可以合理地预期这两个工具可能会显示一些相似之处。 通过比较从 Invoke-Kerberoast 和 Rubeus 请求服务票证的代码,可以发现它们都依赖于对 KerberosRequestorSecurityToken .NET 类 的构造函数重载的调用,如下所示:

 image.png

Invoke-Kerberoast 调用 KerberosRequestorSecurityToken 的构造函数

 image.png

Rubeus 调用 KerberosRequestorSecurityToken 的构造函数

正如你所看到的,虽然这些工具是用不同的语言编写的,但它们最终都依赖于 KerberosRequestorSecurityToken 类。 理论上,如果可以构建一个检测方法来关注这个特定类的使用,那么就可以实现使用单一方法检测两个工具。

是时候为“托管代码”的抽象图添加一个新层了,注意,这个层有一个条目,涵盖了两个工具实现。

image.png

希望剥离抽象的价值开始变得清晰起来。 然而,重要的是要注意,虽然剥离抽象层允许更广泛或全面的检测,这也意味着检测可能失去精确度,这导致产生更高的误报的可能性。 例如,.NET中的KerberosRequestorSecurityToken类的合法用例是什么?分析师如何区分合法使用和恶意使用? 这是我的一个同事将在未来的博客文章中更深入讨论的话题。

Windows API 函数

假设你编写了一个检测逻辑,来检测当KerberosRequestorSecurityToken .NET类被使用出发告警。 你是否应该停下来考虑 ,将 Kerberos 煅烧攻击视为一个已经解决的问题? 如果有人使用不与 .NET 交互的语言编写 Kerberos 煅烧攻击利用工具会发生什么? 也许他们决定用 C++ 编写。 那么,正如前面提到的,. Net 本身就是一个抽象层,所以让我们深入挖掘一下,看看底下发生了什么。

幸运的是 .Net 是开源的,所以源代码(.Net 参考源代码)是容易访问的。 使用引用源,检测工程师可以深入研究 KerberosRequestorSecurityToken 类的实现,以了解它在底层是如何工作的。 经过一番调查,我们发现 Invoke-Kerberos 和 Rubeus 的 kerberoast 命令所使用的 KerberosRequestorSecurityToken 类的功能(构造函数)是在 security32.dll 的两个 Windows API 函数上构建的,即 AcquireCredentialsHandleInitializeSecurityContext

Windows API 是一组函数,允许程序员以预定义和文档化的方式与操作系统交互。 可以把它们看作是另一个抽象层,规定了软件如何与硬件组件(如内存、网络接口或输入设备)进行交互。 理论上,攻击者也可以调用 InitializeSecurityContext 而无需通过 KerberosRequestorSecurityToken  .Net 类。

下面的截图来自于  .Net 引用源,显示了  .Net 通过名为 Platform Invoke (P/Invoke)的概念实现了 AcquireCredentialsHandleW 和 I InitializeSecurityContextW

image.png

.NET 引用源 — AcquireCredentialsHandleW

image.png

.NET 引用源 — InitializeSecurityContextW Net

因此,这个函数提供了另一个层次,检测工程师可以在这个层次中构建检测逻辑。

 image.png

一个合理的假设是,使用非 .Net语言编写的Kerberos 煅烧攻击工具也会使用InitializeSecurityContext API函数。让我们看看用C++编写的一个工具,看看这个假设是否正确。

几乎信息安全领域的每个人都熟悉 mimikatz 这个工具,它允许攻击者从内存中转储明文密码。 很少有人知道 mimikatz 是一个复杂的工具,它提供了许多功能,其中之一就是能够为 kerberos 煅烧攻击请求任意的服务票证。 下面的图片显示了 mimikatz 被用来请求与我们使用Invoke-Kerberoast和Rubeus请求的相同的服务票据。。

image.png

Mimikatz kerberos::ask 命令执行

Mimikatz 的 kerberos::ask 命令现在可以添加到支持 kerberos 煅烧攻击工具列表中,如下所示:

image.png

现在,检测工程师如何确定 mimikatz 是否基于 InitializeSecurityContext? mimikatz 工具是开源的,因此可以检查源代码,看看 mimimikatz 是否调用了 InitializeSecurityContext。

查看 kerberos::ask 命令的源代码,你会发现它是由 kuhl_m_kerberos_ask 函数实现的。

image.png

kuhl_m_kerberos_ask 函数调用一个名为 LsaCallKerberosPackage 的函数。

image.png

LsaCallKerberosPackage 函数最后调用一个名为 LsaCallAuthenticationPackage 的 Windows API 函数。

image.png

看来这个逻辑上的假设是不正确的。 Mimimitz 没有调用 InitializeSecurityContext,而是调用了 LsaCallAuthenticationPackage。 似乎至少有两个 Windows API 函数可以请求服务票据。 让我们花一点时间来更新我们的抽象图。

 image.png

现在你可能知道下一个需要回答的问题了! 在 InitializeSecurityContext 和 LsaCallAuthenticationPackage 之间有共同点吗?

远程过程调用

看起来至少有2个 Windows API 函数可以用来请求服务票证,但是这些 API 函数会在下面汇聚成一个共享的抽象层吗? 为了帮助解决这个问题,我与 Matt Graeber (@mattifestation)一起分析了 security.dll (两个函数都存在的库)。 在我们的分析过程中,我们发现 InitializeSecurityContext 和 LsaCallAuthenticationPackage 都进行了 RPC 调用。 进一步检查表明,这两个 API 函数与 RPC 接口交互,UUID 为4f32adc8-6052-4a04-8701-293ccf2096f0。

在 Google 上快速搜索 UUID,返回了 Matt Nelson 的(@enigma0x3) GitHub 摘要,其中他列出了机器上的所有 RPC 接口。 下面的屏幕截图显示了所讨论的 RPC 接口是由 sspisrv.dll 实现的。

image.png

如果你有兴趣更深入地了解这是如何发现的,可以看看 Adam Chester (@_xpn_)的优秀文章“探索 Mimikatz 第二部分”。 在他的文章中,Adam 解释了他是如何检查了一个与我们遇到的非常类似的情况,这个情况涉及 mimikatz 的安全支持提供者(Security Support Provider)能力的内部工作。

现在可以在抽象图中添加一个新的“RPC”层,以显示 InitializeSecurityContext 和 LsaCallAuthenticationPackage 最终如何依赖于幕后相同的 RPC 调用。

image.png

网络协议

你可能会问自己,“难道攻击者不必先调用我们讨论过的 API 函数之一来发出网络请求吗? ” 答案可以在我们的老朋友 Rubeus 那里找到。 Rubeus 有许多专注于滥用 Kerberos 协议的功能。 “ kerberoast”功能在前面已经介绍过了,但是另一个名为“asktgs”的命令允许攻击者通过构建原始的 TGS-REQ 包并解析原始的 TGS-REP 响应来请求服务票证。 可以把这看作是 Kerberos 煅烧攻击可持续的,本地的,手动式的人肉方法。 如下图所示:

 image.png

Rubeus asktgs 命令执行

在此必须更新抽象图,以便在工具层包含 Rubeus 的 asktgs。 不幸的是,这个实现与迄今为止所发现的任何抽象层都没有重叠。 这听起来像是一个更深入挖掘的机会!

 image.png

从根本上讲,Kerberos 是一种网络身份验证协议,用户通过一个称为 Kerberos 密钥分发中心(KDC)的中心实体进行身份验证。 Kerberos 煅烧攻击需要请求一个服务票据或多个服务票据,以方便离线密码破解。 要发出这个请求,必须建立从客户机到 KDC 的网络连接,并且网络请求必须采用票据授予服务请求的形式(TGS-REQ)。

下面是 Invoke-Kerberoast,Rubeus kerberoast, mimikatz 的 kerberos::ask 和 Rubeus asktgs 的数据包。 请注意,虽然数据包在捕获中存在细微差别,但每个工具都发出了相同的 TGS-REQ 请求,并在下面的每张图片中突出显示。

 image.png

Wireshark 捕获的 Invoke-Kerberoast 数据包

image.png 

Wireshark 捕获的 Rubeus kerberoast 数据包

 image.png

Wireshark 捕获的 Mimikatz kerberos::ask 数据包

 image.png

Wireshark 捕获的 Rubeus asktgs 数据包

抽象图通过添加覆盖所有 Kerberos 煅烧攻击实现的网络协议层来完成。 请记住,尽管 RPC 和网络协议层对 kerberos 煅烧攻击的实现更具包容性,但它们对合法活动也更具包容性。 简单地说,在较低的抽象层上构建检测并不总是理想的。 

image.png

请记住,这个抽象图可能不会考虑 Kerberos 煅烧攻击所涉及的每一个可能的抽象。 你能想到任何额外的抽象层吗? 如果有,请在评论中分享你的想法!

总结

我经常听到攻击者在谈论,了解他们的攻击工具如何工作是多么重要,但是我很少从我的从事防御工作的圈子中听到类似的观点。 我经常看到一个检测工程师从表面上看待攻击工具。理解攻击性能力是如何被抽象出来的,为检测工程师提供了一个机会,以一种明智的方式来评估他们的检测方法。我相信,通过花更多的时间来理解工具从我们身边抽象出来的技术,我们将能够提高标准,不仅检测我们所知道的,而且也检测我们所不知道的。能力抽象只是你可以添加到你的检测工程工具箱中的一个工具。

本系列的下一篇文章将解释在不同的抽象层上理解检测的优缺点的策略,以及如何利用一个抽象图来确定分层检测逻辑的最有效方法,从而创建一个全面的检测方法。

攻击者正在寻找新的技术来进行横向移动,这已经不是什么秘密了。 然而,通常使用的公众都知道的技术屈指可数。 这篇文章并没有强调一种新的横向移动技术,而是提供了一种在你最喜欢的命令和控制(C2)平台上利用已知方法的新方法。 我将展示如何利用远程桌面协议(Remote Desktop Protocol,RDP)对目标执行非图形身份验证的远程命令。 当使用 RDP 进行横向移动时,攻击者通常会启动 SOCKS 代理,使用 RDP 应用程序 / 客户端,执行有效载荷,并关闭会话。 但是这样做总是让人觉得执行一次行动是多余的开销。

在没有 SOCKS 代理或 GUI RDP 客户端的情况下,通过现有的 C2通道执行 RDP 横向移动的想法似乎总是可行的,但并没有人真正公开讨论过。 在搜索现有工作的过程中,我发现了几个留言板和论坛,人们在上面提到了这个想法,并发布了一些小的代码片段,但我从未找到一个完全武器化的版本。 在编译完全不同的信息和代码并与同事讨论这个主题之后,我有了一个可以开始工作的起点。

最终,我发现 Windows 有一个库 mstscax.dll,可以访问任何可能的 RDP 操作,并且几乎被所有 RDP 客户端使用,包括远程桌面连接或 Royal TSX。 此 DLL 是用于微软终端服务的 ActiveX COM 库。 通过利用这个 DLL,攻击者可以创建一个通过 RDP 执行经过身份验证的远程命令执行控制台应用,而不需要 GUI 客户端或 SOCKS 代理。

今天,我发布了 SharpRDP工具,它是一个 . Net 控制台应用,可用于为横向移动的目的对远程目标执行经过身份验证的命令。

它是如何工作的

终端服务库(mstscax.dll)有两种不同的形式可以使用,一种是 web 客户端或脚本可以使用的脚本控件,另一种是本机代码或托管代码中使用的非脚本控件。 SharpRDP 依赖于 COM 库的非脚本控件。 Activex 导入器 aximp.exe,它是 .Net SDK 的一部分,能从 mstscax.DLL 中生成适当的 DLL 例如 MSTSCLib.DLL 和 AxMSTSCLib.DLL。 Dll 包含库的托管定义,而 AxMSTSCLib.dll 包含 ActiveX 类的 Windows Form 控件。 两个 dll 都包含执行横向移动所需操作需要的类。

点击查看演示视频

图1——通过 CobaltStrike 执行 SharpRDP

Windows 窗体在终端服务连接对象实例化过程中使用,因此我们创建了一个 Windows 窗体对象,该对象对于我们正在执行的用户是不可见的。 通过这种形式,我们可以调用方法来执行所有横向运动步骤所需的动作,例如:

· 连接

· 认证

· 对目标的操作(命令执行)

· 与主机断开连接

这些操作中的每一个都被注册为事件和事件处理程序,这些事件和事件处理程序决定了要采取的操作过程。

有两种方法进行身份验证,要么提供纯文本凭证(可能是最常见和最有用的场景) ,要么使用受限管理模式的当前用户上下文。 受限管理模式是一种 Windows 保护机制,它执行网络类型登录而不是交互式登录,以防止在 RDPing 到主机时缓存凭据。 这通常会被攻击者通过 RDP 传递哈希进行滥用。

验证之后,SharpRDP 通过一个名为 SendKeys 的方法向远程系统发送虚拟按键。 由于 SharpRDP 目前只支持按键,默认情况下,这将打开一个运行对话框并输入指定的命令。 此外,还可以作为 Cmd.exe 或 PowerShell.exe 的子进程运行,这些进程将从运行对话框中产生。

OPSEC 考虑因素——当从运行对话框中运行任何内容时,将在 HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\RunMRU  中创建一个注册表条目,显示输入到框中的内容。 出于横向移动的目的,在建立一个新的代理之后,建议使用 CleanRunMRU 来清除刚刚执行的命令。

为了使用 C2工具,比如 Cobalt Strike,需要克服两个小障碍。 首先,需要将两个 dll 编译到程序集中。 因为 MSTSCLib.DLL 和 AxMSTSCLib.DLL 中都有我们需要的方法,所以我们需要把它们作为资源添加并编译到程序集中。 应用程序域程序集解析事件用于捕获不在同一目录中的 dll 加载失败的情况并加载添加的资源。 其次,dll 的组合大小大约略小于1.5 MB,通过将这些 dll 编译到程序集中,它使其大于了 Cobalt Strike 对程序集大小的限制(1mb)。 为了克服这个问题,这两个dll都被压缩为资源,并在调用程序集解析事件时进行解压以获得可用性。

用例

有时候 RDP 会是执行横向移动技术的首选方法,但是使用传统的 RDP 客户端 GUI 可能会有困难。 我们想到的最常见的一种方法是尝试通过高延迟的连接使用 RDP 客户端。

其次,有了这个,我们可以减少以前使用 RDP 时的大量开销,现在就像通过 C2植入运行单个命令一样简单。 对于 RDP,一般情况下,当我们在系统上没有本地管理特权,但是对该系统拥有 RDP 权限时,我们可以使用它,这可以从 BloodHound (图2)或者是你最喜欢的侦察工具中看到。

 image.png

图2—— BloodHound 显示了当前用户拥有 RDP 权限的主机

正如前面提到的,除非目标主机启用了限制性的管理模式(HKLM\ System\ CurrentControlSet\ Control\ Lsa DisableRestrictedAdmin设置为0) ,否则这个工具通常需要纯文本凭证,它将从当前用户上下文执行。 如果命令中没有提供凭据,它将退回到尝试使用受限制的管理模式验证到当前上下文。

虽然这个工具有它的用途,但也有一些情况是它不能处理的。

· 双重身份验证: 目前无法处理 MFA 身份验证,SharpRDP 将断开会话。

· UAC 绕过——如果操作员希望在特权环境下操作,他们需要为新执行的命令设置升级特权或绕过 UAC

· 文件移动—— SharpRDP 不具备在 RDP 协议上复制或移动文件的能力。 如果3389是主机上唯一打开的端口,你将无法使用此工具将文件拖放到目标上

SharpRDP 已经公开,可以在这里找到

攻击检测

在引擎盖下,这个工具使用与其他 RDP 客户使用的相同的方法,但仍然有工具和技术特定的指标。

RunMRU 注册表项——如前所述,因为 SharpRDP 依赖于向目标系统发送按键,并通过 Windows 运行对话框执行命令。 在运行对话框中输入某些内容并运行时,将在 HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\RunMRU 创建一个注册表条目,显示已执行的命令历史记录。 如果攻击者没有清理这个条目,就会留下他们执行了什么命令取证指示器。

父子进程关系——通过 SharpRDP 执行的任何命令的父进程都是 Explorer.exe,除非命令执行类型设置为 Cmd 或 PS,那么继承关系就是 explorer -> cmd 或 explorer -> ps。

Windows 事件日志——监视 Windows 事件 ID (EID)4624 的类型为 10或 类型为 3(如果启用 NLA 或受限管理)登录到目标主机,以获得远程登录活动的证据。

非标准模块加载——一个更健壮的技术聚焦检测可以查找加载到不是 mstsc.exe (或环境中使用的其他基线 RDP 应用程序)的进程中的 mstscax.dll。 这可以在图3中看到,其中进程 rundll32 可以将 DLL 加载到其中。

image.png

图 3 — Rundll32已将mstscax.dll加载到Rundll32进程中 

在 %LOCALAPPDATA%\Local\Microsoft\Terminal Server Client\cache 中查找RDP BMC缓存文件可以显示攻击者的一些操作行为。

使用TCP 3389的非标准进程——查找不是通过TCP端口3389通信的mstsc.exe(或预定义的基线RDP客户机)的进程。

虽然目前已经有人给出了一些基本的检测逻辑,但从攻击者的角度来看,对于遗留下来的取证分析工作,RDP可能是一个难以使用的协议。JPCert 发布了一些关于RDP检测和取证分析的优秀信息

未来的工作

用例部分强调了 SharpRDP 当前状态中缺少的一些领域,并将在未来解决这些问题。 此外,还有一些功能需要修复(例如,确保正确传递哈希值(假定启用了受限制的管理模式) ,以便明文或当前上下文不是唯一的身份验证方法)。 我计划积极维护项目,任何报告的问题或要求的改进将被修正或考虑。

攻击者正在寻找新的技术来进行横向移动,这已经不是什么秘密了。 然而,通常使用的公众都知道的技术屈指可数。 这篇文章并没有强调一种新的横向移动技术,而是提供了一种在你最喜欢的命令和控制(C2)平台上利用已知方法的新方法。 我将展示如何利用远程桌面协议(Remote Desktop Protocol,RDP)对目标执行非图形身份验证的远程命令。 当使用 RDP 进行横向移动时,攻击者通常会启动 SOCKS 代理,使用 RDP 应用程序 / 客户端,执行有效载荷,并关闭会话。 但是这样做总是让人觉得执行一次行动是多余的开销。

在没有 SOCKS 代理或 GUI RDP 客户端的情况下,通过现有的 C2通道执行 RDP 横向移动的想法似乎总是可行的,但并没有人真正公开讨论过。 在搜索现有工作的过程中,我发现了几个留言板和论坛,人们在上面提到了这个想法,并发布了一些小的代码片段,但我从未找到一个完全武器化的版本。 在编译完全不同的信息和代码并与同事讨论这个主题之后,我有了一个可以开始工作的起点。

最终,我发现 Windows 有一个库 mstscax.dll,可以访问任何可能的 RDP 操作,并且几乎被所有 RDP 客户端使用,包括远程桌面连接或 Royal TSX。 此 DLL 是用于微软终端服务的 ActiveX COM 库。 通过利用这个 DLL,攻击者可以创建一个通过 RDP 执行经过身份验证的远程命令执行控制台应用,而不需要 GUI 客户端或 SOCKS 代理。

今天,我发布了 SharpRDP工具,它是一个 . Net 控制台应用,可用于为横向移动的目的对远程目标执行经过身份验证的命令。

它是如何工作的

终端服务库(mstscax.dll)有两种不同的形式可以使用,一种是 web 客户端或脚本可以使用的脚本控件,另一种是本机代码或托管代码中使用的非脚本控件。 SharpRDP 依赖于 COM 库的非脚本控件。 Activex 导入器 aximp.exe,它是 .Net SDK 的一部分,能从 mstscax.DLL 中生成适当的 DLL 例如 MSTSCLib.DLL 和 AxMSTSCLib.DLL。 Dll 包含库的托管定义,而 AxMSTSCLib.dll 包含 ActiveX 类的 Windows Form 控件。 两个 dll 都包含执行横向移动所需操作需要的类。

点击查看演示视频

图1——通过 CobaltStrike 执行 SharpRDP

Windows 窗体在终端服务连接对象实例化过程中使用,因此我们创建了一个 Windows 窗体对象,该对象对于我们正在执行的用户是不可见的。 通过这种形式,我们可以调用方法来执行所有横向运动步骤所需的动作,例如:

· 连接

· 认证

· 对目标的操作(命令执行)

· 与主机断开连接

这些操作中的每一个都被注册为事件和事件处理程序,这些事件和事件处理程序决定了要采取的操作过程。

有两种方法进行身份验证,要么提供纯文本凭证(可能是最常见和最有用的场景) ,要么使用受限管理模式的当前用户上下文。 受限管理模式是一种 Windows 保护机制,它执行网络类型登录而不是交互式登录,以防止在 RDPing 到主机时缓存凭据。 这通常会被攻击者通过 RDP 传递哈希进行滥用。

验证之后,SharpRDP 通过一个名为 SendKeys 的方法向远程系统发送虚拟按键。 由于 SharpRDP 目前只支持按键,默认情况下,这将打开一个运行对话框并输入指定的命令。 此外,还可以作为 Cmd.exe 或 PowerShell.exe 的子进程运行,这些进程将从运行对话框中产生。

OPSEC 考虑因素——当从运行对话框中运行任何内容时,将在 HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\RunMRU  中创建一个注册表条目,显示输入到框中的内容。 出于横向移动的目的,在建立一个新的代理之后,建议使用 CleanRunMRU 来清除刚刚执行的命令。

为了使用 C2工具,比如 Cobalt Strike,需要克服两个小障碍。 首先,需要将两个 dll 编译到程序集中。 因为 MSTSCLib.DLL 和 AxMSTSCLib.DLL 中都有我们需要的方法,所以我们需要把它们作为资源添加并编译到程序集中。 应用程序域程序集解析事件用于捕获不在同一目录中的 dll 加载失败的情况并加载添加的资源。 其次,dll 的组合大小大约略小于1.5 MB,通过将这些 dll 编译到程序集中,它使其大于了 Cobalt Strike 对程序集大小的限制(1mb)。 为了克服这个问题,这两个dll都被压缩为资源,并在调用程序集解析事件时进行解压以获得可用性。

用例

有时候 RDP 会是执行横向移动技术的首选方法,但是使用传统的 RDP 客户端 GUI 可能会有困难。 我们想到的最常见的一种方法是尝试通过高延迟的连接使用 RDP 客户端。

其次,有了这个,我们可以减少以前使用 RDP 时的大量开销,现在就像通过 C2植入运行单个命令一样简单。 对于 RDP,一般情况下,当我们在系统上没有本地管理特权,但是对该系统拥有 RDP 权限时,我们可以使用它,这可以从 BloodHound (图2)或者是你最喜欢的侦察工具中看到。

 image.png

图2—— BloodHound 显示了当前用户拥有 RDP 权限的主机

正如前面提到的,除非目标主机启用了限制性的管理模式(HKLM\ System\ CurrentControlSet\ Control\ Lsa DisableRestrictedAdmin设置为0) ,否则这个工具通常需要纯文本凭证,它将从当前用户上下文执行。 如果命令中没有提供凭据,它将退回到尝试使用受限制的管理模式验证到当前上下文。

虽然这个工具有它的用途,但也有一些情况是它不能处理的。

· 双重身份验证: 目前无法处理 MFA 身份验证,SharpRDP 将断开会话。

· UAC 绕过——如果操作员希望在特权环境下操作,他们需要为新执行的命令设置升级特权或绕过 UAC

· 文件移动—— SharpRDP 不具备在 RDP 协议上复制或移动文件的能力。 如果3389是主机上唯一打开的端口,你将无法使用此工具将文件拖放到目标上

SharpRDP 已经公开,可以在这里找到

攻击检测

在引擎盖下,这个工具使用与其他 RDP 客户使用的相同的方法,但仍然有工具和技术特定的指标。

RunMRU 注册表项——如前所述,因为 SharpRDP 依赖于向目标系统发送按键,并通过 Windows 运行对话框执行命令。 在运行对话框中输入某些内容并运行时,将在 HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\RunMRU 创建一个注册表条目,显示已执行的命令历史记录。 如果攻击者没有清理这个条目,就会留下他们执行了什么命令取证指示器。

父子进程关系——通过 SharpRDP 执行的任何命令的父进程都是 Explorer.exe,除非命令执行类型设置为 Cmd 或 PS,那么继承关系就是 explorer -> cmd 或 explorer -> ps。

Windows 事件日志——监视 Windows 事件 ID (EID)4624 的类型为 10或 类型为 3(如果启用 NLA 或受限管理)登录到目标主机,以获得远程登录活动的证据。

非标准模块加载——一个更健壮的技术聚焦检测可以查找加载到不是 mstsc.exe (或环境中使用的其他基线 RDP 应用程序)的进程中的 mstscax.dll。 这可以在图3中看到,其中进程 rundll32 可以将 DLL 加载到其中。

image.png

图 3 — Rundll32已将mstscax.dll加载到Rundll32进程中 

在 %LOCALAPPDATA%\Local\Microsoft\Terminal Server Client\cache 中查找RDP BMC缓存文件可以显示攻击者的一些操作行为。

使用TCP 3389的非标准进程——查找不是通过TCP端口3389通信的mstsc.exe(或预定义的基线RDP客户机)的进程。

虽然目前已经有人给出了一些基本的检测逻辑,但从攻击者的角度来看,对于遗留下来的取证分析工作,RDP可能是一个难以使用的协议。JPCert 发布了一些关于RDP检测和取证分析的优秀信息

未来的工作

用例部分强调了 SharpRDP 当前状态中缺少的一些领域,并将在未来解决这些问题。 此外,还有一些功能需要修复(例如,确保正确传递哈希值(假定启用了受限制的管理模式) ,以便明文或当前上下文不是唯一的身份验证方法)。 我计划积极维护项目,任何报告的问题或要求的改进将被修正或考虑。

最近有很多关于红队基础设施的现代战略的讨论。每一种实现都有很大的不同,但是我们希望能够提供一些深入的信息,特别是关于我们团队如何处理命令和控制的挑战。 这反映了我们所犯的许多错误,比如深夜记录的文档,当前正在进行的研究,以及我们每天使用的现实世界的解决方案。

一点理论

在寻找最佳解决方案之前,我们首先需要清楚地说明我们的目标。 每个操作的细节都是独一无二的,但是我们觉得下面的内容是对红队的一个很好的概括。

· 提供可靠的工具通讯

· 混淆和伪装,以充分避免检测

· 确保操作数据不被篡改和提取

· 最大化动作吞吐量

有些人可能熟悉汽车文化中的一句流行格言: “快速、可靠、廉价。” 选两个吧。” 这些目标在不同的方向上相互冲突,使我们的问题... ... 嗯... ... 成为了一个问题。 例如:

· 最大吞吐量可能依赖于不可靠的协议或系统

· 保护数据可能涉及潜在的通信路径

· 充分的伪装可能会减少协议选项

你还将注意到,我们目标的优先级是不同的,取决于操作的每个阶段。 在某些方面,我们可能会优先考虑隐形、吞吐量或可靠性。 正是基于这种洞察力,我们得出了第一个结论: “根据目的将你的基础设施进行分类”。 我们在黑暗面行动课程(Dark Side Ops)中大力宣扬这一点,对某些人来说可能已经过时了,但它仍然是真理。 我们的特殊类别看起来像这样:

· 阶段0(分段)-网络钓鱼和初始代码执行

· 阶段1(持久性)——维护对环境的访问

· 阶段2(交互式)——主动进行漏洞利用、枚举和权限升级

· 阶段3(渗出)-数据提取及影响

这种分段可以用来优化基础设施的一切:流量策略、代码设计、协议选择等等。 详细信息不在本文的范围之内。

浅谈红队基础设施架构和配置

分段基础设施关系图

分段还提供了固有的弹性,允许在不影响整个系统的情况下对基础设施进行独立的妥协。 我们不希望发现任何单一的 C2域、有效载荷或工具包来危及整个操作。

像任何优秀的系统工程师一样,我们必须假设在每个阶段都会发生破坏。 你的域名会被拉黑,你的服务器会瘫痪,你的回调会被阻止。 每个阶段的基础设施设计应该是健壮的,包括备用、检查和恢复。 一般来说,拥有“更多”的一切(具有复杂性)是一个良好的开端: 多域名、多协议、多工具等等。 所有这些都伴随着设计系统的真正挑战,但始终让你的核心目标成为指南。

堡垒

现在最具攻击性的基础设施包括在你的控制之下(或部分控制之下)从远程端点路由通信。 这可能是一个 VPS,无服务器端点,或被入侵的 web 主机。 我们喜欢称这些资产为“堡垒”。

最佳实践是仅使用一个堡垒来捕获流量,而不是直接存储数据,然而,每个团队都需要对外部基础设施端点进行自己的安全评估。 我们有一个内部网络边界,我们希望在解密、处理或存储之前访问所有数据。 在这里,我们为了更好的安全性而牺牲了流量路由的复杂性。

我们还有许多分布在供应商和其他地区的堡垒。 这种多样化是我们前面提到的阶段划分的一个要求,但也有助于提供我们需要的弹性。 这意味着多个供应商、服务器、 CDN、域名等等。 我们喜欢在一个集中的 wiki 中保持对所有事情的跟踪,以便于参考。

DevOps

一旦我们的资产数量变得相当庞大,我们就开始寻找 DevOps 解决方案,任何人都会这么做。 最初,我们走的是 Ansible 这条路,创建了一个集中管理服务器,用于分散我们所有不同的基础设施。 我们首选 Ansible,主要是因为它的无代理能力,只需要 SSH 访问来进行管理。 它执行工具安装、路由配置、证书生成、加固、依赖安装等。 我们已经看到了很多成功的案例,我们的 VPS 将时间从几个小时提升到10-15分钟。 这一成功得到了我们行业中其他人的响应,他们用自己选择的解决方案(Chef、Puppet、Terraform等)执行类似的管理。

然而,我们从来没有成为过 Ansible 的专家,并且不断地为我们次优的执行付出低廉的代价。 我们也看到了对完整 DevOps 工具的需求减少,因为我们已经过渡到了需求更少的简化堡垒。 尽管如此,对于足够多样化的基础设施来说,某种形式的 DevOps 是绝对必须的。 事实上,如果你觉得不需要自动化来管理基础架构,那么你可能需要更多的自动化。

隧道

随着你的堡垒配置,流量路由本身确实是一个优先项目。 更受欢迎的选择包括:

· Socat——易于使用,但在操作系统中比我们想要的要更麻烦。 当试图同时支持多个端口时,它也可能变得复杂

· IPTables ——正确配置比较棘手,但是非常强大,几乎没有依赖项

· 反向代理——在第7层提供高级选择性路由,但需要端点上的软件、证书和配

作为我们的堡垒,我们喜欢使用 IPTables。 这在一定程度上是因为我们喜欢把堡垒看作是我们内部运营网络的最简单扩展。 任何高于第4层的内容都会使配置复杂化,并引入新的依赖关系。 说到这里,我们还在前面的平面上使用了一个反向代理,类似于两阶段的隧道设置。 我们的设置目前看起来像这样:

浅谈红队基础设施架构和配置

流量采集图

我们的操作网络中有一个流量采集器,它创建到公共可访问的堡垒的 OpenVPN 连接。 使用这些隧道 + IPTables,流量从公共域名/ IP 路由到惟一的内部本地隧道接口。 我们使用它在采集器上的公共 IP 地址(1.2.3.4)和它们的隧道等效 IP (10.8.1.42)之间创建一个映射。 这里的一个替代方案是使用 NAT 和端口映射来降低静态复杂性,但是这样就很难对每个可能的目标端口都通用地处理流量(我们喜欢这样做)。

在此过程中,我们还执行路由操作,以避免 IPTables 在此场景中通常使用的源转换(SNAT)。 对于不支持 x-forwarded-For 等选项的协议,我们需要跟踪客户端 IP,以便进行筛选、跟踪等。 对于这个问题,业界有一个称为 PROXY 协议的替代解决方案,它允许包装第四层流量,并在操作和路由期间维护原始数据包信息。 我们发现这个解决方案后,已经开始我们的建设,并最终决定不重新设计。

下面是 DNAT 入站流量通过 VPN 隧道的一个例子:

iptables -t nat -A PREROUTING -d 1.2.3.4 -j DNAT --to-destination 10.8.1.42

为了使返回的流量返回到正确的接口,我们可能还需要执行一些基于策略的路由操作(假设你有多个公共接口) :

ip route add default via 1.2.3.4 dev eth1 table 100
ip route add 10.8.1.0/24 dev tun0 table 100
ip rule add from 10.8.1.42 lookup 100

这将导致从流量采集器返回的任何流量使用新的路由表(100)。 在这个新表中,我们为首选的公共 IP 和 VPN 网络的知识添加了一个默认路由。 我们将为每个处理流量的公共接口提供一个单独的表(比如一个具有多个 ENI 的 EC2实例)。 这将在我们的堡垒上的每个外部IP与OpenVPN隧道另一端的内部IP之间创建映射。

Nginx

随着我们的隧道建设完成,我们现在可以将所有的流量发送到我们周边的服务器上。 这个服务器可以是一个“全局工具服务器” ,但是考虑到我们的工具包的多样性和配置的复杂性,这有点不可行。 相反,我们将在流量路由中实现第二阶段,即流量采集器。 这和你看到的其他路由没什么不同,我们决定使用 Nginx 做这个工作,有几个不同的原因,如下:

· Nginx 得到了良好的支持,并提供了许多插件、特性、选项和项目

· Nginx 是仅有的能够执行第4层(TCP/UDP)流的7层代理之一。 这对于使用 DNS 隧道或混淆的第7层协议之类的工具非常重要

· Nginx 支持一种“透明代理”模式,允许你在没有 SNAT 的情况下转发流量,我们仍在努力避免这种情况

我们也考虑过 Envoy ,它让人好奇,但该项目仍然是相当新的项目。 在我们深入讨论之前,让我们介绍一下配置 Nginx 流量采集器的具体目标:

· 回调函数必须经过适当的路由

· 域名必须有合法的 SSL 证书

· 每个域名必须包含合法的 HTML 内容

· 我们不能在传输过程中丢失真实的客户端 IP 信息

在 Nginx 中,有两种主要的流量重路由方法: 反向代理和流模块。 我们将首先讨论这两者的一般优点和缺点,然后再讨论我们的具体实现。

反向代理

反向代理接收一个 HTTP 请求,有选择地修改或检查数据的各个方面,然后将其发送到指定的 web 服务器。 我们可以使用这个第七层实现智能化:

· 动态地检查 HTTP 流量,并动态地将流量路由到不同的监听站(LP)或内容服务器

· 简化 SSL 管理,并为所有证书使用单个服务器

· 动态修改 / 添加 HTTP 头和内容,以便为后端服务器提供上下文

使用反向代理的主要缺点是功能依赖于 HTTP/S。

流模块

简单来说,Nginx 流模块基本上就是端口重定向,就像 socat 一样。 类似于反向代理,你可以指定负载均衡和故障转移主机。 我们失去了第7层的智能化,不能在转发前限定回调。 然而,我们可以使用支持 TCP/UDP 的任意协议来路由流量。 这是 Nginx 在某种程度上的独特之处,关于这一特性的公开讨论比较少,但配置简单,对我们的目的来说似乎运行良好。

实现

在我们的生产设置中,我们使用了这两种路由选项。 让我们从基本配置开始,逐步完成特性集,直到我们得到所需的一切。 首先,一个基本的反向代理配置路由到我们的工具服务器:

http {
    server {
        listen 10.8.1.42:80;# Tunnel bind IP
        location / {
            proxy_set_header Host $host;
            proxy_set_header X-Forwarded-For $remote_addr;
            proxy_pass http://172.16.1.20; # Tooling server
        }
    }
}

接下来,我们需要添加 SSL 支持。 我们希望在 Nginx 服务器上断开 SSL,只转发 HTTP 通信。 这有助于简化工具服务器的配置。

http {
    server {
        listen 10.8.1.42:80; # Tunnel bind IP
        listen 10.8.1.42:443 ssl;
        ssl_certificate /etc/letsencrypt/live/domain.com/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/domain.com/privkey.pem;
        location / {
            proxy_set_header Host $host;
            proxy_set_header X-Forwarded-For $remote_addr;
            proxy_pass http://172.16.1.20; # Tooling server
        }
    }
}

我们通常使用 certbot 生成证书:

certbot certonly -d mydomain.com –standalone

所有到公共 IP 的流量现在都被路由到我们的工具服务器,但是我们也希望将不必要的 web 流量路由到一个单独的内容服务器。 这有助于稳定 LP 并减少被动负载。 为了实现这一目标,我们确定了两个策略:

· 只有当 LP 用于交互操作、数据外泄等时,才能临时将流量转发到 LP

· 只转发与我们的工具相关的流量(例如文件下载器、持久性等等)

对于解决方案 A,我们可以使用 Nginx 的上游池机制。 当可用时,流量将被转发到主上游地址(工具服务器) ,否则,它将被路由到备份地址(内容服务器)。 Nginx 将自动检测主上游地址何时可用,并相应地转发请求。

http {
    upstream pool-domain-com {
        server 172.16.1.10:80 backup; # Content Server
        server 172.16.1.20:80; # Tooling server
    }
    server {
        listen 10.8.1.42:80; # Tunnel bind IP
        listen 10.8.1.42:443 ssl;
        ssl_certificate /etc/letsencrypt/live/domain.com/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/domain.com/privkey.pem;
        location / {
            proxy_set_header Host $host;
            proxy_set_header X-Forwarded-For $remote_addr;
            proxy_pass http://pool-domain-com;
        }
    }
}

要实现解决方案 B,可以将 Nginx 配置为基于 GET 或 POST 变量、 HTTP 头或请求的 HTTP 页面路由请求。 例如,下面的配置将把对/API的代理请求反向到IP地址172.16.1.30。所有其他请求将被转发到pool-domain-com上游池。

http {
    upstream pool-domain-com {
        server 172.16.1.10:80 backup; # Content Server
        server 172.16.1.20:80; # Tooling server
    }
    server {
        listen 10.8.1.42:80; # Tunnel bind IP
        listen 10.8.1.42:443 ssl;
        ssl_certificate /etc/letsencrypt/live/domain.com/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/domain.com/privkey.pem;
        location /api { # Additional tooling endpoint
            proxy_set_header Host $host;
            proxy_set_header X-Forwarded-For $remote_addr;
            proxy_pass http://172.16.1.30/;
        }
        location / {
            proxy_set_header Host $host;
            proxy_set_header X-Forwarded-For $remote_addr;
            proxy_pass http://pool-domain-com;
        }
    }
}

基于 HTTP 标头和 URL 参数的路由要复杂一些。 我们不会详细讨论这个问题,但是为了给你指出正确的方向,请查看重写(rewrite)模块中的“if”指令文档。 下面是基于特定用户代理字符串的自定义路由规则的示例。 $http_user_agent 是一个标准的 Nginx 配置变量。 同样的逻辑也适用于其他配置变量。 这个文档提供了额外的细节。

location / {
    if ($http_user_agent ~ MSIE) {
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $remote_addr;
        proxy_pass http://pool-domain-com;
    }
}

现在我们的反向代理已经配置好了,我们需要添加对 DNS 回调的支持。 我们只需在 HTTP 配置部分的上方放置一个流指令,详细说明绑定端口和目的地。 值得注意的是,流指令仍然像 HTTP 配置一样支持上游池和透明绑定。 以下将把 TCP 53 全局重定向到172.16.1.20。

stream {
    server {
        listen 53 udp;
        proxy_pass 172.16.1.20:53; # DNS LP
    }
}
http {
    ...
}

经验教训

在生产环境中部署安装程序后不久,我们遇到了以下错误。

2099/01/02 21:08:47 [crit]: accept4() failed (24: Too many open files)

这是因为 Linux 对用户可以打开的文件数量设置了软限制和硬限制。 我们只需要通过修改如下所示的配置来增加操作系统级别和 Nginx 内部的限制。

在 /etc/security/limits.conf 文件中添加以下内容:

nginx       soft    nofile  200000
nginx       hard    nofile  200000

在 /etc/nginx/nginx.conf 文件中添加以下内容:

worker_rlimit_nofile 200000;

除此之外,还有一些其他的配置项值得一提:

· 请求最大内容尺寸(client_max_body_size)

· GZip 支持 (gzip)

· 保持活动超时(keepalive_timeout)

· SSL 配置 (ssl_protocols)

工具集成(签入 / 签出)

随着我们前面的 Nginx 配置完成,我们希望将一些最后的工作放到工具集成中。 理想情况下,我们需要一种临时捕获和释放流量流的机制。这将允许我们编写能够加载、接管可用流量流、将其用于操作、然后将其释放回池中的工具。 其中一个集成就是我们所说的“Op工作站”。一般来说,这只是操作人员用于交互操作的内部VM。当然,我们在这些观测站选择的工具是 Slingshot。

为了构建上面的解决方案,我们将一些基本的 DNS 服务与辅助 IP 寻址结合起来。 首先,假设我们有以下活跃的流量流:

banking.com -> Bastion A [1.2.3.4] -> Nginx [10.8.1.2] -> Content Server [172.16.1.10]
health.org  -> Bastion B [5.6.7.8] -> Nginx [10.8.1.3] -> Content Server [172.16.1.10]
support.com -> Bastion C [9.5.3.1] -> Nginx [10.8.1.4] -> Content Server [172.16.1.10]

使用下列Nginx上游池:

  upstream pool-banking-com {
        server 172.16.1.10:80 backup; # Content Server
        server 172.16.1.20:80; # Operations
  }
  ...
  upstream pool-heath-org {
        server 172.16.1.10:80 backup; # Content Server
        server 172.16.1.30:80; # Operations
  }
  ...
  upstream pool-support-com {
        server 172.16.1.10:80 backup; # Content Server
        server 172.16.1.40:80; # Operations
  }

Nginx 检测到所有操作的 IP 地址都没有被使用(无法访问) ,因此将这三个域名的所有流量路由到我们的内容服务器。 这些域名目前处于“被动模式” ,只是提供内容和看起来正常。 如果我们想让一个新的 VM/工具 开始捕获流量,我们只需为主机分配一个特定上游池的“操作”地址。

# Start collecting traffic for banking.com
ifconfig eth0:0 172.16.1.20 netmask 255.255.255.0

简单易用,但是特定的工具如何知道当前可用 IP 的列表以及它们映射到哪个域名? 我们花了相当多的时间来探索不同的解决方案。 Nginx 公开了一些我们的工具可以用来查询当前配置(redx  或 Nginx Pro)的 API。 我们可以有一个集中的 SQL 数据库,其中包含所有的活动域名。 我们可以使用某种 DHCP 服务来发布 / 更新 IP。 所有这些服务通常都是昂贵的,无论是技术上还是物理上。

最终我们选择了 DNS,即 OG 主机名数据库。 具体来说,我们选择了与本地主机文件配对的 dnsmasq 。 集合服务器很容易更新 / 修改记录,并且可以通过简单的域传送检索所有域名。 我们还可以添加文本标记,以根据目的和上下文划分域。

设置相对简单,大多数安装指南都能让你达到90% 的效果。 我们只需要做一些小的调整,将服务链接到一个静态主机文件,并允许从任何 IP 进行域传送。

addn-hosts=/root/records @ Our host file
auth-sec-servers=0.0.0.0
auth-zone=operations.local
domain=operations.local
log-queries

我们的 /root/records 文件如下所示:

172.16.1.10 content
172.16.1.20 stage2-banking-com
172.16.1.30 stage2-health-org
172.16.1.40 stage1-support-com

我们在这些域名前面添加了一个阶段标识符,以允许不同的工具只查询应用于它们的域名。 查找是一个简单的 AXFR,然后进行一些验证和选择。

$domains = dig axfr @ns1.operations.local operations.local | grep stage2
# Ping/Nmap to see which are in use
# Prompt the operator for a selection

总结

总之,我们设计了一种灵活、安全和可伸缩的方法来管理来自多种资源的多个回调。 这种方法简化了 SSL 证书管理(对于30多个域名来说,这是一个非常头疼的问题) ,以及需要启动和配置额外的外部基础设施,同时在内部网络中维护所有原始的 C2数据。

最终,基础设施提供了达到目的的手段。 它支持和增强了我们的运作,是任何一个好的红队的基础。 就像任何建筑一样,如果地基出现问题,那么所有的建筑最终都会变成一堆瓦砾。

我们希望在这里提供足够的信息,以激发你的兴趣,并激励你将你的基础设施提升到一个更好的水平。 我们欢迎反馈和新的想法。

参考资料

· https://www.nginx.com/resources/wiki/start/topics/depth/ifisevil/

· https://cheat.readthedocs.io/en/latest/nginx.html 

· https://docs.nginx.com/nginx/admin-guide/web-server/reverse-proxy/ 

· https://docs.nginx.com/nginx/admin-guide/security-controls/securing-http-traffic-upstream/

· https://gist.github.com/v0lkan/90fcb83c86918732b894

最近有很多关于红队基础设施的现代战略的讨论。每一种实现都有很大的不同,但是我们希望能够提供一些深入的信息,特别是关于我们团队如何处理命令和控制的挑战。 这反映了我们所犯的许多错误,比如深夜记录的文档,当前正在进行的研究,以及我们每天使用的现实世界的解决方案。

一点理论

在寻找最佳解决方案之前,我们首先需要清楚地说明我们的目标。 每个操作的细节都是独一无二的,但是我们觉得下面的内容是对红队的一个很好的概括。

· 提供可靠的工具通讯

· 混淆和伪装,以充分避免检测

· 确保操作数据不被篡改和提取

· 最大化动作吞吐量

有些人可能熟悉汽车文化中的一句流行格言: “快速、可靠、廉价。” 选两个吧。” 这些目标在不同的方向上相互冲突,使我们的问题... ... 嗯... ... 成为了一个问题。 例如:

· 最大吞吐量可能依赖于不可靠的协议或系统

· 保护数据可能涉及潜在的通信路径

· 充分的伪装可能会减少协议选项

你还将注意到,我们目标的优先级是不同的,取决于操作的每个阶段。 在某些方面,我们可能会优先考虑隐形、吞吐量或可靠性。 正是基于这种洞察力,我们得出了第一个结论: “根据目的将你的基础设施进行分类”。 我们在黑暗面行动课程(Dark Side Ops)中大力宣扬这一点,对某些人来说可能已经过时了,但它仍然是真理。 我们的特殊类别看起来像这样:

· 阶段0(分段)-网络钓鱼和初始代码执行

· 阶段1(持久性)——维护对环境的访问

· 阶段2(交互式)——主动进行漏洞利用、枚举和权限升级

· 阶段3(渗出)-数据提取及影响

这种分段可以用来优化基础设施的一切:流量策略、代码设计、协议选择等等。 详细信息不在本文的范围之内。

浅谈红队基础设施架构和配置

分段基础设施关系图

分段还提供了固有的弹性,允许在不影响整个系统的情况下对基础设施进行独立的妥协。 我们不希望发现任何单一的 C2域、有效载荷或工具包来危及整个操作。

像任何优秀的系统工程师一样,我们必须假设在每个阶段都会发生破坏。 你的域名会被拉黑,你的服务器会瘫痪,你的回调会被阻止。 每个阶段的基础设施设计应该是健壮的,包括备用、检查和恢复。 一般来说,拥有“更多”的一切(具有复杂性)是一个良好的开端: 多域名、多协议、多工具等等。 所有这些都伴随着设计系统的真正挑战,但始终让你的核心目标成为指南。

堡垒

现在最具攻击性的基础设施包括在你的控制之下(或部分控制之下)从远程端点路由通信。 这可能是一个 VPS,无服务器端点,或被入侵的 web 主机。 我们喜欢称这些资产为“堡垒”。

最佳实践是仅使用一个堡垒来捕获流量,而不是直接存储数据,然而,每个团队都需要对外部基础设施端点进行自己的安全评估。 我们有一个内部网络边界,我们希望在解密、处理或存储之前访问所有数据。 在这里,我们为了更好的安全性而牺牲了流量路由的复杂性。

我们还有许多分布在供应商和其他地区的堡垒。 这种多样化是我们前面提到的阶段划分的一个要求,但也有助于提供我们需要的弹性。 这意味着多个供应商、服务器、 CDN、域名等等。 我们喜欢在一个集中的 wiki 中保持对所有事情的跟踪,以便于参考。

DevOps

一旦我们的资产数量变得相当庞大,我们就开始寻找 DevOps 解决方案,任何人都会这么做。 最初,我们走的是 Ansible 这条路,创建了一个集中管理服务器,用于分散我们所有不同的基础设施。 我们首选 Ansible,主要是因为它的无代理能力,只需要 SSH 访问来进行管理。 它执行工具安装、路由配置、证书生成、加固、依赖安装等。 我们已经看到了很多成功的案例,我们的 VPS 将时间从几个小时提升到10-15分钟。 这一成功得到了我们行业中其他人的响应,他们用自己选择的解决方案(Chef、Puppet、Terraform等)执行类似的管理。

然而,我们从来没有成为过 Ansible 的专家,并且不断地为我们次优的执行付出低廉的代价。 我们也看到了对完整 DevOps 工具的需求减少,因为我们已经过渡到了需求更少的简化堡垒。 尽管如此,对于足够多样化的基础设施来说,某种形式的 DevOps 是绝对必须的。 事实上,如果你觉得不需要自动化来管理基础架构,那么你可能需要更多的自动化。

隧道

随着你的堡垒配置,流量路由本身确实是一个优先项目。 更受欢迎的选择包括:

· Socat——易于使用,但在操作系统中比我们想要的要更麻烦。 当试图同时支持多个端口时,它也可能变得复杂

· IPTables ——正确配置比较棘手,但是非常强大,几乎没有依赖项

· 反向代理——在第7层提供高级选择性路由,但需要端点上的软件、证书和配

作为我们的堡垒,我们喜欢使用 IPTables。 这在一定程度上是因为我们喜欢把堡垒看作是我们内部运营网络的最简单扩展。 任何高于第4层的内容都会使配置复杂化,并引入新的依赖关系。 说到这里,我们还在前面的平面上使用了一个反向代理,类似于两阶段的隧道设置。 我们的设置目前看起来像这样:

浅谈红队基础设施架构和配置

流量采集图

我们的操作网络中有一个流量采集器,它创建到公共可访问的堡垒的 OpenVPN 连接。 使用这些隧道 + IPTables,流量从公共域名/ IP 路由到惟一的内部本地隧道接口。 我们使用它在采集器上的公共 IP 地址(1.2.3.4)和它们的隧道等效 IP (10.8.1.42)之间创建一个映射。 这里的一个替代方案是使用 NAT 和端口映射来降低静态复杂性,但是这样就很难对每个可能的目标端口都通用地处理流量(我们喜欢这样做)。

在此过程中,我们还执行路由操作,以避免 IPTables 在此场景中通常使用的源转换(SNAT)。 对于不支持 x-forwarded-For 等选项的协议,我们需要跟踪客户端 IP,以便进行筛选、跟踪等。 对于这个问题,业界有一个称为 PROXY 协议的替代解决方案,它允许包装第四层流量,并在操作和路由期间维护原始数据包信息。 我们发现这个解决方案后,已经开始我们的建设,并最终决定不重新设计。

下面是 DNAT 入站流量通过 VPN 隧道的一个例子:

iptables -t nat -A PREROUTING -d 1.2.3.4 -j DNAT --to-destination 10.8.1.42

为了使返回的流量返回到正确的接口,我们可能还需要执行一些基于策略的路由操作(假设你有多个公共接口) :

ip route add default via 1.2.3.4 dev eth1 table 100
ip route add 10.8.1.0/24 dev tun0 table 100
ip rule add from 10.8.1.42 lookup 100

这将导致从流量采集器返回的任何流量使用新的路由表(100)。 在这个新表中,我们为首选的公共 IP 和 VPN 网络的知识添加了一个默认路由。 我们将为每个处理流量的公共接口提供一个单独的表(比如一个具有多个 ENI 的 EC2实例)。 这将在我们的堡垒上的每个外部IP与OpenVPN隧道另一端的内部IP之间创建映射。

Nginx

随着我们的隧道建设完成,我们现在可以将所有的流量发送到我们周边的服务器上。 这个服务器可以是一个“全局工具服务器” ,但是考虑到我们的工具包的多样性和配置的复杂性,这有点不可行。 相反,我们将在流量路由中实现第二阶段,即流量采集器。 这和你看到的其他路由没什么不同,我们决定使用 Nginx 做这个工作,有几个不同的原因,如下:

· Nginx 得到了良好的支持,并提供了许多插件、特性、选项和项目

· Nginx 是仅有的能够执行第4层(TCP/UDP)流的7层代理之一。 这对于使用 DNS 隧道或混淆的第7层协议之类的工具非常重要

· Nginx 支持一种“透明代理”模式,允许你在没有 SNAT 的情况下转发流量,我们仍在努力避免这种情况

我们也考虑过 Envoy ,它让人好奇,但该项目仍然是相当新的项目。 在我们深入讨论之前,让我们介绍一下配置 Nginx 流量采集器的具体目标:

· 回调函数必须经过适当的路由

· 域名必须有合法的 SSL 证书

· 每个域名必须包含合法的 HTML 内容

· 我们不能在传输过程中丢失真实的客户端 IP 信息

在 Nginx 中,有两种主要的流量重路由方法: 反向代理和流模块。 我们将首先讨论这两者的一般优点和缺点,然后再讨论我们的具体实现。

反向代理

反向代理接收一个 HTTP 请求,有选择地修改或检查数据的各个方面,然后将其发送到指定的 web 服务器。 我们可以使用这个第七层实现智能化:

· 动态地检查 HTTP 流量,并动态地将流量路由到不同的监听站(LP)或内容服务器

· 简化 SSL 管理,并为所有证书使用单个服务器

· 动态修改 / 添加 HTTP 头和内容,以便为后端服务器提供上下文

使用反向代理的主要缺点是功能依赖于 HTTP/S。

流模块

简单来说,Nginx 流模块基本上就是端口重定向,就像 socat 一样。 类似于反向代理,你可以指定负载均衡和故障转移主机。 我们失去了第7层的智能化,不能在转发前限定回调。 然而,我们可以使用支持 TCP/UDP 的任意协议来路由流量。 这是 Nginx 在某种程度上的独特之处,关于这一特性的公开讨论比较少,但配置简单,对我们的目的来说似乎运行良好。

实现

在我们的生产设置中,我们使用了这两种路由选项。 让我们从基本配置开始,逐步完成特性集,直到我们得到所需的一切。 首先,一个基本的反向代理配置路由到我们的工具服务器:

http {
    server {
        listen 10.8.1.42:80;# Tunnel bind IP
        location / {
            proxy_set_header Host $host;
            proxy_set_header X-Forwarded-For $remote_addr;
            proxy_pass http://172.16.1.20; # Tooling server
        }
    }
}

接下来,我们需要添加 SSL 支持。 我们希望在 Nginx 服务器上断开 SSL,只转发 HTTP 通信。 这有助于简化工具服务器的配置。

http {
    server {
        listen 10.8.1.42:80; # Tunnel bind IP
        listen 10.8.1.42:443 ssl;
        ssl_certificate /etc/letsencrypt/live/domain.com/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/domain.com/privkey.pem;
        location / {
            proxy_set_header Host $host;
            proxy_set_header X-Forwarded-For $remote_addr;
            proxy_pass http://172.16.1.20; # Tooling server
        }
    }
}

我们通常使用 certbot 生成证书:

certbot certonly -d mydomain.com –standalone

所有到公共 IP 的流量现在都被路由到我们的工具服务器,但是我们也希望将不必要的 web 流量路由到一个单独的内容服务器。 这有助于稳定 LP 并减少被动负载。 为了实现这一目标,我们确定了两个策略:

· 只有当 LP 用于交互操作、数据外泄等时,才能临时将流量转发到 LP

· 只转发与我们的工具相关的流量(例如文件下载器、持久性等等)

对于解决方案 A,我们可以使用 Nginx 的上游池机制。 当可用时,流量将被转发到主上游地址(工具服务器) ,否则,它将被路由到备份地址(内容服务器)。 Nginx 将自动检测主上游地址何时可用,并相应地转发请求。

http {
    upstream pool-domain-com {
        server 172.16.1.10:80 backup; # Content Server
        server 172.16.1.20:80; # Tooling server
    }
    server {
        listen 10.8.1.42:80; # Tunnel bind IP
        listen 10.8.1.42:443 ssl;
        ssl_certificate /etc/letsencrypt/live/domain.com/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/domain.com/privkey.pem;
        location / {
            proxy_set_header Host $host;
            proxy_set_header X-Forwarded-For $remote_addr;
            proxy_pass http://pool-domain-com;
        }
    }
}

要实现解决方案 B,可以将 Nginx 配置为基于 GET 或 POST 变量、 HTTP 头或请求的 HTTP 页面路由请求。 例如,下面的配置将把对/API的代理请求反向到IP地址172.16.1.30。所有其他请求将被转发到pool-domain-com上游池。

http {
    upstream pool-domain-com {
        server 172.16.1.10:80 backup; # Content Server
        server 172.16.1.20:80; # Tooling server
    }
    server {
        listen 10.8.1.42:80; # Tunnel bind IP
        listen 10.8.1.42:443 ssl;
        ssl_certificate /etc/letsencrypt/live/domain.com/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/domain.com/privkey.pem;
        location /api { # Additional tooling endpoint
            proxy_set_header Host $host;
            proxy_set_header X-Forwarded-For $remote_addr;
            proxy_pass http://172.16.1.30/;
        }
        location / {
            proxy_set_header Host $host;
            proxy_set_header X-Forwarded-For $remote_addr;
            proxy_pass http://pool-domain-com;
        }
    }
}

基于 HTTP 标头和 URL 参数的路由要复杂一些。 我们不会详细讨论这个问题,但是为了给你指出正确的方向,请查看重写(rewrite)模块中的“if”指令文档。 下面是基于特定用户代理字符串的自定义路由规则的示例。 $http_user_agent 是一个标准的 Nginx 配置变量。 同样的逻辑也适用于其他配置变量。 这个文档提供了额外的细节。

location / {
    if ($http_user_agent ~ MSIE) {
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $remote_addr;
        proxy_pass http://pool-domain-com;
    }
}

现在我们的反向代理已经配置好了,我们需要添加对 DNS 回调的支持。 我们只需在 HTTP 配置部分的上方放置一个流指令,详细说明绑定端口和目的地。 值得注意的是,流指令仍然像 HTTP 配置一样支持上游池和透明绑定。 以下将把 TCP 53 全局重定向到172.16.1.20。

stream {
    server {
        listen 53 udp;
        proxy_pass 172.16.1.20:53; # DNS LP
    }
}
http {
    ...
}

经验教训

在生产环境中部署安装程序后不久,我们遇到了以下错误。

2099/01/02 21:08:47 [crit]: accept4() failed (24: Too many open files)

这是因为 Linux 对用户可以打开的文件数量设置了软限制和硬限制。 我们只需要通过修改如下所示的配置来增加操作系统级别和 Nginx 内部的限制。

在 /etc/security/limits.conf 文件中添加以下内容:

nginx       soft    nofile  200000
nginx       hard    nofile  200000

在 /etc/nginx/nginx.conf 文件中添加以下内容:

worker_rlimit_nofile 200000;

除此之外,还有一些其他的配置项值得一提:

· 请求最大内容尺寸(client_max_body_size)

· GZip 支持 (gzip)

· 保持活动超时(keepalive_timeout)

· SSL 配置 (ssl_protocols)

工具集成(签入 / 签出)

随着我们前面的 Nginx 配置完成,我们希望将一些最后的工作放到工具集成中。 理想情况下,我们需要一种临时捕获和释放流量流的机制。这将允许我们编写能够加载、接管可用流量流、将其用于操作、然后将其释放回池中的工具。 其中一个集成就是我们所说的“Op工作站”。一般来说,这只是操作人员用于交互操作的内部VM。当然,我们在这些观测站选择的工具是 Slingshot。

为了构建上面的解决方案,我们将一些基本的 DNS 服务与辅助 IP 寻址结合起来。 首先,假设我们有以下活跃的流量流:

banking.com -> Bastion A [1.2.3.4] -> Nginx [10.8.1.2] -> Content Server [172.16.1.10]
health.org  -> Bastion B [5.6.7.8] -> Nginx [10.8.1.3] -> Content Server [172.16.1.10]
support.com -> Bastion C [9.5.3.1] -> Nginx [10.8.1.4] -> Content Server [172.16.1.10]

使用下列Nginx上游池:

  upstream pool-banking-com {
        server 172.16.1.10:80 backup; # Content Server
        server 172.16.1.20:80; # Operations
  }
  ...
  upstream pool-heath-org {
        server 172.16.1.10:80 backup; # Content Server
        server 172.16.1.30:80; # Operations
  }
  ...
  upstream pool-support-com {
        server 172.16.1.10:80 backup; # Content Server
        server 172.16.1.40:80; # Operations
  }

Nginx 检测到所有操作的 IP 地址都没有被使用(无法访问) ,因此将这三个域名的所有流量路由到我们的内容服务器。 这些域名目前处于“被动模式” ,只是提供内容和看起来正常。 如果我们想让一个新的 VM/工具 开始捕获流量,我们只需为主机分配一个特定上游池的“操作”地址。

# Start collecting traffic for banking.com
ifconfig eth0:0 172.16.1.20 netmask 255.255.255.0

简单易用,但是特定的工具如何知道当前可用 IP 的列表以及它们映射到哪个域名? 我们花了相当多的时间来探索不同的解决方案。 Nginx 公开了一些我们的工具可以用来查询当前配置(redx  或 Nginx Pro)的 API。 我们可以有一个集中的 SQL 数据库,其中包含所有的活动域名。 我们可以使用某种 DHCP 服务来发布 / 更新 IP。 所有这些服务通常都是昂贵的,无论是技术上还是物理上。

最终我们选择了 DNS,即 OG 主机名数据库。 具体来说,我们选择了与本地主机文件配对的 dnsmasq 。 集合服务器很容易更新 / 修改记录,并且可以通过简单的域传送检索所有域名。 我们还可以添加文本标记,以根据目的和上下文划分域。

设置相对简单,大多数安装指南都能让你达到90% 的效果。 我们只需要做一些小的调整,将服务链接到一个静态主机文件,并允许从任何 IP 进行域传送。

addn-hosts=/root/records @ Our host file
auth-sec-servers=0.0.0.0
auth-zone=operations.local
domain=operations.local
log-queries

我们的 /root/records 文件如下所示:

172.16.1.10 content
172.16.1.20 stage2-banking-com
172.16.1.30 stage2-health-org
172.16.1.40 stage1-support-com

我们在这些域名前面添加了一个阶段标识符,以允许不同的工具只查询应用于它们的域名。 查找是一个简单的 AXFR,然后进行一些验证和选择。

$domains = dig axfr @ns1.operations.local operations.local | grep stage2
# Ping/Nmap to see which are in use
# Prompt the operator for a selection

总结

总之,我们设计了一种灵活、安全和可伸缩的方法来管理来自多种资源的多个回调。 这种方法简化了 SSL 证书管理(对于30多个域名来说,这是一个非常头疼的问题) ,以及需要启动和配置额外的外部基础设施,同时在内部网络中维护所有原始的 C2数据。

最终,基础设施提供了达到目的的手段。 它支持和增强了我们的运作,是任何一个好的红队的基础。 就像任何建筑一样,如果地基出现问题,那么所有的建筑最终都会变成一堆瓦砾。

我们希望在这里提供足够的信息,以激发你的兴趣,并激励你将你的基础设施提升到一个更好的水平。 我们欢迎反馈和新的想法。

参考资料

· https://www.nginx.com/resources/wiki/start/topics/depth/ifisevil/

· https://cheat.readthedocs.io/en/latest/nginx.html 

· https://docs.nginx.com/nginx/admin-guide/web-server/reverse-proxy/ 

· https://docs.nginx.com/nginx/admin-guide/security-controls/securing-http-traffic-upstream/

· https://gist.github.com/v0lkan/90fcb83c86918732b894