(1)之前已经审计过了5.1.x的pop链,最后RCE的出口是Request
类的__call
方法。但是5.0.x和5.1.x在$hook[$method]
处的写法不一样,在5.1.x中是$this->$hook[$method]
,这里对于我们来说是可控的,在5.0.x中的写法是self::$hook[$method]
这里是const类型的,所以是不可控的。所以我们不能使用Rquest
类作为一个出口了,要找其他的__call
。
(2)在5.0.x没有含有__toString
方法的Conversion
类,这里我选择用Model
类,这里的操作都是一样的
__toString -> toJson -> toArrary
在toArray
方法中,我们要找到可以利用的类似$a->function($b)
方法,看到这里的$item[$key] = $value ? $value->getAttr($attr) : null;
这里要求$value
和$attr
都是可控的,先看$value
控制$value
的核心代码就是901,902两行,$relation
是$name
控制的,也就是由$this-append
控制的,这是我们可控的,这也就是说$modelRelation
是Model
类任意方法的返回值,这里我们选择Model->getError
方法,因为它的返回值error
是非常简单可控的
再看getRelationData
方法
这里的$this->parent
就是我们要触发的代替Request
类的类也就是$value->getAttr($attr)
中的$value
,这里要求是Relation
类(这里可以通过$this->error来控制这个类)。我们来看Relation
类中的ifSelfRelation
方法和getModel
方法。
isSelfRelation
方法简单可控
public function isSelfRelation()
{
return $this->selfRelation;
}
Model->getModel
public function getModel()
{
return $this->query->getModel();
}
getModel
方法返回的是$this->query
的getModel方法,query
应该是Query
类,
Query->getModel
public function getModel()
{
return $this->model;
}
这里的model
简单可控,而这里的get_class
方法要求$modelRelation->getModel()
和$this->parent
为同类,也就是要求$value->getAttr($attr)
中的$value
和上面简单可控的model
为同类,这样我们就控制了$value->getAttr($attr)
中的$value
,下面看$attr
$attr
由$modelRelation->getBindAttr()
控制,这里要求需要有getBindAttr
方法,经过全局搜索,存在这个方法的Relation
的子类为OnetoOne
类,这里的binAttr
简单可控,而OnetoOne
也是抽象类,进行全局搜索OnetoOne
的子类,最后选定这里的Relation
子类为HasOne
到这里为止,我们已经能够执行$value->getAttr($attr)
了,下面就是选择可用的__call
方法,在这里我们选择Output
类。
这里执行的是$this->block
追溯一下。
所以最终执行的是$this->handler->write
方法。
进行全局搜索什么可用的类可以调用write
方法,这里我们把$this->handler
设置为thinksessiondriverMemcached
类。
在查看有没有可用的类可以调用set
方法,我们把这里的$this->handler
设为thinkcachedrvierFile
类
159行的$result = file_put_contents($filename, $data);
可以进行文件写入。
$filename
由$this -> getCacheKey
方法控制。
可以看到$filename
可以由$this->options['path']
控制,这里简单可控。下面要看的就是$data
了,向上追溯,
File->set
方法的$value
由Output->writeln
中的newline
参数控制,这里默认为true,所以我们就对$value
不可控,也就是对$data
即写入的内容不可控,再向下看,有setTagItem
方法。
这里又会调用一次set
方法,把$name
当作$value
写入新文件,也就是把$filename
当作$data
写入新的文件,因为这里的$data
默认有exit
,我们通过,rot13
转换绕过这个东西。所以我们把$option['config']
设置为php://filter/write=string.rot13/resource=<?cuc @riny($_TRG[_]);?>
最后马的文件名为'<?cuc @riny($_TRG[_]);?>'.md5('tag_'.md5($tag)).'.php'。
执行system('ls')
成功
这里可能。。会有个问题就是权限问题无法写入, 改一下payload的文件路径即可,因为getCacheKey
方法会mkdir一个755的文件夹。
这是完整的pop链
本文作者:星盟安全团队
本文为安全脉搏专栏作者发布,转载请注明:https://www.secpulse.com/archives/123676.html