文件上傳漏洞


文件上傳漏洞

實驗環境:

Windows 7 X64
Phpstudy 2018
PHP 5.4.45
Apache 2.4.23
靶機項目地址:https://github.com/c0ny1/upload-labs

Pass01 — JS限制

開啟burp抓包,嘗試上傳eval.php,點擊上傳后頁面直接提示該文件不允許上傳,而burp並沒有截取到數據包,判斷為JS限制。
在這里插入圖片描述
F12將JS限制代碼找出來,將代碼復制到console,修改允許上傳的后綴為php再運行
在這里插入圖片描述
點擊上傳后顯示上傳成功,在下方回顯的地方右鍵復制圖片地址即可獲取上傳后的圖片路徑。
在這里插入圖片描述
為了直觀查看上傳的文件有沒有被執行,在上傳的文件中均是寫的phpinfo()。復制圖片地址后進行訪問,頁面出現phpinfo()。

除了使用console以外,還可以在瀏覽器中直接禁用JS,這樣在上傳的時候直接沒有限制,可以傳任意文件。
在這里插入圖片描述

Pass02 — Content-Type限制

分析源碼,在對上傳文件的檢測中只對文件的Content-Type做了限制,只要為源碼中所限定的類型即可成功上傳。
在這里插入圖片描述
對於該類型只需要burp抓包修改Content-Type為白名單內的類型即可。
在這里插入圖片描述
上傳成功后,復制圖片地址進行訪問,成功執行。
在這里插入圖片描述
在此補充幾個常見的文件類型對應的content-ytpe:

HTML文檔標記:text/html
普通ASCII文檔標記:text/html
JPEG圖片標記:image/jpeg
GIF圖片標記:image/gif
js文檔標記:application/javascript
xml文件標記:application/xml

 

Pass03 — 黑名單繞過

分析源碼,后台對上傳的文件限制較多,凡是黑名單中的內容全都不都上傳,且不能用大小寫、::DATA、末尾空格等措施繞過。
在這里插入圖片描述
但如果在Apache配置文件中有.+.ph(p[345]?|t|tml)此類的正則表達式,或是在apache配置文件中存在類似於:AddType application/x-httpd-php .php .phtml .php3這樣的語句。就可以將php3、php4、php5、phtml后綴的文件解析為php運行。
在這里插入圖片描述
因此,php3、phtml后綴文件就可以成為黑名單之外的可進行解析的文件。在本關中可以嘗試使用這些后綴進行繞過。
因為我的實驗環境是在Windows環境下,在本關中需要到apache的配置文件中將
AddType application/x-httpd-php .php .phtml .php3 前的#號去掉,再重啟apache服務即可成功解析phtml以及php3后綴的文件
在這里插入圖片描述

Pass04 — .htaccess

分析源碼,發現較Pass03來說,將php3、phtml等后綴的文件也納入了黑名單范圍。
在這里插入圖片描述
在此就需要引進另一個概念:.htaccess文件
一般來說,配置文件的作用范圍都是全局的,但Apache提供了一種很方便的、可作用於當前目錄及其子目錄的配置文件——.htaccess(分布式配置文件)
要想使.htaccess文件生效,需要兩個條件:
一是在Apache的配置文件中寫上:

	AllowOverride All

若這樣寫則.htaccess不會生效:

	AllowOverride None

二是Apache要加載mod_Rewrite模塊。加載該模塊,需要在Apache的配置文件中寫上:

	LoadModule rewrite_module /usr/lib/apache2/modules/mod_rewrite.so

若是在Ubuntu中,可能還需要執行命令:

	sudo a2enmod rewrite

配置完后需要重啟Apache。

.htaccess文件可以配置很多事情,如是否開啟站點的圖片緩存、自定義錯誤頁面、自定義默認文檔、設置WWW域名重定向、設置網頁重定向、設置圖片防盜鏈和訪問權限控制。但我們這里只關心.htaccess文件的一個作用——MIME類型修改。如在.htaccess文件中寫入:

AddType application/x-httpd-php xxx

就成功地使該.htaccess文件所在目錄及其子目錄中的后綴為.xxx的文件被Apache當做php文件。
另一種寫法是:

<FilesMatch "shell.jpg"> SetHandler application/x-httpd-php </FilesMatch>

 

該語句會讓Apache把shell.jpg文件解析為php文件。

