html' target='_blank'>php對象注入是一個非常常見的漏洞,這個類型的漏洞雖然有些難以利用,但仍舊非常危險。本文主要和大家分享php關于反序列化對象注入漏洞詳解,希望能幫助到大家。
分析php基礎serialize 把一個對象轉成字符串形式, 可以用于保存
unserialize 把serialize序列化后的字符串變成一個對象
php類可能會包含一些特殊的函數叫magic函數,magic函數命名是以符號__開頭的,
比如 __construct, __destruct, __toString, __sleep, __wakeup等等。
這些函數在某些情況下會自動調用,比如
__construct當一個對象創建時被調用,
__destruct當一個對象銷毀時被調用,
__toString當一個對象被當作一個字符串使用。
舉個例子:
<?php class TestClass { public $variable = 'This is a string'; public function PrintVariable() { echo $this->variable . '<br />'; } public function __construct() { echo '__construct <br />'; } public function __destruct() { echo '__destruct <br />'; } public function __toString() { return '__toString<br />'; } } $object = new TestClass(); $object->PrintVariable(); echo $object; ?>
php允許保存一個對象方便以后重用,這個過程被稱為序列化。
為什么要有序列化這種機制呢?
在傳遞變量的過程中,有可能遇到變量值要跨腳本文件傳遞的過程。試想,如果為一個腳本中想要調用之前一個腳本的變量,但是前一個腳本已經執行完畢,所有的變量和內容釋放掉了,我們要如何操作呢?難道要前一個腳本不斷的循環,等待后面腳本調用?這肯定是不現實的。
serialize和unserialize就是用來解決這一問題的。serialize可以將變量轉換為字符串并且在轉換中可以保存當前變量的值;unserialize則可以將serialize生成的字符串變換回變量。這樣在跨腳本傳輸和執行就完美解決了。
magic函數__construct和__destruct會在對象創建或者銷毀時自動調用;
__sleep magic方法在一個對象被序列化的時候調用;
__wakeup magic方法在一個對象被反序列化的時候調用。
<?phpclass User { public $age = 0; public $name = ''; public function Printx() { echo $this->name.' is '.$this->age.' years old.<br/>'; } public function __construct() { echo '__construct<br />'; } public function __destruct() { echo '__destruct<br />'; } public function __wakeup() { echo '__wakeup<br />'; } public function __sleep() { echo '__sleep<br />'; return array('name', 'age'); } }$usr = new User(); $usr->age = 20; $usr->name = 'John'; $usr->Printx(); echo serialize($usr);echo '<br/>'; $str = 'O:4:"User":2:{s:3:"age";i:20;s:4:"name";s:4:"John";}'; $user2 = unserialize($str);$user2->Printx();?>
現在我們了解序列化是如何工作的,但是我們如何利用它呢?
有多種可能的方法,取決于應用程序、可用的類和magic函數。
記住,序列化對象包含攻擊者控制的對象值。
你可能在Web應用程序源代碼中找到一個定義__wakeup或__destruct的類,這些函數會影響Web應用程序。
例如,我們可能會找到一個臨時將日志存儲到文件中的類。當銷毀時對象可能不再需要日志文件并將其刪除。把下面這段代碼保存為log.php。
<?php //log.php class LogFile { // log文件名 public $filename = 'error.log'; // 儲存日志文件 public function LogData($text) { echo 'Log some data: ' . $text . '<br />'; file_put_contents($this->filename, $text, FILE_APPEND); } // 刪除日志文件 public function __destruct() { echo '__destruct deletes "' . $this->filename . '" file. <br />'; unlink(dirname(__FILE__) . '/' . $this->filename); } } ?>
test.php 假設這是給用戶的php。
<?php //test.php include 'logfile.php'; // ... 一些使用LogFile類的代碼... // 簡單的類定義 class User { // 類數據 public $age = 0; public $name = ''; // 輸出數據 public function PrintData() { echo 'User ' . $this->name . ' is ' . $this->age . ' years old. <br />'; } } // 重建用戶輸入的數據 $usr = unserialize($_GET['usr_serialized']); ?>
123.php
<?php //123.php include 'logfile.php'; $obj = new LogFile(); $obj->filename = '1.php'; echo serialize($obj) . '<br />'; ?>
開始有一個1.php:
現在用戶傳入一個序列化字符串,test.php將其反序列化,
http://127.0.0.1/test.php?usr_serialized=
O:7:%22LogFile%22:1:{s:8:%22filename%22;s:5:%221.php%22;}
結果,解析出來的對象,在釋放過程中,調用了log.php的__destruct()函數,把文件1.php給刪除了。
在變量可控并且進行了unserialize操作的地方注入序列化對象,實現代碼執行或者其它坑爹的行為。
先不談 __wakeup 和 __destruct,還有一些很常見的注入點允許你利用這個類型的漏洞,一切都是取決于程序邏輯。
舉個例子,某用戶類定義了一個__toString為了讓應用程序能夠將類作為一個字符串輸出(echo $obj),而且其他類也可能定義了一個類允許__toString讀取某個文件。
也可以使用其他magic函數:
如果對象將調用一個不存在的函數__call將被調用;
如果對象試圖訪問不存在的類變量__get和__set將被調用。
但是利用這種漏洞并不局限于magic函數,在普通的函數上也可以采取相同的思路。
例如User類可能定義一個get方法來查找和打印一些用戶數據,但是其他類可能定義一個從數據庫獲取數據的get方法,這從而會導致SQL注入漏洞。
set或write方法會將數據寫入任意文件,可以利用它獲得遠程代碼執行。
唯一的技術問題是注入點可用的類,但是一些框架或腳本具有自動加載的功能。最大的問題在于人:理解應用程序以能夠利用這種類型的漏洞,因為它可能需要大量的時間來閱讀和理解代碼。
相關推薦:
PHP序列化和反序列化原理詳解
序列化和反序列化的詳細介紹
javascript實現json的序列化和反序列化功能示例
以上就是php關于反序列化對象注入漏洞的詳細內容,更多請關注 其它相關文章!
鄭重聲明:本文版權歸原作者所有,轉載文章僅為傳播更多信息之目的,如作者信息標記有誤,請第一時間聯系我們修改或刪除,多謝。
新聞熱點
疑難解答