文件上傳bypass安全狗

0x00 前言

 

本文首發於先知社區://xz.aliyun.com/t/9507

 

我們知道WAF分為軟WAF,如某狗,某盾等等;雲WAF,如阿里雲CDN,百度雲CDN等等;硬WAF,如天融信,安恆等等,無論是軟WAF、雲WAF還是硬WAF,總體上繞過的思路都是讓WAF無法獲取到文件名或者其他方式無法判斷我們上傳的木馬(PHP、JSP、ASP、ASPX等等)。

 

這裡總結下關於軟waf中那些繞過文件上傳的姿勢和嘗試思路,這裡選擇繞過的軟waf為某狗4.0,可能其他軟waf在攔截關鍵字方面可能會有差異,但繞過軟waf的大體思想都是相同的,如果文章中有錯誤,歡迎師傅們斧正。

 

0x01 初探原理

 

寫這篇文章時想過一個問題,如何總結哪些屬於文件上傳Bypass的範疇?打個比方:

 

上傳正常.jpg的圖片 #成功
上傳正常.php #攔截
繞過.php文件的filename後進行上傳 #成功
使用繞過了filename的姿勢上傳惡意.php #攔截

以上這麼個邏輯通常來講是waf檢測到了正文的惡意內容。再繼續寫的話就屬於免殺的範疇了,過於模糊並且跑題了,並不是真正意義上的文件上傳Bypass,那是寫不完的。

 

上傳文件時waf會檢查哪裡?

 

請求的url
Boundary邊界
MIME類型
文件擴展名
文件內容

 

常見擴展名黑名單:

 

asp|asa|cer|cdx|aspx|ashx|ascx|asax
php|php2|php3|php4|php5|asis|htaccess
htm|html|shtml|pwml|phtml|phtm|js|jsp
vbs|asis|sh|reg|cgi|exe|dll|com|bat|pl|cfc|cfm|ini

個人寫的「稍微」全一點,實際上waf的黑名單就不一定這麼全了。

 

測試時的準備工作:

 

  • 什麼語言?什麼容器?什麼系統?都什麼版本?
  • 上傳文件都可以上傳什麼格式的文件?還是允許上傳任意類型?
  • 上傳的文件會不會被重命名或者二次渲染?

 

0x02 環境介紹

 

實驗環境:mysql + apache +php

 

waf:某狗4.0

 

這裡用了一個簡單的上傳頁面判斷,觀察程式碼可以發現只允許上傳Content-Type為image/gif、image/jpeg、image/pjpeg三種形式的文件

 

<html>
<body>

<form action="upload.php" method="post"
enctype="multipart/form-data">
<label for="file">Filename:</label>
<input type="file" name="file" id="file" /> 
<br />
<input type="submit" name="submit" value="Submit" />
</form>

</body>
</html>
<?php
error_reporting(0);
if ((($_FILES["file"]["type"] == "image/gif")
|| ($_FILES["file"]["type"] == "image/jpeg")
|| ($_FILES["file"]["type"] == "image/pjpeg")))
//&& ($_FILES["file"]["size"] < 20000))
  {
  if ($_FILES["file"]["error"] > 0)
    {
    echo "Return Code: " . $_FILES["file"]["error"] . "<br />";
    }
  else
    {
    echo "Upload: " . $_FILES["file"]["name"] . "<br />";
    echo "Type: " . $_FILES["file"]["type"] . "<br />";
    echo "Size: " . ($_FILES["file"]["size"] / 1024) . " Kb<br />";
    echo "Temp file: " . $_FILES["file"]["tmp_name"] . "<br />";

    if (file_exists("upload/" . $_FILES["file"]["name"]))
      {
      echo $_FILES["file"]["name"] . " already exists. ";
      }
    else
      {
      move_uploaded_file($_FILES["file"]["tmp_name"],
      "upload/" . $_FILES["file"]["name"]);
      echo "Stored in: " . "upload/" . $_FILES["file"]["name"];
      }
    }
  }
else
  {
  echo "Invalid file";
  }
?>

 

0x03 實驗bypass

 

先上傳一個asp,看一下返回值

 

 

這裡看到了404xxxdog的頁面,那應該是攔截了,我這裡先放過去看看,果然是某狗攔截了

 

 

開始嘗試繞waf

 

這裡我先把Content-Type改成image/gif通用圖片類型

 

 

