
Forgejo 16.0.5 - 高 - リモート - SSRF - hostmatcher が 0.0.0.1 をパブリック IP として許可
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · forgejo-hostmatcher-0001-ssrf
クラス: SSRF 到達性: リモート
Forgejo 16.0.5 (8d24b7d) - Forgejo
デフォルトの [webhook] ALLOWED_HOST_LIST は空であるため、services/webhook/deliver.go は組み込みの external を使用してクライアントを構築する。この述語は Go の IsGlobalUnicast() && !isPrivate() である。isPrivate は RFC1918/4193 に v16.0.2 の CGNAT 追加を加えたものである。RFC 6890 の 0.0.0.0/8 はそのいずれにも該当しない。127.0.0.1 はループバックであり拒否される。0.0.0.1 は許可される。
サインイン済みユーザーは http://0.0.0.1 に webhook を送信し、フック履歴から HTTP ボディを読み取ることができる。同じポート上の 127.0.0.1 は拒否される。
| ID | CVE 未割当 |
| クラス | SSRF |
| 到達性 | リモート (認証済み。リポジトリ webhook を作成できる任意のユーザー) |
| CWE | CWE-918 |
| CVSS | High: 7.7 CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:N |
| 製品 | Forgejo |
| 影響範囲 | v16.0.5 (8d24b7d) まで。v16.0.2 の CGNAT 追加の残骸 |
| 認証 | リポジトリ webhook を作成できるサインイン済みユーザー |
| ライセンス | GNU Affero GPL v3.0 |
| ラボ | 127.0.0.1 のみ |
デフォルトインストールで登録し、リポジトリを作成し、forgejo webhook を http://0.0.0.1:<port>/... に設定し、テストして、レスポンスボディを読み取る。
| 権限 | メソッド / シンク | 偵察 / 完全性 / 可用性 | ラボ実証または推測 |
|---|---|---|---|
デフォルトの webhook 許可リストを回避してこのネットワークの 0.0.0.1 にダイヤル | POST /api/v1/repos/{owner}/{repo}/hooks の後、URL http://0.0.0.1:8080/ssrf で POST .../hooks/{id}/tests | 偵察 (Forgejo ホストからの外向き HTTP) | ラボ実証済み。履歴に HTTP 200 ボディ FORGEJO-HOSTMATCHER-0001-WITNESS が保存された |
| 応答したものの完全な HTTP レスポンスを読み取る | GET /{owner}/{repo}/settings/hooks/{id} が ResponseInfo.Body を出力する | 偵察 (完全レスポンス SSRF) | ラボ実証済み。履歴ページに同じウィットネス |
IPv4 マップド [::ffff:0.0.0.1] 経由の同クラス | 同じマッチャー To4() の後 checkIP | 偵察 | hostmatcher から推測。ラボでは 0.0.0.1 を使用 |
| Forgejo netns 内でループバックより広くバインドされたリスナーに到達 | 0.0.0.1 が lo 上にあるとき、Linux の 0.0.0.0/8 への connect() はこのホスト | 偵察 | サイドカーオラクルに対してラボ実証済み。特定のクラウド IMDS に関する主張ではない |
同じデフォルトマッチャーでクローズ済み: 127.0.0.1 (履歴で拒否をラボ実証)、127.0.0.0/8、RFC1918、CGNAT 100.64.0.0/10、IPv4 IMDS を含むリンクローカル 169.254.0.0/16、未指定 0.0.0.0。外向き webhook は X-Forgejo-Internal-Auth / INTERNAL_TOKEN を取得しない。これはそれ自体では RCE ではない。
これは v16.0.2 の CGNAT 修正ではない。Forgejo は Gitea スタイルの予約ネットリストを備えるようにはならなかった。gitea-hostmatcher-0000-ssrf と同クラスである。
v16.0.2 は CGNAT を private に追加した。拒否リストを追加するパッチは贈り物である。リストを読み、次に IANA がまだ持っていてリストが忘れているものを問い合わせる。姉妹ハントでは Go 1.26 の IsGlobalUnicast が 0.0.0.1 をクローズしたと主張していた。私は述語とツリー内テストを確認した。それらは 0.0.0.1 を決してカバーしていない。
すでに記録済みの誤った道: webhook 作成の HTTP 201 をオラクルとして扱うこと (オラクルは履歴である)。127.0.0.1 の配信が成功すること (それは別のバグである - ラボでは拒否されることが必要)。X-Forgejo-Internal-Auth で /api/internal を叩くこと。リバースシェル。茶番である。
python3 forgejo-hostmatcher-0001-ssrf-Abraxas-Labs.py
または:
cd lab
./run.sh
ターゲットは http://127.0.0.1:19320 のみ。イメージ codeberg.org/forgejo/forgejo:16.0.5。オラクルサイドカーはポート 8080 で Forgejo netns を共有する。
create-hook name=neg-loopback ...
negative-control 127.0.0.1 blocked
create-hook name=hit-0001 ...
poll id=2 witness=True
SUCCESS forgejo-hostmatcher-0001-ssrf how=live pin=v16.0.5 0.0.0.1:8080 HTTP 200 FORGEJO-HOSTMATCHER-0001-WITNESS
RFC 6890 の 0.0.0.0/8 を非外部として扱う (IsGlobalUnicast ではなく予約ネットリスト)。0.0.0.1 は 127.0.0.1 と同じ方法で拒否されなければならない。
hostmatcher.goGNU Affero GPL v3.0。LICENSE を参照。ループバックラボのみ。無保証。