uploads-lab文件上傳靶場闖關記錄


uploads-lab靶場闖關

0x01 Pass-01 前端檢測

源代碼

function checkFile() {
    //這里getElementsByName取name的值,,判斷表單里是否選擇了文件
    var file = document.getElementsByName('upload_file')[0].value;
    if (file == null || file == "") {
        alert("請選擇要上傳的文件!");
        return false;
    }
    //定義允許上傳的文件類型
    var allow_ext = ".jpg|.png|.gif";
    //提取上傳文件的類型
    // substring()表示返回一個從里面的參數位置開始到末尾的字符串
    // lastIndexOf()表示 返回'.'首次出現的位置,如果未發現此字符串返回 -1
    var ext_name = file.substring(file.lastIndexOf("."));
    //判斷上傳文件類型是否允許上傳
    if (allow_ext.indexOf(ext_name + "|") == -1) {
        var errMsg = "該文件不允許上傳,請上傳" + allow_ext + "類型的文件,當前文件類型為:" + ext_name;
        alert(errMsg);
        return false;
    }
}

Get到javascript的知識點:

onsubmit="return false;" 將無論何時都阻止表單的提交
onsubmit="return check();" 是否提交表單取決於check()的返回值
onsubmit="check();" check()的返回值無影響
null:代表聲明了一個空對象,不是一個字符串,可以賦給任何對象,是沒有地址。
"":  代表聲明了一個對象實例,這個對象實例的值是一個長度為0的空字符串,是有地址但是里面的內容是空的。

繞過方法

  • [ ] ​ 在控制台修改前端js代碼,在allow_ext中 添加 '.php' 即可繞過

  • [ ] ​ 在前端界面審查元素處,刪除檢測上傳的js函數,或者瀏覽器禁止js運行

  • [ ] ​ 上傳shell.jpg,用burpsuit抓包,修改后綴為shell.php 即可繞過


0x02 Pass-02 MIME類型 檢測

源代碼

$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
    if (file_exists(UPLOAD_PATH)) { //upload_file 已經在別的文件里定義好了,表示'../upload/'
        if (($_FILES['upload_file']['type'] == 'image/jpeg') || ($_FILES['upload_file']['type'] == 'image/png') || ($_FILES['upload_file']['type'] == 'image/gif')) {
            $temp_file = $_FILES['upload_file']['tmp_name'];//獲取臨時文件名
            $img_path = UPLOAD_PATH . '/' . $_FILES['upload_file']['name']    //上傳目錄+上傳時的文件名         
            if (move_uploaded_file($temp_file, $img_path)) {//把臨時文件移到UPLOAD_PATH目錄
                $is_upload = true;
            } else {
                $msg = '上傳出錯!';
            }
        } else {
            $msg = '文件類型不正確,請重新上傳!';
        }
    } else {
        $msg = UPLOAD_PATH.'文件夾不存在,請手工創建!';
    }
}

將content-type修改為 image/jpeg image/png image/gif 其中一個即可


0x03 Pass-03

源碼

$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
    if (file_exists(UPLOAD_PATH)) {
        $deny_ext = array('.asp','.aspx','.php','.jsp');
        $file_name = trim($_FILES['upload_file']['name']);//去除空字符以及預定義的字符
        $file_name = deldot($file_name);//刪除文件名末尾的點
        $file_ext = strrchr($file_name, '.'); //查找'.'最后一次出現的位置,並返回從該位置到結尾的所有字符
        $file_ext = strtolower($file_ext); //轉換為小寫
        $file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA
        $file_ext = trim($file_ext); //收尾去空

        if(!in_array($file_ext, $deny_ext)) {
            $temp_file = $_FILES['upload_file']['tmp_name'];
            $img_path = UPLOAD_PATH.'/'.date("YmdHis").rand(1000,9999).$file_ext;            
            if (move_uploaded_file($temp_file,$img_path)) {
                 $is_upload = true;
            } else {
                $msg = '上傳出錯!';
            }
        } else {
            $msg = '不允許上傳.asp,.aspx,.php,.jsp后綴文件!';
        }
    } else {
        $msg = UPLOAD_PATH . '文件夾不存在,請手工創建!';
    }
}

  • [x] 閱讀源碼發現,通過自定義的deldot函數進行末尾去點處理,如果沒有對末尾的點進行處理,則可以利用windows特性上傳后自動去除文件后綴名的點

​ 通過源碼可以發現是 檢測黑名單后綴,所以這里可以通過將后綴改為.php3 .phtml

GET Apache 相關知識點

  • .htaccess

一般來說,配置文件的作用范圍都是全局的,但 Apache 提供了一種很方便的、可作用於當前目錄及其子目錄的配置文件—— .htaccess(分布式配置文件)

要想使 .htaccess 文件生效,需要兩個條件:

1. Apache的配置文件中,要寫上: AllowOverride All
2. Apache要加載mod_Rewrite模塊。加載該模塊,需要在Apache的配置文件中寫上:LoadModule rewrite_module /usr/lib/apache2/modules/mod_rewrite.so

.htaccess文件內容:

AddType application/x-httpd-php xxx

<FilesMatch "shell.jpg">
    SetHandler application/x-httpd-php
  </FilesMatch>
  • httpd.conf

如果想要apache可以將xxx的后綴當作php來執行 .php3 .phtml .xxx等后綴,需要在apache下的httpd.conf配置:

 AddType application/x-httpd-php .php3 .phtml

這時,服務器會將php3, phtml后綴的文件當成php解析。

  • mime.types

有一個名為mime.types的文件,其中記錄着Apache認識的后綴

可以修改mime.types的配置 讓apache 將不常用的后綴解析為php

application/x-httpd-php .php .php3 .phtml

GET windows特性知識點

測試結果

可以成功將phtml文件解析

通過重寫.htacess文件 來繞過黑名單(出現點小問題)

由於黑名單沒有過濾掉 .htaccess ,所以我們能夠上傳.htaccess 文件導致其后上傳的其他文件能夠解析成 php,從而拿到shell ,

問題就在這里出現了,發現上傳后的 .htaccess被改寫為 2019***.htaccess,所以這里並不能直接上傳htaccess

發現源碼使用隨機數對文件名進行重寫


0x04 Pass-04 (.htaccess)繞過

源碼

$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
    if (file_exists(UPLOAD_PATH)) {
        $deny_ext = array(".php",".php5",".php4",".php3",".php2","php1",".html",".htm",".phtml",".pht",".pHp",".pHp5",".pHp4",".pHp3",".pHp2","pHp1",".Html",".Htm",".pHtml",".jsp",".jspa",".jspx",".jsw",".jsv",".jspf",".jtml",".jSp",".jSpx",".jSpa",".jSw",".jSv",".jSpf",".jHtml",".asp",".aspx",".asa",".asax",".ascx",".ashx",".asmx",".cer",".aSp",".aSpx",".aSa",".aSax",".aScx",".aShx",".aSmx",".cEr",".sWf",".swf");
        $file_name = trim($_FILES['upload_file']['name']);
        $file_name = deldot($file_name);//刪除文件名末尾的點
        $file_ext = strrchr($file_name, '.');
        $file_ext = strtolower($file_ext); //轉換為小寫
        $file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA
        $file_ext = trim($file_ext); //收尾去空

        if (!in_array($file_ext, $deny_ext)) {
            $temp_file = $_FILES['upload_file']['tmp_name'];
            $img_path = UPLOAD_PATH.'/'.$file_name;
            if (move_uploaded_file($temp_file, $img_path)) {
                $is_upload = true;
            } else {
                $msg = '上傳出錯!';
            }
        } else {
            $msg = '此文件不允許上傳!';
        }
    } else {
        $msg = UPLOAD_PATH . '文件夾不存在,請手工創建!';
    }
}
?>

黑名單過濾了一堆后綴名,但唯獨沒有過濾 .htaccess 於是上傳一個 .htaccess文件,內容:

表示將所有文件名包含jpg的,都作為php解析

<FilesMatch "jpg">
    SetHandler application/x-httpd-php
  </FilesMatch>

上傳成功

再上傳一個shell.jpg看能否執行

可以正常執行,說明 .htaccess 成功上傳

方法二:

因為apache 由右向左👈解析的特性, 因此可以上傳一個它不認識的后綴來繞過黑名單檢測,比如 shell.php.aaaaaa ,這樣可以繞過黑名單后綴讓文件成功上傳,又因為apache的特性,可以成功以php來解析


0x05 Pass-05 后綴名大小寫繞過

查看源碼可以知道是 根據黑名單后綴名檢測,且沒有對大小寫進行統一轉換,所有這里可以利用 pHP 等來繞過


0x06 Pass-06 空格繞過黑名單

源碼

$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
    if (file_exists(UPLOAD_PATH)) {
        $deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".pht",".pHp",".pHp5",".pHp4",".pHp3",".pHp2",".Html",".Htm",".pHtml",".jsp",".jspa",".jspx",".jsw",".jsv",".jspf",".jtml",".jSp",".jSpx",".jSpa",".jSw",".jSv",".jSpf",".jHtml",".asp",".aspx",".asa",".asax",".ascx",".ashx",".asmx",".cer",".aSp",".aSpx",".aSa",".aSax",".aScx",".aShx",".aSmx",".cEr",".sWf",".swf",".htaccess");
        $file_name = $_FILES['upload_file']['name'];
        $file_name = deldot($file_name);//刪除文件名末尾的點
        $file_ext = strrchr($file_name, '.');
        $file_ext = strtolower($file_ext); //轉換為小寫
        $file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA
        
        if (!in_array($file_ext, $deny_ext)) {
            $temp_file = $_FILES['upload_file']['tmp_name'];
            $img_path = UPLOAD_PATH.'/'.date("YmdHis").rand(1000,9999).$file_ext;
            if (move_uploaded_file($temp_file,$img_path)) {
                $is_upload = true;
            } else {
                $msg = '上傳出錯!';
            }
        } else {
            $msg = '此文件不允許上傳';
        }
    } else {
        $msg = UPLOAD_PATH . '文件夾不存在,請手工創建!';
    }
}

通過源碼發現,和前面幾關相比,這關並沒有對上傳的文件名進行首位去除空白字符(或者其他字符)

所以可以利用windows的特性,末尾加空格后會自動去掉空格

於是上傳 'shell.php ',這個后綴名剛好可以繞過黑名單,並且上傳上去空格自動去掉,可以被解析

另外的思路

看到一篇博客上的作者說,可以用 'shell.php. ' 繞過,但是我分析之后發現是不行的,因為這里的源碼會將上傳文件重命名,首先它會將最后一個'.' 到 末尾的字符串 認為是后綴名, '.'的前面的字符會生成隨機數,所以最后上傳上去的文件應該是 'xxxx. ' ,又因為windows特性,所以 文件變成 'xxxx'


0x07 Pass-07 (沒有對后綴名末尾去除.)

閱讀源碼發現,沒有刪除文件名末尾的點,所以這里又是利用windows的特性

上傳 shell.php.

別的思路

  • 發現沒有對文件進行沖命名,所以這里可以上傳 '.htaccess.' 'shell.php.xxxxxxx'

0x08 Pass-08(利用windows NTFS $DATA特性繞過)

源碼

$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
    if (file_exists(UPLOAD_PATH)) {
        $deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".pht",".pHp",".pHp5",".pHp4",".pHp3",".pHp2",".Html",".Htm",".pHtml",".jsp",".jspa",".jspx",".jsw",".jsv",".jspf",".jtml",".jSp",".jSpx",".jSpa",".jSw",".jSv",".jSpf",".jHtml",".asp",".aspx",".asa",".asax",".ascx",".ashx",".asmx",".cer",".aSp",".aSpx",".aSa",".aSax",".aScx",".aShx",".aSmx",".cEr",".sWf",".swf",".htaccess");
        $file_name = trim($_FILES['upload_file']['name']);
        $file_name = deldot($file_name);//刪除文件名末尾的點
        $file_ext = strrchr($file_name, '.');
        $file_ext = strtolower($file_ext); //轉換為小寫
        $file_ext = trim($file_ext); //首尾去空
        
        if (!in_array($file_ext, $deny_ext)) {
            $temp_file = $_FILES['upload_file']['tmp_name'];
            $img_path = UPLOAD_PATH.'/'.date("YmdHis").rand(1000,9999).$file_ext;
            if (move_uploaded_file($temp_file, $img_path)) {
                $is_upload = true;
            } else {
                $msg = '上傳出錯!';
            }
        } else {
            $msg = '此文件類型不允許上傳!';
        }
    } else {
        $msg = UPLOAD_PATH . '文件夾不存在,請手工創建!';
    }
}

閱讀源碼可以看到,基本過濾了所以可以解析的后綴名, 前幾關的幾個windows小特性也不能利用,對'.' 空格 d等 做了過濾

GET知識點 Windows NTFS $DATA特性

當我們訪問 a.php:: $DATA時,就是請求 a.php本身的數據

::$DATA之后的數據當成文件流處理,不會檢測后綴名.且保持 $DATA之前的文件名

上傳成功, 訪問 123.php


0x09 Pass-09 .[空格]. 繞過黑名單

源碼

$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
    if (file_exists(UPLOAD_PATH)) {
        $deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".pht",".pHp",".pHp5",".pHp4",".pHp3",".pHp2",".Html",".Htm",".pHtml",".jsp",".jspa",".jspx",".jsw",".jsv",".jspf",".jtml",".jSp",".jSpx",".jSpa",".jSw",".jSv",".jSpf",".jHtml",".asp",".aspx",".asa",".asax",".ascx",".ashx",".asmx",".cer",".aSp",".aSpx",".aSa",".aSax",".aScx",".aShx",".aSmx",".cEr",".sWf",".swf",".htaccess");
        $file_name = trim($_FILES['upload_file']['name']);
        $file_name = deldot($file_name);//刪除文件名末尾的點
        $file_ext = strrchr($file_name, '.');
        $file_ext = strtolower($file_ext); //轉換為小寫
        $file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA
        $file_ext = trim($file_ext); //首尾去空
        
        if (!in_array($file_ext, $deny_ext)) {
            $temp_file = $_FILES['upload_file']['tmp_name'];
            $img_path = UPLOAD_PATH.'/'.$file_name;
            if (move_uploaded_file($temp_file, $img_path)) {
                $is_upload = true;
            } else {
                $msg = '上傳出錯!';
            }
        } else {
            $msg = '此文件類型不允許上傳!';
        }
    } else {
        $msg = UPLOAD_PATH . '文件夾不存在,請手工創建!';
    }
}

通過閱讀源碼發現,

這里上傳后的文件名用的還是未完全過濾之前的,前面幾關采用了拼接經過strrchr()處理過的函數名,而這一關並沒有。因為源碼中只進行了一次點號的清除,且我們至需要讓經過過濾后的后綴名不在黑名單即可,所以我們直接采用xxx.php.[空格]. 就可以進行繞過。

測試結果

方法二

依舊采用 apache特性👈由右向左解析, 上傳 'xxx.php.rrrr' ,繞過黑名單


0x10 Pass-10 雙寫繞過黑名單

源碼

$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
    if (file_exists(UPLOAD_PATH)) {
        $deny_ext = array("php","php5","php4","php3","php2","html","htm","phtml","pht","jsp","jspa","jspx","jsw","jsv","jspf","jtml","asp","aspx","asa","asax","ascx","ashx","asmx","cer","swf","htaccess");

        $file_name = trim($_FILES['upload_file']['name']);
        $file_name = str_ireplace($deny_ext,"", $file_name);//不區分大小寫替換
        $temp_file = $_FILES['upload_file']['tmp_name'];
        $img_path = UPLOAD_PATH.'/'.$file_name;        
        if (move_uploaded_file($temp_file, $img_path)) {
            $is_upload = true;
        } else {
            $msg = '上傳出錯!';
        }
    } else {
        $msg = UPLOAD_PATH . '文件夾不存在,請手工創建!';
    }
}

閱讀源碼可以發現,這里將把上傳的文件名中所有包含黑名單字符的,全部替換為空,所以這里可以利用雙寫來繞過, xx.p[php]hp,

測試結果


0x11 Pass-11 00截斷

源碼

$is_upload = false;
$msg = null;
if(isset($_POST['submit'])){
    $ext_arr = array('jpg','png','gif');
    $file_ext = substr($_FILES['upload_file']['name'],strrpos($_FILES['upload_file']['name'],".")+1);
    if(in_array($file_ext,$ext_arr)){
        $temp_file = $_FILES['upload_file']['tmp_name'];
        $img_path = $_GET['save_path']."/".rand(10, 99).date("YmdHis").".".$file_ext;

        if(move_uploaded_file($temp_file,$img_path)){
            $is_upload = true;
        } else {
            $msg = '上傳出錯!';
        }
    } else{
        $msg = "只允許上傳.jpg|.png|.gif類型文件!";
    }
}

