PHP反序列化
PHP基础
php类与对象
在PHP中,类(class)是一种用于定义对象的蓝图或模板,而对象(object)是类的实例。下面是关于PHP类与对象的一些基本概念:
定义类:在PHP中,可以使用class
关键字来定义一个类。类通常包含属性(成员变量)和方法(成员函数)。以下是一个简单的类的定义示例:
class Person {
// 属性
public $name;
public $age;
// 方法
public function greet() {
return "Hello, my name is " . $this->name;
}
}
创建对象:要使用类,需要创建该类的一个对象。可以使用new
关键字来实例化一个类,创建对象。以下是创建Person
类的对象的示例:
$person1 = new Person();
$person1->name = "Alice";
$person1->age = 30;
echo $person1->greet(); // 输出:Hello, my name is Alice
PHPmagic
在PHP中,“Magic Methods”(魔术方法)是一种特殊的方法,它们有特定的命名规则,并在特定情况下自动调用。这些魔术方法以双下划线开头和结尾,例如__construct()
、__destruct()
等。以下是一些常用的PHP魔术方法及其作用:
__construct()
:构造方法,在实例化对象时自动调用,用于初始化对象的属性或执行一些必要的操作。__destruct()
:析构方法,在对象被销毁时自动调用,用于释放资源或执行清理操作。__get($property)
:访问不可访问属性时自动调用,用于获取对象的属性值。__set($property, $value)
:设置不可访问属性时自动调用,用于设置对象的属性值。__isset($property)
:判断不可访问属性是否存在时自动调用,用于检查对象的属性是否被设置。__unset($property)
:删除不可访问属性时自动调用,用于删除对象的属性。__call($method, $arguments)
:调用不可访问方法时自动调用,用于处理对象的方法调用。__toString()
:将对象转换为字符串时自动调用,用于定义对象的字符串表示形式。__clone()
:克隆对象时自动调用,用于处理对象的克隆操作。__sleep()
和__wakeup()
:序列化和反序列化对象时自动调用,分别用于对象序列化和反序列化时的处理。
PHP序列化
在PHP中,序列化是将对象转换为字符串的过程,以便在存储或传输时使用。PHP提供了serialize()
函数用于将对象序列化为字符串,以及unserialize()
函数用于将序列化的字符串反序列化为对象。以下是关于PHP序列化的一些基本概念:
序列化对象:要将对象序列化为字符串,可以使用serialize()
函数。例如:
class Person {
public $name = "Alice";
public $age = 30;
}
$person = new Person();
$serialized = serialize($person);
echo $serialized;
反序列化对象:要将序列化的字符串还原为对象,可以使用unserialize()
函数。__wakeup()例如:
$serialized = 'O:6:"Person":2:{s:4:"name";s:5:"Alice";s:3:"age";i:30;}';
$person = unserialize($serialized);
echo $person->name; // 输出:Alice
echo $person->age; // 输出:30
序列化数组:除了对象,PHP也可以序列化数组。例如:
$array = array('apple', 'banana', 'cherry');
$serializedArray = serialize($array);
echo $serializedArray;
安全性考虑:由于unserialize()
函数会将字符串还原为PHP对象或数组,因此在接收并反序列化数据时需要谨慎防止反序列化攻击(unserialize attack),即恶意构造的序列化字符串可能导致代码执行漏洞。建议在反序列化前对数据进行验证和过滤,以确保安全性。
1、如果传递的字符串不可解序列化,则返回FALSE,并产生一个E_NOTICE
2、返回的是转换之后的值,可为integer``float、string、array或object
3、若被反序列化的变量是一个对象,在成功重新构造对象之后,PHP会自动地试图去调用__wakeup()成员函数(如果存在的话)
4、如果对象没有预定义反序列化得到的对象是__PHP_Incomplete_Class,并指定了未定义类的类名
反序列化漏洞
假设有一个简单的 PHP 类 User
,其中包含一个 name
属性和一个 greet()
方法,如下所示:
class User {
public $name;
public function greet() {
echo "Hello, " . $this->name . "!";
}
}
现在,假设一个用户可以通过表单提交一个序列化的 User
对象,并在服务器端进行反序列化,如下所示:
$userData = $_POST['userData']; // 假设用户通过表单提交了序列化的 User 对象
$user = unserialize($userData); // 反序列化用户提交的数据
$user->greet(); // 调用 greet() 方法
攻击者可以构造一个恶意的序列化字符串,其中包含恶意代码,例如:
O:4:"User":1:{s:4:"name";s:4:"Alice";}<?php phpinfo(); ?>
反序列化的内容可以修改原类的内容(即可以不同)
当这个恶意序列化字符串被提交并反序列化时,phpinfo()
函数将被执行,从而导致恶意代码的执行。
发生条件
unserialize函数参数可控,比如通过GET传参
脚本中定义了有Magic方法,方法有向PHP文件读写数据,比如__destruct(),__unlink()
读写内容需要有对象中成员变量的值
例
class xctf{
public $flag = '111';
public function __wakeup(){
exit('bad requests');
}
?code=
考点:反序列化
如果触发__wakeup(),则退出
目标:绕过__wakeup()方法
CVE-2016-7124
PHP5小于5.6.25或PHP7小于7.0.10
在反序列化的时候,如果写的参数个数,与实际的参数个数不一致的时候,就会跳过__wakeup()的执行
<?php
class xctf{
public $flag = '111';
}
$a = new xctf();
echo serialize($a);?>
O:4:"xctf":1:{s:4:"flag";s:3:"111";}
修改为 O:4:"xctf":2:{s:4:"flag";s:3:"111";}
修复和防御
针对unserialize和Magic函数审计对用户输入的内容过滤
白名单,限制反序列化的类;
不能动态传参