Azure-应用渗透测试-全-
Azure 应用渗透测试(全)
原文:
zh.annas-archive.org/md5/3b98fc2e5c746ededc21631ce9912205译者:飞龙
第一章:准备工作

规划、启动会议、合同。听起来有点平凡,对吧?我想不到有哪位渗透测试员会更喜欢工作中的文书部分而不是黑客部分。话虽如此,一些准备工作对于成功完成测试并避免陷入麻烦是必不可少的。如果没有适当的规划和通知,你的渗透测试可能会违反法律或法律协议,最终可能会结束你的信息安全职业生涯。我保证,少量的前期工作可以快速完成,并且会导致更高质量的渗透测试,这将巩固你在顶级安全专家中的地位——所以,朋友,继续阅读吧!
本章将重点介绍正确设计和启动云聚焦渗透测试所需的步骤。我们将从考虑项目范围应包括哪些内容以及为什么在涉及云服务(如 Azure)时,范围设定比以往任何时候都更重要开始。之后,我们将继续讨论获取许可和一些需要遵循的重要规则。
混合方法
随着越来越多的公司将其 IT 基础设施的一部分迁移到云端,区分内部应用与面向公众的服务变得越来越困难。作为一名在云计算公司工作的专业渗透测试员,我见过很多请求来评估一个新的云部署。每当我看到这样的请求时,我总是推动扩大测试范围,涵盖云部分及任何相关的本地组件,包括非云数据存储、为从事云项目的员工创建的用户账户、员工工作站和测试环境。
当我被允许查看一个团队的内部、外部和基于云的资产时,项目结束时发现的问题数量似乎呈指数级增长——有几个原因。
团队并不总是拥有云计算经验
对于许多 IT 专业人士和软件工程师来说,云计算是一个全新的世界。当然,许多服务看起来与以前公司内部运行的服务相似,但许多行为与用户习惯有所不同。当这些差异被忽视或误解时,可能会导致攻击者能够利用的漏洞。
此外,1990 年代和 2000 年代最常见的安全架构是将所有内容放在受信任的内部网络上,然后在周围设置所有的安全防护。这种布局看起来很像古老的城堡——就像城堡一样,随着技术的变化,它已经变得过时。当一半的服务都放在连接到互联网的共享服务器上时,周界安全就不再有效了。
为云环境设计安全是可能的,但这需要规划、前瞻性思维和经验,而许多工程师尚未具备这些知识。在缺乏这些知识的情况下,通常会遇到各种不完善的云部署。
云默认情况下相对安全
这在一本关于云服务渗透测试的书中看起来可能有些奇怪,但事实是:云默认情况下是相当安全的。当客户访问云服务提供商的门户并点击创建虚拟机(VM)的步骤时,生成的系统通常是被锁定的。提供商有基础镜像,其中包含已启用防火墙、预装防病毒软件和仅有一个管理员。作为渗透测试人员,这意味着如果要求您限制范围仅限于一个云托管服务器,并且不能包含测试中的其他内容,您可能会失败。只有扩展范围后,事情才变得有趣起来。
例如,也许该虚拟机的管理员在多个地方重复使用他们的密码。也许他们会点击钓鱼邮件。我个人最喜欢的是,管理员将用于连接到云平台的密码留在网络共享的文本文件中。问题在于,如果范围仅限于该云虚拟机,您无法测试其中任何内容。这种范围有限的评估会给请求测试的人错误的印象,即他们的云资产是无法渗透的。实际上,黑帽(恶意)攻击者会使用这些方法之一来获取所需的访问权限。
一切都相互连接
如约翰·邓恩提醒我们的那样,“没有人是孤岛”。换句话说,所有人类都是相互连接的。我们的企业网络、云服务和互联网也是如此。在我的测试中,我经常会利用企业工作站上的立足点来访问云服务。一旦进入云服务,我会找到一些能让我访问之前不知道或无法破解的其他企业资源的东西。利用这些链接是你的优势;一个真正的攻击者不会犹豫地这样做。
获得许可
确定评估范围后,下一步是获取所需的许可。毕竟,没有许可,渗透测试可能会被视为黑帽黑客行为。我不希望您被起诉、被解雇或进监狱!因此,遵循本节讨论的步骤非常重要。
确定评估范围
确定一个详细的范围,明确指定将会被攻击的系统、将要使用的方法以及评估将何时进行,并获得所有当事方的批准,对于任何渗透测试都是至关重要的。在传统的本地评估过程中,这一点非常重要,因为您可能不想浪费时间攻击即将在本周末被淘汰的一堆服务器,也不想让已知存在问题正在修复中的一个生产服务器停机。
也就是说,确定一个带有云组件的渗透测试范围是极其重要的。相比于在企业网络中工作时,你可能只会(直接)影响目标组织,在云环境中,范围规划不当可能会导致攻击波及到同一云服务提供商的其他客户,甚至是服务提供商本身!想象一下,发现你认为属于公司 Azure 订阅的互联网协议(IP)地址实际上是某个外国国家的外交部在使用——而且你刚刚发现并利用了他们系统中的一个漏洞。这听起来像是一起国际事件的开始,我当然非常希望避免这种情况。
因此,我建议放弃黑箱测试(测试人员在测试开始时对目标知之甚少或毫无了解)。相反,要求采取更开放的方法,至少向你提供以下内容:
-
目标订阅标识符
-
你要攻击的服务的任何 IP 地址或主机名
-
订阅中服务类型的列表以及它们映射到的 IP 地址
-
参与的目标和期望结果
警告
某些服务会为你的目标分配专用的 IP 地址,但其他服务可能会在相同的基础设施上与多个客户共享这些地址。如果对这些 IP 地址进行广泛扫描将是明显的规则违反行为。
在制定测试范围时,另一个重要的考虑因素是组织政策。对于外部测试人员来说,这包括你所在公司和目标组织的规则。一些大公司有内部程序,规定在安全测试中哪些内容是禁止的(有时也会规定哪些内容必须包括)。违反这些规定可能会导致你失去工作,甚至更糟。如果你发现某个方法或服务是禁止的,但你认为它对准确评估至关重要,请确保向管理层、公司律师和政策制定者提出你的担忧。你可能会得到豁免;最坏的情况是,你可以在最终报告中记录并解释这一遗漏。
通知微软
一旦范围确定,你可能需要云服务提供商的许可——在我们的案例中是微软。每个提供商都有一套规则,限制允许进行的渗透测试类型以及是否需要通知。微软实际上在允许客户对自己订阅的资源进行渗透测试方面相对宽松,但它确实希望提前通知。这也是为什么在云中黑箱测试不太实际的另一个原因:Azure 渗透测试通知表单要求提供一些评估细节,而这些细节在黑箱测试开始时是无法预知的。
警告
云服务提供商的规则和要求随时可能发生变化。请始终检查提供商的网站以获取最新的政策。
截至本文撰写时,建议提交通知表单并收到微软的确认,尽管这不是强制性的。使用商业漏洞扫描器,如 Qualys 的漏洞管理工具或 Tenable 的 Nessus 进行扫描时,无需任何正式通知。此外,如果只是扫描开放网页应用程序安全项目(OWASP)十大网络漏洞、进行模糊测试或对少数资源进行端口扫描,则可以不提交表单。对于所有其他测试,最好提交通知。
要提交通知表单,请访问 portal.msrc.microsoft.com/en-us/engage/pentest 并提供以下信息:
-
用于登录 Azure 的电子邮件帐户
-
订阅 ID
-
联系信息
-
测试开始和结束日期
-
测试描述
-
条款和条件的确认
图 1-1 显示了此表单的示例。请注意,渗透测试的时间最长为六个月。对于更长的测试,表单需要重新提交。

图 1-1:Azure 渗透测试通知表单
表单还要求您确认并接受测试条款和条件。微软在 portal.msrc.microsoft.com/en-us/engage/pentest#pentestterms 上发布了 Azure 渗透测试规则。以下是这些规则的一些要点:
仅测试您已明确获得测试权限的订阅。
仅对您或您的公司拥有的订阅进行测试,或者您已获得所有者明确许可的订阅进行测试。这个规则很容易遵守。只需确保有一个明确的范围协议,将测试范围通过表单发送给 Azure 安全团队,并遵循它!
仅执行您在表单中描述的测试。
在评估过程中,通常会有诱惑将新资源纳入范围,当您发现以前不知道的系统或服务时(这通常被称为范围蔓延)。然而,如果您没有提交更新的通知表单,这将给您带来麻烦。同样,不要急于使用刚找到的新工具;首先提供通知。
不要以微软或其他客户的服务为目标。
在编写范围文档时,您非常精确地仅列出了目标的资产,对吧?如果是这样,应该不会有问题。只需记住,在云环境中,资源可能是流动的:服务器可能是共享的,IP 地址也可能发生变化。如果有疑问,在继续之前,请确认目标是由您的雇主拥有,并再次检查是否已收到微软的确认。
警告
对于平台即服务(PaaS)资源,如 Azure Web Apps,底层服务器可能为多个客户托管网站,因此不允许进行基于主机的攻击。这也是为什么在云环境中,确定攻击范围比在本地环境中要复杂得多的原因。
如果你发现了 Azure 本身的漏洞,请向微软报告。
微软对最后这一点相当严格——你必须在 24 小时内报告任何已识别的 Azure Fabric 漏洞,并且在 90 天内不得将其泄露到其他地方。不过,也有一个亮点:你可以将这些发现提交给微软在线服务漏洞悬赏计划(只要它们符合该计划的要求)。发现此类漏洞意味着需要额外的工作,但也可能带来不错的回报,并获得微软的公开认可。想了解更多关于漏洞悬赏计划的信息,请参阅 technet.microsoft.com/en-us/security/dn800983/。
获得一张“免监禁卡”
借用桌游Monopoly中的一个术语,免监禁卡是一份文件,证明你被授权执行渗透测试所涉及的操作。信中应清楚说明测试人员是谁、你被授权执行的活动范围以及测试的开始和结束日期。信件应由渗透测试负责人、被评估公司的一位高级经理以及(如果渗透测试员是外部人员)执行测试的公司的经理签署。理想情况下,信中还应包含一些验证其合法性而非伪造的手段,例如经理的联系信息。(我听说过一些测试人员实际上携带着伪造和合法的信件,以确保有程序可以验证潜在攻击者的言辞。)
如果渗透测试人员被企业安全人员或蓝队成员询问,可以出示这封信。必要时,也可以出示给执法人员,尽管不要被名字误导——如果你被拘留,警察不太可能仅凭此文件就将你释放。虽然这些信件在评估物理安全时最为有用,但即使物理评估不在测试范围内,我也喜欢准备一封。这能证明我所采取的行动是被授权的,即使一颗流星不幸在我管理层参加外部会议时将他们压垮,我也能证明我上周的黑客行为不是恶意的。
如果你需要一个模板信函,渗透测试专家和 SANS 讲师 Ed Skoudis 在他的网站上提供了一个,地址是 www.counterhack.net/permission_memo.html。Ed 还给他的学生提供了这个非常好的建议:让你的律师审查你的信函(以及任何与渗透测试相关的合同和协议)。对于一个组织在一个地方有效的做法,可能并不适用于你。如果你是公司内部的渗透测试员,你公司的法律团队可以提供帮助。如果你是独立承包商,请聘请律师为你提供法律支持。黑客攻击(即使是经过许可的)也是一项高风险的工作。
注意并尊重当地法律
说到咨询律师,与你的法律顾问合作,确定是否有任何国家、地区或地方的法律可能限制你在渗透测试中可以执行的活动,或者是否需要特别关注某些服务器或数据类型。例如,一些规定要求在财务或医疗记录被不当访问时,必须通知客户或患者。渗透测试者的访问是否需要符合这些披露要求?向律师咨询总比做出假设要好得多。
此外,不仅要关注渗透测试者的所在地,还要关注目标服务器、目标公司总部和分支机构的位置,以及(如果适用)进行测试的安全公司的位置。因为这些实体所在地的法律可能有所不同,所以了解每个评估地点的规则至关重要。尤其是在审视云资源时,这一点尤为复杂。毕竟,如果在测试过程中,服务器迁移到不同的区域怎么办?可能并不会显现出任何变化,但突然间,目标可能位于一个法律大不相同的国家。在制定测试范围时,一定要与客户讨论这个问题,确保你知道在评估窗口期间,服务可能会驻留在哪些地方。如果客户希望测试一个位于渗透测试法规不友好的国家的系统,客户甚至可能考虑在测试过程中将资源迁移到其他地区。只要确保在迁移过程中不改变服务的配置,否则可能导致错误的测试结果。
总结
在这一章中,我讨论了同时测试云服务和公司网络的重要性,以确保最好的覆盖范围。我还讨论了如何在进行渗透测试之前通知或获得所有相关方的许可,以及如何避免触犯刑事司法系统。
接下来,我们将探讨通过一些方法入侵目标的 Azure 订阅。
第二章:访问方法

一旦你手中拿到签署的范围协议并已通知微软,接下来就是获得对目标订阅的特权访问权限。本章重点介绍如何从合法用户或服务获取 Azure 订阅的凭证。我们首先了解 Azure 用来控制订阅访问的不同机制,以及如何管理部署和权限。接下来,我们会讨论常见的 Azure 凭证存放位置,并讲解如何获取它们。最后,我们会讨论可能用于为订阅提供额外保护的双因素认证,并探讨几种绕过它的方法。
Azure 部署模型
在我们开始嗅探订阅的访问权限之前,让我们先讨论一下 Azure 的两种认证和权限模型。Azure 有一个遗留模型,Azure 服务管理(ASM),它在 Azure 刚发布时被使用,另一个是更近期的基于角色的系统,Azure 资源管理器(ARM)。由于这两种模型仍然在使用中,因此了解每种模型的工作原理以及如何绕过它们非常重要。
虽然这两种模型可以在任何给定的订阅中共存,但特定订阅中的每个资源仅使用一种模型。因此,如果你通过传统门户进行认证,你将只能看到“经典” Azure 服务。同样,运行较新的 Azure PowerShell 命令通常只会让你访问现代资源。
结果是,黑客攻击一个用户账户可能只会提供对订阅下部分服务的访问权限。因此,尝试渗透目标订阅中的两种模型至关重要,以确保进行完整的测试。
Azure 服务管理
Azure 服务管理是部署和与 Azure 资源交互的最初设计。有时被称为“Azure 经典版”,ASM 最常与旧版 Azure 管理网站相关联,* manage.windowsazure.com/ *。
ASM 包含许多不同的组件,包括以下内容:
-
一个应用程序编程接口(API),用于以编程方式管理资源
-
一组用于查询和与服务交互的 PowerShell 命令
-
用户名/密码认证支持
-
基于 X.509 证书的认证
-
用于控制资源的命令行界面
-
管理网站
每个组件都代表了渗透测试人员的潜在入口点或信息来源。
ASM 中的授权
Azure 服务管理模型使用一个简单的授权机制,只有三种可能的角色:服务管理员、帐户管理员和共同管理员。前两个角色每个订阅只能有一个。根据需要,可以将这两个角色分配给同一个用户。
服务管理员是主要的管理帐户。它可以对订阅的服务进行任何更改,并添加用户作为共同管理员。帐户管理员(也称为帐户所有者)可以更改账单详情以及分配给服务管理员角色的帐户,但无法修改服务。共同管理员拥有与服务管理员相同的权限,唯一的例外是无法更改其他用户的角色为服务管理员。
因为共同管理员与服务管理员基本等同,且两者对任何 ASM 创建的资源都有完全控制权,一旦你获得 Azure 订阅的 ASM 访问权限,所有 ASM 资源都完全由你控制。
用户或服务帐户可以使用用户名和密码对 ASM 进行身份验证,也可以使用 X.509 证书进行身份验证。订阅的所有者可以登录管理门户并向订阅添加用户。他们添加的帐户必须是 Microsoft 帐户(MSA),即微软注册的电子邮件地址(以前称为 Live ID,甚至更早时是 Passport),或者是 Azure Active Directory(AAD) 中的帐户。添加到订阅后,该用户只需使用其电子邮件地址和为其 MSA 或 AAD 帐户设置的密码进行连接。
基于证书的身份验证是 ASM 特有的,并没有在 ARM 中(直接)实现,本章稍后会讨论。它在 ASM 中被称为管理证书,X.509 身份验证最初是为需要与 Azure 进行程序化交互的服务设计的。它也用于直接从 Visual Studio 部署代码到 Azure,并且在使用 PowerShell 管理订阅时,可以用来替代用户名/密码凭据。
这些都是合理的使用案例,理论上,证书在身份验证中应该比密码更安全。毕竟,证书不容易通过钓鱼攻击被用户泄露,不像密码那样容易受到猜测或字典攻击,而且几乎肯定比用户的密码拥有更多的熵。那么,为什么 Azure 不将它们应用到更现代的模型中呢?可能有许多原因,但我在渗透测试中最常遇到的问题是证书的可管理性。
ASM 中的证书管理
可管理性是 Azure 管理证书的最大问题。一些管理证书的问题包括确定证书的使用位置、证书名称的重复使用、缺乏吊销列表、存储不当以及不可否认性。
图 2-1 显示了 Azure 的管理证书设置页面,其中包括每个添加到订阅中的证书的详细信息,并允许管理员添加新证书或移除现有证书。

图 2-1:Azure 管理证书设置
让我们看看管理这些证书的一些难题,这些问题可能导致安全隐患。
跨订阅跟踪证书
当证书被添加到订阅中时,Azure 门户不会告诉你是谁创建了该证书或是谁上传的。(请注意图 2-1 中没有所有者或创建者列。)更为复杂的是,无法查找某个证书在哪些订阅中被授权。这意味着,如果网络防御团队收到某个证书被泄露的警报,他们不一定知道哪些订阅受到了影响。
名称重用
名称不当的证书是管理员在维护订阅时面临的另一个问题。由于证书是由各种工具(如 Visual Studio、PowerShell,甚至 Azure 门户本身)自动生成的,不同的证书经常使用相同的名称。例如,图 2-1 显示了多个由 Visual Studio 生成的证书,它们使用相同的名称——“Visual Studio Ultimate” ➊——仅通过指纹 ➋ 区分。
由于每个 Azure 订阅最多可以有 100 个管理证书,名称重用很快会使得确定哪个证书属于谁变得困难。如果管理员被解雇,剩下的管理员如何知道哪些证书必须被删除?
吊销
与大多数使用 X.509 证书的系统不同,Azure 并没有为管理证书实现证书吊销列表(CRLs)。证书吊销列表会在一个集中位置记录证书何时不再可信,服务可以检查该位置。例如,如果实现了 CRLs,管理员可以发布更新,声明“不再信任证书 X”,所有允许该证书的服务将自动阻止它。没有 CRLs 时,必须手动从每个订阅中删除受损的证书。然而,由于无法确定哪些订阅可以使用某个证书,因此常常会发现一些不良证书被无意中留在某些订阅中。
存储
管理证书的另一个关键问题是如何妥善、安全地存储证书。由于证书经常由像 Visual Studio 这样的工具生成,这些文件的位置通常是可预测的。事实上,它们常常可以在源代码库和用户的下载文件夹中找到,甚至可能直接从管理员计算机上的证书存储中导出。
不可否认性
不可否认性描述了系统能够明确声明某个操作是由特定用户执行的能力,从而确保该用户无法声称是其他人执行的操作。不可否认性在用户名和密码的使用中最为直观,且密码不应共享这一原则已被广泛认可。不幸的是,用户通常不像对待密码那样重视证书,团队成员常常共享一个证书来访问多个订阅。
这些问题使得管理证书的持续、彻底审核和清理变得困难。孤立的管理证书可能会使订阅易受攻击,遗忘的证书的使用可能长时间不被察觉。
Azure 资源管理器
在 Azure 最初发布后的几年,微软意识到需要改进 Azure 管理的多个方面。与其将这些更改整合到现有的 ASM 管理门户和 API 中,微软推出了 Azure 资源管理器作为替代。
ARM 最显著的变化是可通过* portal.azure.com/*访问的门户,但这仅仅是模型中最直观的部分。按重要性顺序,ARM 中引入的显著变化包括:
-
基于角色的访问控制
-
移除管理证书
-
增加服务主体
-
能够将一组资源作为一个单元进行管理
-
新的 PowerShell cmdlet
-
快速部署复杂服务的模板
基于角色的访问控制(RBAC)为渗透测试人员带来了最大变化。与 ASM 仅提供有限角色不同,ARM 提供了大量角色,这些角色可以在订阅级别和每个资源基础上分配给用户。
最常见的角色包括所有者(完全控制)、贡献者(拥有除更改权限外的所有权利)、读者(只读控制)和用户访问管理员(仅能编辑权限)。其他服务特定角色,如 SQL 数据库贡献者和网站贡献者,允许所有者将数据库管理员的权限限制为仅能访问 SQL 服务器,同时允许网页开发人员仅修改网站。在危害订阅时,理想情况下,你会优先选择针对整个订阅的所有者用户。
另一个重要的变化是增加了服务主体。这些帐户类似于本地服务器中的服务帐户——如用于运行 Web 服务器的 Apache 守护进程和互联网信息服务(IIS)帐户。服务主体允许应用程序在与常规用户无关的帐户下运行,并且仍然能够访问其他云资源。例如,一家公司的 Azure 网站可能需要访问 Azure Active Directory(AAD)以查找员工信息。该网站需要某个帐户登录 AAD,但开发人员显然不希望该网站使用他们的用户凭据来执行这些查询。此时就需要使用服务主体。
因为服务主体用于软件、脚本和自动化,这些账户可以使用密码(自动生成并称为“客户端密钥”)或证书进行身份验证,尽管它们的配置和使用与 ASM 管理证书不同。遵循最小权限原则,服务主体通常仅通过 RBAC 被分配足够的访问权限来执行特定任务,因此即使一个服务主体被攻破,也只能提供访问订阅中一小部分资源的权限。
DEFENDER’S TIP
因为 ARM 相比 ASM 提供了多个安全优势,你应该将现有的基于 ASM 的服务迁移到 ARM。为此,从 GitHub 下载 MigAz 和 ASM2ARM 工具。微软也发布了几篇关于 ARM 迁移的文章,详见 docs.microsoft.com/en-us/azure/virtual-machines/windows/migration-classic-resource-manager-overview/。
获取凭证
作为渗透测试员,我们必须收集凭证,以展示真实攻击者可能会如何利用访问客户资源的权限。我们的目标账户应当是一个能够提供管理员访问权限的账户,能够访问目标的 ASM 资源,拥有订阅中所有 ARM 资源的所有者权限,并且没有启用双因素认证(2FA)。这样的账户将能够创建、查看、修改或删除订阅中的任何服务,并且可以无需响应电话提示即可登录。在 Azure 上找到这样的账户,等同于在 Linux 中找到一个使用默认密码且可以远程登录的 root 账户。
寻找目标账户的第一步是定位一个使用用户名和密码登录的服务账户,并且该账户是目标订阅在 ASM 中的共同管理员。服务账户是理想的选择,因为它们很少启用双因素认证,密码不常更改,且密码经常保存在源代码中。如果没有这样的账户,一个人类管理员用户的账户(例如经理或首席开发人员)也可以,因为他们可能对所有资源拥有完全控制权,即使启用了双因素认证也不例外。作为最后的手段,可以考虑使用管理证书。尽管它们不能提供对 ARM 资源的访问,但通常很容易获得,并且不常更改或删除。
通过调查凭证,你将能够判断客户是否正确保护了这些关键的秘密,如果没有,你可以提供指导,帮助他们安全地保护这些秘密。让我们看看如何尝试获取这些凭证。
Mimikatz
直接从用户的操作系统中获取凭据,应该是我最喜欢的渗透测试方法之一。这个概念非常简单:即使系统断开了网络,操作系统仍然需要跟踪用户的密码,以完成一些任务,比如验证密码,或者将密码转发给其他系统,这样用户就不必重新输入密码了,比如连接文件服务器时。
多年来,许多用于从操作系统的不同位置提取密码或密码哈希的工具一直存在。早期的工具,如 Cain & Abel,可以从 Windows 安全账户管理器(SAM)文件中提取密码,而 PwDump 也有多个不同版本,使用了不同的提取方法。然而,Benjamin Delpy 发布的 Mimikatz 彻底改变了这一局面,它允许直接从系统的内存中窃取密码。
使用 Mimikatz
Mimikatz 的主要功能是通过识别 Windows 系统上正在运行的本地安全认证子系统服务(LSASS),连接到该服务,并从其内存中提取秘密。尽管 Mimikatz 能够提取多种类型的秘密,我们这里只关注用户密码。
在使用 Mimikatz 之前,你需要先获得目标管理员使用的系统的管理员权限。在域环境中,这通常并不困难。例如,你可以通过钓鱼攻击终端服务器的管理员,该服务器也被目标用户使用,然后在该服务器上运行 Mimikatz,或者你可以通过社交工程攻击帮助台员工,获取一个在域中所有工作站上都有管理员权限的安全组账户。只需要在任何最近被帮助台处理过的系统上拥有管理员账户,就可以在该系统上执行 Mimikatz,获取帮助台的密码。
一旦你获得了系统的管理员权限,就可以从github.com/gentilkiwi/mimikatz/下载 Mimikatz。如果下载被杀毒软件拦截,完全可以运行一个已经转换为 PowerShell 脚本的版本,该版本作为 PowerSploit 框架的一部分,可以从github.com/PowerShellMafia/PowerSploit/下载。你也可以获取 Mimikatz 的源代码,进行一些小的修改,然后重新编译(并重命名二进制文件),以绕过任何基于签名的杀毒软件检测。(Mimikatz 的 GitHub 页面提供了详细的操作步骤。)
现在,在目标系统上启动一个提升权限的命令提示符,并根据操作系统架构执行 32 位或 64 位版本的mimikatz.exe。(如果不确定架构,可以运行 wmic OS get OSArchitecture 命令。)
捕获凭据
要捕获凭据,Mimikatz 需要调试权限。它使用这个权限来读取 LSASS 中的内存。为了赋予它这个权限,在 Mimikatz 提示符下输入 privilege::debug,如下所示:
mimikatz # privilege::debug
Privilege '20' OK
接下来,执行 sekurlsa::logonpasswords 命令以转储 Mimikatz 可以找到的所有密码和哈希值,如 清单 2-1 所示。
mimikatz # sekurlsa::logonpasswords
Authentication Id : 0 ; 249835 (00000000:0003cfeb)
Session : Interactive from 1
User Name : Administrator
Domain : Corporation
Logon Server : Workstation
Logon Time : 11/1/2016 11:09:59 PM
SID : S-1-5-21-2220999950-2000000220-1111191198-1001
msv :
[00000003] Primary
* Username : TargetUser
* Domain : Corporation
➊ * NTLM : 92937945b518814341de3f726500d4ff
* SHA1 : 02726d40f378e716981c4321d60ba3a325ed6a4c
[00010000] CredentialKeys
* NTLM : 92937945b518814341de3f726500d4ff
* SHA1 : 02726d40f378e716981c4321d60ba3a325ed6a4c
➋ tspkg :
* Username : TargetUser
* Domain : Corporation
* Password : Pa$$w0rd
wdigest :
* Username : TargetUser
* Domain : Corporation
* Password : Pa$$w0rd
kerberos :
* Username : TargetUser
* Domain : Corporation
* Password : (null)
清单 2-1:使用 Mimikatz 获取密码
如你在输出中看到的,Mimikatz 成功找到了 TargetUser 的 NTLM 和 SHA1 哈希值 ➊。它还能够在 LSASS 中的 tspkg 和 wdigest 扩展中找到明文密码(非哈希版本) ➋。
影响成功的因素
有几个因素会影响 Mimikatz 获取密码的能力。最重要的因素是用户使用的操作系统版本。虽然 Mimikatz 支持从 Windows 2000 到 Windows 10 的所有版本,但较新的 Windows 版本在凭据存储方面有所改进。例如,在 Windows Vista 和 Windows Server 2008 中,即使用户已注销(只要系统未重启),获取明文密码是很常见的。而在 Windows 10 中,虽然仍然可以获取哈希值,但明文密码获取难度较大,仅在用户会话处于活动状态时才能成功获取。此外,Windows 10 企业版中的 Credential Guard 功能启用后,会将这些秘密信息移入一个独立的容器中,更加防范黑客工具的攻击。
Mimikatz 获取凭据的能力还取决于目标系统的配置和安装的应用程序。一些应用程序和 Windows 功能依赖于有一份用户凭据的副本,以便在每次建立远程连接时,用户无需重新输入密码。随着每个新版本的发布,Windows 删除了一些对明文密码的依赖关系,但微软无法控制第三方软件的行为,因此可能需要一段时间才能清除所有内存中的凭据。
Mimikatz 依赖于 Windows 中某些已知存储凭据的位置,且该程序会随着 Windows 的更新而演变。因此,如果目标系统运行的是某个不常见的 Windows 版本(例如技术预览版),Mimikatz 可能无法确定凭据在内存中的存储位置。
DEFENDER’S TIP
使用 Credential Guard 是保护用户凭据免受如 Mimikatz 等黑客工具攻击的最佳方法之一,但该功能在 Windows 10 或 Windows Server 2016 之前的操作系统中不可用。对于攻击者来说,这是一个最令人沮丧的安全功能。你可以通过访问 technet.microsoft.com/en-us/itpro/windows/keep-secure/credential-guard/ 了解更多关于此 Windows 功能的信息。
最佳实践:用户名和密码
尽管密码已经使用了几十年,但弱密码选择仍然是安全漏洞的一个主要因素。虽然让所有用户都选择强密码可能很困难,但管理员和公司政策制定者可以通过消除导致弱密码构造的规则来帮助支持用户做出更好的密码选择。
例如,传统观点认为公司应该强制实施短期密码有效期,以便用户每隔几个月就需要更换密码。尽管这种做法确实有助于防止长密码的哈希破解,但这也意味着用户需要每年多次想出一个新的、复杂的密码,并且这个密码不基于过去使用的密码,而是能够记住的。实际上,这往往导致用户选择的密码仅勉强满足公司对密码长度的要求,并且包含一些可以预测的元素,如字典词汇或日期。
相反,美国国家标准与技术研究院(NIST)2017 年的《数字身份指南》现在建议不要强制频繁更改密码,以便让用户能够创建一个非常强大的密码并保持较长时间。该指南建议只有在凭证被确定已被泄露时,才强制要求更改密码。
公司还可以鼓励用户使用合适的密码管理器来生成和存储凭证。这些工具帮助确保用户为他们使用的每个系统、服务或网站选择强大且随机的密码。这大大提高了安全性,因为跨多个站点的密码重复使用意味着,如果任何一个站点被攻破,用户在其他服务中使用相同密码的安全性也会受到威胁。
此外,即使是强密码,如果用户容易受到钓鱼攻击,密码仍然可能被获取(更多内容请参见“钓鱼攻击”一节,第 19 页)。阻止钓鱼攻击的最有效方法之一是为服务启用多因素认证,例如要求用户在输入密码的同时,还需要输入从手机设备收到的验证码。这大大增加了攻击者发起攻击的复杂性。
最后,我们知道,使用基于密码的身份验证的面向网络的服务,常常成为密码猜测攻击的目标,正如在“猜测密码”一节中,第 21 页所描述的那样。为了减少这种风险,确保这些服务的所有管理员账户使用唯一的用户名,因为攻击者通常会尝试一些常见的用户名,如administrator、admin和root。
用户名和密码
当 Mimikatz 不可用时,你需要找到另一种方式来获取用户名和密码。这可以通过搜索未加密的文档、钓鱼攻击、查找已保存的认证令牌或利用教育性猜测来实现。每种方法都有其优缺点。
搜索未加密文档
企业渗透测试人员常常会发现大量密码就这样散落在外,供调查者轻易获取。尽管在一些公司里,贴在显示器上的便签上写着俗气的密码仍然是一个问题,但大多数渗透测试人员无法一间办公室一间办公室地寻找凭证。幸运的是,许多密码保存在未加密的文件中,攻击者可以轻松地远程访问。
如果你的目标是一个服务账户,你通常会在该服务使用的源代码和配置(.config)文件中找到该账户的密码。密码也可能出现在团队门户网站或文件共享中的设计文档里。
当你以寻找用户名和密码为目标时,可以在文本文件或电子表格中查找密码,这些文件通常位于用户的桌面或文档目录下。(当然,你需要访问该用户的 PC 或网络。)正如你所知道的,浏览器会主动为用户保存密码,而一旦进入系统,这些密码通常很容易恢复。
钓鱼攻击
一种出人意料的成功获取密码的方法是通过钓鱼攻击—或者更准确地说,鱼叉式钓鱼攻击。在钓鱼攻击中,你会通过电子邮件联系大量用户,试图欺骗他们采取某些行动,例如通过说服他们访问恶意网站,或者让他们安装恶意软件,从而泄露他们的用户名和密码。
鱼叉式钓鱼攻击(Spear phishing)实际上是钓鱼攻击(phishing)的一种更有针对性的变种:你通过电子邮件联系一个非常特定的群体,使用对目标来说熟悉的语言,并让邮件看起来像是来自一个合法或预期的地址。例如,通常的钓鱼邮件可能包含一个链接,指向一个所谓的贺卡,并发送给成千上万的用户,而鱼叉式钓鱼邮件可能看起来像是来自人力资源部门,仅发送给十几个人,并要求更新他们的联系方式。
作为一名安全专业人员,根据我的经验,许多鱼叉式钓鱼攻击模仿了用户通常期望的邮件类型,包括某些泄露的公司邮件的风格和语言。这些邮件通常来自一个听起来合法的地址,并包含一个看似合理的 URL 链接。例如,攻击者可能会注册一个与目标公司真实地址非常相近的域名—也许使用.net而不是.com,或者进行字符替换,例如将大写字母I替换为小写字母l。
最成功的钓鱼攻击往往利用人们的希望和恐惧。提供某种奖励的邮件,比如免费的活动门票或礼品卡,或者威胁取消某些员工福利或暂停用户账户,几乎总是能得到迅速的回应。
网络钓鱼邮件包含一个链接,旨在诱使用户点击该链接,将用户引导到一个网页,在该网页上用户被提示登录。成功的目标页面看起来与目标用户公司使用的真实页面一模一样。钓鱼页面会将密码保存到攻击者控制的安全日志或数据库中,然后将用户重定向到某个合理的地方,以避免引起怀疑,例如重定向到一个真实的登录页面、一个显示邮件中提到的促销活动已过期的页面,或者一个显示公司重新考虑并决定不再向员工收取复印机使用费的页面。
警告
在设置凭证捕获系统时要格外小心。你应该遵循所有针对钓鱼网站和数据库的安全最佳实践,包括在传输过程中使用加密、静态加密以及使用强大的多因素身份验证来访问秘密。你的网站应进行代码审查以发现缺陷,底层服务/系统应完全修补。未能采取这些预防措施可能会使员工凭证面临更大的风险,违反目标公司政策,并导致实际的安全漏洞。
然而,钓鱼攻击也不是没有缺点。首先,它只能用来攻击用户,而不是服务帐户。此外,只需一个用户识别出该邮件是钓鱼攻击并进行报告,就能使目标组织的安全团队介入,隔离邮件,列入钓鱼网站黑名单,并重置你已经获得的任何帐户密码。
寻找保存的 ARM 配置文件令牌
JavaScript 对象表示法(JSON)文件是另一种能够存储凭证的地方。由于开发人员在访问 ARM 资源时经常需要使用不同的帐户(可能是出于自动化或测试的目的),Azure 提供了一个 ARM PowerShell cmdlet,用于将 Azure 凭证保存为配置文件:Save-AzureRmProfile。这些配置文件只是 JSON 文件,开发人员可以选择将其存储在任何他们喜欢的位置。这些 JSON 文件中包含一个令牌,这是已保存凭证的存储表示。要使用它,只需运行 Select-AzureRmProfile cmdlet,并使用 -Path 参数指定 JSON 文件即可。
查找这些已保存的配置文件可能有些棘手,因为它们没有独特的扩展名(事实上,它们可以有任何扩展名,尽管大多数用户选择 .json,因为文档中使用了这个扩展名)。然而,你应该能够通过搜索包含配置文件中使用的关键字的文件来找到这些配置文件。搜索像TokenCache这样的术语,这是文件中存储实际凭证的变量。如果这在目标用户的系统中返回太多误报,可以尝试Tenant、PublishSettingsFileUrl 和 ManagementPortalUrl。这些关键字应该足以定位任何已保存的配置文件,并且误报最少。
猜测密码
获取账户密码的最终方式之一就是简单地猜测。没有受过教育的猜测不太可能有成果,但结合一些推理和研究,猜测是有可能成功的。
在尝试猜测密码时,首先应尝试找到组织的密码策略。如果所有密码都必须至少包含九个字符,并且包括字母和数字,那么仅仅尝试某人的生日肯定会失败。此外,知道是否有账户锁定政策至关重要,因为它决定了在账户被锁定之前,可以对单个账户进行多少次猜测,从而提醒用户这些尝试。
接下来,尝试收集目标用户的信息。配偶、孩子和宠物的名字非常有用,生日、纪念日和毕业日期也同样重要。甚至知道一个组织要求多久更换一次密码也可能很有用。必须每 30 天更换一次密码的用户常常在密码中使用月份的名字(或其数字等价物),这一点令人不安。
在猜测时,尝试找到一些可以验证用户凭证并快速报告结果的公共端点。企业的 Web 邮件站点和虚拟私人网络(VPN)端点可能是不错的选择。一个不限制登录尝试次数且不锁定用户账户的站点对攻击者来说非常有用。
防御者提示
在一定次数的登录尝试失败后实施自动账户锁定是一种流行的应对密码猜测攻击的方法;然而,这可能会导致意外的后果,阻止合法账户持有者在账户解锁之前访问网络资源。因此,基于源机器的 IP 地址或正在测试的账户限制登录尝试的速率,可能是更好的选择。无论采取何种方法,防御这种类型的攻击应当是系统管理员的优先事项。防御团队还应在适用的端点设置监控,以提高对正在发生的攻击的意识。
针对账户锁定策略,密码喷射已成为攻击者常用的技术。传统的暴力破解尝试会针对少数账户尝试许多不同的密码,而密码喷射则会针对许多不同的账户尝试少数常见的密码:这可以识别出所有使用相同弱密码的账户。即使这些账户没有访问目标资源的权限,它们也可以作为跳板,进入环境以攻击其他系统。这是渗透测试者常用的好方法,可以展示越来越常见的现实世界攻击,同时衡量目标组织的检测和响应能力。
Hydra(黑客之选,THC)是一个非常有用的密码猜测工具。你可以在 github.com/vanhauser-thc/thc-hydra/ 或 www.thc.org/thc-hydra/ 找到它。
最佳实践:管理证书
管理证书用于编程式地管理经典的基于 ASM 的资源。在 ARM(Azure 资源管理器)中,这是部署 Azure 资源的推荐方式,服务主体取代了管理证书。与管理证书相比,服务主体提供了许多优势——最显著的是能够指定细粒度的权限,从而减少被攻破的账户可能带来的损害。在可能的情况下,放弃管理证书,使用服务主体是更合理的选择。
然而,如果你必须维护现有服务的管理证书,还是有几个步骤可以采取以保护它们。这些步骤包括追踪管理证书的使用位置和所有者,安全存储证书,确保证书仅用于 Azure 管理,并在可能的情况下,逐步淘汰管理证书。
正如我之前提到的,管理管理证书的困难是它们最大的问题之一。我建议对你所有订阅中的证书进行详细的清单记录,包括证书的名称、指纹、所在订阅、以及如果可能的话,创建证书的人或使用证书的人和它们的用途。然后制定一项政策,要求所有新管理证书必须在添加前进行记录,未遵守此政策的证书将被移除。一旦建立了这个清单,定期审计以检查所有订阅中的证书列表是否有变化,并移除不再使用的证书。
此外,为了帮助追踪证书的使用,我建议为所有非自动生成的证书使用唯一的名称。你甚至可以考虑在每次审计时移除所有自动生成的证书——只要确保开发人员知道这是政策,避免他们期望这些证书会保留。
另一个问题是如何妥善保护管理证书。绝不要将证书提交到源代码管理中,因为这样会导致证书过于容易被共享。相反,应将证书像其他凭据一样对待,并将其存放在安全的位置。即便是临时存储私钥在安全性不当的工作站或硬盘中也是不可取的。此外,务必为包含管理证书私钥的.pfx文件设置强密码。
另一个常见的错误是将证书用于多个目的,比如使用相同的 SSL/TLS 证书既来保护网站流量,又用来管理托管该网站的订阅。不要这样做!以这种方式重复使用证书不仅容易引起混淆,还意味着如果某个证书在一个地方被泄露,所有使用该证书的系统都会受到影响。Azure 管理证书不需要是复杂、昂贵、被公开信任的证书;一个免费的自签名证书就足够了。
如果可能的话,私钥或密钥对应该在最终使用私钥的系统上生成。如果管理员经常在自己的工作站上为生产系统生成密钥对,那么这些私钥就不必要地暴露在单一系统上,从而使该系统成为一个高价值的攻击目标。
查找管理证书
回顾本章之前的内容,除了通过用户名和密码进行用户认证外,ASM 还支持使用证书。在本节中,我们将探讨如何使用证书访问发布设置文件中的管理证书、证书存储、配置文件和云服务包文件。
请记住,Azure 使用的是非对称 X.509 证书,这意味着每个证书都有公钥和私钥。获取证书的私钥部分非常重要,因为这是进行认证所需的组件。
虽然证书可以有多种文件扩展名(当证书没有嵌入其他文件中时,如下一节所述),但在 Windows 上最常见的两个扩展名是.pfx和.cer。通常,.cer 文件仅包含公钥,而 .pfx 文件还包含私钥。因此,攻击者通常会在目标机器的文件系统中搜索**.pfx*文件。
如果你发现一个.pfx文件被密码保护,可以查看同一目录下的文本文件。用户经常将密码保存在与证书本身位于同一目录中的纯文本文件中!
发布设置文件
发布设置文件是 XML 格式的文档,包含有关 Azure 订阅的详细信息,包括订阅的名称、ID,最重要的是一个 base64 编码的管理证书。这些文件通常可以通过它们那不太简洁的扩展名.publishsettings来识别。
发布设置文件旨在简化开发人员将项目部署到 Azure 的过程。例如,在 Visual Studio 中创建一个 Azure 网站后,发布向导会接受一个发布设置文件,用于认证到 Azure 并将解决方案推送到云端。由于这些文件是从 Azure 管理门户下载的,并且通常在 Visual Studio 中使用,因此它们通常可以在用户的下载目录中找到,或者与 Visual Studio 项目文件一起保存。
一旦你拥有发布设置文件,打开它并用文本编辑器查看,复制ManagementCertificate部分中引号之间的所有内容,将其粘贴到一个新文档中,并保存为.pfx扩展名的文件。请注意,这个.pfx文件没有密码,所以如果在使用时提示输入密码,只需点击“下一步”或“确定”即可。
重用证书
重用证书是管理证书的另一个意外来源。一些 IT 专业人员认为证书制作成本高或难以创建,因此他们会在各个地方重复使用相同的证书。(虽然用于面向公众网站的证书应来自受信任的公共证书颁发机构,并且可能需要付费,但自签名证书对于 Azure 管理来说完全足够——而且它们是免费的。)因此,你可能会发现用于公司网站的 SSL/TLS 证书的私钥也被用于公司的 Azure 订阅。
攻击者不能仅通过访问网站来获取网站证书的私钥;相反,必须先入侵 Web 服务器,并且必须破坏证书存储。一旦实现这一点,攻击者需要从服务器中提取证书。遗憾的是,对于渗透测试人员来说,大多数服务器将其证书标记为“不可导出”,这会防止证书被直接复制;然而,Mimikatz 可以提取受保护的证书。
要从服务器提取证书,请从管理员命令提示符运行 Mimikatz,然后执行以下命令:
mimikatz # crypto::capi
mimikatz # privilege::debug
mimikatz # crypto::cng
mimikatz # crypto::certificates /systemstore:local_machine /store:my /export
前三个命令授予 Mimikatz 访问证书的权限。最后一个命令从本地计算机存储的个人证书文件夹中导出所有证书,并将其保存为当前工作目录中的.pfx和.cer文件。(有关其他可能的store和systemstore值的名称,请参见github.com/gentilkiwi/mimikatz/wiki/module-~-crypto/。)
配置文件
管理证书通常用于部署服务,或者在服务运行在 Azure 中后,供应用程序与资源交互。尽管发布设置文件负责服务部署,配置文件则可供连接到 Azure 服务的应用程序使用。配置文件 通常具有 .config 扩展名,且最常见的名称是 app.config(用于应用程序)或 web.config(用于 Web 服务)。配置文件的作用是将服务的详细信息从应用程序的代码中提取出来,并保存在一个用户可编辑的 XML 文件中。这样,如果服务移动或重命名,应用程序就不需要重新编译。例如,应用程序中无需硬编码 SQL 服务器的名称和连接信息,而是可以将这些信息以 XML 格式保存。由于开发人员在这些配置文件中包含了服务器地址和未加密的凭证,这种做法从安全角度来看存在缺陷。
最常见的凭证是用于 Azure SQL 数据库的连接字符串,其中包括明文的用户名和密码。其次常见的是用于与 Azure 存储账户交互的访问密钥,因为应用程序通常需要读取/写入存储中的数据。(我们将在第四章中详细介绍 Azure 存储。)
不太常见的是我们正在寻找的凭证类型:一个 base64 编码的管理证书。由于开发人员可以为配置文件中的变量使用任何名称,管理证书不会总是显而易见,但它们有一些特征,足以让我们识别。它们通常是配置文件中最长的字符串(稍超过 3000 个字符),以大写字母 M 开头,通常以一个或两个等号结尾,并且只包含 base64 字符(A–Z, a–z, 0–9, +, / 和 =)。
找到证书后,将其从文件中复制出来,并保存为 .pfx 扩展名。因为证书也可以用于与 Azure 无关的目的,所以可以通过查看配置文件中的订阅 ID 来判断。如果你找到了订阅 ID,那么该证书几乎肯定是用于 Azure 管理的,你至少知道一个证书应该有效的订阅。
云服务包
当开发人员创建一个应用程序并部署到 Azure 时,Visual Studio 会将整个部署打包成一个 云服务包 (.cspkg) 文件。这些文件实际上就是 ZIP 文件,包含特定的元素,包括已编译的代码、配置文件、清单和依赖项。尽管这些文件中有些会有不常见的扩展名,但几乎每个文件都将是一个 ZIP 文件、XML 文件、纯文本文件或已编译的二进制文件。
每当你遇到云服务包时,审查其内容,并尝试在你喜欢的文本编辑器和文件压缩工具中打开嵌套的文件。由于 Azure 中的服务通常会调用其他 Azure 服务(例如,一个从 Azure 存储和 Azure SQL 获取内容的 Azure 网站),你有时会发现管理证书或其他凭证嵌入在.cspkg文件中。
最佳实践:保护特权账户
特权账户需要得到严格保护,以防止攻击者控制其管理的系统。实现这一目标的有效方法包括使用独立的凭证、凭证保管、特权访问工作站和及时管理。
保护这些凭证最重要的步骤是将其与正常的业务任务(如查看电子邮件和浏览网页)分开。与其为用户的标准账户授予敏感系统的管理权限(或在 Azure 中授予类似 Owner 的高级角色),不如为用户创建一个专门用于服务管理的账户。此外,确保该账户要求强身份验证,即强密码并启用多因素身份验证——或者更好的是,基于智能卡的身份验证。如果该账户使用密码,考虑要求使用安全的密码管理器或保管库,确保密码长度适当,定期更改,并且可审计。
即使实施了这些保护措施,如果在同一台系统上使用该账户进行网页浏览或打开标准账户中的文档,该账户仍然可能被攻破。相反,使用特权访问工作站(PAW)是减少敏感账户暴露的一个好方法,重点保护管理员使用的客户端。PAW 是一个专用的、经过硬化的工作站,管理员通过该工作站访问高价值系统,并且使用的是在其他系统上不使用的账户。
PAW 应该仅能通过特权账户访问;用户不应是本地管理员。此外,PAW 应强制执行预定义的软件和网站白名单,以便只能访问已批准的应用和网站(例如,Azure 门户)。你可以在docs.microsoft.com/en-us/windows-server/identity/securing-privileged-access/privileged-access-workstations/了解更多关于 PAW 的信息。
为了进一步减少这些账户被攻破的风险,可以考虑使用 即时(JIT)管理 或 最小权限管理(JEA)。使用 JIT 时,账户只有在用户需要执行管理任务时才会出现在高度特权的角色中。同样,使用 JEA 时,会仔细审查每个管理员的确切权限和责任,并仅授予执行工作所需的最小权限。Azure 通过使用特权身份管理(PIM)功能来支持 JIT。有关如何配置的更多信息,请参见 docs.microsoft.com/en-us/azure/active-directory/active-directory-privileged-identity-management-configure/。
遇到双重身份验证
为了增加防止凭证被窃取的安全性,一些公司采用 双重身份验证(2FA),有时也称为 多重身份验证(MFA)。在登录时,用户不仅需要提供他们知道的东西(密码),还需要提供他们拥有的某种东西的证明(例如手机或智能卡)或他们本人的某种东西(生物识别验证)。
Azure 本身支持双重身份验证,管理员可以通过在 图 2-2 中显示的设置启用此功能,该设置可以在经典门户中找到,方法是选择 Active Directory 服务,点击 多重身份验证提供程序,然后点击 管理。

图 2-2:Azure 多重身份验证设置
如果启用了 MFA,在使用用户名和密码进行身份验证时,通常会遇到要求提供第二个身份验证因素的提示——通常是以下之一:
-
从用户注册的手机发送的短信验证码
-
来自一次性验证码生成应用(如 Microsoft Authenticator)的验证码
-
用户的智能卡及其关联的个人身份号码(PIN)
-
从已注册的移动应用接收来自用户智能手机的通知确认
-
电话呼叫,可能提供一个验证码或请求确认或 PIN 码
假设你没有用户的移动设备,这可能是一个需要克服的重大障碍。幸运的是,有几种方法可以绕过这个障碍。
使用证书身份验证
避免 2FA 的一种简单方法是使用管理证书而不是用户名和密码进行 Azure 身份验证。由于证书身份验证通常用于自动化,因此在没有用户输入令牌的情况下,证书通常不需要进行 2FA。尽管这可能是一个很好的选择,但证书仅限于 ASM 访问,因此你可能需要采用不同的绕过方法来访问 ARM 资源。
使用服务主体或服务账户
另一种尝试绕过 MFA 的方法是获取具有访问目标订阅权限的服务账户的凭证。服务账户通常是由服务用于在 Azure 中以编程方式完成操作,或者由公司中的一组人共享使用。无论是哪种情况,2FA 都不太可能被使用,因为服务没有手机,且群体共享 2FA 令牌也很困难。这意味着服务账户通常可以免除使用第二因素认证。
访问 Cookies
在 Azure 的多重身份验证设置页面底部,注意到图 2-2 中有一个选项,允许用户将设备标记为可信设备,持续一段时间。这个选项是为了缓解一个常见的关于双因素身份验证的抱怨:输入代码或插入智能卡非常繁琐,特别是在用户频繁登录的系统上。启用此设置后,用户可以在身份验证过程中勾选一个框,停止系统在一段时间内重复要求凭证或 2FA 令牌。此功能通过在用户的网页浏览器中保存带有令牌的 Cookie 来实现,前提是用户已经通过 2FA 成功认证。令牌是一个长且加密的字符串,持有该 Cookie 的用户可以立即访问 Azure。请注意,这种方法并非 Azure 独有,许多网站都采用了类似的方式。
由于 Cookie 存储通常并不是特别安全,渗透测试人员需要做的就是获得用户的工作站访问权限,复制 Cookie,然后将其放入自己系统的浏览器中。通常,这些令牌在不同主机上不会被阻止使用,因此一旦被获取,它们可以在任何地方使用。
获取 Cookie 的方法取决于目标用户选择的网页浏览器以及渗透测试人员对工作站的访问权限。如果渗透测试人员能够在用户的安全上下文中运行代码,导出 Cookie 可以像使用合适的后渗透框架一样简单。别忘了检查用户是否安装了 Cookie 管理器——就像真正的攻击者一样,你可能会发现所有你需要的工具已经安装好了。一些浏览器还会在文件系统中不加密地存储 Cookie,使得它们更容易被获取。
DEFENDER’S TIP
许多网站依赖包含加密令牌的 cookie 来验证用户在身份验证后(以及完成 2FA 验证时,如适用)发送的请求。如果没有这些,用户将被频繁要求重新输入凭证。由于这些 cookie 包含了作为该用户发出的请求所需的所有信息,因此不应随意留下它们。为了防止像 Azure Portal 这样的关键网站的 cookie 被窃取,用户在完成管理工作后应尽早退出,并清除他们的 cookie。(在这种情况下,我建议至少清除 microsoftonline.com 和 azure.com 域名的 cookie。)另外,大多数浏览器的“隐私”模式也可以使用,因为它们确保这些 cookie 在浏览器关闭后不会持续存在。
通过用户浏览器代理流量
使用 cookie 的替代方法是通过目标用户的网页浏览器转发 Web 请求,以便这些请求使用用户的会话令牌,并显示为来自他们的计算机。这个方法的操作可能会很复杂:在用户的系统上,您需要运行一个隐蔽的恶意应用程序,该应用程序能够监听来自您系统的请求,通过用户的浏览器转发这些请求,然后获取响应并将其返回给您。幸运的是,这个特定的场景已经集成到 Cobalt Strike 中,这是一款黑客命令与控制工具。
要创建代理,您需要运行一个 Cobalt Strike 服务器,并且将 Cobalt Strike 负载包(称为 Beacon)部署到用户的系统中。从这里,使用 Browser Pivot 命令来创建代理。
现在,代理正在运行,将您的浏览器设置为使用目标系统作为代理服务器。此时,来自您系统的 Web 请求将通过目标用户的浏览器转发(对用户完全不可见)。您的流量将继承用户的会话和凭证,绕过任何提示。使用这种方法可以向组织证明,工作站上的安全问题可能导致云资源的泄露。
注意
您可以在此场景中找到更多详细信息,详见 blog.cobaltstrike.com/2013/09/26/browser-pivoting-get-past-two-factor-auth/。有关 Cobalt Strike 特定的说明,请参见 cobaltstrike.com/help-browser-pivoting。
防御者提示
浏览器代理攻击表明,保护重要服务的需求不仅限于运行它们的系统,而是扩展到整个环境,包括工程师的凭证和工作站。一旦攻击者进入用户的工作站,他们的活动可能很难被检测到,因为网络流量看起来是来自用户的正常计算机。然而,你可能能够检测到将请求和响应从工作站转发到攻击者系统的指挥与控制(C2)回传流量。对于 Web 流量代理攻击,这种流量通常会比正常的 C2 网络活动更大且更频繁。
使用智能卡
双重身份验证(2FA)的核心理念是,用户在认证过程中提供两项信息来证明自己的身份。第一项通常是密码——用户知道的东西。第二项要么验证“用户拥有的东西”(例如手机),要么验证“用户的身份特征”(例如指纹)。尽管最常见的第二因素是通过身份验证应用或短信验证登录者拥有正确的手机,但这并不是唯一的选择。一些组织使用智能卡(内嵌加密芯片的实体卡)来确认用户的身份。因此,如果使用智能卡,那么获取一张智能卡是绕过 2FA 的一个可能方法。有两种方法可以获取用户的智能卡。第一种是控制智能卡当前插入的系统,并从该系统使用它;第二种是物理获取用户的卡片。这两种方法各有其挑战。
如果你已经控制了目标系统,可以利用插入在不同系统中的智能卡。只需使用前一部分讨论的方法通过该主机传递请求即可。困难之处在于,你不仅需要访问目标用户的系统,还必须在用户插入智能卡并且已经输入 PIN 码(即 PIN 码已缓存)后进行请求。
当你窃取用户的物理智能卡时,主要的挑战实际上是如何获取卡片、避免被发现以及确定用户的 PIN 码。为了克服第一个挑战,你必须找到一种方法靠近用户并在他们没有注意到的情况下拿走他们的智能卡。这就引出了第二个问题:大多数用户会注意到他们的卡片不见了,特别是当他们依赖该卡登录计算机时。一些公司的智能卡还兼作员工徽章,并控制进出建筑物的权限,这种情况下,用户更有可能意识到发生了什么,并报告丢失事件。
另一个挑战是智能卡通常需要与之关联的 PIN 才能解锁并用于身份验证。您可以尝试猜测 PIN(例如,使用常见的数字模式或用户的生日),但智能卡可能会在指定的错误 PIN 尝试次数后锁定。更好的方法是直接获取用户的 PIN,例如通过在用户的系统上安装键盘记录器(无论是物理设备还是偷偷安装的应用程序)来尝试捕捉他们输入的 PIN。然而,通常更有效的方法是当智能卡正在使用时,从用户计算机的内存中获取 PIN。
Mimikatz 可以从内存中获取智能卡的 PIN,只要用户已登录,智能卡已插入系统,并且用户已经使用智能卡登录。如果满足这些条件,PIN 将出现在 Mimikatz 的输出中。
防御者提示
为了确保智能卡的安全,重要的是将发放智能卡证书的过程与其他基础设施隔离开来。此外,由于通常有许多不同的模板可供选择,且具有不同的敏感级别(例如虚拟智能卡、VPN 证书等),请确保适当地限制哪些模板可以用于满足您的 2FA 要求。对证书操作进行全面的审计、监控和警报。
此外,您必须确保用于连接敏感服务器的系统安全性,例如那些发放智能卡的服务器。在第 26 页的“最佳实践:保护特权账户”中讨论过的使用 PAW 是一种很好的方法,因为 PAW 不用于电子邮件或网页浏览,因此比管理员的主系统更不容易被攻击。
偷窃手机或电话号码
这可能是所有 2FA 绕过选项中最难的(也是在标准交战规则下最不可能被允许的),但如果您成功了,它的成功率很高。就像智能卡绕过一样,我们再次获得了某种提供身份验证第二因素的东西,只不过这次是用户的手机或控制他们手机号码的权限。
最直接的方法是简单地偷走目标用户的手机。如果 Azure 订阅支持使用短信进行身份验证,那就理想了。因为许多手机操作系统会将短信的第一行作为通知显示在锁屏上,您很可能在不解锁手机的情况下就能获得短信中的 2FA 验证码。当使用身份验证器应用生成的代码时,您需要某种方式猜测或获取手机的解锁码(如果设置了的话)。(这超出了本书的范围。)
另一个选项是获取用户的电话号码并通过短信认证选项进行身份验证。尽管大多数人认为手机及其号码是一个整体,但实际上,手机和号码是松散耦合的。最近的一些报告中,犯罪分子能够假冒客户进入当地手机商店并说服商店为他们提供手机升级(将新手机的账单计入真实客户账户)。因为 Azure 渗透测试员的目标并不是窃取最新的智能手机,另一种策略是告诉店员你更换了手机并需要一张新的用户身份识别模块(SIM)卡。离开商店后,只需将卡插入你的手机并进行认证。
该选项需要使用短信或电话认证,因为即使使用安装有用户电话号码的 SIM 卡,认证应用程序也无法与 2FA 后端注册。这通常需要一个带有额外验证的带外设置过程,以确认执行注册的用户确实是他们所声称的人。
注意
除了可能被视为盗窃并潜在地违反电话提供商的服务条款外,这种做法非常危险。一旦为该用户账户发放了新手机或 SIM 卡,他们的现有号码将被转移至新卡,而用户原来的手机将被停用。大多数用户会在手机无法使用服务时迅速发现这一点,因此一旦盗窃发生,报告事件的时间极其有限。换句话说,你很可能会很快被抓住并从目标订阅中移除。将此选项作为最后手段,并在尝试之前务必咨询你的客户和律师!
提示用户进行 2FA 认证
最后,可能通过社会工程学手段诱使用户放弃他们的 2FA 令牌,这一过程就是说服用户做出他们通常不会做的事情。这个方法可能是最不可能成功的,因为它依赖于用户没有察觉到异常,因此只有在绝望时才使用。如果用户在手机上设置了需要确认的弹出提醒,那么简单的做法可能就是触发认证请求并观察用户是否接受。虽然不太可能,但有些用户已经习惯于确认提示,即使他们并未预料到出现此类提示。当然,一个聪明的用户可能会将此事件报告给他们的安全团队。
这种方法的一个稍微高级的变体是尝试观察用户的活动,并在他们预期会看到此提示时发送消息。也许你怀疑这个用户总是在上班时登录 Azure 门户,你可以将提示的时机与此同步。或者,可能你注意到他们在咖啡店工作,并能看到他们何时登录,然后在这个时候发送请求。许多用户可能会认为他们的初始授权没有通过,系统可能只是再次提示他们。
如果用户依赖于从短信或身份验证器应用程序中输入代码,仍然有可能获得该代码。实现这一点的两种常见方式是通过钓鱼网站和电话。
为了演示攻击者如何通过钓鱼获取 2FA 代码,你首先需要按照我们在第 19 页中“钓鱼”部分的方式设置一个页面。接下来,你需要修改该网页,使其在提示输入用户名和密码后,要求输入用户的 2FA 代码。由于时间至关重要,你需要设计该页面,使得一旦这些信息提交后,网站会调用你机器上的脚本进行 Azure 身份验证,从而为你提供访问权限。如前面的示例所示,页面应将用户重定向到真实的登录页面,以便他们认为身份验证出现了问题。一旦网站功能正常,你可以像之前一样通过电子邮件发送链接给用户。
获取用户代码的另一种方式是给他们打电话并索要。为了使这种方法有效,你需要使用借口,即编造一个听起来合理的电话理由。例如,你可以声称自己是他们 IT 部门的工作人员,因用户数据库中出现数据损坏问题,你需要他们当前的代码来重新启用访问权限。这种方法可能和让你被举报一样有可能获得有效的代码,但它可以作为最后的手段使用。
防御者提示
尽管本节中描述的多因素身份验证存在一些弱点,但它仍然是最有效的方式之一,可以延缓或防止攻击者访问订阅。它大大增加了攻击者进行攻击的时间,尤其是当目标订阅的管理证书和服务账户较少时。鉴于 Azure 内置了多因素支持,启用起来相对容易。要开始使用,请访问 azure.microsoft.com/en-us/documentation/articles/multi-factor-authentication/。
总结
在这一章中,我们讨论了两种不同的 Azure 模式——Azure 服务管理和 Azure 资源管理——以及每种模式可能如何影响渗透测试。我演示了获取 Azure 凭据的多种方法,包括从纯文本文档中恢复密码、钓鱼攻击、利用内存,甚至猜测。接着,我们探讨了使用证书进行身份验证以及它们可能存在的位置,比如发布设置文件、证书存储中的回收证书、配置文件和云服务包。最后,我们检查了通过证书、服务账户、被盗的 cookies、被盗的电话号码和社会工程学绕过双因素认证的方法。
通过研究这些访问方法,我们识别了用户可能遗留下来的不再使用的旧凭据。清理这些项目可以减少客户订阅的攻击面。此外,测试账户的弱密码可以帮助在攻击者发现之前找到易受攻击的凭据,同时也可以帮助用户了解如何正确构建密码,前提是客户还没有为除主要用户账户以外的所有账户使用高熵(高度随机、不可预测)的计算机生成密码。最后,我们看到,当所有账户都一致使用多因素认证时,非法访问订阅变得更加困难。
在下一章中,你将探讨你在参与过程中所妥协的订阅,并对其中运行的服务进行高层次的了解。
第三章:侦察

在本章中,我将展示如何搜索订阅中的有用数据,如使用的存储账户、SQL 数据库、虚拟机以及任何网络防火墙。
像其他大型云服务提供商一样,Azure 提供了越来越多的服务,涵盖从网站托管到数据库、密钥存储和机器学习等内容。由于服务种类繁多,很难确定特定客户正在使用哪些服务和功能,以及这些服务是否配置存在漏洞。
在本章中,我将演示如何使用 Azure 的 PowerShell cmdlet 和命令行工具快速检查订阅的内容。我们从在控制台中进行 Azure 身份验证开始。接下来,我们列举订阅的 web 服务,然后列出其虚拟机。然后,我们获取订阅的存储账户及其访问密钥,接着查看任何面向互联网的网络端口和防火墙。最后,我们查看 SQL 服务器和数据库。
通过列举这些服务,你将能够将所有客户的资源纳入渗透测试,确保没有遗漏任何内容。这一点非常重要,因为在请求评估时,客户可能会关注生产服务,却忘记提到测试资源,而这些资源的安全控制可能较为薄弱。同样,记录存储账户的内容有助于客户判断是否遵循了正确的数据分类和存储规范。
在回顾了几个常用 Azure 服务的强大命令后,我将展示一些理想的脚本,用于扫描你所渗透的任何新订阅。
安装 PowerShell 和 Azure PowerShell 模块
在开始之前,你需要从 Microsoft 安装一些免费的工具。在 Windows 上,PowerShell 和 Azure PowerShell 模块是收集订阅信息的最直接工具。另一个选择是 Azure 命令行界面(CLI)工具,它适用于 Windows、Linux 和 macOS。
在 Windows 上
你可以通过两种方式在 Windows 上安装这些工具。如果你想同时拥有 PowerShell cmdlet 和命令行界面,并能够在发布新版本时更新这些工具,可以使用 Microsoft Web Platform Installer (WebPI)。这个小型包管理器让你可以轻松安装多个 Microsoft 工具,包括用于管理 Azure 的工具。WebPI 还会检查是否缺少依赖项,如果你尚未安装 PowerShell,它会自动为你处理。
要使用 WebPI,只需从 www.microsoft.com/web/downloads/platform.aspx 下载安装程序并运行。一旦安装完成,搜索“Web Platform Installer”并启动应用程序。
你可以使用 WebPI 的搜索框来查找 Microsoft Azure PowerShell 和 Microsoft Azure 跨平台命令行工具(参见 图 3-1)。然后点击 添加 来下载并安装这些工具。如果返回了多个版本的工具,请选择最新发布的版本。(你可以再次启动 WebPI 来检查软件包的更新情况。)
安装完工具后,关闭任何打开的 PowerShell 和命令行窗口,以确保工具被正确识别。
在 Linux 或 macOS 上
如果你使用的是 Linux 或 macOS,你需要安装 Azure 命令行跨平台工具包。这个工具包有两个版本——一个是用 Node.js 编写的,另一个是用 Python 编写的。在我的示例中,我使用的是 Node.js 版本,但两个版本的语法类似,所以你可以任选其一。你可以在 github.com/azure/azure-xplat-cli/ 上找到适用于 macOS 的 DMG 格式和适用于 Linux 的 TAR 格式的 Node.js 版本安装包。Python 版本可以从 github.com/azure/azure-cli/ 下载。你可以像安装其他任何软件包一样安装它们。

图 3-1:使用微软的 Web 平台安装程序查找和安装 Azure 工具
运行你的工具
安装完工具后,启动它们。对于 PowerShell 模块,打开一个 PowerShell 窗口,并在提示符下运行 Import-Module Azure。对于命令行工具,打开一个终端窗口并输入 azure(如果使用 Python 版本,则输入 az)。如果命令行工具安装正确,你应该会看到像 图 3-2 中所示的帮助信息。

图 3-2:Azure 命令行工具的帮助信息
到这时,你应该已经拥有了开始连接到 Azure 所需的一切。让我们开始收集关于目标订阅及其服务的信息吧。
服务模型
回顾 第二章,微软在 Azure 中使用了两种不同的服务模型,每种模型都有自己的一组命令来查看或更改服务。在本章讨论的每个服务中,我都会提供查询 Azure 资源管理器(ARM)和 Azure 服务管理(ASM)两种模型的语法,除非某个服务仅适用于某一个模型。
PowerShell 模块包含了 ARM 和 ASM 的 cmdlet。为了保持组织性,ASM 服务的命令通常命名为 Verb-AzureNoun,例如 Get-AzureVM,而 ARM 命令则命名为 Verb-AzureRmNoun,例如 Get-AzureRmVM。
命令行工具采用不同的方法。你可以将 azure 可执行文件置于 ARM 或 ASM 模式,之后它将保持在该模式,直到你切换模式。
要确定当前选择的模式,请查看运行 azure 时输出的最后一行。要切换模式,请运行 azure config mode asm 来切换到 ASM 模型,或运行 azure config mode arm 来切换到 ARM 模型。示例 3-1 显示了 Azure CLI 切换模式时的输出,以及确认当前模式的 Azure 命令的最后一行。
C:\>azure config mode asm
info: Executing command config mode
info: New mode is asm
info: config mode command OK
C:\>azure
--snip--
help: Current Mode: asm (Azure Service Management)
C:\>azure config mode arm
info: Executing command config mode
info: New mode is arm
info: config mode command OK
C:\>azure
--snip--
help: Current Mode: arm (Azure Resource Management)
示例 3-1:在 Azure CLI 中切换和验证模式
最佳实践:PowerShell 安全性
自 2006 年正式发布以来,PowerShell 在流行度、功能和成熟度方面不断增长。最初作为一种脚本语言,用于执行基本的 Windows 管理,PowerShell 现在是管理各种 Microsoft 产品和服务的事实标准方法,当然也包括 Azure。由于它提供了许多功能,PowerShell 也成为了黑客的目标。作为系统管理员或防御者,您需要了解一些设置,以确保 PowerShell 在您的系统中保持安全。正如我们已经看到的,受损的工作站可能导致 Azure 订阅访问,因此保护端点非常重要!
首先,启用 PowerShell 日志记录,并确保将这些数据转发到您的安全审计解决方案。这不仅会提高检测攻击者在您的环境中利用 PowerShell 的速度,还能让防御者清楚地了解攻击者采取了哪些行动。转发事件还可以使攻击者更难篡改事件日志。
注意事项
微软的 Lee Holmes 发表了一篇优秀的文章,介绍了 PowerShell 团队如何将蓝队功能集成到 PowerShell 中。您可以在 blogs.msdn.microsoft.com/powershell/2015/06/09/powershell-the-blue-team/.
其次,请注意 PowerShell 支持远程会话和远程命令执行,使用 WS-Management 协议通过 TCP 端口 5985 和 5986。此外,由于 PowerShell 已被移植到 Linux,现在还可以通过 SSH(TCP 端口 22)执行远程 PowerShell 命令。PowerShell 远程通常在 Windows Server 安装中默认启用,但在工作站上默认禁用。所有形式的 PowerShell 远程都需要身份验证,通常需要一个属于管理员组的帐户才能连接。尽管远程 PowerShell 可以简化对大量远程系统的管理,但如果管理员帐户没有得到充分保护,或者远程权限设置得过于宽泛,也可能导致非法访问。有关 PowerShell 远程安全性的讨论,请参阅 docs.microsoft.com/en-us/powershell/scripting/setup/winrmsecurity/。
最后,考虑使用 PowerShell 安全功能,如受限语言模式。启用后,受限语言模式大大降低了在 PowerShell 中任意执行某些强大操作的能力,同时不会影响执行正确签名的脚本。这样,如果攻击者确实获得了系统上的 PowerShell 会话访问权限,他们将无法使用许多他们想要运行的工具或脚本。关于受限语言模式的一个很好的介绍可以通过 blogs.msdn.microsoft.com/powershell/2017/11/02/powershell-constrained-language-mode/ 获得。
使用 PowerShell 模块和 CLI 进行身份验证
要收集有关 Azure 中任何服务的详细信息,首先需要进行身份验证。身份验证过程因凭据类型(用户名和密码、服务主体或管理证书)、服务模型和所使用的工具(Azure CLI 或 PowerShell)而异。表 3-1 显示了每种凭据类型下,可以使用哪些服务模型/工具组合进行身份验证。请注意,并不是所有这些选项的组合都是可能的。
表 3-1: 按服务模型和工具支持的认证方法
| 工具/接口 | 用户名和密码 | 管理证书 | 带密码的服务主体 | 带证书的服务主体 |
|---|---|---|---|---|
| Azure CLI – ASM 模式 | 支持 | 部分支持 | 不支持 | 不支持 |
| Azure CLI – ARM 模式 | 支持 | 不支持 | 支持 | 支持 |
| Azure PowerShell ASM cmdlets | 支持 | 支持 | 不支持 | 不支持 |
| Azure PowerShell ARM cmdlets | 支持 | 不支持 | 支持 | 支持 |
portal.azure.com/ |
支持 | 不支持 | 不支持 | 不支持 |
manage.windowsazure.com/ |
支持 | 不支持 | 不支持 | 不支持 |
如你所见,用户名和密码组合被每个 Azure 管理接口接受。使用用户名和密码进行身份验证还有其他几个优点。首先,一旦完成身份验证,你可能不需要知道某个用户可以访问哪些订阅,因为你可以使用他们的密码登录到任一 Azure Web 接口,以查看他们的订阅列表。相比之下,命令行接口在执行命令时需要你指定目标订阅。
用户名和密码比管理证书和服务主体更容易使用。每个工具都会显示一个登录提示,接受密码。如果用户没有启用多因素身份验证,那就可以顺利进行。使用管理证书或服务主体进行身份验证可能需要一系列命令。让我们看看如何使用它们进行身份验证。
使用管理证书进行身份验证
在使用管理证书进行身份验证时,你需要知道计划要针对的订阅 ID。正如你在第一章中的范围讨论中所知道的,这不应该是一个问题。
当然,为了成功进行身份验证,你的证书需要在目标订阅的管理证书列表中。确定给定证书可以使用的最佳方法是通过有根据的猜测和反复试验。换句话说,如果一个证书来自拥有某个订阅的开发者机器,或者证书被提交到一个你知道在目标订阅中运行的服务的代码库中,那么它很有可能会有效。幸运的是,尝试一个证书并发现它无效并不会带来什么负面影响。尽管失败的连接尝试可能会被记录到某个地方,但我还没有遇到过这样的日志,实际上,订阅所有者也从未检测到我因为尝试错误的证书而试图突破他们的订阅。
安装证书
要使用证书,首先需要将其安装到计算机的证书存储区。为此,双击证书文件并按照向导完成操作。证书的位置无关紧要,但如果你选择将其放入本地计算机存储区,则需要以管理员权限(用户帐户控制提升)运行后续命令。
身份验证
列表 3-2 中显示的 PowerShell 脚本使用证书对订阅进行身份验证。这允许你使用此证书作为凭据对订阅执行后续命令。
➊ PS C:\> $storeName = "My"
➋ PS C:\> $storeLocation = "LocalMachine"
➌ PS C:\> $certs = Get-ChildItem Cert:\$storeLocation\$storeName
➍ PS C:\> $certs
Thumbprint Subject
---------- -------
8D94450FB8C24B89BA04E917588766C61F1981D3 CN=AzureCert
➎ PS C:\> $ azureCert = Get-Item Cert:\$storeLocation\$storeName\
8D94450FB8C24B89BA04E917588766C61F1981D3
➏ PS C:\> $azureCert
Thumbprint Subject
---------- -------
8D94450FB8C24B89BA04E917588766C61F1981D3 CN=AzureCert
➐ PS C:\> $azureCert.HasPrivateKey
True
➑ PS C:\> Set-AzureSubscription -SubscriptionName 'Target' -SubscriptionId
Subscription_ID -Certificate $azureCert
PS C:\> Select-AzureSubscription -SubscriptionName 'Target'
➒ PS C:\> Get-AzureAccount
Id Type Subscriptions
-- ---- -------------
8D94450FB8C24B89BA04E91758... Certificate Subscription_IDs
列表 3-2:使用 PowerShell 中的管理证书对 Azure 进行身份验证
以下是列表 3-2 中逐步发生的情况:
-
要使用管理证书进行身份验证,我们需要从证书存储区中检索它。我们首先指定证书安装在个人目录(我的)➊中,位于
LocalMachine存储区➋(而不是CurrentUser存储区)。如果你将其安装在其他位置,请务必使用该位置的编程名称,你可以在微软网站上找到该位置的相关信息,网址是msdn.microsoft.com/en-us/library/windows/desktop/aa388136(v=vs.85).aspx。 -
然后,我们请求该位置的证书列表,并将其放入变量
$certs➌。 -
要查看可用证书的列表,我们执行该变量作为命令 ➍。输出会告诉我们唯一安装的证书是 AzureCert,并列出证书的 指纹(“8D9 . . . 1D3”)。指纹唯一标识一个证书。
-
接下来,我们使用
Get-Itemcmdlet 获取证书对象的引用,通过指纹选择正确的证书 ➎。 -
要检查是否有可用的证书,请将证书变量名作为命令执行,以确保已检索到证书,如 ➏ 所示。如果您看到空响应,说明
Get-Item命令出了问题,您应该重新检查是否正确输入了 ➎ 中的值。 -
最后,我们检查找到的证书是否包含相关的私钥,使用
HasPrivateKey➐。没有私钥,您将无法使用该证书连接到订阅。
连接和验证访问
证书准备好使用后,尝试连接到订阅。您可以通过使用两个命令来实现:Set-AzureSubscription 后跟 Select-AzureSubscription。在前一个命令中,您需要指定订阅的名称、订阅 ID 和证书变量 ➑。如果您不知道订阅名称,可以自己编一个。因为您可能有多个订阅,所以使用 Select-AzureSubscription cmdlet 来指定 PowerShell 后续命令要针对的订阅。请注意,这里的名称必须与 set 命令中指定的名称匹配。
此时,如果证书对该订阅有效,您应该可以访问。为确认,运行 Get-AzureAccount ➒。如果订阅列出,您现在应该能够对订阅运行其他任何 Azure ASM 命令,以查看和交互其 ASM 资源。
Azure CLI 在其 ASM 模式下技术上支持管理证书,但在实际操作中未能正确加载证书。解决方法是使用 .publishsettings 文件,而不是证书。
因为 .publishsettings 文件只是嵌入了 base64 编码的管理证书和订阅 ID 的 XML 文档(如 第二章 所讨论),您可以根据证书和订阅 ID 手动创建一个。创建过程稍微复杂些;幸运的是,软件开发人员和微软 MVP Gaurav Mantri 发布了自动化该过程的示例代码: gauravmantri.com/2012/09/14/about-windows-azure-publish-settings-file-and-how-to-create-your-own-publish-settings-file/。
一旦您拥有 .publishsettings 文件,请运行以下命令将凭据添加到 Azure CLI:
C:\>azure account import "Path_to_.publishsettings_File"
接下来,运行一个命令来验证凭证是否有效,例如azure vm list。如果看到错误We don't have a valid access token,说明凭证无效。成功身份验证后,您应该看到info: vm list command OK,即使订阅中没有虚拟机。
最佳实践:服务主体
服务主体取代了管理证书,成为应用程序、脚本和服务以编程方式访问和管理 Azure 资源的首选方式。与管理证书相比,使用服务主体有多个安全优势。
服务主体的最大改进是它们能够拥有有限的权限范围。默认情况下,服务主体是为单个应用程序创建的,并可以授予它执行其功能所需的特定权限。遵循最小权限原则,测试您的应用程序实际需要哪些权限;不要仅仅授予它访问所有资源的权限,因为如果服务主体被攻破,攻击者就可以肆意破坏。
此外,服务主体可以使用长的、自动生成的密码(称为客户端密钥)或证书进行身份验证。当您使用密码创建服务主体时,客户端密钥值仅显示一次,并且在离开该页面后无法再次查看(但如果需要,可以重新生成)。因此,页面会提示您记录此值。请确保将此值存储在安全的地方,例如密钥保管库或密码管理器中。避免将其存储在源代码控制库中,因为这样会很难控制或追踪谁有权限访问以及谁查看过它,而且也很难从版本历史中移除。存储在源代码中的密钥是安全漏洞的常见来源。同样,绝对不要将这样的密钥存储在纯文本文件中,即使是暂时存储也不行。
最后,确保记录您创建的所有服务主体的目的,并定期审查具有资源访问权限的服务主体。随着应用程序的退役,容易忘记删除旧的服务主体;清理旧账户有助于减少订阅及其资源的攻击面。
使用服务主体进行身份验证
回想一下第二章,服务主体是 Azure 环境中类似于大多数公司域中的服务账户的角色。就像在本地环境中一样,当服务需要定期运行时(即独立于特定管理员账户时),这些账户就会被使用。
Azure 为这些帐户提供了两种身份验证选项:密码和证书。然而,服务主体比常规帐户或管理证书更具限制性。由于服务主体与特定应用程序绑定,它们通常只具有该应用程序需要访问的权限。此外,服务主体会检查密码是否过期或证书是否有效(取决于你使用的身份验证方法),因此被捕获的凭据不能无限期使用。
DEFENDER'S TIP
由于服务主体不能使用多因素身份验证,它们可能比标准的用户帐户更具风险,因为标准用户帐户在身份验证时使用第二个因素。尽管服务主体具有较长的自动生成密码或强大的基于证书的密钥,有助于缓解暴力破解和密码猜测攻击的风险,但为了安全起见,你应该确保服务主体仅具有执行其职能所需的最小权限。此外,最好使用多个服务主体,每个服务主体专注于执行特定任务并具有少量权限,而不是使用一个具有完全控制权限的服务主体来控制订阅中的所有内容。虽然最初的设置可能更复杂,但安全性方面的好处是值得的。
使用密码的服务主体
要作为服务主体使用密码进行连接,你需要服务主体的 GUID(通常称为客户端 ID 或应用程序 ID),其密码(在 Azure 门户中也称为 密钥)以及该服务主体定义的 Azure Active Directory 实例的租户 ID(另一个 GUID)。你很可能会在发现客户端 ID 和密码的地方找到租户 ID,因为任何使用服务主体的程序也需要此值。一旦你拥有这些值,你应该能够如下一步所述在 PowerShell 或 Azure CLI 中进行身份验证。
PowerShell
在 PowerShell 中,运行以下命令:
➊ PS C:\> $key = Get-Credential
➋ PS C:\> $tenant = Tenant_ID
➌ PS C:\> Add-AzureRmAccount -Credential $key -ServicePrincipal -TenantId $tenant
Environment : AzureCloud
Account : Service_Principal_ID
TenantId : Tenant_ID
SubscriptionId :
SubscriptionName :
CurrentStorageAccount :
Get-Credential cmdlet 应该会弹出一个对话框,供你输入用户名和密码。将应用程序 ID 值作为用户名,密钥作为密码 ➊。在下一行,将租户 ID 保存为变量 ➋,然后将这两个值传递给 Add-AzureRmAccount ➌。如果有的话,你还可以使用 Add-AzureRmAccount 的 -SubscriptionID 参数指定一个订阅,但如果服务主体没有该订阅中的任何资源权限,这将返回错误。
Azure CLI
要在 Azure CLI 中使用基于密码的服务主体进行身份验证,请确保 Azure CLI 处于 ARM 模式,然后运行以下命令:
C:\>azure login --service-principal --username "Client_ID"
--password "Key" --tenant "Tenant_ID"
该命令不会显示任何输出,因此使用 Azure 资源列表查看是否成功,并显示现有资源。如果凭据无效,它应该会显示一个错误。
注意
通常,我会将传递给各种命令的参数值用双引号括起来,例如这里的用户名和密码值。如果输入值不包含空格,这并不是必需的;然而,由于 Azure 在许多字段中允许使用空格(如服务名称),因此假设输入中有空格并用双引号括起来是更安全的做法。
使用 X.509 证书进行身份验证
服务主体也可以通过 X.509 证书进行身份验证。要在 PowerShell 中执行此操作,请运行以下命令:
➊ PS C:\> $thumbprint = Certificate_Thumbprint
➋ PS C:\> $appId = Service_Principal_ID
➌ PS C:\> $tenant = Tenant_ID
➍ PS C:\> Add-AzureRmAccount -ServicePrincipal -TenantId $tenant
-CertificateThumbprint $thumbprint -ApplicationId $appId
Environment : AzureCloud
Account : Application_ID
TenantId : Tenant_ID
SubscriptionId : Subscription_ID
SubscriptionName :
CurrentStorageAccount :
请务必指定您计划使用的证书的指纹 ➊,而不是密码,并在命令行中输入服务主体 ID(应用程序 ID) ➋,因为不会有凭据提示。在密码认证中,租户 ID ➌ 与密码认证中的相同。对于 Add-AzureRMAccount 命令,请将 -Credential 开关替换为 -CertificateThumbprint 开关 ➍。
最佳实践:订阅安全性
订阅所有者可以采取若干措施来减少订阅的攻击面,并提高他们对订阅中变化的敏感性。这包括将订阅中的高权限用户数量保持在最低限度,限制非人类账户的权限,启用审计,限制每个订阅中的服务范围,以及使用 JIT 和 Azure PIM(如在“最佳实践:保护特权账户”第 26 页中描述的)来保护剩余账户。
首先,订阅的安全性仅与其最薄弱的管理员一样强。因此,要求用户选择强密码并对所有订阅用户账户强制执行多重身份验证至关重要。限制具有订阅访问权限的用户数量还可以减少用户账户或计算机被攻破后被用于成功攻击订阅的概率。
接下来,查看具有订阅访问权限的非人类账户数量,包括管理证书、服务账户和服务主体。管理员通常对这些账户的责任感较弱,尤其是当这些账户被多个用户共享时。
此外,审计在跟踪订阅访问、识别异常和提供对订阅操作的问责方面发挥着关键作用。如果没有审计日志,防御者在发生安全事件时将很难确定入侵者是如何获得访问权限以及他们采取了哪些操作。微软提供了关于 Azure 中可用的日志类型及如何启用这些日志的详细文档,网址为 docs.microsoft.com/en-us/azure/monitoring-and-diagnostics/monitoring-overview-activity-logs/。
另一个考虑因素是订阅中运行的服务范围。一些公司倾向于仅配置少数几个订阅,并在每个订阅中放置多个工作负载,但这可能会加剧管理员过多的问题。它还可能导致创建混乱的安全权限,以限制每个人只能访问他们自己的资源(更糟的是,创建允许所有人对订阅中的所有内容都拥有自由权限的权限)。我建议为每个主要项目使用一个单独的订阅,并且为开发、预生产和生产部署使用不同的订阅。对于特别敏感的资源,例如托管关键机密的密钥保管库,将其放在单独的订阅中可能是明智的。
为了帮助进行这些更改并确保订阅随着时间的推移不会再次陷入不安全状态,微软发布了一个名为 Secure DevOps Kit 的订阅和资源安全自动化工具包。我们将在第八章中深入讨论这一内容。
最后,考虑使用 Azure PIM(特权身份管理),使账户仅在需要时才能拥有订阅的管理员权限。PIM 还允许在这些权限被使用时进行额外的审计。有关更多详情,请参见 “最佳实践:保护特权账户” 第 26 页(page 26)。
收集订阅信息
登录后,你可以开始收集关于订阅及其服务的信息。你收集的数据将帮助你确定需要深入调查的领域。收集任何订阅时,首先要获取关于订阅本身的数据,比如订阅的名称以及哪些账户可以访问该订阅。这些信息通常能够帮助你了解订阅的用途,并为你提供如何切换到其他订阅的线索。
在收集这些数据时,从列出当前选定的订阅开始。该列表应提供当前订阅的名称和订阅 ID。订阅名称通常非常具有信息性。例如,它可能包含团队或项目名称,如“人力资源 – 生产站点”或“电子商务测试环境”。此外,确认订阅 ID 是你预期的,并且它在你的评估范围内。
要在 PowerShell 中列出当前的 ASM 订阅,请运行以下命令:
PS C:\> Get-AzureSubscription -Current
SubscriptionId : d72ad5c5-835a-4908-8f79-b4f44e833760
SubscriptionName : Visitor Sign-In Production
Environment : AzureCloud
DefaultAccount : admin@burrough.com
IsDefault : True
IsCurrent : True
TenantId : 7eb504c7-c387-4fb1-940e-64f733532be2
CurrentStorageAccountName :
该命令应返回一个 PSAzureSubscription 对象,并显示订阅名称、订阅 ID、Azure Active Directory 租户 ID 以及你连接的账户。它还应显示环境,即此订阅所托管的 Azure 云类型。例如,AzureCloud 是 Azure 的默认商业版,而 AzureUSGovernment 是仅供美国政府使用的独立 Azure 实例。
注意
一些拥有独特隐私和数据法律的国家,例如德国和中国,拥有自己的云服务。你可以通过运行 Get-AzureEnvironment 命令找到云环境及其管理 URL 的列表。
要查看 PowerShell 中的 ARM 订阅的当前订阅信息,你可以运行 Get-AzureRmContext cmdlet。该命令应返回一个 PSAzureContext 对象,这是一个容器,包含 PSAzureRmAccount、PSAzureEnvironment、PSAzureSubscription 和 PSAzureTenant 对象。换句话说,它的输出应该让你深入查看你正在使用的租户、订阅和帐户的具体信息。
在上下文命令前放置一个变量名称和等号,以便其输出将保存到一个你稍后可以引用的变量中,像这样:
PS C:\> $context = Get-AzureRmContext
接下来,再次输入变量名称,后跟一个点号,再后跟你想深入查看的数据(Account、Environment、Subscription 或 Tenant),以返回该对象的所有可用信息。例如,你可以运行以下命令:
PS C:\> $context.Account
注意
记住在一个由变量表示的对象上可以使用的选项可能会有些棘手。幸运的是,PowerShell 具有自动补全功能。只需键入变量名称,后跟一个点号,然后按 TAB 键显示第一个可选项。继续按 TAB 键可以循环查看所有可能的选项。当你找到你想要的选项时,按 ENTER 键执行它。或者,你可以使用 Get-Member cmdlet 查看所有可能的值。
运行此 cmdlet 查看哪些用户具有 ARM 访问权限及其权限:
PS C:\> Get-AzureRmRoleAssignment
要查看所有可能的 ARM 角色,请运行以下命令:
PS C:\> Get-AzureRmRoleDefinition
如果你正在使用 Azure 命令行工具,请运行
C:\>azure account show
查看当前订阅。尽管 CLI 不会显示当前用户帐户,但它应该会显示订阅 ID 和名称,以及环境和租户 ID(如果可用)。它还应显示你是否通过证书连接。
你可以在 ARM 模式下使用 CLI 来显示具有访问权限的帐户:
C:\>azure role assignment list
你也可以显示所有可用的角色,如下所示:
C:\>azure role list
查看资源组
资源组是在 ARM 中添加的一种方式,用于将一组服务组合成一个包,以便于管理。例如,一个网站可能包括网页本身、用于存储用户资料的 SQL 数据库,以及一个 Application Insights 实例(应用程序的遥测服务)。在 ASM 中,每个项目都是单独管理的,通常很难判断哪些服务是相关的。资源组允许你监控所有相关服务,查看给定部署的运行成本,批量分配权限给组中的所有服务,甚至在一个地方删除组中的所有内容。(资源组还通过帮助你理解这些关系并评估给定服务的重要性,为侦察提供了一个起点。)
然而,资源组存在两个挑战。第一个是一些开发人员可能不理解如何使用资源组,干脆为每个服务创建一个新的组,即使是相关的服务。由于资源组只是管理上的便利,而非安全边界,因此没有任何措施阻止不同组中的服务相互交互。
第二,当你调查某个服务时,ARM PowerShell cmdlet 通常会要求提供资源组作为必需参数,Azure CLI 在 ARM 模式下也是如此。这可能会令人沮丧,因为你可能知道某个资源的名称,但不知道它位于哪个资源组。要确定这一点,你需要使用单独的命令来枚举各个资源组。
要使用 PowerShell 查看订阅中的资源组,请运行以下命令:
PS C:\> Get-AzureRmResourceGroup
在 Azure CLI 中,运行以下命令:
C:\>azure group list
每个命令会显示订阅中的所有资源组,但不会显示这些组中有哪些服务。在有数十个甚至上百个组的订阅上运行枚举命令可能会很繁琐。幸运的是,你可以在高层次上列出订阅中的所有 ARM 资源,以及它们的资源组和服务类型。要在 ARM PowerShell 中获取资源列表,请运行以下命令:
PS C:\> Get-AzureRmResource
在 Azure CLI 中,使用以下命令:
C:\>azure resource list
这些命令的输出可能会很难看,所以最好将其放入电子表格中,并作为指南,确保你的调查没有遗漏任何内容。
查看订阅的应用服务(Web 应用)
当公司决定将部分服务迁移到云时,网站通常是一个容易的第一步。毕竟,大部分甚至所有这些数据已经是公开的,因此与将数据存储在远程服务器上通常相关的机密性问题大大减少。此外,网站还可以利用平台即服务(PaaS)云提供商的自动扩展功能,在忙碌的时段(如新产品发布和假日购物)期间增加容量。
微软最初在旧管理界面中将这些站点称为Web 应用,但已经将它们的管理完全迁移到新的门户并重新命名为应用服务。新的门户还提供了一个预构建的 Web 服务模板库——从博客到电子商务平台一应俱全。迁移的一个好处是,即使是基于 ASM 模型部署的应用,也可以通过 ARM PowerShell cmdlet 和 CLI 的 ARM 模式进行查看。
使用 PowerShell
要使用 PowerShell 查看订阅中的 Web 应用,请运行没有参数的 Get-AzureRmWebApp 命令。旧版的Get-AzureWebsite将返回站点列表。这两个命令都允许你传递站点名称作为参数,以获取更多细节。尝试使用 ASM 版本的命令,因为它返回了 ARM 版本在经典网站上遗漏的细节。列出 3-3 展示了这种输出的示例。
➊ PS C:\> Get-AzureWebsite
Name : anazurewebsite
State : Running
Host Names : {anazurewebsite.azurewebsites.net}
➋ PS C:\> Get-AzureWebsite -Name anazurewebsite
Instances : {d160 ... 0bb13}
NumberOfWorkers : 1
DefaultDocuments : {Default.htm, Default.html, index.htm...}
➌ NetFrameworkVersion : v4.0
➍ PhpVersion : 5.6
RequestTracingEnabled : False
HttpLoggingEnabled : False
DetailedErrorLoggingEnabled : False
➎ PublishingUsername : $anazurewebsite
➏ PublishingPassword : gIhh ... cLg8a
--snip--
列出 3-3:来自 Get-AzureWebsite PowerShell cmdlet 的输出
在获取任何 Azure 网站及其 URL 的名称之后➊,将你感兴趣的站点名称传递给Get-AzureWebsite,并使用-Name ➋。Get-AzureWebsite 提供的一些详细信息,而 Get-AzureRmWebApp 则省略了,包括站点运行的 .NET 版本 ➌ 和 PHP 版本 ➍,以及用于发布站点内容的账户的用户名 ➎ 和密码 ➏。这些信息对攻击者极具价值,因为它们可以帮助寻找已知的 PHP 和 .NET 漏洞,具体根据版本来判断。同时,它们还可以修改站点内容。
在 ASM 中使用 CLI
你可以使用 CLI 获取类似的数据。在 ASM 模式下,使用命令 azure site list 查看所有订阅网站的列表,然后运行
C:\>azure site show "sitename"
查看给定站点的详细信息。与 PowerShell cmdlet 不同,详细输出并不那么全面,许多细节有自己单独的命令,例如
C:\>azure site appsetting list "sitename"
要查看所有这些选项,请运行 azure help site。
在 ARM 中使用 CLI
在 ARM 模式下,CLI 要求你提供网站所在的资源组,即使你只是想列举站点列表。首先使用 azure group list 获取资源组列表。然后,在获得组列表后,针对每个资源组运行 azure webapp list "group_name"。接下来,运行以下命令查看详细信息:
C:\>azure webapp show "group_name" "app_name"
与 ASM CLI 一样,一些细节隐藏在附加的子命令后面。要查看这些选项,请输入 azure help webapp。
收集虚拟机信息
作为典型的 基础设施即服务(IaaS) 角色,虚拟机(VM)是 Azure 订阅中最常见的服务之一。在管理方面,Azure 实际上将虚拟机分解为多个组件,这些组件都通过不同的命令单独配置。我将讨论如何获取虚拟机容器本身的信息,然后向你展示如何获取虚拟机的硬盘镜像和网络设置。
查看虚拟机列表
与应用服务不同,虚拟机按服务模型进行隔离,经典虚拟机仅出现在 ASM cmdlet 中,而 ARM 虚拟机仅出现在 ARM cmdlet 中。在 PowerShell 中运行Get-AzureVM会返回基于 ASM 的虚拟机列表,其中包括每个虚拟机的服务名称、名称和状态。要查看虚拟机的详细状态报告,请使用 cmdlet 的服务名称参数:
PS C:\> Get-AzureVM -ServiceName "service_name"
此报告应包括虚拟机的 IP 地址、DNS 地址、电源状态和虚拟机的“大小”等信息。
虚拟机定价层揭示的目标信息
虚拟机大小映射到特定的一组硬件配置和每月费用。例如,A0 虚拟机有 768MB 内存,20GB 硬盘空间,1 个 CPU 核心,和 1 个网络接口,而 D14 虚拟机有 112GB 内存,800GB SSD 存储,16 个 CPU 核心,和最多 8 个网络接口。每个层级的规格可以在 docs.microsoft.com/en-us/azure/virtual-machines/virtual-machines-windows-sizes/ 上找到,当前的定价可以通过 azure.microsoft.com/en-us/pricing/details/cloud-services/ 查看。
这些详细信息可能至关重要,因为它们提供了虚拟机的重要性、工作负载或价值的一些指示。测试虚拟机通常在 A0-A3 范围内,而生产虚拟机通常位于更高的 D 层级。此外,像 N 这样的特殊层级提供专用的硬件 Nvidia 图形处理单元(GPU),直接供虚拟机使用。这些通常用于计算密集型工作,例如渲染动画(或者对于我们渗透测试人员来说,用于破解密码)。
在 PowerShell 中查看 ARM 虚拟机列表
要在 PowerShell 中获取 ARM 虚拟机的列表,使用没有参数的 Get-AzureRmVM cmdlet。这应该会返回订阅中的每个虚拟机,以及其资源组名称、区域和大小。
列表 3-4 显示了如何在 PowerShell 中获取 ARM 虚拟机的详细信息。
➊ PS C:\> $vm = Get-AzureRmVM -ResourceGroupName "resource_group" -Name "name"
➋ PS C:\> $vm
ResourceGroupName : resource_group
...
Name : VM_name
Location : centralus
--snip--
HardwareProfile : {VmSize}
NetworkProfile : {NetworkInterfaces}
OSProfile : {ComputerName, AdminUsername, LinuxConfiguration, Secrets}
ProvisioningState : Succeeded
StorageProfile : {ImageReference, OsDisk, DataDisks}
➌ PS C:\> $vm.HardwareProfile
VmSize
------
Basic_A0
➍ PS C:\> $vm.OSProfile
ComputerName : VM_name
AdminUsername : Username
AdminPassword :
CustomData :
WindowsConfiguration :
LinuxConfiguration : Microsoft.Azure.Management.Compute.Models.LinuxConfiguration
Secrets : {}
➎ PS C:\> $vm.StorageProfile.ImageReference
Publisher Offer Sku Version
--------- ----- --- -------
Canonical UbuntuServer 16.04-LTS latest
列表 3-4:在 PowerShell 中获取 ARM 虚拟机的详细信息
第一个命令获取虚拟机的详细信息并将其保存到变量 $vm ➊ 中。接下来,我们转储变量中的信息 ➋ 并显示虚拟机大小 ➌。这些信息可以在初始虚拟机枚举中通过 Get-AzureRmVM 获取,但将其与虚拟机的其他详细信息一起输出时,查看时会更加方便。
现在,我们转储操作系统配置块 ➍,其中包括管理员的用户名(遗憾的是,密码通常会被省略)。最后,我们显示存储配置文件中的镜像参考信息 ➎。这告诉我们虚拟机的基础镜像,通常包含版本信息——在本例中是 Ubuntu Server 16.04 长期支持(LTS)版本。
通过 CLI 收集信息
要从 CLI 中收集 ASM 模式的信息,使用 azure vm list 列举订阅中的经典虚拟机,然后使用 azure vm show "name" 查看每个虚拟机的详细信息。
在 ARM 模式下使用 CLI 对虚拟机(VM)的操作几乎与其他方式相同——列举命令也是azure vm list。唯一的区别是,在显示虚拟机详细信息时,ARM 模式还需要提供资源组:
C:\>azure vm show "resource_group_name" "VM_name"
与 PowerShell 不同,这将一次性显示所有详细信息,包括用户名、虚拟机大小和操作系统版本。
查找存储账户和存储账户密钥
Azure 存储是微软云中存储数据的主要场所。存储账户提供四种类型的数据存储,任何给定的存储账户都可以同时使用这些类型中的任何一种或全部。Blob 存储用于存储非结构化数据,包括文件和大规模二进制流。文件存储与 Blob 存储类似,不同之处在于它提供直接的服务器消息块(SMB)文件访问。(这很方便,因为 Blob 存储传统上需要使用复杂的 API 或第三方工具来访问其内容。有关如何使用这些工具提取数据,我将在第四章中讲解。)表格存储是一个可扩展的 NoSQL 表格数据集容器。最后,队列用于存储用于有序、异步处理的瞬态消息。
许多其他服务依赖存储账户来托管其基础数据,包括虚拟机。虚拟机中使用的虚拟硬盘(VHD)文件作为块存储在这里。其他服务,如 Azure 网站、机器学习和活动日志,也可以使用存储账户来存储其日志文件。
你的侦察任务应回答有关存储账户的两个主要问题:
-
目标订阅中有哪些存储账户?
-
它们的密钥是什么?
第一个问题的答案很简单,只要记住经典(基于 ASM)存储账户和基于 ARM 的存储账户在 Azure 中是完全独立的,因此要记得同时查找这两种类型的账户。要在 PowerShell 中检查经典存储账户,使用Get-AzureStorageAccount cmdlet,不带任何参数来列出订阅中的所有 ASM 存储账户。Azure CLI 中等效的命令是azure storage account list。这两个命令都会显示存储账户的名称、类型(它的数据是冗余存储在一个数据中心、一个区域还是多个区域)以及位置(数据存储的具体数据中心,例如“美国中部”)。PowerShell 命令还提供一些额外的细节,如账户使用的 URL,但这些信息也可以通过 CLI 使用azure storage account show "account_name"命令获取。
检查 ARM 存储账户同样简单。在 CLI 中,你用于 ASM 的相同命令也适用于 ARM(只需切换 CLI 模式)。对于 PowerShell,命令是Get-AzureRmStorageAccount。
接下来,你需要存储账户的密钥才能访问 Azure 存储中的数据。Azure 为每个存储账户分配两个 base64 编码的 64 字节密钥。它们分别标记为“主密钥”和“辅助密钥”,但你可以使用任何一个。拥有两个密钥的好处是管理员可以通过以下步骤轮换密钥,而不会中断服务:
-
更新服务的配置,从使用主密钥切换到辅助密钥
-
使用 Azure 门户生成新的主密钥
-
更新服务,将其从辅助密钥切换到新的主密钥
你不会遇到太多困难来获取这些密钥。由于每个访问该存储帐户的服务都使用相同的密钥(或相同的两把密钥),管理员需要一种简单的方式来一次又一次地检索密钥,每次他们添加或更新服务时。此外,由于密钥在任何地方都被使用,并且除非生成新密钥,否则密钥不会过期,因此大多数管理员从不更改它,因为对多个服务执行上述三个步骤可能会很繁琐。
DEFENDER’S TIP(DEFENDER 提示)
了解如何正确重置泄露或其他形式泄露的凭据,对于在安全事件发生时迅速进行补救至关重要。理解认证依赖关系同样重要,以便最大程度减少凭据更改可能引起的中断。因此,定期练习重置或“滚动”组织使用的任何类型凭据是明智的做法,并根据需要进行优化,以便在真实攻击中能够及时准确地重置凭据。存储密钥或 SSL 私钥也不例外——在开发和生产过程中,练习在所有服务中切换主密钥和次密钥,以确保你已经妥善记录了每个需要替换密钥的地方。
由于密钥需要能够检索,Azure 通过门户、PowerShell 和 CLI 提供它们。要在 PowerShell 中获取 ASM 存储帐户的主密钥和次密钥,请运行
PS C:\> Get-AzureStorageKey -StorageAccountName "Storage_Account_Name"
要在 ARM PowerShell 中执行相同操作,请使用以下命令:
PS C:\> Get-AzureRmStorageAccountKey -ResourceGroupName
"Resource_Group_Name" -StorageAccountName
"Storage_Account_Name"
在 CLI 中,获取 ASM 密钥很简单;只需执行以下命令:
C:\>azure storage account keys list "account_name"
出于某种原因,获取密钥的 ARM CLI 命令与所有其他 ARM CLI 命令行为不同。它需要存储帐户的资源组名称,但命令行不接受该组名称作为参数;因此,如同 ASM 模式一样,你需要运行以下命令:
C:\>azure storage account keys list "account_name"
运行此命令后,系统会提示你提供资源组名称。请输入该名称,密钥随后将显示出来。
收集网络信息
网络是 Azure 中较为复杂的部分之一,因为它涉及到 IP 地址分配、防火墙规则、虚拟网络以及虚拟私人网络(VPN)。它甚至可能涉及到企业与 Azure 之间的专用线路,这被称为 ExpressRoute。ExpressRoute 连接本质上是一个专用的广域网(WAN)连接,允许公司将 Azure 中运行的资源视为其内部企业网络的一部分。在这一阶段的操作中,我专注于简单列举常用的网络功能:网络接口(IP 地址)、端点(端口)和网络安全组(防火墙)。更高级的主题将在第六章中详细介绍。
网络接口
网络接口 是与基于 ARM 的虚拟机关联的虚拟网卡。在经典虚拟机中,它们仅被称为 IP 地址。每个虚拟机通常有两个 IP 地址——一个是内部的、非面向互联网的地址,用于连接订阅中的其他服务,另一个是面向互联网的公共 IP 或虚拟 IP 地址。从 Azure 直接获取这些 IP 对渗透测试者非常有利,因为这样可以进行端口扫描和其他针对虚拟机的定向攻击,而不需要扫描整个地址范围寻找设备。它还确保了扫描范围的准确性,因为 Azure 空间中的公共 IP 地址可能会动态重新分配给其他 Azure 客户。
注意
如果你已经拥有 Azure 门户或 API 访问权限,为什么还需要对虚拟机的 IP 地址进行外部扫描?在渗透测试中,客户通常希望检查多个攻击向量,从内部威胁到基于互联网的“脚本小子”。虽然内部人员或国家级攻击者可能能够突破客户的网络并获得门户访问权限,但技能较低的攻击者可能做不到,因此,评估暴露在互联网上的任何内容进行传统的安全评估非常重要。此外,Azure 不提供从门户对虚拟机进行控制台类型的访问。对虚拟机的所有访问必须通过其网络接口使用远程管理服务,如远程桌面协议(RDP)或 SSH。
DEFENDER’S TIP
互联网上的所有服务都面临着几乎不断的端口和漏洞扫描、暴力破解密码攻击以及其他类型的攻击。甚至像 Shodan (*www.shodan.io/) 这样的站点,会索引端口扫描数据并使其可以公开搜索。尽可能地,通过关闭未使用的管理服务、通过 IP 限制访问这些服务,以及将虚拟机放置在私有 VLAN 中,避免其暴露在互联网上,可以帮助减轻这些攻击。
列出经典虚拟机使用的内部 IP
要获取经典虚拟机使用的内部 IP 列表,只需运行 Get-AzureVM 或 azure vm show 命令。内部 IP 应该包含在这两个命令的 ASM 输出中。相反,ARM 的 CLI vm show 命令默认只显示公共 IP。表 3-2 描述了虚拟机命令显示的 IP。
表 3-2: 工具显示的 IP 地址
| 命令(模式) | 内部 IP | 公共 IP |
|---|---|---|
azure vm show (ASM) |
显示 | 显示 |
azure vm show (ARM) |
未显示 | 显示 |
Get-AzureVM (ASM) |
显示 | 未显示 |
Get-AzureRmVM (ARM) |
未显示 | 未显示 |
对于 ASM 虚拟机,CLI 的 azure vm show 命令是获取 IP 地址的一站式工具。要在 ARM 模式下使用 CLI 显示所有网络接口的列表,输入 azure network nic list。这将显示接口的名称、资源组、MAC 地址和位置。以下是如何使用它显示特定 NIC 的详细信息:
C:\>azure network nic show "resource_group_name" "NIC_name"
输出还应显示诸如 IP 地址、是否为静态或动态分配、以及关联的虚拟机或服务等详细信息。
为了从 ASM PowerShell cmdlet 获取指定虚拟机的动态分配公共 IP 信息,你需要列出虚拟机的端点,具体内容将在下一节中讨论。也就是说,如果订阅中有任何为 ASM 资源保留的(静态)公共 IP 地址,使用 Get-AzureReservedIP 命令(没有开关)应该能列出它们,以及它们绑定的服务。
最后,要查看 ARM 资源的 IP 地址,可以使用 Get-AzureRmNetworkInterface 来显示订阅中所有正在使用的 NIC,这将只显示私有 IP 地址。要查看公共 IP 地址,使用 Get-AzureRmPublicIpAddress cmdlet,它将显示使用公共 IP 的任何 ARM 资源、IP 地址,以及该地址是动态分配还是静态分配。
使用 Azure 管理工具查询端点
一旦知道了订阅中的 IP 地址,你应该确定这些 IP 地址上可用的端口。在经典的 Azure 虚拟机中,网络端口被称为 端点 —— 即在主机上运行的服务。对于 ARM 虚拟机,端口管理已整合到防火墙管理中,但 ASM 仍然将它们分开管理。我们来看看如何列举 ASM 端点。
虽然你可以使用端口扫描器(如 Nmap)来收集这些信息,但这样做有几个缺点:
-
基于 ASM 的虚拟机会将远程桌面协议(RDP)放置在随机的高端口号上,因此你需要扫描所有 65,535 个端口,以确保找到正确的端口。
-
由于扫描将通过互联网进行,它比在本地网络上进行类似的扫描要慢得多。
-
一个订阅可能有几十台,甚至上百台主机。
-
你只会找到允许通过防火墙的面向互联网的端口,而不会找到任何可能仅对订阅中的其他主机或 Azure 内部暴露的服务。
由于这些原因,直接使用 Azure 管理工具查询端口更快、更彻底。要在 PowerShell 中查询端点,使用 Get-AzureEndpoint,如 清单 3-5 所示。你必须对每个经典虚拟机运行此命令,并传递一个 PowerShell IPersistentVM 对象,而不是虚拟机的名称。Get-AzureVM cmdlet 返回的就是这种类型的对象。
➊ PS C:\> $vm = Get-AzureVM -ServiceName vmasmtest
➋ PS C:\> Get-AzureEndpoint -VM $vm
LBSetName :
LocalPort : 22 ➌
Name : SSH ➍
Port : 22 ➎
Protocol : tcp
Vip : 52.176.10.12 ➏
--snip--
清单 3-5:在 PowerShell 中获取 ASM 虚拟机的端点
在➊,我们使用虚拟机的服务名称获取虚拟机对象,并将其存储在一个变量中。接下来,我们将该对象传递给Get-AzureEndpoint cmdlet ➋,它应该返回服务器监听的端口 ➌、端点的名称 ➍(通常是所使用的服务名称,如 SSH、RDP 或 HTTP)、暴露到互联网的端口(即转发到本地端口的端口) ➎,以及端点的虚拟 IP 地址 ➏。VIP 是虚拟机的公共 IP 地址。
Azure CLI 也允许你列出 ASM 模式下的端点。要获取具有特定虚拟机名称的端点列表,请运行以下命令:
C:\>azure vm endpoint list "VM_name"
你只需要为每个虚拟机运行此命令一次,以查看所有其端点。
获取防火墙规则或网络安全组
从 Azure 的防火墙规则中收集虚拟机网络设置信息非常有帮助,因为这些规则决定了哪些端口对于特定虚拟机是可访问的,以及从哪里可访问。这些规则与虚拟机操作系统级别的防火墙是分开的,并且像路由器上的端口转发设置一样工作。Azure 在 ARM 中称这些防火墙过滤器为网络安全组(NSG),在 ASM 中称之为经典网络安全组(NSG)。
使用 PowerShell 查看基于 ASM 的 NSG
由于各种原因,经典虚拟机通常不使用 NSG。然而,了解如何列出经典和基于 ARM 的 NSG 仍然是值得的,因为知道是否存在防火墙有助于避免不必要的端口扫描,甚至你可能会在报告中向客户报告防火墙缺失的情况。在 PowerShell 中,你可以通过不带任何参数的Get-AzureNetworkSecurityGroup命令列出经典 NSG 的名称和位置。要查看特定经典 NSG 中的规则,请使用以下命令:
PS C:\> Get-AzureNetworkSecurityGroup -Detailed -Name "NSG_Name"
要查看每个经典 NSG 的详细信息,请运行以下命令:
PS C:\> Get-AzureNetworkSecurityGroup -Detailed
不幸的是,这个命令的输出不能将 NSG 映射回虚拟机。为了实现这一点,获取目标虚拟机的虚拟机对象,然后运行以下命令来显示与该虚拟机关联的 NSG(如果虚拟机没有使用 NSG,你将看到一个错误):
PS C:\> Get-AzureNetworkSecurityGroupAssociation -VM $vm
-ServiceName $vm.ServiceName
使用 CLI 查看基于 ASM 的 NSG
Azure CLI 还可以显示经典 NSG 设置。要查看 ASM 模式下的所有经典 NSG,请运行以下命令:
C:\>azure network nsg list
要查看 NSG 中的规则,请运行以下命令:
C:\>azure network nsg show "NSG_Name"
我还没有找到使用 CLI 映射 NSG 与虚拟机之间关联的方法。
使用 PowerShell 查看基于 ARM 的 NSG
运行Get-AzureRmNetworkSecurityGroup命令以使用 PowerShell 查看基于 ARM 的 NSG。这将返回每个 ARM NSG 的名称、资源组、区域和规则。这些规则包括订阅管理员定义的规则,以及 Azure 自动创建的规则,如“允许所有虚拟机向互联网发送出站流量”。查看这些规则很有帮助(毕竟,移除“允许向互联网发送出站流量”的规则可能会阻止你在被攻陷虚拟机上的指挥控制流量),但如果你更倾向于,你可以使用Get-AzureRmNetworkSecurityRuleConfig命令仅查看某个特定 NSG 的自定义规则。
为了使用 PowerShell 获取 ARM 虚拟机与 ARM NSG 的映射,您需要查找所需虚拟机的接口,然后查找该接口的 NSG。您可以将以下所有命令嵌套成一行,但为了提高可读性并避免错误,我通常将其分解成一系列命令,如清单 3-6 所示。
➊ PS C:\> $vm = Get-AzureRmVM -ResourceGroupName "VM_Resource_Group_Name"
-Name "VM_Name"
➋ PS C:\> $ni = Get-AzureRmNetworkInterface | where { $_.Id -eq
$vm.NetworkInterfaceIDs }
➌ PS C:\> Get-AzureRmNetworkSecurityGroup | where { $_.Id -eq
$ni.NetworkSecurityGroup.Id }
Name : NSG_Name
ResourceGroupName : NSG_Resource_Group_Name
Location : centralus
. . .
SecurityRules :
{
"Name": "default-allow-ssh",
--snip--
清单 3-6:在 PowerShell 中查找给定虚拟机的网络安全组
在 ➊,我们获取虚拟机对象并将其放入变量中。在 ➋,我们执行查找以获取该虚拟机的网络接口对象,使用虚拟机的网络接口 ID 属性。最后,我们使用存储在网络接口对象中的网络安全组标识符➌显示 NSG。除了在第一行替换虚拟机的资源组和名称,您可以像这里所示的那样运行其余命令。
使用 CLI 查看基于 ARM 的 NSG
在 ARM 模式下查看 NSG 的 CLI 命令与 ASM 中几乎相同。唯一的区别是,显示特定 NSG 的 ARM 命令需要资源组名称:azure network nsg show "Resource_Group_Name" "NSG_Name".
查看 Azure SQL 数据库和服务器
SQL 经常出现在 Azure 中,不仅因为许多基于 Azure 的网站需要它,还因为在本地服务器上安装 SQL 可能很慢,并且有数十个可能令人困惑的配置选项。然而,设置 Azure SQL(微软的基于云的 SQL 解决方案)只需要几分钟。
Azure SQL 被分为 SQL 服务器和 SQL 数据库。尽管数据库存在于 Azure SQL 服务器实例中,但这两个项目是分别管理的——这种分离可能会让经验丰富的 SQL 管理员感到惊讶。
列出 Azure SQL 服务器
要列出订阅中的 SQL 服务器(包括数据库服务器名称、位置、管理员帐户的用户名和版本),请运行 Get-AzureSqlDatabaseServer 而不带参数。获取服务器信息后,运行
PS C:\> Get-AzureSqlDatabase -ServerName "Server_Name"
查看该服务器中每个数据库的名称、大小和创建日期。
查看 Azure SQL 防火墙规则
要查看应用于 Azure SQL 的任何防火墙规则,请运行以下命令:
PS C:\> Get-AzureSqlDatabaseServerFirewallRule -ServerName "Server_Name"
默认情况下,Azure 阻止对 Azure SQL 服务器的访问,除了来自其他 Azure 服务的访问。虽然这对于安全性非常有益,但对于那些希望从工作站连接到数据库的开发者来说,这却非常令人沮丧。事实上,这个问题已经困扰了很长时间,以至于 SQL Server 管理工作室(用于管理 SQL 数据库的工具)在登录 Azure SQL 服务器时,添加了一个提示,自动将用户当前的 IP 地址添加到防火墙规则中。毫不奇怪的是,这让那些 IP 地址频繁变化的开发者感到恼火,因此你经常会发现 Azure SQL 中的防火墙规则允许来自全球任何 IP 地址的连接,或者至少允许来自公司网络内的任何地方的连接。检查防火墙,看看你可以使用哪些主机绕过防火墙,直接访问 SQL 服务器。
SQL ARM PowerShell Cmdlets
ARM PowerShell 扩展比 ASM PowerShell 拥有更多与 SQL 相关的命令,尽管大多数命令涉及的是不太常见的功能,或者对渗透测试人员来说并不相关。不过,使用 ARM 的最大障碍可能是 Get-AzureRmSqlServer cmdlet 的资源组字段是必需的。幸运的是,虽然这通常意味着你需要为每个订阅中的资源组运行命令才能看到所有的 SQL 服务器,但 PowerShell 提供了一个快捷方式。只需将 Get-AzureRmResourceGroup 的输出通过管道传递给 Get-AzureRmSqlServer,你就可以看到所有 SQL 服务器,如[清单 3-7 所示。
PS C:\> Get-AzureRmResourceGroup | Get-AzureRmSqlServer
ResourceGroupName : Resource Group Name
ServerName : Server Name
Location : Central US
SqlAdministratorLogin : dba
SqlAdministratorPassword :
ServerVersion : 12.0
Tags : {}
清单 3-7:在 PowerShell 中查找基于 ARM 的 SQL 服务器
列出服务器中的数据库
PowerShell 提供了一个 ARM 命令,可以显示 SQL 服务器中的所有数据库,包括数据库的大小、创建日期和区域。要列出某个服务器中的数据库,请运行以下命令:
PS C:\> Get-AzureRmSqlDatabase -ServerName "Server_Name"
-ResourceGroupName "Server_Resource_Group_Name"
要查看 ARM 的 SQL 防火墙规则,以及每个规则的起始和结束 IP 地址及其名称,请运行以下命令:
PS C:\> Get-AzureRmSqlServerFirewallRule -ServerName "Server_Name"
-ResourceGroupName "Server_Resource_Group_Name"
最后,考虑运行以下命令,查看 Azure 的威胁检测工具是否在运行:
PS C:\> Get-AzureRmSqlServerThreatDetectionPolicy -ServerName "Server_Name"
-ResourceGroupName "Server_Resource_Group_Name"
这个工具会监视如 SQL 注入等攻击。你需要知道它是否正在运行,以便在发起可能触发警报的测试之前了解情况。
DEFENDER 提示
一定要充分利用 Azure 的安全功能。定期检查,确保没有人向你的 SQL 防火墙添加允许所有连接的规则,并在新增安全功能时启用它们,例如 SQL 威胁检测 (docs.microsoft.com/en-us/azure/sql-database/sql-database-threat-detection/ )。尽管没有任何功能能够保证系统的完全安全,但每增加一个控制措施,都会提供另一层保护,使得针对你的服务的攻击变得更加困难。让攻击者觉得足够麻烦,从而决定去攻击其他目标。
使用 CLI 进行 Azure SQL 操作
你可以使用 CLI 来收集 Azure SQL 的信息,但请记住,在 ASM 模式下它只提供 SQL 命令。此外,列出 SQL 服务器实例中数据库的命令需要数据库账户凭据,而且没有命令可以查看 SQL 威胁检测的状态(或 ARM PowerShell 中可用的任何高级 SQL 命令)。
要使用 CLI 查看订阅中的 SQL 服务器,包括数据库名称和托管数据中心,运行azure sql server list。然后运行
C:\>azure sql server show "Server_Name"
要查看更多详细信息,例如数据库管理员用户名和服务器版本,最后要检查防火墙规则,输入azure sql firewallrule list。你可以使用以下命令显示特定的防火墙规则:
C:\>azure sql firewallrule show "Server_Name" "Rule_Name"
合并 PowerShell 脚本
在渗透测试期间,我通常时间有限,需要收集数据,可能是因为我有数十个订阅需要审查,或者因为我使用的是合法用户的系统或凭据,使用时间越长,被发现的概率越大。因此,我喜欢将所有需要的命令集中在一个地方,并使用易于运行的脚本。
在接下来的章节中,我将介绍 ASM PowerShell 和 ARM PowerShell 的脚本。掌握这两者都很重要,因为在一种订阅模型中有效的凭据可能在另一种中无效。而且,并非所有系统都会安装 ARM cmdlet。当不受任何限制时,我通常会运行这两个脚本。虽然有些重复,但获得更多信息总比错过什么要好。
我没有为 CLI 工具提供脚本,因为 PowerShell 的输出更易于以脚本形式处理。而且,如果你使用与你的目标相同的工具进行渗透测试,被发现的可能性会更低。大多数开发人员都会安装 Azure PowerShell 扩展;而安装 CLI 的人要少得多。
你可以从本书的官网* nostarch.com/azure/*下载这两个脚本。当然,你可能需要根据你的特定情况对其进行自定义,添加身份验证等。(我发现最简单的方法是启动一个 PowerShell 窗口,使用我已获得的凭据进行身份验证,然后启动脚本。)如果你还没有在这个 PowerShell 窗口中这样做,你可能还需要运行Set-ExecutionPolicy -Scope Process Unrestricted命令,以便系统能够运行未签名的脚本。
ASM 脚本
在清单 3-8 中显示的脚本会遍历订阅中的常见 ASM 资源,然后显示有关这些服务的信息。它使用了本章讨论的所有 ASM PowerShell 命令。
# Requires the Azure PowerShell cmdlets be installed.
# See https://github.com/Azure/azure-powershell/ for details.
# Before running the script:
# * Run: Import-Module Azure
# * Authenticate to Azure in PowerShell
# * You may also need to run: Set-ExecutionPolicy -Scope Process Unrestricted
# Show subscription metadata
Write-Output (" Subscription ","==============")
Write-Output ("Get-AzureSubscription -Current")
Get-AzureSubscription -Current
# Display websites
Write-Output ("", " Websites ","==========")
$sites = Get-AzureWebsite
Write-Output ("Get-AzureWebsite")
$sites
foreach ($site in $sites)
{
Write-Output ("Get-AzureWebsite -Name " + $site.Name)
Get-AzureWebsite -Name $site.Name
}
# View virtual machines
Write-Output ("", " VMs ","=====")
$vms = Get-AzureVM
Write-Output ("Get-AzureVM")
$vms
foreach ($vm in $vms)
{
Write-Output ("Get-AzureVM -ServiceName " + $vm.ServiceName)
Get-AzureVM -ServiceName $vm.ServiceName
}
# Enumerate Azure Storage
Write-Output ("", " Storage ","=========")
$SAs = Get-AzureStorageAccount
Write-Output ("Get-AzureStorageAccount")
$SAs
foreach ($sa in $SAs)
{
Write-Output ("Get-AzureStorageKey -StorageAccountName" + $sa.StorageAccountName)
Get-AzureStorageKey -StorageAccountName $sa.StorageAccountName
}
# Get networking settings
Write-Output ("", " Networking ","============")
Write-Output ("Get-AzureReservedIP")
Get-AzureReservedIP
Write-Output ("", " Endpoints ","===========")
# Show network endpoints for each VM
foreach ($vm in $vms)
{
Write-Output ("Get-AzureEndpoint " + $vm.ServiceName)
Get-AzureEndpoint -VM $vm
}
# Dump NSGs
Write-Output ("", " NSGs ","======")
foreach ($vm in $vms)
{
Write-Output ("NSG for " + $vm.ServiceName + ":")
Get-AzureNetworkSecurityGroupAssociation -VM $vm -ServiceName $vm.ServiceName
}
# Display SQL information
Write-Output ("", " SQL ","=====")
$sqlServers = Get-AzureSqlDatabaseServer
Write-Output ("Get-AzureSqlDatabaseServer")
$sqlServers
foreach ($ss in $sqlServers)
{
Write-Output ("Get-AzureSqlDatabase -ServerName " + $ss.ServerName)
Get-AzureSqlDatabase -ServerName $ss.ServerName
Write-Output ("Get-AzureSqlDatabaseServerFirewallRule -ServerName " + $ss.ServerName)
Get-AzureSqlDatabaseServerFirewallRule -ServerName $ss.ServerName
}
清单 3-8:合并的 ASM PowerShell 侦察脚本
ARM 脚本
清单 3-9 展示了清单 3-8 的 ARM 版本。它比 ASM 版本稍长,因为它收集了更多关于订阅、虚拟机和网络接口的细节。
# Requires the Azure PowerShell cmdlets be installed.
# See https://github.com/Azure/azure-powershell/ for details.
# Before running the script:
# * Run: Import-Module Azure
# * Authenticate to Azure in PowerShell
# * You may also need to run Set-ExecutionPolicy -Scope Process Unrestricted
# Show details of the current Azure subscription
Write-Output (" Subscription ","==============")
Write-Output ("Get-AzureRmContext")
$context = Get-AzureRmContext
$context
$context.Account
$context.Tenant
$context.Subscription
Write-Output ("Get-AzureRmRoleAssignment")
Get-AzureRmRoleAssignment
Write-Output ("", " Resources ","===========")
# Show the subscription's resource groups and a list of its resources
Write-Output ("Get-AzureRmResourceGroup")
Get-AzureRmResourceGroup | Format-Table ResourceGroupName,Location,ProvisioningState
Write-Output ("Get-AzureRmResource")
Get-AzureRmResource | Format-Table Name,ResourceType,ResourceGroupName
# Display Web Apps
Write-Output ("", " Web Apps ","==========")
Write-Output ("Get-AzureRmWebApp")
Get-AzureRmWebApp
# List virtual machines
Write-Output ("", " VMs ","=====")
$vms = Get-AzureRmVM
Write-Output ("Get-AzureRmVM")
$vms
foreach ($vm in $vms)
{
Write-Output ("Get-AzureRmVM -ResourceGroupName " + $vm.ResourceGroupName +
"-Name " + $vm.Name)
Get-AzureRmVM -ResourceGroupName $vm.ResourceGroupName -Name $vm.Name
Write-Output ("HardwareProfile:")
$vm.HardwareProfile
Write-Output ("OSProfile:")
$vm.OSProfile
Write-Output ("ImageReference:")
$vm.StorageProfile.ImageReference
}
# Show Azure Storage
Write-Output ("", " Storage ","=========")
$SAs = Get-AzureRmStorageAccount
Write-Output ("Get-AzureRmStorageAccount")
$SAs
foreach ($sa in $SAs)
{
Write-Output ("Get-AzureRmStorageAccountKey -ResourceGroupName " + $sa.ResourceGroupName +
" -StorageAccountName" + $sa.StorageAccountName)
Get-AzureRmStorageAccountKey -ResourceGroupName $sa.ResourceGroupName -StorageAccountName
$sa.StorageAccountName
}
# Get networking settings
Write-Output ("", " Networking ","============")
Write-Output ("Get-AzureRmNetworkInterface")
Get-AzureRmNetworkInterface
Write-Output ("Get-AzureRmPublicIpAddress")
Get-AzureRmPublicIpAddress
# NSGs
Write-Output ("", " NSGs ","======")
foreach ($vm in $vms)
{
$ni = Get-AzureRmNetworkInterface | where { $_.Id -eq $vm.NetworkInterfaceIDs }
Write-Output ("Get-AzureRmNetworkSecurityGroup for " + $vm.Name + ":")
Get-AzureRmNetworkSecurityGroup | where { $_.Id -eq $ni.NetworkSecurityGroup.Id }
}
# Show SQL information
Write-Output ("", " SQL ","=====")
foreach ($rg in Get-AzureRmResourceGroup)
{
foreach($ss in Get-AzureRmSqlServer -ResourceGroupName $rg.ResourceGroupName)
{
Write-Output ("Get-AzureRmSqlServer -ServerName" + $ss.ServerName +
" -ResourceGroupName " + $rg.ResourceGroupName)
Get-AzureRmSqlServer -ServerName $ss.ServerName -ResourceGroupName
$rg.ResourceGroupName
Write-Output ("Get-AzureRmSqlDatabase -ServerName" + $ss.ServerName +
" -ResourceGroupName " + $rg.ResourceGroupName)
Get-AzureRmSqlDatabase -ServerName $ss.ServerName -ResourceGroupName
$rg.ResourceGroupName
Write-Output ("Get-AzureRmSqlServerFirewallRule -ServerName" + $ss.ServerName +
" -ResourceGroupName " + $rg.ResourceGroupName)
Get-AzureRmSqlServerFirewallRule -ServerName $ss.ServerName -ResourceGroupName
$rg.ResourceGroupName
Write-Output ("Get-AzureRmSqlServerThreatDetectionPolicy -ServerName" +
$ss.ServerName + " -ResourceGroupName " + $rg.ResourceGroupName)
Get-AzureRmSqlServerThreatDetectionPolicy -ServerName
$ss.ServerName -ResourceGroupName $rg.ResourceGroupName
}
}
清单 3-9:综合 ARM PowerShell 侦察脚本
一定要查看本书的网站 (nostarch.com/azure/) 获取这些脚本的更新版本。
总结
我已经涵盖了你可以用来了解 Azure 订阅使用情况的广泛命令。我解释了如何获取 Azure 的 PowerShell 和命令行工具。我讨论了基于你获取的凭据类型,应该使用的各种身份验证方法。我展示了如何在订阅中发现网站、虚拟机、存储帐户、网络设置和 SQL 数据库。最后,我提供了你可以用来快速查询这些服务的脚本。
我认为这些技术对于任何彻底的渗透测试都是不可或缺的,因为它们有助于更好地了解客户的整体攻击面:非生产系统往往可以作为跳板访问生产资源,但在风险评估中经常被忽视。通过将整个订阅纳入测试,而不仅仅是那些被认为最关键的资源,你可以显著提高对客户提供的价值。
在下一章,我将演示一些利用 Azure 存储帐户的实用技巧。
第四章:检查存储

在接下来的几章中,我们将深入探讨特定的 Azure 服务以及每种服务独特的渗透测试技术和工具。我们将从 Azure 存储账户开始,这些账户被多个 Azure 服务用于存储从日志到虚拟机“硬盘”映像的所有内容。客户还使用存储账户进行文档共享和备份,基本上是本地文件服务器的云端替代方案。当然,将所有这些数据集中存储在一个地方会成为攻击者诱人的目标。
除了其数据潜在价值之外,存储账户出于多种原因是理想的攻击目标;其中最重要的是每个存储账户都有两个密钥,可以完全控制其数据。这些密钥被所有使用该存储账户的服务和所有账户管理员共享。更糟糕的是,大多数客户从不更改它们。
这些做法会导致否认、授权和补救问题(如果确实发生攻击)。存储账户密钥还可能存在用户自身引发的弱点:因为许多应用程序需要存储访问权限,开发人员经常在其代码或配置文件中嵌入存储密钥,而未考虑可能的安全后果。
在本章中,我们首先讨论 Azure 存储中可用的不同身份验证方法。然后,我们将看看如何在源代码中找到这些凭据,接着看看每个常用工具用于访问和管理 Azure 存储的方法以及如何从中窃取凭据。这非常重要,因为您事先不知道将在开发人员系统中遇到哪些实用程序。最后,我们将研究如何从存储账户中检索不同形式的数据。这有两个目的:首先,向客户证明未经适当保护的云存储存在重大数据泄露的风险;其次,账户中的数据有时可以用于获取对环境的额外访问权限。
最佳实践:存储安全
不当配置的云存储在 2016 年至 2018 年间已在超过二十起公开披露的数据泄露事件中被提及。通常,当开发人员编写程序化访问云存储容器的代码,并将访问密钥嵌入源代码中并提交到源代码管理系统时,会出现问题。由于许多公司使用像 GitHub 这样的服务来托管他们的代码,开发人员可能没有意识到他们提交密码的代码库是公开可访问的。偶尔,泄露也发生在存储账户被配置为任何人都可以读取,无需密码的情况下。由于恶意行为者定期扫描公共代码库,寻找密码和存储账户网址,试图获取访问权限,因此错误发生与泄露之间的时间可能非常短。但即使对代码库的访问是有限的,能够访问代码的人数通常也高于被授权访问密钥的人数。此外,密钥和密码绝不应以明文形式存储,即使是临时存储也不行。
作为管理员,您可以采取若干措施来防范这些问题。首先,定期进行存储账户的“滚动”或重置访问密钥,并记录需要更新密钥的地方。这样,如果发生实际事件,您可以在不担心破坏依赖服务的情况下开始修复工作。
接下来,尽可能启用云存储的数据传输和静态数据加密。从 2017 年底开始,Azure 默认加密 Azure 存储中的所有静态数据,使用的是自动管理的密钥。如果需要,管理员可以通过 Azure 门户的存储账户设置提供自己的加密密钥。然而,尽管此设置保护了存储介质上的数据,但它并没有保护数据在上传或下载过程中。为此,存储账户必须配置为仅允许通过 HTTPS 协议连接。可以在 Azure 门户的存储账户配置设置中通过启用“要求安全传输”选项来实现。也可以通过 PowerShell 启用此功能:
PS C:\> Set-AzureRmStorageAccount -Name "StorageName" -ResourceGroupName "
GroupName" -EnableHttpsTrafficOnly $True
为了确保存储账户不会被超过预期的人访问,请定期检查存储容器的访问类型设置。除非您打算允许匿名访问,否则它应设置为私有。此外,您可以使用共享访问签名(SAS)访问令牌来指定存储账户内更细粒度的权限,包括限制访问的时间段和 IP 范围。有关这些权限的更多信息,请参阅 docs.microsoft.com/en-us/azure/storage/blobs/storage-manage-access-to-resources/。
最后,定期进行代码审查,查找开发人员将密钥检查到源代码中的实例。你甚至可以考虑使用代码分析工具,在每次提交新代码时自动检查是否包含密码。这不仅对查找存储帐户密钥有帮助,还能帮助发现其他凭据。
访问存储帐户
可以通过存储帐户密钥、用户凭据和共享访问签名(SAS)令牌访问 Azure 存储,这些令牌是带有嵌入式访问密钥的 URL,通常提供对文件子集的访问权限,并可能有其他限制。每种凭据类型有不同的用途,有些对渗透测试人员比其他类型更有用。让我们逐一检查这些凭据。
存储帐户密钥
使用存储帐户密钥和存储帐户名称是最理想且最常用的攻击方法,因为它们允许完全访问整个存储帐户,而无需 2FA。存储帐户只有两个密钥——一个主密钥和一个次密钥——所有存储帐户用户共享这些密钥。这些密钥不会自动过期,但可以被更新。与可以由用户选择的密码不同,存储密钥是自动生成的 64 字节值,以 base64 编码表示,这使它们在源代码或配置文件中容易被识别。
存储密钥也受到每个 Azure 存储工具和与存储相关的 API 的支持,因此它们非常通用。此外,它们是开发人员最常使用的凭据,并且不经常更改,因此获取有效密钥的机会较大。
用户凭据
获取用户凭据是下一个最佳的访问方式。尽管基于角色的权限可以限制用户帐户对存储帐户执行某些操作的能力,但实际上,这种细粒度的权限很少被实施。依赖这些凭据的最大缺点是可能遇到双因素认证(2FA)。如果用户帐户启用了 2FA,那么在没有使用在“遇到双因素认证”中讨论过的某些方法的情况下,无法冒充该用户。这些方法增加了攻击的复杂性,降低了成功的概率。在使用用户凭据时,另一个障碍是工具的支持缺乏。我们将在本章后面讨论的许多 Azure 存储工具仅接受存储密钥,因此您可能需要使用用户凭据登录到 Azure 门户并复制存储密钥以供使用。
SAS 令牌
SAS 令牌是仅授予对存储帐户中某些对象的访问权限的密钥。例如,SAS 令牌用于启用 OneDrive、SharePoint Online、Office 365、Dropbox 和类似服务中的“共享文件”选项。
Azure SAS 令牌格式为指向 Azure 存储的 URL,其中包含一长串参数和一个独特的 SHA256 哈希值,经过 base64 编码,类似这样: storagerm.blob.core.windows.net/container/file.txt?st=2017-04-09T01%3A00%3A00Z&se=2017-04-20T01%3A00%3A00Z&sp=r&sip=127.0.0.1-127.0.0.100&sig=7%2BwycBOdzx8IS4zhMcKNw7AHvnZlYwk8wXIqNtLEu4s%3D。
渗透测试人员可能会发现 SAS 令牌并不特别有用,不仅因为它们通常只对一小部分文件有效,还因为它们可能已分配了某些权限(通过 SP 参数),例如只读。SAS 令牌也可以指定只能从特定的 IP 地址或范围(通过 SIP 参数)使用,因此即使你得到了一个 SAS 令牌,它也可能只对原本创建它的机器有效。SAS 令牌还可能有指定的开始和结束时间(通过 ST 和 SE 参数,分别限制令牌的有效期)。
如果这些还不够让你灰心丧气,大多数 Azure 工具并不支持 SAS 令牌。这意味着你可能只能通过 web 浏览器使用它们。而且,如果你偶然找到这些令牌的缓存,逐一查看它们将需要一些时间,从而浪费宝贵的测试时间。话虽如此,如果前两种凭证类型不可用,能够使用 SAS 令牌总比完全没有访问权限要好。
防御者提示
微软提供了关于选择正确存储身份验证选项、常见陷阱、可能的缓解措施以及如何从泄露凭证中恢复的详细指南,详细内容可见于 docs.microsoft.com/en-us/azure/storage/storage-security-guide。
查找存储凭证的位置
现在你知道了需要查找哪些类型的凭证,我们来看看它们可能最常见的几个存放位置:源代码和存储管理工具。对于源代码侦查,你需要访问开发人员的机器或他们的源代码控制系统。要从存储工具中提取密钥,你需要找到这些工具安装的位置;通常这些工具安装在开发人员的工作站上。有了对这些系统的访问权限,你就可以开始寻找密钥。
在源代码中查找密钥
查找存储密钥的最直接方法是通过使用 Azure 存储的应用程序的源代码—通常是在用于构建从 Azure 网站到自定义商业应用程序的配置文件中,这些应用程序使用云来存储数据。你有多种方法可以快速定位源代码中的存储密钥,但应选择的方式取决于你所找到的代码类型。
Microsoft 为 .NET(C# 和 Visual Basic)以及 Java 提供了库,使得访问存储和其他 Azure 功能更加简便。幸运的是,这些库中用于验证 Azure 存储的函数名称是一致的。搜索 StorageCredentials 类的实例,你很可能会找到任何应用程序使用存储密钥的地方。如果这不起作用,可以尝试搜索库的完整名称,比如在 .NET 中是 Microsoft.WindowsAzure.Storage.Auth,在 Java 中是 com.microsoft.azure.storage.StorageCredentials。
如果你怀疑某个存储实例可能使用了 SAS 令牌,可以在代码仓库中搜索 .core.windows.net,这是所有 SAS 令牌 URL 中使用的域名。(SAS 令牌中的 base64 签名应该使它们与任何其他 windows.net 域名引用易于区分。)
许多代码库将存储账户密钥放入配置文件中,尤其是在与 ASP.NET 和 Azure 网站结合使用时。ASP.NET 和 Azure 网站使用名为 web.config 的文件,而其他网站则通常使用 app.config 文件。配置文件中的存储账户密钥通常标记为 StorageAccountKey、StorageServiceKeys 或 StorageConnectionString(这是某些 Microsoft 文档示例代码中使用的名称)。
你可以通过扫描 azure-storage.common.js 来识别 JavaScript 文件中的 Azure 存储使用。如果你在代码中找到这个脚本引用,还需要查找 AzureStorage.createBlobService;你需要它来进行 Azure 身份验证。(JavaScript 库允许使用存储密钥和 SAS 令牌,但强烈鼓励使用高度限制的 SAS 令牌,因为用户可以查看 JavaScript 代码。)
从开发人员的存储工具中获取密钥
如果你无法在源代码中找到存储密钥,你可以尝试从开发人员用来传输文件到 Azure 的工具中恢复这些密钥。要找到这些密钥,首先需要访问开发人员的工作站,然后查找 Azure 存储管理应用程序。一旦访问成功,检查该应用程序是否在其用户界面中暴露了已保存的密钥,或者是否以不安全的方式保存了密钥。
在本节中,我们将查看最常用的存储账户管理工具,看看它们是否容易受到此类攻击。
防御者提示
在接下来的讨论中,请注意,只有 Microsoft Azure Storage Explorer 使得攻击者恢复密钥变得困难。如果你必须使用工具来管理 Azure 存储,并且系统中缓存了凭据,Microsoft Azure Storage Explorer 是最安全的选择。
从 Microsoft Azure Storage Explorer 获取密钥
Azure Storage Explorer 设计良好,存储密钥保护是其显而易见的目标。它没有显示密钥的选项,一旦密钥被保存在界面中,且加密的密钥被存储在 Windows 凭据管理器中,这使得直接恢复它们变得不实际。
尽管有这些安全功能,但一切并未失去。因为 Azure Storage Explorer 需要解密密钥,以便在传输数据时将其提供给 Azure 的 API,你可以在 Storage Explorer 的代码中设置一个断点,位置在密钥解密后的下一行,然后使用内置调试器直接在内存中查看它们。
要执行此测试,请按照以下步骤进行:
-
在目标工程师的工作站上启动 Azure Storage Explorer。
-
选择帮助 ▸ 切换开发者工具。你应该能看到调试器界面。
-
在调试窗口中,点击屏幕顶部的源代码选项卡,然后点击垂直省略号菜单并选择转到文件,如图 4-1 所示。
![image]()
图 4-1:Azure Storage Explorer 中的源代码视图
-
在出现的文件列表对话框中,输入 AzureStorageUtilities.js 并点击第一个条目加载 AzureStorageUtilities.js 文件,该文件包含加载存储帐户密钥的逻辑。
-
展开调试器窗口,以便查看源代码;然后找到
loadStorageAccounts(host, key)函数,该函数显示在清单 4-1 中。/** * Load the stored storage accounts: * Get account data from localStorage * Combine session key and account data as user account manager key * to get account key stored there. * @param host * @param key */ function loadStorageAccounts(host, key) { --snip-- switch (account.connectionType) { case 1 /* sasAttachedAccount */: account.connectionString = confidentialData; break; case 3 /* key */: account.accountKey = confidentialData; break; default: // For backward compatibility reasons if the // connection type is not set // we assume it is a key account.accountKey = confidentialData; } return account; }); return storageAccounts; }); }清单 4-1:来自 Microsoft Azure Storage Explorer 的代码片段 loadStorageAccounts() 函数
-
在此函数中设置一个断点,位置在帐户信息返回应用程序之前,点击窗口左侧
return account;行号,如图 4-2 所示。 -
现在,为了触发应用程序重新加载帐户信息以便触发断点,点击帐户列表上方的刷新所有。调试器应该会中断并暂停应用程序。查看窗口右侧的帐户:对象变量(如图 4-2 所示),点击
account旁边的箭头展开它。

图 4-2:在调试器中展开的帐户对象
account 对象应列出第一个在 Azure Storage Explorer 中注册的存储帐户的 accountKey 和 accountName。要查看是否有多个帐户,请按 F8 继续执行。如果有更多存储帐户,调试器应立即中断并更新帐户对象,显示下一个帐户的详细信息。继续按 F8,直到你恢复了每个存储帐户的连接信息。
当最后一个存储帐户的详细信息显示后,再次按 F8 以恢复应用程序的正常操作。然后,在右侧窗格的断点列表中右键单击并选择移除所有断点来移除断点。最后,点击帮助 ▸ 切换开发者工具以关闭调试工具,然后退出应用程序。
从 Redgate 的 Azure Explorer 获取密钥
Redgate 的 Azure Explorer 提供了两种方式来访问其中包含的密钥:连接编辑器对话框和每个帐户上下文菜单中的复制选项。要查看帐户密钥,启动 Redgate 的 Azure Explorer,打开帐户,然后右键单击帐户以查看其详细信息,如 图 4-3 所示。

图 4-3:Redgate 的存储帐户菜单
编辑连接详细信息选项会打开一个对话框,如 图 4-4 所示,在这个对话框中你可以更新与存储帐户关联的密钥。对话框方便地以明文显示当前的密钥。

图 4-4:Redgate 的 Azure Explorer 中的存储帐户密钥
复制连接字符串选项也很有趣。你可以用它将密钥以 SQL 连接字符串格式复制到剪贴板,连接字符串中包含密钥本身和帐户名称,还可以指示是否应使用 SSL 或未加密的连接访问存储帐户。使用此选项抓取帐户所需的所有连接信息,然后将其粘贴到一个小文档中。对每个列出的帐户重复此操作。
注意
因为 Redgate 在 Azure Explorer 的设置文件 %UserProfile%\AppData\Local\Red Gate\Azure Explorer\Settings.xml 中加密了存储密钥,你需要能够运行 Azure Explorer 来恢复密钥;你不能仅仅拿到 XML 文件。*
从 ClumsyLeaf 的 CloudXplorer 获取密钥
ClumsyLeaf 软件公司开发了三款用于与云存储交互的产品:CloudXplorer、TableXplorer 和 AzureXplorer。所有这些工具不仅可以管理 Azure 存储,还可以管理其他提供商的存储服务,如亚马逊和谷歌。
CloudXplorer 处理文件和 Blob 存储,而 TableXplorer 为表格型云存储提供类似 SQL 的接口。AzureXplorer 是一个 Visual Studio 插件,旨在简化开发过程中与云内容的交互。
你可以通过在左侧窗格中右键单击存储帐户并选择 属性 来查看和编辑 CloudXplorer 中存储的密钥,如 图 4-5 所示。

图 4-5:CloudXplorer 中的存储帐户上下文菜单
账户窗口(参见 图 4-6)显示当前使用的是哪个 Azure 实例,是否启用了 SSL,并且应该允许你复制存储帐户的名称和密钥。

图 4-6:CloudXplorer 中的帐户信息
注意
CloudXplorer 的配置 ▸ 导出选项会导出所有存储帐户连接的详细信息,但它们是加密的。你可能会发现这不太有用。
与 Redgate 一样,ClumsyLeaf 也将其帐户信息加密存储在 XML 文件中。你可以在 %AppData%\ClumsyLeaf Software\CloudXplorer\accounts.xml 找到它。
从 ClumsyLeaf 的 TableXplorer 获取密钥
要使用 TableXplorer 查看存储账户,点击管理账户,如图 4-7 所示,打开管理账户窗口。

图 4-7:TableXplorer 中的管理账户按钮
管理账户窗口应显示每个账户,如图 4-8 所示。Azure 存储账户标有 Windows 标志,而 Amazon 账户则标有橙色立方体。点击一个账户的名称并选择编辑。

图 4-8:TableXplorer 中的账户列表
编辑窗口将与之前在图 4-6 中显示的 CloudXplorer 窗口相同。此外,像 CloudXplorer 一样,TableXplorer 会加密其配置文件中的密钥,该文件位于%AppData%\ClumsyLeaf Software\TableXplorer\accounts.xml。
从 Azure Storage Explorer 6 获取密钥
Azure Storage Explorer 6 可能是这个列表中最古老的工具。尽管它不再维护,但它曾是标准工具多年,你可能会在许多开发者的系统中找到它,未来几年也可能继续使用。
要通过 Azure Storage Explorer 6 查看存储账户设置,请按照以下步骤操作:
-
启动应用程序并从下拉列表中选择一个账户。
-
选择账户后,点击存储账户 ▸ 查看连接字符串,如图 4-9 所示。
![image]()
图 4-9:Azure Storage Explorer 6 中的存储账户菜单
-
你应该看到一个弹出消息框,显示格式化的 SQL 连接字符串账户密钥,如图 4-10 所示。点击确定将值复制到剪贴板。
![image]()
图 4-10:Azure Storage Explorer 6 中的存储账户连接字符串
在 Azure Storage Explorer 6 版本之前,未加密的凭据存储在%AppData%\AzureStorageExplorer\AzureStorageExplorer.config中,因此每当你怀疑某台机器被用来管理存储账户时,这个文件是一个值得查找的文件。从版本 6 开始,这些设置被加密并移动到%AppData%\Neudesic\AzureStorageExplorer<Version>\AzureStorageExplorer6.dt1。然而,由于 Azure Storage Explorer 是开源的,并且每次安装使用相同的加密密钥,所以非常容易在网上找到它用来“保护”这些文件的加密密钥,以及加密和解密代码。当然,从 GUI 恢复存储密钥更容易,但如果你无法在目标系统上启动应用程序,那么有其他选项也会很有帮助。
访问存储类型
一旦你访问了存储账户,就该了解可以获取何种类型的数据了。首先,你需要确定每个账户使用了哪种存储机制(Blob、表、队列和/或文件),并记住一个账户可以使用多个存储机制。务必检查每个账户的每种存储类型。
识别正在使用的存储机制
虽然你可以使用 Azure 门户检查存储账户的内容,但渗透测试者在使用这种方法时可能会面临一些挑战。首先,账户可能只有一个管理证书,这将无法提供直接的门户访问权限。其次,Azure 门户不会在一个视图中显示每种存储类型的摘要;你需要点击每个账户,点击查看该账户中的任何 Blob,然后点击查看文件的按钮,依此类推。当订阅中包含大量存储账户时,这个过程需要花费一些时间。
识别正在使用的存储类型最好的方法是使用 PowerShell。例如,下面的 PowerShell 脚本在列表 4-2 中显示,将枚举订阅中的所有存储账户,检查每种存储机制的内容,然后显示它找到的任何内容的摘要。
# ASM Storage Accounts
Write-Output ">>> ASM <<<"
➊ $storage = Get-AzureStorageAccount
foreach($account in $storage)
{
$accountName = $account.StorageAccountName
Write-Output "======= ASM Storage Account: $accountName ======="
➋ $key = Get-AzureStorageKey -StorageAccountName $accountName
➌ $context = New-AzureStorageContext -StorageAccountName `
$accountName -StorageAccountKey $key.Primary
➍ $containers = Get-AzureStorageContainer -Context $context
foreach($container in $containers)
{
Write-Output "----- Blobs in Container: $($container.Name) -----"
➎ Get-AzureStorageBlob -Context $context -Container $container.Name |
format-table Name, Length, ContentType, LastModified -auto
}
Write-Output "----- Tables -----"
➏ Get-AzureStorageTable -Context $context | format-table Name -auto
Write-Output "----- Queues -----"
➐ Get-AzureStorageQueue -Context $context |
format-table Name, Uri, ApproximateMessageCount -auto
➑ $shares = Get-AzureStorageShare -Context $context
foreach($share in $shares)
{
Write-Output "----- Files in Share : $($share.Name) -----"
➒ Get-AzureStorageFile -Context $context -ShareName $share.Name |
format-table Name, @{label='Size';e={$_.Properties.Length}} -auto
}
Write-Output ""
}
Write-Output ""
# ARM Storage Accounts
Write-Output ">>> ARM <<<"
$storage = Get-AzureRmStorageAccount
foreach($account in $storage)
{
$accountName = $account.StorageAccountName
Write-Output "======= ARM Storage Account: $accountName ======="
$key = Get-AzureRmStorageAccountKey -StorageAccountName `
$accountName -ResourceGroupName $account.ResourceGroupName
$context = New-AzureStorageContext -StorageAccountName `
$accountName -StorageAccountKey $key[0].Value
$containers = Get-AzureStorageContainer -Context $context
foreach($container in $containers)
{
Write-Output "----- Blobs in Container: $($container.Name) -----"
Get-AzureStorageBlob -Context $context -Container $container.Name |
format-table Name, Length, ContentType, LastModified -auto
}
Write-Output "----- Tables -----"
Get-AzureStorageTable -Context $context | format-table Name -auto
Write-Output "----- Queues -----"
Get-AzureStorageQueue -Context $context |
format-table Name, Uri, ApproximateMessageCount -auto
$shares = Get-AzureStorageShare -Context $context
foreach($share in $shares)
{
Write-Output "----- Files in Share : $($share.Name) -----"
Get-AzureStorageFile -Context $context -ShareName $share.Name |
format-table Name, @{label='Size';e={$_.Properties.Length}} -auto
}
Write-Output ""
}
列表 4-2:通过 PowerShell 列出存储账户使用情况
这个脚本分为两部分:第一部分搜索 ASM 存储账户,第二部分搜索 ARM。
我们首先获取订阅中所有 ASM 存储账户的列表 ➊。对于每个账户,我们获取密钥 ➋ 然后为该存储账户创建一个 上下文 ➌——一个包含存储账户名称和密钥的 PowerShell 对象。以后访问存储账户时,我们可以使用这个上下文。
接下来,脚本开始检查不同的存储类型,如后续章节所讨论的内容,然后对 ARM 存储账户重复该过程。
访问 Blob
Blob 是 Azure 中最基本的存储形式:它是一个无结构的比特集合,应用程序可以自由使用。Blob 最常用于存储 Azure 虚拟机的虚拟硬盘文件。
在 Azure 中,你会发现三种类型的 Blob:页面 Blob、追加 Blob 和 块 Blob。作为渗透测试者,了解每种 Blob 类型的主要用途可能会很有帮助,这样你可以在不必下载的情况下,对给定的 Blob 内容做出合理的猜测。在我的评估中,我发现下载一个数十 GB 的文件需要几个小时,而最终发现它并不是我预期的内容,这种情况令人非常沮丧。
-
页面 Blob 由一组字节组成,称为 页。每个页的大小为 512 字节,页面 Blob 本身的最大大小可以达到 1TB。总大小必须在创建 Blob 时设置,这意味着页面 Blob 文件可能会非常大,但其中只有一小部分是数据,其余部分可能是空的。由于页面 Blob 在随机读写操作时非常高效,因此它们是用于硬盘映像的 Blob 类型。
-
追加块优化了添加新数据的操作,但禁止修改现有数据。它们最大可达 195GB,特别适合日志文件。如果你正在尝试识别可能与评估相关的其他用户帐户、IP 地址或服务器,那么日志文件可能会非常有用;然而,如果你只是希望修改日志以抹去痕迹,追加块将无法让你做到这一点。
-
块 Blob 是默认类型。它由一个或多个字节块组成,块的大小可以最大为 100MB。一个 Blob 中最多可以包含 50,000 个块,块 Blob 可以根据需要增长。这种类型用于所有其他类型的非结构化数据。
Azure 要求用户将所有 Blob 存放在 容器 中,容器类似于文件目录,只是它不能嵌套。换句话说,容器可以包含 Blob,但不能包含其他容器。每个存储账户可以有无限数量的容器,每个容器中可以包含任意数量的 Blob。
清单 4-2 中的脚本通过 Get-AzureStorageContainer cmdlet 获取 ➍ 所有 Blob 容器的列表,然后使用 Get-AzureStorageBlob 为每个容器打印一张表,每个 Blob 占一行 ➎。表格包括 Blob 的名称、大小、数据类型及最后修改日期,如清单 4-3 所示。浏览此列表,查找有用的文件,忽略任何 .status 文件和大多数日志文件,而应关注文档、源代码和配置文件。一旦你列出了感兴趣的文件,使用 Azure 存储管理工具开始收集这些文件。

清单 4-3:Blob 命令的输出
要查看 Blob 的内容,Microsoft Azure 存储资源管理器可能是渗透测试人员的最佳选择。它是免费的,能够正确显示所有类型的 Blob,并支持打开 ASM 和 ARM 存储。或许最重要的是,它提供多种登录选项来访问存储账户,包括以下几种:
-
共享访问签名令牌
-
SQL 连接字符串格式中的存储账户密钥
-
存储账户名称和密钥
-
有权访问订阅的用户的用户名和密码
用户名和密码登录功能特别好,因为它会自动填充用户可以访问的每个订阅的存储账户。你还可以添加多个用户账户,这样你就可以同时查看每个被侵入账户的文件。
在将所有存储账户添加到 Microsoft Azure 存储资源管理器后,展开所需存储账户下的 Blob 存储部分;然后浏览容器列表,选择感兴趣的文件,点击 下载 按钮即可下载一份副本,如图 4-11 所示。

图 4-11:从 Microsoft Azure 存储资源管理器下载 Blob
一旦你获取了文件,一定要检查其中是否有其他凭证。我发现 Azure 存储中存储了令人惊讶数量的机密数据。这使得它成为获取更多系统或服务访问权限的绝佳途径,进一步深入目标环境。
DEFENDER 提示
Azure 存储 Blob 不是存储未加密机密的理想场所。由于访问密钥提供了广泛的访问权限和否认权限,机密应该存储在其他地方——或者至少要加密,并且加密密钥不应存储在同一存储帐户中。虽然 Azure Key Vault 并非完全免受攻击,正如我在第七章中所讨论的那样,但它是一个更适合存储机密的选择。
访问表格
表格提供了在 Azure 中存储表格数据的功能。它们非常适合存储半结构化数据,如 Web 服务日志或网站内容数据库,是 SQL Server 等资源密集型、成本更高的数据库解决方案的良好替代选择。
清单 4-2 调用了 Get-AzureStorageTable cmdlet ➏,该命令将返回提供的存储上下文中的所有表格名称,如清单 4-4 所示。你还可以使用 Azure 表格的唯一另一个 cmdlet,Get-AzureStorageTableStoredAccessPolicy,它显示表格的任何特殊权限。我很少看到访问策略在使用中,因此通常会跳过它。由于 PowerShell 选项有限,你需要使用独立的工具来访问表格中的数据。
----- Tables -----
Name
----
TestTable
TransactionAudits
SchemasTable
清单 4-4: Get-AzureStorageTable 命令的输出
选择正确的工具很容易,因为选择不多。主要的工具有 Microsoft Azure Storage Explorer 和 ClumsyLeaf 的 TableXplorer。在这种情况下,尽管 TableXplorer 不是免费软件,我更倾向于使用它,因为它非常快速,提供导出数据的选项,并且提供如图 4-12 所示的查询选项,该选项使用普通的 SQL 语法。这个最后的功能让任何有 SQL 背景的人都能轻松识别数据。Microsoft Azure Storage Explorer 也有查询功能,但它不支持 SQL 语法,且比 TableXplorer 更慢。
在 TableXplorer 中,你可能会看到一些以 $Metrics 开头的表格,这些表格在使用 PowerShell 时并不会出现。Azure 会自动生成并使用这些表格来存储关于它们所处的存储帐户的详细信息。名称开头的美元符号($)标记这些表格为隐藏,因此 PowerShell 不会列出它们。

图 4-12:使用 TableXplorer 使用 SQL 语法查询 Azure 存储表格
这些度量表中的数据追踪了像存储的 blob 总数以及任何具有计费影响的事务,比如数据的添加或删除。这些文件对攻击者通常没有太大价值,除非他们想查找显示他们对存储账户执行的活动的日志条目。不幸的是,你不能删除这些条目,因为度量表是只读的。
访问队列
Azure 存储队列提供了一个排队事务的地方,可以按顺序处理这些事务,当资源变得可用时。主要是软件开发人员使用队列;毕竟,除了开发人员,很少有人需要担心按顺序处理数据。
从渗透测试的角度来看,我曾经觉得队列很无聊。它们通常是空的,等待工作流入,然后在任务处理完毕后迅速被清空。然而,当我看到队列被用来向服务器发送未签名的命令以供执行时,我改变了看法。许多安全研究人员会花费数周甚至数月的时间来寻找漏洞软件,并开发远程代码执行漏洞——让另一台计算机上的进程执行攻击者控制的代码。在这里,它不是一个漏洞,而是一个故意的功能!
尽管那个特定的实例是极端情况,但如果开发人员不小心,队列实际上容易导致这种行为。开发人员通常将它们作为某个自定义应用程序的输入,比如订单履行系统。应用程序的开发人员可能期望队列中只包含来自他们拥有的另一个受信任系统的工作项,比如他们网站上的订单页面,因此开发人员忽视了对工作项字段进行适当验证。这意味着攻击者可以将他们自己的自定义消息注入队列,而处理它们的服务可能不会确认这些消息中的数据是否合理。如果这些字段恰好包含商品的价格、应该发送支付款项的银行账户,或者应该执行的系统命令,那么攻击者就找到了一个优先级非常高的漏洞。
防御者提示
如果你使用队列传输机密数据,或者发送必须来自已验证来源的命令,应该使用非对称加密来加密或签名消息,在它们被放入队列之前。然后,接收者可以解密消息或验证其签名,以确保消息是原始的,并且没有被篡改。
队列通常用作后端服务,开发人员通常使用它们来促进应用程序之间的通信,因此它们有良好的 API 支持,而且与队列的交互通常需要编写自定义应用程序。PowerShell 只有两个相关的 cmdlet 用于显示队列信息。一个是 Get-AzureStorageQueue,在清单 4-2 ➐中的脚本中,我用它来列出队列及其当前的消息数量,如清单 4-5 所示。第二个是 Get-AzureStorageQueueStoredAccessPolicy,它用于查看 SAS 令牌的权限和限制,这些权限和限制很少使用。请注意,没有 cmdlet 用于创建或查看队列中的项目。
----- Queues -----
Name Uri ApproximateMessageCount
---- --- -----------------------
testqueue https://storeasm.queue.core.windows.net/testqueue 0
清单 4-5: Get-AzureStorageQueue 命令的输出
要实际查看和插入队列中的消息,你必须再次使用 Microsoft Azure Storage Explorer。在其界面中,选择一个存储帐户,展开该帐户下的队列列表,然后选择一个队列。这将打开一个视图,显示所有当前排队的消息,并允许你查看消息的内容或插入新消息。我建议在尝试插入自己的消息之前,先检查任何现有消息,以了解有效消息的格式。如果队列为空,尝试找到处理这些消息的应用程序源代码,看看它期望什么。
警告
像其他编程语言中的队列数据结构一样,Azure 队列有两个与查看消息相关的功能。你可以使用 PeekMessage 查看队列中的下一个消息而不更改或移除它。另一方面, GetMessage 会实际从队列中取出项目,并使其对任何其他使用队列的程序不可见。如果你只是使用 Microsoft Azure Storage Explorer,你不必担心这个问题,但如果你开发了一个自定义应用程序来监视队列,调用 GetMessage 可能会阻止 Azure 处理来自队列的合法请求。所以,在使用这些 API 之前,一定要完全理解它们!
访问文件
Azure Storage 最新的服务,称为 Azure Files,是一个基于云的 SMB 文件共享服务。它允许用户创建共享目录并填充文件,就像在本地文件服务器中一样。这对于将依赖 SMB 共享的传统应用程序迁移到 Azure 非常有用。Azure Files 支持从客户端连接,前提是这些客户端支持 SMB 2.1 或 SMB 3.0 协议。
虽然 Azure Files 旨在作为现有企业文件服务器的替代品,但它确实存在一些局限性。首先,任何连接到它的客户端必须能够通过原生的 SMB 端口:TCP 445\。这可能听起来不是大问题,但一些公司网络会在双向阻止 TCP 445 流量,因为文件共享通常被视为内部资源。然而,与传统 Windows 文件服务器的最大区别是没有用户账户和权限。
在普通的 SMB 共享中,用户可以为任意数量的用户或组分配读取、修改和完全控制权限。此外,用户还可以为这些共享中的文件指定文件系统级别的权限,以进一步限制访问。
Azure Files 是不同的。按照设计,它的共享只有一个用户,并且无法配置。共享的用户是 AZURE\存储帐户名称,密码是该存储帐户的主密钥,再次突显了保护存储帐户密钥免受未经授权访问的重要性。因此,要完全访问名为 myshare 的 Azure Files 共享,该共享位于名为 mysa 的存储帐户中,您需要在 Windows 命令行中运行以下命令:
net use * \\mysa.file.core.windows.net\myshare /u:AZURE\mysa Primary_Key
注意
从远程机器到 Azure Files 的连接仅限于支持 SMB 3.0 的 Windows 主机,因为 Linux 和早期版本的 Windows 不支持加密的 SMB 连接。Linux 和旧版 Windows 可以连接到 Azure Files,但仅在它们是运行在 Azure 中的虚拟机,并且处于同一区域时才能连接。
要枚举共享,使用 Get-AzureStorageShare cmdlet,如清单 4-2 中所示的 ➑。对于每个共享,您可以使用 Get-AzureStorageFile cmdlet 查看该共享中的文件列表。在 清单 4-2 的 ➒ 处,我将 Get-AzureStorageFile 的输出通过管道传递到格式化表命令中——并使用了一些相当难看的参数——以在一行中显示每个文件,并包括文件的名称及其大小(以字节为单位)。因为文件大小被埋藏在每个文件对象的属性中(并被称为“Length”),所以需要使用 PowerShell 的哈希表语法来显示它。-auto 开关会自动调整表格的列宽。结果输出显示在清单 4-6 中。
----- Files in Share : asmshare -----
Name Size
---- ----
testfile.txt 33
清单 4-6:文件命令的输出
除了使用 PowerShell 和 Windows 内置的 SMB 连接功能外,您还可以通过 Microsoft Azure Storage Explorer 查看 Azure Files(见图 4-13)。

图 4-13:使用 Microsoft Azure Storage Explorer 访问 Azure Files
Microsoft Azure Storage Explorer 并未提供比 PowerShell 和 Windows SMB 客户端组合更多的功能,但它通过使用 Azure 的 API 进行访问,而非直接通过 SMB 连接,从而绕过了 TCP 445 防火墙问题。它还提供了一个名为连接虚拟机的便捷按钮,能够自动创建并显示格式正确的 net use SMB 命令,帮助你通过 Windows 连接共享。
总结
在本章中,我们讨论了 Azure 存储身份验证设计中的一些设计限制,以及攻击者可以用来访问 Azure 存储的不同类型凭证:存储账户密钥、用户名和密码,以及共享访问签名。接下来,我们检查了攻击者通常会找到凭证的地方,如源代码、配置文件,以及存储在各种存储管理工具中的凭证。然后,我们讨论了 Azure 中可用的不同类型存储,包括 Blob、表、队列和文件,并分析了攻击者如何访问它们。利用这些信息,你可以从目标的存储账户中提取所有数据,这些数据通常包括文档、日志文件、硬盘镜像和源代码。
在下一章,我们将探讨 Azure 存储的最大用户:Azure 虚拟机。
第五章:虚拟机目标

每个渗透测试人员可能会遇到大量的 Azure 虚拟机(VM)。正如你将在本章中学习的那样,攻击者可以利用 Azure 存储作为窃取秘密并控制 Azure 虚拟机的途径。只要获得适当级别的访问权限,攻击者就能完全控制运行在虚拟机上的任何服务,并秘密收集连接到这些虚拟机的用户数据。
为了演示这一点,我首先展示如何在不访问 Azure 门户的情况下获取虚拟机的 虚拟硬盘(VHD) 镜像。一旦获得虚拟机的 VHD 副本,我将解释如何提取重要数据。最后,我将展示如何在 Azure 门户中利用虚拟机密码重置选项。
最佳实践:虚拟机安全
虚拟机是最常见的云工作负载之一,因为它们允许企业快速将本地服务器迁移到云端。尽管虚拟机是利用云的好方式,且工程投入有限,但如果公司没有充分考虑因此类迁移可能遇到的新威胁,这种方式可能会带来安全问题。
最重要的是,内部服务器的管理员往往理所当然地认为公司网络边界上的防火墙和其他安全设备已经足够。默认情况下,云托管的虚拟机是面向互联网的,因此每个开放的端口都必须经过仔细考虑,只有最少数量的服务暴露出来,因为每个端口都可能成为攻击目标。除了虚拟机的主机防火墙外,还应使用网络安全组来限制对所有不需要的端口的访问。此外,对于那些只需要从其他云资源访问的虚拟机,考虑使用不面向互联网的虚拟网络。
如果你确实将管理服务暴露到互联网上,比如 RDP 或 SSH,可以通过确保系统上的用户账户使用不常见的账户名(避免使用常见的特权账户名,如administrator、admin和root)以及强密码,或者在可能的情况下使用基于证书或多因素身份验证,来降低成功进行密码喷射或暴力破解密码攻击的风险。鼓励使用密码管理器,以便用户不必担心记住奇怪的用户名和复杂的密码。
接下来,在可能的情况下,利用虚拟机的全盘加密来保护其上的任何数据。这可以防止离线分析 VHD,如在 “使用 Autopsy 探索 VHD” 第 95 页 中所述。Azure 磁盘加密是一种方便的加密 VHD 的方式。它利用密钥保管库来存储磁盘的加密密钥,因此你不需要担心管理这些密钥。这是 Azure 中的免费服务,适用于大多数虚拟机定价层。
最后,确保正在监控所有与 VM 相关的事件。启用 Azure 的 VM 日志并将其包含在你的蓝队安全日志分析工具中是一个好的开始。然而,使用 Azure 安全中心(ASC)和运营管理套件(OMS)可以检测更多事件。ASC 监控 VM 的已知威胁,而 OMS 为安装其代理的任何系统提供详细的日志。两种解决方案在第八章中有详细介绍。
虚拟硬盘盗窃与分析
因为可以在没有完全访问订阅的情况下获取 Azure Storage 凭证(如第四章中所述),攻击者可能仅凭存储帐户密钥就能控制正在运行的 VM。为了做到这一点,攻击者需要获取 VHD,检索存储在 VHD 上的密码或证书,然后使用这些密钥访问 VM。让我们首先看看渗透测试人员如何获取 VM 的 VHD 副本。
下载 VHD 快照
为了下载磁盘映像,你需要获取存储帐户的密钥,该帐户包含所需 VM 的 VHD。如果你有订阅权限,可以直接从 Azure 门户获取密钥,或者通过 Azure PowerShell 的Get-AzureRmStorageAccountKey cmdlet 获取。此外,如果你没有订阅权限,也可以使用第四章中描述的任何存储密钥恢复方法。一旦获得了存储凭证,启动 Microsoft Azure Storage Explorer 或 ClumsyLeaf CloudXplorer。这是能够创建 Azure Storage 中文件快照的唯一两个工具。我将展示如何使用 Microsoft Azure Storage Explorer,因为它是免费的选项。
注意
如果你尝试从 Azure 下载一个正在使用中的文件,比如正在运行的 VM 使用的 VHD,下载将会中断,文件将损坏或不完整。快照 API 会创建一个一致的(即不损坏的)时间点副本,你可以复制它。因为你无法判断 VHD 是否正在使用,所以你应该始终假设它正在使用并创建快照。
按照以下步骤在 Microsoft Azure Storage Explorer 中下载快照:
-
点击你想复制的 VHD 文件,然后点击功能区菜单中的创建快照按钮,如图 5-1 所示。
![image]()
图 5-1:在 Microsoft Azure Storage Explorer 中为 VHD 创建快照
-
点击管理快照按钮。你应该能在文件列表中看到所有选定文件的快照。它们的名称应以 VHD 的名称开始,后面跟着括号中的日期和时间。
-
要将快照保存到你的 PC,选择快照并点击功能区中的下载按钮。
确保在下载完 VHD 快照后,从存储帐户中删除该快照。用户不仅可能注意到重复的文件,而且重复的文件还会占用额外的存储空间,导致订阅的月度账单产生额外费用。尽管在复制 VHD 时保留快照一两个小时可能不会被注意到,但一个月的费用,如果是数百 GB 的 Blob 存储量,对于一个精明的会计来说是显而易见的。
DEFENDER’S TIP
Azure 存储分析日志会记录 Azure 存储活动,包括 Blob、队列和表的操作。这包括成功和失败的身份验证尝试、上传、下载、删除和快照操作。务必启用此功能,并查看这些数据以识别异常活动。有关更多信息,请参见 docs.microsoft.com/en-us/rest/api/storageservices/enabling-storage-logging-and-accessing-log-data/。
此外,账单数据可以是一个意外有用的工具,帮助你发现是否有人正在利用你的订阅。如果你预计订阅的使用情况从月到月保持不变,那么费用的突然变化就值得调查。原因可能是一些无害的因素,比如 Azure 费率的变化,但也有可能是有人在你的订阅中运行额外的服务,进行不正当的活动!
要在 Microsoft Azure Storage Explorer 中删除快照,点击文件列表中的快照以选中它,然后点击工具栏上的 删除 按钮。如果没有看到列出的快照,首先点击工具栏菜单中的 管理快照。
获取 VHD 的秘密
一旦你在计算机上有了 VHD 的副本,可以查看其中有用的信息。需要查找的文件取决于客户操作系统,但目标是相同的:找出那些本身具有渗透测试价值的信息(例如,尚未发布的财务数据),或者那些可以帮助你进一步访问目标系统的信息(例如,密码)。
找到用于盗取 VHD 的同一虚拟机的密码是非常值得追求的。虽然拥有该凭证在手中有 VHD 后可能看起来没有意义,但一旦你找到了密码,你就可以在运行的虚拟机上执行许多有效的操作,而这些操作在静态的 VHD 副本上无法进行。例如,通过访问虚拟机,你可以运行 Mimikatz 查找尚未获得的凭证。你还可以修改虚拟机上的运行服务,秘密地将信息转发给你。你甚至可以用它发送钓鱼邮件,因为用户通常会更信任他们已经知道的服务器链接。可能性仅受限于你的想象力。
审查 VHD 文件的内容可能会成为一项漫长的计算机取证工作,具体取决于你获得的 VHD 数量。由于你可能没有时间逐一检查每个磁盘映像中的所有文件,因此让我们重点关注几个通常最有价值的关键领域。
使用 Autopsy 探索 VHD
在你可以查看 VHD 内容之前,你必须找到一种方法来打开它。如果你使用的是 Windows 10,且目标虚拟机也运行 Windows 版本,你应该能够右键点击 VHD 并选择 Mount,将 VHD 作为一个新的虚拟磁盘挂载到 Windows 文件资源管理器中。如果你在运行 Linux,并且安装了 VHD 库,你应该能够使用 mount 命令来挂载 VHD。然而,我更喜欢使用像 Autopsy 这样的磁盘取证工具来探索 VHD。使用磁盘取证程序相对于原生挂载选项有几个优势:
广泛的磁盘格式支持 Windows 只能挂载 NTFS 和 FAT 格式的磁盘映像,而取证工具可以打开多种格式——即使是在 Windows 上运行时。而在 Linux 上,取证工具通常比 Linux 本身更擅长读取不常见的格式。
更好的恶意软件保护 当你直接将一个不可信的文件系统挂载到你的系统中时,存在 VHD 上的任何恶意软件可能感染宿主系统的风险。通过使用取证工具只提取几个特定的感兴趣文件,你可以大大降低这个风险。
VHD 完整性保护 取证工具旨在以只读模式挂载磁盘映像,这样可以防止你意外修改或删除 VHD 中的文件。这不仅可以避免错误,还能帮助你在展示发现时消除怀疑。
恢复删除文件的能力 取证工具专门用于恢复用户已删除但尚未被新数据覆盖的磁盘映像中的文件。你可能会发现一些非常有趣的文件,这些文件在使用原生挂载命令时是看不到的。
我常用的取证工具是免费的开源软件 Autopsy (www.sleuthkit.org/)。它可以在 Windows、Linux 和 macOS 上运行。尽管它缺少一些商业取证程序的高级功能和打磨,但它对于渗透测试已经足够,并且避免了与小众商业工具相关的高成本。
导入 VHD
无论你的计算机操作系统或 VHD 的操作系统是什么,使用 Autopsy 导入 VHD 进行检查的步骤如下:
-
启动 Autopsy,并在欢迎界面上选择 Create New Case。
-
为案件命名(使用虚拟机的名称),并选择一个目录以便 Autopsy 保存其工作文件。点击 Next。
-
将 Case Number 和 Examiner 字段留空,然后点击 Finish 以打开 "Add Data Source Wizard"。
-
在 "Add Data Source" 窗口中,浏览到下载的 VHD,选择它,然后点击 Next。
-
配置导入模块屏幕,如图 5-2 所示,允许您选择 Autopsy 对 VHD 执行的后处理操作,例如创建搜索索引和所有图片的缩略图。做出选择后,点击下一步,然后在下一个屏幕上点击完成。

图 5-2:在 Autopsy 中选择导入选项
注意
导入是取证软件用来自动扫描被检查磁盘内容的过程,并为检查员标出感兴趣的项目。Autopsy 提供了多种预配置的导入选项,如电子邮件和信用卡号识别以及照片提取。它还支持自定义过滤器,供检查员添加自己的过滤条件。
此时,您应该已经进入了 Autopsy 的主界面,如图 5-3 所示。双击目录列表区域中的 VHD 文件,您将看到 VHD 内分区的列表,包括代表虚拟磁盘中未使用空间的未分配分区。

图 5-3:使用 Autopsy 导航磁盘映像
如果 Autopsy 无法加载 VHD,可能是 VHD 已损坏,应该重新下载,或者 VM 所有者启用了 Azure 磁盘加密,在这种情况下,您无法继续操作。要检查是否启用了加密,可以尝试在 Windows 系统上使用 PowerShell 挂载 VHD:
PS C:\> Mount-DiskImage -ImagePath C:\temp\file.vhdx -StorageType VHDX
-Access ReadOnly
如果镜像已损坏,PowerShell 会显示错误文件或目录已损坏,无法读取。如果它被加密,则会打开一个新的 Windows 资源管理器窗口,尝试显示 VHD 的内容,但会报告驱动器无法访问。
防御者小贴士
Azure 磁盘加密允许您加密存储在 Azure 中的 VHD 内容。它利用 BitLocker 为 Windows 虚拟机和 DM-Crypt 为 Linux 虚拟机提供完整的磁盘加密,因此如果 VHD 从 Azure 中移除,您将无法读取其内容。VHD 的加密密钥存储在 Azure 密钥保管库中。请注意,要使用 Azure 磁盘加密,您必须使用标准或高级虚拟机,并且虚拟机必须基于 ARM 架构。您可以在docs.microsoft.com/en-us/azure/security/azure-security-disk-encryption/了解更多关于 Azure 磁盘加密的信息。
当 VHD 加载时,双击第一个未标记为未分配的分区。您应该看到 VHD 中的文件列表,如图 5-4 所示。

图 5-4:在 Autopsy 中检查 VHD
在此界面中,浏览文件系统以寻找感兴趣的文件。您可以使用屏幕下方的内置十六进制查看器预览文件。要进一步查看文件,选择该文件,右键点击它,然后选择提取文件将文件保存到您的主机系统中。
现在让我们看看在 Windows 和 Linux VHD 中最有趣的一些文件。
分析 Windows VHD
当我分析虚拟机的磁盘时,我的首要任务是收集凭据。分析 Windows VHD 时,我首先从 \Windows\System32\config\SAM 中的 Security Account Manager (SAM) 数据库开始。SAM 存储所有本地非域用户的密码哈希,如本地管理员账户。Windows 使用一个加密密钥,称为 Syskey,来保护 SAM。你可以在 \Windows\System32\config\SYSTEM 中找到这个密钥。
下面是解密 SAM 文件并获取哈希的方法:
-
使用 Autopsy 从 VHD 中提取 SYSTEM 和 SAM 注册表蜂巢文件到你的计算机中。
-
启动 Cain & Abel(可从
www.oxid.it/cain.html获取)。 -
点击 Cracker 选项卡。
-
点击 文件 ▸ 添加到列表。
-
选择 从 SAM 数据库导入哈希 选项。
-
点击 SAM 文件名旁边的浏览按钮 (...),选择提取的 SAM 文件。
-
点击启动键旁边的浏览按钮,选择提取的 SAM 文件。
-
在打开的 Syskey 解码器框中,点击浏览按钮并选择你提取的 SYSTEM 文件。
-
高亮并复制显示的启动键。
-
关闭 Syskey 解码器框,然后将密钥粘贴到启动键字段中。
-
点击 下一步。
你应该能够看到系统中每个账户的哈希,如 图 5-5 所示。(我们将在 “密码哈希攻击工具” 一节中,讲解如何处理这些哈希,具体包括 Cain & Abel 如何利用它们获取明文密码,详见 第 103 页)

图 5-5:Cain & Abel 中的哈希
除了密码之外,在检查 VHD 时,我还对源代码、配置文件和文档感兴趣。你会找到什么取决于虚拟机的使用方式以及安装的软件。检查这些位置,如果存在的话,可能会找到有价值的内容:
-
\InetPub 目录用于存放网站源代码和配置文件(通常是 web.config)。这些文件可能包含密码和其他秘密信息。
-
每个用户在 \Users 下的主目录——特别是他们的 Documents 文件夹,用于存放关于目标环境的规格说明和部署文档;Desktop 文件夹,用于存放文档、密钥和笔记;Downloads 文件夹,用于提供关于在虚拟机上可能使用的工具的线索;以及 AppData\Roaming 文件夹,用于存放包含网页历史、Cookies 和保存的密码的 Internet Explorer、Firefox 和 Chrome 子目录。
-
SQL 使用的目录。
-
Azure 管理工具使用的任何目录。
-
用于输出计划任务、测试脚本和其他随机信息的临时目录。
-
包含备份的目录。
此外,还应在 VHD 中执行完整的扩展名搜索,查找像.pfx*这样的证书私钥文件;.doc、**.docx、.xls*、.xlsx、**.ppt和.pptx*这些 Microsoft Office 文件;.bak用于备份;**.txt用于笔记,这些文件有时包含密码。你可能还想搜索密码管理器使用的文件,如 KeePass 的.kdx*和.kdbx、Password Safe 的**.psafe3,以及 Dashlane 的.dash*或.dashlane。最后,找到操作系统中没有包含的任何脚本文件,如从除\Windows外的任何目录中找到的**.bat、.cmd*和.ps1*,看看它们的用途。
分析 Linux VHDs
要从 Linux VHD 中提取密码哈希,可以导出/etc/passwd和/etc/shadow文件,以获取用户及其密码哈希的列表。复制/etc/group和/etc/gshadow也是个好主意,以确定用户账户的组成员资格和权限。
/etc/samba、/etc/ssl和/etc/ssh目录应包含系统使用的配置文件和证书。此外,/etc/hostname将包含虚拟机的名称,/etc/fstab将列出虚拟机中挂载的任何其他磁盘,/etc/hosts可能会显示虚拟机与其他服务器交互的静态名称到 IP 的映射。
尝试检索虚拟机上托管的任何网站的源代码和配置文件是个好主意,因为它们可能包含秘密。尤其是 Apache 的.htpasswd和.htaccess文件,它们控制对网页内容的访问。这些文件的常见位置包括/var/www、/usr/share/nginx和/httpd。
用户的主目录是另一个很好的信息来源;这些目录通常位于/home和/root下。保存的用于连接远程系统的安全外壳(SSH)密钥文件以及命令历史记录,通常名为.bash_history,尤其值得关注。命令历史记录通常会包含其他值得调查的服务器名称。查找像ssh、telnet、scp和smbclient这样的命令,以及这些系统的有效用户名。
虽然 Linux 不像 Windows 那样普遍使用文件扩展名,但你仍然应该在 Linux VHD 上执行文件扩展名搜索,因为许多用户和应用程序会使用扩展名。扫描与证书相关的文件(.pfx*、.p12、**.jks),以及 shell 脚本(.sh*)和文本文件(.txt)。你可能还会在数据库文件中发现一些有趣的内容,如**.sql、.db*和.myd*。
破解密码哈希
一旦您成功地从 Linux 或 Windows 虚拟机中获取了密码哈希,您就需要恢复它们的明文值才能使用。哈希是单向的,这意味着您不应该仅凭哈希就能够确定实际的明文密码。但正如您在本节中将看到的那样,有几种可能的方式可以从哈希中恢复密码,包括字典攻击、暴力破解攻击、混合攻击和彩虹表攻击。
字典攻击
在字典攻击中,攻击者编制一个常见单词或短语的列表,然后使用目标服务器密码系统所使用的相同哈希算法对列表中的每个项进行哈希处理。接着,攻击者将每个字典单词的哈希值与密码哈希列表进行比较,并显示匹配项。
如果您拥有目标组织常用的密码列表,或者您怀疑用户使用的是简单的单词密码,这些密码会出现在您编制的英语单词列表中,或者您拥有一个庞大的密码字典,那么字典攻击非常有效。通常可以在线找到这些庞大的字典,尤其是在犯罪分子入侵了一个流行网站并泄露了被盗的密码后。一个好的来源是github.com/danielmiessler/SecLists/。
警告
在使用泄露的密码列表之前,务必与您公司及目标公司中的法律团队进行核实。仅仅因为它们是公开可用的,并不意味着您可以自由使用它们。一些组织可能会认为这些文件是被盗的财产,并且视其为禁用文件。如果您打算使用这些列表,请考虑在您的规则中提到这一点。
暴力破解攻击
在暴力破解密码时,您会生成所有可能的字母、数字和特殊字符的密码组合,然后对其进行哈希处理,直到找到匹配项为止。此方法非常耗时,通常不适用于长度超过八个字符的密码,但它可能会找到一个短密码,这个密码是攻击者在典型字典中找不到的,比如f8i!R+。
混合攻击
混合攻击将字典攻击和暴力破解攻击结合起来,试图快速恢复复杂密码。在这种方法中,攻击者将一个基础字典单词与一系列字符组合,测试结果与哈希值对比,然后继续下一个单词。例如,像hippopotamus200这样的密码可能不会出现在任何字典单词列表中,而暴力破解一个 15 个字符的密码则需要极其长的时间。然而,使用混合攻击的方法,先用一个英语单词,然后加上一个至四个数字,通常会在几小时或几天内找到这个密码。混合攻击的最大缺点是您需要对密码的格式有所了解。例如,“单词加上一到四个字符”的模式将无法成功找到200hippopotamus。
彩虹表攻击
彩虹表攻击有点像暴力破解攻击,攻击者提前计算并存储所有的哈希值,以便与捕获的目标哈希值进行匹配。然而,真正存储所有可能的哈希值对于给定长度的密码来说需要巨大的存储空间,因而不切实际。为了避免这个问题,彩虹表的设计者执行一个复杂的加密操作(称为还原函数),将哈希值串联在一起,并且只存储每个链的开始和结束部分。(要了解具体方法,请参见 Philippe Oechslin 在lasec.epfl.ch/pub/lasec/doc/Oech03.pdf上发布的原始论文。)
为了让攻击者使用彩虹表,一个程序接收目标哈希,并开始通过还原函数将捕获的哈希值传递到预计算的彩虹表中进行计算,查看结果是否与某个链的结尾匹配。如果匹配,它就取出该链的起始值并开始从链的起点进行哈希计算和还原,直到找到创建原始哈希的值。如果捕获哈希的还原版本与任何链的结尾不匹配,它会通过哈希和还原函数再次循环执行,直到正确的链被识别出来。
攻击者优化彩虹表以追求速度或大小:较小的彩虹表将花费更长时间来返回密码(尽管它仍然比暴力破解要快得多),而较大的表则可以更快地返回结果,但会消耗更多的磁盘空间。
尽管彩虹表比本节讨论的其他攻击方式快得多,但它们有三个主要缺点。首先,你必须预先计算它们,因此它们比其他方法需要更多的规划和准备。其次,彩虹表仅适用于一种哈希格式,例如 MD5。这意味着你需要为遇到的每种哈希类型准备不同的彩虹表。至少,你可以在 Windows 上找到 LM 和 NTLM 哈希,而在 Linux 上则可能会遇到 MD5 和 SHA1 哈希。第三,它们对盐值哈希格式无效。
Windows 密码哈希的弱点
对于基于 Azure 的 Windows 虚拟机,Azure 要求用户名不能是admin或administrator,密码长度必须在 12 到 123 个字符之间,并且密码必须包含至少四种字符类型中的三种:小写字母、大写字母、数字和符号。这通常会使暴力破解攻击变得不可行,除非 Windows 为了兼容性原因在 NTLM 和 LM 哈希格式中都存储密码。早期版本的 Windows 使用 LM 哈希格式,而较新的版本使用更安全的 NTLM 格式。LM 存在一些弱点:
-
密码会根据需要用空字符填充,直到总长度为 14 个字符,然后将其分成两部分。两部分分别进行哈希计算,然后连接起来形成最终的 LM 哈希值,因此攻击者只需攻击两个 7 字符字符串的哈希,这可以并行进行。
-
密码限制为 14 个字符。
-
密码中的字母在哈希之前会转换为大写字母,使得它们不区分大小写。
如果用户的密码在 Windows 中少于 15 个字符,它可能会以 NTLM 和 LM 格式同时存储在 SAM 中。当密码少于或等于七个字符时,LM 会将 LM 哈希的第二部分设置为 AAD3B435B51404EE(7 个空字节的哈希值),因此攻击者只需破解第一部分。对于超过 14 个字符的密码,Windows 不会存储 LM 哈希,而是存储默认值 AAD3B435B51404EEAAD3B435B51404EE。Windows 对于没有密码的账户使用相同的哈希值,因此如果你遇到这个值,尝试用空密码登录该账户,你可能会好运!
因为任何存储为 LM 哈希的密码本质上只是两个七个字符密码的哈希,并且由于这些哈希不包含小写字符,所以需要攻击的 LM 哈希的密钥空间相对较小。因此,攻击者可以非常快速地恢复任何存储为 LM 格式的密码。一旦攻击者破解了 LM 哈希,得到的密码可能不是账户的实际密码,因为 LM 哈希是不区分大小写的。因此,攻击者需要对该密码的每种大小写组合执行短时间的暴力破解测试,以便与 NTLM 哈希进行匹配,从而找出最终正确的密码。例如,如果 LM 哈希是密码DOG,用户的实际密码可能是dog、Dog、dOg、doG、DOg、DoG、dOG或DOG。
DEFENDER’S TIP
为了让你的密码更难被攻击,确保它们至少有 15 个字符,以便 Windows 不存储 LM 哈希。此外,确保你的密码包含大写字母、小写字母、符号和数字,并且不是基于词典中的单词。这类密码可能很难记住,因此可以考虑使用一个具有非常强大主密码的安全密码管理器!
密码哈希攻击工具
你可能会使用两个工具之一来进行密码哈希攻击:Cain & Abel 或 hashcat。Cain & Abel 是一款多功能的安全工具,已成为业界标准多年。除了拥有众多功能外,它还具有易于学习的图形用户界面(GUI)。Hashcat 是渗透测试人员工具包中的一个新成员。它没有图形用户界面,只有一个功能:破解哈希。然而,hashcat 在易用性上有所欠缺,但在性能和对大量哈希类型的支持上弥补了这一点。作为渗透测试人员,了解如何使用这两款工具是很有用的。
使用 Cain & Abel 攻击哈希
Cain & Abel 在“Cracker”标签页中提供哈希破解功能(与您在《分析 Windows VHDs》中第 98 页使用的相同标签)。加载哈希到 Cracker 标签页后,选择您要破解的哈希,然后右键点击所选哈希中的任意一个。上下文菜单应会显示三个破解选项:字典攻击、暴力破解攻击和密码分析攻击,如图 5-6 所示。

图 5-6:Cain & Abel 哈希上下文菜单
选择字典攻击后,将呈现一个屏幕,您可以在其中选择字典单词列表,并对字典词条进行一些有限的修改,例如尝试将每个单词转换为全大写或全小写,如图 5-7 所示。
暴力破解攻击选项会打开一个不同的窗口,您可以在其中输入要包含在攻击中的字符,以及尝试的密码长度,如图 5-8 所示。

图 5-7:Cain & Abel 字典攻击窗口

图 5-8:Cain & Abel 暴力破解攻击窗口
Cain & Abel 包含自动调整暴力破解选项的逻辑,具体取决于哈希类型。当您攻击 LM 哈希时,默认的密码空间不包括小写字符,并且预设密码长度为 1 到 7 个字符,这是 LM 哈希的已知限制。一旦攻击开始,Cain & Abel 会显示测试进度,包括每秒尝试的密码数和剩余总时间。
最后,密码分析攻击选项将对哈希进行彩虹表攻击。该攻击的选项窗口非常简单,只提供一个选择路径的选项,用于指定彩虹表的路径。与暴力破解攻击一样,它还会显示攻击的进度。
使用 hashcat 测试哈希
Hashcat 是一个免费的开源跨平台密码哈希破解工具,经过优化,能够充分利用现代显卡的 GPU 处理能力以及 CPU 的处理能力。您可以从 hashcat.net/hashcat/ 下载 hashcat。
与 Cain & Abel 类似,hashcat 提供字典攻击和暴力破解选项,但它在混合模式下表现尤为出色。通过利用 GPU 的强大性能,hashcat 可以每秒测试大量密码组合——可以达到数百万、数十亿甚至数万亿次,具体取决于显卡和哈希类型。hashcat 还支持使用复杂的规则来控制密码生成,这在您能够确定目标公司的密码策略时非常有用。例如,如果您知道所有密码必须至少包含八个字符,并且必须包含数字和符号,您可以通过排除所有不符合这些条件的密码来开始测试。
Hashcat 支持多种哈希格式。与 Cain & Abel 只支持约 30 种哈希格式不同,hashcat 支持超过 200 种格式。如果你遇到一个运行某种操作系统或软件的虚拟机,这些系统或软件保存了自己的密码列表(例如 PeopleSoft、Lotus Notes 或 Joomla),那么这种广泛的支持将非常有用。
要了解如何使用 hashcat,我建议阅读 wiki,链接为hashcat.net/wiki/。请注意,配置错误的 hashcat 任务可能比正确配置的任务花费更长时间,尤其是当字典不合适或规则不正确时。更糟糕的是,匆忙创建的任务可能会无意中排除目标系统的合法密码。在渗透测试过程中,没有什么比因为命令行错误而意识到需要重新启动已经运行了几天的破解任务更令人痛苦的了!
注意
如果你电脑中的 GPU 性能不强,你可能需要考虑在包含 NVIDIA GPU 的专用 Azure 虚拟机上运行 hashcat,这些虚拟机是为计算密集型任务设计的。不幸的是,长时间运行这些虚拟机的成本通常比构建和运行一台配备几块高端显卡的个人电脑要高。不过,在两种情况下,你可能会更倾向于使用 Azure GPU。第一种情况是你需要非常迅速地破解一个非常重要的密码。使用 Azure,你可以创建数十个这样的专用虚拟机,并为每个虚拟机分配不同的密钥空间子集进行测试。另一种情况是,如果你发现密码破解在你的渗透测试中是一个很少使用的技术。在这种情况下,使用 Azure 可能比在 GPU 硬件上进行初始资本投资更有意义。
利用 VHD 的秘密对付虚拟机
一旦你从 VHD 中恢复了用户名和密码,就可以开始评估 Azure 中运行的虚拟机了——但首先,你需要知道如何连接到虚拟机。为此,你需要知道虚拟机的主机名或 IP 地址,并且需要知道虚拟机上运行的远程管理服务及其端口。运行 Windows 的 Azure 虚拟机通常会提供远程桌面协议(RDP),而 Linux 虚拟机通常会开放安全外壳(SSH)。较少情况下,虚拟网络计算(VNC)协议或 telnet 协议会被暴露,但这些协议默认不加密,尤其是在互联网环境下不应使用。
确定主机名
在主机名和 IP 地址之间选择时,我更倾向于使用主机名,因为 IP 地址可能会动态分配。默认情况下,Azure 会根据虚拟机的主机名命名其 VHD。例如,如果一个 VHD 文件名是myazurevm20151231220005.vhd,其主机名通常是myazurevm.cloudapp.net。
当然,VHD 可以被重命名,或者虚拟机(VM)可以被分配一个不同的主机名。如果你发现是这种情况,你可以尝试从 Azure 或 VHD 内部获取主机名信息。最简单的方法是使用 Azure PowerShell 和 Get-AzureVM cmdlet 来返回订阅中每个虚拟机的主机名,但这需要你拥有适当权限的账户。
或者,你可以直接查看 VHD 本身。Windows 将主机名存储在 SYSTEM 注册表区,我们在 “分析 Windows VHDs” 的 第 98 页 中已经导出过此信息。要查看此值,你需要将该文件加载到注册表查看器中。
在 Windows 上恢复 VHD 中的主机名
使用 Windows 内置的 regedit 工具从 VHD 恢复主机名时需要非常小心;因为很容易不小心将虚拟机的注册表值覆盖到你自己电脑的注册表中。一个更好的选择是使用 MiTeC 的 Windows 注册表恢复工具 (www.mitec.cz/wrr.html),操作如下。
-
安装 Windows 注册表恢复工具后,点击 文件▸打开。
-
选择从 VHD 导出的 SYSTEM 文件并点击 确定。
-
点击左侧菜单中的 原始数据 选项(参见 图 5-9)。
-
在中间窗格中,导航到 ROOT\ControlSet001\Control\ComputerName\ComputerName。
-
在右侧窗格中的 ComputerName 字符串应包含主机名,如 图 5-9 所示。
-
如果你看到名为 ControlSet002 或 ControlSet003 的目录位于 ROOT 下,一定要检查它们,因为主机名可能已更改。

图 5-9:从 SYSTEM 注册表区查看主机名
Windows 虚拟机的 VHD 中还有其他可能包含主机名的文件,但 SYSTEM 注册表区是获取主机名的最可靠方法。
在 Linux 上恢复 VHD 中的主机名
在 Linux 上恢复 VHD 中的主机名非常简单。只需定位到 /etc/hostname 文件并显示它。文件中应包含虚拟机的主机名。
查找远程管理服务
一旦你知道了主机名,就应该确定虚拟机是否有可访问的远程管理工具。虽然 RDP、SSH、VNC 和 Telnet 服务有默认端口,但目标虚拟机可能不会使用这些端口,因此你需要确定远程服务使用的是哪个端口。这可以通过使用订阅中的信息、检查已知端口或执行完整端口扫描来完成。
使用 PowerShell
查找虚拟机中任何可访问的远程端口的最佳方法是使用你在“网络信息收集”一节中学习到的 PowerShell 侦察技术,前提是你拥有适当的凭据。此数据将包含从Get-AzureEndpoint和Get-AzureRmNetworkSecurityGroup cmdlet 的输出中获取的允许通过防火墙的每个虚拟机的开放端口。查看此输出并将任何列出的开放端口与表 5-1 中列出的常见管理端口进行比较。
表 5-1: 常见管理端口
| 服务 | TCP 端口 |
|---|---|
| RDP | 3389 |
| SSH | 22 |
| VNC | 5900 |
| telnet | 21 |
| Windows 远程管理(PowerShell 远程) | 5985, 5986 |
如果你发现任何匹配项,尝试使用该协议的客户端连接到虚拟机(VM)。例如,在 Windows 中,你可以使用内置的mstsc.exe应用程序连接到 RDP 端点,使用 PuTTY (www.chiark.greenend.org.uk/~sgtatham/putty/latest.html)连接 SSH 和 telnet,或使用 TightVNC (tightvnc.net/)连接 VNC 服务器。如果你在运行 Linux,通常内置有 SSH、VNC 和 telnet 的客户端。对于 RDP,freeRDP (www.freerdp.com/) 是一个流行的选择。
如果 Windows 远程管理可用,你可以通过 PowerShell 进行连接。为此,运行以下命令:
➊ PS C:\> $s = New-PSSessionOption –SkipCACheck –SkipCNCheck –SkipRevocationChecke
➋ PS C:\> $c = Get-Credential
➌ PS C:\> Enter-PSSession -Credential $c -ComputerName TARGET_IP -UseSSL -SessionOption $s
➍ [TARGET_IP]: PS C:\Users\Administrator\Documents> hostname
WebhostSrv2012
[TARGET_IP]: PS C:\Users\Administrator\Documents> exit
PS C:\>
这将指示 PowerShell 跳过 SSL 证书验证➊(因为你的客户端不信任此主机),提示你输入目标机器的凭据➋,然后进行连接➌。如果连接成功,命令提示符将更改为显示你已连接到远程主机,并且现在可以在该机器上运行命令➍。
测试默认端口
如果无法访问订阅的 PowerShell,可以尝试测试表 5-1 中列出的每个服务的常见默认端口。这可以在 Windows 上使用内置的Test-NetConnection PowerShell cmdlet 快速执行,无需订阅访问权限。只需对每个需要测试的端口运行该命令:
➊ PS C:\> Test-NetConnection -ComputerName TARGET_IP -Port 3389
ComputerName : TARGET_IP
RemoteAddress : TARGET_IP
RemotePort : 3389
InterfaceAlias : Ethernet
SourceAddress : 192.168.0.114
➋ TcpTestSucceeded : True
➌ PS C:\> Test-NetConnection -ComputerName TARGET_IP -Port 21
WARNING: TCP connect to (TARGET_IP : 21) failed
WARNING: Ping to TARGET_IP failed with status: TimedOut
ComputerName : TARGET_IP
RemoteAddress : TARGET_IP
RemotePort : 21
InterfaceAlias : Ethernet
SourceAddress : 192.168.0.114
PingSucceeded : False
PingReplyDetails (RTT) : 0 ms
➍ TcpTestSucceeded : False
在此示例中,尝试连接到端口 3389➊并成功连接➋,而连接端口 21➌失败➍。因为 3389 是 RDP 的端口,我接下来会尝试使用mstsc.exe连接到此虚拟机。
端口扫描
如果测试默认端口失败且你没有适当的 PowerShell 访问权限,则继续进行虚拟机的完整 TCP 端口扫描。这可能需要几分钟,具体取决于你的网络连接速度和虚拟机的当前负载,但它将可靠地确定每个可用的端口,这些端口既在虚拟机上开放,又能从你的 PC 访问。
最适合此任务的端口扫描工具是 Nmap(nmap.org/)。它可以安装在 Windows 或 Linux 上,但我推荐尽可能在 Linux 上使用,因为它在 Linux 上运行更快。安装 Nmap 后,打开命令提示符并运行以下命令:
# nmap -Pn -p 0-65535 -sV hostname
Starting Nmap 7.01 ( https://nmap.org )
Nmap scan report for hostname (IP)
Host is up (0.041s latency).
Not shown: 65534 filtered ports
PORT STATE SERVICE VERSION
3389/tcp open ssl/ms-wbt-server?
5986/tcp open ssl/http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
Service Info: OS: Windows; CPE: cpe:/o:microsoft:windows
Service detection performed. Please report any incorrect results at https://nmap.org/submit/.
Nmap done: 1 IP address (1 host up) scanned in 10081.46 seconds
-Pn选项告诉 Nmap 即使主机没有响应 ping 请求,也要继续扫描。-p选项告诉 Nmap 要扫描哪些端口(在这种情况下,是所有可能的 TCP 端口)。最后,-sV指示 Nmap 尝试确定它找到的任何开放端口上运行的服务。根据这些结果,你应该能够了解目标虚拟机上哪些远程管理服务可用以及它们运行的端口。
这些技术可能会失败,原因有三种可能:虚拟机当前已关闭,所有管理服务已被禁用(或其端口已被防火墙限制),或者主机名或 IP 地址不正确。在这种情况下,唯一的选择是稍后再试,或者放弃并转向渗透测试的其他部分。
重置虚拟机凭据
如前所述,将 VHD 取证与密码破解相结合,是从虚拟机获取凭据的强大方式,但仅限于在未启用 Azure 磁盘加密的情况下,并且攻击者有足够时间破解管理员密码。如果你设法获得了订阅的管理员权限,你可以使用另一种更快速的方法,这种方法不依赖于从磁盘中获取信息:你可以重置虚拟机的管理员密码。虽然这种方法既快速又可靠,但它也有较高的被检测到的可能性,因此我将其作为最后的手段。
如何重置虚拟机凭据
为了避免当用户忘记密码时永久锁定虚拟机,Azure 门户提供了虚拟机密码重置选项,如图 5-10 所示。要访问目标虚拟机的密码重置选项,请登录到门户,点击虚拟机部分,选择目标虚拟机,然后点击重置密码。
这个表单有一些不错的功能。首先,它显示了虚拟机的内置管理员或根账户名(此例中为azureadmin),即使它已被更改。即使你不打算执行密码重置,这也非常有用,因为它可以帮助你确定一个有效的账户名,用于字典攻击等操作。其次,当密码过于简单时,密码框右侧会出现一个红色的感叹号。如果你将鼠标悬停在感叹号上,你将能够看到有关密码复杂度要求的提示信息。这将是用来配置 hashcat 规则的完美信息。

图 5-10:Azure 虚拟机的重置密码界面
要实际完成密码重置并更改管理员密码,只需在“密码”字段中输入所需的密码并点击更新。如果修改了“用户名”字段,管理员账户的名称也应该被更改。此外,如果内置管理员账户被禁用,密码重置选项应该会重新启用它。
此表单还包含一个在“模式”下拉菜单中的选项,用于重置远程访问配置。该选项将保留原始密码不变,但会启用虚拟机上的 RDP(Windows)或 SSH(Linux),以恢复远程连接能力。此功能旨在恢复管理员在配置错误后重新连接虚拟机的能力,但对于渗透测试人员而言,它可以重新开启在已加固的虚拟机上的远程访问服务。
密码重置的缺点
即使密码重置是一种相对可靠的方式来访问虚拟机,它也有一些缺点。最重要的是,当通过门户成功更改密码时,你将无法确定之前的密码是什么。这意味着密码不能恢复到原来的值,而你现在是唯一拥有凭据的人。当然,这也意味着,一旦虚拟机管理员账户的合法用户尝试连接虚拟机,他们会意识到出了问题。他们不一定会被阻止访问虚拟机,因为他们可以自己执行密码重置(假设他们有 Azure 门户访问权限),但即使是没有经验的用户,也很可能会意识到发生了安全事件,并开始进行调查或向安全监控团队报告。
其次,尽管你将拥有凭据,但你可能对目标虚拟机的配置了解甚少。如果虚拟机中运行的软件正在使用你重置的账户,重置密码可能会导致其他服务出现意外中断,这些服务可能需要不同的密码。
最后,这种方法有一些技术限制。虚拟机(VM)必须处于运行状态,才能启用密码重置选项。此外,Azure VM 代理软件必须已安装在虚拟机上。Azure 中的默认操作系统镜像通常已经安装了该代理,但某些虚拟机可能被管理员移除了该代理,可能正在运行不太常见的旧版操作系统,且没有代理可用,或者可能是从非标准镜像构建的。
总结
在本章中,我们讨论了攻击者如何从 Azure 存储中创建并下载虚拟机磁盘镜像的快照,然后使用法医恢复工具(如 Autopsy)从中恢复密码哈希和其他敏感数据。接着,我们检查了如何在 Cain & Abel 或 hashcat 中破解这些哈希,以确定原始的明文密码。之后,我们使用 PowerShell 或端口扫描确定虚拟机上可访问的管理服务。最后,我们利用破解的密码连接回虚拟机。
在那之后,我们查看了 Azure 的虚拟机密码重置选项。你可以使用此选项在门户中访问的任何虚拟机上获得管理员级别的访问权限,而无需了解虚拟机的配置。最后,我们考虑了此攻击可能存在的一些限制。
在下一章中,我们将探讨 Azure 网络,以检查如何定位面向互联网的虚拟机,以及企业网络中的系统如何与 Azure 服务进行交互。
第六章:调查网络

从根本上讲,云是一个大规模的计算和数字存储资源的集合,供租用使用。这种商业模式依赖于互联网,允许云的用户将数据进出提供商的系统,管理远程系统,并使网站、电子邮件服务器等服务面向终端用户。
由于连接性对云的整体成功至关重要,Azure 为用户提供了多种网络设置。默认情况下,Azure 使服务面向互联网,从而允许任何人访问。然而,Azure 还提供了其他网络选项,用于在内部公司网络和 Azure 服务之间建立连接。这两种连接对于 Azure 能够满足客户工作负载和需求至关重要,但这也意味着配置错误可能会导致安全灾难。
本章将讨论防火墙中常见的配置快捷方式如何使服务容易受到攻击。我们还将探讨攻击者如何利用 Azure 的隧道来破坏公司网络。
最佳实践:网络安全
在保护云中资源时,首先要做的防御工作之一就是适当的网络配置。毕竟,如果恶意流量永远无法到达服务,漏洞被利用的风险就会大大降低。我给客户的一些常见建议包括创建小型专用虚拟网络、使用网络安全组,以及避免不小心将公司网络桥接到互联网。
首先,为你在云中运行的每个服务定义独立的 Azure 虚拟网络。通过创建一个仅供提供某个服务所需资源的网络,你可以将网络配置为仅允许最小程度的访问,从而使该服务能够正常工作。如果网络中包含多个用于不同项目的资源,那么管理起来就会变得更加困难。
接下来,使用 Azure 网络安全组(NSG),正如在“收集网络信息”一文的第 56 页中首次讨论的那样。将虚拟机的流量限制为仅需要的部分,如果当前没有进行虚拟机的管理任务,则禁止访问远程管理服务——如果需要进行更改,你可以稍后临时添加一条规则,允许从你的 IP 地址访问这些端口。另外,考虑修改默认规则。例如,如果某个服务不需要进行外部互联网连接,就将其阻止。这可以大大增加攻击者在成功入侵虚拟机后,无法通过恶意软件与攻击者的系统回连的难度。
最后,Azure 提供了几项服务,可以在 Azure 与你公司网络之间建立链接,我在“云到企业网络桥接”一节中有讨论,见第 123 页。这些功能非常适合实现混合 IT,即在本地运行的服务与云中的服务无缝连接,但它们也可能导致一个不希望出现的情况:如果一个具有此连接性的 Azure 虚拟网络还托管了面向公网的服务,那么这些服务中的任何一个被攻击者攻破,都可能为攻击者提供一条直接返回公司网络的路径。因此,非常重要的一点是要将需要访问公司网络的服务与需要公开暴露的服务分开。我建议将它们放在完全不同的订阅中,以避免意外的桥接。如果某些服务需要两种类型的访问权限,务必非常小心地设计,并花费大量时间进行威胁建模,以尽可能识别并解决所有潜在的危险。当然,也要确保对其进行渗透测试,以验证其安全性!
Azure 中的网络是一个广泛的话题,因此有许多功能可能会对你的使用场景有所帮助,但我无法在这里一一覆盖。幸运的是,Azure 网络安全有着一些最全面的文档。请参阅docs.microsoft.com/zh-cn/azure/best-practices-network-security/,了解详细的威胁模型,并参考docs.microsoft.com/zh-cn/azure/security/azure-security-network-security-best-practices/,讨论可以使你的链接更安全的功能。
避免使用防火墙
Azure 为其多个服务提供防火墙。它们最常用于保护虚拟机、SQL 服务器和应用服务。对于虚拟机和 SQL,防火墙默认启用,并且与各自的服务一起使用是免费的。对于应用,Azure 提供了一个付费的 Web 应用防火墙选项。了解每个防火墙的功能和默认设置,可以帮助渗透测试人员更好地了解哪些方法可能有效,以及哪些耗时的扫描应该避免。
虚拟机防火墙
防火墙是虚拟机对抗基于网络攻击的首要防线,而且通常是唯一的防线。在撰写本文时,管理员可用于保护虚拟机的入侵防御虚拟设备选项很少。同时,他们也无法创建高级路由规则,以便在流量到达虚拟机之前进行拦截。因此,管理员在设置防火墙时必须格外小心。
几乎所有的操作系统都包含主机防火墙,允许系统管理员配置哪些端口和服务应该从网络上进行访问。然而,这些原生防火墙存在一些问题:
复杂性和不一致性 每种操作系统配置防火墙的方法不同,使用的命令也不同,有时甚至术语也各不相同。管理员可能在某种类型的防火墙上有经验,但在为不太熟悉的操作系统配置防火墙时,可能会无意中犯下关键错误。
无计划的变化 主机防火墙配置可能在开始时是安全的,但随着时间的推移,可能会在无人察觉的情况下变得更弱。例如,安装新的软件包或更新时,可能会向防火墙添加新的例外规则,而没有任何警告,比如一个包含网页界面的程序,它会开放 TCP 端口 80 和 443,允许外部流量进入。
漏洞 防火墙软件通常经过非常严格的测试,但总是有可能出现漏洞,导致数据包意外通过,甚至崩溃整个虚拟机。事实上,安全软件中的漏洞,诸如防火墙和杀毒软件,往往是最严重的。这不仅仅是因为利用这些漏洞可以绕过软件本应提供的安全控制,还因为这些软件始终在运行,几乎存在于每个系统中,拥有系统级别的权限,并且暴露于潜在的恶意输入中。例如,2017 年,谷歌的安全工程师发现了微软杀毒软件扫描引擎中的一个漏洞,攻击者可以通过发送一封恶意电子邮件来控制计算机,而用户甚至不需要打开这封邮件。这个漏洞很快得到了修复,但同年,其他厂商的安全产品也发现了类似问题,且很可能还有更多漏洞尚未被发现。
负载 基于主机的防火墙会分析操作系统内的数据包,这意味着每一个被检查的数据包都会瞬间消耗处理器周期和内存。在负载过重时,尤其是在遭遇拒绝服务(DoS)攻击时,这种额外的压力可能会阻止服务器执行正常工作。这甚至可能对云环境造成财务影响,因为 Azure 的自动扩展功能可以配置为在负载暂时增加时自动上线更多资源或将虚拟机升级到更高的定价层,而这些升级会计入虚拟机的订阅费用。
订阅与虚拟机管理 虚拟机的管理员(可能与订阅管理员不同)控制基于主机的防火墙。这意味着管理员可能会将系统暴露于攻击之下,如果该虚拟机被攻破,攻击者可能会利用该系统攻击 Azure 中更多受限的虚拟机或服务。考虑到许多公司允许用户成为自己工作站的本地管理员,但很少允许这些用户将工作站直接暴露于互联网。Azure 也应当以同样的方式对待。
为了解决这些问题,Azure 提供了虚拟机的防火墙,除了主机级防火墙选项之外,提供了经典 Azure 服务管理(ASM)虚拟机中的端点规则和 Azure 资源管理器(ARM)虚拟机中的网络安全组(NSG)。这些规则易于配置,并且无论虚拟机的操作系统是什么,都能有效工作——只有具有正确订阅权限的人才能禁用或重新配置这些防火墙。
注意
微软允许其他安全公司向客户提供 下一代防火墙 服务,在 Azure 市场上进行销售。这些“防火墙即服务”解决了本节讨论的问题,并且可能还提供额外的独特保护措施,如深度数据包检查或内容过滤。由于这些防火墙在不同供应商之间差异较大,我们无法在此覆盖它们。如果你在评估过程中遇到一个,请查看其功能,并确保它已正确配置,以确保客户服务的安全。
然而,这种看似坚固的防御体系中也存在一些漏洞。为了便于管理,每个新虚拟机都会应用几个默认规则。这些规则会根据虚拟机中使用的操作系统开放不同的端口。作为渗透测试人员,了解 Azure 默认开放的端口非常重要。用户通常不会更改这些规则,这意味着这些端口对互联网上的任何人都开放。
对于 Windows 服务器,Azure 开放了端口 3389,用于 TCP 和 UDP 的入站流量,用于远程桌面协议(RDP)。此外,默认情况下,入站的 TCP 端口 5986 也对外开放,用于 Windows 远程管理(WinRM),其中,PowerShell 用于远程连接虚拟机。对于较旧的虚拟机,Azure 将 RDP 移动到 49152 到 65535 之间的随机端口。尽管新建的经典虚拟机不再使用这种方式,但你仍然可能会发现一些较旧的虚拟机使用这种安全通过模糊化的方法。
对于 Linux,端口列表要小得多;默认情况下,只有 TCP 端口 22 对外开放。这个端口用于安全外壳协议(SSH),即加密的基于控制台的远程管理服务。根据选择的 Linux 镜像和用户的偏好,SSH 可能被配置为使用基于证书的身份验证或传统的用户名和密码。
当然,所有这些协议都有身份验证,因此你不能仅仅连接到端口并控制虚拟机。然而,如果攻击者找到了有效的凭证,成功进行了字典攻击或暴力破解,或者发现了这些服务的身份验证绕过漏洞,那么他们将能够访问系统。
防御者提示
为了帮助防止攻击者通过防火墙中允许的入站连接访问管理接口,您可以更改防火墙规则,仅允许来自特定 IP 地址的连接,例如来自公司网络出口点的地址。或者,您可以阻止来自互联网的端口访问,并设置一个强化的虚拟机,允许来自有限 IP 地址范围的入站 RDP 连接,该虚拟机充当跳板服务器。通过这个跳板服务器,您可以通过一个仅从订阅内访问的虚拟网络,访问所有其他服务的管理接口。
默认情况下,Azure 虚拟机允许所有出站流量。订阅管理员可以更改这一点,但这种情况很少发生。渗透测试人员可以从这个允许所有的规则中受益。首先,如果攻击者获得了对系统的访问权限,则没有规则限制数据的外泄。其次,像 Metasploit 这样的工具可以利用反向 TCP shell 连接回攻击者的指挥控制服务器,接收指令。最后,系统上的攻击者可以从任何地方下载他们需要的工具。
Azure SQL 防火墙
Azure SQL 服务器也有自己的防火墙,但与虚拟机防火墙不同,它们不是可选的;默认情况下它们是开启的,任何人都无法禁用它们。然而,攻击者仍然可以使用一些技巧绕过防火墙,直接攻击 SQL 服务器。
首先,您可能还记得在第三章中提到,开发人员有时会向 SQL 防火墙中添加允许任何地方连接的规则。攻击者可以很容易在 Azure 门户中的数据库防火墙页面上发现这些规则,因为这些规则允许来自大量 IP 地址范围的连接,例如 0.0.0.0 到 255.255.255.255。虽然防火墙在技术上仍然运行,但此类规则使其不再过滤任何连接,因此攻击者可以从互联网上的任何地方连接到 SQL 服务器,并尝试进行如密码暴力破解等攻击。
其次,即使没有设置允许所有连接的规则,攻击者仍然可能建立连接。一些数据库服务器有许多授权用户,这些用户经常从各种网络位置连接,例如总部、分公司、企业 VPN、家庭,甚至是咖啡馆和机场航站楼的移动网络。当用户可以从多种位置访问服务器时,防火墙规则可能包含至少几个允许的范围;例如,防火墙可能允许来自公司网络的任何连接。这意味着,攻击者如果获得了任何公司系统的访问权限,就可以利用该机器作为攻击 SQL 服务器的跳板。如果攻击者能够访问 Azure 门户,但无法访问具有先前授予 IP 规则的机器,攻击者可能会成功地为其 IP 地址添加新规则。而且,由于用户经常为 SQL 防火墙添加新规则——有时候一个数据库可能会有十几个或更多的条目——因此不太可能有人注意到再添加一个规则。如果你添加了新规则,确保你的规则名称与其他合法规则相似,以便更好地融入。另外,确保你记录并跟踪任何此类修改,以便在项目结束时与你的客户共享一份清单,验证这些修改是否已被移除。请注意,真正的攻击者可能会利用你所创造的任何新漏洞——这是一个非常不希望发生的情况。
防御者提示
你应该定期检查防火墙规则的变化。保持一个列出所有依赖 SQL 服务器的服务所需规则的清单是个好主意;这样,你可以删除随着时间推移而逐渐增多的多余规则。例如,如果某个已删除的规则曾用于开发人员工作站,当开发人员重新连接时,他们可以通过 Azure 门户或 SQL Server 管理工作室轻松地再次添加该规则。如果没有偶尔的清理,旧规则会逐渐积累,从而增加服务器暴露风险,并且很难发现恶意规则的添加。你可以通过 Azure PowerShell 的 Get-AzureSqlDatabaseServerFirewallRule cmdlet 自动检测非法规则。
最后一个可能的弱点是,SQL 防火墙规则是在服务器级别配置的,而不是每个数据库单独配置的。因此,如果一个服务器有 20 个数据库,每个数据库由不同的团队使用,则同一套规则会应用于所有这些数据库。因此,攻击者可能会破坏一个使用不良安全习惯的团队所用的工作站,这台工作站访问的是一个不重要的 Azure SQL 数据库;然后,攻击者可以利用同一台系统来攻击另一个更重要的数据库,该数据库由安全性更强的团队使用。
Azure Web 应用防火墙
Web 应用防火墙(WAF)与传统防火墙不同,后者基于端口和 IP 地址的规则来决定是否允许流量通过。相反,WAF 位于 Web 应用程序前面,专门寻找恶意请求。当 WAF 识别到可疑模式时,它可以报告事件或直接阻止流量。因此,WAF 更像入侵检测系统(IDS)或入侵防御系统(IPS),而不是 IP 防火墙。WAF 已经足够普及,从 2017 年起,流行的开放 Web 应用程序安全项目(OWASP)十大 Web 漏洞列表将缺乏 WAF 本身视为一个安全隐患。
紧跟行业趋势,Azure 现在提供了一个 WAF,用户可以将其部署在 Azure 网站和应用程序前面。微软还允许其他供应商为 Azure 客户提供 WAF。大多数 WAF 的功能类似,因此我们将重点讨论微软的 WAF,它是 Azure 中最常用的。
要启用微软的 WAF,客户必须创建一个 Azure 应用程序网关,这是一个负载均衡服务,将 HTTP 和 HTTPS 请求分配给一组 Azure 服务器。在 Azure 应用程序网关的配置阶段,用户可以选择是否在网关上启用 WAF。在配置 WAF 时,用户可以选择防火墙是仅检测并记录威胁,还是直接阻止威胁。后者选项可以提高 WAF 保护的站点的安全性,但如果某条规则过于宽泛,可能会导致阻止有效流量的风险。
Azure 的 WAF 使用 OWASP 在其 ModSecure Core Rule 项目中定义的规则。网站管理员可以选择使用 OWASP 2.29 或 OWASP 3.0 规则集。除了移除一些常见的误报并调整一些规则的严重性评分外,OWASP 3.0 的最大变化是新增了 IP 否认规则。这些规则可以阻止来自已知恶意发送者的请求,以及来自某些国家/地区 IP 地址的请求。渗透测试人员应该注意 OWASP 的否认规则,因为 WAF 可能会根据这些规则阻止测试人员的主机,从而导致他们误以为服务器不易受到某个攻击的影响,但实际上,该攻击从其他 IP 地址发起时是有效的,这可能会导致报告中出现严重的漏报(false negative)。
Azure 的 WAF 一个主要的弱点是其配置能力有限。管理员可以手动启用或禁用单个 WAF 规则或一类规则,但无法调整规则以适应特定场景。因此,如果某条规则可能产生大量误报,管理员可能会禁用该规则。此外,许多规则的描述较为模糊,配置 WAF 的用户可能会关闭比实际需要更多的规则,以便使网站正常运行。为了让你更好地理解规则列表,WAF 配置页面如图 6-1 所示。
渗透测试人员如果想绕过 WAF,并没有一个明确的解决方案。相反,如果你怀疑客户使用的 WAF 阻止了某个攻击,最好的办法是在线查找该漏洞的资料,看看是否有人找到了绕过 WAF 的方法。否则,可以尝试修改攻击中使用的代码——也许一些微小的变化就能绕过 WAF 规则的模式。

图 6-1:选择了 OWASP 3.0 规则的 Azure WAF 配置
DEFENDER'S TIP
WAF 并非万无一失。像任何基于模式的安全产品一样,它们可能会漏掉新型攻击,攻击者可以通过巧妙地重写已知的漏洞来绕过 WAF。尽管存在漏洞,WAF 仍然提供了额外的保护层,这是构建更安全系统的关键部分。
此外,WAF 往往会引入人为风险。开发人员常常容易认为 WAF 会阻止任何恶意行为,因此他们认为可以不受惩罚地部署包含安全漏洞的代码。这就相当于 IT 专业人员认为只要安装了防病毒软件,就可以跳过安全更新的安装。显然,这两种想法都是错误的!即使在使用 WAF 时,也要保持警惕;否则,WAF 可能会导致你的整体安全性下降。
云与企业网络桥接
当公司将云计算作为 IT 战略的一部分开始采用时,可以选择迁移现有工作负载或构建专门为云设计的新服务。无论选择哪种方式,将数据在企业系统和云提供商之间传输都会带来挑战。为了解决这个难题,微软提供了两种不同的连接方式,连接客户环境和 Azure。
对于从企业环境迁移的系统,Azure 允许用户在其订阅和公司网络之间创建直接连接,使 Azure 资源与原始公司网络共享相同的 IP 地址空间;这种直接连接被称为 Azure 虚拟网络。公司可以通过两种不同的 Azure 服务之一来实现 Azure 虚拟网络连接:虚拟私人网络或 ExpressRoute。我们将在下一节中讨论这两种服务。
Azure 虚拟网络对于云迁移非常方便,但对于某些工作负载来说,它有些过于复杂。对于许多使用场景——例如为云环境设计的服务——简单的消息传递系统可能已经足够。例如,一个 Azure 网站可能完全在云中运行,但需要在新订单生成时向本地数据库插入一条记录。对于这些场景,Azure 提供了 Service Bus 和 Logic Apps。
虚拟私人网络
虚拟专用网络(VPN)连接是企业 IT 世界中成熟的技术。许多公司使用 VPN 使员工能够在家工作或旅行时工作。VPN 会在客户端与公司运行的 VPN 网关之间,通过互联网创建一个加密隧道。VPN 可以隧道化所有网络流量,或者仅隧道化目的地为办公室的流量。VPN 最常用于客户端计算机与企业网络之间,偶尔也用于连接两个不同的企业位置,甚至是将技术精通的消费者的智能手机连接到他们的家庭网络。
Azure 提供几种不同形式的 VPN 连接:
点对站点 连接单个客户端系统到 Azure 虚拟网络的隧道
站点对站点 企业网络与 Azure 虚拟网络之间的连接
多站点 多个企业网络全部连接到同一个 Azure 虚拟网络
VNet 对 VNet 两个 Azure 虚拟网络之间的隧道
Azure 提供这些选项,使得订阅中的 Azure 服务能够与其他系统、网络或订阅进行通信,而无需让连接的任一方或双方暴露于互联网。这对渗透测试人员意味着两件事:首先,可能有一些服务是评估范围内的,但只能通过连接到这些 VPN 隧道的系统访问。其次,攻破一个 Azure 服务或订阅可能会提供一个直接通往企业网络或服务的连接,这些网络或服务本身并未暴露。
警告
VPN 连接可能将目标的资源连接到合作伙伴公司的网络,这可能不在你评估的约定范围内。发现任何新系统时,请务必先确认它们是否属于评估范围,然后再继续。
要利用这些连接,攻击者需要知道如何识别每种形式的 VPN 连接以及每种连接如何执行身份验证。确定这些属性的方式因连接类型的不同而有所不同。让我们来逐一分析。
连接到点对站点 VPN
点对站点连接要求客户端使用基于证书的身份验证。为了设置 VPN,管理员需要在 Azure 中创建一个虚拟网络,并为该网络定义一个私有 IP 地址范围,如 10.0.0.0/16。接下来,他们创建一个 VPN 网关服务实例,并为其分配一个虚拟网络中的子网范围。最后,管理员创建一个自签名证书,作为受信任的根证书来验证客户端请求,并将证书的公钥部分保存到 VPN 网关配置中。
为了允许客户端连接,管理员需要从 Azure 门户下载 VPN 客户端软件并将其安装到客户端机器上。管理员还必须使用先前生成的证书作为根证书,生成一个新证书,并将该证书的私钥安装到客户端的证书存储中。
要确定是否正在使用点对站点 VPN,你可以通过 Azure 门户在订阅中检查,或者检查你怀疑使用 VPN 的客户端机器。在 Azure 门户中,打开虚拟网络网关 blade——Azure 对服务配置页面的术语——并查看是否列出了任何类型为 VPN 的网关。如果有,点击每个网关,然后点击每个网关的 Point-to-site configuration 选项,这将打开一个类似于 图 6-2 的页面。
此窗口向管理员显示有关所选网关的点对站点连接的所有信息:活动连接的数量和总带宽使用情况、分配给 VPN 的地址空间、用于验证客户端证书的根证书的 base64 编码公钥部分、任何已撤销的客户端证书的指纹,以及当前连接的 VPN 客户端的 IP 地址。如你所见,关于连接的客户端的唯一信息是正在使用的 IP 地址。这意味着,如果你能够创建一个非法连接到 VPN,管理员将无法获得有关你系统的详细信息。

图 6-2:Azure VPN 点对站点配置
在 Windows 10 客户端机器上,你可以通过按 WINDOWS-R 并输入 ms-settings:network-vpn 来检查 VPN,这将打开 VPN 设置页面。在早期版本的 Windows 中,改为输入 control netconnections。检查是否列出了任何 VPN 连接;如果有,选择一个连接并点击 Advanced Options。Azure VPN 连接的服务器地址将以 azuregateway 开头并以 cloudapp.net 结尾,如 图 6-3 所示。

图 6-3:Windows 10 上的 Azure VPN 连接详细信息
如果你发现某个客户端具有此类 VPN 连接,你可以利用该机器对虚拟网络范围内的其他地址进行网络扫描——但这可能会引起系统所有者的警觉。相反,只要你拥有系统的管理员权限,我建议你从客户端获取连接详情和证书,然后从任何其他 Windows 主机连接到 VPN。
在客户端系统中,打开 %appdata%\Microsoft\Network\Connections*Cm* 目录。该目录应包含一个 .cmp 文件和一个子目录,两个名称都使用相同的 GUID。将 .cmp 文件和 GUID 子目录中的所有文件复制到你自己计算机上的一个文件夹中,例如 C:\vpn。
接下来,导出 VPN 根证书的公钥。为此,打开 PowerShell 窗口并运行 清单 6-1 中的脚本。
$path = "$env:appdata\Microsoft\Network\Connections\Cm"
➊ $cmsFiles = Get-ChildItem -Path $path -Filter *.cms -Recurse
foreach ($file in $cmsFiles)
{
➋ $match = Select-String -pattern "CustomAuthData1=" $file
$thumbprint = $match.Line.Split('=')[1].Substring(0,40)
$cert = (Get-ChildItem -Path "cert:\CurrentUser\Root\$thumbprint")
➌ Export-Certificate -Cert $cert -FilePath "$thumbprint.cer"
}
清单 6-1:用于导出 VPN 连接所使用根证书的 PowerShell 脚本
该脚本递归检查 Network\Connections 目录中的 .cms 配置文件 ➊,提取连接的根证书指纹 ➋,然后将该证书导出到当前目录 ➌。将任何导出的证书复制到您的计算机并将其导入到 当前用户\受信任根证书颁发机构 存储区。
从目标系统中,最后需要的就是用于认证 VPN 连接的证书的私钥。它位于 当前用户\个人 证书存储区,但很可能被标记为不可导出。幸运的是,Mimikatz 可以导出这些受保护的证书。要提取证书,请从管理员命令提示符运行 Mimikatz,然后执行以下命令:
mimikatz # crypto::capi
mimikatz # privilege::debug
mimikatz # crypto::cng
mimikatz # crypto::certificates /store:my /export
这将把所有用户的个人证书导出到当前目录。您之前导出的根证书将是用于 Azure VPN 认证的证书路径的根。将导出的 PFX 文件复制到您的系统,然后将其导入到 当前用户\个人 证书存储区。
注意
通过 Mimikatz 导出的 PFX 文件的默认密码是 mimikatz*。
最后,您需要运行一个命令,在您的计算机上创建 VPN 连接。打开命令提示符,导航到您复制文件所在的目录(例如 C:\vpn),然后运行命令
C:\vpn> cmstp.exe /s /su /ns GUID.inf
其中 GUID 是从目标系统复制的 .inf 文件的名称。这将把 VPN 连接添加到您的系统;现在,您应该能够通过单击通知区的网络图标,然后单击 连接 按钮,在飞出菜单中连接到 Azure 虚拟网络,正如 图 6-4 所示。

图 6-4:带有 Azure VPN 连接的网络飞出菜单
连接到站点到站点 VPN
单点 VPN 连接将单个客户端连接到远程网络,而站点到站点 VPN 将整个网络段桥接到另一个远程网络。在 Azure 中,这些连接用于将部分企业网络连接到 Azure 虚拟网络。使用站点到站点 VPN 允许位于本地数据中心的服务器组直接与 Azure 资源(如虚拟机)连接,而无需在每台服务器上安装 VPN 客户端。这是许多逐步迁移服务器到云的公司中常见的配置,但仍然需要访问他们的企业网络。
要创建这样的连接,企业网络必须具有支持站点到站点 VPN 的本地网络设备,如路由器或 VPN 网关设备。然后,管理员在 Azure 门户和本地网络设备上配置 VPN。接着,他们为连接的每一端配置对方的公共 IP 地址,以及每个 VPN 网关后面代表的私有网络 IP 范围,这允许网关判断是否应通过该连接路由流量。为了验证连接,双方还需要使用相同的共享密钥。
由于管理员可以在各种设备上设置 VPN 的企业网络部分,确定哪个设备负责某个特定连接是很困难的,因此描述可能的攻击方式并不现实。因此,对于站点到站点的 VPN,重点放在连接的 Azure 端。
如果你可以获得 Azure 订阅的管理员访问权限,你可以使用 PowerShell 显示 VPN 连接的详细信息。示例 6-2 中的脚本将列出每个连接并显示其重要详细信息。
➊ $connections = Get-AzureRmResourceGroup | `
Get-AzureRmVirtualNetworkGatewayConnection
foreach ($connection in $connections)
{
➋ Get-AzureRmVirtualNetworkGatewayConnection -ResourceGroupName `
$connection.ResourceGroupName -Name $connection.Name
➌ Get-AzureRmLocalNetworkGateway -ResourceGroupName `
$connection.ResourceGroupName | `
Where {$_.Id -eq ($connection.LocalNetworkGateway2.Id)}
Write-Output "========================================================="
}
示例 6-2:用于导出站点到站点 VPN 连接详细信息的 PowerShell 脚本
该脚本将获取订阅中每个资源组中的每个虚拟网络网关的列表 ➊,然后显示有关连接的详细信息 ➋ 和与 VPN 连接的远程站点的信息 ➌。对于订阅中的每个 VPN 连接,脚本输出的内容应如下所示:
➊ Name : VPN_Name
ResourceGroupName : Resource_Group
Location : centralus
Id : /. . ./Microsoft.Network/connections/VPN_Name
Etag : W/"GUID"
ResourceGuid : GUID
ProvisioningState : Succeeded
Tags :
AuthorizationKey :
➋ VirtualNetworkGateway1 : "/. . ./virtualNetworkGateways/Gateway_Name"
VirtualNetworkGateway2 :
➌ LocalNetworkGateway2 : "/. . ./localNetworkGateways/Remote_Network"
Peer :
RoutingWeight : 0
➍ SharedKey : MySuperSecretVPNPassword!
➎ ConnectionStatus : Connected
EgressBytesTransferred : 0
IngressBytesTransferred : 0
TunnelConnectionStatus : []
➏ GatewayIpAddress : 203.0.113.17
LocalNetworkAddressSpace : Microsoft.Azure.Commands.Network.Models.PSAddressSpace
ProvisioningState : Succeeded
BgpSettings :
➐ AddressSpaceText : {
"AddressPrefixes": [
"192.168.200.0/24"
]
}
--snip--
输出首先显示站点到站点连接的名称 ➊,这可能会告诉你连接的目的,Azure VPN 网关设备的名称 ➋ 和本地网络 ➌ 也可能给出一些线索——这些都是用户选择的。SharedKey 值是用于验证一个站点与另一个站点的秘密 ➍;通过获取 SharedKey,你可能能够根据配置的 IP 范围建立到企业 VPN 网关的连接。ConnectionStatus 显示 VPN 链接是否已建立 ➎。最后,GatewayIpAddress 是企业 VPN 网关的公共 IP 端点 ➏,而 AddressSpaceText 是客户端网络上用于 VPN 的私有网络 IP 范围 ➐。
DEFENDER 的提示
你需要采取两个重要步骤来避免恶意连接到你的站点到站点 VPN。首先,确保选择一个复杂的共享密钥,使攻击者无法猜测;这样,你的对手就必须破坏你的 VPN 网关设备或 Azure 订阅来获取该密钥。其次,配置你的 VPN 设置和防火墙,仅允许在你预期的 IP 地址之间建立站点到站点的连接(以及通过它们路由的网络流量)。
连接到多站点 VPN
多站点 VPN 允许多个站点互相连接,可以采用网状拓扑(每个分支与其他分支相连)或中心-辐射设计(分支与中央办公室通信)。多站点 VPN 对于有许多小型分支办公室的公司非常有用,例如银行、保险公司和政治竞选活动。
Azure 通过允许每个 Azure VPN 网关同时拥有多个站点到站点的连接来处理多站点 VPN。因此,上一节中的所有信息也适用于多站点配置。列表 6-2 中的脚本旨在处理所有类型的 VPN 部署,因此你也可以将它用于多站点 VPN。
连接 VNet 到 VNet 的 VPN
对于需要在两个不同 Azure 虚拟网络中运行的资源进行通信,微软提供了 VNet 到 VNet 的 VPN 连接。管理员可以使用这些 VPN 连接来连接位于不同区域或甚至不同订阅中的其他虚拟网络。它们与站点到站点的 VPN 几乎具有相同的所有属性,不同之处在于,VNet 到 VNet 的 VPN 连接在连接的一端使用的是另一个 Azure VPN 网关实例,而不是客户网络设备。
作为渗透测试人员,你可以选择将 VPN 网关添加到你自己的订阅中,然后尝试将其与目标的虚拟网络配对。这是一个相当显眼的操作,因为 VPN 连接会在 Azure 门户中明显可见,但它提供了一种新的方式,帮助你在订阅中维持持久访问虚拟机,直到连接被发现。如果你尝试这样做,建议在一个较少使用的订阅中进行,因为目标的管理员将能直接访问你的系统——毕竟,VNet 到 VNet 的 VPN 是双向的。
为了使其正常工作,目标订阅中必须已经有一个 VPN 网关。从这个网关,你需要获取网关的名称和 ID(例如,/subscriptions/Subscription_Id/resourceGroups/Resource_Group/providers/Microsoft.Network/virtualNetworkGateways/Gateway_Name)。你可以使用 PowerShell 命令,并通过管理员权限访问目标订阅来获取这两个值:
PS C:\> Get-AzureRmResourceGroup | Get-AzureRmVirtualNetworkGateway
你还需要在自己的订阅中拥有一个 VPN 网关,并且需要获取自己的网关的相同信息。拥有这些数据后,你可以在自己的订阅中运行以下命令:
$myGateway = Get-AzureRmVirtualNetworkGateway -Name "Local_Gateway_Name" `
-ResourceGroupName "Local_Gateway_Resource_Group"
$remoteGateway = New-Object Microsoft.Azure.Commands.Network.Models.PSVirtualNetworkGateway
$remoteGateway.Name = "Target_Gateway_Name"
$remoteGateway.Id = "Target_Gateway_ID"
New-AzureRmVirtualNetworkGatewayConnection -Name "V2V" -ResourceGroupName `
$myGateway.ResourceGroupName -VirtualNetworkGateway1 $myGateway -VirtualNetworkGateway2 `
$remoteGateway -Location $myGateway.Location -ConnectionType Vnet2Vnet -SharedKey "Key"
你可以替换网关连接名称(此处为 V2V)和共享密钥(Key)为任何想要的值。然后,你可以在目标订阅中运行此命令,将目标网关的值替换为你网关的详细信息。此时,VPN 连接应该已经建立并准备好使用。
ExpressRoute
站点到站点的 VPN 对于许多客户来说效果很好,但它们仍然依赖于公司与 Azure 数据中心之间的基础互联网连接。这条路径可能需要经过多个不同的网络提供商,因此链接的延迟和带宽无法保证。对于一些关键任务应用程序,这种不确定性是不可接受的;在这些情况下,ExpressRoute 提供了一个可行的替代方案。
ExpressRoute 是微软的一项服务,允许客户在其公司和微软的云服务之间建立专用电路。这些连接使用私有线路而非互联网构建,具有稳定的延迟和带宽,并提供服务级别协议(SLA)。它们的速度范围从 50MBps 到 10GBps 不等。
因为这些连接需要客户、创建链接的网络提供商和微软之间的特定协议,并且需要高级的网络知识来配置,所以通常只有在大型企业和机构中才能找到这些类型的连接。由于这些要求,你通常无法直接访问 ExpressRoute 连接本身;然而,你可能可以利用该连接访问原本无法访问的系统。
要确定目标是否正在使用 ExpressRoute,你可以使用 PowerShell(如果你有订阅访问权限),如下所示:
PS C:\> Get-AzureRmExpressRouteCircuit
➊ Name : Express_Route_Circut_Name
ResourceGroupName : Express_Route_Resource_Group
➋ Location : westus
Id : /. . ./Express_Route_Circut_Name
Etag : W/"Id"
ProvisioningState : Succeeded
➌ Sku : {
"Name": "Standard_MeteredData",
"Tier": "Standard",
"Family": "MeteredData"
}
CircuitProvisioningState : Enabled
ServiceProviderProvisioningState : NotProvisioned
ServiceProviderNotes :
ServiceProviderProperties : {
➍ "ServiceProviderName": "ISP",
➎ "PeeringLocation": "Silicon Valley",
➏ "BandwidthInMbps": 200
}
➐ ServiceKey : GUID
Peerings : []
该命令将返回当前订阅中的所有 ExpressRoute 电路,包括它们的名称 ➊、数据中心区域 ➋、连接是否按数据量(计量)收费或是无限流量 ➌、哪个网络提供商运行该链接 ➍、链接位置 ➎,以及带宽 ➏。此外,还提供了一个ServiceKey,其他命令可以使用它来查看或更改连接的设置 ➐。
如果你获得了 ExpressRoute 连接系统的访问权限,了解通过该链接可以访问的内容是很有帮助的。ExpressRoute 可以在企业和微软数据中心之间传输流量,目的地可以是三种不同类型的服务:Azure 私有系统、Azure 公共 IP 和微软公共 IP。
私有对等互联是公司服务器与在 Azure 中运行且连接到 Azure VPN 的资源之间的双向链接(例如,虚拟机)。这相当于站点到站点的 Azure VPN 连接。因此,如果你妥协了一个连接到 ExpressRoute 网络的 Azure 虚拟机,你将直接访问链接另一端的企业网络,反之亦然。
Azure 公共对等互联是一种单向的公司到 Azure 的链接,连接到 Azure 公开暴露的服务(例如,Azure 存储)。对于这种流量,公司网络可以向这些服务发出请求,但服务不能主动与公司进行通信。流量仍然通过专用链接传输。
Microsoft 公共对等连接是用于其他公开暴露的 Microsoft 服务的双向链路,例如 Office 365、Exchange Online 和 Skype。由于这些服务是为了直接从互联网使用而设计的,Microsoft 不鼓励通过 ExpressRoute 路由此类流量,并要求希望路由此类流量的客户与 Microsoft 账户代表合作以启用此功能。因此,你不太可能遇到这种配置。
你可以通过运行这些 PowerShell 命令,使用 Get-AzureRmExpressRouteCircuit cmdlet 返回的服务密钥,来确定为给定 ExpressRoute 启用的路由类型:
PS C:\> Import-Module 'C:\Program Files (x86)\Microsoft SDKs\Azure\PowerShell\
ServiceManagement\Azure\ExpressRoute\ExpressRoute.psd1'
PS C:\> Get-AzureBGPPeering -AccessType Private -ServiceKey "Key"
PS C:\> Get-AzureBGPPeering -AccessType Public -ServiceKey "Key"
PS C:\> Get-AzureBGPPeering -AccessType Microsoft -ServiceKey "Key"
第一行导入了 ExpressRoute PowerShell cmdlet,这些 cmdlet 不会随着其他 cmdlet 自动加载。每个 Get-AzureBGPPeering cmdlet 将返回指定路由的状态——启用或禁用——以及与该连接关联的网络子网。
DEFENDER 提示
使用 ExpressRoute 连接的最大风险是,连接到 ExpressRoute 虚拟网络的 Azure 虚拟机可能会被攻击,并用来攻击企业网络上的资源。避免这种攻击的最佳方法是确保虚拟网络中的虚拟机没有分配公共 IP 地址。如果虚拟机不是面向公众的,那么它只能从订阅内部或企业网络内部受到攻击,这大大降低了泄露的风险。为了确保不会创建互联网到 ExpressRoute 再到企业的桥接,良好的做法是将 ExpressRoute 连接和所有使用它们的资源放入自己的订阅中;这样,公共资源就无法意外地添加到 ExpressRoute 虚拟网络中。另一个选项是启用强制隧道,它会将系统上的所有流量通过 VPN 连接进行路由。更多信息请参考 docs.microsoft.com/en-us/azure/vpn-gateway/vpn-gateway-about-forced-tunneling/。
服务总线
VPN 和 ExpressRoute 提供的全面网络连接适用于使用大量协议的复杂环境,但并非每个场景都需要如此大带宽的云与公司之间的连接。对于范围较小的项目,Azure 服务总线可能是一个更好的解决方案。通过服务总线,开发人员可以在 Azure 中创建一个服务端点,服务可以通过这个端点进行通信,然后在公司网络上运行一个小型代理应用程序,该应用程序向 Azure 发起请求以接收传入的工作。采用这种设计,管理员无需在公司防火墙上打开任何入站端口,因为连接是从内部网络发起的。
Service Bus 提供两种不同的操作模式:经纪人消息传递是一种拉取机制,它会将传入的消息缓存到 Azure,直到代理应用程序调用并获取任何待处理的工作。Azure Relay 在 Azure 和代理之间保持一个持久连接,因此工作会立即通过管道推送,并且没有任何缓存。这两种机制都使用相同的 Service Bus 资源;开发者可以选择接收哪一方的消息。
通过 Service Bus 传递的消息完全由使用该服务的开发者自行决定;就像邮局一样,Service Bus 仅负责正确交付数据包,而不关心其内容。由于 Service Bus 非常灵活,管理员必须为管道的消息生产端和消费端编写自定义代码,以创建、解释并处理消息。因此,Azure 门户和 Azure PowerShell cmdlet 仅显示 Service Bus 资源的管理详细信息(例如,待处理消息数量和最后接收到的消息日期),而不显示消息本身的任何详细信息。然而,你可以使用开源工具来检查这些消息。
获取 Service Bus 管理详细信息
每个 Service Bus 实例都有一些对渗透测试者有用的属性:实例名称、资源组、URL 和访问密钥。要获取这些信息,请首先打开 PowerShell 命令提示符,连接到 Azure 订阅,然后运行以下命令:
PS C:\> Get-AzureRmServiceBusNamespace
➊ Name : name
Id : /. . ./ resourceGroups/sbrg➋/. . ./namespaces/name
➌ Location : West US
Sku :
ProvisioningState : Succeeded
Status : Active
CreatedAt : 6/24/2019 2:02:22 PM
UpdatedAt : 6/24/2019 3:01:00 PM
➍ ServiceBusEndpoint : https://name.servicebus.windows.net:443/
Enabled : True
这应该显示当前订阅中的每个 Service Bus 资源,包括其名称 ➊、资源组 ➋(嵌套在 Id 字段中)、地理位置 ➌ 和 URL ➍。每个 Service Bus 也可以有多个访问密钥。每个密钥与一个授权规则相关联,该规则决定了密钥是否可以用于发送消息(发送权限)、接收消息(接收权限)、对队列执行管理操作(管理权限)或这些操作的组合。默认情况下,每个 Service Bus 都有一个主密钥和一个副密钥,这些密钥可以执行任何操作。
要查看给定实例使用的授权规则,请运行以下命令:
PS C:\> Get-AzureRmServiceBusNamespaceAuthorizationRule
-ResourceGroup resource_group -NamespaceName name
Id : /. . ./namespaces/name/AuthorizationRules/RootManageSharedAccessKey
Type : Microsoft.ServiceBus/Namespaces/AuthorizationRules
➊ Name : RootManageSharedAccessKey
Location :
Tags :
➋ Rights : {Listen, Manage, Send}
这应该提供每个规则的名称 ➊ 以及它授予的权限 ➋。你可以在 docs.microsoft.com/en-us/azure/service-bus-messaging/service-bus-sas#rights-required-for-service-bus-operations 上找到有关每个权限的详细信息。
一旦你有了规则名称,你可以运行以下命令来获取与该规则相关联的访问密钥:
PS C:\> Get-AzureRmServiceBusNamespaceKey -ResourceGroup resource_group
-NamespaceName name -AuthorizationRuleName RootManageSharedAccessKey
PrimaryConnectionString : Endpoint=sb://name.servicebus.windows.net/;
SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=Base64_Value
SecondaryConnectionString : Endpoint=sb://name.servicebus.windows.net/;
SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=Base64_Value
PrimaryKey : Base64_Value
SecondaryKey : Base64_Value
KeyName : RootManageSharedAccessKey
使用这些密钥中的任何一个,你应该能够像开发者的应用程序一样与 Service Bus 实例交互。
与 Service Bus 消息交互
一旦你拥有了一个 Service Bus 实例的访问密钥,你应该检查通过该通道传输的消息内容。根据你看到的消息,你可能会采取以下几种行动之一:
-
如果消息包含敏感数据,如电子邮件地址或信用卡号码,这就是一个需要报告的发现。
-
对于看起来会触发某些操作的消息,例如订单处理,检查插入恶意消息是否会导致某些操作,如在未付款的情况下发货。
-
发送包含无效值的消息,看看接收应用是否容易受到常见软件错误的影响,例如远程代码执行、拒绝服务和 SQL 注入。
当然,以上每个操作都需要一个可以与 Service Bus 交互的程序。由于没有本地的 Azure 工具可以做到这一点,因此你有两个选择:尝试修改开发者的代码,或者使用一个独立的工具。如果你在参与过程中已经找到了开发者的源代码(或者你有他们应用程序的副本并且具备逆向工程技能),第一种选择可能是最好的。这将使你能够准确理解该 Service Bus 处理的消息类型,并检查接收者的代码,寻找可利用的错误,例如不充分的消息验证检查。此外,你可能只需要进行少量修改就可以创建测试消息。
然而,在许多情况下,你可能找不到开发者的代码副本。在这种情况下,Service Bus Explorer (github.com/paolosalvatori/ServiceBusExplorer/) 是你最好的选择。Service Bus Explorer 是一个免费的开源工具,用于检查待处理消息、发送测试消息以及执行 Service Bus 上的管理任务。图 6-5 显示了 Service Bus Explorer 查看来自队列的未检索的经纪消息。

图 6-5:Service Bus Explorer 界面
对于特别繁忙的队列,Service Bus Explorer 提供了创建队列监听器的选项;你可以通过右键单击队列名称来访问它。这会打开一个窗口,能够在消息进入队列时进行记录,并显示关于消息处理的数量、大小和速度的统计信息。在查看了若干消息之后,你可以使用同一菜单中的发送消息选项,测试接收者对恶意指令的处理。
关于 Service Bus Explorer 还有一件事需要了解,那就是它如何缓存其凭证。与第四章中讨论的存储工具类似,Service Bus Explorer 允许用户保存他们使用的任何连接字符串。因此,如果你发现它已安装在你攻破的系统上,请检查是否有保存的凭证。这些凭证存储在与 Service Bus Explorer 应用相同的目录下,文件名为 ServiceBusExplorer.exe.Config;这是一个 XML 文件,凭证位于 <serviceBusNamespaces> 部分。
Logic Apps
Logic Apps 是跨网络通信领域的最新参与者,它允许开发人员和代码新手创建事件触发器,触发 Azure 或第三方服务中的一个事件,进而引发一系列其他事件。例如,Logic App 可以监控 Twitter,查找包含公司名称的推文,并将它们记录到 SQL 数据库中。同一个应用还可以发送电子邮件给 CEO,并发布到市场团队的 Slack 频道。
与 Service Bus 依赖开发人员决定如何处理传入消息并编写相应代码不同,Logic Apps 完成了将不同服务连接在一起的所有后台工作。用户只需要通过简单的 GUI 创建一个工作流。
作为其他服务的中介,Logic Apps 的攻击面并不大。它们不会保存它们路由的数据的副本,因此目标服务决定如何处理数据。但有一个渗透测试人员关注的领域:服务凭证。由于能够读取或发布从 Adobe Creative Cloud 到 Zendesk 的所有内容,Logic Apps 有能力缓存大量的凭证或访问令牌,无论是 Microsoft 还是第三方服务。然而,所有的凭证都是只写的;一旦提交,密钥可以被覆盖,但不会再向用户透露。
尽管该设计确实可以防止攻击者窃取服务凭证并在其他地方使用它们,但攻击者仍然可以利用这些凭证进行不法行为。一旦凭证被存储,它就可以在该特定的 Logic App 中访问,并用于与该服务相关的所有操作。换句话说,如果一个 Logic App 包含从 Twitter 读取数据的操作,渗透测试人员可以在该应用中添加一个操作,从同一账户发布推文,而无需额外授权,如图 6-6 所示。
作为渗透测试人员,如果你有权限访问 Azure 门户中的 Logic App,你可以修改它,执行针对该应用已经使用的相同服务的新操作。我建议在门户中执行此操作,因为 Logic Apps 是通过基于 GUI 的编辑器创建的;因此,Logic Apps 的 PowerShell cmdlet 功能有限。

图 6-6:Logic App 设计器显示添加发布推文操作
总结
在本章中,我们讨论了在 Azure 中建立和保护网络的各种方法,以及如何在渗透测试中利用这些技术。我们从内置于 Azure 中的防火墙开始,包括用于虚拟机、SQL 服务器和 Web 应用程序的防火墙。接着,我们了解了 Azure 中可用的 VPN 选项,包括点对站点、站点对站点、多站点和 VNet 对 VNet,以及攻击者如何尝试渗透这些连接。然后,我们讨论了 ExpressRoute,一种类似于 VPN 的专用电路技术,大型公司使用它来直接连接到 Azure。
最后,我们介绍了两种将非 Azure 服务连接到 Azure 的技术:Service Bus 为开发人员提供了一个接收来自云端信息的消息通道,而 Logic Apps 旨在让非开发人员在 Azure、其他服务提供商和企业系统之间构建工作流。在审核网络组件时要格外小心;尽管这些技术都包含了安全机制,但如果配置不当,可能会导致 Azure 虚拟网络、企业网络或第三方服务中的账户被攻破。
第七章:其他 Azure 服务

曾几何时,软件发布的时间表大致与奥运会相吻合——你最喜欢的操作系统、生产力套件或游戏的新版本大约每两年发布一次。尽管可能会有一些临时更新和服务包来修复漏洞,但急切渴望新功能的用户必须等待几个月,直到他们可以排队购买一个装满磁盘或 CD 的纸箱。然而,世界已经脱离了这种范式,发布周期大幅缩短,分发方式发生了变化,甚至公司盈利产品的方式也变了。
这一新模式在 Azure 中尤为明显,新的服务不断上线。在前面的章节中,我专注于任何采用 Azure 的企业可能会使用的核心服务。在这一章中,我们将探讨一些较新的、较少使用的或更具特色的 Azure 服务,并从安全角度审视一些有趣的服务。
我们首先来看看 Key Vault,这是一个用于在云中安全存储和检索凭证(如密码和证书)的机制。然后,我们讨论 Azure 应用服务中的 Web 应用功能,这是发布网站的一个特性。最后,我们将介绍 Azure 自动化服务,这是一个用于在云端和企业网络上自动化管理任务的服务。
最佳实践:密钥库
在 Key Vault 中存储秘密时,你可以采取几种措施来增加额外的安全层次,例如严格控制访问、预加密秘密和使用日志记录。这些措施使得一个本已强大的服务更加难以攻击。
首先,任何秘密存储解决方案的安全性都取决于拥有最弱安全实践的用户。因此,限制能够访问密钥库的人员数量至关重要。通过基于角色的访问控制(RBAC),可以为密钥库及其内容授予非常具体、细粒度的权限。然而,即使对密钥库的权限设置非常严格,如果密钥库位于一个有几十个拥有所有者权限且不需要访问密钥库的用户的订阅中,这也帮助不大。毕竟,这些用户中的任何人都可以利用他们的订阅权限授予自己访问密钥库的权限。为了防止这种情况,我建议你考虑为你的密钥库创建一个单独的订阅,特别是当它存储特别敏感的秘密时。有关密钥库强化的更多细节,请访问 docs.microsoft.com/en-us/azure/key-vault/key-vault-secure-your-key-vault/。
如果你使用 Key Vault 存储不会被其他云服务直接使用的机密,可能值得考虑在将机密放入 Key Vault 之前先进行本地加密。当然,Key Vault 会将所有数据以加密格式存储;然而,如果攻击者破坏了用于检索机密的帐户,他们可以获取解密后的机密。如果你在上传之前对机密进行本地加密(并将解密密钥存储在离线位置),即使攻击者获得了有访问权限的帐户,他们也只能拉取加密后的值,而无法获得明文机密。
与其他服务一样,Key Vault 的日志记录也非常重要。启用后,日志包含诸如密钥枚举、创建、读取、写入和删除等信息。这些日志包含有助于识别非法访问的详细信息,如调用者的 IP 地址和发起请求的帐户。有关 Key Vault 审计日志的更多细节可以在 docs.microsoft.com/en-us/azure/key-vault/key-vault-logging/ 中找到。
审查 Azure Key Vault
Azure Key Vault 是一项服务,允许开发者将密码、连接字符串、存储密钥、证书等安全地存储起来,以便在其他 Azure 服务中使用。作为渗透测试人员,我喜欢 Key Vault,因为我可以将其作为解决许多常见渗透测试问题的建议。而且,如果用户错误配置了 Key Vault 实例,它还可以成为进一步访问目标环境的凭证来源。
说我在大多数报告中将 Key Vault 作为潜在解决方案是毫不夸张的。在“获取凭证”的第 15 页,我演示了如何轻松地在源代码库、错误的配置文件甚至开发者工作站上发现密码和其他机密信息。Key Vault 提供了一个 API——大多数主要编程语言都有库和示例代码——使开发者能够轻松地将这些敏感信息存储在一个安全、受控访问、可审计的位置。尽管 Key Vault 并不能防止所有开发者的错误,但它在解决机密信息清理问题上表现优秀。
Key Vault 中提供了三种不同类型的存储:机密、密钥和证书。每种存储为渗透测试人员提供了不同的机会,详细内容将在以下各节中说明。
显示机密
机密是由名称和文本值组成的键值对;文本值可以大到 25KB,并支持版本历史。你可以在门户中、使用 API 或 PowerShell 查看机密的文本值——前提是你的账户具有正确的权限。因为机密可以被检索,微软的文档建议在保存机密到 Azure 之前,特别敏感的机密应先用公钥加密。解密机密的私钥将存储在 Key Vault 的 HSM 存储中,从而保护私钥和机密不被未经授权访问。
如果你怀疑某个账户可能有权限访问 Key Vault 实例及其机密,使用 PowerShell 一次性列出所有这些信息。为此,请运行清单 7-1 中显示的脚本。
PS C:\> ➊ $keyvaults = Get-AzureRmKeyVault
PS C:\> foreach ($keyvault in $keyvaults)
>> {
>> $vault = $keyvault.VaultName
>> ➋ $secrets = Get-AzureKeyVaultSecret –VaultName $vault
>> foreach ($secret in $secrets)
>> {
>> $value = Get-AzureKeyVaultSecret –VaultName $vault -Name $secret.Name
>> ➌ Write-Output "$vault`: $($secret.Name) = $($value.SecretValueText)"
>> }
>> }
shhh: BackendDbConStr = Server=mydb;Database=prod;User ID=admin;Password=1234
shhh: password = MyB@dPassw0rd
清单 7-1:显示 Key Vault 机密
脚本首先获取订阅中 Key Vault 实例的列表 ➊。然后,在每个实例中检索所有机密的列表 ➋。最后,对于每个机密,它以 Vault 名称: 机密名称 = 机密值的格式输出该机密 ➌。
显示密钥
密钥存储允许用户将 RSA 非对称密钥生成或上传到 Key Vault。在 Vault 内部,这些密钥可以用于执行加密操作,如签名、验证、加密和解密,使用 Azure 的 API。密钥上传后,Azure 不允许用户导出它们,除非以加密备份的形式,这种备份仅能用于将密钥恢复到 Azure 中。
由于没有人可以导出密钥,Key Vault 的密钥存储部分对渗透测试者来说相较于机密存储稍显乏味。然而,如果你可以访问一个有权限调用加密 API 的账户,你仍然可能能够利用这些密钥。但在你能利用这些密钥之前,你需要知道每个密钥的使用方式。
Azure 要求每个密钥必须有一个名称,这个名称可能暗示其用途。它还允许用户为每个密钥关联最多 15 个标签(或 256 字符的名称-值对)。组织可以选择如何使用这些标签,这些标签可能会提供有关密钥用途的额外信息。清单 7-2 展示了如何使用 PowerShell 显示订阅中每个 Vault 的每个密钥的详细信息。
PS C:\> $keyvaults = Get-AzureRmKeyVault
PS C:\> foreach($keyvault in $keyvaults)
>> {
>> $vault = $keyvault.VaultName
>> ➊ $keys = Get-AzureKeyVaultKey –VaultName $vault
>> foreach ($key in $keys)
>> {
>> Write-Output $key
>> ➋ Get-AzureKeyVaultKey –VaultName $vault -KeyName $key.Name
>> }
>> }
➌ Vault Name : shhh
➍ Name : key1
Version :
Id : https://shhh.vault.azure.net:443/keys/key1
Enabled : True
➎ Expires :
Not Before :
Created : 8/12/2018 4:54:07 AM
Updated : 8/13/2018 6:09:15 AM
Purge Disabled : False
➏ Tags : Name Value
CreatedBy Matt
Attributes : Microsoft.Azure.Commands.KeyVault.Models.KeyAttributes
Key : {"kid":"https://shhh.vault.azure.net/keys/key1/Version",
"kty":"RSA",➐"key_ops":["sign","verify","wrapKey",
"unwrapKey","encrypt","decrypt"],"n":"4vaUgZCV3OG...",
"e":"AQAB"}
VaultName : shhh
Name : key1
Version : ed2ebbdc51754d45b69bd6551d2d2052
Id : https://shhh.vault.azure.net:443/keys/key1/Version
清单 7-2:显示 Key Vault 密钥信息
与机密检索脚本类似,密钥脚本从遍历 Key Vault 实例开始。在每个实例中,首先检索到密钥列表 ➊,然后打印每个密钥的详细信息 ➋。输出包括 Vault 实例名称 ➌、密钥名称 ➍、密钥有效期 ➎、标签 ➏ 以及密钥可执行的操作 ➐。
一旦确定了密钥的用途,你可能会将其用于相同的目的。例如,如果密钥用于签署文件以证明真实性,你可能会生成伪造文件。或者,如果它用于加密文件,你可以解密这些文件。在 PowerShell 中没有简单的方法来做到这一点,但 Microsoft 确实提供了KeyVaultClient类,它在KeyVault库中支持这些操作,并且可以在 .NET 和 Java 中使用。你可以在* www.microsoft.com/en-us/download/details.aspx?id=45343*找到示例代码。
显示证书
证书存储是 Key Vault 中“秘密”类别下的一个特殊类别。用户可以上传 PFX 文件,或者让 Key Vault 生成自签名证书或证书请求。然后,他们可以使用这些证书,例如,用于保护用户与自定义 Azure 应用程序之间的通信。Key Vault 的密钥和证书功能都涉及非对称加密,但它们的预期用途略有不同。密钥用于提交加密操作,并通过安全存储中的私钥执行操作。证书可以在不同的应用程序中使用,例如,用于加密的同时确认站点名称(以及其他属性和预期用途)的站点证书,因此即使在 Azure 外部也能使用。
Key Vault 会遵循添加到其中的证书的导出标志。因此,如果用户导入一个标记为不可导出的证书,攻击者将无法恢复它。但如果密钥标记为可导出,它就可以像其他 Key Vault 秘密一样被检索。事实上,如果用户在创建 Key Vault 证书时没有指定导出策略,它默认为可导出。列表 7-3 演示了如何列出 Key Vault 中的证书、查看其详细信息并获取公钥,以及(如果可访问)私钥。
PS C:\temp> $keyvaults = Get-AzureRmKeyVault
PS C:\temp> foreach ($keyvault in $keyvaults)
>> {
>> $vault = $keyvault.VaultName
>> $certs = Get-AzureKeyVaultCertificate –VaultName $vault
>> foreach ($cert in $certs)
>> {
>> $cn = $cert.Name
>> ➊ $c = Get-AzureKeyVaultCertificate –VaultName $vault -Name $cn
>> $x509 = $c.Certificate
>> Write-Output $c
>> ➋ $privkey = (Get-AzureKeyVaultSecret -VaultName $vault
-Name $cn).SecretValueText
>> Write-Output "Private Key:"
>> Write-Output $privkey
>> Write-Output ""
>> Write-Output "Exporting Public Key to $cn.cer..."
>> ➌ Export-Certificate -Type CERT -Cert $x509 -FilePath "$cn.cer"
>> Write-Output "Exporting Private Key to $cn.pfx..."
>> $privbytes = [Convert]::FromBase64String($privkey)
>> ➍ [IO.File]::WriteAllBytes("$pwd\$cn.pfx", $privbytes)
>> Write-Output "----------------------------------------------"
>> }
>> }
Name : devcertificate
Certificate : [Subject]
CN=test.burrough.org
[Issuer]
CN=test.burrough.org
[Serial Number]
72AF4152C9F54651B9AE039730FB1AAD
[Not Before]
8/13/2018 11:06:23 PM
[Not After]
8/13/2019 11:16:23 PM
[Thumbprint]
9C5A0E244E353369560EFBE4EDB015D3FDE54635
Id : https://shhh.vault.azure.net:443/certificates/devcertificate/Id
KeyId : https://shhh.vault.azure.net:443/keys/devcertificate/Id
SecretId : https://shhh.vault.azure.net:443/secrets/devcertificate/Id
Thumbprint : 9C5A0E244E353369560EFBE4EDB015D3FDE54635
Tags :
Enabled : True
Created : 8/14/2018 6:16:23 AM
Updated : 8/14/2018 6:16:23 AM
Private Key:
MIIKTAIBAzCCCgwGCSqGSIb3DQEHAaCCCf0Eggn5MIIJ9TCCBhYGCSqGSIb3DQEHAaCCBgcEggYD
--snip--
Exporting Public Key to devcertificate.cer...
LastWriteTime : 8/14/2018 9:23:48 PM
Length : 834
Name : devcertificate.cer
Exporting Private Key to devcertificate.pfx...
----------------------------------------------
列表 7-3:显示 Key Vault 证书
这个最终的 Key Vault 枚举脚本与其他脚本一样开始——通过遍历 Key Vault 实例,然后是证书。对于每个证书,你需要两次调用 Azure 才能获取其详细信息。第一次调用Get-AzureKeyVaultCertificate会检索关于证书的公共信息,包括主题、指纹、有效期和公钥 ➊。然后,调用Get-AzureKeyVaultSecret获取证书的私钥部分(如果可用) ➋。接下来,脚本将公钥值导出到当前工作目录中的证书文件(证书名称.cer) ➌。最后,创建一个包含公钥数据和私钥信息(如果可导出的)的 PFX 文件 ➍。
DEFENDER’S TIP
如果你不打算将证书用于 Key Vault 之外的地方,务必将其标记为不可导出。为此,在创建证书时,将 -KeyNotExportable 选项传递给 New-AzureKeyVaultCertificatePolicy cmdlet。如果你有非常敏感的证书或密钥,可以考虑 Key Vault 的物理硬件安全模块(HSM)选项。虽然这个选项比基于软件的 HSM 版本更昂贵,但证书被存放在行业标准的加密设备中,这些设备旨在防止私钥在添加到设备后被提取。
通过其他 Azure 服务访问 Key Vault
用户可以在 Azure 门户的高级访问策略设置中配置 Key Vault 实例,允许虚拟机、Azure 资源管理器和 Azure 磁盘加密访问,如 图 7-1 所示。

图 7-1:Azure Key Vault 的高级访问策略——允许其他服务访问
这些设置各有其用途:虚拟机可以在 Key Vault 中存储和访问 SSL 证书,Azure 资源管理器可以创建和部署需要机密的模板(例如虚拟机模板的本地管理员密码),Azure 磁盘加密使用 Key Vault 的机密存储来保存虚拟硬盘(VHD)的加密密钥。这些都是 Key Vault 的非常好的使用场景,比将这些机密提交到源代码管理系统要安全得多。然而,这也意味着具有管理虚拟机或修改和部署模板权限的用户,可能能够访问他们本不应查看的 Key Vault 数据。
DEFENDER’S TIP
因为高级访问策略是在 Key Vault 实例级别设置的,所以实例中的所有机密都遵循相同的策略。因此,最好创建多个密钥库,并限制每个库的访问权限,仅允许特定的服务访问。每个密钥库应仅包含那些所有拥有访问权限的服务所需要的机密。
针对 Web 应用的攻击
Azure 应用服务中的一部分子集,Web 应用是设计用于在 Azure PaaS(平台即服务)上运行的网站。开发人员可以使用多种语言编写 Web 应用——例如 ASP.NET、PHP、JavaScript、Node.js 和 Python——并在 Windows 或 Linux 容器中运行它们。识别这些网站通常很容易,因为它们默认的 URL 为 <网站名称>.azurewebsites.net,但如果在非免费服务层中部署,开发人员可以为 Web 应用设置自定义域名。
Web 应用是一个有趣的攻击目标,原因有几个:
-
它们是面向公众(互联网)的,因此篡改可能会对客户造成声誉损害。
-
它们使用的部署帐户可能会在开发人员工作站上被攻击者发现。
-
它们是 Azure 的热门功能,并被许多企业使用。
-
免费套餐中的站点通常是开发者测试站点,安全规划较少,但它们可能包含生产站点的机密信息。
-
他们的代码有时包含访问其他服务的凭证,例如 Azure SQL。
基于这些原因,渗透测试人员在 Azure 评估中应始终包括 Web 应用。
部署方法
当开发人员想将他们最新的站点版本发布到 Azure 时,他们必须做出两个选择:使用什么部署方法以及使用什么凭证进行身份验证。Web 应用支持几种不同的方式将代码加载到站点中:
-
FTP/FTPS
-
WebDeploy
-
Git 仓库(本地或在 GitHub 上)
-
来自外部服务的部署,例如 OneDrive、Dropbox 或 Bitbucket
熟悉这些方法是很有好处的;当你获得开发者工作站的访问权限时,这将帮助你识别哪些工具可能缓存了凭证或保存了源代码副本。
Web 开发者传统上使用 文件传输协议(FTP)将网站推送到服务器,尽管这不是一个好的选择,因为用户的凭证和文件内容是未加密发送的。如果你发现开发者使用 FTP,这本身就是一个问题!
幸运的是,Azure 也支持 FTP Secure(FTPS),它是加密的,也是一个可接受的选择。在任何找到已保存连接的地方,查看协议部分(位于服务器地址之前)以确定正在使用的连接类型。连接到 FTP 的用户会看到以 ftp:// 开头的连接,而安全连接则会使用 ftps://。
另一种常见的部署方法是 WebDeploy,也叫做 MSDeploy,它可以通过 Visual Studio 或 msbuild.exe/msdeploy.exe 编译工具管道来发布编译后的项目。WebDeploy 最初不是用来发布到 Azure,而是开发者将站点部署到 Microsoft IIS Web 服务器时使用的。因此,我并不惊讶它似乎在使用 Microsoft ASP.NET 语言编写的站点中被广泛使用。WebDeploy 仅在 Windows 客户端上可用。你也可能遇到一个名为 WAWSDeploy.exe 的工具,它是 WebDeploy 的一个封装工具,简化了其使用。
对于使用 git 管理源代码的开发者而言,直接从 git 客户端进行部署是非常方便的。鉴于 git 的流行程度不断增长,我预计使用这种方法的开发者数量将显著增加。使用这种方法时,开发者只需从 Azure 门户获取部署凭证和 git 仓库 URL,然后使用 git 将站点推送到远程主分支。开发者不需要在工作站上安装任何特殊的工具或库。
Azure 还支持越来越多的外部服务,开发人员可以利用这些服务为 Web 应用阶段性地准备内容,例如 Visual Studio Team Server、OneDrive、Bitbucket 和 Dropbox。此功能通常被称为云同步,与前面讨论的其他方法不同。所有其他部署方法都在开发人员的系统上运行,使用从 Azure 获得的凭证,将内容推送到 Azure;但云同步则采用拉取模型。开发人员授权 Azure 访问他们的在线存储提供商,然后 Azure 从外部服务的指定文件夹中拉取内容到 Web 应用。
获取部署凭证
除了云同步以外的每种部署方法,Web 应用开发人员在上传文件到他们的网站时必须提供用户名和密码。这些部署凭证不同于用户的 Azure 门户登录信息——该账户无法用于部署网站。相反,开发人员可以选择使用用户特定的部署账户或站点特定的账户。无论哪种账户类型,都可以用于 FTP、WebDeploy 和 git 部署;两种凭证的区别在于它们的共享对象以及可以在哪里找到。
用户部署凭证
每个 Azure 用户可以创建一个部署账户,用于添加、删除或更改他们有权限修改的任何网站上的文件,适用于他们可以访问的所有订阅。要创建此账户或重置其密码,用户必须执行以下操作:
-
登录到 Azure 门户并导航到 应用服务。
-
选择他们订阅中的任何 Web 应用(如果没有现有的,可以创建一个新的)。
-
点击 部署凭证。
-
指定用户名和密码。
账户创建后,账户持有者可以在他们的任何 Web 应用中使用该账户,站点之间只有轻微的差异。要连接到每个网站,用户必须以 <网站名称><用户名> 格式输入用户名,并指定他们的密码。例如,假设开发人员选择了用户名 webadmin,并指定 Awe5omeDev# 作为他们(相对较弱的)密码。要管理网站 azweb8426.azurewebsites.net/,开发人员将在他们选择的部署工具中输入 azweb8426\webadmin作为用户名,并输入Awe5omeDev# 作为密码。如果开发人员之后想要在 *[bkunaenk.azurewebsites.net/](http://bkunaenk.azurewebsites.net/)* 上工作,他们将输入 bkunaenk\webadmin作为用户名,并输入Awe5omeDev#` 作为密码。
由于相同的凭证被广泛用于所有站点,攻击者如果破坏了它,就可以修改任何该开发人员有权限访问的站点——甚至是一些与该开发人员无关的站点,只要它们位于同一个订阅中,并且权限设置过于宽泛。假设有一个拥有 50 名管理员的订阅,每个管理员都拥有并管理一个站点,但他们都没有更改自己站点的所有者或贡献者权限——因此,任何拥有订阅访问权限的人都可以修改该站点。一个仅有个人博客的开发人员可能不会特别关注保护自己的凭证,而另一个负责公司主页的开发人员则可能会非常小心地保护自己的密码。在这种情况下,第一个开发人员的凭证就可以对第二个开发人员的站点进行修改!这同样适用于一个开发人员拥有多个 Web 应用的情况,其中只有部分应用是重要的。
那么,在哪里可以找到用户的部署凭证呢?这取决于用户,但通常你可以在 FTP 客户端、密码管理器或用户主目录中的 git 凭证存储文件(如 .git-credentials)中找到它们。但如果用户通过 Visual Studio 使用 WebDeploy 或 FTP,你可能就没戏了。Visual Studio 会将用户的密码保存在一个加密的 Blob 中,存储在名为
注意
你可以在 Azure 门户中重置部署账户,而无需知道当前密码,因此,如果你有门户访问权限,你可以随时将密码更改为不同的值。然而,如果账户突然无法使用预期密码,用户可能会注意到。还需要注意的是,部署账户本身并不授予门户访问权限,只是能够更改 Web 应用文件的权限。
应用部署凭证
另一种部署凭证是应用特定的。每个 Web 应用都有一个单独的部署凭证,该凭证在该站点的所有开发人员之间共享,并且可以在与用户部署账户相同的地方使用:FTP、WebDeploy 和 git。
这种类型的账户比用户部署凭证具有稍低的风险,因为如果凭证泄露,攻击者只能修改单一站点。然而,凭证的安全性取决于持有它的开发人员的安全意识最差的情况。此外,如果攻击者破坏了多个用户可以访问的凭证,那么可能很难确定漏洞发生的具体位置。最后,共享账户在员工离职、被解雇或角色变动时往往不会重置,因此用户的访问权限可能会比预期的持续更长时间。
Azure 门户不会显示应用部署凭证。相反,开发人员可以通过在 Azure 门户中导航到 Web 应用,然后点击概览标签上的 获取发布配置文件 按钮,如 图 7-2 所示,来获取凭证。如果管理员担心账户已被泄露,他们可以使用相同工具栏上的 重置发布配置文件 按钮重置凭证。

图 7-2:获取 Web 应用的发布配置文件
获取发布配置文件 按钮会启动一个下载,下载的文件名为
-
Web 应用目标 URL
-
用于 WebDeploy 和 FTP 部署的 URL
-
应用部署用户名,始终为
<App Name>$ -
应用部署密码,它是一个明文的、60 字符的字母数字字符串
文件中还可能包含一些可选数据,例如应用所依赖的数据库的连接字符串以及 Azure 门户的 URL。
因为此账户的密码没有加密,其他用户可以复制 Web 应用的发布设置文件,并从另一台计算机使用它。所以,如果你能够访问开发工作站或代码仓库,请查找这些文件,因为它们将包含连接到 Web 应用服务器所需的所有信息。
在 Web 应用服务器上创建和搜索工件
一旦你访问了应用服务器,你可能需要做一些事情。首先,如果你需要向客户证明你已访问服务器,可以考虑放置一个小的文本文件,文件扩展名为 .config,声明你曾经在那里。这种标记比公开可见的更改要好得多,而且因为应用服务器不会将 .config 文件暴露给网页浏览器,网站的用户无法看到它;只有登录到服务器的管理员才能看到。
你还可以使用服务器尝试捕获凭证,通过修改 Web 应用隐秘地将登录信息以安全的方式存储下来。或者,你可以向网站添加一个页面,用于网络钓鱼,因为用户可能会信任这个页面,因为它托管在一个合法的网站上。
警告
在修改或添加公共网站页面之前,一定要确保你的参与规则允许进行此类活动——特别是当你添加代码以外泄用户信息或凭证时。这通常在渗透测试中是禁止的!如果有任何疑虑,请与客户和律师确认。像往常一样,你还应该确保记录并跟踪你所做的任何更改,以便在参与结束时完全撤销所有更改。
我在入侵 Web 服务器时最喜欢做的事情之一是寻找不向站点用户暴露的机密。例如,.config、.asp、.aspx 和 .php 文件通常不会直接返回给用户请求的内容。因为 config 文件通常包含机密信息,所以它们根本不会返回,而 ASP 和 PHP 文件会首先在服务器上呈现,然后只返回客户端准备好的结果。通过 FTP 访问这些文件,你可以查看原始代码,保留任何嵌入的机密信息。然后,你通常可以进一步访问数据库服务器或其他后端系统。
除了未提供服务的文件,应用服务器可能还包含一些难以找到的文件。例如,开发人员可能会将页面上传到服务器,但延迟在站点的其他页面上链接它们,直到某个特定的时间,比如新产品发布时。有些开发人员可能会创建仅供那些知道如何找到它们的人访问的页面,例如管理员登录表单。发现这些文件可能会被视为一个发现点,如果这些信息在公开时会对客户造成伤害,或者如果该信息依赖于“通过模糊性实现安全”来保护。机密数据不应在面向公众的网站上可以访问,即使它不容易被发现。
最佳实践:Automation
Azure Automation 是一个强大的工具,用于自动化云端和本地的重复任务。然而,它能够执行多种任务,也使其在被恶意行为者使用时成为一个安全隐患。以下是一些帮助保持 Azure Automation 作业安全的步骤。
开始时要小心你在 Azure Automation 的变量存储中放置了哪些值或 资产。Automation 允许用户存储像凭证这样的东西,凭证可以被作业用来访问它们执行工作所需的资源。资产是加密存储的,但由于运行中的作业需要使用它们,因此解密密钥存储在可以访问 Automation 的 Key Vault 中。这意味着任何可以创建并运行作业的人,都能够获取任何资产的明文值,正如在“获取 Automation 资产”一节中,位于第 152 页所描述的那样。如果你存储凭证作为资产,请确保这些凭证拥有完成任务所需的最少权限。
接下来,如果你计划让自动化在你的企业环境中启动任务,你需要设置混合工作者,这涉及到在本地系统上安装一个代理,详细内容见第 157 页。默认情况下,这些代理将在这些服务器上使用本地系统帐户运行作业,这意味着作业将具有对运行它们的服务器的完全管理员访问权限。因此,你绝不应该将敏感系统配置为混合工作者。尽管混合工作者及其运行的作业肯定需要某种程度的资源访问权限才能完成任务,但请确保创建一个良好的威胁模型,并考虑到这种云到企业访问可能带来的任何风险。
利用 Azure 自动化
另一个值得讨论的最终服务是 Azure 自动化,它本质上是云中的一个复杂任务调度程序。管理员使用 PowerShell 或 Azure 门户中的图形编辑器创建 运行簿,即任务的工作流。运行簿可以执行多种多样的操作。例如,它可以每五分钟解析一次日志文件,然后在发生严重错误时向管理员发送警报。如果某个任务是重复性的,使用云资源,并且可以用 PowerShell 脚本化,那么它是自动化的一个良好候选项。
尽管 Azure 自动化是一个功能复杂的服务,具有许多功能,但有两个组件对安全专业人员尤为重要:资产和混合工作者。自动化资产是 Azure 中的另一个位置,用户可以在其中存储机密,类似于一个 Key Vault 实例。混合工作者允许运行簿使用本地资源执行任务,这与第六章中某些网络桥接技术类似。
获取自动化资产
任何曾在系统管理中工作过的人,可能都写过数十个,甚至数百个脚本,以提高工作效率并减少繁琐的工作。尽管这些脚本在作者、组织和目标平台之间差异很大,但几乎每个脚本都有变量和输入数据。通常,这包括脚本应该使用的帐户、目标系统的列表以及记录任何输出的位置。
Azure 自动化需要允许这种输入,以便其运行簿能够提供比最基本功能更多的功能。但与传统脚本不同,运行簿是由 Azure 执行的,而不是由用户从命令行执行。为了弥补这一差距,Azure 自动化允许用户在自动化服务中声明并保存变量、凭据、连接和证书——统称为 资产。运行簿可以引用这些资产,但它们不是特定于运行簿的;它们在一个自动化帐户内的所有运行簿之间共享。尽管一个订阅可能有多个自动化帐户,但资产在这些帐户之间是不可共享的。
让我们讨论四类资产,它们相似但有微妙的区别:
变量
在定义变量时,开发人员提供名称、数据类型、值和可选描述,并指定是否应加密存储值。如果设置了加密标志,Azure 门户将不会显示该变量的数据类型,并且值字段将显示为星号。然而,由于运行簿需要能够使用该值,用户可以通过在运行簿中使用 Get-AutomationVariable cmdlet 来显示变量,无论它们的加密状态如何。
连接
连接用于在运行簿中登录到 Azure 订阅。用户可以使用 Get-AutomationConnection cmdlet 检索连接,它返回一个哈希表,其中包含以下键的值:SubscriptionId、ApplicationId、TenantId 和 CertificateThumbprint。通常,这些值会在随后的调用中用于 Add-AzureRMAccount 以连接到所需的订阅。连接对象本身不包含任何机密数据。
凭据
在 Azure 自动化中,凭据存储在 PSCredential 对象中,包含对象名称、用户名、密码和可选描述。与加密变量类似,凭据在 Azure 门户中被加密,以保护其密码。即使使用 Get-AutomationPSCredential cmdlet 来检索凭据,Azure 也不会显示值,因为它期望开发人员将返回的整个 PSCredential 对象传递给任何需要该账户的系统。然而,用户可以通过调用 PSCredential 对象上的 GetNetworkCredential 函数来显示密码和用户名。
证书
用户可以以 .cer(仅公钥)或 .pfx(公钥和私钥)形式将 X.509 证书上传到 Azure 自动化。当创建自动化帐户时,Azure 提供了一个选项,可以自动填充证书存储,其中包含两个可以用于管理 ASM 和 ARM 资源的证书:AzureClassicRunAsCertificate 和 AzureRunAsCertificate。如果用户拒绝此选项,Azure 会第二次提示用户确认,因为这些证书对于完成 Azure 中的任务非常有用。因此,您应该期望在几乎所有遇到的自动化帐户中看到这些证书。尽管用户可以上传用于任何目的的证书,但自动化中的证书通常与连接一起使用,以管理其他 Azure 资源。您可以使用 Get-AutomationCertificate cmdlet 检索证书,它将检索证书的详细信息、公钥和私钥(如果存在)。
使用刚才讨论过的 cmdlet 和函数,您可以创建一个 runbook 来收集可能有助于进一步渗透客户端环境的资产值。首先打开 Azure 门户,从服务列表中选择 Azure 自动化。在自动化帐户窗口中,检查是否有现有的自动化帐户,如图 7-3 所示。

图 7-3:Azure 自动化帐户列表
如果没有列出任何项,则目标订阅没有使用自动化,您可以跳过此部分。如果列出了多个帐户,您需要对每个帐户执行本节中的步骤。点击某个自动化帐户的名称以打开它。接下来,您应该看到类似于图 7-4 的视图。
一旦显示出特定帐户,您可以浏览查看自动化的使用情况。点击Runbooks并查看脚本的名称。如果有任何看起来有趣的,点击它们,然后点击编辑查看其源代码——只是确保不要保存任何更改。您还可以通过点击左侧菜单中共享资源部分下的各种标签,快速浏览可用的资产,如图 7-4 所示,但 Azure 不会显示任何机密值。
要显示所有资产,包括密码、加密变量和证书私钥,点击Runbooks,然后点击页面顶部的添加 runbook。在出现的菜单中,点击创建新的 runbook,然后为 runbook 提供一个名称,并选择PowerShell作为 runbook 类型。最后,点击创建。

图 7-4:自动化帐户的主视图
一个空白的 runbook 将出现。在左侧,树状视图提供了可用的 PowerShell cmdlet、其他 runbook,以及最重要的,可以使用的资产列表。展开资产对象以及每个嵌套项,如图 7-5 所示。
对于每个听起来有趣的资产,您可以点击资产名称旁边的省略号菜单,然后点击添加到画布。这将向 runbook 中添加一行新代码,用于检索该资产。对于变量和连接,这足以显示这些元素中有趣的部分。然而,对于凭证和证书,您需要添加几行额外的代码来获取密码和私钥。

图 7-5:runbook 可用资产列表
对于密码,将Get-AutomationPSCredential凭证的输出存储在一个变量中,然后使用GetNetworkCredential()获取用户名和密码值,如下所示:
$cred = Get-AutomationPSCredential -Name 'credential_name'
$cred.GetNetworkCredential().username
$cred.GetNetworkCredential().password
查看证书时,我喜欢显示证书的名称和指纹,以及其公钥和私钥的 XML 格式。这应该足以将证书导入到不同的系统中,以便在 Azure 外部使用。要做到这一点,请在 runbook 中输入以下内容:
➊ $cert = Get-AutomationCertificate -Name 'certificate_name'
➋ $cert
➌ $cert.PrivateKey.ToXmlString($true)
➍ $cert.PublicKey.Key.ToXmlString($false)
这将把证书对象保存到变量 ➊ 中,显示其指纹和主题 ➋,并输出其私钥 ➌ 和公钥 ➍。图 7-6 显示了准备执行的完整 Runbook。

图 7-6:完成的 Runbook 用于检索资产
一旦您对您的 Runbook 感到满意,点击保存,然后点击测试窗格。这将打开一个新视图,在该视图中您可以点击开始来执行 Runbook。运行结束后,任何输出将以白色显示,如图 7-7 所示。如果您的 Runbook 出现异常,错误信息将以红色显示在输出区域。

图 7-7:带有输出的 Runbook 测试窗格
在测试窗格中,您可以看到完成的 Runbook 执行情况,以及变量值、连接详情、凭据用户名和密码、证书详情,以及您请求的公钥和私钥。然后,您可以利用这些信息进入之前可能无法访问的订阅、服务或系统。
混合工作节点
除了能够在云中自动化任务外,Azure 自动化还能够在公司网络上执行任务。Azure 提供了一个软件包,管理员可以将其安装在多个本地系统上。这些机器随后成为混合工作节点,接收来自 Azure 自动化的命令并在公司网络上执行。这类似于第六章中讨论的网络桥接技术;不过,那些服务是为在公司与云之间传输数据而设计的,而混合工作节点则用于向公司系统发送管理命令。
混合工作节点机制
设置混合工作节点并不简单。管理员需要在mms.microsoft.com/创建一个操作管理套件(OMS)账户,在 OMS 门户中启用自动化解决方案,在他们希望作为混合工作节点的机器上下载并安装一个名为 Microsoft 管理代理的程序,然后在这些系统上运行New-OnPremiseHybridWorker**.ps1脚本,指定工作节点应使用的订阅和自动化账户。因此,您不太可能在每个自动化账户中找到一个混合工作节点,但那些有混合工作节点的账户很可能正在使用它。对于渗透测试人员来说,这是个好消息,因为这意味着混合工作节点系统通常是在线的,并且可以访问公司网络上的有趣账户和系统。
安装后,混合工作者通过运行名为MonitoringHost.exe的系统中心管理服务主机进程来操作,该进程通过 HTTPS 与azure-automation.net服务器进行通信,查找任务。一旦找到任务,它会生成一个Orchestrator.Sandbox.exe实例,该实例随后运行运行簿脚本。如果需要,Orchestrator.Sandbox.exe可以启动conhost.exe进程来执行非 PowerShell 命令。默认情况下,所有这些进程都以NT AUTHORITY\SYSTEM账户运行,这意味着运行簿具有对充当混合工作者的系统的管理权限,但它们不会自动访问域上的其他系统。此时,凭证资产—即存储在 Azure 自动化中的凭证供运行簿使用—就派上用场了;如果运行簿需要访问公司域上的其他系统(例如,从网络共享复制文件),则需要使用具有这些权限的账户。运行簿开发人员可以通过Get-AutomationPSCredential cmdlet 直接在脚本中使用凭证,或者可以设置混合工作者以凭证资产的身份运行所有脚本。无论哪种方式,开发人员都必须将凭证存储在自动化账户中。
识别混合工作者
判断一个自动化账户是否包含混合工作者很简单:在 Azure 门户中,导航到一个自动化账户实例,然后点击账户菜单中的混合工作者组。可能会列出一个或多个工作者组;每个组是一个可以分配工作的一个或多个混合工作者的池。要查看某个组中有哪些机器,请点击组名。这将打开该组,如图 7-8 所示。

图 7-8:混合工作者组面板
在此面板中,您可以通过点击混合工作者图标来查看此组中各个服务器的名称。您还可以通过点击混合工作者组设置来查看该组中的工作者是否以默认的本地系统账户运行,或是否使用凭证资产,如图 7-9 所示。

图 7-9:展示使用自定义凭证的混合工作者组设置
给定组中的所有混合工作者都使用相同的凭证运行。
使用混合工作者
当我找到一个带有 Hybrid Workers 的自动化账户时,我立刻好奇我能用它做什么。如果你是一个外部人员,通过自动化作为进入网络的入口点,你可能完全不知道 Hybrid Worker 服务器或凭据资产可以访问哪些内容。一个好的入门方法是查看账户中现有的任何运行手册。通过这种方式,你将了解订阅是如何使用自动化的,并且至少了解一些可以使用凭据资产的系统。为此,选择 Azure 门户中自动化账户的运行手册标签;然后点击任意运行手册并点击编辑按钮。这将显示源代码。
在自动化账户面板中,你可能还想查看活动日志和调度标签。活动日志标签让你查看最近运行的任何任务,以及是否有人对运行手册、Hybrid Worker 组或资产进行了更改。调度标签显示任何即将执行的运行手册,这在你计划修改现有运行手册并需要知道下一个将执行的是哪个时非常有用。
一旦你对自动化账户有了一些了解,你可能会创建或修改一个运行手册,以便在 Hybrid Worker 上运行代码。为此,按照我们在“获取自动化资产”中所做的相同步骤来创建一个运行手册,详见第 152 页。一个好的初始测试运行手册可能是这样的:
Write-Output "Hybrid Worker Computer Name: $env:COMPUTERNAME"
Write-Output "Worker running as: $(whoami)"
Write-Output $host
这个运行手册显示了分配的工作者的名称,脚本以哪个账户运行,以及一些关于主机进程的信息。
一旦运行手册完成并且你打开测试面板,你将看到一个标有运行在的选项。选择Hybrid Worker按钮,而不是 Azure,然后从选择 Hybrid Worker 组下拉列表中,选择你想执行代码的组。你不能为运行手册选择特定的工作者;自动化将根据其调度器分配任务。一旦点击开始,任务将被发送到一个工作者,结果将在测试面板中显示——就像运行手册在 Azure 上运行时一样,如图 7-10 所示。

图 7-10:在 Hybrid Worker 上完成的运行手册执行
此时,你已经有了一个相当理想的渗透测试设置。你有一个可以访问私有网络的外部入口点,拥有该网络的凭据,并且有现有的脚本作为起点。从这里,你可以使用你最喜欢的 PowerShell 命令进行后期利用,探索网络,切换到其他系统,收集战利品,等等。
总结
在本章中,我们介绍了三个 Azure 独有的服务:Key Vault、Web Apps 和 Azure Automation。每个服务都对信息安全专业人员提出了挑战,同时也带来了机会。Key Vault 可以解决渗透测试人员发现的许多问题,但如果配置错误,也可能会有自身的问题。Web Apps 使得新网站的开发和部署变得非常简单,但也存在一些凭证管理的问题风险。而 Azure Automation 尽管是一个学习起来较为复杂的服务,从安全角度来看,最有趣的组件与 Azure 中其他部分使用的概念相似,如 Key Vault 和 Service Bus,具有类似的风险和威胁模型。
在下一章,我们将转换话题,探讨 Azure 的安全监控功能如何检测并警告非法活动。
第八章:监控、日志和警报

渗透测试人员面临一个悖论,我们常常在尽力规避检测的同时,也希望防御者能够及时阻止我们的行动。进攻性安全专业人员的工作不仅仅是发现和解释客户系统中的漏洞,还包括帮助负责监控和保护企业的人员提升他们的技能。渗透测试可以帮助确定防御者规则和警报中的漏洞,同时保持防御者的敏锐度和实战经验,以备真实对手的到来。
本章与前几章中介绍的渗透测试技巧和工具有所不同。我将介绍防御者应当审查的监控工具、日志和警报,以便检测本书其余部分描述的攻击者行为。如果蓝队在使用这些资源,攻击者将更难在不被发现和驱逐的情况下取得进展。
我从 Azure 安全中心(ASC)开始介绍,它是一个将来自不同服务和系统的安全建议和事件汇总的 Azure 特性。接着,我将介绍操作管理套件(OMS),它收集事件并提供 Azure、企业网络及其他云提供商系统的集中管理。然后,我将介绍安全 DevOps 工具包,它是一个用于保护订阅、启用重要警报并提供持续保障的脚本包。最后,我们将讨论如何收集 Azure 服务日志,超出管理工具的范围。
Azure 安全中心
Azure 安全中心是 Azure 中的一项服务,它将关键信息汇总到一个视图中。通过整合这些数据,安全中心使得没有全职安全人员支持的管理员能够快速验证他们服务的安全性。即使是包含防御人员的团队,也可以覆盖更多的订阅,并释放员工投入更多时间进行主动防御。如果在订阅中没有启用 Azure 安全中心,这本身就已经是渗透测试人员的一个发现。
虽然最初仅限于来自 Azure 服务的安全事件,安全中心自 2017 年中期起开始接收来自非 Azure 系统的事件。这被称为混合安全,并且对 Azure 安全中心付费服务的用户开放。Azure 安全中心分析从外部系统导入到 OMS 工作区的日志,这些工作区在“设置 OMS”中的 第 169 页有详细描述。
安全中心有两个主要组件:检测和预防。检测标记针对订阅资源的潜在非法活动,预防检查服务配置,以识别缺失的安全控制措施。让我们更深入地了解这两者。
利用安全中心的检测功能
对于任何防御者来说,一个关键要求是威胁检测和警报。安全中心通过查看日志并在虚拟机上安装小型监控代理来监控虚拟机和 SQL 数据库。当安全中心检测到异常时,它会在 Azure 门户的安全中心面板中生成一个警报,如图 8-1 所示。可选地,安全中心可以生成并将电子邮件发送给指定的安全联系人或订阅所有者。
注意
威胁检测功能仅对使用付费(标准)版本的安全中心客户启用,该版本根据订阅中虚拟机和数据库的数量按月收费。安全中心的版本设置在订阅级别,因此无法单独为资源启用或禁用该服务。如果客户希望为生产工作负载启用威胁检测,但又不想为测试系统支付安全中心的费用,可以考虑将资源拆分到两个订阅中——一个使用安全中心的付费选项,另一个使用免费版。理想情况下,安全中心会监控所有节点,但安全建议往往需要与预算现实进行竞争。

图 8-1:Azure 安全中心主视图,带有警报
安全中心会对多种威胁发出警报,从基于主机的检测到网络事件。以下是一些可用警报的列表:
-
对远程桌面的暴力破解登录尝试
-
对 SSH 的暴力破解登录尝试
-
存在一个名称与已知恶意软件匹配的二进制文件
-
执行具有已知恶意软件签名的二进制文件
-
当二进制文件执行可疑操作时(通过启发式方法确定)
-
对数据库的 SQL 注入攻击
除了记录触发警报的资源外,安全中心还提供关于事件的详细信息和修复问题的建议,如图 8-2 所示。在这里,管理员可以看到可疑程序的名称、运行该程序的位置、执行者、为什么认为该程序有危险以及如何解决问题的步骤。

图 8-2:Azure 安全中心检测警报
在云中运行服务的一个常被忽视的安全优势是,云提供商可以观察所有服务中的趋势。然后,他们可以利用这些信息更好地检测针对客户资源的威胁。例如,微软追踪已知网络犯罪团伙的 IP 地址,并监控 Azure 虚拟机的出站流量,以检测攻击者的指挥与控制通信。通过 Azure 安全中心,微软可以随着新的黑客攻击和检测技术的出现,随时添加新的警报,这些更新会立即生效,Azure 客户无需任何干预。
利用安全中心的预防功能
除了警报外,安全中心还为多种服务提供主动的安全建议。这些建议不是对适当规划、威胁建模和安全评估的替代,而是一些预防性建议,旨在帮助消除一些最常见的安全错误。预防性建议包括在安全中心的免费和付费版中。
例如,安全中心会检查以确保虚拟机已完全打补丁并运行端点保护软件。它还会建议对虚拟机应用 Azure 磁盘加密,这可以防止第五章中描述的离线 VHD 分析攻击。在虚拟机之外,安全中心将检查是否启用了 Azure SQL 数据库和存储账户的加密,以保护静态数据,如图 8-3 所示。

图 8-3:Azure 安全中心关于 SQL 和存储的预防性建议
此外,预防警报可以帮助确保随着用户部署新资源或服务进行维护,安全性不会随着时间的推移而退化。如果管理员忽视虚拟机(VM)并未安装补丁,这将变得非常明显,因为在 Azure 安全中心页面的计算状态面板上会显示红色警报。如果工程师为故障排除暂时禁用了防火墙,这也会触发警报。但最重要的是,如果 Azure 添加了客户端之前未使用过的新安全功能,安全中心会提醒客户端,他们的服务未能充分利用所有可用的保护功能。鉴于 Azure 更新的快速节奏,跟上所有当前最佳实践是很困难的,但 Azure 安全中心可以帮助管理员将这项任务从工作负担中剔除。
如果在评估过程中发现有未解决的预防警报,您应该与客户讨论这个问题。以下是客户可能提供的一些解释:
-
他们不愿意或没有时间查看安全中心。
-
他们认为某个警报不重要或不适用,或者他们通过其他控制措施解决了这个问题。
-
他们觉得解决警报的成本太高,或者修复措施与他们的部署不兼容。
-
他们认为 Azure 触发了一个误报。
进行更深入的对话,以真正了解任何这些情况中发生的事情。如果客户完全忽略安全中心,我会担心他们没有正确地将安全放在优先位置。安全中心是市场上最容易使用的安全工具之一,他们应该使用它。如果他们认为已经通过其他方式解决了警报,你应该确认他们的修复确实解决了警报所暗示的威胁。如果客户已经进行过成本效益评估,并决定解决标记的风险的解决方案太昂贵,这可能很难争辩,但在这种情况下,确保客户了解他们所接受的威胁的具体性质。
最后,如果警报是误报,告诉客户他们可以点击警报并选择忽略以将其隐藏。他们还可以通过访问安全中心,选择安全策略,点击订阅名称,点击预防策略,然后将任何规则集切换为关闭来禁用订阅中的整个预防策略类别。然而,他们应该完全确定这确实是误报。在这种情况下,他们也可以考虑向微软提交反馈。截至目前,我还没有遇到过安全中心的预防规则集中真正的误报。
操作管理套件
Azure 安全中心旨在为 IT 管理员提供其服务中的安全相关问题视图。尽管这对于以一个视图查看威胁的汇总信息非常有用,但这意味着团队需要在其他地方查看与安全无关的事件或执行与安全无关的管理任务。为了应对跨多个环境管理系统的难题,微软提供了云平台——操作管理套件(OMS),该平台可以汇聚来自本地和云托管系统与服务的日志、警报和自动化信息。
注意
微软已经将许多最初仅限于 OMS 的安全功能添加到 Azure 安全中心,包括从 Azure 以外的系统查询日志的功能。这使得防御者能够使用单一的控制面板来监控整个环境。然而,这些功能仍然可以通过 OMS 访问,并且两个系统使用相同的 OMS 工作区。
OMS 允许用户启用各种解决方案或模块,以提供特定的功能。其中一个核心解决方案是安全性与合规性,它监控主机上的反恶意软件服务状态、系统面临的威胁以及补丁级别。OMS 还提供其他可以增强安全意识的解决方案,例如活动目录健康检查、Azure 网络安全组分析、SQL 服务器评估和密钥保管库分析。OMS 中还有与安全无关的解决方案,例如用于启用 Azure 自动化混合工作者的自动化组件,您在第七章中看到过。
设置 OMS
由于 OMS 将多个环境的管理连接在一起,它需要进行一些设置。要使用 OMS 来监控服务,请执行以下步骤:
-
在
mms.microsoft.com/创建一个 OMS 工作区。 -
在 OMS 工作区启用所需的任何解决方案。
-
启用 OMS 将监控的任何 Azure 服务的日志分析。
-
在任何需要监控的非 Azure 服务器上安装代理。
首先,管理员创建一个工作区,它是 OMS 相当于 Azure 订阅的存在。多个人员可以共享一个工作区,企业可以选择拥有多个工作区,以便将不同系统的管理分配给不同的人组。
第二步,管理员需要将解决方案添加到他们的工作区。每个解决方案代表 OMS 可以使用的不同类型的日志、代理或服务。在订阅内,有一个画廊,它由一个购物袋图标表示,包含了几十个可用的解决方案。OMS 用户可以点击任何一个解决方案,获取更详细的功能描述及相关费用(如果有的话),或者在他们的工作区启用该解决方案。工作区可以包含用户所需的任意数量的解决方案。图 8-4 展示了画廊中的一些提供内容。
第三步,服务日志需要转发到 OMS,以便管理员启用任何特定于 Azure 的解决方案。为了让 OMS 能够分析日志,它需要访问这些日志,但 Azure 的日志并不会自动提供给 OMS。相反,具有必要权限的管理员必须登录 Azure 门户,在 Azure 订阅和 OMS 工作区中启用每个资源的日志转发。尽管在首次配置 OMS 时这可能有些繁琐,但它允许管理员选择订阅中各个服务的实例进行监控;这可以避免数据过度共享,使不同的服务可以将日志发送到不同的工作区(例如,测试服务日志发送到一个工作区,而生产日志发送到另一个工作区),并防止 OMS 被不需要跟踪的资源日志所杂乱。

图 8-4:运营管理套件画廊
为了启用这些日志,管理员执行以下步骤:
-
导航到 Azure 中与已启用 OMS 解决方案相对应的服务。
-
选择该服务的一个实例,然后点击诊断日志标签。
-
如果尚未开启,启用诊断日志。
-
为日志指定一个名称—通常是资源的名称。
-
勾选发送到日志分析选项。
-
点击日志分析配置按钮,然后选择列表中的某个 OMS 工作区。
-
勾选任何表示需要收集的日志类型的框,如审计日志。
-
点击保存。
此时,日志应该开始流入 OMS,OMS 会在短暂的延迟后开始分析它们并显示结果。启用将日志转发到 OMS 的示例,针对 Key Vault 实例,见图 8-5。

图 8-5:为 Key Vault 资源启用日志分析
设置 OMS 的最后一步是启用来自非 Azure 系统的数据收集。这包括本地服务器和在其他云提供商上运行的虚拟机。对于这些系统,Azure 提供了 Windows 和 Linux 代理应用程序,这些应用程序作为服务运行,并将任何相关数据转发到 OMS 进行分析和警报。OMS 用户可以通过点击 OMS 中的设置按钮,选择连接源,然后在 Windows 服务器和 Linux 服务器标签页中点击下载代理按钮来下载这些代理。页面还提供了代理 ID 值和 OMS 密钥,这些在代理安装过程中用于将日志定向到正确的工作区。
除了代理,OMS 用户还可以从连接源页面下载 OMS 网关应用程序。该应用程序允许安装在服务器上的代理——在没有出站互联网访问的受限网络环境中——将其日志转发到一个中央网关,然后将日志传递到 OMS。您可以在 docs.microsoft.com/en-us/azure/log-analytics/log-analytics-oms-gateway/ 查找有关 OMS 连接要求的更多信息。
在 OMS 中查看警报
一旦完全配置并接收日志数据,OMS 应该开始在工作区主页上显示日志状态。这对于查看有多少主机正在检查很有用,但对于追踪事件来说,这并不是最佳视图。为此,OMS 还有两个面板:我的仪表板和日志搜索。
我的仪表板面板允许用户选择已启用解决方案中提供的各个指标,并将其添加到仪表板。用户可以重新排列它们,并为数据选择不同的可视化方式,如条形图、折线图或计数图。通过这种方式,OMS 用户可以确定对他们来说哪些特定事件是重要的,并仅在门户中查看相关数据。用户还可以共享仪表板或使用 OMS 中的视图设计器页面创建多个仪表板。
日志搜索是所有传入 OMS 工作区数据的汇总,允许用户搜索特定事件。搜索面板使用 Microsoft 的 Azure Log Analytics 查询语言,用户可以根据资源、事件类型、时间范围、平台等进行查询。幸运的是,对于那些不想学习新语言的用户,OMS 提供了结果左侧的过滤选项,进一步缩小数据范围——就像消费者在购物网站上筛选产品属性一样。用户可以从通配符搜索(*)开始,显示所有记录,然后通过 GUI 进一步筛选,如图 8-6 所示。

图 8-6:OMS 中的日志搜索与过滤
注意
日志搜索还可以通过点击左侧菜单栏中的搜索,在 Azure 安全中心访问。OMS 和安全中心都包含相同的工作区和事件,并且使用相同的查询语言,因此无论通过何种方式访问日志搜索,您都应该获得相同的结果。
虽然 OMS 门户是监控各个环境趋势的好地方,但安全人员需要知道何时发生攻击,即使他们不在屏幕前。因此,OMS 具备在某个事件发生或某个度量值超出指定阈值时执行操作的功能。这些操作包括发送电子邮件、触发 webhook 调用 API 到另一个服务,以及在流行的 IT 服务管理(ITSM)工具中创建工单,如 ServiceNow、System Center Service Manager、Provance 和 Cherwell。
要创建警报,OMS 用户可以在日志搜索中创建一个查询,匹配警报的所需条件。或者,他们可以点击仪表板中的任何图表,然后点击顶部菜单中的警报按钮。这将打开一个警报规则创建窗口,允许用户指定警报的确切条件以及应采取的操作,如图 8-7 所示。

图 8-7:在 OMS 中创建警报
创建规则的用户可以指定他们认为警报的严重性。他们还可以设置冷却期,以防止规则持续触发。在自定义仪表板、查询和警报选项之间,OMS 用户可以随时了解其环境中的事件和趋势。
安全 DevOps 工具包
安全 DevOps 工具包是一组脚本,旨在帮助开发人员以高效、一致的方式启用关键安全控制。这些脚本是在微软 IT 组织内创建的,经过其云安全团队的广泛研究和测试。该工具包是用 PowerShell 编写的,要求运行它的工作站已安装 Azure PowerShell 工具。要获取工具包,请打开 PowerShell 提示符并运行以下命令:
PS C:\> Install-Module AzSK -Scope CurrentUser
下载工具包完成后,运行 cmdlet Get-AzSKSubscriptionSecurityStatus,并指定一个订阅 ID。它将检查指定订阅中的多个属性,例如订阅管理员的数量、未解决的 ASC 警报、经典资源的使用情况,以及是否已提供该订阅的指定安全联系人。清单 8-1 显示了在订阅上运行 Get-AzSKSubscriptionSecurityStatus 的情况。
PS C:\> Get-AzSKSubscriptionSecurityStatus -SubscriptionId ID
================================================================================
Method Name: Get-AzSKSubscriptionSecurityStatus
Input Parameters:
Key Value
--- -----
SubscriptionId ID
================================================================================
Running AzSK cmdlet using a generic (org-neutral) policy...
================================================================================
Starting analysis: [FeatureName: SubscriptionCore] [SubscriptionName: Sub] [SubscriptionId: ID]
--------------------------------------------------------------------------------
Checking: [SubscriptionCore]-[Minimize the number of admins/owners]
Checking: [SubscriptionCore]-[Justify all identities that are granted with admin/owner access]
Checking: [SubscriptionCore]-[Mandatory central accounts must be present on the subscription]
Checking: [SubscriptionCore]-[Deprecated/stale accounts must not be present]
Checking: [SubscriptionCore]-[Do not grant permissions to external accounts]
Checking: [SubscriptionCore]-[There should not be more than 2 classic administrators]
Checking: [SubscriptionCore]-[Use of management certificates is not permitted]
Checking: [SubscriptionCore]-[Azure Security Center (ASC) must be correctly configured]
Checking: [SubscriptionCore]-[Pending Azure Security Center (ASC) alerts must be resolved]
Checking: [SubscriptionCore]-[Service Principal Names should not be Owners or Contributors]
Checking: [SubscriptionCore]-[Critical resources should be protected using a resource lock]
Checking: [SubscriptionCore]-[ARM policies should be used to audit or deny certain activities]
Checking: [SubscriptionCore]-[Alerts must be configured for critical actions]
Checking: [SubscriptionCore]-[Do not use custom-defined RBAC roles]
Checking: [SubscriptionCore]-[Do not use any classics resources on a subscription]
Checking: [SubscriptionCore]-[Do not use any classic virtual machines on your subscription.]
Checking: [SubscriptionCore]-[Verify the list of public IP addresses on your subscription]
--------------------------------------------------------------------------------
Completed analysis:[FeatureName: SubscriptionCore] [SubscriptionName: Sub] [SubscriptionId: ID]
================================================================================
Summary Total Critical High Medium
------- ----- -------- ---- ------
Passed 7 1 3 3
Failed 8 0 5 3
Verify 2 0 1 1
Manual 1 0 1 0
Total 18 1 10 7
================================================================================
Status and detailed logs have been exported to path - AppData\Local\Microsoft\AzSKLogs\
================================================================================
清单 8-1:安全 DevOps 工具包检查订阅的安全设置
该命令将列出正在运行的测试以及通过、失败或需要手动验证的测试数量,并提供输出日志的路径。结果会被记录到 CSV 文件中,文件包含每个控制项的通过/失败状态以及可以采取的推荐步骤以确保符合安全要求。例如,如果没有启用关键警报通知,结果将建议运行 Set-AzSKAlerts 来启用它们。
接下来,运行 Get-AzSKAzureServicesSecurityStatus cmdlet。该命令与 Get-AzSKAzureSubscriptionSecurityStatus cmdlet 的作用相同,不同之处在于,它检查的是每个在订阅中运行的服务的安全性,而不是订阅配置的安全性。结果会显示在屏幕上,并写入 CSV 文件,就像订阅安全检查一样。
尽管这些对 Azure 设置的一次性检查是一个不错的起点,但订阅及其服务随着时间推移可能会变得不那么安全。这可能发生在管理员意外禁用某个安全设置、部署了新的资源但未设置监控,或者 Azure 添加了新的安全功能但未能回溯应用到现有资源的情况下。为了解决这些问题,Secure DevOps Kit 还提供了 Continuous Assurance 组件。
Continuous Assurance 使用 Azure Automation 创建一个运行簿,每天验证一次指定资源组的安全性。结果会存储在 OMS 工作区中,管理员可以随时追踪其资源的安全态势。要启用 Continuous Assurance,请运行以下命令:
PS C:\> Install-AzSKContinuousAssurance -SubscriptionId ID -OMSWorkspaceId Workspace `
-OMSSharedKey Key -ResourceGroupNames "Group1,Group2"
请确保指定一个已存在的 OMS 工作区及其关联的访问密钥,以及任何需要监控的资源组。命令执行完毕后,自动化任务将在几小时内生成结果并显示在 OMS 中。
根据您的客户环境,Secure DevOps Kit 中的其他功能也可能非常有用。更多信息,请参阅 github.com/azsk/DevOpsKit-docs/。
自定义日志处理
OMS 和安全中心都是寻求使用 Microsoft 第一方解决方案来管理和监控服务的客户的不错选择,但这些解决方案可能并不适合每个客户。有些企业可能希望将日志集成到他们已经使用的其他监控工具中;这样,他们可以将所有内容集中在一个地方。或者他们可能以新颖的方式使用某项服务,或者有特定的威胁担忧,这些担忧是任何商业产品中没有考虑到的——需要在自定义解决方案中解决的事件。有些客户可能希望监控新发布的 Azure 服务,而这些服务在 OMS 中尚无相应的解决方案。而其他客户则可能有独特的合规要求,需要保留较长时间的日志数据。对于这些客户,Azure 确实提供了几乎所有服务的日志保存能力,通常是保存到存储账户中。
服务日志通常默认是关闭的。用户必须在 Azure 门户中逐个资源启用它们。这样做是为了节省客户开支,因为日志会写入存储账户,而存储账户按使用的空间量收费。该设置的位置因服务而异;对于支持 OMS 日志转发的服务,选项应在同一诊断日志页面上。对于其他服务,有时标签为诊断、警报、度量、日志记录或活动日志。
在大多数这些设置页面中,有一个复选框可以将日志保存到存储账户中,勾选后会显示一个下拉菜单供选择所需的存储账户——非常类似于为 OMS 配置 Log Analytics。对于某些服务,如虚拟机,你需要先在该服务的活动日志页面查看日志,点击导出,然后选择目标存储账户,如图 8-8 所示。

图 8-8:将虚拟机日志导出到 Azure 存储
在各种服务的日志保存到存储账户后,用户可以使用 PowerShell、存储账户库或在第四章中讨论的任何存储账户客户端应用程序来检索它们。许多服务将日志作为平面文件写入 Blob 存储,尽管有些服务使用表存储保存记录。不幸的是,并不是所有服务都使用一致的格式,因此开发人员需要解析感兴趣服务的日志,并根据组织的需求创建自定义解决方案。
渗透测试人员应该偶尔查看执行操作或使用新工具前后的日志,以更好地了解当前记录和检测到的活动量。如果你发现一些事件出现在日志中,但没有在 Azure 安全中心或 OMS 中显示,请让你的客户意识到这个差距,并通知 Microsoft。你可以通过feedback.azure.com/或者通过 Azure 门户中的产品支持链接进行反馈。如果你的客户是高级客户,他们可以通过他们的技术账户经理提交反馈。
总结
在本章中,我们回顾了客户如何配置 Azure 中的安全事件警报,并审计其资源以确保遵循最佳实践。我们首先介绍了 Azure 安全中心,这是一个专注于 Azure 安全的好选择,因为它为多种 Azure 服务提供了警报和配置建议。对于希望管理多个环境的用户,我们探索了操作管理套件,它也可以对安全事件发出警报,但与安全中心不同,它能够执行健康检查、监控本地服务器,甚至自动化服务器上的管理任务。接下来,你了解了如何使用安全 DevOps 工具包验证 Azure 订阅是否正确配置了关键的安全设置。最后,我们考察了如何从 Azure 中检索日志,供开发人员手动查看或用于自定义管理工具。
感谢你和我一起走过这片云。愿你的参与合法、愉快、受到赞赏,并且难度越来越大。






浙公网安备 33010602011771号