Ecco il comando che ho usato per controllare la mia shell bash per il bug Shellshock:
env x='() { :;}; echo vulnerable' bash -c "echo this is a test"
Qualcuno può spiegare il comando in dettaglio?
Ecco il comando che ho usato per controllare la mia shell bash per il bug Shellshock:
env x='() { :;}; echo vulnerable' bash -c "echo this is a test"
Qualcuno può spiegare il comando in dettaglio?
Risposte:
Questa risposta è un derivato di un articolo originale su Fedora Magazine di Matthew Miller, concesso in licenza con la licenza Creative Commons Attribution-Share Alike 4.0 .
Lasciatemi spiegare:
env x='() { :;}; echo OOPS' bash -c :
Questo stamperà "OOPS" su un sistema vulnerabile, ma uscirà silenziosamente se bash è stato patchato.
env x='() { :;}; echo OOPS' bash -c "echo this is a test"
Questo stamperà "OOPS" su un sistema vulnerabile, ma stampa “this is a test”
se bash è stato patchato.
E probabilmente hai sentito che ha qualcosa a che fare con le variabili d'ambiente. Ma perché viene eseguito il codice nelle variabili d'ambiente? Beh, non dovrebbe esserlo, ma, a causa di una caratteristica che sono tentato di definire un po 'troppo intelligente per il suo bene, c'è spazio per un difetto. Bash è ciò che vedi come prompt terminale, ma è anche un linguaggio di scripting e ha la capacità di definire funzioni. Lo fai in questo modo:
$ Ubuntu() { echo "Ubuntu is awesome."; }
e poi hai un nuovo comando. Tieni presente che il echo
qui non è ancora in esecuzione; è appena salvato come ciò che accadrà quando eseguiremo il nostro nuovo comando. Questo sarà importante tra un minuto!
$ Ubuntu
Ubuntu is awesome.
Utile! Ma, diciamo, per qualche motivo, abbiamo bisogno di eseguire una nuova istanza di bash, come sottoprocesso, e voglio eseguire il mio fantastico nuovo comando sotto quello. L'istruzione bash -c somecommand
fa esattamente questo: esegue il comando dato in una nuova shell:
$ bash -c Ubuntu
bash: Ubuntu: command not found
Ooh. Triste. Il bambino non ha ereditato la definizione della funzione. Ma è inerente all'ambiente: una raccolta di coppie chiave-valore che sono state esportate dalla shell. (Questo è un concetto completamente più pazzo; se non hai familiarità con questo, fidati di me per ora.) E, a quanto pare, Bash può anche esportare funzioni. Così:
$ export -f Ubuntu
$ bash -c Ubuntu
Ubuntu is awesome.
Il che va bene e va bene - tranne per il fatto che il meccanismo con cui questo viene realizzato è un po 'complicato . Fondamentalmente, poiché non esiste alcuna magia Linux / Unix per eseguire funzioni nelle variabili di ambiente, la funzione di esportazione in realtà crea semplicemente una normale variabile di ambiente contenente la definizione della funzione. Quindi, quando la seconda shell legge l'ambiente "in arrivo" e incontra una variabile con contenuti che sembrano una funzione, la valuta.
In teoria, questo è perfettamente sicuro , perché, ricorda, la definizione di una funzione non la esegue effettivamente . Tranne - ed è per questo che siamo qui - c'era un bug nel codice in cui la valutazione non si fermava quando veniva raggiunta la fine della definizione della funzione. Continua a funzionare.
Ciò non accadrà mai quando la funzione memorizzata in una variabile di ambiente viene effettuata in modo legittimo, con export -f
. Ma perché essere legittimi? Un utente malintenzionato può semplicemente compensare qualsiasi vecchia variabile d'ambiente, e se sembra una funzione, le nuove shell bash penseranno che lo sia!
Quindi, nel nostro primo esempio:
env x='() { :;}; echo OOPS' bash -c "echo this is a test"
Il env
comando esegue un comando con un determinato set di variabili. In questo caso, stiamo impostando x
qualcosa che assomiglia a una funzione. La funzione è solo una :
, che in realtà è un semplice comando che viene definito come non fare nulla. Ma poi, dopo il semi-colon
quale segna la fine della definizione della funzione, c'è un echo
comando. Non dovrebbe essere lì, ma non c'è niente che ci impedisce di farlo.
Quindi, il comando dato per essere eseguito con questo nuovo ambiente è una nuova shell bash, sempre con un comando " echo this is a test
" o "non fare nulla :
", dopo di che uscirà, completamente innocuo.
Ma - oops! Quando quella nuova shell si avvia e legge l'ambiente, arriva alla x
variabile e, poiché sembra una funzione, la valuta. La definizione della funzione viene caricata in modo innocuo, quindi viene attivato anche il nostro payload dannoso. Quindi, se esegui quanto sopra su un sistema vulnerabile, verrai “OOPS”
stampato di nuovo su di te. Oppure, un attaccante potrebbe fare molto peggio della semplice stampa di cose.
env
non è necessario. È possibile ottenere lo stesso risultato (Passa / Scarta a seconda che Bash è stato aggiornato) utilizzando il comando senza di essa: x='() { :;}; echo OOPS' bash -c "echo this is a test"
. Questo perché la precedente di un comando con un'assegnazione di variabile passa quella variabile e il suo valore nell'ambiente ( bash -c "..."
in questo caso) del comando .
env
sia necessario o meno è determinato dalla shell da cui si esegue il test, non dalla shell da testare. (Questi possono essere gli stessi. Anche allora, stiamo testando il modo in cui bash elabora il proprio ambiente.) Le shell in stile Bourne accettano la NAME=value command
sintassi; Conchiglie in stile C (ad esempio, csh
, tcsh
) non lo fanno. Quindi il test è un po 'più portatile con env
(a costo di creare a volte confusione su come funziona).
Nella versione senza patchbash
memorizza le definizioni delle funzioni esportate come variabili di ambiente.
Memorizza una funzione x
come
$ x() { bar; }
$ export -f x
E controlla la sua definizione come,
$ env | grep -A1 x
x=() { bar
}
Quindi uno potrebbe sfruttare questo definendo le proprie variabili d'ambiente e le interpreta come definizioni di funzione. Ad esempio env x='() { :;}'
verrebbe trattato come
x() { :;
}
env x='() { :;}; echo vulnerable' bash -c "echo this is a test"
Da man env
,
env
- esegue un programma in un ambiente modificato.
:
non fare altro che uscire con lo stato di uscita 0
. vedi di più
Quando viene lanciata una nuova istanza di bash senza patch bash -c "echo this is a test"
, la variabile ambientale predisposta viene trattata come una funzione e caricata. Di conseguenza si ottiene l'output
vulnerabile questo è un test
Nota: l'eco al di fuori della definizione della funzione è stato eseguito inaspettatamente durante l'avvio di bash. La definizione della funzione è solo un passo per ottenere la valutazione e l'exploit, la definizione della funzione stessa e la variabile di ambiente utilizzata sono arbitrarie. La shell esamina le variabili di ambiente, vede x, che sembra soddisfare i vincoli che conosce su come appare una definizione di funzione, e valuta la linea, eseguendo involontariamente anche l'eco (che potrebbe essere qualsiasi comando, dannoso o no) . Vedi anche questo
env test='() { echo "anything"; }' bash -c "echo otherthing"
vedrai all'uscita otherthing
. Questo è corretto nella patch. sentiti libero se non sono ancora chiaro.
unpatched bash
è possibile chiamare la funzione come è definita, ma in una patch bash
la definizione stessa non c'è.
echo vulnerable
) non viene eseguito. Si noti che nelle ultime patch, la funzione passata deve avere un prefisso specifico ( env 'BASH_FUNC_x()'='() { :;}; echo vulnerable' bash -c "echo this is a test"
). Alcune patch più recenti potrebbero utilizzare al %%
posto della prima ()
.