0x00 任務
1、編寫一個上傳圖檔的功能頁面
2、針對上傳的檔案進行驗證(字尾驗證、檔案頭驗證、檔案名驗證等)
3、檔案上傳通常會與檔案解析漏洞相結合,可以收集整理存在解析漏洞的元件和相關版本,無法部署相關環境,可以學習相關技術,不用實際操作
擴充學習:學習如何繞過黑名單驗證、檔案頭驗證,如何杜絕上傳圖檔的功能無法利用擷取 shell ?
0x01 用戶端檢測
(1)字尾檢測(使用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;
}
}
函數解釋
getElementsByName()
方法可傳回帶有指定名稱的對象的集合。
document.getElementsbyname(name)[0].value
document.getElementsbyname(name)的意思就是擷取目前頁面上指定name名稱的對象集合
頁面上有可能不止一個叫name的對象,是以[0]就是擷取第一個
Substring()
例如:
string front = null;
string back = null;
string str = "abcdefg";
front = str.Substring(0, 1);//從第一個開始截取,共截取一位
back = str.Substring(str.Length - 1, 1);//從最後一個開始截取,共截取一位
Response.Write(front + "***" + back);
輸出效果:a***g
lastIndexOf()
例如:
string str = "abcdefg";
str = str.Substring(0, str.LastIndexOf("c"));
Response.Write(str);
輸出效果:ab
就是截取c前面的字元串。
indexOf()
stringObject.indexOf(searchvalue,fromindex)
該方法将從頭到尾地檢索字元串 stringObject,看它是否含有子串 searchvalue。開始檢索的位置在字元串的 fromindex 處或字元串的開頭(沒有指定 fromindex 時)。如果找到一個 searchvalue,則傳回 searchvalue
的第一次出現的位置。stringObject 中的字元位置是從 0 開始的。indexOf() 方法對大小寫敏感!如果要檢索的字元串值沒有出現,則該方法傳回 -1。
繞過方式
可以利用burp抓包改包,先上傳一個gif類型的木馬,然後通過burp将其改為asp/php/jsp字尾名即可
0x02 服務端檢測
(1)檔案類型(MIME類型檢測)
$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
if (file_exists($UPLOAD_ADDR))
{
if (($_FILES['upload_file']['type'] == 'image/jpeg') || ($_FILES['upload_file']['type'] == 'image/png') || ($_FILES['upload_file']['type'] == 'image/gif'))
{
if (move_uploaded_file($_FILES['upload_file']['tmp_name'], $UPLOAD_ADDR . '/' . $_FILES['upload_file']['name']))
{
$img_path = $UPLOAD_ADDR . $_FILES['upload_file']['name'];
$is_upload = true;
}
}
else $msg = '檔案類型不正确,請重新上傳!';
}
else $msg = $UPLOAD_ADDR.'檔案夾不存在,請手工建立!';
}
函數解釋
$_FILES['myFile']['type']
檔案的 MIME 類型,需要浏覽器提供該資訊的支援,例如"image/gif"。
move_uploaded_file() 函數将上傳的檔案移動到新位置。若成功,則傳回 true,否則傳回 false。
文法move_uploaded_file(file,newloc) 其中newloc是新的位置。
繞過方式
檢測上傳到伺服器的檔案類型,在 burp 抓包可以看到類似于 Content-Type: image/gif
使用 burp 抓包,上傳本地檔案 muma.php
在 burp 的 request 包裡可以看到Content-Type: text/plain
修改:Content-Type: text/plain -> Content-Type: image/gif
像這種服務端檢測http 包的Content-Type 都可以用這種類似的方法來繞過檢測
(2)字尾檢測(黑名單)
$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
if (file_exists($UPLOAD_ADDR)) {
$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))
{
if (move_uploaded_file($_FILES['upload_file']['tmp_name'], $UPLOAD_ADDR. '/' . $_FILES['upload_file']['name']))
{
$img_path = $UPLOAD_ADDR .'/'. $_FILES['upload_file']['name'];
$is_upload = true;
}
}
else $msg = '不允許上傳.asp,.aspx,.php,.jsp字尾檔案!';
}
else $msg = $UPLOAD_ADDR . '檔案夾不存在,請手工建立!';
}
函數解釋
(1)trim() 函數移除字元串兩側的空白字元或其他預定義字元。
trim(string,charlist)
string 必需。規定要檢查的字元串。
charlist 可選。規定從字元串中删除哪些字元。如果被省略,則移除以下所有字元:
“\0” - NULL
“\t” - 制表符
“\n” - 換行
“\x0B” - 垂直制表符
“\r” - 回車
" " - 空格
(2)strrchr() 函數查找字元在指定字元串中從後面開始的第一次出現的位置,如果成功,則傳回從該位置到字元串結尾的所有字元,如果失敗,則傳回 false。
(3)str_ireplace() 函數替換字元串中的一些字元(不區分大小寫)
文法str_ireplace(find,replace,string,count)
參數 描述
find 必需。規定要查找的值。
replace 必需。規定替換 find 中的值的值。
string 必需。規定被搜尋的字元串。
count 可選。一個變量,對替換數進行計數。
(4)in_array() 函數搜尋數組中是否存在指定的值。
注釋:如果 search 參數是字元串且 type 參數被設定為 TRUE,則搜尋區分大小寫。
文法in_array(search,array,type)
繞過方式
不允許上傳
.asp,.aspx,.php,.jsp
字尾檔案,但是可以上傳其他任意字尾
.php .phtml .phps .php5 .pht
前提是apache的
httpd.conf
中有如下配置代碼
AddType application/x-httpd-php .php .phtml .phps .php5 .pht
或者上傳
.htaccess
檔案:
(3).htaccess(沒過濾.htaccess)
需要條件:
1.
mod_rewrite子產品開啟
2.
AllowOverride All
檔案内容
<FilesMatch "shell.jpg">
SetHandler application/x-httpd-php
</FilesMatch>
此時上傳
shell.jpg
檔案即可被當作php來解析。
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsICM38FdsYkRGZkRG9lcvx2bjxiNx8VZ6l2cs0TPR1keBpnTxkFVNBDOsJGcohVYsR2MMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2X0hXZ0xCMx81dvRWYoNHLrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZuBnL2YjM5IDN0QTM1ETMwAjMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
或者
AddType application/x-httpd-php .jpg
另外基本上所有的黑名單都可以用Apache解析漏洞繞過。
0x03 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);//找到.的位置+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類型檔案!";
}
函數解釋
strrpos() 函數查找字元串在另一字元串中最後一次出現的位置。傳回字元串在另一字元串中最後一次出現的位置,如果沒有找到字元串則傳回 FALSE
注釋:strrpos() 函數對大小寫敏感。
strrpos(string,find,start)
參數 | 描述 |
---|---|
string | 必需。規定被搜尋的字元串。 |
find | 必需。規定要查找的字元。 |
start | 可選。規定在何處開始搜尋。 |
substr() 函數傳回字元串的一部分。
注釋:如果 start 參數是負數且 length 小于或等于 start,則 length 為 0。
文法:substr(string,start,length)
繞過方式
CVE-2015-2348影響版本:
5.4.x<= 5.4.39, 5.5.x<= 5.5.23, 5.6.x <= 5.6.7
exp:move_uploaded_file($_FILES['name']['tmp_name'],"/file.php\x00.jpg");
源碼中
move_uploaded_file
中的
save_path
可控,是以00截斷即可。
0x04 繞過總結
用戶端繞過
可以利用burp抓包改包,先上傳一個gif類型的木馬,然後通過burp将其改為asp/php/jsp字尾名即可。
服務端繞過
檔案類型繞過
我們可以通過抓包,将content-type字段改為image/gif
檔案頭繞過
在木馬内容基礎上再加了一些檔案資訊,有點像下面的結構
GIF89a<?php phpinfo(); ?>
還有PE的MZ頭,JPG的JFIF等等,GIF的GIF89a
檔案字尾名繞過
前提:黑名單校驗
黑名單檢測:一般有個專門的 blacklist 檔案,裡面會包含常見的危險腳本檔案。
繞過方法:
(1)找黑名單擴充名的漏網之魚 - 比如 asa 和 cer 之類
(2)可能存在大小寫繞過漏洞 - 比如 aSp 和 pHp 之類
能被解析的檔案擴充名清單:
jsp jspx jspf
asp asa cer aspx
php php php3 php4
exe exee
配合檔案包含漏洞
前提:校驗規則隻校驗當檔案字尾名為asp/php/jsp的檔案内容是否為木馬。
繞過方式:(這裡拿php為例,此漏洞主要存在于PHP中)
(1)先上傳一個内容為木馬的txt字尾檔案,因為字尾名的關系沒有檢驗内容;
(2)然後再上傳一個.php的檔案,内容為
<?php Include(“上傳的txt檔案路徑”);?>
此時,這個php檔案就會去引用txt檔案的内容,進而繞過校驗,下面列舉包含的文法:
#PHP
<?php Include("上傳的txt檔案路徑");?>
\#ASP
<!--#include file="上傳的txt檔案路徑" -->
\#JSP
<jsp:inclde page="上傳的txt檔案路徑"/>
or
<%@include file="上傳的txt檔案路徑"%>
配合伺服器解析漏洞
詳細可參考:http://thief.one/2016/09/21/伺服器解析漏洞/
配合作業系統檔案指令規則
(1)上傳不符合windows檔案命名規則的檔案名
test.asp.
test.asp(空格)
test.php:1.jpg
test.php::$DATA
shell.php::$DATA…….
會被windows系統自動去掉不符合規則符号後面的内容。
(2)linux下字尾名大小寫
在linux下,如果上傳php不被解析,可以試試上傳pHp字尾的檔案名。
CMS、編輯器漏洞
(1)CMS漏洞:比如說JCMS等存在的漏洞,可以針對不同CMS存在的上傳漏洞進行繞過。
(2)編輯器漏洞:比如FCK,ewebeditor等,可以針對編輯器的漏洞進行繞過。
這兩方面的漏洞以後單獨成文彙總,這裡點到為止。
配合其他規則
(1)0x00截斷:基于一個組合邏輯漏洞造成的,通常存在于構造上傳檔案路徑的時候
test.php(0x00).jpg
test.php%00.jpg
路徑/upload/1.php(0x00),檔案名1.jpg,結合/upload/1.php(0x00)/1.jpg
僞代碼示範:
name= getname(httprequest) //假如這時候擷取到的檔案名是 help.asp.jpg(asp 後面為 0x00)
type =gettype(name) //而在 gettype()函數裡處理方式是從後往前掃描擴充名,是以判斷為 jpg
if(type == jpg)
SaveFileToPath(UploadPath.name, name) //但在這裡卻是以 0x00 作為檔案名截斷
//最後以 help.asp 存入路徑裡
WAF繞過
垃圾資料
有些主機WAF軟體為了不影響web伺服器的性能,會對校驗的使用者資料設定大小上限,比如1M。此種情況可以構造一個大檔案,前面1M的内容為垃圾内容,後面才是真正的木馬内容,便可以繞過WAF對檔案内容的校驗;
0x05 參考文章
檔案上傳驗證繞過技術總結
upload-labs
圖檔馬二次渲染
upload超全