什麼是php偽協議
在 PHP 中,"偽協議"是一種特殊的語法,用於訪問不同的資源或執行特定的操作。這些偽協議以 php://
開頭,後面跟著特定的指示符或引數,以實現不同的功能。這些偽協議提供了一種方便的方式來處理各種輸入輸出操作,而不必依賴於實際的檔案或網路資源。
簡單的理解就是,在URL中使用特殊的協議字首來指示PHP執行特定的程式碼。
php.ini引數設定
在php.ini裡有兩個重要的引數allow_url_fopen、allow_url_include。
-
allow_url_fopen:預設值是ON。允許url裡的封裝協議訪問檔案;
-
allow_url_include:預設值是OFF。不允許包含url裡的封裝協議包含檔案;
有哪些偽協議
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:// — 處理互動式的流
應用場景
檔案包含
(關於檔案包含的函式)
include()、require()、include_once()、require_once()、highlight_file()
show_source() 、readfile() 、file_get_contents() 、fopen() 、file()
偽協議詳解
data://
資料流封裝器,以傳遞相應格式的資料。可以讓使用者來控制輸入流,當它與包含函式結合時,使用者輸入的data://流會被當作php檔案執行。
allow_url_fopen和allow_url_include都需要開啟。
example:
1、data://text/plain,
http://127.0.0.1/include.php?file=data://text/plain,<?php%20phpinfo();?>
2、data://text/plain;base64,
http://127.0.0.1/include.php?file=data://text/plain;base64,PD9waHAgcGhwaW5mbygpOz8%2b
file://
用於訪問本地檔案系統,並且不受allow_url_fopen,allow_url_include影響
file://協議主要用於訪問檔案(絕對路徑、相對路徑以及網路路徑)
比如:www.xx.com?file=file:///etc/passwd
php://
不需要開啟allow_url_fopen,僅php://input、php://stdin、php://memory和php://temp需要開啟allow_url_include。
php://filter
一箇中介軟體,在讀入或寫入資料的時候對資料進行處理後輸出的過程。可以獲取指定檔案原始碼。當它與包含函式結合時,php://filter流會被當作php檔案執行。所以我們一般對其進行base64編碼,讓其不執行,展現在頁面上。從而導致任意檔案讀取。
ctf解題常用:
變數=php://filter/read=convert.base64-encode/resource=檔名
使用的convert.base64-encode,是一種過濾器。
協議引數
利用filter偽協議繞過死亡exit
何為死亡exit?
舉個例子:
file_put_contents($content, '<?php exit();' . $content);
// 或者這樣
file_put_contents($content, '<?php exit();?>' . $content);
如果想插入一句話木馬,檔案內容會變成這樣
<?php exit();?>
<?php @eval($_POST['test']);?>
即使插入了一句話木馬,在被使用的時候也無法被執行。這樣的死亡exit通常存在於快取、配置檔案等等不允許使用者直接訪問的檔案當中。
如何繞過?————filter偽協議+base64decode
利用php://filter的base64-decode
方法,將$content
解碼,利用php base64_decode
函式特性去除死亡exit。base64編碼中只包含64個可列印字元,當PHP遇到不可解碼的字元時,會選擇性的跳過。
當$content
包含 <?php exit; ?>
時,解碼過程會先去除識別不了的字元,< ; ? >
和空格等都將被去除,於是剩下的字元就只有phpexit
以及我們傳入的字元了。由於base64是4個byte一組,再新增一個字元例如新增字元a
後,將phpexita
當做兩組base64進行解碼,也就繞過這個死亡exit了。
這個時候後面再加上編碼後的一句話木馬,就可以getshell了。
php://input
可以訪問請求的原始資料的只讀流, 將post請求中的資料作為PHP程式碼執行。在POST請求中訪問POST的data部分,在enctype="multipart/form-data"
的時候php://input 是無效的。
當傳進去的引數作為檔名變數去開啟檔案時,可以將引數php://input,同時post方式傳進去值作為檔案內容,供php程式碼執行時當做檔案內容讀取。
其他
php://stdin、php://stdout 和 php://stderr 允許直接訪問 PHP 程序相應的輸入或者輸出流。 資料流引用了複製的檔案描述符,所以如果你開啟 php://stdin 並在之後關了它, 僅是關閉了複製品,真正被引用的 STDIN 並不受影響。
注意 PHP 在這方面的行為有很多 BUG 直到 PHP 5.2.1。 推薦簡單使用常量 STDIN、 STDOUT 和 STDERR 來代替手工開啟這些封裝器。
php://stdin 是隻讀的, php://stdout 和 php://stderr 是隻寫的。
zip://
可以訪問壓縮包裡面的檔案。當它與包含函式結合時,zip://流會被當作php檔案執行。從而實現任意程式碼執行。相同型別的還有zlib://和bzip2://。
可以配合檔案上傳獲取webshell,將shell.txt壓縮成zip,再將字尾名改為jpg上傳,透過zip偽協議訪問壓縮包裡的檔案,來連線木馬
?url=zip://shell.jpg
注意:此處只能傳入絕對路徑,要用#
分隔壓縮包和壓縮包裡的內容,並且#要用url編碼%23。只要是zip的壓縮包即可,字尾名可以任意更改。
phar://
與zip://類似,同樣可以訪問zip格式壓縮包內容
http://127.0.0.1/include.php?file=phar://E:/phpStudy/PHPTutorial/WWW/phpinfo.zip/phpinfo.txt
利用 phar 擴充 php 反序列化漏洞攻擊面
http:// & https://
allow_url_fopen和allow_url_include都需要開啟。
常規 URL 形式,允許透過 HTTP 1.0 的 GET方法,以只讀訪問檔案或資源。CTF中通常用於遠端包含。
http://127.0.0.1/include.php?file=http://127.0.0.1/phpinfo.txt
參考文章
https://juejin.cn/post/7163831572158742535
https://blog.csdn.net/IDHALASHAO/article/details/130368938
https://crayon-xin.github.io/2018/04/15/php偽協議-php/
https://segmentfault.com/a/1190000018991087
https://paper.seebug.org/680/