eval - nutzbar für sandbox?

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
jtk
User
Beiträge: 37
Registriert: Montag 19. November 2007, 17:16

Hallo

kann man mit folgendem code eine Sandbox für einen Funktionsaufruf bauen?

Code: Alles auswählen

import __builtin__
erlaubt={
 # funktionen, die aufgerufen werden dürfen
}
blocker={} # wird mit überschribungen für alle builtin werte gefüllt
for b in dir(__builtin__):
    blocker[b]=None   # oder irgnedein andere dummy-wert

try:
    eval("irgendeine_Funktion('Was auch immer')",blocker,blocker)
except:
    .... Fehler Abfangen ...
Ist das sicher, das damit nichts das hauptprogrammmanipuliert?
ich möchte objektstrukturen abspeichern und dies in form von Python Code (dictionarys, listen, Konstruktoren mit schlüsselwortargumenten) tun, um nicht so viel parserei zu haben,
aber möchte nicht, dass eine manipulierte datei irgendetwas ausführen kann
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Solange man auf ein Objekt zugreifen kann, kann man sich ueber die mro oder __bases__ zu object durchhangeln und von dort mit __subclasses__ auf so ziemlich alles zugreifen und jede Menge Schaden anrichten.
lunar

@jtk: "eval()" ist nicht sicher, selbst wenn man den Namensraum strikt kontrolliert. Reichen einfache Literalformen für Deine Zwecke aus, so kannst Du "ast.literal_eval()" nutzen. Andernfalls musst Du den Quelltext mithilfe des "ast"-Moduls parsen und den generierten Syntaxbaum anschließend manuell auswerten, wobei Du nur eine zu definierende, „sichere“ Untermenge an Anweisungen und Ausdrücken zulässt.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Vielleicht hilft dir da auch dieer Thread weiter; da gibt es ein Beispiel für das Nutzen von ast: http://python-forum.de/viewtopic.php?f= ... al+sandbox
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
jtk
User
Beiträge: 37
Registriert: Montag 19. November 2007, 17:16

Danke, ich werds mir mal anschauen!
jtk
User
Beiträge: 37
Registriert: Montag 19. November 2007, 17:16

in der docu für marshal steht, das dies unsicher sei (http://docs.python.org/library/marshal. ... le-marshal) - inwiefern?
lunar

@jtk: Da die Dokumentation darüber keine genaueren Angaben macht, musst Du die Implementierung dieses Moduls zu Rate ziehen. Ins Blaue geraten vermute ich, dass die Implementierung Eingabedaten nicht auf Gültigkeit prüft und somit bei ungültigen Daten anfällig für Pufferüberläufe oder ähnliches ist.
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:


GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
Defnull
User
Beiträge: 778
Registriert: Donnerstag 18. Juni 2009, 22:09
Wohnort: Göttingen
Kontaktdaten:

Marshal kann auch Code-Objekte abbilden und damit beliebigen Python Code enthalten. Darüber hinaus wird es beim Einlesen nur grob auf Fehler überprüft. In der Vergangenheit gab es haufenweise Bugs, die bei kaputtem marschal input zu abstürzen oder undefinierten Verhalten geführt haben. Das gleiche gilt übrigens für Pickle.

Ich würde die Daten entweder kryptographisch signieren, oder ein sichereres Format wählen (json, YAML, XML).
Bottle: Micro Web Framework + Development Blog
lunar

@Defnull: Wo genau ist das Problem darin, dass "marshal" Code-Objekte abbilden kann? Der Code wird schließlich beim Laden nicht ausgeführt.
Benutzeravatar
Defnull
User
Beiträge: 778
Registriert: Donnerstag 18. Juni 2009, 22:09
Wohnort: Göttingen
Kontaktdaten:

lunar hat geschrieben:@Defnull: Wo genau ist das Problem darin, dass "marshal" Code-Objekte abbilden kann? Der Code wird schließlich beim Laden nicht ausgeführt.
Während Pickle nur Instanzen von existierenden Klassen erzeugt, kann marshal auch neuen Code einschleusen. Sobald du irgend etwas mit den Daten machst, werden Methoden wie __getattr__, __eq__ und co ausgeführt. Die Code-Objekte von Funktionen sind austauschbar.
Bottle: Micro Web Framework + Development Blog
lunar

@Defnull: Verzeihe mir, doch ich sehe da noch immer kein Problem. Man hat dann nach "marshal.load()" eben ein Code-Objekt oder eine Liste derselben. Ja und? Dieses Code-Objekt ist ja per se nicht böse, sondern müsste erst einmal ausgeführt werden. Von selbst geschieht das nun allerdings nicht, es müsste im Quelltext zum Laden ja etwas der Art "foo.func_code = evil_code_object_from_marshal" stehen und das ist dann keine Unsicherheit in "marshal", sondern ein Fehler im Programm, welches Marshal nutzt.
jtk
User
Beiträge: 37
Registriert: Montag 19. November 2007, 17:16

ok Danke ich komm wohl doch nicht drum herum, auf eunen "echten" prser zu nehmen - hatte ich beführchtet!
lunar

@jtk: Du benötigst keinen eigenen Parser, sondern kannst auf das "ast"-Modul aufsetzen. Lediglich die Auswertung der Ausdrücke musst Du anschließend selbst implementieren, aber das ist nicht allzu schwer.
Benutzeravatar
Defnull
User
Beiträge: 778
Registriert: Donnerstag 18. Juni 2009, 22:09
Wohnort: Göttingen
Kontaktdaten:

lunar hat geschrieben:@Defnull: Verzeihe mir, doch ich sehe da noch immer kein Problem. Man hat dann nach "marshal.load()" eben ein Code-Objekt oder eine Liste derselben. Ja und? Dieses Code-Objekt ist ja per se nicht böse, sondern müsste erst einmal ausgeführt werden. Von selbst geschieht das nun allerdings nicht, es müsste im Quelltext zum Laden ja etwas der Art "foo.func_code = evil_code_object_from_marshal" stehen und das ist dann keine Unsicherheit in "marshal", sondern ein Fehler im Programm, welches Marshal nutzt.
Du willst mit den Daten ja irgend etwas machen, nachdem du sie geladen hast, oder? Stell dir vor, du möchtest eine Liste aus der Datei laden. Stattdessen bekommst du ein Objekt, das __getitem__ implementiert und darin Schadcode ausführt. Oder __subclasscheck_ oder __instancecheck__.
Bottle: Micro Web Framework + Development Blog
lunar

@Defnull: Laut Dokumentation funktioniert das nicht, da marshal nur bestimmte Typen unterstützt:
Not all Python object types are supported; …[…]. The following types are supported: booleans, integers, long integers, floating point numbers, complex numbers, strings, Unicode objects, tuples, lists, sets, frozensets, dictionaries, and code objects […]
Schlimmstenfalls also erhält man ein Code-Objekt selbst, aber niemals ein Objekt beliebigen Typs, dessen Methoden beliebige Code-Objekte haben. Anders gesagt, das marshal-Format kann keine Objekte mit beliebigen Methoden ala "Unterklasse von list mit bösen __getitem__()" beschreiben. Es beschreibt nur Code-Objekte selbst, man müsste das Code-Objekt also nachträglich manuell an eine Methode oder Funktion hängen, und das wird kaum jemand bei Verstand machen.
ms4py
User
Beiträge: 1178
Registriert: Montag 19. Januar 2009, 09:37

Pickle ist ebenfalls ziemlich gefährlich, was das Ausführen von Code betrifft. Hier ist man nur mit einer modifizierten `pickle.loads` auf der sicheren Seite, s. http://docs.python.org/py3k/library/pic ... ng-globals.
„Lieber von den Richtigen kritisiert als von den Falschen gelobt werden.“
Gerhard Kocher

http://ms4py.org/
Benutzeravatar
Defnull
User
Beiträge: 778
Registriert: Donnerstag 18. Juni 2009, 22:09
Wohnort: Göttingen
Kontaktdaten:

lunar hat geschrieben:Anders gesagt, das marshal-Format kann keine Objekte mit beliebigen Methoden ala "Unterklasse von list mit bösen __getitem__()" beschreiben.
Stimmt. Das hatte ich anders im Gedächtnis. Unabhängig davon gilt marshal und Pickle aber nach wie vor als unsicher.
Bottle: Micro Web Framework + Development Blog
Antworten