文件上傳漏洞 大總結

以下上傳測試使用的HTML表單的代碼爲:

<html>
	<head>
		<title>File Upload</title>
		<meta charset="utf-8">
	</head>
	<body>
		<form action="upload.php" method="POST" enctype="multipart/form-data">
			<input type="hidden" name="MAX_FILE_SIZE" value="1000000">
			選擇文件: <input type="file" name="myfile">
			<input type="submit" value="Upload">
		</form>
	</body>
</html>

前端一般都是使用js來限制我們的上傳類型和文件大小,這裏以upload-labs Pass-01的源碼爲例:

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

2.1 後端檢測文件類型

2.1.1 檢測content-type

後端代碼大致爲:

<?php
$allow_content_type = array("image/gif", "image/png", "image/jpeg");
$path = "./uploads";
$type = $_FILES["myfile"]["type"];

if (!in_array($type, $allow_content_type)) {
        die("File type error!<br>");
} else {
        $file = $path . '/' . $_FILES["myfile"]["name"];
        if (move_uploaded_file($_FILES["myfile"]["tmp_name"], $file)) {
                echo 'Success!<br>';
        } else {
                echo 'Error!<br>';
        }
}
?>

繞過方法:

抓包將content-type改爲圖片形式(即’image/png’等),即可成功上傳

2.1.2 檢測文件頭判斷文件類型

後端代碼大致爲:

<?php
$allow_mime = array("image/gif", "image/png", "image/jpeg");
$imageinfo = getimagesize($_FILES["myfile"]["tmp_name"]);
$path = "./uploads";

if (!in_array($imageinfo['mime'], $allow_mime)) {
        die("File type error!<br>");
} else {
        $file = $path . '/' . $_FILES["myfile"]["name"];
        if (move_uploaded_file($_FILES["myfile"]["tmp_name"], $file)) {
                echo 'Success!<br>';
        } else {
                echo 'Error!<br>';
        }
}
?>

此時雖然檢查的也是文件類型,但是是使用getimagesize()函數來獲取文件的MIME類型,此時檢測的不是數據包中的content-type,而是圖片的文件頭,常見的圖片文件頭如下:

gif(GIF89a) : 47 49 46 38 39 61

jpg、jpeg : FF D8 FF

png : 89 50 4E 47 0D 0A

繞過方法:

當上傳php文件時,可以使用winhex010editor等十六進制處理工具,在數據最前面添加圖片的文件頭,從而繞過檢測

2.2 後端檢測文件擴展名

2.2.1 黑名單檢測

後端代碼大致爲:

<?php
// 實際情況中黑名單內數據會更多更全面
$blacklist = array('php', 'asp', 'aspx', 'jsp');
$path = "./uploads";
$type = array_pop(explode('.', $_FILES['myfile']['name']));

if (in_array(strtolower($type), $blacklist)) {
        die("File type errer!<br>");
} else {
        $file = $path . '/' . $_FILES['myfile']['name'];
        if (move_uploaded_file($_FILES['myfile']['tmp_name'], $file)) {
                echo 'Success!<br>';
        } else {
                echo 'Error!<br>';
        }
}
?>

衆所周知使用黑名單是非常不安全的,很多網站會使用擴展名黑名單來限制上傳文件類型,有些甚至在判斷時都不用strtolower()來處理,因此造成漏洞

繞過方法:

  1. 使用一些特殊擴展名來繞過(如php可以使用php3、php4、php5等來代替)
  2. 在後端比較沒有轉換大小寫處理時,使用大小寫混淆(如將php改爲pHp等)來繞過

2.2.2 白名單檢測

大致代碼如下,與黑名單檢測沒有太大差別:

<?php
$whitelist = array('png', 'jpg', 'jpeg', 'gif');
$path = "./uploads";
$type = array_pop(explode('.', $_FILES['myfile']['name']));

if (!in_array(strtolower($type), $whitelist)) {
        die("File type errer!<br>");
} else {
        $file = $path . '/' . $_FILES['myfile']['name'];
        if (move_uploaded_file($_FILES['myfile']['tmp_name'], $file)) {
                echo 'Success!<br>';
        } else {
                echo 'Error!<br>';
        }
}

白名單相對與黑名單就安全許多,要求只能是特定擴展名的文件才能上傳,雖然我們無法從代碼層面來繞過,但這樣也不是絕對的安全,可以利用其他漏洞來繞過

繞過方法:

  1. 使用%00截斷文件名來上傳(後面會講)
  2. 如果目標還存在文件包含漏洞,那麼就可以上傳圖片馬再文件包含來拿shell

2.3 後端檢測文件內容

2.3.1 文件內容替換

這種主要是將文件中的敏感字符替換掉,大致代碼類似於下面這樣:

<?php
$path = "./uploads";
$content = file_get_contents($_FILES['myfile']['tmp_name']);
$content = str_replace('?', '!', $content);
$file = $path . '/' . $_FILES['myfile']['name'];

if (move_uploaded_file($_FILES['myfile']['tmp_name'], $file)) {
        file_put_contents($file, $content);
        echo 'Success!<br>';
} else {
        echo 'Error!<br>';
}
?>

繞過方法:

主要還是要根據實際過濾的字符來判斷,如果寫死的話可能是沒辦法的(一般不會,因爲還要兼顧圖片上傳)

比如過濾掉問號,我們就可以使用<script language='php'>system('ls');</script>這樣的一句話。具體方法要看實際代碼過濾了哪些字符。

2.3.2 圖片二次渲染

這個情況自己平時沒有遇到過,是在syclover的一個paper中看到的

大致意思是後端調用了php的GD庫,提取了文件中的圖片數據,然後再重新渲染,這樣圖片中插入的惡意代碼就會被過濾掉了,可以參考一下upload-labs Pass-16中二次渲染的代碼:

