Heim > php教程 > PHP开发 > Die Funktion getimagesize ist nicht völlig zuverlässig

Die Funktion getimagesize ist nicht völlig zuverlässig

黄舟
Freigeben: 2016-12-28 13:04:37
Original
1791 Leute haben es durchsucht

Die Funktion getimagesize ist nicht Teil der GD-Erweiterung. Diese Funktion kann von standardmäßig installiertem PHP verwendet werden. Sie können sich zunächst die Dokumentbeschreibung dieser Funktion ansehen: http://php.net/manual/zh/function.getimagesize.php

Wenn die angegebene Datei kein gültiges Bild ist, wird „false“ angezeigt zurückgegeben und die Daten werden zurückgegeben. Es gibt auch Felder, die den Dokumenttyp darstellen. Wenn Sie es nicht verwenden, um die Größe der Datei zu ermitteln, sondern um festzustellen, ob es sich bei der hochgeladenen Datei um eine Bilddatei handelt, ist dies natürlich eine sehr gute Lösung, um beispielsweise mögliche Warnungen zu blockieren. Der Code ist wie folgt geschrieben:

<?php
$filesize = @getimagesize(&#39;/path/to/image.png&#39;);
if ($filesize) {
    do_upload();
}
# 另外需要注意的是,你不可以像下面这样写:
# if ($filesize[2] == 0)
# 因为 $filesize[2] 可能是 1 到 16 之间的整数,但却绝对不对是0。
Nach dem Login kopieren

Aber wenn Sie nur eine solche Überprüfung durchführen, haben Sie leider erfolgreich eine Webshell-Schwachstelle in den Code eingebaut.

Um dieses Problem zu analysieren, werfen wir zunächst einen Blick auf den Prototyp dieser Funktion:

static void php_getimagesize_from_stream(php_stream *stream, zval **info, INTERNAL_FUNCTION_PARAMETERS)
{
    ...
    itype = php_getimagetype(stream, NULL TSRMLS_CC);
    switch( itype) {
        ...
    }
    ...
}

static void php_getimagesize_from_any(INTERNAL_FUNCTION_PARAMETERS, int mode) {
    ...
    php_getimagesize_from_stream(stream, info, INTERNAL_FUNCTION_PARAM_PASSTHRU);
    php_stream_close(stream);
}

PHP_FUNCTION(getimagesize)
{
    php_getimagesize_from_any(INTERNAL_FUNCTION_PARAM_PASSTHRU, FROM_PATH);
}
Nach dem Login kopieren

Der begrenzte Platz hat einige Details verborgen. Jetzt wissen wir zwei Dinge aus dem obigen Code: Genug :

Die letzte Verarbeitungsfunktion ist php_getimagesize_from_stream

Die für die Bestimmung des Dateityps verantwortliche Funktion ist php_getimagetype

Werfen wir einen Blick auf die Implementierung von php_getimagetype:

PHPAPI int php_getimagetype(php_stream * stream, char *filetype TSRMLS_DC)
{
    ...
    if (!memcmp(filetype, php_sig_gif, 3)) {
        return IMAGE_FILETYPE_GIF;
    } else if (!memcmp(filetype, php_sig_jpg, 3)) {
        return IMAGE_FILETYPE_JPEG;
    } else if (!memcmp(filetype, php_sig_png, 3)) {
        ...
    }
}
Nach dem Login kopieren

Einige Details wurden entfernt. php_sig_gif php_sig_png usw. sind im Dateikopf definiert:

PHPAPI const char php_sig_gif[3] = {&#39;G&#39;, &#39;I&#39;, &#39;F&#39;};
...
PHPAPI const char php_sig_png[8] = {(char) 0x89, (char) 0x50, (char) 0x4e, (char) 0x47,
                                    (char) 0x0d, (char) 0x0a, (char) 0x1a, (char) 0x0a};
Nach dem Login kopieren

Es ist ersichtlich, dass der Bildtyp anhand der ersten paar Bytes der Datei beurteilt wird Stream (Dateikopf). Können wir in diesem Fall eine spezielle PHP-Datei erstellen, um dieses Urteil zu umgehen? Warum probieren Sie es nicht einmal aus?

Suchen Sie einen hexadezimalen Editor, um eine PHP-Anweisung zu schreiben, zum Beispiel:

<?php phpinfo(); ?>
Nach dem Login kopieren

Die hexadezimale Kodierung (UTF-8) dieser Zeichen ist wie folgt:

3C3F 7068 7020 7068 7069 6E66 6F28 293B 203F 3E
Nach dem Login kopieren

Strukturieren wir es und fügen wir das Header-Byte der PNG-Datei voran, sodass es so aussieht:

8950 4E47 0D0A 1A0A 3C3F 7068 7020 7068 7069 6E66 6F28 293B 203F 3E
Nach dem Login kopieren

Speichern Sie es abschließend als Datei mit dem Suffix .php (beachten Sie, dass es sich bei dem oben genannten um den Hexadezimalwert handelt). der Datei), wie zum Beispiel test.php. Führen Sie php test.php aus und Sie werden feststellen, dass es erfolgreich ausgeführt werden kann. Können Sie also getimagesize verwenden, um die Dateiinformationen zu lesen? Erstellen Sie eine neue Datei und schreiben Sie den Code, um Folgendes zu versuchen:

<?php
print_r(getimagesize(&#39;test.php&#39;));
Nach dem Login kopieren

Ausführungsergebnis:

Array
(
    [0] => 1885957734
    [1] => 1864902971
    [2] => 3
    [3] => width="1885957734" height="1864902971"
    [bits] => 32
    [mime] => image/png
)
Nach dem Login kopieren

wurde erfolgreich gelesen und die Datei wurde trotz der Breite normal als PNG-Datei erkannt und Höhe Die Werte sind etwas unverschämt.

Jetzt sollten Sie verstehen, warum oben gesagt wurde, dass eine versteckte Gefahr von Webshell besteht. Wenn es hier nur ein solches Upload-Urteil gibt und die hochgeladene Datei zugänglich ist, kann über diesen Eingang beliebiger Code eingeschleust und ausgeführt werden.

Warum kann die obige Datei normal von PHP ausgeführt werden? Verwenden Sie die Funktion token_get_all, um diese Datei anzuzeigen:

<?phpprint_r(token_get_all(file_get_contents(&#39;test.php&#39;)));
Nach dem Login kopieren

Wenn die Anzeige normal ist, können Sie sehen, dass der Parser-Code des ersten Elements des Ausgabearrays 312 ist und der über token_name erhaltene Name verwendet wird sei T_INLINE_HTML. Mit anderen Worten, die Informationen im Dateiheader werden als normaler eingebetteter HTML-Code behandelt und ignoriert.

Warum es eine absurd große Breite und Höhe gibt, können Sie anhand der Implementierung der Funktion php_handle_png erkennen. Diese Informationen werden auch durch Lesen der spezifischen Dateiheader-Bits erhalten.

Für normale Bilddateien ist getimagesize also voll funktionsfähig, für einige bewusst erstellte Dateistrukturen jedoch nicht.

Bei der Verarbeitung von von Benutzern hochgeladenen Dateien ist dies auch eine effektive Möglichkeit, die Dateierweiterung einfach und grob zu bestimmen und den Dateinamen zu verarbeiten, um sicherzustellen, dass er nicht direkt auf dem Server ausgeführt werden kann, es sei denn, es handelt sich um eine PHP-Datei. Sie können dann getimagesize verwenden, um eine zusätzliche Verarbeitung durchzuführen.

Das Obige ist der Inhalt, dass die Funktion getimagesize nicht vollständig zuverlässig ist. Weitere verwandte Inhalte finden Sie auf der chinesischen PHP-Website (m.sbmmt.com)!


Verwandte Etiketten:
Quelle:php.cn
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Empfehlungen
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage