PHP審計之POP鏈挖掘

PHP審計之POP鏈挖掘

前言

續上文中的php反序列化,繼續來看,這個POP的挖掘思路。在其中一直構思基於AST去自動化挖掘POP鏈,迫於開發能力有限。沒有進展,隨後找到了一個別的師傅已經實現好的項目。

魔術方法

__wakeup() //使用unserialize時觸發
__sleep() //使用serialize時觸發
__destruct() //對象被銷燬時觸發
__call() //在對象上下文中調用不可訪問的方法時觸發
__callStatic() //在靜態上下文中調用不可訪問的方法時觸發
__get() //用於從不可訪問的屬性讀取數據
__set() //用於將數據寫入不可訪問的屬性
__isset() //在不可訪問的屬性上調用isset()或empty()觸發
__unset() //在不可訪問的屬性上使用unset()時觸發
__toString() //把類當作字符串使用時觸發,file_exists()判斷也會觸發
__invoke() //當腳本嘗試將對象調用爲函數時觸發

__call__callstatic

現實情況下__call的利用居多,該魔術方法觸發的條件是在對象上下文中調用不可訪問的方法時觸發。

調用流程如下:

$this->a() ==> 當前類a方法 ==> 父類a方法 ==> 當前類__call方法 ==> 父類__call方法

如果觸發__call方法,那麼a,即方法名,會作爲__call的方法的第一個參數,而參數列表會作爲__call的方法第二個參數。

來看到代碼

function __destruct(){
    $this->a->b();
}

這裏有2個利用路徑,一個是$this->a中構造一個存在方法的實例化類,另一種方式是找一個不存在b方法並且存在__call方法的類,當b不存在時,即自動調用__call

__callstatic方法只有在調用到靜態方法的時候才能觸發

__get__set

不存在該類變量或者不可訪問時,則會調用對應的__get方法

$this->a ==> 當前類a變量 ==> 父類a變量 ==> 當前類__get方法 ==> 父類__get方法

__get代碼案例

function __destruct(){
    echo $this->a;
}

調用不存在變量a,即會自動觸發__get方法,

數據寫入不可訪問的變量或不存在的變量即調用__set

function __destruct(){
    $this->a = 1;
}

__toString

把類當作字符串使用時觸發

$this->_adapterName = $adapterName;
$adapterName = 'xxx' . $adapterName;

POP鏈挖掘

此前構思的自動化挖掘POP鏈的功能已經被其他師傅實現了,在此就不班門弄斧了,直接拿現成的來用。
思路其實就是尋找__destruct方法,作爲入口點,然後尋找一個回調函數作爲末端。而中間需要尋找各種中間鏈,將其串聯起來。串聯的方法基本上就是一些魔術方法和一些自定義的方法。

項目地址:https://github.com/LoRexxar/Kunlun-M

cp Kunlun_M/settings.py.bak Kunlun_M/settings.py

python kunlun.py init initialize

python kunlun.py config load

python kunlun.py plugin php_unserialize_chain_tools -t C:\kyxscms-1.2.7

結果:

 [20:28:51] [PhpUnSerChain] New Source __destruct() in thinkphp#library#think#Process_php.Class-Process
 [20:28:51] thinkphp#library#think#Process_php.Class-Process
 newMethod                        Method-__destruct()
 [20:28:51] thinkphp#library#think#Process_php.Class-Process.Method-__destruct
 MethodCall                       Variable-$this->stop()
 [20:28:51] thinkphp#library#think#Process_php.Class-Process.Method-stop
 MethodCall                       Variable-$this->updateStatus('Constant-false',)
 [20:28:51] thinkphp#library#think#Process_php.Class-Process.Method-updateStatus
 MethodCall                       Variable-$this->readPipes('Variable-$blocking', '\ === Constant-DIRECTORY_SEPARATOR ? 627')
 [20:28:51] thinkphp#library#think#Process_php.Class-Process.Method-readPipes
 MethodCall                       Variable-$this->processPipes->readAndWrite('Variable-$blocking', 'Variable-$close')
 [20:28:51] thinkphp#library#think#console#Output_php.Class-Output
 newMethod                        Method-__call('$method', '$args')
 [20:28:51] thinkphp#library#think#console#Output_php.Class-Output.Method-__call.If
 FunctionCall                     call_user_func_array("Array-['Variable-$this', 'block']", 'Variable-$args')
 [20:28:51] [PhpUnSerChain] UnSerChain is available.

這其實利用鏈就清晰了

Process->__destruct ==>Process->stop ==>Process->updateStatus ==> Process->readPipes ==> Output->readAndWrite ==> Output->__call==> call_user_func_array()

參考

淺析 PHP 反序列化漏洞的利用與審計

如何自動化挖掘php反序列化鏈 - phpunserializechain誕生記

結尾

但該工具並沒有達到我個人的預期,因爲該工具中只是使用__destruct這單個方法作爲反序列化的入口點。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章