The getimagesize function is not part of the GD extension. This function can be used by standard installed PHP. You can first take a look at the document description of this function: http://php.net/manual/zh/function.getimagesize.php
If the specified file is not a valid image, false will be returned and the data will be returned. There are also fields representing the document type. If you don't use it to get the size of the file but use it to determine whether the uploaded file is an image file, it seems to be a very good solution. Of course, this requires shielding possible warnings. For example, the code reads like this:
<?php $filesize = @getimagesize('/path/to/image.png'); if ($filesize) { do_upload(); } # 另外需要注意的是,你不可以像下面这样写: # if ($filesize[2] == 0) # 因为 $filesize[2] 可能是 1 到 16 之间的整数,但却绝对不对是0。
But if you just do such verification, then unfortunately, you have successfully planted a webshell vulnerability in the code.
To analyze this problem, let’s first take a look at the prototype of this function:
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); }
Due to space limitations, some details are hidden. Now we know two things from the above code. :
The final function is php_getimagesize_from_stream
The function responsible for determining the file type is php_getimagetype
Let’s take a look at the implementation of 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)) { ... } }
Removed Some details, php_sig_gif php_sig_png, etc. are defined in the file header:
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};
It can be seen that the image type is judged based on the first few bytes of the file stream (file header). So in this case, can we construct a special PHP file to bypass this judgment? Why not give it a try.
Find a hexadecimal editor to write a PHP statement, for example:
<?php phpinfo(); ?>
The hexadecimal encoding (UTF-8) of these characters is like this:
3C3F 7068 7020 7068 7069 6E66 6F28 293B 203F 3E
Let’s structure it and add the header byte of the PNG file in front to become like this:
8950 4E47 0D0A 1A0A 3C3F 7068 7020 7068 7069 6E66 6F28 293B 203F 3E
Finally save it as a file with a .php suffix (note that the above is the hexadecimal value of the file value), such as test.php. Execute php test.php and you will find that it can be executed successfully. So can you use getimagesize to read its file information? Create a new file and write the code to try:
<?php print_r(getimagesize('test.php'));
Execution result:
Array ( [0] => 1885957734 [1] => 1864902971 [2] => 3 [3] => width="1885957734" height="1864902971" [bits] => 32 [mime] => image/png )
was read successfully, and the file was recognized as a PNG file normally, although the width and height values are large. A bit outrageous.
Now you should understand why it is said above that there is a hidden danger of webshell here. If there is only such upload judgment here, and the uploaded file is accessible, arbitrary code can be injected and executed through this entrance.
So why can the above file be executed normally by PHP? Use the token_get_all function to look at this file:
<?phpprint_r(token_get_all(file_get_contents('test.php')));
If the display is normal, you can see that the parser code of the first element of the output array is 312, and the name obtained through token_name will be T_INLINE_HTML, that is It says that the information in the file header is treated as normal embedded HTML code and ignored.
As for why there is an outrageously large width and height, you can know by looking at the implementation of the php_handle_png function. This information is also obtained by reading the specific file header bits.
So, for normal image files, getimagesize is fully capable, but for some deliberately constructed file structures, it cannot.
When processing files uploaded by users, it is also an effective way to simply and roughly determine the file extension and process the file name to ensure that it cannot be directly executed on the server unless it is a PHP file. You can then use getimagesize to do some auxiliary processing.
The above is the content that the getimagesize function is not completely reliable. For more related content, please pay attention to the PHP Chinese website (www.php.cn)!