反序列化及PHP魔法函数

简介: 反序列化及PHP魔法函数

1、原理

PHP反序列化也叫PHP对象注入,形成的原因是程序未对用户输入的序列化字符串进行检测,导致攻击者可以控制反序列化过程,从而导致代码执行、文件操作、执行数据库操作等参数不可控。反序列化攻击在Java、Python等面向对象语言中均存在。序列化是广泛存在于PHP、Java等编程语言中的一种将有结构的对象/数组转化为无结构的字符串并储存信息的一种技术。

2、序列化(以PHP语言为例)

PHP类都含有的特定元素:类属性、类常量、类方法。

序列化就是将一个类压缩成一个字符串的方法。

eg:

<?php
class userInfo
{
 private $passwd='123456';
 protected $sex = 'male'; //定义了三个属性
 public $name ='Myon';
 public function modifyPasswd($passwd)
{
$this->passwd = $passwd; //将函数传进来的值传给passwd
 }
public function getPasswd()
{
echo $this->$passwd; //输出passwd
 }
}
$Myon = new userInfo(); //创建 userInfo对象实例
$Myon->modifyPasswd('123abc'); //调用modifyPasswd函数并将123abc值传进去
$data = serialize($Myon); //序列化
echo $data;
?>

输出结果:

O:8:"userInfo":3{s:16:"userInfopasswd";s:6:"123abc";s:6:"*sex";s:4:"male";s:4:"name";s:4:"Myon";}

对序列化后的字符串进行解读:

大括号外表示“Object”对象名称是“userInfo”,长度为8,这个对象有3个属性。


(特别注意:在CTF中常有一个对 _wakeup() 函数的绕过,当序列化字符串中表示对象属性个数的值大于实际属性个数时,就会跳过wakeup方法的执行。)


在前面的文章中有对CTF题PHP反序列化及绕过实例的讲解,可以参考


http://t.csdn.cn/Mffji


http://t.csdn.cn/wbtkK


大括号内表示这些属性的具体信息及它们的值


根据属性的权限不同,在序列化中的表示方法也不同


从代码中可以看出,三个属性的权限分别是private,protected和public


(1)private权限是私有权限,只能在本类内使用,子类不能继承。

(2)protected权限是私有权限,即只能在类内部使用,子类可以继承这个变量。

(3)public权限就是正常的变量权限,一般声明的变量权限均为public。


标红的是private,前面加上了本类名称;


标蓝的是protected,前面加上了星号;


标绿的是public,没有任何前缀。


一个类经过序列化之后,存储在字符串的信息只有类名称和类内属性键值对,序列化字符串中没有将类方法一并序列化。


3、反序列化

反序列化与序列化是相对应的,就是将含有类信息的序列化过的字符串“解压缩”还原成类。

反序列化的类想要使用原先的类方必须依托于域,脱离了域的反序列化的类是无法调用序列化之前的类方法的。

<?php
class userInfo
{
 private $passwd='123456';
 protected $sex = 'male'; //定义了三个属性
 public $name ='Myon';
 public function modifyPasswd($passwd)
{
$this->passwd = $passwd; //将函数传进来的值传给passwd
 }
public function getPasswd()
{
echo $this->$passwd; //输出passwd
 }
}
$Myon = new userInfo(); //创建 userInfo对象实例
$Myon->modifyPasswd('123abc'); //调用modifyPasswd函数并将123abc值传进去
$data = serialize($Myon); //序列化
$new_Myon = unserialize($data); //反序列化数据
$new_Myon->getPasswd();
?>

理论上这里类方法应该被成功执行,但是...

不过有一点可以确定,如果我们单独将序列化后的字符串作为输入,在一个新的域下执行代码片段,肯定是会报错的。

<?php
$data = "O:8:\"userInfo\":3{s:16:\"userInfopasswd\";s:6:\"123abc\";s:6:\"*sex\";s:4:\"male\";s:4:\"name\";s:4:\"Myon\";}"
$new_Myon =unserialize($data);//反序列化数据
$new_Myon->getPasswd();
?>

