PHP反序列化
C3ngH Lv3

PHP反序列化的概念

PHP反序列化漏洞是一种安全漏洞,存在于使用PHP编程语言的应用程序中。它涉及到将未经充分验证的用户提供的数据作为序列化字符串传递给unserialize()函数或类似的反序列化函数,从而导致潜在的安全风险。

序列化是将数据结构或对象转换为字符串的过程,以便在网络上传输或存储到数据库等地方。反序列化则是将序列化的字符串转换回原始数据结构或对象

当应用程序使用反序列化函数处理来自用户的输入时,如果没有进行足够的验证和过滤,恶意用户可以构造恶意的序列化字符串,以执行未授权的操作,如执行任意代码、修改对象属性、实现拒绝服务攻击等。

这种漏洞通常出现在应用程序中处理用户提供的会话数据、cookie、缓存、消息队列等地方。攻击者可以通过利用这些漏洞来实现对应用程序的攻击和控制。

PHP反序列化漏洞的修复建议

  1. 更新PHP版本:确保使用的PHP版本是最新的稳定版本,因为新版本通常会修复已知的安全漏洞。
  2. 谨慎处理用户输入:对于从用户获取的数据,始终进行充分的验证和过滤。不要将未经验证的数据传递给反序列化函数。
  3. 使用安全的反序列化方法:如果必须执行反序列化操作,尽量使用安全的反序列化方法,例如JSON序列化而非PHP序列化。
  4. 限制反序列化操作的范围:在可能的情况下,限制反序列化操作的范围,仅允许序列化和反序列化受信任的数据结构。
  5. 实施输入验证:在接受用户输入之前,进行输入验证,确保数据符合预期格式和范围。
  6. 使用白名单:对于反序列化操作,使用白名单机制来验证数据结构,只允许特定的类被反序列化。
  7. 监控和日志记录:实施监控和日志记录机制,以便及时检测到可能的攻击,并记录恶意行为以进行后续分析。

PHP面向对象编程

创建一个PHP类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php
class TestClass //定义一个类
{
//一个变量
public $variable = 'This is a string';
//一个方法
public function PrintVariable()
{
echo $this->variable;
}
}
//创建一个对象
$object = new TestClass();
//调用一个方法
$object->PrintVariable();
?>

PHP的访问控制

在PHP中,publicprotectedprivate是用于定义类成员(属性和方法)可见性的访问修饰符。

  1. public(公共):公共成员可以在任何地方被访问,包括类的外部。这意味着公共属性和方法可以通过类的实例或类本身直接访问。
1
2
3
4
5
6
7
8
9
10
11
class MyClass {
public $publicVar = 'public';

public function publicMethod() {
return 'Public Method';
}
}

$obj = new MyClass();
echo $obj->publicVar; // Output: public
echo $obj->publicMethod(); // Output: Public Method
  1. protected(受保护的):受保护的成员只能在其定义的类和其子类中访问。外部类无法直接访问受保护的成员。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class MyClass {
protected $protectedVar = 'protected';

protected function protectedMethod() {
return 'Protected Method';
}
}

class SubClass extends MyClass {
public function accessProtected() {
return $this->protectedVar; // 这里可以访问父类的受保护属性
}
}

$obj = new SubClass();
echo $obj->accessProtected(); // Output: protected
  1. private(私有的):私有成员只能在其定义的类内部访问,外部类和子类都无法直接访问私有成员。
1
2
3
4
5
6
7
8
9
10
11
class MyClass {
private $privateVar = 'private';

private function privateMethod() {
return 'Private Method';
}
}

$obj = new MyClass();
// echo $obj->privateVar; // 无法直接访问私有属性,会导致错误
// echo $obj->privateMethod(); // 无法直接访问私有方法,会导致错误

这些访问修饰符允许类作者控制类成员的可见性和访问权限,从而提高代码的安全性和封装性。

注:

public:属性被序列化的时候属性值会变成属性名

protected:属性被序列化的时候属性值会变成 \x00*\x00属性名

private:属性被序列化的时候属性值会变成\x00类名\x00属性名

其中:\x00表示空字符,但是还是占用一个字符位置(空格)

PHP魔术方法

  1. __construct():类的构造函数,在创建对象时触发。用于初始化对象的状态。
  2. __destruct():类的析构函数,在对象被销毁时触发。用于执行清理操作。
  3. __call($name, $arguments):在对象上下文中调用不可访问的方法时触发。
  4. __callStatic($name, $arguments):在静态上下文中调用不可访问的方法时触发。
  5. __get($name):读取不可访问属性的值时触发。这里的不可访问包括私有属性或未定义属性。
  6. __set($name, $value):在给不可访问属性赋值时触发。
  7. __isset($name):当对不可访问属性调用 isset() 或 empty() 时触发。
  8. __unset($name):在不可访问的属性上使用unset()时触发。
  9. __invoke():当尝试以调用函数的方式调用一个对象时触发。即使对象不是一个函数。
  10. __sleep():执行serialize()时,先会调用这个方法。通常用于执行对象序列化之前的准备工作。
  11. __wakeup():执行unserialize()时,先会调用这个方法。通常用于执行对象反序列化之后的处理。
  12. __toString():当反序列化后的对象被输出在模板中时(转换成字符串时)自动调用。通常用于自定义对象的字符串表示形式。

魔术方法的执行过程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
<?php
class A{
public $a="hi";
public $b="no";
function __construct()
{
$this->a="hiiiii!";
echo $this->a."\n";
echo "this is construct\n";
}
function __wakeup()
{
echo "this is wakeup\n";
}//反序列化之前
function __destruct()
{
echo "this is destruct\n";
}//反序列化时会最后才触发

function __toString()
{
return "this is tostring\n";
}
function __call($name, $arguments)
{
echo "this is call\n";
}
function __get($a)
{
echo "this is get\n";
}
function __invoke()
{
echo "this is invoke\n";
}//尝试当作函数


function say_hi()
{
echo "hiuhiu\n";
}
}
$aa=new A();// 所有最后都还要析构一次,对象的消失
$aa->say_hi();
$bb=serialize($aa);
$cc=unserialize($bb);
echo $aa;// 作为字符串用时触发 tostring
$aa->say_no(); //call
$aa->c; //get
$aa(); //invoke

执行结果:

1
2
3
4
5
6
7
8
9
10
hiiiii!
this is construct //$aa=new A();
hiuhiu //$aa->say_hi();
this is wakeup //$bb=serialize($aa);
this is tostring //echo $aa;
this is call //$aa->say_no();
this is get//$aa->c
this is invoke //$aa();
this is destruct //$cc=unserialize($bb);
this is destruct

从序列化到反序列化这几个函数的执行过程是:
__construct() ->__sleep -> __wakeup() -> __toString() -> __destruct()

PHP序列化的格式

O:<length>:"<class name>":<n>:{<field name 1><field value 1>...<field name n><field value n>}

O:表示序列化的是对象
<length>:表示序列化的类名称长度
<class name>:表示序列化的类的名称
<n>:表示被序列化的对象的属性个数
<field name 1>:属性名
<field value 1>:属性值

POP链构造

 评论
评论插件加载失败
正在加载评论插件
访客数 访问量