这篇博文旨在为提权操作提供思路,每一种方法后都附有利用脚本,这次是针对 Google Cloud Platform (GCP)。原文链接:https://rhinosecuritylabs.com/gcp/privilege-escalation-google-cloud-platform-part-1/
这篇文章旨在阐述如何权限提升,向大家提供利用的思路,以及方便大家迅速排查的相关POC。
如果大家对提权细节不太感兴趣,可以直接看 GCP的新提权扫描程序 章节,此工具允许您扫描您的 GCP 组织/环境以了解本文列出的所有提权方法。
访问令牌
在进入每种方法之前的最后一步。每种方法的脚本都需要来自 GCP 的访问令牌来进行身份验证。
要获取 gcloud CLI-Authenticated 用户的访问令牌,您可以运行以下命令:
gcloud auth print-access-token
在实际攻击中,此访问令牌可能来自服务器端请求伪造、来自一些人群的本地文件系统等。
PrivEsc 方法
部署管理器.deployments.create
这种权限可能是我们在 GCP 中发现的最简单但最强大的提权方法。此单一权限允许您以<project number>@cloudservices.gserviceaccount.comService Account的身份将新的资源部署到 GCP 中,默认情况下,该帐户被授予项目的 Editor 角色。更重要的是,不需要iam.serviceAccounts.actAs权限(在下面更详细地介绍),即使您实际上只是一个Service Account。这已报告给 Google Bug Bounty 计划,但我们被告知这属于正常的功能设计。
Deployment Manager 允许您以 YAML 或 Jinja 格式指定要在项目中创建和配置的资源。它基本上可以被视为一种基础设施即代码服务,类似于 AWS 中的 CloudFormation。我们指定的资源使用授予该Service Account的权限,而不是我们自己的用户。因此,只要我们有deploymentmanager.deployments.create,我们就可以控制该Service Account。
上面的屏幕截图显示我们使用 YAML 配置文件,其中指定了一个 Compute Engine 虚拟机实例。然后我们运行读取该 YAML 文件并将其提交给 GCP 的漏洞利用脚本。几分钟后,Deployment Manager 将使用我们提供的配置为我们创建该 VM 实例。请注意,创建 Compute Engine 实例不需要 compute.instances.create,因为Service Account具有权限。
可以自定义 YAML 模板以包含各种不同的资源,要查看支持的资源,您可以查看此链接或运行以下 gcloud 命令:
gcloud deployment-manager types list
在尝试提升权限时, iam.v1.serviceAccount和iam.v1.serviceAccount.keys会特别有用。
此方法的漏洞利用脚本可在此处找到。
利用IAM
身份和访问管理 (IAM) 服务管理 GCP 环境的授权和身份验证。
iam.roles.update
如果您被分配了一个自定义 IAM 角色,则iam.roles.update将允许您更新该角色的“includedPermissons”。
上图显示了自定义角色“privtesting”仅授予iam.roles.update。然后我们使用该权限向它添加iam.serviceAccountKeys.create权限,然后由我们的用户继承。
该方法的利用脚本在此处获得。
iam.serviceAccounts.getAccessToken
此权限允许您请求属于指定Service Account的访问令牌。我们可以通过比我们拥有更多权限的Service Account请求访问令牌以此来提升权限。如下图所示,其中“iamcredentials”API 旨在生成新令牌。您甚至可以指定令牌的关联范围。
此方法的漏洞利用脚本可在此处找到。
iam.serviceAccountKeys.create
此权限允许我们执行与前一种方法类似的操作,但不是访问令牌,而是为Service Account创建用户管理的密钥,这将允许我们作为该Service Account访问 GCP。如下图所示:我们使用 gcloud CLI 创建新的Service Account密钥(Service Account key)。之后,我们将只使用此密钥向 API 进行身份验证。
此方法的漏洞利用脚本可在此处找到。
iam.serviceAccounts.implicitDelegation
作为Service Account,您可能不一定需要iam.serviceAccounts.getAccessToken来获取另一个Service Account的访问令牌。如果您对另一个Service Account具有iam.serviceAccounts.implicitDelegation权限,而另一个Service Account对第三个Service Account具有iam.serviceAccounts.getAccessToken权限,则可以使用implicitDelegation 为该第三个Service Account创建令牌,如下图所示:
解析上图:简而言之,A在B上有implicitDelegation,B在C上有getAccessToken,所以允许A在C上getAccessToken。
下图显示了一个Service Account(Service Account A)向“iamcredentials”API 发出请求,为“测试项目”Service Account(Service Account C)生成访问令牌。“scc-user”Service Account(Service Account B)在 POST 正文中指定为“委托”,这意味着您正在使用您对“scc-user”(Service Account B)的implicitDelegation 权限为“测试项目”(Service Account C)。接下来,向“tokeninfo”终端发出请求,以验证接收到的令牌的有效性。
此方法的漏洞利用脚本可在此处找到。
iam.serviceAccounts.signBlob
因为这种方法(以及下一种方法)很难手工完成,所以下图相关操作主要采用脚本完成。
GCP 中的iam.serviceAccounts.signBlob权限“允许对任意有效负载进行签名”。这意味着我们可以创建一个从目标Service Account请求访问令牌的Blob。该脚本帮你实现繁琐的步骤,下图展现的是为Service Account检索的访问令牌。
此方法的漏洞利用脚本可在此处找到。
iam.serviceAccounts.signJwt
与之前的方法通过签署任意有效负载的工作方式类似,此方法通过签署正确格式的 JSON Web 令牌 (JWT) 来工作。此方法的脚本将签署正确格式的 JWT,并使用它请求属于Service Account的新访问令牌。下图显示了返回Service Account访问令牌的脚本。
此方法的漏洞利用脚本可在此处找到。
cloudfunctions.functions.create
对于这种方法,我们将创建一个新的云函数(Cloud Function),其中包含我们想要访问的关联Service Account。由于调用云函数可以访问元数据 API,我们可以直接从它请求令牌,就像在 Compute Engine 实例上一样。
此方法所需的权限如下:
- cloudfunctions.functions.call或cloudfunctions.functions.setIamPolicy
- cloudfunctions.functions.create
- cloudfunctions.functions.sourceCodeSet
- iam.serviceAccounts.actAs
此方法的脚本使用 GitHub 上包含的预制 Cloud Function,这意味着您需要上传相关的 .zip 文件并将其公开在 Cloud Storage 上(有关更多信息,请参阅漏洞利用脚本)。创建并上传函数后,您可以直接调用该函数或修改 IAM 策略以允许调用该函数。响应内容中包括属于分配给该云功能的Service Account的访问令牌。
该脚本创建函数并等待它部署,然后运行它并返回访问令牌。
此方法的漏洞利用脚本可在此处和此处找到,预构建的 .zip 文件可在此处找到。
cloudfunctions.functions.update
与cloudfunctions.functions.create类似,此方法更新(覆盖)现有函数,而不是创建新函数。如果您有另一个要获取令牌的Service Account,用于更新该功能的 API 还允许您交换Service Account。
此方法需要以下权限:
- cloudfunctions.functions.sourceCodeSet
- cloudfunctions.functions.update
- iam.serviceAccounts.actAs
此方法的漏洞利用脚本可在此处找到。此脚本的输出类似于cloudfunctions.functions.create。
compute.instances.create
此方法使用指定的Service Account创建一个新的 Compute Engine 实例,然后将属于该Service Account的令牌发送到外部服务器。这意味着您根本不需要访问该实例。
此方法需要以下权限:
- compute.disks.create
- compute.instances.create
- compute.instances.setMetadata
- compute.instances.setServiceAccount
- compute.subnetworks.use
- compute.subnetworks.useExternalIp
- iam.serviceAccounts.actAs
上面的第一个终端显示正在运行的脚本,它创建了一个新的 Compute Engine 实例。底部终端显示我们的侦听服务器接收 Compute Engine 服务帐户的访问令牌。如果您在脚本中指定IP_PORT,脚本将自动在指定端口上侦听0.0.0.0上的凭据并在收到时打印它们,否则它们将被发送到EXFIL_URL中指定的主机。
此方法的漏洞利用脚本可在此处找到。