這里先參考下這個鏈接

淺顯的意思就是在url中%00表示ascii碼中的0,而ascii碼中0作為保留字符,表示字符串結束,所以當url中出現%00時就會認為讀取已結束

img

所以在burpsuit中作出以下修改

最后成功上傳2.php文件

上傳思路分析

1.這里是因為上傳路徑可控,所以才可以對路徑進行截斷

2.當前版本是5.2 存在%00截斷問題 (php 5.3 不可以)

GET 到的知識點--> %00和%00(urldecode)

在網上常見用Burp將數據包中的%00進行urldecode的操作,那為什么要進行這一個操作?網上也常見直接放入%00就可以截斷成功的案例,為什么呢?

  1. 首先解釋為什么要進行urldecode操作呢?其原因在於上傳的表單中有一個enctype的屬性,並且需要enctype="multipart/form-data" (不對表單中數據進行編碼),path大多數都是存放在表單中的,因此需要在數據包中進行urldecode操作使%00變成字符串結束符號。
  1. 那么為什么網上也有直接添加%00而不進行urldecode操作呢?因為path也可以存放在URL或者Cookie中,而在提交數據的時候,瀏覽器會對數據做一次urldecode的操作,而到服務端,會對數據進行一次urldecode的操作,因此如果path在非enctype=multipart/form-data的表單中或URL or Cookie中的時候,就可以直接寫%00不需要進行URLdecode操作,讓服務端對%00進行URL解碼即可。
  1. %00截斷的使用是在路徑上

GET到的知識點--> 00截斷利用條件

PHP<5.3.4,且GPC關閉

GET到的知識點--> 誤區

有很多朋友喜歡在文件名中加%00進行截斷,筆者認為這種方式是不對的,為什么呢?比如攻擊者構造文件名:admintony.php%00a.jpg,在提取后綴名的時候遇到%00則認為字符串結束了,那么他提取到的后綴名會是.php.php后綴又不允許上傳所以上傳失敗了(這里有必要提一句,有人可能會說在一些情況下,%00截斷文件名可以成功,這種案例你試一下是不是任意文件上傳,西普的00截斷實驗就是一個任意文件上傳的上傳點,既然是任意文件上傳又何必用00截斷繞過呢?)


0x12 Pass-12 POST類型 截斷

這關和上一關基本一致,這里就不詳細說了,附上測試結果


0x13 Pass-13 -15文件頭類型檢查

13關源碼

function getReailFileType($filename){
    $file = fopen($filename, "rb");//fopen() 函數打開一個文件或 URL。
    $bin = fread($file, 2); //只讀2字節 fread() 函數讀取打開的文件。
    fclose($file);
    $strInfo = @unpack("C2chars", $bin);    
    $typeCode = intval($strInfo['chars1'].$strInfo['chars2']);    
    $fileType = '';    
    switch($typeCode){      
        case 255216:            
            $fileType = 'jpg';
            break;
        case 13780:            
            $fileType = 'png';
            break;        
        case 7173:            
            $fileType = 'gif';
            break;
        default:            
            $fileType = 'unknown';
        }    
        return $fileType;
}

$is_upload = false;
$msg = null;
if(isset($_POST['submit'])){
    $temp_file = $_FILES['upload_file']['tmp_name'];
    $file_type = getReailFileType($temp_file);

    if($file_type == 'unknown'){
        $msg = "文件未知,上傳失敗!";
    }else{
        $img_path = UPLOAD_PATH."/".rand(10, 99).date("YmdHis").".".$file_type;
        if(move_uploaded_file($temp_file,$img_path)){
            $is_upload = true;
        } else {
            $msg = "上傳出錯!";
        }
    }
}

通過閱讀源碼發現,getReailFileType() 只會讀取文件的前兩個字節

14關

這題一樣使用getimagesize函數判斷文件類型,但是這個函數也是檢查文件頭,是不可信的。

15關

exif_imagetype的作用是判斷一個圖像的類型 ,其實是讀取一個圖像的第一個字節並檢查其簽名。

方法一:

使用winhex等編輯器 打開圖片文件,將webshell直接插入末尾

方法二:

直接上傳webshell,使用burpsuit 攔截並添加圖片的文件頭

方法三:

使用cmd命令行 copy 生成圖片馬

方法四: php 讀文件

