【Portswigger 學院】文件上傳

教程和靶場來源于 Burpsuite 的官網 Portswigger:File upload vulnerabilities - PortSwigger

原理與危害

很多網站都有文件上傳的功能,比如在個人信息頁面允許用戶上傳圖片作為頭像。如果網站應用程序對用戶上傳的文件沒有針對文件名、文件類型、文件內容或文件大小做充分的驗證,就可能導致允許攻擊者上傳有潛在危險的文件,比如服務端的腳本文件,然后訪問該文件以觸發代碼執行。

文件上傳漏洞的危害取決于兩個因素:

  • 網站應用程序對文件名、文件類型、文件內容或文件大小等參數中的哪一個沒有做充分的驗證。
  • 上傳文件成功后受到哪些限制。

最壞的情況是文件類型沒有受到服務器的任何限制,允許 .php.jsp 作為腳本文件執行,那么攻擊者可以上傳 .php.jsp 文件作為 webshell,接管服務器。

其他的一些危害:

  • 對文件名沒有做驗證,攻擊者上傳一個同名的文件,覆蓋服務器上已存在的文件,如果還存在路徑遍歷漏洞,那么危害更大,可以覆蓋服務器的系統文件。
  • 對文件大小沒有做驗證,攻擊者上傳一個非常大的文件,占用服務器的磁盤空間,也就是?DoS 攻擊。

由于文件上傳漏洞的危害很大,所以現在大部分網站應用程序都做了防御,能直接上傳 .php.jsp 文件的網站很少看到了。然而,漏洞仍然會產生,這是因為開發人員堅信他們的防御足夠有效。

靜態文件處理

在剛學習 Web 安全時,看了很多課程和書籍,我們潛意識認為一個 URL 對應網站服務器上的一個文件,對應關系是 1:1,比如 http://example.com/includes/func.php 這個 URL 在網站服務器上對應的文件位于網站根目錄下的 includes 目錄下的 func.php 文件。這種理解在以前靜態網站甚至 PHP 網站和 ASP 網站流行的時候確實是這樣,這只不過是?Apache 或 IIS 等中間件正好這樣管理站點的文件,但是現代 Web 應用程序已經不是這樣 URL 與文件呈現一對一的映射關系,我們現在看到一個 URL 比如? https://csdn.net/mp_blog/creation/editor,在網站服務器并不存在一個路徑為 <網站根目錄>/mp_blog/creation/editor 的文件

當然,像圖片、CSS 和 JS 等靜態資源,Web 服務器仍然用一對一的映射關系處理它們,處理步驟是:解析 URL 中的 path 部分,識別出請求的文件的擴展名,然后根據擴展名匹配對應的?MIME,最后根據服務器預先的配置執行下一步:

  • 如果文件類型是不可執行的,就作為靜態文件把文件內容響應給客戶端。
  • 如果文件類型是可執行的,例如 PHP 文件,就創建運行環境,根據請求頭和請求參數分配變量,然后執行腳本。
  • 如果文件類型是可執行的,但服務器被配置成不執行該類型的文件,就給客戶端響應一個錯誤。不過,大多數情況下,服務器仍然把這些當成普通文本,將它們的內容返回給客戶端,這一點特性可能被利用實現泄露代碼或其他敏感信息的目的。

實驗

實驗說明:

服務器沒有對上傳的文件沒做任何驗證,上傳一個 PHP 腳本并讀取 /home/carlos/secret 文件的內容就能完成實驗。

進入實驗場景:

用賬號 wiener:peter 登錄,進入個人信息頁面:

點擊最下面的“瀏覽”按鈕,選擇一個 PHP 腳本上傳,PHP 腳本的內容:

<?php echo file_get_contents("/home/carlos/secret"); ?>

讀取并返回 /home/carlos/secret 文件的內容。

點擊“Upload”按鈕上傳文件,響應結果:

結果表示文件上傳成功并給出保存的文件路徑。除了這里可以看到保存的文件路徑,還可以返回個人信息頁面打開 F12 查看路徑:

訪問?/files/avatars/info.php 就能讀取到 /home/carlos/secret 文件的內容:

復制這段數據,返回到首頁點擊 “Submit solution” 按鈕提交即可。

繞過驗證機制

Content-Type 偽造

提交表單后客戶端發送一個 POST HTTP 請求,Content-Type 是請求包中的一個請求頭,表示請求體的內容類型,如果是發送一段簡短的文本,Content-Type 的值一般是?application/x-www-form-url-encoded,但如果發送的是一個大文件,比如 PDF,那么就得用文件上傳的方式發送,此時的 Content-Type 是?multipart/form-data,表示表單數據多個部分,而 HTTP 請求包內容類似于這樣:

POST /images HTTP/1.1
Host: normal-website.com
Content-Length: 12345
Content-Type: multipart/form-data; boundary=---------------------------012345678901234567890123456---------------------------012345678901234567890123456
Content-Disposition: form-data; name="image"; filename="example.jpg"
Content-Type: image/jpeg[...binary content of example.jpg...]---------------------------012345678901234567890123456
Content-Disposition: form-data; name="description"This is an interesting description of my image.---------------------------012345678901234567890123456
Content-Disposition: form-data; name="username"wiener
---------------------------012345678901234567890123456--

表單中每個輸入之間用一段 ---------------------------012345678901234567890123456?字符串分割,第一個輸入是圖片,它也有自己的 Content-Type,值是 image/jpeg,表示這部分屬于圖片類型。第二個輸入是沒有 Content-Type,其實它相當于一個請求參數,參數名是 decsription,參數值是?

This is an interesting description of my image.

第三個輸入同上。

如果服務器在接受上傳的文件時,根據 Content-Type 決定文件的類型,那么就能讓攻擊者利用偽造繞過。如圖:

結合路徑遍歷漏洞

上傳文件的存儲目錄可能被限制為不允許執行腳本,這的確是可以實現的配置。例如,Apache 服務器可以針對某個特定目錄配置特性,只要在目錄下放置一個 .htaccess 文件,里面配置如下的指令:

php_flag engine offphp_flag engine off

那么當前目錄下的所有腳本被訪問時都不會運行,而是當作普通文本返回。

嘗試利用路徑遍歷漏洞繞過這個限制,把文件上傳到存儲目錄的上一級目錄:

訪問該文件時注意它的路徑,avatars/../info.php 其實就是 info.php。

這里用 URL 編碼處理了斜杠,因為應用程序在保存上傳之前對文件名做了一次 URL 解碼處理:

<?php
$target_dir = "avatars/";
$target_file = urldecode($target_dir.$_FILES["avatar"]["name"]);if (strpos($target_file, ".htaccess")) {echo "The upload of .htaccess files is prohibited.";http_response_code(403);
} else if (move_uploaded_file($_FILES["avatar"]["tmp_name"], $target_file)) {echo "The file ". htmlspecialchars( $target_file). " has been uploaded.";
} else {echo "Sorry, there was an error uploading your file.";http_response_code(403);
}
?>

如果沒有做 URL 解碼處理,文件名中的 ../..\ 會被去掉。我在本地做了一個測試,如圖:

也就是說文件上傳漏洞結合路徑遍歷漏洞需要滿足一定的條件。

重寫服務器配置

有些應用程序對文件上傳功能的安全防護是設置一個后綴名黑名單,里面包含不允許上傳的文件后綴名,但這仍然存在風險,因為無法囊括所有不合法的后綴名,比如 .php5.shtml 等等,這些可能會被忽略。另外,相關配置文件的文件名或后綴名也應該被列為黑名單。

大多數 Web 服務器并不是在一開始安裝成功后就能執行文件的,像 Apache,要執行 PHP 腳本,需要在 /etc/apache2/apache2.conf 配置文件中添加如下指令:

LoadModule php_module /usr/lib/apache2/modules/libphp.soAddType application/x-httpd-php .php

意思是加載 php 模塊,以及當訪問后綴名為 .php 的文件時,作為 php 腳本執行。

不止 Apache,Nginx 和 IIS 也都是要做一些配置才能執行腳本。

