黑客手把手教你分析一次漏洞( 四 )

因为前半条链已经来到了$this->name.$this->suffix,那么无论是name还是suffix连接后半条链都是可以的,重要的就是这后半条链从那个类开始,漏洞作者找到Conversion类,其中他的魔术方法__toString如下:
public function __toString(){    return $this->toJson();}继续跟toJson:
public function toJson(int $options = JSON_UNESCAPED_UNICODE): string{     return json_encode($this->toArray(), $options);}跟进toArray:
    public function toArray(): array    {        echo "进入toArray函数!!!<br>";        $item       = [];        $hasVisible = false;        foreach ($this->visible as $key => $val) {            xxxxxx        }        foreach ($this->hidden as $key => $val) {            xxxxxx        }        // 合并关联数据        $data = array_merge($this->data, $this->relation); //$data=https://www.isolves.com/it/aq/hk/2020-07-16/["axin"=>"ls"] foreach ($data as $key => $val) { if ($val instanceof Model || $val instanceof ModelCollection) { // 关联模型对象 if (isset($this->visible[$key]) && is_array($this->visible[$key])) { $val->visible($this->visible[$key]); } elseif (isset($this->hidden[$key]) && is_array($this->hidden[$key])) { $val->hidden($this->hidden[$key]); } // 关联模型对象 if (!isset($this->hidden[$key]) || true !== $this->hidden[$key]) { $item[$key] = $val->toArray(); } } elseif (isset($this->visible[$key])) { $item[$key] = $this->getAttr($key); } elseif (!isset($this->hidden[$key]) && !$hasVisible) { $item[$key] = $this->getAttr($key); } } xxxxxx return $item; }根据我最开始给出的poc,$data=https://www.isolves.com/it/aq/hk/2020-07-16/["axin"=>"ls"],所以会来到最后一个getAttr()函数处,我们跟进
public function getAttr(string $name){    echo "进入getAttr函数!!!!<br>";    try {        $relation = false;        $value    = $this->getData($name); // $name='axin'    } catch (InvalidArgumentException $e) {        $relation = $this->isRelationAttr($name);        $value    = null;    }    return $this->getValue($name, $value, $relation);}如果熟悉tp5.1.x pop链的同学肯定觉得getData的似曾相识,我们一起来看看吧:
public function getData(string $name = null)//$name='axin'{    echo "进入getData函数!!!!<br>";    if (is_null($name)) {        return $this->data;    }    $fieldName = $this->getRealFieldName($name);    if (array_key_exists($fieldName, $this->data)) {        return $this->data[$fieldName];    } elseif (array_key_exists($fieldName, $this->relation)) {        return $this->relation[$fieldName];    }    throw new InvalidArgumentException('property not exists:' . static::class . '->' . $name);}跟进getRealFieldName:
protected function getRealFieldName(string $name): string  // $name = 'axin'{    return $this->strict ? $name : Str::snake($name);}这里我们可以令$this->strict=true,这样就会发挥‘axin’,回到getData,getData继续执行,也就是$fieldName='axin',最后getData()返回$this->data['axin']也就是返回了'ls' 。回到getAttr(),继续执行进入getValue():


推荐阅读