Individuazione di una vulnerabilità non isolabile relativa all'iniezione di comando in Kubernetes
Editoriale e commenti aggiuntivi di Tricia Howard
Analisi riassuntiva
Tomer Peled, ricercatore della sicurezza di Akamai, ha recentemente scoperto una vulnerabilità molto grave in Kubernetes a cui è stato assegnato il codice CVE-2023-3676 con un punteggio CVSS di 8,8.
Questa scoperta ha portato all'identificazione di altre due vulnerabilità che condividono la stessa causa principale: chiamata di funzione non sicura e mancata sanificazione dell'input utente.
La vulnerabilità consente l'esecuzione di codice da remoto con privilegi di SISTEMA su tutti gli endpoint Windows all'interno di un cluster Kubernetes. Per sfruttare questa vulnerabilità, l'autore dell'attacco deve applicare un file YAML dannoso sul cluster.
Questa vulnerabilità può essere sfruttata nelle installazioni predefinite di Kubernetes ed è stata testata sia nelle distribuzioni on-premise sia in Azure Kubernetes Service.
Forniamo un file YAML proof-of-concept oltre a una regola OPA in grado di risolvere questa vulnerabilità.
Introduzione
L'acronimo YAML (che sta per YAML Ain't Markup Language, cioè YAML non è un linguaggio di markup) è appunto un linguaggio di serializzazione dei dati simile a JSON, che viene utilizzato principalmente nei file di configurazione. In quanto tale, svolge un ruolo importante in Kubernetes, il nuovo e onnipresente sistema di orchestrazione dei container che aiuta le organizzazioni ad automatizzare la distribuzione, la scalabilità e la gestione delle applicazioni containerizzate. Il framework di Kubernetes utilizza i file YAML praticamente per tutto, dalla configurazione della CNI (Container Network Interface) alla gestione dei pod fino alla gestione segreta.
I file YAML in Kubernetes sono stati oggetto di ricerca negli ultimi anni. Considerando che Kubernetes vi si affida per la configurazione dei cluster, si tratta di un argomento di ricerca particolarmente interessante da approfondire.
Come sono stati sfruttati in precedenza i file YAML e Kubernetes?
Nel 2022, all'interno del costruttore di SnakeYAML, noto parser di file YAML, è stata rilevata la vulnerabilità CVE-2022-1471. Questa consentiva la creazione di oggetti non sicuri, che potevano portare all'esecuzione di codice sulle applicazioni vulnerabili che lo utilizzavano. Un altro esempio che mostra il possibile impatto dei file YAML è illustrato in questo documento consultivo delle CVE relativo alla vulnerabilità CVE-2021-25749 e redatto dal team della sicurezza di Kubernetes. Questa vulnerabilità consente agli utenti malintenzionati di eludere la verifica degli utenti autorizzati all'esecuzione come root, digitandone erroneamente il nome nel file YAML.
Nell'ambito della nostra ricerca su Kubernetes abbiamo rilevato le vulnerabilità CVE-2017-1002101 e CVE-2021-25741. Queste hanno dimostrato come gli autori degli attacchi possono combinare race condition e symlink con la sottoproprietà subPath in un file YAML per accedere ai dati privilegiati all'esterno del container.
La scoperta di queste vulnerabilità ci ha spinto a perseguire la direzione dell'elaborazione dei percorsi nel codebase di Kubernetes, che alla fine ha portato all'individuazione della vulnerabilità di cui stiamo parlando oggi.
In questo post del blog, illustreremo come un utente malintenzionato con privilegi di "applicazione", ovvero i privilegi necessari per interagire con l'API Kubernetes, può iniettare un codice che verrà eseguito su computer Windows remoti con privilegi di SISTEMA.
Dettagli della vulnerabilità
Quando crea un pod, l'utente ha la possibilità di creare anche una directory condivisa tra il pod e l'host. Questa funzione, detta volumi, è utile ad esempio mentre si servono siti web attraverso un container in un pod. Potremmo voler condividere i file del sito da una directory condivisa con l'host; in questo modo, saremmo in grado di modificare il layout del sito come desideriamo e non avremmo bisogno di ricompilare ogni volta un'immagine contenente il sito.
L'attivazione dei volumi viene eseguita includendo il parametro volume nel file YAML del pod. Le posizioni in cui collocare il volume sono elencate nella mountPath (la posizione nel contenitore) e in hostPath (la posizione sull'host).
Per noi, la cosa più importante èla possibilità di collocare la directory o il file condiviso in una posizione scelta utilizzando la sottoproprietà subPath. Tutte le proprietà rilevanti per i volumi sono visibili nella Figura 1.
L'analisi del file YAML viene eseguita da kubelet, un servizio fondamentale in Kubernetes, responsabile dell'esecuzione delle applicazioni containerizzate su un nodo. Come parte della patch per CVE-2021-25741, kubelet convalida ogni parametro nel file YAML e assicura che non vengano creati collegamenti symlink in seguito all'utilizzo del parametro subPath, chiamando la funzione interna "isLinkPath". La funzione viene visualizzata nella Figura 2.
La funzione prende come parametro il subPath fornito dall'utente nel file YAML. Quindi utilizza questo percorso per creare un comando PowerShell destinato a stabilire il tipo di percorso (ad esempio, se si tratta di un symlink o meno). Il comando formattato PowerShell viene quindi richiamato immediatamente dalla chiamata di funzione "exec.Command".
La presenza di "exec.Command" combinata con un input non sanitizzato fornito dall'utente, suggerisce prepotentemente l'opportunità di un'iniezione di comandi.
PowerShell consente agli utenti di esaminare i valori all'interno delle stringhe prima di utilizzarli. Questa operazione può essere eseguita aggiungendo, ad esempio, $(<experssion_to_be_evaluated>) alla stringa (Figura 3).
PS> echo “the value of 1+1 is $(1+1)
Output:
the value of 1+1 is 2
Figura 3. Esempio di PowerShell che valuta le espressioni all'interno delle stringhe
Questo esempio è piuttosto semplice, ma in realtà qualsiasi comando PowerShell può essere inserito tra le parentesi e valutato, ad esempio $(Start-Process cmd), $(Invoke-Expression exp) e altre considerazioni PowerShell.
Un utente malintenzionato può sfruttare questa valutazione del subPath per raggiungere il codice vulnerabile ed eseguire qualsiasi comando desideri con privilegi di SISTEMA (contesto proprio di kubelet) dai nodi remotie ottenere così il controllo di tutti i nodi Windows nel cluster. La Figura 4 mostra un valore di subPath dannoso.
Proof-of-Concept che presenta la vulnerabilità CVE-2023-3676
La Proof-of-Concept è semplicemente un file YAML che contiene la valutazione del comando PowerShell. Questo file, insieme a un video che mostra il terminale in fase di avvio, è disponibile nel nostro archivio GitHub.
Questa CVE ci ha permesso di scoprire e correggere altre vulnerabilità legate all'iniezione di comandi a cui sono stati assegnati collettivamente i numeri CVE-2023-3955 e CVE-2023-3893.
Analisi delle patch
Il team di Kubernetes ha scelto di risolvere questo tipo di vulnerabilità fornendo i parametri dalle variabili di ambiente invece che dall'input utente (Figura 5). Trasmettendo i valori in questo modo, i parametri vengono trattati come stringhe, pertanto non vengono valutati come espressioni da PowerShell.
Sono vulnerabile?
Come accennato in precedenza, tutte le versioni di Kubernetes precedenti a 1.28 sono vulnerabili a questa CVE. Esistono diversi metodi per stabilire se uno dei nodi del cluster è un nodo Windows. Uno di questi consiste nell'eseguire il comando riportato nella Figura 6.
kubectl get nodes -o wide --show-labels | grep “os=windows” Output: akswin000000 Ready agent 4d17h v1.26.6 agentpool=win,beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=windows… akswin000001 Ready agent 4d17h v1.26.6 agentpool=win,beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=windows… |
Figura 6. Un comando kubectl per stabilire se uno dei nodi del cluster è un nodo Windows
Mitigazione
L'applicazione di patch è il modo più affidabile per proteggersi da questa vulnerabilità. Nei casi in cui l'applicazione delle patch non sia possibile, abbiamo delineato una serie di metodi di protezione alternativi e potete scegliere quello più adatto al vostro ambiente.
Soluzioni precedenti
Per la vulnerabilità CVE-2023-3676, gli amministratori di Kubernetes possono disattivare l'uso di Volume.Subpath. Questa azione garantisce la protezione del cluster da questa vulnerabilità, ma disattiva un meccanismo che a volte è importante per i cluster in produzione.
OPA
Open Policy Agent (OPA) è un agente open source che consente agli utenti di ricevere dati sul traffico in entrata e in uscita dai nodi e di eseguire azioni sui dati ricevuti in base a determinate policy. L'agente OPA utilizza Rego come linguaggio per il motore e con questo gli amministratori possono creare regole per bloccare l'implementazione di determinati file YAML. La Figura 7 illustra una regola che nega la creazione di pod con un subPath dannoso.
package kubernetes.admission
deny[msg] {
input.request.kind.kind == "Pod"
path := input.request.object.spec.containers.volumeMounts.subPath
not startswith(path, "$(")
msg := sprintf("malicious path: %v was found", [path])
}
Figura 7. Regola che blocca la creazione di pod con un subPath dannoso
RBAC
Il controllo degli accessi basato sui ruoli (RBAC) è un metodo che segmenta le operazioni degli utenti in base alla loro identità. Ad esempio, ogni utente può creare i pod solo nel proprio spazio dei nomi o solo visualizzare le informazioni per gli spazi dei nomi consentiti. Ciò può aiutare a limitare il numero di utenti autorizzati a eseguire azioni su un cluster e permette di concentrare l'attenzione su quelli che dispongono dei privilegi necessari per lo sfruttamento.
Conclusione
La vulnerabilità CVE-2023-3676 richiede privilegi minimi, pertanto facilita gli attacchi da parte di utenti malintenzionati a cui basta avere l'accesso a un nodo e i privilegi di applicazione . Come discusso in questo post del blog, sfruttando correttamente questa vulnerabilità, è possibile eseguire un codice da remoto in qualsiasi nodo Windows sul computer con privilegi di SISTEMA.
Di solito l'impatto elevato e la facilità di sfruttamento si traducono in una maggiore probabilità di vedere questo attacco (e attacchi simili) perpetrati nei confronti delle organizzazioni. In effetti, l'unico limite di questa vulnerabilità è il suo ambito: è riservata ai nodi Windows, che oggi non sono molto diffusi.
È importante che gli amministratori aggiornino i cluster Kubernetes alla versione più recente disponibile per evitare lo sfruttamento di queste vulnerabilità. Se non è possibile applicare immediatamente le patch, si consiglia di utilizzare uno dei metodi descritti in precedenza per proteggersi da questa vulnerabilità.
Desideriamo ringraziare il team di Kubernetes per la risposta molto rapida e la comunicazione efficace.
Cronologia delle divulgazioni
13/07/2023 - Vulnerabilità segnalata al team Kubernetes.
19/07/2023 - Il team di Kubernetes assegna i numeri CVE
23/08/2023 - Kubernetes rilascia le correzioni CVE
13/09/2023 - Pubblicazione del post sul blog