除了 apache2.conf 這個系統級的配置文件,Apache 服務器允許在每個目錄下放置一個 .htaccess 文件,在該文件中添加的指令可以覆蓋和補充 apache2.conf 的配置。如果應用程序允許上傳 .htaccess,那么就能利用它繞過安全防護,執行代碼。

首先,第一步是先上傳 .htaccess

文件內容:

AddType application/x-httpd-php .png

這表示 .png 后綴的文件也被當成 PHP 腳本執行。

第二步是上傳包含 PHP 代碼的 .png 文件:

最后一步是訪問 phpinfo.png 文件,觸發代碼執行。

IIS 服務器也有一個類似的配置文件,名為 web.config,它的指令示例:

<staticContent><mimeMap fileExtension=".json" mimeType="application/json" /></staticContent>

表示 .json 文件被當成 json 發送給客戶端。

PS:通常,.htaccess 和 web.config 被從客戶端禁止訪問。

混淆文件后綴

下面列舉一些混淆技巧:

  • 如果在驗證文件后綴名是否合法時區分大小寫,但是在后綴名映射?MIME 時不區分大小寫,那么可嘗試大寫后綴,比如 exploit.pHpexploit.PHP 等。
  • 多后綴名,比如 exploit.php.jpg。(Apache 多后綴解析漏洞)
  • 末尾加點,比如 exploit.php.? 。(Windows不允許文件名末尾有點,如果有,會自動去掉)
  • 在驗證文件后綴名之前沒有做 URL 解碼處理,但是在之后做了,那么可用 URL 編碼繞過安全驗證,比如?exploit%2Ephp
  • 如果服務器用低級語言如 C/C++ 寫的,那么可嘗試空字節繞過,比如?exploit.asp%00.jpg
  • 結合 IIS 6.0 解析漏洞,如:exploit.asp;.jpg
  • 如果應用程序匹配到不合法的后綴名后只做一次刪除處理,而不是遞歸刪除,那么可雙寫后綴繞過,比如 exploit.p.phphp

下圖是利用空字節繞過的一個例子:

下面是應用程序處理這個文件名的代碼,我們看看如何處理這個 %00 的:

<?php
$target_dir = "avatars/";
$target_file = urldecode($target_dir . $_FILES["avatar"]["name"]);
$uploadOk = true;$imageFileType = strtolower(pathinfo($target_file,PATHINFO_EXTENSION));if($imageFileType != "jpg" && $imageFileType != "png") {echo "Sorry, only JPG & PNG files are allowed\n";$uploadOk = false;
}//去掉空字節及其后面的字符
$target_file = strtok($target_file, chr(0));if ($uploadOk && move_uploaded_file($_FILES["avatar"]["tmp_name"], $target_file)) {echo "The file ". htmlspecialchars( $target_file). " has been uploaded.";
} else {echo "Sorry, there was an error uploading your file.";http_response_code(403);
}

這很容易看懂。然而,在實際的場景中,并不會有開發人員會這樣處理文件名,讓攻擊者有利用空字節繞過的可能,更多是服務器由 C/C++ 開發時才有可能出現。

文件內容驗證繞過

當應用程序不信任 Content-Type 所指示的那樣判斷一個文件的類型,可能會直接通過驗證文件的內容來判斷。對于這種情況,最簡單的驗證方式就是查看文件開頭幾個字節,這幾個字節又稱魔術數字,大多數類型的文件都會在開頭設置獨一無二的字節序列,比如 JPEG 文件的就是?FF D8 FF,這種驗證方式很容易繞過,因為攻擊者也能在腳本的開頭放置這幾個字節并且不會影響代碼執行。

比較復雜的情況是,應用程序用一些圖片處理函數來判斷上傳的文件的數據是否真的是合法的圖片數據,比如獲取圖片的尺寸,腳本文件就不會有這種數據。但是,攻擊者可以將代碼嵌入到圖片的一些數據區,這些數據區不會破壞圖片本身的數據和圖片的渲染,比如 JPEG 圖片的注釋部分,用 Exiftool 工具可以做到這些事情。(Exiftool 工具在 kali 系統中已默認安裝)

