原文地址:https://www.wiz.io/blog/wiz-research-discovers-extrareplica-cross-account-database-vulnerability-in-azure-postgresql/
Wiz Research 在广泛使用的Azure Database for PostgreSQL服务中发现了一系列严重漏洞。该漏洞被称为#ExtraReplica,允许未经授权的读取访问其他客户的 PostgreSQL 数据库,绕过租户隔离。如果被利用,攻击者可以获得 Azure PostgreSQL 服务器客户数据库的读取权限。
在这篇文章中,我们将介绍研究过程的各个步骤,从分析潜在的攻击面到完整的漏洞利用,以及我们最终如何绕过云隔离模型。
总体来看,我们实现了以下目标:
通过发掘和利用 Azure 的 PostgreSQL 服务器(Flexible Server)中的漏洞,在我们自己的 PostgreSQL 服务器(Flexible Server)上获得代码执行。
在该服务的内部网络中进行排查,发现我们可以通过网络访问子网中的其他客户实例。
发现在服务器认证过程中还存在一个漏洞:由于正则表达式末尾的通配符(.*)导致证书的通用名称(CN)的正则表达式验证过于宽松,使我们能够使用发给任意域的证书登录到目标PostgreSQL。需要关注一下正则表达式末尾的错误:
/^(.*?)\.eee03a2acfe6\.database\.azure\.com(.*)$/
用我们的域名(wiz-research.com)去颁发证书:
replication.eee03a2acfe6.database.azure.com.wiz-research.com
我们成功访问到我们自己在不同租户上搭建的独立账户的数据库,验证了跨账户数据库访问漏洞的存在。
利用证书透明度源来识别客户目标,最终允许我们使用前面提到的漏洞复制任何 PostgreSQL 灵活服务器实例(配置为私有访问 - VNet 的实例除外)。

研究初衷
我们之前在 Azure Cosmos DB 中发现了漏洞。我们能否在其他 Azure 服务中重现类似问题?
在 Black Hat Europe 2021 上,我们展示了“ ChaosDB:我们如何入侵了数千名 Azure 客户的数据库”——披露了我们如何通过 Azure Cosmos DB 中的一系列错误配置来任意地访问 Microsoft Azure 客户的数据库。
在之前的研究中,我们的最初思路是在内部 Azure 环境中的 Jupyter Notebook 实例上运行任意代码。我们发现 Jupyter Notebook 实例可以通过网络访问内部管理 API,从而向内部 Azure 组件进行攻击操作。
在 Black Hat 之后,我们想知道这是否可能是一种模式,以及为客户提供专用虚拟机(属于内部 Azure 环境的一部分)的其他托管服务是否也可以被敏感的网络组件访问。
这边激发了我们下一个研究思路,以下便是我们寻找目标的几个参考属性:
- 在内部云环境中为客户提供专用虚拟机实例的托管云服务。
- 允许我们代码执行的服务。该要求可以是属于自身服务标准,也可以是通过其他漏洞而允许代码执行。如果我们可以使用漏洞执行代码,我们将更有可能找到一个不那么严格的环境,因为服务开发人员可能不希望用户在那里运行他们的代码。
- 目标应为高价值、被广泛运用的且包含敏感信息。
若要同时具备以上要求,我们首先想到的是针对云管理的数据库服务:
云服务提供商 (CSP) 以托管服务的形式向客户提供多种开源和商业数据库解决方案。这些数据库实例在 CSP 拥有和运营的内部云环境中运行,通常不属于用户的云环境。
攻击步骤总结
- 选择一个目标 PostgreSQL 灵活服务器。
- 从 Certificate Transparency 中检索目标的信息。
- 从 DigiCert 或 DigiCert 中间证书颁发机构购买特制证书。
- 通过解析数据库域名并将其与 Azure 的公共 IP 范围匹配来查找目标的 Azure 区域。
- 在目标的 Azure 区域中创建数据库。
- 利用攻击者控制的实例上的漏洞 #1 来提升权限并获得代码执行。
- 扫描目标实例的子网并利用漏洞 #2 获得读取权限!
Azure PostgreSQL数据库介绍
PostgreSQL 是一个功能强大、开源且成熟的对象关系数据库,被广大企业、组织用来存储不同类型的数据。Azure Database for PostgreSQL - 灵活服务器是 Azure 中的四种 PostgreSQL 产品之一:
下图展示的为PostgreSQL 部署选项及其优势:

Azure PostgreSQL数据库攻击思路
如何选择攻击组件
为了全面、快速了解我们可选择的突破口,我们可以利用 PostgreSQL 数据库语句查询并收集一下关于环境的信息,例如:当前用户的权限、 PostgreSQL 可用功能等等。
运行后发现:即使我们的数据库用户是名为 PostgreSQL 的高权限组的一部分azure_pg_admin,我们仍缺乏执行本机代码所需的特定 PostgreSQL 权限,如下图所示:

这意味着我们必须找到一种方法来提升我们在 PostgreSQL 实例中的权限。幸运的是,我们之前有关于 PostgreSQL 中权限提升的研究(1、2 )作为参考。
#1 – PostgreSQL 权限提升
我们发现 Azure 修改了他们的 PostgreSQL 引擎。Azure 很可能将这些更改引入 PostgreSQL 引擎,以强化其特权模型并添加新功能。我们设法利用这些修改中的错误来实现权限提升,允许我们以superuser. 获得superuser特权允许我们在我们的实例上执行操作系统级别的命令。
下图为通过恶意 SQL 查询执行操作系统级代码:

信息搜集
在获得在我们的 PostgreSQL 托管实例上执行任意代码的能力后,我们对目标环境信息进行了收集:
我们发现我们azuredb在一个主要托管 PostgreSQL 进程的 docker 容器中作为非特权用户运行。该容器正在运行 Ubuntu 18.04.6 LTS 的修改映像,并安装了最近的内核5.4.0-1063-azure,我们还注意到可以从容器内部访问以下网络接口:

查看网络接口,我们意识到我们的容器与其主机共享一个网络命名空间。看到内部 IP 地址给了我们一个思路———如果通过其中一个内部网络接口进入路由,我们是否可以访问其他客户的其他 PostgreSQL 实例?
我们在另一个 Azure 帐户上创建了另一个 PostgreSQL 灵活实例,并尝试通过端口 5342 上的内部网络接口 ( eth0, 10.0.0.0/23) 从我们创建的第一个数据库中访问它。令人高兴的是:成功了!!
最重要的是,即使实例将其防火墙配置为拒绝所有连接尝试,它也能正常工作。
我们认为这违反了预期的隔离模型,因为我们刚刚通过利用某种内部网络访问来连接到一个不相关的 PostgreSQL 实例。但是,由于我们仍然需要此数据库的用户名和密码才能执行任何有意义的操作(例如读取或修改数据),因此此问题的严重性仍然很低。
值得注意的是:当我们运行netstat命令时,除了 5432 (PostgreSQL) 之外,还有其他端口正在侦听所有接口 ( 0.0.0.0)。但是,当我们尝试从内部子网连接到其中一些时,我们超时了。我们执行了更多测试,例如:监听任意端口并尝试从另一个实例连接,但失败了。我们怀疑防火墙配置为明确允许端口 5432 的连接。
#2 – 使用伪造证书绕过跨账户身份验证
为了探究为什么我们的实例可以在内部访问其他实例,我们决定检查机器上的两个文件:pg_hba.conf和pg_ident.conf。根据 PostgreSQL 文档,这些文件分别负责客户端身份验证和用户名映射。
该pg_hba.conf文件定义了哪些客户端可以连接到哪个数据库,来自哪个 IP 范围,使用哪个用户名和身份验证方法。
查看一下配置文件:
pg_hba.conf:

解析一下:
- 在第 25 行,我们看到客户端可以使用标准密码身份验证 (md5) 从内部和外部网络连接到实例。
- 在第 17 到 21 行中,特殊帐户replication只能使用客户端证书身份验证(子网10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16)从内部网络中进行身份验证。
replication用户的目的是什么?事实证明,PostgreSQL 提供了一项独特的功能,允许将数据库数据从一台服务器复制到另一台服务器,从而“复制”数据库。这通常用于备份和故障转移/高可用性方案。例如,Azure 将其用于其高可用性功能:

如果我们能够设法以replication用户身份对其他客户的其他 PostgreSQL 实例进行身份验证,PostgreSQL 会验证提供的证书是否由受信任的证书颁发机构 (CA) 签名。
受信任的 CA 列表可在 SSL 证书颁发机构文件中找到。SSL 证书颁发机构文件位置位于 PostgreSQL 服务器配置中的ssl_ca_file字段下。
####### CERT CONNECTIVITY RELATED CONFIG ######
ssl = 'on'
ssl_ca_file = '/datadrive/certs/ca.pem'
ssl_cert_file = '/datadrive/certs/cert.pem'
ssl_key_file = '/datadrive/certs/key.pem'
ssl_ciphers = 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256'
通过检查此文件,我们了解到 Azure 信任多个 CA 的证书,其中一个是 DigiCert。DigiCert 是著名的根证书颁发机构和 SSL 证书颁发机构,为个人和开发人员以及企业提供服务。
Baltimore CyberTrust Root
DigiCert Global Root CA
DigiCert Global Root G2
DigiCert Global Root G3
Microsoft Internal Corporate Root
Ameroot – (Self signed)
访问其他客户的数据库
到目前为止,我们只讨论了登录到我们自己的 PostgreSQL 实例。我们如何应用这个技巧来访问其他客户的实例?让我们再看一下pg_ident.conf文件中的正则表达式:
pgusermap /^(.*?)\.eee03a2acfe6\.database\.azure\.com(.*)$ \1
我们发现数据库的唯一标识符出现在服务器的 SSL 证书中。通过尝试使用 SSL 连接内部网络中的其他数据库,我们可以检索它们的 SSL 证书并提取子网中每个数据库的唯一标识符。

在发现目标数据库的唯一标识符后,我们可以颁发一个新的客户端证书,但这次使用目标的标识符 replication.ebe6ed51328f.database.azure.com.wiz-research.com ,并使用它连接到目标数据库,具有完全读取权限。
我们怎么通过在公共证书透明度概要中搜索数据库域名来获取具有唯一标识符的 CN :

一旦我们有了标识符,我们就可以购买一个伪造的通用名称的证书:

接下来,我们可以通过解析数据库域并将 IP 地址与 Azure 的公共IP 范围之一匹配(例如)来找到目标实例的相关 Azure 区域:

最后,我们可以在与目标相同的区域中创建攻击者控制的数据库,并将其用作利用我们发现的漏洞的入口点,并获得对我们所追求的数据的访问权限!