4、PHP魔法函数

(1)__wakeup()

在PHP中如果需要进行反序列化,会先检查类中是否存在_wakeup()函数,如果存在,则会先调用此类方法,预先准备对象需要的资源。

<?php
class example
{
    public $color = 'black';//定义color属性
public function __wakeup()
    {
        $this->color = 'white';//将white赋值给color
    }
    public function printColor()
    { 
        echo $this->color . PHP_EOL; //输出color
    }
}
$my = new example; //实例化对象
$data = serialize($my); //进行序列化
$new_my = unserialize($data); //反序列化
$new_my->printColor(); //调用printColor()函数
?>

可以看到类属性color已经被__wakeup()函数自动调用并修改了

这种函数被称为PHP魔法函数,它在一定条件下不需要被调用而可以自动调用

(2)__destruct()

在对象的所有引用都被删除或类被销毁时自动调用

<?php
class example
{
    public $color ='black'; //定义color属性
    public function __destruct()
    {
        echo "__destruct()". PHP_EOL; //打印__destruct()
    }
}
echo "initializing...". PHP_EOL; //打印 initializing...
$my = new example; //创建对象实例
echo "serializing..." . PHP_EOL; //打印 serializing... 
$data = serialize($my); // 序列化
?>

可以看到在序列化类的时候,__destruct()函数自动执行了 。

(3)__construct()

此函数会在创建一个类的实例时自动调用

<?php
class example
{
    public $color='black'; //定义color属性
    public function __construct()
    {
        echo"____construct()". PHP_EOL; //打印__construct()
    }
}
echo "initializing...". PHP_EOL; //打印initializing...
$my = new example; //创建对象实例
echo "serializing...". PHP_EOL; //打印 serializing... 
$data = serialize($my); //序列化
?>

可以看到在序列化之前,实例化时__construct()函数就被调用了。

(4)__toString()

此函数会在类被当作字符串时调用

<?php
class example
{
    public $color='black'; //定义color属性
    public function __toString()
    {
        return"_toString()". PHP_EOL;//打印__toString()
    }
}
echo "initializing...". PHP_EOL; //打印initializing...
$my = new example; //创建对象实例
echo "echo...". PHP_EOL; //打印echo...
echo $my;//输出$my
echo "serializing...". PHP_EOL; // 打印 serializing... 
$data = serialize($my); //序列化
?>

可以看到当实例化对象被当作字符串使用时,__toString()函数自动调用。

其他触发此函数的情况:

反序列化对象与字符串连接时。

反序列化对象参与格式化字符串时。

反序列化对象与字符串进行==比较时(PHP进行==比较时会转换参数类型)。

反序列化对象参与格式化SQL语句,绑定参数时。

反序列化对象在经过PHP字符串函数,如strlen()、addslashes()时。

在in_array()方法中,第一个参数是反序列化对象,第二个参数的数组中有toString返回的字符串时,toString会被调用。

反序列化的对象作为class_exists()的参数时。

(5)__get()

在读取不可访问的属性值时自动调用

<?php
class example
{
    private $color ='black'; // 定义私有属性 color
    public function __get($color)
    {
        return"__get()". PHP_EOL; //打印__get()
    }
}
$my = new example; //创建对象实例
echo $my->color; //输出 color 属性
?>

因为试图访问私有变量color导致__get()函数自动调用

(6)__call()

调用未定义的方法时调用

<?php
class example
{
    private $color='black'; //定义私有属性 color
    public function __call($function,$parameters)
    {
        echo $function."('.Sparameters.')".PHP_EOL;//打印两个参数
        return"__call()". PHP_EOL;
    }
}
$my = new example; //创建对象实例
echo $my->notExistFunction("patameters"); //调用未定义方法?>
?>

可以看到__call()函数被调用

也就是说你想让调用方法未定义,那么这个方法名就会作为 __call的第一个参数传入,因此不存在方法的参数会被装进数组中作为 __call的第二个参数传入。

