php僞協議

最近在做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://stdinphp://stdoutphp://stderr 允許直接訪問 PHP 進程相應的輸入或者輸出流。 數據流引用了複製的文件描述符,所以如果你打開php://stdin並在之後關了它, 僅是關閉了複製品,真正被引用的 STDIN 並不受影響。 推薦簡單使用常量 STDIN、 STDOUT 和 STDERR 來代替手工打開這些封裝器。

php://stdin是隻讀的,php://stdoutphp://stderr 是隻寫的。

舉例:

php://stdin

<?php
    while($line = fopen('php://stdin','r'))
    {//open our file pointer to read from stdin
        echo $line."\n";
        echo fgets($line);//讀取
    }
?>

這裏寫圖片描述

可以看到打開了一個文件指針進行讀取

php://stdout

<?php
    $fd = fopen('php://stdout', 'w');
    if ($fd) {
        echo $fd."\n";
        fwrite($fd, "這是一個測試");
        fwrite($fd, "\n");
        fclose($fd);
    }
?>

這裏寫圖片描述

可以看到打開了一個文件指針進行寫入

php://stderr

<?php
    $stderr = fopen( 'php://stderr', 'w' );
    echo $stderr."\n";
    fwrite($stderr, "lalala" );
    fclose($stderr);
?>

這裏寫圖片描述

可以看到打開了一個文件指針進行寫入

php://input

php://input 是個可以訪問請求的原始數據的只讀流。因爲它不依賴於特定的 php.ini 指令。
注:enctype=”multipart/form-data” 的時候 php://input 是無效的。

舉例:

就拿最近的HBCTF的一道題吧
相關源碼:

<!--
$user = $_GET["user"];
$file = $_GET["file"];
$pass = $_GET["pass"];

if(isset($user)&&(file_get_contents($user,'r')==="the user is admin")){
    echo "hello admin!<br>";
    include($file); //class.php
}else{
    echo "you are not admin ! ";
}
 -->

這裏寫圖片描述

php://output

php://output 是一個只寫的數據流, 允許你以 print 和 echo 一樣的方式 寫入到輸出緩衝區。

舉例:

<?php
    $out=fopen("php://stdout", 'w');  
    echo $out."\n";
    fwrite($out , "this is a test");
    fclose($out);
?>

這裏寫圖片描述

php://fd

php://fd 允許直接訪問指定的文件描述符。 例如 php://fd/3 引用了文件描述符 3。

php://memory 和 php://temp

php://memoryphp://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 參數

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

封裝協議摘要(針對 php://filter,參考被篩選的封裝器。)

屬性 支持
受限於 allow_url_include php://inputphp://stdinphp://memoryphp://temp
允許讀取 php://stdinphp://inputphp://fdphp://memoryphp://temp
允許寫入 php://stdoutphp://stderrphp://outputphp://fdphp://memoryphp://temp
允許追加 php://stdoutphp://stderrphp://outputphp://fdphp://memoryphp://temp(等於寫入)
允許同時讀寫 php://fdphp://memoryphp://temp
支持 stat() php://memoryphp://temp
僅僅支持 stream_select() php://stdinphp://stdoutphp://stderrphp://fdphp://temp

舉例:

依舊拿HBCTF舉例好啦
這裏寫圖片描述
明顯將class.php的代碼以base64的形式輸出,當然也可以試試字符轉成rot13形式
這裏寫圖片描述

這就涉及過濾器的靈活使用
php://filter/read=<讀鏈需要應用的過濾器列表>
這個參數採用一個或以管道符 | 分隔的多個過濾器名稱。
這裏寫圖片描述

過濾器

過濾器有很多種,有字符串過濾器、轉換過濾器、壓縮過濾器、加密過濾器

字符串過濾器


  • 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);

    $fp = fopen('php://output', 'w');
    stream_filter_append($fp, 'string.toupper');
    echo "Upper:";
    fwrite($fp, "This is a test.\n");
    fclose($fp);

    $fp = fopen('php://output', 'w');
    stream_filter_append($fp, 'string.tolower');
    echo "Lower:";
    fwrite($fp, "This is a test.\n");
    fclose($fp);

    $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);

    $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);

    $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);
