1. 程式人生 > >檔案上傳解析漏洞

檔案上傳解析漏洞

上傳漏洞

Mirror王宇陽

2019年10月28日

Web網站通常存在檔案上傳(例如:圖片、文件、zip壓縮檔案^等)只要存在上傳功能,就有可能會有上傳漏洞的危機。和SQL注入漏洞相比較而言,上傳漏洞更加危險,因為該漏洞可以直接上傳一個WebShell到伺服器上。

解析漏洞

利用上傳漏洞,通常需要結合Web容器(IIS、Nginx、Apache、Tomcat)的解析漏洞來讓上傳的漏洞得到實現

IIS解析漏洞

IIS5.x/IIS 6.0檔案解析漏洞

  • 目錄名中含有.asp字串的(目錄下)均按照asp檔案進行解析;例如:index.asp/目錄中的所有檔案都會asp解析

    當出現xx.asp命名的檔名,訪問目錄下任意一個檔案,均會送給asp.dll解析(執行asp指令碼)

  • 檔名中含有.asp;字元,即使時jpg格式檔案,IIS也會按照asp對檔案進行解析

    當檔名xx.asp;xx.jpg,IIS6會將檔案送給asp.dll解析(按照asp指令碼解析);

    請求時:IIS從左往右檢查.號,查詢到;/號則(記憶體)截斷;如此執行後,IIS認識的就是xx.asp

  • 預設解析:.asa .cer .cdx IIS6 同時預設解析前面三個檔案字尾,都會給asp.dll解析

  • 修復方案:

    設定許可權,限制使用者建立、修改資料夾許可權

    更新微軟的補丁或者自定義修改IIS的檢測規則,阻止上傳非法的檔名字尾

IIS7.0/7.5

  • 預設開啟 Fast-CGI 狀態,在一個伺服器檔案URL地址後面新增xx.php

    會將xx.jpg/xx.php解析為PHP檔案

  • 修復方法:

    修改php.ini檔案,將cgi.fi: x_pathinfo設定為 0

    IIS7的解析漏洞主要是由於PHP的配置不當導致的

    Windows作業系統中,檔名不能以空格或“.”開頭,也不能以空格或“.”結尾。當把一個檔案命名為以空格或“.”開頭或結尾時,會自動地去掉開頭和結尾處的空格和“.”。利用此特性,也可能造成“檔案解析漏洞”。

Nginx解析漏洞

Nginx <= 0.8.37

影響版本:0.5/0.6/<0.7.65/<0.8.37

  • Fast-CGI開啟狀態下,存在如同IIS7一樣的漏洞:URL地址後面新增xx.php會將xx.jpg/xx.php

    解析為PHP檔案

    空位元組:xx.jpg%00.php (部分版本中,Fast-CGI關閉下也會被執行)

  • 修復方法:

    修改php.ini檔案,將cgi.fix_pathinfo設定為 0 [關閉]

    再Nginx配置中設定:當類似xx.jpg/xx.php的URL訪問時候,返回403;

    if ( $fastcgi_script_name ~ ..*/.*php) {
        return 403 ;
    }

Apache解析漏洞

Apache字尾名解析漏洞

  • Apache解析檔案的規則時從右到左開始判斷,如果字尾名為不可識別檔案解析,則會繼續向左判斷,直至可以正確識別

    xxx.php.owf.zip 其中.owf.zip檔案字尾Apache不識別,直至判斷.php才會按照PHP解析檔案

  • 修復方法:

    Apache配置中,禁止xx.php.xxx類似的檔案執行

    <Files ~ "/.(php.|php3.)">
        Order Allow,Deny
        Deny from all
    </Files>

Apache"%0A"繞過上傳黑名單 [CVE-2017-15715]

  • Apache中存在一個上傳的判斷邏輯:(自定義)

    <?php
        if(isset($_FILES['file'])){
            $name = basename($_POST['name']);
            $ext = pathinfo($name,PATHINFO_EXTNSION);
            if(in_array($ext,['php','php3','php4','php5','phtml','pht'])){
                exit("bad file");
            }
            move_uploaded_file($_FILES['file']['tmp_name'],'./'.$name);
        }
    ?>

    判斷檢查上傳檔案的字尾名,如果發現了,就進行攔截。

    利用CVE-2017-15715,上傳一個包含換行符的檔案。注意,只能是\x0A,不能是\x0D\x0A,所以我們用hex功能在1.php後面新增一個\x0A

​ 訪問/1.php%0A,即課成功getShell;

檔案上傳繞過