目录
相关文章
|
2月前
|
PHP
php常见问题,php.ini文件不存在或者找不到,mb_strlen()函数未定义系列问题,dll模块找不到的解决
本文介绍了解决PHP常见问题的步骤,包括定位和创建`php.ini`文件,以及解决`mb_strlen()`函数未定义和DLL模块加载错误的具体方法。
php常见问题,php.ini文件不存在或者找不到,mb_strlen()函数未定义系列问题,dll模块找不到的解决
|
2月前
|
存储 API PHP
php学习笔记-php数组的创建和使用,数组常用函数-day03
关于PHP数组的创建、使用以及常用函数的详细学习笔记。
php学习笔记-php数组的创建和使用,数组常用函数-day03
|
1月前
|
Unix PHP 数据库
PHP日期和时间Date()函数获取当前时间
通过灵活运用 `date()`函数及其丰富的格式选项,PHP开发者可以轻松地在应用程序中处理和展示日期及时间信息。无论是需要精确到秒的完整时间戳,还是仅仅展示日期或时间的某一部分,`date()`函数都能胜任。理解并熟练应用这些格式化技巧,对于提升代码的可读性和维护性至关重要。
35 1
|
2月前
|
XML SQL PHP
php学习笔记-php字符串及字符串常用函数总结-day04
本文总结了PHP中字符串的三种定义方式和常用字符串处理函数,包括字符串的修剪、转换、长度计算、子串操作、比较、连接、分割及替换等操作。
|
2月前
|
设计模式 存储 算法
PHP中的设计模式:策略模式的深入解析与应用在软件开发的浩瀚海洋中,PHP以其独特的魅力和强大的功能吸引了无数开发者。作为一门历史悠久且广泛应用的编程语言,PHP不仅拥有丰富的内置函数和扩展库,还支持面向对象编程(OOP),为开发者提供了灵活而强大的工具集。在PHP的众多特性中,设计模式的应用尤为引人注目,它们如同精雕细琢的宝石,镶嵌在代码的肌理之中,让程序更加优雅、高效且易于维护。今天,我们就来深入探讨PHP中使用频率颇高的一种设计模式——策略模式。
本文旨在深入探讨PHP中的策略模式,从定义到实现,再到应用场景,全面剖析其在PHP编程中的应用价值。策略模式作为一种行为型设计模式,允许在运行时根据不同情况选择不同的算法或行为,极大地提高了代码的灵活性和可维护性。通过实例分析,本文将展示如何在PHP项目中有效利用策略模式来解决实际问题,并提升代码质量。
|
3月前
|
Linux PHP
Linux CentOS 宝塔 Suhosin禁用php5.6版本eval函数详细图文教程
【8月更文挑战第27天】本文介绍两种禁用PHP执行的方法:使用`PHP_diseval_extension`禁用和通过`suhosin`禁用。由于`suhosin`不支持PHP8,仅适用于PHP7及以下版本,若服务器安装了PHP5.6,则需对应安装`suhosin-0.9.38`版本。文章提供了详细的安装步骤,并强调了宝塔环境下与普通环境下的PHP路径差异。安装完成后,在`php.ini`中添加`suhosin.so`扩展并设置`executor.disable_eval = on`以禁用执行功能。最后通过测试代码验证是否成功禁用,并重启`php-fpm`服务生效。
40 2
|
3月前
|
JavaScript 前端开发 PHP
|
3月前
|
监控 数据库连接 PHP
php中register_shutdown_function函数用法详解
通过 `register_shutdown_function`,PHP开发者可以对脚本的终止进行更精细化的处理,这个函数让开发者能在脚本的生命周期结束时有机会执行最后的操作,无论脚本是正常结束还是发生错误。由于它的高度实用性和灵活性,`register_shutdown_function`是PHP开发中不可或缺的工具之一。
60 0
|
4月前
|
SQL 关系型数据库 MySQL
php所有函数总结
以上只是PHP中函数的一部分,实际上PHP提供了丰富的内置函数,能够处理各种复杂的任务。
26 2
|
4月前
|
存储 Serverless PHP