?>

這裏寫圖片描述

轉換過濾器


  • convert.base64-encode & convert.base64-decode
base64 編碼解碼
convert.base64-encodeconvert.base64-decode使用這兩個過濾器等同於分別用 base64_encode()base64_decode()函數處理所有的流數據。 convert.base64-encode支持以一個關聯數組給出的參數。如果給出了line-lengthbase64 輸出將被用 line-length個字符爲長度而截成塊。如果給出了* line-break-chars*,每塊將被用給出的字符隔開。這些參數的效果和用 base64_encode()再加上 chunk_split()相同。 convert.quoted-printable-encode & convert.quoted-printable-decode
quoted-printable
編碼解碼
convert.quoted-printable-encodeconvert.quoted-printable-decode等同於用 quoted_printable_decode()函數處理所有的流數據。沒有和* convert.quoted-printable-encode*相對應的函數。* convert.quoted-printable-encode*支持以一個關聯數組給出的參數。除了支持和 convert.base64-encode一樣的附加參數外,* convert.quoted-printable-encode*還支持布爾參數 binaryforce-encode-firstconvert.base64-decode只支持 line-break-chars參數作爲從編碼載荷中剝離的類型提示。

舉例:

<?php
    $fp = fopen('php://output', 'w');
    stream_filter_append($fp, 'convert.base64-encode');
    echo "base64-encode:";
    fwrite($fp, "This is a test.\n");
    fclose($fp);

    $param = array('line-length' => 8, 'line-break-chars' => "\n");
    $fp = fopen('php://output', 'w');
    stream_filter_append($fp, 'convert.base64-encode', STREAM_FILTER_WRITE, $param);
    echo "\nbase64-encode-split:\n";
    fwrite($fp, "This is a test.\n");
    fclose($fp);

    $fp = fopen('php://output', 'w');
    stream_filter_append($fp, 'convert.base64-decode');
    echo "\nbase64-decode:";
    fwrite($fp, "VGhpcyBpcyBhIHRlc3QuCg==\n");
    fclose($fp);

    $fp = fopen('php://output', 'w');
    stream_filter_append($fp, 'convert.quoted-printable-encode');
    echo "quoted-printable-encode:";
    fwrite($fp, "This is a test.\n");
    fclose($fp);

    $fp = fopen('php://output', 'w');
    stream_filter_append($fp, 'convert.quoted-printable-decode');
    echo "\nquoted-printable-decode:";
    fwrite($fp, "This is a test.=0A");
    fclose($fp);
?>

這裏寫圖片描述

壓縮過濾器


  • 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 庫用最小的內存佔用來執行解壓縮,代價是速度會慢一些。

加密過濾器

_mcrypt.*__mdecrypt.*_使用 libmcrypt 提供了對稱的加密和解密。這兩組過濾器都支持 mcrypt 擴展庫中相同的算法,格式爲_mcrypt.ciphername_,其中 ciphername是密碼的名字,將被傳遞給 mcrypt_module_open()。有以下五個過濾器參數可用:

mcrypt 過濾器參數

參數 是否必須 默認值 取值舉例
mode 可選 cbc cbc, cfb, ecb, nofb, ofb, stream
algorithms_dir 可選 ini_get(‘mcrypt.algorithms_dir’) algorithms 模塊的目錄
modes_dir 可選 ini_get(‘mcrypt.modes_dir’) modes 模塊的目錄
iv 必須 N/A 典型爲 8,16 或 32 字節的二進制數據。根據密碼而定
key 必須 N/A 典型爲 8,16 或 32 字節的二進制數據。根據密碼而定
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章