Es gibt anscheinend eine Sicherheitsanfälligkeit (CVE-2014-6271) in bash: Bash speziell gestaltete Umgebungsvariablen Code-Injection-Angriff
Ich versuche herauszufinden, was passiert, aber ich bin nicht ganz sicher, ob ich es verstehe. Wie kann das echo
ausgeführt werden, wie es in einfachen Anführungszeichen steht?
$ env x='() { :;}; echo vulnerable' bash -c "echo this is a test"
vulnerable
this is a test
EDIT 1 : Ein gepatchtes System sieht so aus:
$ env x='() { :;}; echo vulnerable' bash -c "echo this is a test"
bash: warning: x: ignoring function definition attempt
bash: error importing function definition for `x'
this is a test
BEARBEITEN 2 : Es gibt eine verwandte Sicherheitsanfälligkeit / einen verwandten Patch: CVE-2014-7169, der einen etwas anderen Test verwendet:
$ env 'x=() { :;}; echo vulnerable' 'BASH_FUNC_x()=() { :;}; echo vulnerable' bash -c "echo test"
ungepatchte Ausgabe :
vulnerable
bash: BASH_FUNC_x(): line 0: syntax error near unexpected token `)'
bash: BASH_FUNC_x(): line 0: `BASH_FUNC_x() () { :;}; echo vulnerable'
bash: error importing function definition for `BASH_FUNC_x'
test
teilweise (frühe Version) gepatchte Ausgabe :
bash: warning: x: ignoring function definition attempt
bash: error importing function definition for `x'
bash: error importing function definition for `BASH_FUNC_x()'
test
gepatchte Ausgabe bis einschließlich CVE-2014-7169:
bash: warning: x: ignoring function definition attempt
bash: error importing function definition for `BASH_FUNC_x'
test
EDIT 3 : Geschichte geht weiter mit:
bash
shellshock
vulnerability
jippie
quelle
quelle
vulnerable
in der Ausgabe erscheint. Das Hauptproblem ist, dass bash den Code auch nach der Funktionsdefinition analysiert und ausführt . Ein weiteres Beispiel finden Sie im/bin/id
Teil von seclists.org/oss-sec/2014/q3/650 .Antworten:
bash speichert exportierte Funktionsdefinitionen als Umgebungsvariablen. Exportierte Funktionen sehen folgendermaßen aus:
Das heißt, die Umgebungsvariable
foo
hat den wörtlichen Inhalt:Wenn eine neue Instanz von bash gestartet wird, sucht sie nach diesen speziell gestalteten Umgebungsvariablen und interpretiert sie als Funktionsdefinitionen. Sie können sogar selbst eines schreiben und sehen, dass es immer noch funktioniert:
Leider kann das Parsen von Funktionsdefinitionen aus Zeichenfolgen (den Umgebungsvariablen) umfassendere Auswirkungen haben als beabsichtigt. In ungepatchten Versionen werden auch beliebige Befehle interpretiert, die nach Beendigung der Funktionsdefinition auftreten. Dies ist auf unzureichende Einschränkungen bei der Bestimmung akzeptabler funktionsähnlicher Zeichenfolgen in der Umgebung zurückzuführen. Zum Beispiel:
Beachten Sie, dass das Echo außerhalb der Funktionsdefinition beim Bash-Start unerwartet ausgeführt wurde. 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 prüft die Umgebungsvariablen, stellt fest
foo
, wie sie die Bedingungen für das Aussehen einer Funktionsdefinition erfüllen, wertet die Zeile aus und führt versehentlich auch das Echo aus (bei dem es sich um einen beliebigen Befehl handeln kann, der böswillig ist oder nicht).Dies wird als unsicher angesehen, da Variablen normalerweise nicht von sich aus direkt den Aufruf von in ihnen enthaltenem willkürlichem Code auslösen dürfen oder sollen. Möglicherweise setzt Ihr Programm Umgebungsvariablen aus nicht vertrauenswürdigen Benutzereingaben. Es ist sehr unerwartet, dass diese Umgebungsvariablen so manipuliert werden können, dass der Benutzer beliebige Befehle ausführen kann, ohne dass Sie ausdrücklich beabsichtigen, diese Umgebungsvariable aus einem im Code angegebenen Grund zu verwenden.
Hier ist ein Beispiel für einen realisierbaren Angriff. Sie betreiben einen Webserver, auf dem eine anfällige Shell im Laufe ihrer Lebensdauer ausgeführt wird. Dieser Webserver übergibt Umgebungsvariablen an ein Bash-Skript. Wenn Sie beispielsweise CGI verwenden, werden häufig Informationen zur HTTP-Anforderung als Umgebungsvariablen vom Webserver einbezogen. Zum Beispiel
HTTP_USER_AGENT
könnte der Inhalt des User - Agent eingestellt werden. Dies bedeutet, dass, wenn Sie Ihren Benutzeragenten so fälschen, dass er wie '() {:; }; echo foo 'wird ausgeführt, wenn das Shell-Skriptecho foo
ausgeführt wird. Auch hierecho foo
könnte alles sein, bösartig oder nicht.quelle
export bar='() { echo "bar" ; }'; zsh -c bar
und es wirdbar
eher angezeigt alszsh:1: command not found: bar
? Sind Sie sicher, dass Sie die aufzurufende Shell nicht mit der Shell verwechseln, die Sie zum Einrichten des Tests verwenden?Dies kann hilfreich sein, um weiter zu demonstrieren, was los ist:
Wenn Sie eine anfällige Shell ausführen, werden Sie beim Starten einer neuen Subshell (hier einfach mithilfe der bash-Anweisung) feststellen, dass der beliebige Code (
echo "pwned"
) sofort im Rahmen seiner Initiierung ausgeführt wird. Anscheinend sieht die Shell, dass die Umgebungsvariable (Dummy) eine Funktionsdefinition enthält, und wertet die Definition aus, um diese Funktion in ihrer Umgebung zu definieren (beachten Sie, dass sie die Funktion nicht ausführt: das würde 'hi' ausgeben.)Leider wird nicht nur die Funktionsdefinition ausgewertet, sondern der gesamte Text des Werts der Umgebungsvariablen, einschließlich der möglicherweise schädlichen Anweisungen, die auf die Funktionsdefinition folgen. Beachten Sie, dass ohne die anfängliche Funktionsdefinition die Umgebungsvariable nicht ausgewertet wird, sondern lediglich als Textzeichenfolge zur Umgebung hinzugefügt wird. Wie Chris Down betonte, handelt es sich hierbei um einen bestimmten Mechanismus zum Implementieren des Imports exportierter Shell-Funktionen.
Wir können die Funktion sehen, die in der neuen Shell definiert wurde (und die dort als exportiert markiert wurde), und wir können sie ausführen. Außerdem wurde Dummy nicht als Textvariable importiert:
Weder die Erstellung dieser Funktion noch die Ausführung dieser Funktion ist Teil des Exploits - es ist nur das Fahrzeug, mit dem der Exploit ausgeführt wird. Der Punkt ist, dass wenn ein Angreifer bösartigen Code, dem eine minimale und unwichtige Funktionsdefinition vorausgeht, in einer Textzeichenfolge bereitstellen kann, die in eine exportierte Umgebungsvariable eingefügt wird, diese ausgeführt wird, wenn eine Subshell gestartet wird, was ein häufiges Ereignis ist in vielen Skripten. Außerdem wird es mit den Rechten des Skripts ausgeführt.
quelle
export
Befehl, während die anderen hattenenv
? Ich dachte,env
wird verwendet, um die Umgebungsvariablen zu definieren, die aufgerufen werden, wenn eine andere Bash-Shell gestartet wird. dann, wie funktioniert das mitexport
env
und für denexport
Export, sodass sie in einer Subshell verfügbar sind. Das Problem besteht tatsächlich darin, wie diese exportierten Definitionen in die Umgebung einer Subshell importiert werden, und insbesondere in dem Mechanismus, mit dem Funktionsdefinitionen importiert werden.env
führt einen Befehl aus, bei dem einige Optionen und Umgebungsvariablen festgelegt sind. Beachten Sie, dass in den ursprünglichenenv
Fragenbeispielenx
eine Zeichenfolge festgelegt undbash -c
mit einem auszuführenden Befehl aufgerufen wird. Wenn Sie dies tunenv x='foo' vim
, wird Vim gestartet, und Sie können dort die Shell / Umgebung aufrufen, mit der!echo $x
es ausgeführt wird, und es wird gedrucktfoo
. Wenn Sie dann und beendenecho $x
, wird es nicht definiert, da es nur existierte, während Vim ausgeführt wurde über denenv
Befehl. Derexport
Befehl legt stattdessen dauerhafte Werte in der aktuellen Umgebung fest, damit eine später ausgeführte Subshell diese verwendet.Ich schrieb dies als eine Wiederholung der hervorragenden Antwort von Chris Down im Stil eines Tutorials.
In bash können Sie solche Shell-Variablen haben
Standardmäßig werden diese Variablen nicht an untergeordnete Prozesse vererbt.
Wenn Sie sie jedoch für den Export markieren, setzt bash ein Flag, das bedeutet, dass sie in die Umgebung von Unterprozessen gelangen (obwohl der
envp
Parameter nicht sehr häufig angezeigt wird, hat dasmain
in Ihrem C-Programm drei Parameter:main(int argc, char *argv[], char *envp[])
wobei das letzte Zeigerarray ein Array ist von Shell-Variablen mit ihren Definitionen).Exportieren wir also
t
wie folgt:Während oben
t
in der Subshell undefiniert war, wird es jetzt angezeigt, nachdem wir es exportiert haben (verwendenexport -n t
Sie diese Option, wenn Sie den Export stoppen möchten).Aber Funktionen in der Bash sind ein anderes Tier. Sie erklären sie so:
Und jetzt können Sie die Funktion einfach aufrufen, indem Sie sie so aufrufen, als wäre es ein anderer Shell-Befehl:
Noch einmal, wenn Sie eine Subshell erzeugen, wird unsere Funktion nicht exportiert:
Wir können eine Funktion exportieren mit
export -f
:Hier ist der knifflige Teil: Eine exportierte Funktion wie
fn
wird in eine Umgebungsvariable konvertiert, genau wie unser Export der Shell-Variablent
oben war. Dies passiert nicht, wennfn
es sich um eine lokale Variable handelt, aber nach dem Export können wir sie als Shell-Variable sehen. Sie können jedoch auch eine reguläre (dh nicht funktionsfähige) Shell-Variable mit demselben Namen haben. bash unterscheidet anhand des Inhalts der Variablen:Jetzt können wir
env
alle für den Export markierten Shell-Variablen anzeigen und sowohl die regulärefn
als auch die Funktionfn
anzeigen:Eine Sub-Shell nimmt beide Definitionen auf: eine als reguläre Variable und eine als Funktion:
Sie können
fn
wie oben beschrieben oder direkt als reguläre Variablenzuweisung definieren:Beachten Sie, dass dies eine ungewöhnliche Sache ist! Normalerweise definieren wir die Funktion
fn
wie oben mit derfn() {...}
Syntax. Aber da bash es durch die Umgebung exportiert, können wir direkt zur oben genannten regulären Definition "abkürzen". Beachten Sie, dass dies (möglicherweise entgegen Ihrer Intuition) nicht zu einer neuen Funktionfn
in der aktuellen Shell führt. Aber wenn Sie eine ** sub ** Shell erzeugen, dann wird es.Brechen wir den Export der Funktion ab
fn
und lassen Sie die neue reguläre Funktionfn
(wie oben gezeigt) intakt.Jetzt wird die Funktion
fn
nicht mehr exportiert, sondern die reguläre Variablefn
ist, und sie enthält() { echo "direct" ; }
darin.Wenn eine Subshell nun eine reguläre Variable sieht, die damit beginnt
()
, interpretiert sie den Rest als Funktionsdefinition. Dies ist jedoch nur dann der Fall, wenn eine neue Shell beginnt. Wie wir oben gesehen haben,()
verhält sich eine reguläre Shell-Variable, die mit beginnt, nicht wie eine Funktion. Sie müssen eine Unterschale starten.Und jetzt der "Shellshock" Bug:
Wie wir gerade gesehen haben,
()
interpretiert eine neue Shell die Definition einer regulären Variablen, die damit beginnt , als Funktion. Wenn jedoch nach der schließenden Klammer, die die Funktion definiert, mehr angegeben ist, wird ausgeführt, was auch immer vorhanden ist.Dies sind noch einmal die Anforderungen:
In diesem Fall führt eine verwundbare Bash die letzteren Befehle aus.
Beispiel:
Die reguläre exportierte Variable
ex
wurde an die Subshell übergeben, die als Funktion interpretiert wurde, aber die nachfolgendenex
Befehle wurden ausgeführt (this is bad
), als die Subshell erzeugt wurde.Erklären Sie den glatten Einzeilentest
Ein beliebter Einzeiler zum Testen der Shellshock-Sicherheitsanfälligkeit ist der in @ jippies Frage genannte:
Hier ist eine Aufschlüsselung: Zuerst ist die
:
In-Bash nur eine Abkürzung fürtrue
.true
und:
beide bewerten zu (Sie haben es erraten) wahr, in bash:Zweitens gibt der
env
Befehl (der ebenfalls in bash integriert ist) die Umgebungsvariablen aus (wie wir oben gesehen haben), kann aber auch verwendet werden, um einen einzelnen Befehl mit einer exportierten Variablen (oder Variablen) auszuführen, die diesem Befehl zugewiesen wurde, undbash -c
führt dann einen einzelnen Befehl aus Befehlszeile:Wenn wir also all diese Dinge zusammennähen, können wir bash als Befehl ausführen, ihm eine Dummy-Aufgabe geben (wie
bash -c echo this is a test
) und eine Variable exportieren, die mit beginnt,()
sodass die Subshell sie als Funktion interpretiert. Wenn Shellshock vorhanden ist, werden auch alle nachfolgenden Befehle in der Subshell sofort ausgeführt. Da die übergebene Funktion für uns irrelevant ist (aber geparst werden muss!), Verwenden wir die kürzeste gültige Funktion, die man sich vorstellen kann:Die Funktion
f
hier führt nur den:
Befehl aus, der true zurückgibt und beendet wird. Hänge nun einen "bösen" Befehl an diesen an und exportiere eine reguläre Variable in eine Subshell und du gewinnst. Hier ist wieder der Einzeiler:Wird
x
also als reguläre Variable mit einer einfachen gültigen Funktion exportiertecho vulnerable
, die bis zum Ende angeheftet ist. Dies wird an bash übergeben und bash interpretiertx
als eine Funktion (die uns nicht interessiert) und führt dann möglicherweise das Kommandoecho vulnerable
if shellshock aus.Wir könnten den Einzeiler ein wenig verkürzen, indem wir die
this is a test
Nachricht entfernen :Dies stört nicht
this is a test
, führt aber den stillen:
Befehl erneut aus. (Wenn Sie das-c :
dann weglassen, sitzen Sie in der Unterschale und müssen manuell beenden.) Die vielleicht benutzerfreundlichste Version wäre diese:quelle
{ :;};
tatsächlich gesagt wird. Das wäre meiner Meinung nach eine schöne Ergänzung zu Ihrer Antwort. Können Sie erklären, wie Sie von Ihrem Beispiel zum ursprünglichen Befehl in der Frage kommen?Wenn Sie einem Programm beliebige Umgebungsvariablen hinzufügen können, können Sie dafür sorgen, dass es fast alles tut, indem es Bibliotheken Ihrer Wahl lädt. In den meisten Fällen wird dies nicht als Sicherheitsanfälligkeit für das Programm angesehen, das diese Umgebungsvariablen empfängt, sondern für den Mechanismus, mit dem ein Außenstehender beliebige Umgebungsvariablen einspeisen kann.
CVE-2014-6271 ist jedoch anders.
Es ist nichts Falsches daran, nicht vertrauenswürdige Daten in einer Umgebungsvariablen zu haben. Man muss nur sicherstellen, dass es nicht in eine dieser Umgebungsvariablen eingefügt wird, die das Verhalten des Programms ändern können. Etwas abstrakter ausgedrückt, können Sie für einen bestimmten Aufruf eine Whitelist mit Umgebungsvariablennamen erstellen, die von einem Außenstehenden direkt angegeben werden dürfen.
Ein Beispiel, das im Zusammenhang mit CVE-2014-6271 vorgestellt wurde, sind Skripte, die zum Parsen von Protokolldateien verwendet werden. Diese müssen möglicherweise sehr legitimerweise nicht vertrauenswürdige Daten in Umgebungsvariablen weitergeben. Natürlich wird der Name für eine solche Umgebungsvariable so gewählt, dass er keine nachteiligen Auswirkungen hat.
Aber hier ist, was an dieser besonderen Bash-Schwachstelle schlimm ist. Es kann über einen beliebigen Variablennamen ausgenutzt werden. Wenn Sie eine Umgebungsvariable mit dem Namen erstellen
GET_REQUEST_TO_BE_PROCESSED_BY_MY_SCRIPT
, würden Sie nicht erwarten, dass ein anderes Programm als Ihr eigenes Skript den Inhalt dieser Umgebungsvariablen interpretiert. Durch die Ausnutzung dieses Bash-Fehlers wird jedoch jede einzelne Umgebungsvariable zu einem Angriffsvektor.Beachten Sie, dass dies nicht bedeutet, dass die Namen von Umgebungsvariablen geheim sein müssen. Wenn Sie die Namen der beteiligten Umgebungsvariablen kennen, wird ein Angriff nicht einfacher.
Wenn
program1
Aufrufe,program2
die ihrerseits aufrufenprogram3
,program1
Datenprogram3
über Umgebungsvariablen weiterleiten könnten . Jedes Programm hat eine spezifische Liste von Umgebungsvariablen, die es setzt, und eine spezifische Liste, auf die es einwirkt. Wenn Sie einen Namen gewählt haben, der nicht von erkannt wirdprogram2
, können Sie Daten vonprogram1
an weitergeben,program3
ohne sich darüber Gedanken machen zu müssen, ob dies nachteilige Auswirkungen hatprogram2
.Ein Angreifer, der die genauen Namen der von exportierten Variablen
program1
und die Namen der von interpretierten Variablenprogram2
kennt, kann dieses Wissen nicht ausnutzen, um das Verhalten von "program2" zu ändern, wenn sich die Namen nicht überschneiden.Aber dies
program2
war einbash
Skript, weil aufgrund dieses Fehlersbash
jede Umgebungsvariable als Code interpretiert wurde.quelle
Es wird in dem Artikel erklärt, den Sie verlinkt haben ...
Das heißt, die Bash, die mit aufgerufen wird,
-c "echo this is a test"
führt den Code in einfachen Anführungszeichen aus, wenn er aufgerufen wird.In dem von Ihnen veröffentlichten Codebeispiel wird die Tatsache ausgenutzt, dass die aufgerufene Bash die Auswertung dieser Zeichenfolge nach der Ausführung der Zuweisung nicht beendet. Eine Funktionszuweisung in diesem Fall.
Das Besondere an dem von Ihnen veröffentlichten Code-Snippet ist meines Wissens, dass durch die Verwendung einer Funktionsdefinition vor dem Code, den wir ausführen möchten, einige Sicherheitsmechanismen umgangen werden können.
quelle