JoyChou JoyChou

Typecho install.php Unserialize Vulnerability Analysis

Web 阅读(1217) 文章转载请注明来源!

对PHP反序列化的漏洞理解可以阅读下这篇浅谈php反序列化漏洞文章。

反序列化

反序列化漏洞又叫对象注入,利用反序列化可以控制对象,进而控制对象的某些方法和参数,达到攻击目的。

我们知道,在PHP里,当反序列化的参数可控时,可以无任何条件的调用任意类的__wakeup__destruct方法,前者优先。

不过,还有很多魔术方法都可以在某种前提下被调用,详情可以查看PHP魔术方法手册

__toString

public string __toString ( void )

先来看下官方描述:

__toString() 方法用于一个类被当成字符串时应怎样回应。例如 echo $obj; 应该显示些什么。此方法必须返回一个字符串,否则将发出一条 E_RECOVERABLE_ERROR 级别的致命错误。

经过测试,以下情况,__toString方法会被调用。

  1. echo或者print一个对象
  2. 一个对象在和一个字符串进行拼接
  3. 对象被字符串函数进行操作,比如strlen等…

其实,这就是官方中描述的,一个类被当成了字符串。

如下漏洞代码就可以造成任意文件读取。漏洞Poc: pass=O:4:"Read":1:{s:4:"file";s:11:"/etc/passwd";}

<?php
    class Read
    {
        public $file;
        public function __toString()
        {
            if(isset($this->file))
            {
                echo file_get_contents($this->file);
            }
        }
    }

$pass = $_GET['pass'];
$pass = unserialize($pass);
echo($pass); // 调用__toString方法
// $pass = $pass . "test"; // 调用__toString方法
?>

__get

public mixed __get ( string $name )

比如__get魔术方法,官方描述如下:

读取不可访问属性的值时,__get() 会被调用。

__get的参数为触发时,不可访问参数名。

不可访问大概有两种情况:

  1. 参数未定义
  2. 参数为private

Poc:http://localhost/unserialize.php?pass=O:4:%22Read%22:1:{s:3:%22xxx%22;s:11:%22/etc/passwd%22;}

参数未定义情况

<?php
    class Read
    {
        public function __get($para)
        {
            echo "call __get<br>";
            echo $para;
        }
    }

    $pass = $_GET['pass'];
    $unserial = unserialize($pass);
    // 访问反序列化后对象的$name变量,如果变量不可访问,那对象的__get方法将被调用。
    $test = $unserial->name;
?>

输出

call __get
name

参数为私有情况

<?php
    class Read
    {
        private $file;
        public function __get($para)
        {
            echo "call __get<br>";   
            echo $para;
        }
    }

    $pass = $_GET['pass'];
    $unserial = unserialize($pass);
    // 访问反序列化后对象的$name变量,如果变量不可访问,那对象的__get方法将被调用。
    $test = $unserial->file;
?>

请求http://localhost/unserialize.php?pass=O:4:%22Read%22:1:{s:3:%22xxx%22;s:11:%22/etc/passwd%22;}

输出

call __get
file

攻击weapon

控制的方法内有什么样的函数,就能有什么样的攻击方式。比如file_get_contents可造成文件读取。那我们来大概列举了,这东西太多了。

文件

  • file_get_contents
  • file_put_contents
  • unlink
  • fputs
  • fwrite

代码执行

  • call_user_func

命令执行

  • system
  • popen
  • shell_exec

Typecho反序列化漏洞分析

install.php文件第230行,unserialize一个外部可控的cookie参数

$config = unserialize(base64_decode(Typecho_Cookie::get('__typecho_config')));
Typecho_Cookie::delete('__typecho_config');
$db = new Typecho_Db($config['adapter'], $config['prefix']);
$db->addServer($config, Typecho_Db::READ | Typecho_Db::WRITE);
Typecho_Db::set($db);
?>

接下来构造ROP链。

进入Typecho_Db类db.php的构造函数,可以看到第121行进行了字符串添加,并且$adapterName参数可控,我们只需传入一个对象就可以调用__toString方法。

public function __construct($adapterName, $prefix = 'typecho_')
{
    /** 获取适配器名称 */
    $this->_adapterName = $adapterName;


    /** 数据库适配器 */
    $adapterName = 'Typecho_Db_Adapter_' . $adapterName;

搜索__toString类,发现Typecho_Feed类在Feed.php里第290行,这里可以构造一个Typecho_Request类,而且该类没有screenName参数,导致可以触发Typecho_Request类的__get方法

 $content .= '<dc:creator>' . htmlspecialchars($item['author']->screenName) . '</dc:creator>' . self::EOL;

Typecho_Request类的__get方法,参数$keyscreenName`

public function __get($key)
{
    return $this->get($key);
}

get方法

public function get($key, $default = NULL)
{
    switch (true) {
        case isset($this->_params[$key]):
            $value = $this->_params[$key];
            break;
        case isset(self::$_httpParams[$key]):
            $value = self::$_httpParams[$key];
            break;
        default:
            $value = $default;
            break;
    }

    $value = !is_array($value) && strlen($value) > 0 ? $value : $default;
    return $this->_applyFilter($value);
}

_applyFilter方法

private function _applyFilter($value)
{
    if ($this->_filter) {
        foreach ($this->_filter as $filter) {
            $value = is_array($value) ? array_map($filter, $value) :
            call_user_func($filter, $value);
        }

        $this->_filter = array();
    }

    return $value;
}

最后利用call_user_func命令执行。

Reference

JoyChou WeChat Pay

微信打赏

JoyChou Alipay

支付宝打赏

phptypechounserialize
最后由admin修改于2017-11-30 14:14
发表新评论
博客已经运行
© Powered by JoyChou (2013-2018)
前篇 后篇
雷姆
拉姆