最近在作ctf的時候,遇見了好幾回關於php僞協議的妙用,因此經過學習整理出相關知識
文檔:http://cn2.php.net/manual/zh/wrappers.php.php#refsect2-wrappers.php-unknown-descriptioophp
php僞協議,事實上是其支持的協議與封裝協議laravel
支持的種類有這12種
* 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://的用法sql
php://
PHP 提供了一些雜項輸入/輸出(IO)流,容許訪問 PHP 的輸入輸出流、標準輸入輸出和錯誤描述符, 內存中、磁盤備份的臨時文件流以及能夠操做其餘讀取寫入文件資源的過濾器。shell
php://stdin, php://stdout 和 php://stderr
php://stdin、php://stdout 和 php://stderr 容許直接訪問 PHP 進程相應的輸入或者輸出流。 數據流引用了複製的文件描述符,因此若是你打開php://stdin並在以後關了它, 僅是關閉了複製品,真正被引用的 STDIN 並不受影響。 推薦簡單使用常量 STDIN、 STDOUT 和 STDERR 來代替手工打開這些封裝器。數組
php://stdin是隻讀的,php://stdout 和 php://stderr 是隻寫的。服務器
舉例:
php://stdin架構
1 <?php 2 while($line = fopen('php://stdin','r')) 3 {//open our file pointer to read from stdin 4 echo $line."\n"; 5 echo fgets($line);//讀取 6 } 7 ?>
能夠看到打開了一個文件指針進行讀取併發
php://stdoutapp
1 <?php 2 $fd = fopen('php://stdout', 'w'); 3 if ($fd) { 4 echo $fd."\n"; 5 fwrite($fd, "這是一個測試"); 6 fwrite($fd, "\n"); 7 fclose($fd); 8 } 9 ?>
能夠看到打開了一個文件指針進行寫入
php://stderr
1 <?php 2 $stderr = fopen( 'php://stderr', 'w' ); 3 echo $stderr."\n"; 4 fwrite($stderr, "lalala" ); 5 fclose($stderr); 6 ?>
能夠看到打開了一個文件指針進行寫入
php://input
php://input 是個能夠訪問請求的原始數據的只讀流。由於它不依賴於特定的 php.ini 指令。
注:enctype=」multipart/form-data」 的時候 php://input 是無效的。
舉例:
就拿最近的HBCTF的一道題吧
相關源碼:
1 <!-- 2 $user = $_GET["user"]; 3 $file = $_GET["file"]; 4 $pass = $_GET["pass"]; 5 6 if(isset($user)&&(file_get_contents($user,'r')==="the user is admin")){ 7 echo "hello admin!<br>"; 8 include($file); //class.php 9 }else{ 10 echo "you are not admin ! "; 11 }
php://output
php://output 是一個只寫的數據流, 容許你以 print 和 echo 同樣的方式 寫入到輸出緩衝區。
舉例:
1 <?php 2 $out=fopen("php://stdout", 'w'); 3 echo $out."\n"; 4 fwrite($out , "this is a test"); 5 fclose($out); 6 ?>
php://fd
php://fd 容許直接訪問指定的文件描述符。 例如 php://fd/3 引用了文件描述符 3。
php://memory 和 php://temp
php://memory 和 php://temp 是一個相似文件 包裝器的數據流,容許讀寫臨時數據。 二者的惟一區別是 php://memory 老是把數據儲存在內存中, 而 php://temp 會在內存量達到預約義的限制後(默認是 2MB)存入臨時文件中。 臨時文件位置的決定和 sys_get_temp_dir() 的方式一致。
php://temp 的內存限制可經過添加 /maxmemory:NN 來控制,NN 是以字節爲單位、保留在內存的最大數據量,超過則使用臨時文件。
php://filter
能夠說這是最常使用的一個僞協議,通常能夠利用進行任意文件讀取。
php://filter 是一種元封裝器, 設計用於數據流打開時的篩選過濾應用。 這對於一體式(all-in-one)的文件函數很是有用,相似 readfile()、 file() 和 file_get_contents(), 在數據流內容讀取以前沒有機會應用其餘過濾器。
php://filter 參數
封裝協議摘要(針對 php://filter,參考被篩選的封裝器。)
依舊拿HBCTF舉例好啦
明顯將class.php
的代碼以base64的形式輸出,固然也能夠試試字符轉成rot13形式
這就涉及過濾器的靈活使用
php://filter/read=<讀鏈須要應用的過濾器列表>
這個參數採用一個或以管道符 | 分隔的多個過濾器名稱。
過濾器有不少種,有字符串過濾器、轉換過濾器、壓縮過濾器、加密過濾器
進行rot13轉換
string.toupper
將字符所有大寫
string.tolower
將字符所有小寫
string.strip_tags
去除空字符、HTML 和 PHP 標記後的結果
着重介紹一下這個,功能相似於strip_tags()函數,若不想某些字符不被消除,後面跟上字符,可利用字符串或是數組兩種方式
1 <?php 2 $fp = fopen('php://output', 'w'); 3 stream_filter_append($fp, 'string.rot13'); 4 echo "rot13:"; 5 fwrite($fp, "This is a test.\n"); 6 fclose($fp); 7 8 $fp = fopen('php://output', 'w'); 9 stream_filter_append($fp, 'string.toupper'); 10 echo "Upper:"; 11 fwrite($fp, "This is a test.\n"); 12 fclose($fp); 13 14 $fp = fopen('php://output', 'w'); 15 stream_filter_append($fp, 'string.tolower'); 16 echo "Lower:"; 17 fwrite($fp, "This is a test.\n"); 18 fclose($fp); 19 20 $fp = fopen('php://output', 'w'); 21 echo "Del1:"; 22 stream_filter_append($fp, 'string.strip_tags', STREAM_FILTER_WRITE); 23 fwrite($fp, "<b>This is a test.</b>!!!!<h1>~~~~</h1>\n"); 24 fclose($fp); 25 26 $fp = fopen('php://output', 'w'); 27 echo "Del2:"; 28 stream_filter_append($fp, 'string.strip_tags', STREAM_FILTER_WRITE, "<b>"); 29 fwrite($fp, "<b>This is a test.</b>!!!!<h1>~~~~</h1>\n"); 30 fclose($fp); 31 32 $fp = fopen('php://output', 'w'); 33 stream_filter_append($fp, 'string.strip_tags', STREAM_FILTER_WRITE, array('b','h1')); 34 echo "Del3:"; 35 fwrite($fp, "<b>This is a test.</b>!!!!<h1>~~~~</h1>\n"); 36 fclose($fp); 37 ?>
base64 編碼解碼
convert.base64-encode和convert.base64-decode使用這兩個過濾器等同於分別用 base64_encode()和 base64_decode()函數處理全部的流數據。 convert.base64-encode支持以一個關聯數組給出的參數。若是給出了line-length,base64 輸出將被用 line-length個字符爲長度而截成塊。若是給出了* line-break-chars*,每塊將被用給出的字符隔開。這些參數的效果和用 base64_encode()再加上 chunk_split()相同。
convert.quoted-printable-encode & convert.quoted-printable-decode
quoted-printable 編碼解碼
convert.quoted-printable-encode和 convert.quoted-printable-decode等同於用 quoted_printable_decode()函數處理全部的流數據。沒有和* convert.quoted-printable-encode*相對應的函數。* convert.quoted-printable-encode*支持以一個關聯數組給出的參數。除了支持和 convert.base64-encode同樣的附加參數外,* convert.quoted-printable-encode*還支持布爾參數 binary和 force-encode-first。 convert.base64-decode只支持 line-break-chars參數做爲從編碼載荷中剝離的類型提示。
1 <?php 2 $fp = fopen('php://output', 'w'); 3 stream_filter_append($fp, 'convert.base64-encode'); 4 echo "base64-encode:"; 5 fwrite($fp, "This is a test.\n"); 6 fclose($fp); 7 8 $param = array('line-length' => 8, 'line-break-chars' => "\n"); 9 $fp = fopen('php://output', 'w'); 10 stream_filter_append($fp, 'convert.base64-encode', STREAM_FILTER_WRITE, $param); 11 echo "\nbase64-encode-split:\n"; 12 fwrite($fp, "This is a test.\n"); 13 fclose($fp); 14 15 $fp = fopen('php://output', 'w'); 16 stream_filter_append($fp, 'convert.base64-decode'); 17 echo "\nbase64-decode:"; 18 fwrite($fp, "VGhpcyBpcyBhIHRlc3QuCg==\n"); 19 fclose($fp); 20 21 $fp = fopen('php://output', 'w'); 22 stream_filter_append($fp, 'convert.quoted-printable-encode'); 23 echo "quoted-printable-encode:"; 24 fwrite($fp, "This is a test.\n"); 25 fclose($fp); 26 27 $fp = fopen('php://output', 'w'); 28 stream_filter_append($fp, 'convert.quoted-printable-decode'); 29 echo "\nquoted-printable-decode:"; 30 fwrite($fp, "This is a test.=0A"); 31 fclose($fp); 32 ?>
壓縮過濾器
zlib.deflate和 zlib.inflate
zlib.deflate(壓縮)和 zlib.inflate(解壓)實現了定義與 » RFC 1951的壓縮算法。 deflate過濾器能夠接受以一個關聯數組傳遞的最多三個參數。* level*定義了壓縮強度(1-9)。數字更高一般會產生更小的載荷,但要消耗更多的處理時間。存在兩個特殊壓縮等級:0(徹底不壓縮)和 -1(zlib 內部默認值,目前是 6)。 window是壓縮回溯窗口大小,以二的次方表示。更高的值(大到 15 —— 32768 字節)產生更好的壓縮效果但消耗更多內存,低的值(低到 9 —— 512 字節)產生產生較差的壓縮效果但內存消耗低。目前默認的 window大小是 15。 memory用來指示要分配多少工做內存。合法的數值範圍是從 1(最小分配)到 9(最大分配)。內存分配僅影響速度,不會影響生成的載荷的大小。
Note: 由於最經常使用的參數是壓縮等級,也能夠提供一個整數值做爲此參數(而不用數組)。
bzip2.compress和 bzip2.decompress
bzip2.compress過濾器接受以一個關聯數組給出的最多兩個參數:* blocks*是從 1 到 9 的整數值,指定分配多少個 100K 字節的內存塊做爲工做區。 work是 0 到 250 的整數值,指定在退回到一個慢一些,但更可靠的算法以前作多少次常規壓縮算法的嘗試。調整此參數僅影響到速度,壓縮輸出和內存使用都不受此設置的影響。將此參數設爲 0 指示 bzip 庫使用內部默認算法。 bzip2.decompress過濾器僅接受一個參數,能夠用普通的布爾值傳遞,或者用一個關聯數組中的* small*單元傳遞。當* small*設爲&true; 值時,指示 bzip 庫用最小的內存佔用來執行解壓縮,代價是速度會慢一些。
phper在進階的時候總會遇到一些問題和瓶頸,業務代碼寫多了沒有方向感,不知道該從那裏入手去提高,對此我整理了一些資料,包括但不限於:分佈式架構、高可擴展、高性能、高併發、服務器性能調優、TP6,laravel,YII2,Redis,Swoole、Kafka、Mysql優化、shell腳本、Docker、微服務、Nginx等多個知識點高級進階乾貨須要的能夠免費分享給你們,須要的請點擊(→)個人官方羣
加密過濾器
_mcrypt.*_和 _mdecrypt.*_使用 libmcrypt 提供了對稱的加密和解密。這兩組過濾器都支持 mcrypt 擴展庫中相同的算法,格式爲_mcrypt.ciphername_,其中 ciphername是密碼的名字,將被傳遞給 mcrypt_module_open()。有如下五個過濾器參數可用:
mcrypt 過濾器參數