什么是文件包含
簡(jiǎn)單一句話,為了更好地使用代碼的重用性淌山,引入了文件包含函數(shù),可以通過(guò)文件包含函數(shù)將文件包含進(jìn)來(lái)王浴,直接使用包含文件的代碼氓辣。
文件包含漏洞成因
在包含文件時(shí)候钞啸,為了靈活包含文件体斩,將被包含文件設(shè)置為變量絮吵,通過(guò)動(dòng)態(tài)變量來(lái)引入需要包含的文件時(shí),用戶(hù)可以對(duì)變量的值可控而服務(wù)器端未對(duì)變量值進(jìn)行合理地校驗(yàn)或者校驗(yàn)被繞過(guò)伴嗡,這樣就導(dǎo)致了文件包含漏洞瘪校。通常文件包含漏洞出現(xiàn)在
PHP
語(yǔ)言中阱扬。
PHP文件包含的函數(shù)
- include( )
當(dāng)使用該函數(shù)包含文件時(shí),只有代碼執(zhí)行到 include()函數(shù)時(shí)才將文件包含
進(jìn)來(lái)用踩,發(fā)生錯(cuò)誤時(shí)之給出一個(gè)警告脐彩,繼續(xù)向下執(zhí)行惠奸。 - include_once( )
功能與 Include()相同梗掰,區(qū)別在于當(dāng)重復(fù)調(diào)用同一文件時(shí)及穗,程序只調(diào)用一次 - require( )
require()與 include()的區(qū)別在于 require()執(zhí)行如果發(fā)生錯(cuò)誤埂陆,函數(shù)會(huì)輸出
錯(cuò)誤信息焚虱,并終止腳本的運(yùn)行。 - require_once( )
功能與 require()相同民鼓,區(qū)別在于當(dāng)重復(fù)調(diào)用同一文件時(shí)摹察,程序只調(diào)用一次黄娘。
文件包含漏洞分類(lèi)
- 本地文件包含漏洞
當(dāng)包含的文件在服務(wù)器本地時(shí)逼争,就形成了本地文件包含誓焦。
下面簡(jiǎn)單做個(gè)測(cè)試:
<?php
$file = $_GET['file'];
include($file);
// ......
先說(shuō)一下文件包含的一個(gè)要點(diǎn):文件包含可以包含任意文件移层,即便被包含的文件并不是與當(dāng)前編程語(yǔ)言相關(guān)观话,甚至為圖片频蛔,只要文件被包含瀑粥,其內(nèi)容會(huì)被包含文件包含利凑,并以當(dāng)前服務(wù)器腳本語(yǔ)言執(zhí)行。
可以看到割按,以上代碼中可以控制可控參數(shù)file
來(lái)控制包含的$file
的值适荣。
- 因此可以建立隨意后綴文件進(jìn)行包含,比如新建文件
file.txt
,文件內(nèi)容如下:
<?php
phpinfo();
?>
然后包含file.txt
文件:
如果包含的文件內(nèi)容不符合php語(yǔ)言語(yǔ)法的,會(huì)直接將文件內(nèi)容輸出万俗,比如:
- 接下來(lái)再看一種情況闰歪,開(kāi)發(fā)者限制了包含文件的后綴临扮,代碼如下:
<?php
$file = $_GET['file'] . '.php';
echo $file;
include($file);
這樣就找不到要包含的文件了,如下:
此時(shí),可以使用%00
截?cái)喙匕裕贿^(guò)需要有前提條件:
1). PHP版本 < 5.3 (不包括5.3) ;
2). PHPmagic_quotes_gpc = off
;
3).PHP對(duì)所接收的參數(shù),如以上代碼的$_GET['file']
未使用addslashes
函數(shù)佳遣。
因?yàn)镻HP大于等于5.3的版本已經(jīng)修復(fù)了這個(gè)問(wèn)題,如果開(kāi)啟了gpc
或者使用了addslashes
函數(shù)的話則會(huì)對(duì)其進(jìn)行轉(zhuǎn)義
首先看php版本小于5.3
凡伊,并且magic_quotes_gpc = Off
零渐,1.php
內(nèi)容如下
<?php
$file = $_GET['file'] . '.php';
echo $file."<br>";
include($file);
phpinfo();
那么我們看magic_quotes_gpc = On
是什么情況呢(效果與使用函數(shù)的為一致)
接下來(lái)看php版本為5.3
的情況。
可以看到系忙。是沒(méi)有任何效果的诵盼。
總結(jié)
對(duì)于限制了包含文件后綴的情況,PHP版本小于5.3
风宁,php.inimagic_quotes_gpc = off
,對(duì)可控參數(shù)未使用addslashes
函數(shù)蛹疯,滿(mǎn)足這三個(gè)條件就可以使用%00
截?cái)唷?/p>
那么這兩種包含有什么區(qū)別呢戒财?其實(shí)是沒(méi)有區(qū)別的,原理都一樣捺弦,只不過(guò)第一種是將后綴一起傳入饮寞,第二種則在程序內(nèi)固定死了后綴。但是在滿(mǎn)足一定條件下可以使用%00
羹呵,因?yàn)楫?dāng)程序流遇到%00終止符的時(shí)候?qū)⒅苯咏K止骂际。
- 除此之外疗琉,還有包含Apache 日志文件冈欢。
具體不再講解,簡(jiǎn)單直接做一遍一看就懂了盈简。
首先第一步:
此處后來(lái)又看到一個(gè)騷姿勢(shì)凑耻,開(kāi)始是訪問(wèn)路徑由于url編碼原因需要抓包再修改太示,稍微麻煩,后來(lái)看到使用可以直接寫(xiě)進(jìn)
User Agent
里面也可以被寫(xiě)進(jìn)日志里香浩,厲害了类缤。
第二步:本地包含日志文件
注意:開(kāi)始明明php代碼寫(xiě)進(jìn)日志文件里面了,可怎么也包含不成功邻吭,弄了好久才發(fā)現(xiàn)
httpd
文件夾其他用戶(hù)沒(méi)有x
權(quán)限餐弱,此處記錄下哈!
- 遠(yuǎn)程文件包含漏洞
當(dāng)包含的文件在遠(yuǎn)程服務(wù)器上時(shí)囱晴,就形成了遠(yuǎn)程文件包含膏蚓。
遠(yuǎn)程文件包含的注意點(diǎn):
1). 需要php.ini
中allow_url_include = on
以及allow_url_fopen=on
2). 所包含遠(yuǎn)程服務(wù)器的文件后綴不能與目標(biāo)服務(wù)器語(yǔ)言相同。(比如目標(biāo)服務(wù)器是php腳本語(yǔ)言解析的畸写,那么包含的遠(yuǎn)程服務(wù)器文件后綴不能是php
)
主要解釋下第2點(diǎn):
比如遠(yuǎn)程服務(wù)器文件yuancheng.php
驮瞧,內(nèi)容為:
<?php
phpinfo();
?>
再來(lái)看下目標(biāo)服務(wù)器的信息
接下來(lái)目標(biāo)服務(wù)器包含遠(yuǎn)程服務(wù)器上的文件yuancheng.php
可以看到包含后得到的結(jié)果是我們遠(yuǎn)程機(jī)的信息,而不是我們想要的目標(biāo)機(jī)信息枯芬。為什么呢论笔?
因?yàn)槟繕?biāo)服務(wù)器包含的代碼并不是:
<?php phpinfo();?>
而是而是遠(yuǎn)程服務(wù)器執(zhí)行完這段代碼的源代碼,如下圖:
所以說(shuō)遠(yuǎn)程文件包含只有符合了以上兩點(diǎn)才能正常包含千所。
因此狂魔,正確遠(yuǎn)程包含文件漏洞利用如下:
首先確保配置文件allow_url_fopen = On
以及allow_url_include = On
,如果修改為On記得重啟服務(wù)
其次淫痰,修改文件后綴毅臊,只要不是php
就行,比如后綴為.txt
黑界,然后再來(lái)包含管嬉。
很明顯,這次就是我們想要獲取的信息了朗鸠。
接下來(lái)就嘗試拿webshell了蚯撩。
文件包含漏洞之偽協(xié)議
偽協(xié)議在文件包含的利用,本文演示以下偽協(xié)議:
data:text/plain
或 data:text/plain;base64
php://input
php://filter
file://
zip://
其它協(xié)議可閱讀官方文檔:傳送門(mén)
- data:text/plain
直接在對(duì)應(yīng)URL參數(shù)內(nèi)輸出:data:text/plain,
,需要執(zhí)行的php代碼 如下圖:
這個(gè)偽協(xié)議還有另一種使用方法烛占,那么就是將需要執(zhí)行的php代碼使用base64編碼:data:text/plain;base64,
,需要執(zhí)行的base64編碼后的php代碼
如下圖:
此處開(kāi)始在瀏覽器使用
hackbar
測(cè)試不成功胎挎,尋其原因,應(yīng)該是hackbar有問(wèn)題忆家。
注意:這里base64編碼的php代碼不能有
;
補(bǔ)充修正:回看寫(xiě)的這個(gè)犹菇,有問(wèn)題,不知道之前怎么寫(xiě)的芽卿,寫(xiě)了句這話揭芍,后經(jīng)思考應(yīng)該是<?php phpinfo();?>
base64編碼為PD9waHAgcGhwaW5mbygpOz8+
,里面有+
,所以應(yīng)該是這個(gè)原因卸例,故可以寫(xiě)為PD9waHAgcGhwaW5mbygpOz8%2b
即可称杨。
php://input
可以訪問(wèn)請(qǐng)求的原始數(shù)據(jù)的只讀流, 將post請(qǐng)求中的數(shù)據(jù)作為PHP代碼執(zhí)行肌毅。
php://filter
該偽協(xié)議可以讀取php文件代碼以base64編碼輸出,比如說(shuō)我們想讀取一個(gè)php文件但是不想讓它正常php執(zhí)行代碼后的結(jié)果姑原,我們想要這個(gè)php文件的代碼的時(shí)候就可以使用這個(gè)偽協(xié)議悬而。
使用方法:php://filter/read=convert.base64-encode/resource=需要讀取源碼的文件名
- file://
file://
用于訪問(wèn)本地文件系統(tǒng),且不受allow_url_fopen
與allow_url_include
的影響锭汛。
使用方法:file://文件絕對(duì)路徑 file://C:/Windows/system.ini
- zip://
zip://
可以訪問(wèn)壓縮文件中的文件笨奠。但是需要絕對(duì)路徑。
使用方法: zip://[壓縮包絕對(duì)路徑]#[壓縮文件內(nèi)的文件名]
在本地創(chuàng)建一個(gè)文件2.php
唤殴,并且壓縮成2.zip
壓縮包艰躺,然后包含壓縮包里面的文件:
可以看到我已經(jīng)填寫(xiě)了絕對(duì)路徑以及文件名稱(chēng),但是為什么不能成功包含呢眨八,可以看到它的報(bào)錯(cuò)Warning: include(zip://E:/soft/phpmystudy/WWW/file_include/2.zip):
我們并不是包含這個(gè)壓縮包腺兴,我們是要包含這個(gè)zip里面的文件,為什么#后面的值沒(méi)了呢廉侧,是因?yàn)?和URL規(guī)則里面的#沖突了页响,所以我們需要使用編碼%23的形式,如下圖:
文件包含漏洞防御
- PHP 中使用 open_basedir 配置限制訪問(wèn)在指定的區(qū)域
- 過(guò)濾.(點(diǎn))/(反斜杠)\(反斜杠)
- 禁止服務(wù)器遠(yuǎn)程文件包含