因此,該關卡可以嘗試利用.htaccess進行繞過。
為驗證的確是.htaccess文件生效,我先將eval.jpg上傳,eval.jpg實際是由eval.php改后綴而來,其中包含的是phpinfo()的代碼。
上傳eval.php后,嘗試訪問圖片
在這里插入圖片描述
服務端並沒有將文件當作php執行。
接下來在.htaccess中寫入以下代碼,再上傳文件

AddType application/x-httpd-php jpg

嘗試再次訪問eval.jpg,已經成功解析。
在這里插入圖片描述

Pass05 — 后綴大小寫繞過

分析源碼,相比於之前的對於后綴統一轉為小寫的防護措施,在本關卡中並未出現,因此可以考慮通過文件后綴的大小寫來繞過檢測
在這里插入圖片描述
上傳eval.php,通過burp抓包修改為eval.phP,放行數據包后,上傳成功
在這里插入圖片描述
在這里插入圖片描述

Pass06 — 空格繞過(Windows環境下)

在開始本關的實驗之前,先來解釋一下為什么可以使用空格來進行上傳繞過。

在windows環境下,xx.jpg[空格] 或xx.jpg.
這兩類文件都是不允許存在的,若這樣命名,windows會默認除去空格或點,但在數據包進行傳輸的時候,空格是被允許傳送的。因此可以通過抓包軟件,在文件名后加一個空格或者點,當數據包到達檢測機制時,".php"
和 “.php.” 或 “php
“是不等同的,因此繞過了黑名單限制。當服務端為Windows時,上傳成功后,空格和點都會被windows自動消除,這樣就可以使其恢復為正常的”.php”

分析源碼,發現對於文件后綴中的空格的限制消失了,本關嘗試在后綴之后再追加一個空格來繞過。
在這里插入圖片描述
burp抓包,在eval.php后追加一個空格,放行數據包后上傳成功
在這里插入圖片描述
在這里插入圖片描述

Pass07 — 后綴后加.繞過(Windows環境下)

分析源碼,該關卡和Pass06相比,Pass06是沒有做后綴去空格處理,本關卡是沒有做后綴去.處理。只需要將Pass06繞過時加的 " " 換成 “.” 即可
在這里插入圖片描述

Pass08 — ::$DATA(Windows環境下)

開始本關實驗之前,依然要引入一個概念:

當php在windows環境的時候,如果文件名+ “::D A T A " 會 把 " : : DATA" 會把 "::DATA""::DATA” 之后的數據當成文件流處理,不會檢測后綴名.且保持"::$DATA"之前的文件名

分析源碼,在源碼中並未對::D A T A 加 以 限 制 , 結 合 服 務 端 為 W i n d o w s 服 務 器 的 前 提 下 , 可 利 用 : : DATA加以限制,結合服務端為Windows服務器的前提下,可利用::DATAWindows::DATA進行繞過

上傳eval.php,burp抓包,在eval.php后添加::$DATA后放行數據包。
在這里插入圖片描述

在訪問上傳的文件時,去除鏈接中的::$DATA即可
在這里插入圖片描述

Pass09 — 點空格點繞過(Windows環境下)

分析源碼,從第5行開始,各行代碼的意思分別為:黑名單、提取文件名、刪除文件名末尾的點、找出文件后綴、將文件后綴替換為小寫、去除文件后綴中的::$DATA、首位去空。經過一系列處理后,文件后綴不在黑名單列表內便進行拼接(15行)
在這里插入圖片描述
對此,我們可以采用"eval.php. ."來進行繞過,將payload帶入處理程序進行執行一次:


> 6:$file_name=eval.php. ; //刪去末尾空格 > 7:$file_name=eval; //提取文件名字 > 8:$file_ext=php. ; //提取后綴 > 9:$file_ext=php. ; //將后綴轉換為小寫 > 10:$file_ext=php. ; //去除后綴中的::$DATA > 11:$file_ext=php.; //除去后綴前后的空格 

 

經過所有處理后,文件的后綴名變成了".php.",再進入下面的拼接處理,拼接完成后的文件為"eval.php.",再根據Windows去除點的特性,服務端收到的文件為"eval.php",成功繞過並執行。
在這里插入圖片描述
訪問上傳的文件:
在這里插入圖片描述

Pass10 — 雙寫后綴繞過

