PHPGangsta - Der praktische PHP Blog

PHP Blog von PHPGangsta


Gefährliche PHP-Funktionen ausschalten

with 23 comments

PHP ist mächtig, man kann nahezu alles umsetzen, zur Not auch mit Zugriff auf die Kommandozeile. Doch die Macht hat auch immer eine böse Seite, sie kann missbraucht werden. Nicht nur auf shared Webservern sollte man aus Sicherheitsgründen einige Funktionen ausschalten, auch auf einem einzelnen Server, auf der nur die eigene Webseite liegt, sollten die gefährlichsten Funktionen im Normalfall abgeschaltet werden (können). Falls ein Eindringling es schafft, eigenen PHP-Code hochzuladen, wäre er sehr eingeschränkt in seinen Möglichkeiten, viel kaputt zu machen, Daten auszuspähen oder sonstige böse Sachen auf unserem Server zu veranstalten.

Natürlich gibt es noch viele weitere Sicherheitsmaßnahmen, die man ergreifen sollte. Der Safe-Mode wird ja bald abgeschafft, kann und sollte also nicht mehr genutzt werden. Stattdessen sollten open_basedir, disable_classes und disable_functions genutzt werden.

Natürlich ist es auch ein guter Rat, immer eine aktuelle Version von PHP zu verwenden, seine Scripte abzusichern (Directory-Traversal, Code-Injection, Dateiuploads auf PHP-Code zu überprüfen, Remote-File-Inclusion etc. etc.), um einen Eindringlich erst gar nicht reinzulassen, aber das soll hier heute nicht das Thema sein.

Hier geht es also um disable_functions. Wir können in der php.ini PHP-Funktionen abschalten, die wir nicht benötigen und evtl. einem Eindringlich helfen, Schaden anzurichten. Welche Funktionen sollten deaktiviert werden? Ich habe hier mal eine Liste, über die wir diskutieren können:

disable_functions = „apache_child_terminate, apache_get_modules, apache_get_version, apache_getenv, apache_note, apache_setenv, curl_exec, curl_multi_exec, define_syslog_variables, disk_free_space, diskfreespace, dl, error_log, escapeshellarg, escapeshellcmd, exec, ftp_connect, ftp_exec, ftp_get, ftp_login, ftp_nb_fput, ftp_put, ftp_raw, ftp_rawlist, ini_alter, ini_get_all, ini_restore, link, mysql_pconnect, openlog, passthru, pfsockopen, php_uname, phpinfo, popen, posix_getpwuid, posix_kill, posix_mkfifo, posix_setpgid, posix_setsid, posix_setuid, posix_uname, proc_close, proc_get_status, proc_nice, proc_open, proc_terminate, set_time_limit, shell_exec, symlink, syslog, system, tmpfile, virtual

shell_exec verbietet auch gleich das Ausführen von Systembefehlen via Backticks (´).

Einige davon sind sicherlich gefährlicher als andere, und einige werden sogar vielleicht im ein oder anderen Projekt dringend gebraucht, sodass sie aus der Liste rausgenommen werden müssen. Als ich diese Liste erstellt habe musste ich feststellen dass ich mehr als ein Dutzend der Funktionen nicht kannte, es ist also sehr zu empfehlen sich mal ein paar davon anzuschauen.

Welche Funktionen verbietet ihr in der php.ini?

Written by Michael Kliewe

Januar 14th, 2011 at 9:05 am

Posted in PHP

Tagged with , , ,

23 Responses to 'Gefährliche PHP-Funktionen ausschalten'

