最近在做ctf的時候,碰見了好幾次關于php偽協議的妙用,所以通過學習整理出相關知識
檔案:http://cn2.php.net/manual/zh/wrappers.php.php#refsect2-wrappers.php-unknown-descriptioo
php偽協議,事實上是其支持的協議與封裝協議
支持的種類有這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://的用法
php://
PHP 提供了一些雜項輸入/輸出(IO)流,允許訪問 PHP 的輸入輸出流、標準輸入輸出和錯誤描述符, 記憶體中、磁盤備份的臨時檔案流以及可以操作其他讀取寫入檔案資源的過濾器,
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://stdout
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=<讀鏈需要應用的過濾器串列>
這個引數采用一個或以管道符 | 分隔的多個過濾器名稱,

過濾器
過濾器有很多種,有字串過濾器、轉換過濾器、壓縮過濾器、加密過濾器
字串過濾器
- string.rot13
-
進行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 ?>

轉換過濾器
- convert.base64-encode & convert.base64-decode
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 過濾器引數

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/131469.html
標籤:PHP
