
Forgejo 16.0.5 - 高 - リモート - IDOR - GET /api/v1/user/keys/{id} が他のユーザーの SSH キーおよびデプロイキーを返す
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · forgejo-keys-idor
クラス: IDOR 到達範囲: リモート
Forgejo 16.0.5 (8d24b7d) - Forgejo
GET /api/v1/user/keys/{id} は現在のユーザーグループ (reqToken、ユーザースコープ) に属している。ハンドラーは依然として数値IDで public_key をロードし、所有者チェックを行わない。同じテーブルにはユーザーキー、デプロイキー、プリンシパルが格納されている。このピンにおけるGPGは正しく処理している: GetGPGKeyForUserByID(ctx, ctx.Doer().ID, id)。プライベートな追加フィールドはゲートされている。公開鍵素材、タイトル、フィンガープリントはゲートされていない。IDは連番である。
read:user トークンで 1、2、3 と辿り、他人のSSHキーとデプロイキーを棚卸しできる。
| ID | CVE未割当 |
| クラス | IDOR |
| 到達範囲 | リモート (認証済み read:user / セッション) |
| CWE | CWE-639 |
| CVSS | High: 7.5 CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N |
| 製品 | Forgejo |
| 影響 | v16.0.5 (8d24b7d) まで |
| 認証 | 認証済み (read:user トークンまたはセッション) |
| ライセンス | GNU Affero GPL v3.0 |
| ラボ | 127.0.0.1 のみ |
任意のアカウントを登録または使用し、read:user トークンを発行し (またはセッションCookieを使用し)、/api/v1/user/keys/{id} を辿る。所有していないキーのタイトル、フィンガープリント、公開鍵素材を取得できる。秘密鍵は取得できない。シェルも取得できない。誰が何にアクセスできるかを棚卸しするだけである。
| 権限 | メソッド / シンク | 偵察 / 完全性 / 可用性 | ラボ実証または推測 |
|---|---|---|---|
| 他ユーザーのSSH公開鍵のタイトル、フィンガープリント、鍵素材を読み取る | 他所有者として GET /api/v1/user/keys/{id} | 偵察 (公開鍵インベントリの機密性) | ラボ実証済み。id 1 でタイトル FORGEJO-KEYS-IDOR-WITNESS を確認。攻撃者の一覧は id 2 のみ |
| 同様にデプロイキーを棚卸しする | 同じハンドラー、public_key 内の KeyTypeDeploy 行 (OwnerID 0) | 偵察 | テーブルから推測。ラボにはユーザーSSHキーを設置し、デプロイキーは設置していない |
| SSH証明書プリンシパルを読み取る | 同じハンドラー、KeyTypePrincipal 行。ListPublicKeys はこの型を除外する | 偵察 | テーブルから推測 |
| 制限ユーザーまたはプライベートユーザーに属するキーを閲覧する | このルックアップに可視性チェックなし | 偵察 | ハンドラーから推測 |
追加JSON (user、key_type、read_only) | appendPrivateInformation は管理者または所有者の場合のみ | 偵察 | ラボ実証済みでクローズ: 非所有者のレスポンスに user フィールドはなかった |
このルートでクローズ済み: 秘密鍵素材、シェル、GET /users/{username}/keys (ユーザー名スコープの公開一覧)、GPG GET /api/v1/user/gpg_keys/{id} (他ユーザーのidで404)、DeletePublicKey (所有者/管理者で403)。クロスリポジトリの GET /repos/{owner}/{repo}/keys/{id} は RepoID が一致しない場合404となる。
v16.0.5のセキュリティパッチ (#14370) は git-apply RCE と OpenID CSRF であった。これらはこのルックアップをクローズしなかった。gitea-user-keys-idor と同クラスであり、ここでも独立して依然としてオープンである。
2026-09の波の後、Forgejo v16.0.5 をピン留めした。Gitea 1.27.3 には依然としてこのルックアップがあった。Forgejoは分岐しているため、Giteaのパックをコピーするのではなく、GPGと並べて現在のユーザーキーハンドラーを再読した。GPGは他ユーザーのidで404を返す。SSHは返さない。
すでに記録済みの誤った道: 攻撃者自身の一覧をリークとみなすこと (そうではない - 一覧はスコープされているが、IDによるGETはスコープされていない); インストーラーの DISABLE_REGISTRATION=true をクローズとみなすこと (既存のアカウントがあれば十分); リバースシェル。茶番である。
python3 forgejo-keys-idor-Abraxas-Labs.py
または:
cd lab
./run.sh
対象は http://127.0.0.1:19310 のみ。イメージ codeberg.org/forgejo/forgejo:16.0.5。2つのアカウント。ウィットネス FORGEJO-KEYS-IDOR-WITNESS。
IOC planted victim-id=1 attacker-id=2
IOC attacker-list status=200 ... title=attacker-own-key
IOC get id=1 status=200 ... FORGEJO-KEYS-IDOR-WITNESS
IOC gpg-neg id=1 status=404
SUCCESS forgejo-keys-idor victim-id=1 get-http=200 list-has-id=no gpg-http=404 FORGEJO-KEYS-IDOR-WITNESS
key.OwnerID == ctx.Doer().ID (またはサイト管理者) でない限り404とする。このルートで KeyTypeDeploy / KeyTypePrincipal を拒否する。GetGPGKeyForUserByID に合わせる。
GetPublicKeyGNU Affero GPL v3.0。LICENSE を参照。ループバックラボのみ。無保証。