魔术方法,CVE-2016-7124与反序列化漏洞

0x01 魔法方法

魔法方法,是一种特殊的方法,如果定义了,它会在调用一些方法之前自动运行。在很多语言中都有魔法方法,例如,在php中,如果在一个类中定义了__construct方法,在这个类初始化时,它会被自动调用。__sleep()方法会在serialize()方法调用之前调用,__wakeup方法会在调用unserialize()方法之前调用,这些都是php自行规定的,开发者必须使用规定的方法名,才能触发魔法方法的自动运行。在Python中,魔法方法更加常见,例如__init__方法等。

0x02 序列化与反序列化

序列化是指把面向对象的对象变成二进制的能持续存储的文件。反序列化则是相反,将二进制的文件转换成对象,使他活起来。序列化与反序列化一般成对的,例如,在Python中有好几种序列化和反序列化方法,pickle定义了一对,使用pickle序列化后的必需使用pickle反序列化。php中,可以直接使用serialize()和unserialize()方法来序列化和反序列化。因为下面要说的漏洞是关于php的,下面详细说一下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
<?php
class Sample1{
public $a="Sample_str";
public function say(){
echo $a;
}
}
class Sample2{
public $a="Sample_str";
}
$i=5;
$str="hello world";
$arr=array(1,2,3);
$obj1=new Sample1();
$obj2=new Sample2();
echo serialize($i);
echo "\n";
echo serialize($str);
echo "\n";
echo serialize($arr);
echo "\n";
echo serialize($obj1);
echo "\n";
echo serialize($obj2);
?>

运行结果如下:

1
2
3
4
5
i:5;
s:11:"hello world";
a:3:{i:0;i:1;i:1;i:2;i:2;i:3;}
O:6:"Sample":1:{s:1:"a";s:10:"Sample_str";}
O:6:"Sample":1:{s:1:"a";s:10:"Sample_str";}

可见,在类的实例序列化以后,只会将变量名字类型以及值保存下来,并不会保存类的方法。反序列化函数能把上述的字符串转换回原来的对象。

0x03 反序列化漏洞

如果unserialize()函数的参数可控,那么我们就可以控制反序列化后对象中变量的值,如果原来代码中有一些危险的方法,我们可以直接调用。虽然利用条件略微苛刻,但是实际中漏洞还是很多。

0x04 CVE-2016-7124

这是PHP的一个漏洞,利用环境是PHP5 < 5.6.25 ,PHP7 < 7.0.10。简单来说,就是当序列化字符串中表示对象中属性个数的数字大于真实个数时,就会跳过__wakeup()函数的执行。例子可以参见2016 SWPU CTF中的Web3题