$is_upload = false;
$msg = null;
if (isset($_POST['submit'])){
    // 獲得上傳文件的基本信息,文件名,類型,大小,臨時文件路徑
    $filename = $_FILES['upload_file']['name'];
    $filetype = $_FILES['upload_file']['type'];
    $tmpname = $_FILES['upload_file']['tmp_name'];

    $target_path=UPLOAD_PATH.'/'.basename($filename);

    // 獲得上傳文件的擴展名
    $fileext= substr(strrchr($filename,"."),1);

    //判斷文件後綴與類型,合法才進行上傳操作
    if(($fileext == "jpg") && ($filetype=="image/jpeg")){
        if(move_uploaded_file($tmpname,$target_path)){
            //使用上傳的圖片生成新的圖片
            $im = imagecreatefromjpeg($target_path);

            if($im == false){
                $msg = "該文件不是jpg格式的圖片!";
                @unlink($target_path);
            }else{
                //給新圖片指定文件名
                srand(time());
                $newfilename = strval(rand()).".jpg";
                //顯示二次渲染後的圖片(使用用戶上傳圖片生成的新圖片)
                $img_path = UPLOAD_PATH.'/'.$newfilename;
                imagejpeg($im,$img_path);
                @unlink($target_path);
                $is_upload = true;
            }
        } else {
            $msg = "上傳出錯!";
        }
...

詳細的可以查看:http://www.owasp.org.cn/OWASP_Training/Upload_Attack_Framework.pdf

3.1 解析漏洞及其他漏洞

3.1.1 IIS解析漏洞

1.IIS6.0

在IIS6.0中有兩個很重要的asp解析漏洞:

  1. 假設當前有一個名爲”xxx.asp”的目錄,那麼該目錄下的所有文件都將被作爲asp文件解析
  2. 假設上傳一個名爲”test.asp;xxx.jpg”時,該文件會被當做asp文件解析

2.IIS7.5

在該版本的IIS中存在一個php的解析漏洞,但這個漏洞利用條件是服務器在php.ini中將cgi.fix_pathinfo的值設置爲1

然後當我們訪問服務器上任意一個文件時(如:http://test.com/a.jpg),當我們在URL後面添加.php(即:http://test.com/a.jpg/.php),那麼文件a.jpg就將被作爲php文件來解析

3.1.2 Apache解析漏洞

1.利用低版本apache擴展名解析特性

在瞭解這個解析漏洞之前,我們要首先了解apache和php的三種結合方式:

Apache和php三種結合方式: 1.CGI 2.Module 3.FastCGI

該解析漏洞只有在apache和php以Module方式結合時才存在,而且Apache還有一個特性:

Apache在解析文件時會以文件名從右向左解析,當最後一個擴展名無法識別時,就會向左查看是否有可以識別的文件名,如果沒有的話就以配置中的默認文件類型來解析 例如: a.php.xxx因爲xxx無法識別,而左邊的php可識別,就會被解析爲php文件

因此,如果上傳文件名爲a.php.xxx的一句話,訪問後就很可能拿到shell

2.CVE-2017-15715

還有一個apache的解析漏洞就是CVE-2017-15715,這個漏洞利用方式就是上傳一個文件名最後帶有換行符(只能是\x0A,如上傳a.php,然後在burp中在文件名最後添上\x0A),以此來繞過一些黑名單過濾

具體的漏洞分析可以看p牛:https://www.leavesongs.com/PENETRATION/apache-cve-2017-15715-vulnerability.html

3.1.3 nginx解析漏洞

nginx有一個和IIS7.5差不多的解析漏洞。其實這個漏洞的成因不在nginx和IIS,而是因爲php-cgi的配置問題才導致的漏洞。漏洞的條件和利用方法和前面講的IIS7.5相同。

似乎nginx還有一個%00的解析漏洞(不是截斷,而是在訪問test.jpg時在其後添加%00.php,然後test.jpg會被作爲php文件解析),但是存在於很早之前的版本中,查了一下是以下版本:0.5.x, 0.6.x, 0.7 <= 0.7.65, 0.8 <= 0.8.37

3.1.4 %00截斷

這個多數被利用在截斷路徑,利用的條件是:

PHP < 5.3.4

magic_quotes_gpc 關閉

因爲0x00是字符串的結束標誌符,所以php在讀取到0x00時就不會再往後讀取,我們可以利用這些截斷字符後面不需要的內容

以upload-labs的Pass-12爲例,源碼如下:

$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 = $_POST['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類型文件!";
    }
}

由於是白名單限制了上傳文件類型,因此我們無法在文件名處做文章。但最終move_uploaded_file()的目標目錄是我們可控的,我們可以將POST傳入的save_path改爲../upload/shell.php%00,這樣後面的內容就會被截斷掉,這就導致了任意文件上傳

還要注意的是%00是url編碼,在以POST傳參時應該使用burpsuite對其進行url decode,或者修改hex值爲00;當GET傳參時因爲瀏覽器會做一遍url decode,所以直接傳%00即可。

3.1.5 利用.htaccess解析

.htaccess文件(或者”分佈式配置文件”),全稱是Hypertext Access(超文本入口)。提供了針對目錄改變配置的方法, 即,在一個特定的文檔目錄中放置一個包含一個或多個指令的文件, 以作用於此目錄及其所有子目錄。作爲用戶,所能使用的命令受到限制。管理員可以通過Apache的AllowOverride指令來設置。

利用.htaccess的條件:Apache中配置AllowOverride All

.htaccess文件可以配置將特定的文件按規定的文件類型進行解析,可以用以下兩種方式來配置:

<FilesMatch "test">
  SetHandler application/x-httpd-php
</FilesMatch>

這一種採用正則匹配,只要文件名爲test的文件都將被作爲php文件解析

AddType application/x-httpd-php .jpg

第二種是將.jpg文件都作爲php文件解析

這樣我們如果能將.htaccess上傳到服務器的話,就可以再根據我們自己設定的規則來解析上傳的文件,以此來繞過上傳過濾

轉自:https://loong716.top/2019/08/14/File-Upload.html
作者:Loong716

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章