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
$ t="hi there"
$ echo $t
hi there
$
Standardmäßig werden diese Variablen nicht an untergeordnete Prozesse vererbt.
$ bash
$ echo $t
$ exit
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 envpParameter nicht sehr häufig angezeigt wird, hat das mainin 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 twie folgt:
$ echo $t
hi there
$ export t
$ bash
$ echo $t
hi there
$ exit
Während oben tin der Subshell undefiniert war, wird es jetzt angezeigt, nachdem wir es exportiert haben (verwenden export -n tSie diese Option, wenn Sie den Export stoppen möchten).
Aber Funktionen in der Bash sind ein anderes Tier. Sie erklären sie so:
$ fn() { echo "test"; }
Und jetzt können Sie die Funktion einfach aufrufen, indem Sie sie so aufrufen, als wäre es ein anderer Shell-Befehl:
$ fn
test
$
Noch einmal, wenn Sie eine Subshell erzeugen, wird unsere Funktion nicht exportiert:
$ bash
$ fn
fn: command not found
$ exit
Wir können eine Funktion exportieren mit export -f:
$ export -f fn
$ bash
$ fn
test
$ exit
Hier ist der knifflige Teil: Eine exportierte Funktion wie fnwird in eine Umgebungsvariable konvertiert, genau wie unser Export der Shell-Variablen toben war. Dies passiert nicht, wenn fnes 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:
$ echo $fn
$ # See, nothing was there
$ export fn=regular
$ echo $fn
regular
$
Jetzt können wir envalle für den Export markierten Shell-Variablen anzeigen und sowohl die reguläre fnals auch die Funktion fnanzeigen:
$ env
.
.
.
fn=regular
fn=() { echo "test"
}
$
Eine Sub-Shell nimmt beide Definitionen auf: eine als reguläre Variable und eine als Funktion:
$ bash
$ echo $fn
regular
$ fn
test
$ exit
Sie können fnwie oben beschrieben oder direkt als reguläre Variablenzuweisung definieren:
$ fn='() { echo "direct" ; }'
Beachten Sie, dass dies eine ungewöhnliche Sache ist! Normalerweise definieren wir die Funktion fnwie oben mit der fn() {...}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 Funktion fnin der aktuellen Shell führt. Aber wenn Sie eine ** sub ** Shell erzeugen, dann wird es.
Brechen wir den Export der Funktion ab fnund lassen Sie die neue reguläre Funktion fn(wie oben gezeigt) intakt.
$ export -nf fn
Jetzt wird die Funktion fnnicht mehr exportiert, sondern die reguläre Variable fnist, 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:
- Neue Bash wird erzeugt
- Eine Umgebungsvariable wird aufgenommen
- Diese Umgebungsvariable beginnt mit "()" und enthält dann einen Funktionskörper in geschweiften Klammern und hat danach Befehle
In diesem Fall führt eine verwundbare Bash die letzteren Befehle aus.
Beispiel:
$ export ex='() { echo "function ex" ; }; echo "this is bad"; '
$ bash
this is bad
$ ex
function ex
$
Die reguläre exportierte Variable exwurde an die Subshell übergeben, die als Funktion interpretiert wurde, aber die nachfolgenden exBefehle 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:
env x='() { :;}; echo vulnerable' bash -c "echo this is a test"
Hier ist eine Aufschlüsselung: Zuerst ist die :In-Bash nur eine Abkürzung für true. trueund :beide bewerten zu (Sie haben es erraten) wahr, in bash:
$ if true; then echo yes; fi
yes
$ if :; then echo yes; fi
yes
$
Zweitens gibt der envBefehl (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, und bash -cführt dann einen einzelnen Befehl aus Befehlszeile:
$ bash -c 'echo hi'
hi
$ bash -c 'echo $t'
$ env t=exported bash -c 'echo $t'
exported
$
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:
$ f() { :;}
$ f
$
Die Funktion fhier 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:
$ env x='() { :;}; echo vulnerable' bash -c "echo this is a test"
Wird xalso als reguläre Variable mit einer einfachen gültigen Funktion exportiert echo vulnerable, die bis zum Ende angeheftet ist. Dies wird an bash übergeben und bash interpretiert xals eine Funktion (die uns nicht interessiert) und führt dann möglicherweise das Kommando echo vulnerableif shellshock aus.
Wir könnten den Einzeiler ein wenig verkürzen, indem wir die this is a testNachricht entfernen :
$ env x='() { :;}; echo vulnerable' bash -c :
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:
$ env x='() { :;}; echo vulnerable' bash -c "echo If you see the word vulnerable above, you are vulnerable to shellshock"