Spiegazione del comando per verificare lo shellshock


32

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?


4
Vedi anche: unix.stackexchange.com/q/157329/70524 - La risposta di Fixee potrebbe essere di aiuto.
Muru,

Risposte:


45

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 echoqui 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 somecommandfa 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 envcomando esegue un comando con un determinato set di variabili. In questo caso, stiamo impostando xqualcosa 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-colonquale segna la fine della definizione della funzione, c'è un echocomando. 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 xvariabile 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.


1
Grazie per una eccellente spiegazione del perché questo funziona.
Doug R.,

2
Nota che envnon è 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 .
In pausa fino a nuovo avviso.

1
... ma potrebbe essere necessario in alcune delle patch più recenti. Le cose sono in evoluzione.
In pausa fino a nuovo avviso.

4
@DennisWilliamson Il fatto che envsia 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 commandsintassi; 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).
Eliah Kagan,

2

Nella versione senza patchbash memorizza le definizioni delle funzioni esportate come variabili di ambiente.

Memorizza una funzione xcome

$ 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() { :;
}

Cosa fa il comando per controllare shellshock,

env x='() { :;}; echo vulnerable' bash -c "echo this is a test"

Da man env,

  1. env - esegue un programma in un ambiente modificato.

  2. :non fare altro che uscire con lo stato di uscita 0. vedi di più

  3. 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


Ho ancora scoperto che qualsiasi funzione bash definita, se esportata, veniva valutata nella shell figlio nella versione patchata di bash. Vedi questo: chayan @ chayan: ~ / testr $ test () {echo "anything"; }; esportazione -f test; bash -c test Ouput: qualcosa Quindi la tua risposta non è in qualche modo indirizzata correttamente. Credo che la spiegazione di kasiyA del bug come espandere la variabile oltre la sua definizione sia corretta.
heemayl,

@heemayl questo comportamento è naturale. Ma se ci provi env test='() { echo "anything"; }' bash -c "echo otherthing"vedrai all'uscita otherthing. Questo è corretto nella patch. sentiti libero se non sono ancora chiaro.
souravc,

Per favore, chiariscimi ancora una volta. Nel tuo ultimo commento stiamo sostanzialmente definendo la funzione e quindi dicendo a bash di eseguire l'eco. In questo esempio non abbiamo chiamato la funzione in bash. Questo non avrebbe lo stesso output in entrambi i bash patchati e non patchati? Sto avendo l'idea che il bug era sostanzialmente come bash stava eseguendo comandi posti dopo la definizione della funzione mentre la funzione non è mai stata chiamata da nessuna parte in seguito per esempio se facciamo questo env test = '() {echo "niente"; }; echo "pippo" 'bash -c "echo altro". Per favore, chiariscimi in questo contesto.
heemayl,

@heemayl Ho modificato la mia risposta, spero che ora sia chiaro. Hai ragione nell'esempio nel mio ultimo commento, non abbiamo chiamato la funzione. Ma la differenza è che in un unpatched bashè possibile chiamare la funzione come è definita, ma in una patch bashla definizione stessa non c'è.
souravc,

@heemayl: No, non è corretto. Un Bash con patch passerà comunque la definizione della funzione nell'ambiente del bambino. La differenza che la patch fa è che il codice che segue la definizione della funzione ( 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 ().
In pausa fino a nuovo avviso.
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.