* David Haller schrieb am 19.Jul.2001:
On Don, 19 Jul 2001, Bernd Brodesser wrote:
* David Haller schrieb am 18.Jul.2001:
On Mit, 18 Jul 2001, Bernd Brodesser wrote:
* David Haller schrieb am 18.Jul.2001: [..]
$ mktemp /root/${prg}.$$.XXXXXX Cannot create temp file /root/.12760.YTRUBd
Ich mache meine Fehlermeldung lieber selber. Was soll der Endanwender mit obiger Meldung anfangen?
Du weisst ja auch nix genaues (Rechte, Disk voll, uebergeordnetes Verz. existiert nicht)... Du weisst du dass es nicht geklappt hat (mkstemp liefert nur 1 als exit-status).
Das ist richtig. Aber wenn ich mktemp in einer Anwendung benutze, die wiederum von einem anderen Skript benutzt wird, dann kann der Endanwender nichts damit anfangen, daß mktemp nicht funktioniert. Welches mktemp?
mktemp(1).
;) Aber der User versteht es nicht. Der braucht keine man-pages zu kennen.
Cannot create temp file /root/test.YTRUBd: Permission denied
Wenn das so manchen User vorgelegt wird, dann weigert er sich noch weiter an diesem Rechner zu arbeiten, bis ein Geisterbeschwörer die Tastatur und den Bildschirm ausgependelt hat und bestätigt hat, daß eine weitere Benutzung des Rechners nicht notwendig einen Weltkrieg auslöst. "Was soll YTRUBd sein, und wie ließt man das?"
Ich erwarte von mktemp, daß wenn es feststellt, daß der von ihm gewählten Namen schon existiert, einfach einen anderen nimmt. Solange bis es einen gefunden hat.
Genau _das_, das alternativen testen, macht keine der Funktionen (bzw. mktemp(1)). Darum muss man sich selbst kuemmern. z.B. in der bash mit:
Dann ist das aber ein Gewaltiger Rückschritt. Wenn ich mich Recht erinnere und nicht völlig daneben liege, hat das eine HP_UX-Kiste genau so gemacht. Hatte ich mal durchgetestet. Da hat er Anstelle von a$$ eben b$$ geschrieben.
while ! tmpfile=`mktemp vorlage.XXXXXX`; do : ; done
(ggfs. noch mit nem schleifenzaehler um irgendwann abzubrechen).
Das "sicher" bezieht auf die Vorhersagbarkeit...
Was ist schlimm an Vorhersagbarkeit? Was ich will ist Einzigartigkeit. Das ist wichtig. Wenn ich eine Datei temp1 nenne, die nächste temp2 usw. so ist das absolut vorhersehbar, aber es ist Einzigartig, genau das was ich will. Allerdings müßten alle Programme, die temporäre Dateien benutzen dieses Schema benutzen.
Das hat mir Wolfgang mal erklaert hat (IIRC im Zusammenhang mit meine "toggle-a-attr", das IIRC anfangs auch ueber die Liste ging)... (s.u.)
Wolfgang koennte zu den Folgen der (von mir vermuteten Vorhersagbarkeit) noch einiges mehr sagen...
Aber wie gesagt, ich denke, dass die (Nicht-)Vorhersagbarkeit von __gen_tempname (und somit von mkstemp(3) und mktemp(1)) fuer die meisten Faelle ausreicht (also schwierig genug ist)...
Ich verstehe immer noch nicht, was da so schlimm dran sein soll. Was kann der Angreifer machen, wenn er weiß, wie die nächste temporäre Datei heißt? Er darf natürlich von Anfang an keine Schreibrechte darauf haben. Am Besten auch keine Leserechte. Wenn diese Datei schon existiert, wird sie nicht angelegt, sondern ein anderen Namen gewählt. Also kann der Angreifer da auch keine Fallen aufbauen. Habe ich da was übersehen?
Ja. Reingefallen. Wie ich auch... :)
Ein Szenario folgt (das aber, wie ich schrieb, fuer die meisten Faelle wenig bis nicht relevant ist, aber wir reden hier ja inzwischen um's Prinzip, oder?
Ja.
Darueber, dass mktemp in der Praxis (fast) immer ausreicht sind wie uns glaub einig...)
Ja, obwohl wenn das blöde Teil noch nicht mal testet.
Ach ja, ob und wie man das genannte Problem "remote" ausnuezten koennte weiss ich nicht, Wolfgang wuesste da mehr, aber es waere AFAIK moeglich sich als lokaler user (und somit ggfs. via einem solchen auch remote) mit root-Rechten zu agieren (oder sogar diese zu erlangen?)
gehen wir von local aus. Das ein remote-Angreifer zuerst versucht sich als User einzuloggen ist klar.
Vielleicht den kurzen Moment, der vom Test auf Existenz bis zur tatsächlichen Anlegung vergeht? Aber das Problem habe ich immer.
Ja. So in etwa....
- Angreifer erlangt "user-Rechte" auf einer Kiste (egal wie).
- A macht einen benchmark auf die Verzoegerung zwischen Aufruf von mktemp(1) und dem __gettimeofday [1] in __gen_tempname. Je ungenauer die tatsaechliche "Zeitaufloesung" auf der HW ist (in Bezug zu den Mikrosekunden die in __gen_tempname verwendet werde), umso einfacher wird IMO der Angriff.
- A schreibt einen exploit, der anhand der Voraussage der Latenz zwischen dem mktemp Aufruf und dem __gettimeofday sehr vereinfacht wird, und der (millonenfach) versucht die Ausgabe des __gettimeofday vorherzusagen.
- hat A einen "Treffer" erzielt ist die PID (via dem __getpid [2]) trivial. Aus diesen Daten kann die Ausgabe von __gen_tempname vorhergesagt werden.
Lassen wir das doch mal weg. Angenommen er kennt den Namen exakt.
(Wobei die laenger dauernden Funktionen wie evtl. getpid natuerlich passen vorverlagert werden muessen)
- A kann also mit einer hinreichenden Genauigkeit "voraussagen" was mktemp generieren wird (beim naechsten Aufruf generieren wuerde).
Nehmen wir an er weiß es genau.
- A "weiss" den Namen der tempdatei bevor es der legitime Nutzer weiss.
Ja, das nehmen wir an.
- Zwei Moeglichkeiten:
a) mktemp kann von A mit dem Parameter -u aufgerufen werden, der die tempdatei unlinkt (man 2 unlink). => ln -sf /etc/passwd tempfile und mktemp loescht fuer A /etc/passwd, dass A dann ganz nach Geschmack neu anlegen kann, oder wenn /etc/ passende Rechte hat, ist /etc/passwd auch nur einfach weg.
b) A klinkt sich mit einem aehnlichen Angriff "mittenrein" in mktemp(1)/mkstemp(3)/__gen_tempname und kann ebenfalls beliebige Dateien so verlinken, dass er die Rechte daran hat (die Details weiss ich leider nicht mehr, bin mir aber recht sicher, dass das gehen wuerde).
Insgesamt ergibt sich, dass __gen_tempname (und somit mkstemp(3), mktemp(1), und mehr noch mktemp(3)) nicht wirklich "sicher" sind, auch wenn diese Sicherheit wohl fuer die meisten Faelle in der Praxis ausreicht.
Ich sehe das Problem darin, daß jeder in tmp schreiben darf. Dann wäre es doch besser, wenn /tmp root gehört mit den Rechten 755 und für jeden User gibt es ein eigenes Unterverzeichnis, daß ihm gehört, und wo er hineinschreiben darf. Das wäre dann eine vernünftige Lösung. Wie sollte man dann sonst eine Interprozeßkommunikation, über verschiedene Prozesse hinweg, mittels Dateien gestalten? Da müssen doch beide Prozesse wissen, wie der Dateiname heißt.
Kurz und gut: Die Sicherheit von __gen_tempname (und abegeleitete) beruht auf der Vorhersagbarkeit von __gettimeofday(), und die _ist_ vorherzusagen...
Wenn du das mit den Kommentaren am Anfang von /usr/src/linux/drivers/char/random.c vergleichst, insbesondere, welche wesentlich zufaelligeren Datenquellen im Vergleich zu __gettimeofday verwendet werden, wirst du sehen, dass das _vergleichsweise_ unsicher ist (auch wenn es fuer die meisten _praktischen_ Faelle ausreichen sollte.
Ein "sicheres" __gen_tempname wuerde also nicht 64 bit aus __gettimeofday + PID sondern 64 bit aus /dev/random verwenden,
ACK
das u.a. Tastatur(Taste, Zeitpunkt), Maus (Position, Klicks, Zeitpunkt), HD (Zeit von IO ops), IRQs (Zeitpunkt) allgemein verwendet und mit (wenn nicht) der beste Zufallsgenerator auf PCs ist.
Und nur, damit keine Missverstaendnisse aufkommen: Fuer (fast) alle praktischen Anwendungen ist __gen_tempname (also auch mkstemp und mktemp) sicher genug! Und auch die zeitliche Aufloesung von __gettimeofday sollte fuer (fast) alle Anwendungen "reichen" um zusaetzliche Sicherheit zu gewaehrleisten.
Leider bin ich weder in C noch in der Kryptographie bewandert genung um auch nur eine Abschaetzung der Sicherheit (d.h. des Aufwandes, um z.B. oben skizzierten Angriff durchzufuehren) zu wagen...
Um nochmal zusammenzufassen:
Die (pauschale(!!!)) Aussage __gen_tempname (und somit mkstemp(3) und somit mktemp(1)) sei "sicher" ist falsch!
Die Aussage __gen_tempname sei sicher _genug_ fuer *fast* alle Anwendungen ist IMO richtig!
Und nochmal: Die "Eindeutigkeit" des erzeugten Muster ist mit 62^6 IMO gut genug, die "Schwaeche" ist die Vorhersagbarkeit des Ergebnisses (egal in welcher Stufe, sei's noch innerhalb von __gen_tempname, sei's in mkstemp(3) oder sei's in mktemp(1)).
Die "Guete" von 62^6 ist aber nur gleichzusetzen mit einer "Schluessel- laenge" x von 35 bit < x < 36 Bit... Und das ist heutzutage kein Problem.
Doch, denn Du hast nur ein paar Nanosekunden Zeit, wenn ich es richtig sehe.
Und da gettimeofday quasi fuer jeden beliebigen Zeitpunkt im Voraus(!)[3] berechnet werden kann (und die PID ein "piece of cake" ist)...
Hmm. Sowenig das ganze mit der Praxis zu tun haben mag (das kann und will ich nicht beurteilen, ich bin kein Hacker und erst recht kein Cracker), so hoffe ich doch, das "blinde" Vertrauen erschuettert zu haben und, wie Wolfgang es bei mir in Sachen Race-Conditions etc. generell tat, auch bei dir (und anderen?) ein gewisses, gesundes Misstrauen und vielleicht auch Interesse an der Problematik geweckt zu haben.
Ja, klar fuer die 08/15 Kiste ist sogar mktemp vielleicht schon overkill, aber fuer Rechner, die sicher sein muessen, ist IMO eine bessere Version von mkstemp (s.o., mit /dev/random) zu verwenden...
Und ja, auf solchen Kisten, sollte man wohl die GNU libc sowieso nicht verwenden ;)
-dnh
P.S: Ja, das "clever" in __gen_tempname hat mich stutzig gemacht...
PPS: Nein, ich bin kein Sicherheitsfetischist, ich hab weder eine Firewall am laufen noch einen aktuellen PGP/GPG Key...
Dann schreib es nicht auch noch in einer öffentlichen Liste. ;) Bernd -- Homepages von deutschsprachigen Linux-Gurus: Kristian Köhntopp: http://www.koehntopp.de/kris/artikel/ Sven Guckes: http://www.math.fu-berlin.de/~guckes/sven Robin S Socha: http://socha.net/index2.html |Zufallssignatur 10