文件上傳學習
一、編寫一個文件上傳的頁面
代碼參考菜鳥教程:https://www.runoob.com/php/php-file-upload.html
結構:
test
|-----upload # 文件上傳的目錄
|-----form.html # 表單文件
|-----upload_file.php # php 上傳代碼
創建文件上傳表單
<html>
<head>
<meta charset="utf-8">
<title>文件上了個傳</title>
</head>
<body>
<form action="upload_file.php" method="post" enctype="multipart/form-data">
<label for="file">文件名:</label>
<input type="file" name="file" id="file"><br>
<input type="submit" name="submit" value="提交">
</form>
</body>
</html>
創建文件上傳腳本
<?php
if ($_FILES["file"]["error"] > 0)
{
echo "錯誤:: " . $_FILES["file"]["error"] . "<br>";
}
else
{
echo "上傳文件名: " . $_FILES["file"]["name"] . "<br>";
echo "文件類型: " . $_FILES["file"]["type"] . "<br>";
echo "文件大小: " . ($_FILES["file"]["size"] / 1024) . " kB<br>";
echo "文件臨時存儲的位置: " . $_FILES["file"]["tmp_name"] . "<br>";
// 判斷當前目錄下的 upload 目錄是否存在該文件
// 如果沒有 upload 目錄,你需要創建它,upload 目錄權限為 777
if (file_exists("upload/" . $_FILES["file"]["name"]))
{
echo $_FILES["file"]["name"] . " 文件已經存在。 ";
}
else
{
// 如果 upload 目錄不存在該文件則將文件上傳到 upload 目錄下
move_uploaded_file($_FILES["file"]["tmp_name"], "upload/" . $_FILES["file"]["name"]);
echo "文件存儲在: " . "upload/" . $_FILES["file"]["name"];
}
}
?>
測試:



二、對上傳的文件進行驗證
1.文件名驗證
<?php
// 允許上傳的圖片后綴
$allowedExts = array("gif", "jpeg", "jpg", "png");
$temp = explode(".", $_FILES["file"]["name"]);
echo $_FILES["file"]["size"];
$extension = end($temp); // 獲取文件后綴名
if ((($_FILES["file"]["type"] == "image/gif")
|| ($_FILES["file"]["type"] == "image/jpeg")
|| ($_FILES["file"]["type"] == "image/jpg")
|| ($_FILES["file"]["type"] == "image/pjpeg")
|| ($_FILES["file"]["type"] == "image/x-png")
|| ($_FILES["file"]["type"] == "image/png"))
&& ($_FILES["file"]["size"] < 204800) // 小于 200 kb
&& in_array($extension, $allowedExts))
{
if ($_FILES["file"]["error"] > 0)
{
echo "錯誤:: " . $_FILES["file"]["error"] . "<br>";
}
else
{
echo "上傳文件名: " . $_FILES["file"]["name"] . "<br>";
echo "文件類型: " . $_FILES["file"]["type"] . "<br>";
echo "文件大小: " . ($_FILES["file"]["size"] / 1024) . " kB<br>";
echo "文件臨時存儲的位置: " . $_FILES["file"]["tmp_name"] . "<br>";
// 判斷當前目錄下的 upload 目錄是否存在該文件
// 如果沒有 upload 目錄,你需要創建它,upload 目錄權限為 777
if (file_exists("upload/" . $_FILES["file"]["name"]))
{
echo $_FILES["file"]["name"] . " 文件已經存在。 ";
}
else
{
// 如果 upload 目錄不存在該文件則將文件上傳到 upload 目錄下
move_uploaded_file($_FILES["file"]["tmp_name"], "upload/" . $_FILES["file"]["name"]);
echo "文件存儲在: " . "upload/" . $_FILES["file"]["name"];
}
}
}
else
{
echo "非法的文件格式";
}
?>
測試功能:上傳一個PHP文件試試