客戶端校驗

  • 客戶端使用JavaScript檢查上傳檔案的字尾名

    # js驗證檔案字尾
    extArray = new Array('.gif','.jpg','.png'); // 白名單
    function LimitAttach(form,file){
        allowSubmit = false;
        if(!file)
            return;
        while(file.indexOf('\\')!=-1)
        file = file.slice(file.indexOf('\\')+1);
        ext = file.slice(file.indexOf('.')).toLowerCase();
        for(var i = 0 ; i < extArray.length ; i++){
            if(extArray[i] == ext){
                allowSubmit = true ; 
                break ;
            }
        }
        if(allowSubmit)
            form.submit();
        else
            alert("bad Extension");
    }

    一般情況可以通過抓包繞過客戶端的 js校驗

    # php接收檔案(沒有任何校驗)
    <?php
      if(isset($_POST['submit'])){
            $name = $_FILES['file']['name']; //檔名
            $naem = md5(date('Y-m-d h:m:s')).strrchr($name,'.');// 檔案重新命名保留擴充套件
            $size = $_FILES['file']['size']; //檔案位元組大小
            $tmp = $_FILES['file']['tmp_name']; //臨時路徑
            move_uploaded_file($tmp,$name); //移動檔案到tmp目錄下
            echo '檔案上傳成功'.$name;
        }
    ?>
  • 繞過客戶端校驗:

    使用FireBug開發者工具,在本地構造一個可以越過觸發校驗函式即可提交表單的內容;讓校驗函式不被呼叫即可繞過。

    另外也可以通過抓包方式在通過客戶端校驗後修改資料包的內容。(改包過程中可能會改動資料包的大小,需要留意Content-Length定義的長度要與實際相符)

服務端校驗

  • Content-type欄位校驗(MIME型別校驗)
  • 副檔名檢測(檢測檔案Extension相關的內容)採用黑白名單過濾的機制
  • 檔案內容體檢測(檢測內容是否合法或者惡意程式碼)

  • 目錄驗證

MIME校驗:Content-type

  • Content-type欄位顯示檔案的MIME型別,判斷MIME型別可以對檔案做簡單的過濾

    # 校驗Content-type欄位MIME型別
    <?php
        if($_FILES['file']['type'] != 'image/jpeg'){  // 判斷檔案的MIME格式
            echo "Sorry!檔案上傳格式錯誤 Error";
            exit;
    
        }
    ?>
  • 繞過MIME校驗:

    利用Burp抓包工具,將content-type欄位改為需要的MIME型別

副檔名檢測

  • 黑名單策略:

    存在一個專門的檔案,記錄伺服器不允許上傳的檔名

  • 白名單策略:

    存在一個專門的檔案,記錄伺服器允許上傳的檔名

    # 副檔名檢測
    <?php
        if(isset($_POST['submit'])){
            $name = $_FILES['file']['name']; // 獲取檔名
            $ext = substr(strrchr($name,"."),1); //獲取副檔名[strrchr()找到符號"."並返回從該位置到結尾的所有字元(字串),substr(str,1)獲得副檔名字串]
            while($ext==xxx){}
            // 呼叫黑白名單進行迴圈對比,一旦命中則執行相關的放過/攔截操作!
        }
    ?>

目錄驗證

  • 讓上傳的檔案儲存在一個統一的目錄

    # 目錄驗證
    <?php
        if(isset($_POST['submit'])){
            $name = $_FILES['file']['name']; //檔名
            $naem = date('Y-m-d h:m:s').strrchr($name,'.');// 檔案重新命名保留擴充套件
            $tmp = "./root/"; //儲存路徑,可以是伺服器指定或者使用者原則或則機制選擇
            move_uploaded_file($tmp,$name); //移動檔案到tmp目錄下
        }
    ?>

伺服器校驗檔案例項程式碼

<?php
    if(isset($_POST['submit'])){
        $name = $_FILES['file']['name'] ;
        $type = $_FILES['file']['type'] ;
        $tmp = "./image/";
    }
    
    file_array = new array('jpeg','png','jpg','gif');// 白名單
    for ($i=0; $i < file_array.length; $i++) {
        if (substr(strrchr($name, "."),1) == file_array[i]) {
            if( $type == "image/gif" | $type == "image/jpeg" ){

                move_uploaded_file($tmp, $name);
                echo "圖片上傳成功……".$name;
                exit;
            }
        }
    }
?>

繞過策略

  • burp抓包改包,繞過校驗機制,再利用包含漏洞進行getShell

文字編輯器上傳漏洞

常見文字編輯器:FCKEditor、Ewebeditor、UEditor、KindEditor、XHditor;合俗稱“富文字編輯器”

筆者接觸文字編輯器不多,貢獻一個不錯的參考文章: https://blog.yuntest.org/jszy/stcs/91.h