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函數。
記住,序列化物件包含攻擊者控制的物件值。
你可能在網路應用程式原始碼中找到一個定義__wakeup或__destruct的類,這些函數會影響網路應用程式。
例如,我們可能會找到一個暫時將日誌儲存到檔案中的類別。當銷毀時物件可能不再需要日誌檔案並將其刪除。把下面這段程式碼儲存為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關於反序列化物件注入漏洞的詳細內容。更多資訊請關注PHP中文網其他相關文章!