Subscribe to comments with RSS or TrackBack to 'Gefährliche PHP-Funktionen ausschalten'.

  1. Zumindest in der Vergangenheit konnte man zumindest eval _nicht_ auf diesem Wege deaktivieren, da es keine Funktion ist sondern ein Sprachkonstrukt.

    Um eval zu deaktivieren könnte mann stattdessen suhosin verwenden.

    Julian Hartmann

    14 Jan 11 at 09:14

  2. @Julian: Du hast Recht, in einem Kurztest war eval weiterhin möglich. Ich dachte es hätte mal einen Hack gegeben sodass auch Sprachkonstrukte darüber deaktiviert werden können, dem ist wohl nicht so, schade.

    Michael Kliewe

    14 Jan 11 at 09:42

  3. Hi,

    der Liste stimme ich weitestgehend zu, diese ist bei mir fast genauso gesetzt. Jedoch bei einer Sache habe ich gestutzt: Warum curl_exec? Lasst ihr stattdessen lieber allow_url_fopen=On oder wie lautet eure/deine Empfehlung für den Zugriff auf entfernte Services? Ich hatte mal gelernt, dass man lieber auf curl als auf allow_url_fopen zurückgreift, daher meine Frage 😉

    Viele Grüße,
    Uli

    Uli

    14 Jan 11 at 10:27

  4. Stimme der Auflistung zum großen Teil zu. Grad so Sachen wie set_time_limit hätte man jetzt nicht direkt auf der Rechnung, obwohl es sehr sinnvoll ist diese Funktion nicht zuzulassen (es sei denn man braucht sie explizit). Einzig ohne curl könnte ich nicht leben. Und goto könnte man auch gleich noch absägen, wenn man mal dabei ist 😉

    David Müller

    14 Jan 11 at 10:54

  5. @Uli: Ich überlege gerade. Im Zend Framework wird stream_socket_client() als Standard genommen wenn Zend_Http_Client genutzt wird. In den Zeta-Components (ehemals ez-Components) wird auch stream_socket_client() verwendet.

    Das kommt drauf an was ihr machen wollt. Ich habe allow_url_fopen=Off und nutze keine Wrapper a la „http://“ oder „ftp://“ irgendwo im Code, sondern arbeite immer mit Host und Port: „tcp://1.2.3.4:80/“ (bzw. die von mir verwendete Frameworks arbeiten damit).

    allow_url_fopen bzw. auch allow_url_include erlaubt den Einsatz von Wrappern wie http:// oder ftp:// in einigen Funktionen, die mit Dateien arbeiten (fopen, file_get_contents etc.). Wenn man sicherstellt dass keine Variablen in den entsprechenden Funktionsaufrufen verwendet werden kann man allow_url_fopen auch aktiviert lassen und die Wrapper nutzen, ist häufig einfacher (und nicht weniger sicher) als der Einsatz von stream_socket_client(). Wobei die Nutzung von Streams noch andere Vorteile hat.

    Ich erinnere mich gerade dass ich mal eine Datei per SFTP oder SCP hochladen musste, da war ich kurz davor einfach allow_url_fopen zu aktivieren um „ssh2.scp://“ bzw. „ssh2.sftp://“ nutzen zu können. Aber auch dort gibt die Klasse Net_SFTP, die auf Socket-Ebene arbeitet und fsockopen($host, $port) nutzt.

    Im Normalfall versuche ich allow_url_fopen abzuschalten und keine Wrapper zu nutzen (und auch curl kompiliere ich meistens nicht mit ein).

    Michael Kliewe

    14 Jan 11 at 11:32

  6. @David: Wenn set_time_limit benötigt wird sollte man drüber nachdenken diese langlaufende Aufgabe auf einen anderen Server im Hintergrund auszulagern oder falls man nur einen Server hat auf die CLI auszuweichen (dort ist das time_limit deaktiviert).

    Solche lang laufenden Scripte gehören im Normalfall nicht auf einen Webserver und können prima mit Gearman, Zend-Server-Queue oder anderen Job-Queues ausgelagert werden und damit asynchron ausgeführt werden.

    set_time_limit aktiviert zu lassen verleitet einen dazu, es einfach auf 10000 zu setzen und damit Probleme zu umgehen, die man eigentlich an der Wurzel packen sollte.

    Aber auch hier gibt es natürlich Ausnahmen.

    goto ist nicht gefährlich, und es ist ein Sprachkonstrukt, lässt sich also mit disable_functions nicht deaktivieren.

    Mich verwundert dass curl so beliebt ist, ich habe es ehrlich gesagt noch nie verwendet…. Das einzige was sehr nett ist ist curl_multi_* für mehrere parallele Aktionen, aber wie gesagt noch nie benötigt.

    Michael Kliewe

    14 Jan 11 at 11:54

  7. Ich würde zusätzlich noch ini_set() und eval() abschalten, damit kann man schon genug Schaden anrichten:

    (Garnicht erst laufen lassen, den Code!)

    Wenn man sowas beispielsweise auf die Startseite kriegt stürzt der Server bei jedem Aufruf ab.

    DukeNightcrawler

    14 Jan 11 at 14:05

  8. Code ging verloren:

    $injected_code = ‚
    ini_set(„memory_limit“,“0″);
    $a = 10000000;
    while(1) { echo $a *= $a; }
    ‚;
    eval($injected_code);

    DukeNightcrawler

    14 Jan 11 at 14:06

  9. @Michael: Ich denke die „Beliebtheit“ von CURL liegt auch zum großen Teil an den (immernoch nicht bei allen PHP’lern angekommenen) Streams. Zudem steckt CURL auch unter vielen Implementierungen drunter, die z.B. einen REST-Wrapper für eine API anbieten.

    David Müller

    14 Jan 11 at 14:21

  10. @DukeNightcrawler: Ich hatte eval() auch erst in der Liste, aber es ist, wie Julian richtig sagte, ein Sprachkonstrukt und keine Funktion, sie ist also nicht mit disable_functions abschaltbar, sondern nur mit Suhosin.

    ini_set() abzuschalten dürfte in den meisten Fällen nicht funktionieren, man braucht es einfach zu häufig, z.B. display_errors, display_startup_errors werden je nach Umgebung (development, pre-live, production…) unterschiedlich gesetzt. PEAR nutzt z.B. track_errors.
    Aber all das könnte man auch vielleicht per .htaccess setzen, müßte man mal prüfen ob das geht.

    Die Erhöhung des memory_limit könnte man mit suhosin.memory_limit verbieten.

    Michael Kliewe

    14 Jan 11 at 14:40

  11. @Michael: Danke für die Erläuterung. Ich nutze Curl gerne, weils schnell geht und man recht viel damit machen kann. Ich habe immer allow_url_fopen=Off, das war mir einfach unsympatisch.

    Danke für die Klärung 😉

    Viele Grüße,
    Uli

    Uli

    14 Jan 11 at 15:19

  12. Mal abgesehen von einigen anderen nicht allzu gefährlichen, wieso escapeshellarg und escapeshellcmd?

    Jens

    14 Jan 11 at 22:48

  13. Nich schlecht,

    eine Menge Funktionen, schön, das mal auf einem „Haufen“ zu sehen.

    Thx.

    Christian Hünniger

    15 Jan 11 at 23:55

  14. @Jens: Wofür brauchst du die beiden Funktionen wenn exec(), system(), popen() etc. eh verboten sind?

    Michael Kliewe

    16 Jan 11 at 22:05

  15. @Michael: Das ist gar nicht die Frage. Wozu etwas deaktivieren was nicht gefährlich ist?

    Beispiel: Man könnte z.B. Befehle vorbereiten, die auf einem anderen Server ausgeführt werden sollen.

    Jens

    16 Jan 11 at 22:20

  16. @Jens: Wie genau führst du die Befehle auf dem anderen Server aus? Per SSH?
    Im Prinzip hast du Recht, die beiden sind nicht direkt gefährlich, ähnlich wie einige andere in der Liste (tmpfile, diskfreespace…). Sollte man sie doch brauchen kann man sie natürlich aus der Liste nehmen. Sie sind nur normalerweise recht unbekannt und unbenutzt und kommen recht häufig in Exploits und Script-Kiddy-Schadscripten vor liest man.

    Michael Kliewe

    16 Jan 11 at 22:36

  17. @Michael mit tmpfile() hat man eine Datei in die man sicher schreiben kann, mit diskfreespace() kann man beurteilen ob es sich für einen Angriff lohnt die Datei vollzuschreiben.

    Sind zumindest größere Probleme als escaping. 😉

    Jens

    16 Jan 11 at 22:45

  18. @Michael: Jetzt habe ich ganz vergessen auf deine Frage zu Antworten. Man könnte die Befehle in einer Viel-Server-Landschaft auf dem einen Server in die DB auf dem anderen schreiben und auf dem 3. abfragen und ausführen. Lastverteilung. Aber schon richtig: Sehr theoretisch.

    Jens

    16 Jan 11 at 22:46

  19. @Jens: Genau dann, wenn ich die Befehle in eine DB schreibe und sie auf anderen Servern ausführe würde ich auf jeden Fall auf den Zielservern escapen, und nicht auf dem Webserver. Bei solchen Dingen muss man sowieso dann SEHR vorsichtig sein, denn sonst hat ein Angreifer sehr schnell durch die Übernahme des Webservers die anderen Server auch direkt in der Hand.

    Nagut, egal, ich glaub wir sind uns einig dass man in 99% aller Fälle kein escaping braucht ohne auch exec/system zu brauchen, was recht selten sein sollte auf Webservern.

    Michael Kliewe

    17 Jan 11 at 00:03

  20. […] hat in seinem Blog einen Artikel über “gefährliche” PHP-Funktionen und wie man Sie ausschaltet […]

  21. […] Gefährliche PHP-Funktionen deaktivieren. […]

  22. […] Einsatzort sogar "gefährlich". In PHP gibt die Möglichkeit solche Funktionen zu deaktivieren. Gefährliche PHP-Funktionen ausschalten Weiterhin gibt es dazu noch das Suhosin Projekt. Damit kann man sich noch ein wenig mehr […]

  23. Auch wenn Dein Artikel schon ein paar Monate alt ist, möchte ich trotzdem vielen Dank für Deine Anregungen sagen. Ich habe für mich zusätzlich folgende Einschränkungen getroffen: disk_total_space, opendir, readdir, realpath

    Grund für diese Erweiterungen war, dass ich durch einen versuchten Angriff an ein php-Skript gekommen bin, das über eine fehlerhafte Upload-Funktion auf den Server geladen wurde (Skript konnte Gott sei Dank nicht ausgeführt werden). Über die zusätzlichen Einschränkungen ist das Skript nun praktisch wertlos.

    Neben Michaels Einschränkungen, die bereits u.a. die Funktionen für die Ausführung von shell-Befehlen ausschließen, wird dem Angreifer durch die zusätzlichen Einschränkungen auch die Möglichkeit der Orientierung genommen. Im Endeffekt wird mir nun bei Ausführung des Hack-Skripts eine nutzlose HTML-Seite, ohne Funktionen angezeigt.

    Gruß Dirk

    Dirk

    17 Sep 11 at 23:32

Leave a Reply

You can add images to your comment by clicking here.