Hier ist der Befehl, mit dem ich meine Bash-Shell auf den Shellshock-Fehler überprüft habe:
env x='() { :;}; echo vulnerable' bash -c "echo this is a test"
Kann jemand bitte den Befehl im Detail erklären?
Hier ist der Befehl, mit dem ich meine Bash-Shell auf den Shellshock-Fehler überprüft habe:
env x='() { :;}; echo vulnerable' bash -c "echo this is a test"
Kann jemand bitte den Befehl im Detail erklären?
Antworten:
Diese Antwort ist eine Ableitung eines Originalartikels im Fedora Magazine von Matthew Miller, lizenziert unter der Creative Commons Namensnennung-Weitergabe unter gleichen Bedingungen 4.0 .
Lassen Sie mich erklären:
env x='() { :;}; echo OOPS' bash -c :
Dies gibt "OOPS" auf einem anfälligen System aus, beendet sich jedoch unbemerkt, wenn bash gepatcht wurde.
env x='() { :;}; echo OOPS' bash -c "echo this is a test"
Dadurch wird "OOPS" auf einem anfälligen System gedruckt, es wird jedoch gedruckt, “this is a test”
wenn bash gepatcht wurde.
Und Sie haben wahrscheinlich gehört, dass es etwas mit Umgebungsvariablen zu tun hat. Aber warum wird Code in Umgebungsvariablen ausgeführt? Nun, das soll es nicht sein - aber aufgrund eines Merkmals, das ich in der Versuchung bin, es ein bisschen zu schlau zu nennen, gibt es etwas Raum für einen Fehler. Bash ist das, was Sie als Terminal-Eingabeaufforderung sehen, aber es ist auch eine Skriptsprache und kann Funktionen definieren. Das machst du so:
$ Ubuntu() { echo "Ubuntu is awesome."; }
und dann hast du einen neuen befehl. Denken Sie daran, dass das echo
hier noch nicht ausgeführt wird. Es wird nur gespeichert, was passieren wird, wenn wir unseren neuen Befehl ausführen. Dies wird in einer Minute wichtig sein!
$ Ubuntu
Ubuntu is awesome.
Sinnvoll! Aber lassen Sie uns aus irgendeinem Grund sagen, wir müssen eine neue Instanz von bash als Unterprozess ausführen und möchten meinen fantastischen neuen Befehl unter diesem ausführen. Die Anweisung bash -c somecommand
macht genau das: Führt den angegebenen Befehl in einer neuen Shell aus:
$ bash -c Ubuntu
bash: Ubuntu: command not found
Oh. Traurig. Das Kind hat die Funktionsdefinition nicht geerbt. Die Umgebung ist jedoch inhärent - eine Sammlung von Schlüssel-Wert-Paaren, die aus der Shell exportiert wurden. (Dies ist ein komplettes Konzept. Wenn Sie damit nicht vertraut sind, vertrauen Sie mir jetzt.) Und wie sich herausstellt, kann bash auch Funktionen exportieren. So:
$ export -f Ubuntu
$ bash -c Ubuntu
Ubuntu is awesome.
Was alles gut und schön ist - außer dass der Mechanismus, durch den dies erreicht wird, ein bisschen zweifelhaft ist . Da es für die Ausführung von Funktionen in Umgebungsvariablen keine Linux / Unix-Magie gibt, erstellt die Exportfunktion im Grunde genommen nur eine reguläre Umgebungsvariable, die die Funktionsdefinition enthält. Wenn dann die zweite Shell die "eingehende" Umgebung liest und auf eine Variable mit Inhalten stößt, die wie eine Funktion aussehen, wertet sie diese aus.
Theoretisch ist dies absolut sicher , da das Definieren einer Funktion sie nicht tatsächlich ausführt . Außer - und aus diesem Grund sind wir hier - gab es einen Fehler im Code, bei dem die Auswertung nicht gestoppt wurde, als das Ende der Funktionsdefinition erreicht wurde. Es läuft einfach.
Das würde niemals passieren, wenn die in einer Umgebungsvariablen gespeicherte Funktion mit legitim gemacht wird export -f
. Aber warum echt sein? Ein Angreifer kann einfach eine alte Umgebungsvariable erfinden, und wenn es wie eine Funktion aussieht, werden neue Bash-Shells denken, dass dies der Fall ist!
Also, in unserem ersten Beispiel:
env x='() { :;}; echo OOPS' bash -c "echo this is a test"
Der env
Befehl führt einen Befehl mit einem bestimmten Variablensatz aus. In diesem Fall stellen wir x
etwas ein, das wie eine Funktion aussieht. Die Funktion ist nur eine einzige :
, was eigentlich ein einfacher Befehl ist, der definiert ist, nichts zu tun. Aber dann, nach dem, semi-colon
was das Ende der Funktionsdefinition signalisiert, gibt es einen echo
Befehl. Das sollte nicht da sein, aber es hindert uns nichts daran, es zu tun.
Dann ist der Befehl, der zum Ausführen mit dieser neuen Umgebung gegeben wird, eine neue Bash-Shell, wiederum mit einem " echo this is a test
" oder "nichts tun":
" enthält. sie völlig harmlos beendet.
Aber - hoppla! Wenn diese neue Shell gestartet wird und die Umgebung liest, gelangt sie zur x
Variablen, und da sie wie eine Funktion aussieht, wertet sie sie aus. Die Funktionsdefinition ist harmlos geladen - und dann wird auch unsere schädliche Nutzlast ausgelöst. Wenn Sie die oben genannten Schritte auf einem anfälligen System ausführen, werden Sie darauf hingewiesen “OOPS”
. Oder ein Angreifer kann viel Schlimmeres tun, als nur Dinge zu drucken.
env
nicht erforderlich ist. Sie können das gleiche Ergebnis (bestanden / nicht bestanden , je nachdem ob Bash aktualisiert wurde) , indem Sie den Befehl ohne es: x='() { :;}; echo OOPS' bash -c "echo this is a test"
. Dies liegt daran, dass vor einem Befehl mit einer Variablenzuweisung diese Variable und ihr Wert an die bash -c "..."
Umgebung des Befehls ( in diesem Fall) übergeben werden.
env
erforderlich ist oder nicht , hängt von der Shell ab, von der aus der Test ausgeführt wird, nicht von der zu testenden Shell. (Diese können identisch sein. Selbst dann testen wir, wie bash seine eigene Umgebung verarbeitet.) Shells im Borowski-Stil akzeptieren NAME=value command
Syntax. C-Stil Schalen (zB csh
, tcsh
) nicht. Daher ist der Test etwas portabler env
(auf Kosten von Verwirrung, wie er manchmal funktioniert).
In der ungepatchten Versionbash
werden exportierte Funktionsdefinitionen als Umgebungsvariablen gespeichert.
Speichern Sie eine Funktion x
als,
$ x() { bar; }
$ export -f x
Und überprüfen Sie seine Definition als,
$ env | grep -A1 x
x=() { bar
}
Man könnte dies also ausnutzen, indem man seine eigenen Umgebungsvariablen definiert und sie als Funktionsdefinitionen interpretiert. Zum Beispiel env x='() { :;}'
würde als behandelt werden
x() { :;
}
env x='() { :;}; echo vulnerable' bash -c "echo this is a test"
Von man env
,
env
- Führen Sie ein Programm in einer geänderten Umgebung aus.
:
Mach nichts anderes als Exits mit Exit-Status 0
. sehen mehr
Wenn eine neue Instanz von Bash ohne Patch gestartet wird bash -c "echo this is a test"
, wird die gestaltete Umgebungsvariable als Funktion behandelt und geladen. Dementsprechend bekommt man die Ausgabe
verletzlich das ist ein Test
Hinweis: Das Echo außerhalb der Funktionsdefinition wurde beim Bash-Start unerwartet ausgeführt. Die Funktionsdefinition ist nur ein Schritt, um die Evaluierung und den Exploit durchzuführen. Die Funktionsdefinition selbst und die verwendete Umgebungsvariable sind beliebig. Die Shell betrachtet die Umgebungsvariablen, sieht x, das den Einschränkungen entspricht, die für das Aussehen einer Funktionsdefinition bekannt sind, und wertet die Zeile aus. Dabei wird unbeabsichtigt auch das Echo ausgeführt (bei dem es sich um einen beliebigen Befehl handeln kann, der böswillig ist oder nicht). . Siehe auch dies
env test='() { echo "anything"; }' bash -c "echo otherthing"
, werden Sie am Ausgang sehen otherthing
. Das ist im Patch korrigiert. Fühlen Sie sich frei, wenn ich noch nicht klar bin.
unpatched bash
die Funktion aufrufen können, wie sie definiert ist, aber in einem gepatchten bash
die Definition selbst nicht vorhanden ist.
echo vulnerable
) folgt, nicht ausgeführt wird. Beachten Sie, dass in den neuesten Patches die übergebene Funktion ein bestimmtes Präfix ( env 'BASH_FUNC_x()'='() { :;}; echo vulnerable' bash -c "echo this is a test"
) haben muss. Einige neuere Patches können %%
anstelle des ersten verwendet werden ()
.