System-config-firewall: Python Pickle intrinsisch unsicher
Ende Juni 2011 hat Marco Slaviero eine Sicherheitslücke in Red Hats Tool "system-config-firewall" gemeldet. Die Software bietet ein GUI zum Aufsetzen von Firewall-Regeln.
System-config-firewall stellt auch ein D-Bus-Interface bereit. Das GUI nutzt diese Schnittstelle, um mit dem Backend zum eigentlichen Setzen der Firewall-Regeln via IPC zu kommunizieren. Das Backend ist in "system-config-firewall-mechanism.py" untergebracht, das notwendigerweise mit Root-Rechten läuft. Der Datenverkehr über D-Bus besteht dabei aus zuvor vom GUI serialisierten Objekten, die das Backend dann de-serialisiert und auswertet. Da Python verwendet wird, kommt hierbei das Modul "pickle" zum Einsatz.
Allerdings haben die Entwickler nicht beachtet, dass das Pickle-Verfahren sehr unsicher ist. Dadurch ist es für einen lokalen Angreifer möglich, auf betroffenen Systemen Befehle mit Root-Rechten auszuführen. Allerdings benötigt der Angreifer für eine Attacke die Berechtigung, die Firewall zu konfigurieren. Details zur Sicherheitslücke sollen am 4. August 2011 auf der Blackhat-Konferenz in einem allgemeinen Vortrag zur Pickle-Sicherheit vorgestellt werden. Es ist aber nicht anzunehmen, dass dort großartige neue Einsichten zur Pickle-Sicherheit präsentiert werden, denn die Sicherheitsmängel des Moduls sind schon länger bekannt.
Hintergründe zu Pickle-Sicherheit
Auch wenn noch keine Details öffentlich bekannt sind, handelt es bei der Schwachstelle höchstwahrscheinlich um ein Standardproblem beim Verwenden von Pickle: Das Python-Modul "pickle" und dessen schnellere C-Variante cPickle erledigen das Kodieren und Dekodieren von Python-Objekten in Byte-Streams. Obwohl es zur Serialisierung von Python-Objekten auch das Modul "marshal Modul" gibt, ist Pickle in der Regel vorzuziehen, da Marshal deutlich begrenzter ist. Ist ein Objekt erst einmal in einen Byte-Stream umgewandelt, lässt es sich in einer Datei speichern, zu einem anderen Prozess schicken oder über ein Netzwerk verschicken. Grundsätzlich kann Pickle die Attribute jedes Python-Objektes serialisieren - Klassen, Funktionen und Methoden allerdings nicht. Im Falle eines Objekts wird also die Klasse selbst nicht serialisiert, und es wird im Byte-Stream lediglich die Klasse des Objekts vermerkt. Das Pickle-Format ist Python-spezifisch und besteht gewöhnlich aus Ascii-Text (Format 0). Allerdings ist es auch möglich, das Ganze binär abzuwickeln was etwas kompakter ist (Format 1 und höher).
Das Verfahren ist am einfachsten anhand eines Beispiels zu verstehen: Die folgende Datei "hello.py" enthält die Klasse des zu serialisierenden Objekts:
class Hello:
def __init__(self, name):
self.name=name
def message(self):
print "Hello:",self.name
Neben einem Konstruktor und einer Message-Methode enthält diese Klasse nichts weiter. Dem Konstruktor wird ein Name übergeben, der dann von "message" ausgegeben wird. Der folgende Code erzeugt eine Instanz dieser Klasse und schreibt diese via Pickle in die Datei "object.dat":
import pickle
import hello
hello=hello.Hello("Tux")
outfile = open('object.dat', 'wb')
pickle.dump(hello, outfile)
outfile.close()
Hier wird unter anderem der in "self.name" abgelegte String "Tux" in "object.dat" gepackt. Anschließend lässt sich diese Instanz mit der Methode "pickle.load()" wieder rekonstruieren:
import pickle
import hello
infile = open('object.dat', 'rb')
hello=pickle.load(infile)
infile.close()
hello.message()
Die am Ende aufgerufene "hello(")-Methode zeigt dann korrekt "Hello: Tux" an. Es ist hier zu beachten, dass auch der Code zum Auspacken der Pickle-Datei "hello.py" importieren muss, da ja die Klasse selbst nicht serialisiert wird. Ohne diesen Import würde Python sich beschweren, dass es die Hello-Klasse nicht kennt.
Auf den offiziellen Pickle-Seiten wird eindrücklich darauf hingewiesen, dass das Pickle-Modul keinerlei Sicherheitsmaßnahmen implementiert: Ein via Netzwerk versendetes Objekt wird ohne große Kontrolle einfach de-serialisiert. Allerdings ist die Gefahr hierbei deutlich größer als man vermuten würde: Nicht nur, dass einem Anwender falsche Instanzen untergejubelt werden können - es ist in solchen Szenarien sogar möglich, Befehle mit höheren Berechtigungen auszuführen.
Ein einfaches Beispiel hierfür sieht so aus:
import pickle
pickle.loads("cos\nsystem\n(S'ls ~'\ntR.")
Die Methode "loads()" de-serialisiert den übergebenen String zu "os.system('ls ~')" und zeigt damit den Inhalt des Home-Verzeichnisses an. Intern verwendet Pickle eine Stack-basierte virtuelle Maschine mit einfachen Opcodes, um aus serialisierten Daten wieder Objekte herzustellen. Das Modul "pickletools" enthält einen Disassembler, der diesen Prozess transparenter macht:
import pickletools
print pickletools.dis("cos\nsystem\n(S'ls ~'\ntR.")
Dieser liefert dann folgende Zeilen:
0: c GLOBAL 'os system'
11: ( MARK
12: S STRING 'ls ~'
20: t TUPLE (MARK at 11)
21: R REDUCE
22: . STOP
Die Reduce-Anweisung instanziiert dabei das Objekt der Klasse. Auf ähnliche Weise lässt sich mit Pickle auch ein Objekt kodieren, welches eine Shell öffnet. Diese einfachen Beipiele zeigen, dass es kritisch sein kann, Pickle in einer ungesicherten Umgebung zu verwenden. Diese Art der Serialisierung ist intrinsisch unsicher, und die Python-Dokumentation weist darauf mit Nachdruck hin. Vermutlich handelt es sich bei System-config-firewall um eine ähnliche Schwachstelle.
Eine Möglichkeit, ein derartiges Angriffsszenario zu vermeiden, besteht darin, eine neue Unpickler-Klasse von "pickle.Unpickler" abzuleiten und darin die Methode "find_class()" so zu überschreiben, dass Module gegen eine Whitelist geprüft werden, bevor die Objekte erzeugt werden.
Natürlich gibt es auch Alternativen zu dem Python-spezifischen Pickle-Format, beispielsweise die Javascript Object Notation (JSON). Wikipedia liefert einen guten Überblick über verschiedene Serialisierungsverfahren und -formate.
Alle Rezensionen aus dem Linux-Magazin
- Buecher/07 Bücher über 3-D-Programmierung sowie die Sprache Dart
- Buecher/06 Bücher über Map-Reduce und über die Sprache Erlang
- Buecher/05 Bücher über Scala und über Suchmaschinen-Optimierung
- Buecher/04 Bücher über Metasploit sowie über Erlang/OTP
- Buecher/03 Bücher über die LPI-Level-2-Zertifizierung
- Buecher/02 Bücher über Node.js und über nebenläufige Programmierung
- Buecher/01 Bücher über Linux-HA sowie über PHP-Webprogrammierung
- Buecher/12 Bücher über HTML-5-Apps sowie Computer Vision mit Python
- Buecher/11 Bücher über Statistik sowie über C++-Metaprogrammierung
- Buecher/10 Bücher zu PHP-Webbots sowie zur Emacs-Programmierung
Insecurity Bulletin
Im Insecurity Bulletin widmet sich Mark Vogelsberger aktuellen Sicherheitslücken sowie Hintergründen und Security-Grundlagen. mehr...