發現不允許PHP文件上傳
2.文件頭驗證
<?php
function getReailFileType($filename){
$file = fopen($filename, "rb");
$bin = fread($file, 2); //只讀2字節
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;
if(isset($_POST['submit'])){
$temp_file = $_FILES["file"]["tmp_name"];
$file_type = getReailFileType($temp_file);
if($file_type == 'unknown'){
echo"文件未知,上傳失?。?;
}else{
$img_path = $img_path = "upload/" . $_FILES["file"]["name"];
if(move_uploaded_file($temp_file,$img_path)){
$is_upload = true;
echo "成功上傳";
} else {
echo"上傳出錯!";
}
}
}
?>
測試:
嘗試上傳異常gif文件失敗


將.php文件添加頭GIF89a,成功上傳


三、文件上傳結合解析漏洞
1.apache解析漏洞
(1)從右往左解析
Apache解析文件的時候是從右往左開始解析文件名,
比如test.php.abc.def
由于從右往左解析,遇到不支持的文件后綴名的時候繼續往左解析,所以的話就會把該文件解析成test.php
(2)Apache HTTPD是一款HTTP服務器,它可以通過mod_php來運行PHP網頁。其2.4.0~2.4.29版本中存在一個解析漏洞,在解析PHP時,1.php\x0A將被按照PHP后綴進行解析,導致繞過一些服務器的安全策略。
比如:1.php上傳被過濾之后可以burp抓包,然后更改為1.php\x0a可以上傳成功。
(3).htaccess文件實現
如果當你上傳文件的時候發現你的腳本文件被阻止上傳,你可以嘗試上傳.htaccess文件。在.htaccess文件里面將你的文件擴展名映射到可執行MIME類型。只需要添加一句話:
AddType application/x-httpd-php .html(則html文件也能執行.php文件)
AddType application/x-httpd-php .txt(則普通的文本文檔也能執行.php文件)

2.IIS解析漏洞
(1)IIS6.0
路徑解析
原理:在.asp、.asa目錄下的任意文件都會以asp格式解析
文件解析(;截斷)。
原理:在IIS 6.0下,服務器默認不解析;后面的內容。
上傳test.asp;.jpg會被解析為asp。
解析文件類型
原理:IIS 6.0默認的可執行文件除了asp還包含asa、cer、cdx,會將這三種擴展名文件解析為asp文件。
(2)IIS7.5
利用條件:
Fast-CGI運行模式
php.ini里cgi.fix_pathinfo=1
取消勾選php-cgi.exe程序的"invoke handler only if request is mapped to"。也就是取消勾選模塊映射中的請求限制。
利用方式:在上傳的文件名后面加上/.php,可以被作為PHP文件解析。

3.nginx解析漏洞
上傳一個圖片馬,當中間件的版本是nginx的時候,增加/.php后綴,被解析成PHP文件。
比如上傳1.png。訪問upload/1.png/.php會把1.png當作php文件執行。
將.php結尾的文件都會交給fastcgi來執行,/uploadfiles/nginx.png/a.php也會交給fastcgi解析,fastcgi在解析".php"文件時發現文件并不存在,這時php.ini配置文件中的cig.fix_pathinfo就發揮作用了,ccgi.fix_pathinfo是默認開啟的,當php遇到文件路徑/aaa.xxx/bbb.yyy/ccc.zzz時,若/aaa.xxx/bbb.yyy/ccc.zzz不存在,則會去掉最后的/ccc.zzz,然后判斷/aaa.xxx/bbb.yyy是否存在,若存在,則把/aaa.xxx/bbb.yyy文件當作文件/aaa.xxx/bbb.yyy/ccc.zzz解析,若/aaa.xxx/bbb.yyy仍不存在,則繼續去掉/bbb.yyy,以此類推。那么fastcgi到底能解析哪些文件呢,這個由php-fpm.conf中的security.limit_extensions參數決定的,
四、文件上傳繞過
1.繞過黑名單驗證
黑名單:不允許上傳出現在名單中的文件后綴
白名單:只允許上傳出現在名單中的文件后綴
方法:
- 大小寫繞過
- 添加點空格點繞過
- 特殊后綴名比如phps、php5、pht等沒有出現在黑名單中的文件類型
- 上傳.htaccess文件,添加解析類型
- .ini沒禁 所以可以上傳.user.ini文件 內容是 auto_prepend_file=1.jpg讓所有php文件都“自動”包含1.jpg文件
- 沒有對后綴名中的’::$DATA’進行過濾 在php+windows的情況下文件名+"::$DATA"會把::$DATA之后的數據當成文件流處理,不會檢測后綴名 且保持"::$DATA"之前的文件名
- %00截斷:在URL中%00表示ASCII碼中的0,而0作為特殊字符保留,表示字符結束,當url中出現%00時就會認為讀取已結束,而忽略后面上傳的文件或圖片,只上傳截斷前的文件或圖片
2.繞過白名單驗證
- 上傳圖片馬,如果是驗證文件頭的話,在圖片馬的開頭添加文件頭即可,然后結合文件包含漏洞去利用
3.二次渲染繞過
- 如果是先將文件上傳,然后再進行渲染的話,存在一個條件競爭問題,可以一直發包,利用渲染的空擋去解析
- 先上傳圖片,然后下載,將兩者進行對比,在沒有發生變化的位置進行插入PHP代碼,然后去上傳。
五、文件上傳防御
1.運行階段的防御
- 文件上傳的目錄設置為不可執行。只要web容器無法解析該目錄下面的文件,即使攻擊者上傳了腳本文件,服務器本身也不會受到影響。
- 判斷文件類型。在判斷文件類型時,可以結合使用MIME Type、后綴檢查等方式。在文件類型檢查中,強烈推薦白名單方式,黑名單的方式已經無數次被證明是不可靠的。此外,對于圖片的處理,可以使用壓縮函數或者resize函數,在處理圖片的同時破壞圖片中可能包含的HTML代碼。
- 使用隨機數改寫文件名和文件路徑。文件上傳如果要執行代碼,則需要用戶能夠訪問到這個文件。在某些環境中,用戶能上傳,但不能訪問。如果應用了隨機數改寫了文件名和路徑,將極大地增加攻擊的成本。再來就是像shell.php.rar.rar和crossdomain.xml這種文件,都將因為重命名而無法攻擊。
- 單獨設置文件服務器的域名。由于瀏覽器同源策略的關系,一系列客戶端攻擊將失效,比如上傳crossdomain.xml、上傳包含Javascript的XSS利用等問題將得到解決。
- 使用安全設備防御。文件上傳攻擊的本質就是將惡意文件或者腳本上傳到服務器,專業的安全設備防御此類漏洞主要是通過對漏洞的上傳利用行為和惡意文件的上傳過程進行檢測。惡意文件千變萬化,隱藏手法也不斷推陳出新,對普通的系統管理員來說可以通過部署安全設備來幫助防御。
2.開發階段防御
對文件上傳漏洞來說,最好能在客戶端和服務器端對用戶上傳的文件名和文件路徑等項目分別進行嚴格的檢查。客戶端的檢查雖然對技術較好的攻擊者來說可以借助工具繞過,但是這也可以阻擋一些基本的試探。服務器端的檢查最好使用白名單過濾的方法,這樣能防止大小寫等方式的繞過,同時還需對%00截斷符進行檢測,對HTTP包頭的content-type也和上傳文件的大小也需要進行檢查。
3.維護階段防御
- 系統上線后運維人員應有較強的安全意思,積極使用多個安全檢測工具對系統進行安全掃描,及時發現潛在漏洞并修復。
- 定時查看系統日志,web服務器日志以發現入侵痕跡。定時關注系統所使用到的第三方插件的更新情況,如有新版本發布建議及時更新,如果第三方插件被爆有安全漏洞更應立即進行修補。
- 對于整個網站都是使用的開源代碼或者使用網上的框架搭建的網站來說,尤其要注意漏洞的自查和軟件版本及補丁的更新,上傳功能非必選可以直接刪除。除對系統自身的維護外,服務器應進行合理配置,非必選一般的目錄都應去掉執行權限,上傳目錄可配置為只讀。

浙公網安備 33010602011771號