国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

getimagesize 函數不是完全可靠的

Heier / 965人閱讀

摘要:函數并不屬于擴展的部分,標準安裝的都可以使用這個函數。執行一下你會發現完全可以執行成功。所以,對于正常的圖片文件,完全可以勝任,但是對于一些有心構造的文件結構卻不行。

getimagesize 函數并不屬于 GD 擴展的部分,標準安裝的 PHP 都可以使用這個函數。可以先看看這個函數的文檔描述:http://php.net/manual/zh/function.getimagesize.php

如果指定的文件如果不是有效的圖像,會返回 false,返回數據中也有表示文檔類型的字段。如果不用來獲取文件的大小而是使用它來判斷上傳文件是否是圖片文件,看起來似乎是個很不錯的方案,當然這需要屏蔽掉可能產生的警告,比如代碼這樣寫:


但是如果你僅僅是做了這樣的驗證,那么很不幸,你成功的在代碼里種下了一個 webshell 的隱患。

要分析這個問題,我們先來看一下這個函數的原型:

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);
}

限于篇幅上面隱藏了一些細節,現在從上面的代碼中我們知道兩件事情就夠了:

最終處理的函數是 php_getimagesize_from_stream

負責判斷文件類型的函數是 php_getimagetype

接下來看一下 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)) {
        ...
    }
}

去掉了一些細節,php_sig_gif php_sig_png 等是在文件頭部定義的:

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};

可以看出來 image type 是根據文件流的前幾個字節(文件頭)來判斷的。那么既然如此,我們可不可以構造一個特殊的 PHP 文件來繞過這個判斷呢?不如來嘗試一下。

找一個十六進制編輯器來寫一個的 PHP 語句,比如:

這幾個字符的十六進制編碼(UTF-8)是這樣的:

3C3F 7068 7020 7068 7069 6E66 6F28 293B 203F 3E

我們構造一下,把 PNG 文件的頭字節加在前面變成這樣的:

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

最后保存成 .php 后綴的文件(注意上面是文件的十六進制值),比如 test.php。執行一下 php test.php 你會發現完全可以執行成功。那么能用 getimagesize 讀取它的文件信息嗎?新建一個文件寫入代碼試一下:


執行結果:

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

成功讀取出來,并且文件也被正常識別為 PNG 文件,雖然寬和高的值都大的有點離譜。

現在你應該明白為什么上文說這里留下了一個 webshell 的隱患的吧。如果這里只有這樣的上傳判斷,而且上傳之后的文件是可以訪問的,就可以通過這個入口注入任意代碼執行了。

那么為什么上面的文件可以 PHP 是可以正常執行的呢?用 token_get_all 函數來看一下這個文件:


如果顯示正常的話你能看到輸出數組的第一個元素的解析器代號是 312,通過 token_name 獲取到的名稱會是 T_INLINE_HTML,也就是說文件頭部的信息被當成正常的內嵌的 HTML 代碼被忽略掉了。

至于為什么會有一個大的離譜的寬和高,看一下 php_handle_png 函數的實現就能知道,這些信息也是通過讀取特定的文件頭的位來獲取的。

所以,對于正常的圖片文件,getimagesize 完全可以勝任,但是對于一些有心構造的文件結構卻不行。

在處理用戶上傳的文件時,先簡單粗暴的判斷文件擴展名并對文件名做一下處理,保證在服務器上不是 php 文件都不能直接執行也是一種有效的方式。然后可以使用 getimagesize 做一些輔助處理。

個人博客地址:http://0x1.im

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/21197.html

相關文章

  • PHP圖片操作

    摘要:保持原圖長寬比,以圖片的長度,或者寬度中,最小的一個為準,盡可能填充整個縮略圖的畫框,只顯示原圖中的某一部分。涉及到的相關圖片操作函數如下創建黑色圖片獲取圖片相關信息一個圖片中的一部分到另外一個圖片輸出圖片具體使用方法請查看相關手冊。 1, PHP 中 圖片的處理 要 依靠于擴展庫, 可以選擇gd2,或者imagemagick 第一步,首先要開啟gd2的擴展庫,在phpinfo() 中...

    yacheng 評論0 收藏0
  • PHP高級語法總結

    摘要:一執行系統外部命令輸出并返回最后一行結果。相同點都可以獲得命令執行的狀態碼用提供的專門函數提供共了個專門的執行外部命令的函數,,。第二個參數是可選的,用來得到命令執行后的狀態碼。 php高級語法總結。 一、執行系統外部命令 system() 輸出并返回最后一行shell結果。 exec() 不輸出結果,返回最后一行shell結果,所有結果可以保存到一個返回的數組里面。 pass...

    Hydrogen 評論0 收藏0
  • 分享一下利用phpqrcode二維碼生成類庫和imagecopymerge函數制拼合(鑲嵌、合并、水

    摘要:二維碼圖片寬度二維碼圖片高度圖片寬度圖片高度重新組合圖片并調整大小最后直接輸出圖像即可還是老樣子,我們給圖片來個名字這次用為隨機數時間戳而后輸出圖像整個帶的二維碼生成就完成了。 利用 phpqrcode 二維碼生成類庫和 imagecopymerge 函數制作帶二維碼的圖片 首先引用phpqrcode類庫 下載phpqrcode類庫 下載地址就不提供了,百度一搜一大把; 新建...

    Turbo 評論0 收藏0
  • 分享一下利用phpqrcode二維碼生成類庫和imagecopymerge函數制拼合(鑲嵌、合并、水

    摘要:二維碼圖片寬度二維碼圖片高度圖片寬度圖片高度重新組合圖片并調整大小最后直接輸出圖像即可還是老樣子,我們給圖片來個名字這次用為隨機數時間戳而后輸出圖像整個帶的二維碼生成就完成了。 利用 phpqrcode 二維碼生成類庫和 imagecopymerge 函數制作帶二維碼的圖片 首先引用phpqrcode類庫 下載phpqrcode類庫 下載地址就不提供了,百度一搜一大把; 新建...

    SexySix 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<