若是服務器采用文件頭驗證, 則可以先上傳一個 php文件讀文件 readfile() file_get_contents() highlight()


0x16 Pass-16 二次渲染

源碼

$is_upload = false;
$msg = null;
if (isset($_POST['submit'])){
    // 獲得上傳文件的基本信息,文件名,類型,大小,臨時文件路徑
    $filename = $_FILES['upload_file']['name'];
    $filetype = $_FILES['upload_file']['type'];
    $tmpname = $_FILES['upload_file']['tmp_name'];

    $target_path=UPLOAD_PATH.'/'.basename($filename);

    // 獲得上傳文件的擴展名
    $fileext= substr(strrchr($filename,"."),1);

    //判斷文件后綴與類型,合法才進行上傳操作
    if(($fileext == "jpg") && ($filetype=="image/jpeg")){
        if(move_uploaded_file($tmpname,$target_path)){
            //使用上傳的圖片生成新的圖片
            $im = imagecreatefromjpeg($target_path);

            if($im == false){
                $msg = "該文件不是jpg格式的圖片!";
                @unlink($target_path);
            }else{
                //給新圖片指定文件名
                srand(time());
                $newfilename = strval(rand()).".jpg";
                //顯示二次渲染后的圖片(使用用戶上傳圖片生成的新圖片)
                $img_path = UPLOAD_PATH.'/'.$newfilename;
                imagejpeg($im,$img_path);
                @unlink($target_path);
                $is_upload = true;
            }
        } else {
            $msg = "上傳出錯!";
        }

    }else if(($fileext == "png") && ($filetype=="image/png")){
        if(move_uploaded_file($tmpname,$target_path)){
            //使用上傳的圖片生成新的圖片
            $im = imagecreatefrompng($target_path);

            if($im == false){
                $msg = "該文件不是png格式的圖片!";
                @unlink($target_path);
            }else{
                 //給新圖片指定文件名
                srand(time());
                $newfilename = strval(rand()).".png";
                //顯示二次渲染后的圖片(使用用戶上傳圖片生成的新圖片)
                $img_path = UPLOAD_PATH.'/'.$newfilename;
                imagepng($im,$img_path);

                @unlink($target_path);
                $is_upload = true;               
            }
        } else {
            $msg = "上傳出錯!";
        }

    }else if(($fileext == "gif") && ($filetype=="image/gif")){
        if(move_uploaded_file($tmpname,$target_path)){
            //使用上傳的圖片生成新的圖片
            $im = imagecreatefromgif($target_path);
            if($im == false){
                $msg = "該文件不是gif格式的圖片!";
                @unlink($target_path);
            }else{
                //給新圖片指定文件名
                srand(time());
                $newfilename = strval(rand()).".gif";
                //顯示二次渲染后的圖片(使用用戶上傳圖片生成的新圖片)
                $img_path = UPLOAD_PATH.'/'.$newfilename;
                imagegif($im,$img_path);

                @unlink($target_path);
                $is_upload = true;
            }
        } else {
            $msg = "上傳出錯!";
        }
    }else{
        $msg = "只允許上傳后綴為.jpg|.png|.gif的圖片文件!";
    }
}

這里有個函數imagecreatefromjpeg,作用是由文件或 URL 創建一個新圖象。

原理:

將一個正常顯示的圖片,上傳到服務器。尋找圖片被渲染后與原始圖片 部分對比仍然相同的數據塊部分,將Webshell代碼插在該部分,然后上傳。具體實現需要自己編寫Python程序,人工嘗試基本是不可能構造出能繞過渲染函數的圖片webshell的。

先知上有人針對16關專門開了一帖分析,分析得十分詳細:upload-labs之Pass16

也可以參考國外大神,二次渲染與繞過方法參考連接 https://secgeek.net/bookfresh-vulnerability/

0x17 Apache 換行解析漏洞(CVE-2017-15715)

影響版本:

2.4.0~2.4.29版本

源碼

