
Forgejo 16.0.5 - Alta - Remota - IDOR - GET /api/v1/user/keys/{id} restituisce le chiavi SSH e deploy di altri utenti
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · forgejo-keys-idor
Write-up: https://abraxaslabs.tech/research/forgejo-keys-idor
Classe: IDOR Portata: Remota
Forgejo 16.0.5 (8d24b7d) - Forgejo
GET /api/v1/user/keys/{id} si trova nel gruppo dell'utente corrente (reqToken, scope utente). Il gestore carica comunque public_key tramite ID numerico senza alcun controllo del proprietario. La stessa tabella contiene chiavi utente, chiavi di deploy e principal. GPG su questa versione fa le cose correttamente: GetGPGKeyForUserByID(ctx, ctx.Doer().ID, id). I campi privati aggiuntivi sono protetti. Il materiale della chiave pubblica, il titolo e l'impronta non lo sono. Gli ID sono sequenziali.
Un token read:user scorre 1, 2, 3 e inventaria le chiavi SSH e di deploy altrui.
| ID | nessuna CVE al momento |
| Classe | IDOR |
| Portata | Remota (read:user autenticato / sessione) |
| CWE | CWE-639 |
| CVSS | Alta: 7.5 CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N |
| Prodotto | Forgejo |
| Affetto | fino alla v16.0.5 (8d24b7d) |
| Auth | autenticato (token read:user o sessione) |
| Licenza | GNU Affero GPL v3.0 |
| Lab | solo 127.0.0.1 |
Registrare o usare qualsiasi account, generare un token read:user (o usare un cookie di sessione), scorrere /api/v1/user/keys/{id}. Ottiene titoli, impronte e materiale delle chiavi pubbliche di chiavi che non possiede. Non ottiene la chiave privata. Non ottiene una shell. Inventaria chi ha accesso a cosa.
| Privilegio | Metodo / sink | Recon / integrità / disponibilità | Provato in lab o dedotto |
|---|---|---|---|
| Leggere titolo, impronta e materiale della chiave pubblica SSH di un altro utente | GET /api/v1/user/keys/{id} come proprietario estraneo | Recon (riservatezza dell'inventario delle chiavi pubbliche) | Provato in lab. Titolo testimone FORGEJO-KEYS-IDOR-WITNESS sull'id 1; la lista dell'attaccante contiene solo l'id 2 |
| Inventariare le chiavi di deploy allo stesso modo | Stesso gestore, righe KeyTypeDeploy in public_key (OwnerID 0) | Recon | Dedotto dalla tabella. Nel lab è stata inserita una chiave SSH utente, non una chiave di deploy |
| Leggere i principal dei certificati SSH | Stesso gestore, righe KeyTypePrincipal. ListPublicKeys esclude questo tipo | Recon | Dedotto dalla tabella |
| Vedere chiavi appartenenti a utenti limitati o privati | Nessun controllo di visibilità su questa ricerca | Recon | Dedotto dal gestore |
JSON extra (user, key_type, read_only) | appendPrivateInformation solo se admin o proprietario | Recon | Provato in lab chiuso: la risposta per un non proprietario non aveva il campo user |
Chiuso su questa rotta: materiale della chiave privata, una shell, GET /users/{username}/keys (lista pubblica con scope per username), GPG GET /api/v1/user/gpg_keys/{id} (404 su un id estraneo), DeletePublicKey (403 per proprietario/admin). Cross-repo GET /repos/{owner}/{repo}/keys/{id} restituisce 404 quando RepoID non corrisponde.
Le patch di sicurezza della v16.0.5 (#14370) erano RCE tramite git-apply e CSRF su OpenID. Non hanno chiuso questa ricerca. Stessa classe di gitea-user-keys-idor, indipendentemente ancora aperta qui.
Ho fissato Forgejo v16.0.5 dopo l'ondata del 2026-09. Gitea 1.27.3 aveva ancora questa ricerca. Forgejo si è differenziato, quindi ho riletto il gestore delle chiavi dell'utente corrente accanto a GPG invece di copiare il pacchetto Gitea. GPG restituisce 404 su un id estraneo. SSH no.
Trattare la lista dell'attaccante stesso come la fuga di dati (non lo è - la lista è con ambito limitato, il GET-by-id non lo è); trattare DISABLE_REGISTRATION=true sull'installer come una chiusura (qualsiasi account esistente è sufficiente); una reverse shell. Teatro.
python3 forgejo-keys-idor-Abraxas-Labs.py
o:
cd lab
./run.sh
Prendi di mira solo http://127.0.0.1:19310. Immagine codeberg.org/forgejo/forgejo:16.0.5. Due account. Witness 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
404 a meno che key.OwnerID == ctx.Doer().ID (o amministratore del sito). Rifiutare KeyTypeDeploy / KeyTypePrincipal su questa rotta. Corrisponde a GetGPGKeyForUserByID.
GetPublicKeyGNU Affero GPL v3.0. Vedi LICENSE. Solo laboratorio loopback. Nessuna garanzia.