分析源碼,發現在第八行的代碼將黑名單中的后綴進行了替換,只要是黑名單中的后綴全部都會被替換為空,這樣即使成功的上傳了eval.php也會由於后綴被替換變為eval. 無法執行。
在這里插入圖片描述
在這里插入圖片描述

我們可以嘗試使用后綴雙寫來繞過限制,即將eval.php改為eval.pphphp,處理機制會將后綴中識別出的php直接替換為空,這樣剩下的ph和p自然便組合到了一起,變為eval.php.
利用burp抓包實現該過程。
在這里插入圖片描述
成功上傳后,訪問上傳的文件,成功解析。
在這里插入圖片描述

Pass11 — 白名單繞過-%00截斷

開始本關之前,先來了解一下什么是00截斷:

事實上0x00,%00這兩類截斷都是屬於同種原理,%00在url解碼后為空字符,0X00即16進制的00,只是表示和用法不同而已
無論0x00還是%00,最終被解析后都是一個東西:chr(0)

chr()是一個函數,這個函數是用來返回參數所對應的字符的,也就是說,參數是一個ASCII碼,返回的值是一個字符,類型為string。

那么chr(0)就很好理解了,對照ASCII碼表可以知道,ASCII碼為0-127的數字,每個數字對應一個字符,而0對應的就是NUT字符(NULL),也就是空字符,而截斷的關鍵就是這個空字符,當一個字符串中存在空字符的時候,在被解析的時候會導致空字符后面的字符被丟棄。

舉例說明:
當我們在GET場景上傳一個名為eval.php%00.jpg的文件,后台程序收到此文件后,開始檢測其名稱,當檢測到%00后產生截斷,不再繼續解析%00之后的內容。於是,系統上存儲的實際為eval.php。

如何利用%00以及0x00截斷:
1.php版本要小於5.3.4,5.3.4及以上已經修復該問題

2.magic_quotes_gpc需要為OFF狀態
當打開magic_quotes_gpc時,所有的 '(單引號),"(雙引號),\(反斜線)和 NULL字符(%00)都會被自動加上一個反斜杠進行轉義。

3.文件路徑可控(即本關卡),比如我可以修改路徑拼接的path時,比如抓到的包中存在path: uploads/,就可以直接把路徑構造成uploads/xxx.php%00,先構造一個存在截斷字符的后綴“等着”真正的文件名,或者后綴名,因為不管它是啥,都會被截斷而丟棄

一般來說,在GET傳參時,由於url中的內容會進行url編碼,而%00在經過解碼之后便是空字符導致截斷。
而在在POST傳參時, POST 中 %00 不會被 url 解碼,所以只能通過 burpsuite 修改 hex 值為 00 進行截斷,這種情況會在接下來的Pass12進行舉例。

了解了兩種截斷之后,我們來開始本關的實驗。

分析源碼,第五行定義了允許上傳的白名單,第五行取出上傳的文件的后綴,如果后綴在白名單范圍內便將圖片存儲在客戶端指定的save_path下,文件名為10-99的兩位隨機數+日期.后綴
在這里插入圖片描述
源碼中出現了客戶端可控的save_path和拼接上傳的文件,傳輸方式為GET,我們考慮用%00進行截斷。

將phpstudy中的apache版本切換至5.2.17,將magic_quotes_gpc切換至OFF狀態。

嘗試上傳eval.php,burp抓包修改數據。將GET請求中的/upload/路徑構造為/upload/eval.php%00進行截斷等待處理過的數據進行拼接。
在這里插入圖片描述
放行數據包,顯示上傳成功,嘗試訪問上傳的文件,發現報錯。
在這里插入圖片描述
查看文件地址,發現截斷位置之后為實際的經過處理之后的文件,但因為截斷之后的數據並不會被存儲。所以這里應當直接訪問截斷之前的/upload/eval.php。
在這里插入圖片描述

Pass12 — 白名單繞過(0X00截斷)

分析源碼,與Pass11不同的是,本關的傳參方式變為了POST,上傳路徑依然可控,所以考慮0X00截斷繞過。
在這里插入圖片描述
嘗試上傳eval.php,通過burp抓包修改數據。在修改數據的時候有兩種修改方法。

1.通過16進制hex進行修改:
在上傳路徑/upload/后構造 “/upload/eval.php空格” 注意,這個空格只是為了方便尋找插入0X00的階段位置,使用其他任何字符亦可,只要自己知道對應的16進制編碼即可。
在這里插入圖片描述

