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

可以看到我把利用链拆分为了两部分,前面一部分是到有字符串拼接操作为止,后面一部分是从字符串拼接的魔术方法开始,一直到代码执行的触发点 。接下来我们就一边梳理利用链,一边构造POC 。
Model的__destruct方法
public function __destruct(){    echo "lazySave的值:".$this->lazySave."<br>";    if ($this->lazySave) {        $this->save();    }}这里要执行save方法,需要lazySave=true
跟进save方法,因为我们关注的只是updateData方法,所以updateData后面的代码我就省略掉了:
    public function save(array $data = [], string $sequence = null): bool    {        // 数据对象赋值        $this->setAttrs($data);        if ($this->isEmpty() || false === $this->trigger('BeforeWrite')) {            return false;        }        $result = $this->exists ? $this->updateData() : $this->insertData($sequence);  xxxxxxxxxxxx        return true;    }为了能够顺利执行到updateData(),我们需要保证前面的if条件判断不成立($this->isEmpth()==false和$this->trigger()==true)以及$this->exists=true
isEmpty
public function isEmpty(): bool{    return empty($this->data);}只要保证this->data不为空就行
trigger
protected function trigger(string $event): bool{    if (!$this->withEvent) {        return true;    }    $call = 'on' . Str::studly($event);    try {        if (method_exists(static::class, $call)) {            $result = call_user_func([static::class, $call], $this);        } elseif (is_object(self::$event) && method_exists(self::$event, 'trigger')) {            $result = self::$event->trigger(static::class . '.' . $event, $this);            $result = empty($result) ? true : end($result);        } else {            $result = true;        }        return false === $result ? false : true;    } catch (ModelEventException $e) {        return false;    }}看似这么长一串,但是我们只需要令withEvent=false就可以直接发挥true,回到save函数,接下来再令$this->exists==true,然后进入updateData()
    protected function updateData(): bool    {        echo "updateData执行-----<br>";        // 事件回调        if (false === $this->trigger('BeforeUpdate')) {  // 经过我们之前的设置,这儿直接跳过            return false;        }        $this->checkData();        // 获取有更新的数据        $data = $this->getChangedData();        if (empty($data)) {            // 关联更新            if (!empty($this->relationWrite)) {                $this->autoRelationUpdate();            }            return true;        }        if ($this->autoWriteTimestamp && $this->updateTime && !isset($data[$this->updateTime])) {            // 自动写入更新时间            $data[$this->updateTime]       = $this->autoWriteTimestamp($this->updateTime);            $this->data[$this->updateTime] = $data[$this->updateTime];        }        // 检查允许字段        $allowFields = $this->checkAllowFields();        xxxxxxxxx


推荐阅读