php反序列化初步认识

之前国赛的时候就碰到了php反序列化的问题,当时没来得及细看。结果前天在实验吧上做题又碰到了这个问题。于是立马去看了下,然后写个简要的总结。

前言

1、什么是序列化\反序列化?
简单来说
序列化serialize():把对象转换为字符串用于传输或存储。
反序列化unserialize():把字符串又变回对象。
举个例子:

<?php
class A
{
    public $name = "nono";
    public $age = "12";
}
$a = new A();
$a->name = "Jon";
$a->age = "20";
echo serialize($a);//将对象a序列化
?>

这一段代码执行的结果为:
在这里插入图片描述
这就是把对象序列化之后的结果。其中O表示object,1为对象名称字符数,‘A’是对象名,2表示对象有两个变量,括号内分别是每个变量的变量类型,变量名长度,变量名以及变量值。
至于反序列化,就是再把这串字符串变回原来的对象。

2、常用魔术方法:
魔术函数一般以_开头,会在某些条件下自动触发执行。其中一部分如:
__construct()当一个对象创建时被调用
__destruct()当一个对象销毁时被调用
__wakeup在序列化之后立即被调用

实例:

下面具体分析一下网上找到的一道简单的题:

<?php 
    require_once('shield.php');
    $x = new Shield();
    isset($_GET['class']) && $g = $_GET['class'];
    if (!empty($g)) {
        $x = unserialize($g);
    }
    echo $x->readfile();
?>

在这里,先包含shield.php。创建对象 $x,然后传入参数 class赋值给 $g,然后将 $g反序列化之后赋值给 $x,最后输出 $x的readfile()方法。

shield.php如下:

<?php
    //flag is in pctf.php
    class Shield {
        public $file;
        function __construct($filename = '') {
            $this -> file = $filename;
        }
        function readfile() {
            if (!empty($this->file) && stripos($this->file,'..')===FALSE  
            && stripos($this->file,'/')===FALSE && stripos($this->file,'\\')==FALSE) {
                return @file_get_contents($this->file);
            }
        }
    }
?>

这段代码首先定义了一个类Shield,其中有一个变量 $file,一个魔术方法_construct(),其将在类实例化的时候调用,接着是一个readfile()方法。
那么很明确的是我们要传入的参数是一个序列化后的字符串,并且按照提示:flag is in pctf.php,于是构造对象为: O:6:”Shield”:1:{s:4:”file”;s:8:”pctf.php”;}。

刚刚创建对象$x时,会调用_construct()方法导致 $x-file为空,但是传入参数后,通过 $x = unserialize( $g),将 $g反序列化后赋值给 $x,会导致 $x->file = “pctf.php”,接着调用readfile()方法。 !empty( $this->file)为真, stripos()函数是在第一个参数中查找第二个参数第一次出现的位置,而"…","/","\"均未在 $this-file中出现,因此返回值均为false,直接执行return语句,@file_get_contents( $this->file)将 $this-file即pctf.php这个文件的内容(含flag)读入一个字符串,然后由echo $x->readfile()输出。得到结果。

猜你喜欢

转载自blog.csdn.net/weixin_43914930/article/details/89776979