0x03.1 增大文件大小

 

測試發現 waf對於Content-Disposition欄位的 長度驗證不是很準確,因為我們可以想到它進行攔截的規則肯定是基於正則,那麼我們想辦法讓安全狗攔截的正則匹配不到即可

 

這裡附一個對Content-Disposition欄位的解釋

 

在常規的 HTTP 應答中,Content-Disposition 響應頭指示回復的內容該以何種形式展示,是以內聯的形式(即網頁或者頁面的一部分),還是以附件的形式下載並保存到本地。
在 multipart
/form-data 類型的應答消息體中,Content-Disposition 消息頭可以被用在 multipart 消息體的子部分中,用來給出其對應欄位的相關資訊。各個子部分由在Content-Type 中定義的分隔符分隔。用在消息體自身則無實際意義。 Content-Disposition 消息頭最初是在 MIME 標準中定義的,HTTP 表單及 POST 請求只用到了其所有參數的一個子集。只有 form-data 以及可選的 name 和 filename 三個參數可以應用在HTTP場景中。

 

這裡對這個欄位的長度進行篡改,繞過成功

 

 

0x03.2 對文件名修改(卒)

 

我們在上傳時候通常會把文件名後綴和解析漏洞,那麼waf對於filename參數後的值的文件名後綴肯定是要正則去匹配的 這樣正常上傳肯定不行

 

 那麼繞過之前我們猜想,第一個它可能是對filename這樣的鍵值對進行匹配,例如”ket = val”這樣的鍵值對 那麼這裡我們就是filename=「shell.php」 

 

那這裡把雙引號去除,擾亂匹配,發現不行

 

 

那麼我們可不可以多一個filename,因為文件在接收上傳文件名時取的是最後一個filename,那麼我們在最後一個filename參數前加一些干擾的filename參數試試

 

 

發現還是不行  那麼這裡就知道他是對所有filename參數進行檢測  那麼我們能不能把前面的filename參數去掉值呢

 

Content-Disposition: form-data; name="file"; filename= ;  filename="shell.php"

 

 

結果對文件名進行修改全卒,在之前版本的某狗在filename= ;是可以進行繞過的,4.0版本文件名修改全卒 

 

0x03.3 修改文件名後綴

 

經典的apache解析漏洞嘗試,攔截

 

 

可以在文件名中間加符號擾亂某狗匹配,經測試 “;” ” ” ” ‘ ” 均可

 

 

 

 

0x03.4 對filename動手腳

 

這裡可以讓waf對filename這個字元串匹配不到,但是伺服器又可以接收,加入換行這類的干擾

 

先測試單個字元進行換行,都失敗

 

 

 

切斷filename= 和 之後的值,則可以繞過

 

 

文件名換行,即hex加入0a,也可以繞過

 

 

 

0x03.5 修改匹配欄位(卒)

 

我們的filename參數是在post包中的 Content-Disposition 欄位,那麼waf也是先匹配到這個http頭在對內容進行檢測,我們可以嘗試對這個頭的特徵進行修改

 

我們嘗試去掉這個form-data    (form-data;的意思是內容描述,form-data的意思是來自表單的數據,但是即使不寫form-data,apache也接受。)

 

  Content-Disposition: name=”file”; filename=”shell.php”

 

發現失敗,之前3.0版本可以繞,4.0卒

 

 

對Content-Disposition進行參數污染,攔截

 

 

對Content-Disposition進行大小寫混淆,攔截

 

 

加上額外的Content-Type進行干擾,攔截

 

 

加上filename進行參數污染,攔截

 

 

加一個額外的Content-Length頭,攔截

 

 

0x03.6 多個等號

 

經測試兩個=或者三個=都可以達到繞過的效果

 

 

 

 

 

0x03.7 %00截斷

 

%00截斷產生的原因是0x00為十六進位的表示方法,ASCII碼里就為0,而有些函數在進行處理的時候會把這個當作結束符

 

這裡直接嘗試在文件名後面加上%00形成00截斷,成功繞過

 

 

 

 

0x04 後記

 

某狗4.0版本對於3.0版本又有了一定的改進,對於之前的文件名修改和修改匹配欄位已經不能夠繞過waf,但是對於繞waf的思想總結起來可以有如下幾點:

 

大小寫轉換、干擾字元污染、字元編碼、拼湊法