
Forgejo 16.0.5 - Élevé - À distance - Lecture de fichier - restore-repo suit file:// côté dump vers les pièces jointes
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · forgejo-restore-file-open
Write-up : https://abraxaslabs.tech/research/forgejo-restore-file-open
Classe : Lecture de fichier Portée : Locale
Forgejo 16.0.5 (8d24b7d) - Forgejo
forgejo restore-repo sur un dump non fiable réécrit les URLs des assets de release avec un filepath.Join(baseDir, download_url) brut et préfixe par file://. uri.Open fait toujours un os.Open sur ce chemin. Un --units vide restaure les releases. Gitea 1.27.0 a ajouté localFileURL et ignorait l'échappement des entrées. Ce helper n'est pas présent ici.
La restauration par l'opérateur d'un dump non fiable copie un fichier de l'hôte que l'uid forgejo peut ouvrir dans une pièce jointe de release.
| ID | pas encore de CVE |
| Classe | Lecture de fichier |
| Portée | Locale (opérateur forgejo restore-repo d'un dump non fiable) |
| CWE | CWE-22 / CWE-73 |
| CVSS | Élevé : 7.3 CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:C/C:H/I:N/A:N |
| Produit | Forgejo |
| Affecté | jusqu'à v16.0.5 (8d24b7d) ; restauration par l'opérateur local |
| Auth | restauration par l'opérateur local d'un dump non fiable |
| Licence | GNU Affero GPL v3.0 |
| Lab | 127.0.0.1 uniquement |
Fournir à l'opérateur un répertoire de dump (ou disposer déjà de INTERNAL_TOKEN et d'un chemin que le serveur peut lire). Les units incluent releases / release_assets.
| Privilège | Méthode / sink | Recon / intégrité / disponibilité | Prouvé en lab ou déduit |
|---|---|---|---|
Lire un fichier de l'hôte que l'uid forgejo peut ouvrir, via .. hors du dump | release.yml download_url: ../FORGEJO-FILE-WITNESS.txt ; la restauration joint, uri.Open fait un os.Open, les octets sont stockés comme witness.txt | Recon (confidentialité de fichiers de l'hôte) | Prouvé en lab. Le corps de la pièce jointe est FORGEJO-RESTORE-FILE-OPEN-WITNESS. Le leurre dans le dump INSIDE-DUMP-NOT-HOST n'a pas été servi |
| Même résultat avec un lien symbolique planté dans le dump | Le chemin joint reste sous baseDir ; os.Open suit le lien | Recon | Déduit de uri.Open file -> os.Open. Le lab a utilisé .., pas un lien symbolique |
| Même sink sur les patches de PR | pull_request.yml PatchURL est réécrit de la même manière, puis uri.Open vers repo/pulls/<n>.patch | Recon | Déduit de restore.go GetPullRequests. Le lab n'a restauré que les releases |
| Les lecteurs du dépôt restauré téléchargent le fichier de l'hôte | GET /<owner>/<repo>/releases/download/<tag>/<name> | Recon | Prouvé en lab en tant que labadmin Basic sur le dépôt public restauré |
Fichiers d'hôte typiques : app.ini, INTERNAL_TOKEN, SECRET_KEY, mot de passe DB | l'uid forgejo peut lire l'arborescence de configuration | Recon | Déduit. Le témoin du lab était un fichier planté à côté du dump, pas des secrets réels |
Fermé ici : LFI file:// en direct via POST /repos/migrate (DownloadFunc défini ; PatchURL de PR vérifié par préfixe contre la base HTTP du clone). Échappement par jointure à la racine du dump via DownloadURL absolu (en Go filepath.Join("/dump", "/etc/passwd") reste /dump/etc/passwd). Restauration HTTP non authentifiée (CLI / token interne uniquement). Empaquetage de app.ini par le dump de sauvegarde (secrets par conception, mode d'archive 0600). Pas de LPE OS. Pas de LFI distant.
J'avais deux idées de restauration. J'ai d'abord testé mentalement la jointure absolue de Gitea. Le filepath.Join de Go ne supprime pas un second argument absolu comme le fait os.path.join de Python. L'entrée qui fonctionne est le .. relatif. Le localFileURL de Gitea n'est pas dans cet arbre.
Mauvais chemins déjà consignés : évasion par jointure sur la racine du dump via une DownloadURL absolue ; LFI file:// en migration à chaud ; X-Forgejo-Internal-Auth (la restauration se fait en CLI avec l'uid forgejo, pas via /api/internal) ; traiter la restauration HTTP comme non authentifiée à distance ; un reverse shell. Du théâtre.
python3 forgejo-restore-file-open-Abraxas-Labs.py
ou :
cd lab
./run.sh
Ciblez uniquement http://127.0.0.1:19340. Image codeberg.org/forgejo/forgejo:16.0.5. Témoin 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
Confiner les chemins joints sous baseDir après EvalSymlinks (Gitea PR 38215 localFileURL). Refuser ... Ne pas suivre les liens symboliques côté dump hors du dump. Supprimer file:// de uri.Open, sauf pour un helper ancré à la racine du dump.
restore.go · uri.goGNU Affero GPL v3.0. Voir LICENSE. Laboratoire en boucle locale uniquement. Aucune garantie.