<?php
if(isset($_FILES['file'])) {
    $name = basename($_POST['name']);
    $ext = pathinfo($name,PATHINFO_EXTENSION);
    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

15223122857686.jpg

然后訪問/1.php%0A,即可發現已經成功getshell:

總結

研究這個漏洞的過程中遇到幾個問題:

  1. 獲取文件名時不能用$_FILES['file']['name'],因為他會自動把換行去掉,這一點有點雞肋

  2. 默認的Apache配置即可利用,因為默認Apache配置就使用了``:

  3. <FilesMatch \.php$>
        SetHandler application/x-httpd-php
    </FilesMatch>
    

所以理論上,只要用正則來匹配后綴進行php解析的Apache就有這個問題。而這個做法剛好是為了解決Apache老的解析漏洞而做的,可謂非此即彼,必然存在一種解析漏洞。

原理

正則中$可以匹配行尾或一個換行符,所以可以上傳一個后綴末尾包含換行符的文件,來繞過FilesMatch。當然繞過FilesMatch不一定就能被PHP解析,所以這個漏洞也需要看情況,比較雞肋


0x18 Pass-18 條件競爭

源碼

*過濾代碼:*unlink()函數作用是刪除文件。若成功,則返回 true,失敗則返回 false。

$is_upload = false;
$msg = null;

if(isset($_POST['submit'])){
    $ext_arr = array('jpg','png','gif');
    $file_name = $_FILES['upload_file']['name'];
    $temp_file = $_FILES['upload_file']['tmp_name'];
    $file_ext = substr($file_name,strrpos($file_name,".")+1);
    $upload_file = UPLOAD_PATH . '/' . $file_name;

    if(move_uploaded_file($temp_file, $upload_file)){
        if(in_array($file_ext,$ext_arr)){
             $img_path = UPLOAD_PATH . '/'. rand(10, 99).date("YmdHis").".".$file_ext;
             rename($upload_file, $img_path);
             $is_upload = true;
        }else{
            $msg = "只允許上傳.jpg|.png|.gif類型文件!";
            unlink($upload_file);
        }
    }else{
        $msg = '上傳出錯!';
    }
}

上面源碼的代碼邏輯:

  1. 首先接收上傳的文件
  2. 然后判斷上傳的文件的文件后綴是否在白名單中
  3. 在白名單中,則將文件重命名
  4. 不在白名單則刪除文件

通過不斷發送請求包,直到訪問shell.php成功為止


0x19 常見中間件解析漏洞

一:IIS 服務器

01:IIS<=6.0 解析漏洞

​ 起因是解析標准不一致,即Web應用程序與IIS服務器對同一個文件的文件名稱(類型)理解不一致造成。

​ *** 利用方法有兩種:**

 1. 畸形目錄解析/xxxx.asp/xxx.jpg
 2. 分號文件解析test.asp;.jpg 
  • 第1種是因為 xxx.jpg文件在某個以.asp結尾的目錄下,而被IIS當成可執行文件來解析
  • 第2中雖然以.jpg結尾,但是IIS解析時忽略了';'分號后面的.jpg,因此就當成test.asp來處理
02: IIS 7.0 & 7.5 畸形解析漏洞

​ 默認fast-cgi開啟狀況下,在一個文件路徑后面加上/xx.php會將原來的文件解析為php文件

​ *** 利用方法有兩種:**

  • 上傳一張圖片馬 test.jpg,然后訪問test.jpg/.php或test.jpg/abc.php 可以被執行。

二:nginx

01:畸形解析漏洞

默認fast-cgi開啟狀況下,在一個文件路徑后面加上/xx.php會將原來的文件解析為php文件

和 IIS7.0&7.5畸形解析漏洞一樣,上傳圖片馬test.jpg,訪問/test.jpg/.php或test.jpg/abc.php 可以被執行

02:空字節代碼執行漏洞

在fast-cgi關閉的情況下,nginx版本:0.5., 0.6., 0.7- 0.7.65, 0.8 -0.8.37,nginx在圖片后附加 php代碼然后通過訪問

 xx.jpg%00.php 

意思是指在上傳了一個圖片馬之后,通過訪問 xx.jpg%00.php 來執行php代碼

03:文件名邏輯漏洞(CVE-2013-4547)

受影響的nginx版本: 0.8.41至1.4.3和1.5.7之前的1.5.x正常上傳一個附加代碼的圖 片"test.jpg",訪問時后面+"空格"+"\0"+".php",即讓圖片作為php文件解析

 "/test.jpg \0.php" 

三:Apache 解析漏洞

apache 是從右到左開始判斷解析文件名,如果為不可識別的后綴名,就再往左判斷,直到可以解析為止,如

test.php.jpegxtxt.xtie    解析成    test.php 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM