
L'helper writeToFile di Consul Template ha aperto direttamente una destinazione fornita dall'operatore e ha seguito i componenti di percorso collegati, consentendo all'output generato di fuoriuscire dalla directory prevista e di sovrascrivere un file preesistente.
L'helper writeToFile di Consul Template apriva direttamente una destinazione fornita dall'operatore e seguiva i componenti di percorso linkati, consentendo all'output renderizzato di fuoriuscire dalla directory prevista e sovrascrivere un file preesistente.
Ho trovato questo problema durante la revisione di HashiCorp Consul Template, con una domanda diretta sulla sicurezza del filesystem in mente:
Se writeToFile riceve un percorso che sembra essere all'interno della directory prevista, verifica dove il filesystem scriverà effettivamente i dati?
In questo caso, la risposta è stata no.
L'helper di template writeToFile apriva direttamente il percorso finale fornito dall'utente tramite os.Create() o os.OpenFile().
Queste operazioni seguivano i collegamenti simbolici, le junction di directory e le equivalenti redirezioni del filesystem già presenti nel percorso di destinazione.
Ciò significava che la stringa del percorso poteva rimanere sotto la root prevista dall'operatore mentre la scrittura effettiva finiva altrove.
Nella mia prova di concetto controllata, una directory padre linkata ha reindirizzato l'output renderizzato al di fuori dell'albero previsto e ha causato la sovrascrittura di un file di destinazione preesistente.
Questo problema è diventato CVE-2026-14361.
Bollettino HashiCorp: HCSEC-2026-20
Bollettino IBM: bollettino di sicurezza CVE-2026-14361
CVE: CVE-2026-14361
Corretto in: 0.42.1
photo0
la destinazione fornita dall'operatore appare all'interno della root prevista -> l'attaccante posiziona preventivamente un componente padre o finale linkato -> writeToFile apre il percorso direttamente -> il filesystem risolve la scrittura al di fuori della directory prevista -> il segreto renderizzato viene reindirizzato -> il target preesistente può essere sovrascritto
Consul Template renderizza dati da fonti come Consul e Vault.
L'helper writeToFile consente a un template di scrivere contenuto selezionato in un file locale separato applicando proprietario, gruppo e permessi richiesti.
La documentazione di HashiCorp mostra specificamente l'helper con materiale PKI:
private key -> writeToFile /my/path/to/cert.key
certificate authority -> writeToFile /my/path/to/cert.pem
certificate -> append to /my/path/to/cert.pem
Questo lo rende più di un semplice helper di output.
Il contenuto che attraversa questo confine può includere:
La domanda importante non era se writeToFile potesse creare un nome file richiesto.
La vera domanda era:
Il processo scrive nella posizione del filesystem prevista dall'operatore, o semplicemente in qualunque oggetto a cui il percorso si risolve al momento dell'apertura?
Nelle versioni vulnerabili, si fidava di quest'ultimo.
Gli helper di scrittura sono superfici di sicurezza ad alto valore perché passano dai dati dell'applicazione alla mutazione del filesystem.
I guasti interessanti spesso non sono la classica traversal ../.
Sono guasti di risoluzione:
Questo è particolarmente importante quando il processo viene eseguito con più privilegi sul filesystem rispetto all'attaccante.
Un attaccante locale a bassi privilegi potrebbe non essere in grado di sovrascrivere direttamente un file sensibile.
Ma se può influenzare un componente del percorso sotto una directory di scrittura prevista, un processo Consul Template più privilegiato potrebbe eseguire la scrittura al suo posto.
Questo era il confine su cui mi sono concentrato.
Non ho affrontato questo come una generica revisione di path traversal.
Il percorso fornito non richiedeva segmenti ...
Poteva rimanere lessicalmente all'interno della root prevista per tutto il tempo.
La domanda più forte era:
I componenti di destinazione linkati vengono rifiutati prima che il contenuto sensibile venga scritto?
Questa domanda è importante per entrambi:
Il secondo caso è particolarmente utile perché i log e la configurazione mostrano ancora un percorso dall'aspetto innocuo sotto la directory prevista.
Il filesystem lo risolve altrove.
La causa radice era la creazione diretta di file basata sul percorso senza validazione consapevole dei link.
Alla revisione testata, writeToFile() selezionava uno dei due percorsi di apertura.
La modalità append usava:
f, err = os.OpenFile(
path,
os.O_APPEND|os.O_WRONLY|os.O_CREATE,
perm,
)
La normale modalità di scrittura usava:
dirPath := filepath.Dir(path)
if _, err := os.Stat(dirPath); err != nil {
err := os.MkdirAll(dirPath, os.ModePerm)
if err != nil {
return "", err
}
}
f, err = os.Create(path)
Nessuno dei due percorsi rifiutava i componenti di destinazione linkati prima dell'apertura del file.
Questo è importante perché:
os.Create(path) segue le redirezioni esistenti del filesystem e tronca il file risoltoos.OpenFile(path, ...) segue i componenti di percorso linkati durante la modalità appendLa stessa assunzione basata sul percorso continuava dopo la scrittura.
Proprietà e permessi venivano applicati usando di nuovo il percorso:
err = os.Chown(path, uid, gid)
err = os.Chmod(path, perm)
Ciò significava che anche le operazioni sui metadati erano legate a un nome di percorso mutabile invece che al descrittore di file già aperto.
Perché l'attaccante può preparare la redirezione prima che writeToFile venga eseguito.
Nessuna race probabilistica è richiesta per l'attacco di base.
La sequenza è semplice:
writeToFile la apre direttamenteQuesta è l'intera vulnerabilità.
È vero che i sistemi operativi normalmente seguono i symlink durante le aperture di file basate sul percorso.
Questo non rende questo un comportamento applicativo sicuro.
La domanda di sicurezza non è:
"Go si è comportato come documentato?"
La vera domanda è:
Un helper che scrive dati sensibili renderizzati ha verificato che la destinazione risolta corrispondesse alla posizione prevista dall'operatore?
Nelle versioni vulnerabili, non lo ha fatto.
Questa distinzione è importante perché Consul Template può essere eseguito: