PHP基礎知識——PHP偽協議

smile_2233發表於2024-04-11

什麼是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/

相關文章