Exiftool 將 PHP 代碼嵌入到 JPG 圖片的注釋部分:

exiftool -Comment="<?php echo 'START ' . file_get_contents('/home/carlos/secret') . ' END'; ?>" test.jpg -o polyglot.php

意思是將 -Comment 參數指定的內容嵌入到 test.jpg 的注釋部分,最后生成 polyglot.php 文件。

條件競爭上傳文件

有些應用程序接收到上傳的文件后先保存到網站的一個目錄下,接著對文件的安全性做驗證,如果文件被判斷為不安全的就會刪除該文件,這樣的處理是有問題。在保存到目錄后和被判斷為不安全而刪除之前存在一個時間空隙,攻擊者在這段空隙訪問所上傳的文件就能執行該文件,這是能夠做到,利用預先寫好的程序快速不停地訪問即可。

現代開發框架都內置了處理文件上傳的組件,它們通常都能夠阻止這類漏洞,其處理步驟是

  1. 把上傳的文件保存到一個沙盒化的臨時目錄(這里的文件被隔離且無法被訪問到并執行);
  2. 重命名為一個隨機字符串以避免文件覆蓋;
  3. 做安全性驗證,如果文件被判斷為安全的,就移動文件到最終保存的目錄,否則就刪除。

如果開發人員自己編寫文件上傳處理程序,那么就有可能存在這類漏洞。

攻擊者很難在黑盒測試中找到這種漏洞,除非他能找到應用程序的源代碼,通過審計發現這種漏洞。

另外,還有一種情況可能發生條件競爭文件上傳漏洞,就是讓用戶提供一個 URL 來保存文件,這一般只能由開發人員自己編寫處理程序,也必須先下載一份文件副本到本地,然后再做安全性驗證,所以這種情況很容易出現漏洞。

如果上傳的文件或通過 URL 下載的文件保存到一個具有隨機名稱的臨時目錄,這一般不太可能被攻擊者知道,但如果臨時目錄是偽隨機數,那么仍然有可能被攻擊者用暴力破解的方法知道。

為了讓條件競爭上傳文件的攻擊更容易,攻擊者會上傳一個惡意的大文件,里面填充大量無用字符,但不會影響到里面的代碼被執行,應用程序處理這類大文件會處理得更久,那么文件在文件系統上停留的時間更久,也就更容易被攻擊者趁機訪問。

客戶端攻擊

能上傳帶有惡意代碼的文件是最嚴重的漏洞,這是針對服務器的攻擊,但文件上傳也能用于針對客戶端攻擊。上傳一個 HTML 文件或 SVG 圖像,里面包含 XSS 代碼,那么就相當于是一個存儲型 XSS 漏洞了,然后把文件的 URL 發給受害者,因為域名是合法的,所以更容易被信任。(注意,上傳的文件如果被保存到另一個網站,那么要考慮同源策略的影響)

PUT 文件上傳

某些服務器被配置為允許 HTTP PUT 請求方法,這種請求方法是用于上傳文件,攻擊者可先用 OPTIONS 請求方法查看網站是否支持 HTTP PUT 請求方法,然后再嘗試上傳文件。

PUT 上傳請求示例:

PUT /images/exploit.php HTTP/1.1
Host: vulnerable-website.com
Content-Type: application/x-httpd-php
Content-Length: 49<?php echo file_get_contents('/path/to/file'); ?>

防護

下面是一些防護方法:

  • 使用后綴名白名單而不是黑名單,因為列舉出所有允許的后綴名更容易。
  • 文件名不能包含 ../ 序列。
  • 重命名文件避免文件覆蓋。
  • 對文件做完安全性驗證再移動它到永久保存的目錄,在此之前保存到臨時目錄。
  • 盡量使用框架內置的文件上傳處理組件,而不是自己編寫。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/41277.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/41277.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/41277.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

前端基礎:JavaScript(篇一)

目錄 JavaScript概述 JavaScript歷史&#xff1a; 須知&#xff1a; 基本語法 變量 代碼 運行 數據類型 1、數值型(number)&#xff1a; 代碼 運行 2、布爾型(boolean)&#xff1a; 代碼 運行 3、字符串型&#xff1a; 代碼 運行 4、 undefined類型 代碼…

TCP的pop網絡模式

TCP的pop網絡模式 1、tcp連接的狀態有以下11種 CLOSED&#xff1a;關閉狀態LISTEN&#xff1a;服務端狀態&#xff0c;等待客戶端發起連接請求SYN_SENT&#xff1a;客戶端已發送同步連接請求&#xff0c;等待服務端相應SYN_RECEIVED&#xff1a;服務器收到客戶端的SYN請請求&…

MySQL 基本語法講解及示例(下)

第六節&#xff1a;如何檢索資料 在本節中&#xff0c;我們將介紹如何使用SQL語句檢索數據庫中的資料&#xff0c;具體包括選擇特定列、排序、條件過濾以及組合排序等操作。我們以一個名為student的表格為例&#xff0c;演示不同的檢索方法。 初始表格 student student_idname…

修復harbor的/account/sign-in\?globalSearch=b不登錄可以查詢鏡像的問題

Nginx的location指令不能直接匹配查詢參數&#xff0c;所以需要通過其他方式來處理。這里是一個使用if指令結合查詢參數來實現的方法。該方法會在請求路徑中帶有特定查詢參數時返回404。 使用if指令匹配查詢參數 打開Nginx配置文件&#xff1a; sudo vim /etc/nginx/sites-ava…

Python中frozenset,秒變不可變集合,再也不用擔心多線程了!

目錄 1、Frozenset基礎介紹 ?? 1.1 Frozenset定義與創建 1.2 不可變集合特性 1.3 與Set的區別對比 2、Frozenset操作實踐 ?? 2.1 初始化與添加元素嘗試 2.2 成員測試: in & not in 2.3 集合運算: 并集、交集、差集 2.4 使用場景示例: 字典鍵、函數參數默認值 …

登錄設計(實戰項目)-1個手機號多用戶身份登錄

一. 背景&#xff1a; 該需求是一個互聯網醫院的預約單場景&#xff0c;護士在小程序上申請患者查房預約單&#xff0c;醫生在小程序上對預約單進行接單&#xff0c;護士開始查房后填寫查房小結&#xff0c;客戶需要對用戶信息進行授權&#xff0c;醫生查房后進行簽字&#xff…

勁爆!華為享界兩款新車曝光,等等黨有福了

文 | AUTO芯球 作者 | 雷慢 勁爆啊&#xff0c;北汽的一份環境影響分析報告&#xff0c; 不僅曝光了享界S9的生產進展&#xff0c; 還泄露了自家的另兩款產品&#xff0c; 第一款是和享界S9同尺寸的旅行車&#xff0c; 我一看&#xff0c;這不是我最喜歡的“瓦罐”嗎&…

v-html 空格/換行不生效

接口返回的內容如下&#xff1a;有空格有換行&#xff0c;但 使用v-html無效 需加css樣式 white-space: pre-wrap; <div class"pretty-html" v-html"Value"></div>.pretty-html {white-space: pre-wrap; /* 保留空格和換行&#xff0c;并允許…

掌握麥肯錫精英的6個技巧,你也能成為1%的精英!

不知道大家有沒有想過&#xff0c;我們和那些全球頂尖精英的差距可能只有1%&#xff0c;只是99%的人還不知道這件事。 今天給大家推薦一本好書&#xff0c;《你和麥肯錫精英的差別只有1%》。優思學院發現&#xff0c;在我們的六西格瑪、精益管理的學生中很多人對自己沒有自信。…

軟通動力子公司鴻湖萬聯最新成果SwanLink AI亮相世界人工智能大會

7月4日&#xff0c;2024世界人工智能大會暨人工智能全球治理高級別會議&#xff08;WAIC 2024&#xff09;在上海拉開帷幕&#xff0c;軟通動力董事長兼首席執行官劉天文受邀出席開幕式。其間&#xff0c;軟通動力攜子公司鴻湖萬聯深度參與到大會各項活動中&#xff0c;并全面展…

C語言_結構體初階(還未寫完)

結構體的聲明 1. 什么是結構&#xff1f;結構是一些值的集合&#xff0c;這些值稱為成員變量。結構的每個成員可以是不同類型的變量 數組&#xff1a;一組相同類型元素的集合 結構體&#xff1a;一組不一定相同類型元素的集 2. 結構的聲明 struct tag //tag根據實際情況給名字…

Spring注解@Qualifier

Autowired 注解是 Spring 依賴注入。但是有些場景下僅僅靠這個注解不足以讓Spring知道到底要注入哪個 bean。 默認情況下&#xff0c;Autowired 按類型裝配 Spring Bean。 如果容器中有多個相同類型的 bean&#xff0c;則框架將拋出 NoUniqueBeanDefinitionException&#xff0…

數字化產科管理平臺全套源碼,java產科電子病歷系統源碼

數字化產科管理平臺全套成品源碼&#xff0c;產科電子病歷系統源碼&#xff0c;多家大型婦幼專科醫院應用案例。源碼完全授權交付。 數字化產科管理平臺&#xff08;智慧產科系統&#xff09;是為醫院產科量身定制的信息管理系統。它管理了孕婦從懷孕開始到生產結束42天以內的一…

數據庫MySQL學習筆記

數據庫MySQL學習筆記 主要記錄常見的MySQL語句學習過程&#xff0c;增刪改查。 -- 顯示所有數據庫 SHOW DATABASES;-- 創建新數據庫 CREATE DATABASE mydatabase;-- 使用數據庫 USE mydatabase;-- 顯示當前數據庫中的所有表 SHOW TABLES;-- 創建新表 CREATE TABLE users (id …

BERT--學習

一、Transformer Transformer&#xff0c;是由編碼塊和解碼塊兩部分組成&#xff0c;其中編碼塊由多個編碼器組成&#xff0c;解碼塊同樣也是由多個解碼塊組成。 編碼器&#xff1a;自注意力 全連接 多頭自注意力&#xff1a;Q、K、V 公式&#xff1a; 解碼塊&#xff1…

【Hive實戰】 HiveMetaStore的指標分析

HiveMetaStore的指標分析&#xff08;一&#xff09; 文章目錄 HiveMetaStore的指標分析&#xff08;一&#xff09;背景目標部署架構 hive-site.xml相關配置元數據服務的指標相關配置 源碼部分&#xff08;hive2.3系&#xff09;JvmPauseMonitor.javaHiveMetaStore的內部類HMS…

【anaconda】—“conda info“命令后conda配置和環境信息的理解

文章目錄 conda配置和環境信息的理解 conda配置和環境信息的理解 安裝anaconda成功后&#xff0c;打開cmd&#xff0c;輸入"conda info"命令&#xff0c;結果顯示如下&#xff1a; conda的配置和環境信息的輸出。以下是對每個字段的解釋&#xff1a; active environm…

H2 Database Console未授權訪問漏洞封堵

背景 H2 Database Console未授權訪問&#xff0c;默認情況下自動創建不存在的數據庫&#xff0c;從而導致未授權訪問。各種未授權訪問的教程&#xff0c;但是它怎么封堵呢&#xff1f; -ifExists 很簡單&#xff0c;啟動參數添加 -ifExists &#xff0c;它的含義&#xff1a…

中電金信:加快企業 AI 平臺升級,構建金融智能業務新引擎

在當今數字化時代的浪潮下&#xff0c;人工智能&#xff08;AI&#xff09;技術的蓬勃發展正為各行業帶來前所未有的變革與創新契機。尤其是在金融領域&#xff0c;AI 模型的廣泛應用已然成為提升競爭力、優化業務流程以及實現智能化轉型的關鍵驅動力。然而&#xff0c;企業在積…

【C++ 】解決 C++ 語言報錯:Null Pointer Dereferenc

文章目錄 引言 在 C 編程中&#xff0c;空指針解引用&#xff08;Null Pointer Dereference&#xff09;是一種常見且危險的錯誤。當程序試圖通過空指針訪問內存時&#xff0c;會導致程序崩潰或產生不可預期的行為。本文將詳細探討空指針解引用的成因、檢測方法及其預防和解決…