點擊Hex,找到對應的空格對應的十六進制數據0x20,將其修改為00
在這里插入圖片描述
修改完成后,然會Raw下查看,eval.php后的空格已經變為空字符。
在這里插入圖片描述
放行數據包,顯示上傳成功,訪問方法同Pass11.

2.通過url解碼:
同樣的利用burp抓包,在/upload/后構造/upload/eval.php%00,選中%00后,右鍵選擇convert selection-URL-URL-decode
在這里插入圖片描述
將%00進行url解碼后即變成了空字符,可以產生截斷。其原理便是在POST傳參中並不會自動進行url解碼,我們將%00手動解碼后便可產生截斷。
在這里插入圖片描述
放行數據包后文件成功上傳,訪問方法同Pass11。

Pass13 — 圖片一句話木馬

從本關開始,在檢測程序中都有對應的函數來檢測上傳的文件是否為一個真實的圖片文件,且需要利用文件包含漏洞或者文件解析漏洞來使上傳的文件進行解析。分析源碼:
在這里插入圖片描述
本關中定義了一個檢測文件真實類型的功能,通過讀取文件開頭的兩個字節來判斷文件的真實類型(一般的文件前兩個字節信息都是表明自己文件類型),所以之前直接修改文件后綴以及修改Content-Type的方法便不能生效了。
在此,引進圖片一句話木馬這個概念:
圖片一句話木馬即攜帶一句話木馬的圖片,外表上是一個正常的圖片,但圖片的編碼中攜帶了一句話木馬,當存在含文件包含或者文件解析漏洞的時候,便可以將圖片解析為可執行文件,執行其中的一句話木馬。

圖片一句話木馬的制作:

copy a.jpg/b+ b.php c.jpg

/b,即二進制,該命令表示以二進制格式合並a.jpg和b.php。其中a.jpg為正常圖片,b.php中寫的一句話木馬,c.jpg為生成的圖片一句話木馬

直接上傳圖片一句話木馬,上傳后訪問該圖片。
在這里插入圖片描述
在正常情況下,圖片並不會被解析為可執行文件,所以我們需要通過文件包含或者文件解析漏洞來實現對圖片木馬的利用。但靶機總並沒有提供文件包含的相關文件,所以我們自己來寫一個簡單的文件包含文件。

注:文件包含環境需要PHP5.3以上,不然運行文件包含漏洞會出錯。

恢復PHP版本為5.4.45,在靶機的/upload/目錄下新建一個include.php,代碼如下:

<?php $file = $_GET[ 'file' ] ; include ($file); ?> 

 

 

訪問include.php,並用GET方式傳遞file=xxxx.jpg。這個xxxx.jpg便是正常上傳的圖片木馬的地址。

在這里插入圖片描述
可以看到訪問成功,頁面上方的亂碼為圖片的編碼,一直執行到圖片編碼末尾構造的代碼才顯示出phpinfo界面

Pass14 — getimagesize()

分析源碼:
在這里插入圖片描述

getimagesize() 函數將測定任何 GIF,JPG,PNG,SWF,SWC,PSD,TIFF,BMP,IFF,JP2,JPX,JB2,JPC,XBM 或 WBMP 圖像文件的大小並返回圖像的尺寸以及文件類型及圖片高度與寬度。

如果不是真實的圖像,則會獲取信息失敗,所以要繞過該檢測方式也需要用到圖片一句話木馬。方法同Pass13,需要配合文件包含漏洞或文件解析漏洞。

Pass15 — exif_imagetype()

分析源碼:
在這里插入圖片描述

exif_imagetype — 用於判斷一個圖像的類型,讀取一個圖像的第一個字節並檢查其簽名。如果發現了恰當的簽名則返回一個對應的常量,否則返回 FALSE。

如果不是真實的圖像,則會獲取信息失敗,所以要繞過該檢測方式也需要用到圖片一句話木馬。方法同Pass13,需要配合文件包含漏洞或文件解析漏洞。

值得注意的是本關卡需要開啟php_exif拓展,否則上傳后頁面會出錯。
在這里插入圖片描述

Pass16 — 二次渲染

后面的這機關就不分析代碼了,確實太長,沒學過PHP也看不懂,菜。
總的來說,本關中采取了如下幾種限制:
1.文件后綴名
2.Content-Type
3.使用函數imagecreatefromgif、imagecreatefromjpeg、imagecreatefrompng來判斷是否為gif、jpg、png圖片
4.對於判斷是圖片的文件進行二次渲染

二次渲染,就是根據用戶上傳的圖片,新生成一個圖片,將原始圖片刪除,將新圖片添加到數據庫中。比如一些網站根據用戶上傳的頭像生成大中小不同尺寸的圖像。在二次渲染的過程中,我們圖片中所寫的木馬也可能會被渲染掉。
繞過二次渲染的核心思想便是先上傳一張圖片,再將上傳完成后的圖片下載下來,對比渲染前后圖片的編碼變化,將我們的代碼寫在未被渲染的區域便可繞過二次渲染。
由於不同格式文件的特性,在進行繞過二次渲染時,選用gif的圖像最容易成功,對於jpg和png這兩種圖片需要用腳本進行改寫,也不在進行嘗試。

以gif為例:
用winhex在eval.gif的最后寫上phpinfo的代碼
在這里插入圖片描述

上傳eval.gif后,可以正常訪問gif。
在這里插入圖片描述
嘗試用文件包含漏洞來利用圖片木馬,失敗。
在這里插入圖片描述

將渲染后的gif文件下載到本地,通過對比軟件對比渲染前后的十六進制數據。下圖左為渲染前,右為選然后的文件。未標紅的即為前后未發生變化的區域。
在這里插入圖片描述
將木馬寫到該區域再次進行嘗試上傳並利用文件包含訪問。
在這里插入圖片描述
成功解析。
在這里插入圖片描述

Pass17 — 條件競爭

分析源碼,對於上傳的文件處理是先保存到服務器,再對比拓展名,如果拓展名不屬於白名單中的三種后綴,便由18行的操作執行unlink操作將保存的文件刪除。
在這里插入圖片描述
對此,我們可以運用條件競爭機制在程序執行刪除之前訪問上傳的程序。這有什么用呢?對於我之前寫的phpinfo()這樣近乎無害的代碼的確沒什么用,如果換成下面的代碼呢:

<?php fputs(fopen('info.php','w'),'<?php phpinfo();?>');?> 
  • 1

該代碼的意思為,新建一個info.php,並向其中寫入"<?php phpinfo();?>",這樣一旦成功訪問到了上傳后的文件,便會生成一個新的info.php留在服務器,即使原來的文件被刪除后我們依然可以訪問新生成的文件。

接下來進行操作。
上傳eval.php,用burp截取數據,將數據包發送到intruder。

在payload中設置payload為Null payloads,即沒有payload,並將continue indefinitely,意為無限重復。設置好后 start attack ,這樣burp會代替我去一直重復上傳eval.php
在這里插入圖片描述
burp開始發包后,另一邊打開瀏覽器不停刷新嘗試訪問eval.php
在這里插入圖片描述

好吧,手點麻了也沒有成功訪問到eval.php,低估了程序的處理速度。借鑒了其他師傅的方法,可以借助python自動訪問eval.php,當成功訪問到后再停止。

import requests url = "http://192.168.159.128/upload-labs-master/upload/eval.php" while True: html = requests.get(url) if html.status_code == 200: print("OK") break

 

在這里插入圖片描述
返回OK,說明訪問到了eval.php,對應的info.php也應該生成了,嘗試訪問info.php,成功。
在這里插入圖片描述

Pass18 — 圖片木馬條件競爭

從做題的角度來看:
源碼太長就不放了,源碼中定義了一堆允許上傳的文件白名單,當上傳一個新文件上去后,先是將文件后綴跟白名單做了對比,然后檢查了文件大小以及文件是否已經存在。文件上傳之后又對其進行了重命名。

因此,只能利用圖片木馬結合文件包含,並且要在圖片馬違背刪除之前訪問到它,生成新的info.php,這跟Pass18變化不大,還是用burp重放上傳圖片馬的包,再利用python訪問文件包含圖片馬的鏈接,生成新的info.php。不再演示。

從過關的角度來看:
上傳一個圖片馬,會返回重命名的地址,就按照我們之前的訪問方式(Pass01)去訪問利用圖片即可。

Pass19 — %00截斷,參考Pass11

Pass20 — 0X00截斷,參考Pass12


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM