php反序列化漏洞原理,PHP反序列化原理及漏洞解析

什么是PHP序列化

PHP序列化与反序列化的过程

一个反序列化漏洞的例子

CVE-2016-7124

一. 什么是PHP序列化与反序列化

1. PHP序列化

PHP序列化是指把变量转化成可保存或传输的字符串的过程,PHP序列化函数有serialize、json_encode。

以下例子可以实现PHP序列化

1

2

3

4

5

6

7

8

9

10

11

12

13<?php

class test

{

public $name = 'jacky';

public $age = '18';

public $heavy = '81.5';

public $boolean = true;

public $null = NULL;

public $array = array(1,2,3,4,5);

}

$jacky = new test;

echo serialize($jacky);

?>

输出的结果为

O:4:”test”:6:{s:4:”name”;s:5:”jacky”;s:3:”age”;s:2:”18”;s:5:”heavy”;s:4:”81.5”;s:7:”boolean”;b:1;s:4:”null”;N;s:5:”array”;a:5:{i:0;i:1;i:1;i:2;i:2;i:3;i:3;i:4;i:4;i:5;}}

%5Cimage%5CphpUnserialize%5C1.png

其中每项的标识所代表的含义

标识

含义

s

字符串(string)

i

整型(integer)

b

布尔(boolean)

d

双精度(double)

N

空(NULL)

a

数组(array)

同时,序列化过程中还会对不同属性的变量进行不同方式的变化

public的属性在序列化时,直接显示属性名

protected的属性在序列化时,会在属性名前增加0x00*0x00,其长度会增加3

private的属性在序列化时,会在属性名前增加0x00classname0x00,其长度会增加类名长度+2

2. 反序列化

PHP反序列是指将经过序列化的数据转化成原先的状态,PHP反序列化函数有unserialize、json_decode。

二. PHP序列化与反序列化的过程

1. PHP魔法函数

PHP中包含很多魔法函数,他们可以在某些情况下自动执行而不需要手动调用

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16__construct() #类的构造函数

__destruct() #类的析构函数

__call() #在对象中调用一个不可访问方法时调用

__callStatic() #用静态方式中调用一个不可访问方法时调用

__get() #获得一个类的成员变量时调用

__set() #设置一个类的成员变量时调用

__isset() #当对不可访问属性调用isset()或empty()时调用

__unset() #当对不可访问属性调用unset()时被调用。

__sleep() #执行serialize()时,先会调用这个函数

__wakeup() #执行unserialize()时,先会调用这个函数

__toString() #类被当成字符串时的回应方法

__invoke() #调用函数的方式调用一个对象时的回应方法

__set_state() #调用var_export()导出类时,此静态方法会被调用。

__clone() #当对象复制完成时调用

__autoload() #尝试加载未定义的类

__debugInfo() #打印所需调试信息

2. 如何进行序列化

在对象被序列化之前,会检查是否有__sleep()函数,如果存在,该函数会清理对象,并返回一个数组,数组中包含被序列化的对象的所有属性的名称。如果该方法不返回任何内容,则序列化后的字符串将变为N并提示Notice。__sleep()的预期用途是提交需要挂起的数据或执行类似的清理任务。如果有一个非常大的对象,不需要完全保存其所有属性,该功能将非常有用。

在反序列化之前,会检查是否具有__wakeup()魔术方法。如果存在该方法,则在反序列化时执行该方法。__wakeup()魔术方法可以重构对象可能具有的任何资源。__wakeup()预期用途是重新建立在序列化期间可能已丢失的任何数据库连接,并执行其他重新初始化任务。

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<?php

class test

{

public $value;

function __construct(){

echo "__construct";

echo "
";

}

function __destruct(){

echo "__destruct";

echo "
";

}

function __wakeup(){

echo "__wakeup";

echo "
";

}

function __toString(){

echo "__toString";

echo "
";

return $this->value;

}

function setValue($parm){

echo "setValue";

echo "
";

$this->value = $parm;

}

}

$test = new test;

$test->setValue("Jacky");

$ser_test = serialize($test);

echo $ser_test."
";

$obj = unserialize($ser_test);

echo $obj."
";

?>

1

2

3

4

5

6

7

8

9

10//output

__construct

setValue

O:4:"test":1:{s:5:"value";s:5:"Jacky";}

__wakeup

__toString

Jacky

__destruct

__destruct

3. __autoloading()函数

传统的PHP只能反序列化定义过的类,意味着每个PHP文件都需要包含很多文件,在当前主流的PHP框架中,都采用了__autoloading()自动加载类来完成这项繁重的工作。在简化了工作的同时,也为序列化漏洞造成了便捷。

4. 反序列化过程中魔术方法的执行顺序

__wakeup()> __toString()> __destruct()

三. 一个反序列化漏洞的例子

%5Cimage%5CphpUnserialize%5C2.png

右击查看源代码,可以看到如下提示

1

2

3

4

5

6

7

8

9

10$user = $_GET["txt"];

$file = $_GET["file"];

$pass = $_GET["password"];

if(isset($user)&&(file_get_contents($user,'r')==="welcome to the bugkuctf")){

echo "hello admin!
";

include($file); //hint.php

}else{

echo "you are not admin ! ";

}

首先我们尝试将$user的值改为welcome to the bugkuctf,由于使用的是file_get_contents()函数,所以需要使用PHP伪协议来传入$user的值,payload如下

%5Cimage%5CphpUnserialize%5C3.png

下一步处理$file的值,可以看到代码中有文件包含,并提示了所包含的文件时hint.php,这里需要使用另一个PHP伪协议来传入$file的值,payload如下

%5Cimage%5CphpUnserialize%5C4.png

将出现的字符通过base64解密,可以得到如下代码

1

2

3

4

5

6

7

8

9

10

11

12

13<?php

class Flag{//flag.php

public $file;

public function __tostring(){

if(isset($this->file)){

echo file_get_contents($this->file);

echo "
";

return ("good");

}

}

}

?>

可以看到,在flag.php文件中有一个Flag类,此外,我们可以用同样的方法得到index.php文件中的内容

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$txt = $_GET["txt"];

$file = $_GET["file"];

$password = $_GET["password"];

if(isset($txt)&&(file_get_contents($txt,'r')==="welcome to the bugkuctf")){

echo "hello friend!
";

if(preg_match("/flag/",$file)){

echo "不能现在就给你flag哦";

exit();

}else{

include($file);

$password = unserialize($password);

echo $password;

}

}else{

echo "you are not the number of bugku ! ";

}

?>

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值