
Forgejo 16.0.5 - 高 - リモート - ファイル読み取り - restore-repo がダンプ側の file:// を添付ファイルへ追従させる
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · forgejo-restore-file-open
クラス: ファイル読み取り 到達範囲: ローカル
Forgejo 16.0.5 (8d24b7d) - Forgejo
信頼できないダンプに対する forgejo restore-repo は、リリースアセットの URL を生の filepath.Join(baseDir, download_url) で書き換え、file:// を付加する。uri.Open は依然としてそのパスを os.Open する。空の --units はリリースを復元する。Gitea 1.27.0 では localFileURL が追加され、エントリのエスケープをスキップした。そのヘルパーはここには存在しない。
信頼できないダンプのオペレータによる復元は、forgejo uid が開けるホストファイルをリリース添付ファイルにコピーする。
| ID | CVE 未割当 |
| クラス | ファイル読み取り |
| 到達範囲 | ローカル (信頼できないダンプに対するオペレータの forgejo restore-repo) |
| CWE | CWE-22 / CWE-73 |
| CVSS | High: 7.3 CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:C/C:H/I:N/A:N |
| 製品 | Forgejo |
| 影響範囲 | v16.0.5 (8d24b7d) まで; ローカルオペレータによる復元 |
| 認証 | 信頼できないダンプに対するローカルオペレータの復元 |
| ライセンス | GNU Affero GPL v3.0 |
| ラボ | 127.0.0.1 のみ |
オペレータにダンプディレクトリを渡す (または既に INTERNAL_TOKEN とサーバーが読み取れるパスを保持している)。ユニットには releases / release_assets が含まれる。
| 権限 | メソッド / シンク | 偵察 / 完全性 / 可用性 | ラボ実証または推測 |
|---|---|---|---|
ダンプ外への .. を介して、forgejo uid が開けるホストファイルを読み取る | release.yml の download_url: ../FORGEJO-FILE-WITNESS.txt; 復元が結合し、uri.Open が os.Open し、バイトが witness.txt として保存される | 偵察 (ホストファイルの機密性) | ラボ実証済み。添付ファイルの内容は FORGEJO-RESTORE-FILE-OPEN-WITNESS。ダンプ内のおとり INSIDE-DUMP-NOT-HOST は配信されなかった |
| ダンプ内に仕込まれたシンボリックリンクでも同じ結果 | 結合されたパスは baseDir 配下に留まる; os.Open がリンクを追跡する | 偵察 | uri.Open の file -> os.Open から推測。ラボではシンボリックリンクではなく .. を使用 |
| PR パッチに対する同じシンク | pull_request.yml の PatchURL も同様に書き換えられ、その後 uri.Open により repo/pulls/<n>.patch へ | 偵察 | restore.go の GetPullRequests から推測。ラボではリリースのみ復元 |
| 復元されたリポジトリの閲覧者がホストファイルをダウンロードする | GET /<owner>/<repo>/releases/download/<tag>/<name> | 偵察 | 復元された公開リポジトリに対する labadmin Basic としてラボ実証済み |
典型的なホストファイル: app.ini、INTERNAL_TOKEN、SECRET_KEY、DB パスワード | forgejo uid は設定ツリーを読み取れる | 偵察 | 推測。ラボの証人はダンプの隣に仕込んだファイルであり、実際のシークレットではない |
ここで除外されたもの: ライブな POST /repos/migrate の file:// LFI (DownloadFunc が設定され、PR の PatchURL はクローン HTTP ベースに対してプレフィックスチェックされる)。絶対 DownloadURL によるダンプルート結合エスケープ (Go の filepath.Join("/dump", "/etc/passwd") は /dump/etc/passwd のまま)。未認証 HTTP 復元 (CLI / 内部トークンのみ)。app.ini をパックするバックアップ dump (設計上シークレット、アーカイブモード 0600)。OS LPE ではない。リモート LFI ではない。
復元に関するアイデアが 2 つあった。まず Gitea の絶対パス結合を頭の中でラボ検証した。Go の filepath.Join は Python の os.path.join のように絶対パスの第 2 引数を破棄しない。機能する入力は相対パスの .. である。Gitea の localFileURL はこのツリーには存在しない。
既に記録済みの誤った道: 絶対 DownloadURL によるダンプルート結合エスケープ; ライブ migrate の file:// LFI; X-Forgejo-Internal-Auth (復元は forgejo uid としての CLI であり、/api/internal ではない); 復元 HTTP をリモート未認証として扱うこと; リバースシェル。茶番である。
python3 forgejo-restore-file-open-Abraxas-Labs.py
または:
cd lab
./run.sh
対象は http://127.0.0.1:19340 のみ。イメージは codeberg.org/forgejo/forgejo:16.0.5。証人は FORGEJO-RESTORE-FILE-OPEN-WITNESS。
IOC asset name='witness.txt' ...
IOC download status=200 bytes=34 snippet=b'FORGEJO-RESTORE-FILE-OPEN-WITNESS\n'
SUCCESS forgejo-restore-file-open how=live ..-join file:// os.Open FORGEJO-RESTORE-FILE-OPEN-WITNESS
EvalSymlinks の後に結合されたパスを baseDir 配下に封じ込める (Gitea PR 38215 localFileURL)。.. を拒否する。ダンプ側のシンボリックリンクをダンプ外へ追跡しない。ダンプルートに基づくヘルパーを除き、uri.Open から file:// を削除する。
restore.go · uri.goGNU Affero GPL v3.0。LICENSE を参照。ループバックラボのみ。無保証。