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('/path/to/image.png'); if ($filesize) { do_upload(); } # 另外需要注意的是,你不可以像下面这样写: # if ($filesize[2] == 0) # 因为 $filesize[2] 可能是 1 到 16 之间的整数,但却绝对不对是0。
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); }
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)) { ... } }
Einige Details wurden entfernt. php_sig_gif php_sig_png usw. sind im Dateikopf definiert:
PHPAPI const char php_sig_gif[3] = {'G', 'I', 'F'}; ... PHPAPI const char php_sig_png[8] = {(char) 0x89, (char) 0x50, (char) 0x4e, (char) 0x47, (char) 0x0d, (char) 0x0a, (char) 0x1a, (char) 0x0a};
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(); ?>
Die hexadezimale Kodierung (UTF-8) dieser Zeichen ist wie folgt:
3C3F 7068 7020 7068 7069 6E66 6F28 293B 203F 3E
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
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('test.php'));
Ausführungsergebnis:
Array ( [0] => 1885957734 [1] => 1864902971 [2] => 3 [3] => width="1885957734" height="1864902971" [bits] => 32 [mime] => image/png )
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('test.php')));
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)!