php unserialize反序列化漏洞分析

题目如下:

php unserialize反序列化漏洞分析

漏洞解析: (上图代码第11行正则表达式应改为:’/O:d:/’)

题目考察对php序列化函数的利用。在第10行 loadData() 函数中,我们发现了 unserialize 函数对传入的 $data 变量进行了反序列。在反序列化前,对变量内容进行了判断,先不考虑绕过,跟踪一下变量,看看变量是否可控。在代码 第6行 ,调用了 loadData() 函数,$data变量来自于 __construct() 构造函数传入的变量。代码第32行,对 Template 类进行了实例化,并将 cookie 中键为’data’数据作为初始化数据进行传入,$data数据我们可控。开始考虑绕过对传入数据的判断。

代码 11行 ,第一个if,截取前两个字符,判断反序列化内容是否为对象,如果为对象,返回为空。php可反序列化类型有String,Integer,Boolean,Null,Array,Object。去除掉Object后,考虑采用数组中存储对象进行绕过。

第二个if判断,匹配 字符串为 ‘O:任意十进制:’,将对象放入数组进行反序列化后,仍然能够匹配到,返回为空,考虑一下如何绕过正则匹配,PHP反序列化处理部分源码如下:

php unserialize反序列化漏洞分析

php unserialize反序列化漏洞分析

php unserialize反序列化漏洞分析

在PHP源码var_unserializer.c,对反序列化字符串进行处理,在代码568行对字符进行判断,并调用相应的函数进行处理,当字符为’O’时,调用 yy13 函数,在 yy13 函数中,对‘O‘字符的下一个字符进行判断,如果是’:’,则调用 yy17 函数,如果不是则调用 yy3 函数,直接return 0,结束反序列化。接着看 yy17 函数。通过观察yybm[]数组可知,第一个if判断是否为数字,如果为数字则跳转到 yy20 函数,第二个判断如果是’+’号则跳转到 yy19 ,在 yy19 中,继续对 +号 后面的字符进行判断,如果为数字则跳转到 yy20 ,如果不是则跳转到 yy18y18 最终跳转到 yy3 ,退出反序列化流程。由此,在’O:’,后面可以增加’+’,用来绕过正则判断。

绕过了过滤以后,接下来考虑怎样对反序列化进行利用,反序列化本质是将序列化的字符串还原成对应的类实例,在该过程中,我们可控的是序列化字符串的内容,也就是对应类中变量的值。我们无法直接调用类中的函数,但PHP在满足一定的条件下,会自动触发一些函数的调用,该类函数,我们称为魔术方法。通过可控的类变量,触发自动调用的魔术方法,以及魔术方法中存在的可利用点,进而形成反序列化漏洞的利用。

在代码31行,对象销毁时会调用 createCache() 函数,函数将 $template 中的内容放到了 $cacheFile 对应的文件中。 file_put_contents() 函数,当文件不存在时,会创建该文件。由此可构造一句话,写入当前路径。

$cacheFile$template 为类变量,反序列化可控,由此,构造以下反序列化内容,别忘了加’+’号

php unserialize反序列化漏洞分析

放入cookie需进行URL编码

a:1:{i:0;O:+8:"Template":2:{s:9:"cacheFile";s:10:"./test.php";s:8:"template";s:25:"<?php eval($_POST[xx]);?>";}}

文件成功写入:

php unserialize反序列化漏洞分析

实例分析

本次实例分析,选取的是 Typecho-1.1 版本,在该版本中,用户可通过反序列化Cookie数据进行前台Getshell。该漏洞出现于 install.php 文件 230行 ,具体代码如下:

php unserialize反序列化漏洞分析

在上图代码 第3行 ,对Cookie中的数据base64解码以后,进行了反序列化操作,该值可控,接下来看一下代码触发条件。文件几个关键判断如下:

php unserialize反序列化漏洞分析

第一个if判断,可通过GET传递 finish=任意值 绕过 ,第二if判断是否有GET或者POST传参,并判断Referer是否为空,第四个if判断Referer是否为本站点。紧接着还有判断,如下图:

php unserialize反序列化漏洞分析

第一个if判断 $_GET[‘finish’] 是否设置,然后判断 config.inc.php文件 是否存在,安装后已存在,第三个判断cookie中 __typecho_config 参数是否为空,不为空。进入else分支。综上,具体构造如下图:

php unserialize反序列化漏洞分析

$config = unserialize(base64_decode(Typecho_Cookie::get('__typecho_config')));Typecho_Cookie::delete('__typecho_config');$db = new Typecho_Db($config['adapter'], $config['prefix']);

反序列化结果存储到 $config 变量中,然后将 $config[‘adapter’]$config[‘prefix’] 作为 Typecho_Db 类的初始化变量创建类实例。我们可以在 var/Typecho/Db.php 文件中找到该类构造函数代码,具体如下:

php unserialize反序列化漏洞分析

上图代码 第6行 ,对传入的 $adapterName 变量进行了字符串拼接操作,对于PHP而言,如果 $adapterName 类型为对象,则会调用该类 __toString() 魔术方法。可作为反序列化的一个触发点,我们全局搜索一下 __toString() ,查看是否有可利用的点。实际搜索时,会发现有三个类都定义了 __toString() 方法:

php unserialize反序列化漏洞分析

  • 第一处 varTypechoConfig.php

    php unserialize反序列化漏洞分析

    调用 serialize() 函数进行序列化操作,会自动触发 __sleep() ,如果存在可利用的 __sleep() ,则可以进一步利用。

  • 第二处 varTypechoDbQuery.phpphp unserialize反序列化漏洞分析

    该方法用于构建SQL语句,并没有执行数据库操作,所以暂无利用价值。

  • 第三处varTypechoFeed.php

    php unserialize反序列化漏洞分析

    在代码 19行$this->_items 为类变量,反序列化可控,在代码 27行$item[‘author’]->screenName ,如果 $item[‘author’] 中存储的类没有’screenName’属性或该属性为私有属性,此时会触发该类中的 __get() 魔法方法,这个可作为进一步利用的点,继续往下看代码,未发现有危险函数的调用。

记一波魔术方法及对应的触发条件,具体如下:

__wakeup() //使用unserialize时触发__sleep() //使用serialize时触发__destruct() //对象被销毁时触发__call() //在对象上下文中调用不可访问的方法时触发__callStatic() //在静态上下文中调用不可访问的方法时触发__get() //用于从不可访问的属性读取数据__set() //用于将数据写入不可访问的属性__isset() //在不可访问的属性上调用isset()或empty()触发__unset() //在不可访问的属性上使用unset()时触发__toString() //把类当作字符串使用时触发__invoke() //当脚本尝试将对象调用为函数时触发

var/Typecho/Request.phpTypecho_Request 类中,我们发现 __get() 方法,跟踪该方法的调用,具体如下图:php unserialize反序列化漏洞分析

array_map() 函数和 call_user_func 函数,都可以作为利用点,$filter 作为调用函数,$value 为函数参数,跟踪变量,看一下是否可控。这两个变量都来源于类变量,反序列化可控。从上面的分析中,可知当 $item[‘author’] 满足一定条件会触发 __get 方法。

假设 $item[‘author’] 中存储 Typecho_Request 类实例,此时调用 $item[‘author’]->screenName ,在Typecho_Request 类中没有该属性,就会调用类中的 __get($key) 方法,$key 传入的值为 scrrenName 。参数传递过程如下:$key='scrrenName'=>$this->_param[$key]=>$value

我们将 $this->_param[‘scrrenName’] 的值设置为想要执行的函数,构造 $this->_filter 为对应函数的参数值,具体构造如下:

php unserialize反序列化漏洞分析

接下来我们去看一下 Typecho_Feed 类的构造,该类在 var/Typecho/Feed.php 文件中,代码如下:

php unserialize反序列化漏洞分析

上图代码 第7行 ,满足 self::RSS2$this->_type 相等进入该分支,所以 $this->_type 需要构造,item[‘author’] 为触发点,需要构造 $this_items ,具体构造如下:

php unserialize反序列化漏洞分析

代码 22行 在实际利用没必要添加,install.php在代码 54行 调用 ob_start() 函数,该函数对输出内容进行缓冲,反序列化漏洞利用结束后,在varTypechoDb.php代码121行,触发异常,在 varTypechoCommon.php 代码237行调用 ob_end_clean()函数 清除了缓冲区内容,导致无法看见执行结果,考虑在进入到异常处理前提前报错结束程序。由此构造该数据。执行结果如下:

php unserialize反序列化漏洞分析

修复建议

造成该漏洞的原因主要有两点:

  • config.inc.php 文件存在的时,可绕过判断继续往下执行代码。

  • 传入反序列化函数的参数可控

修复方法:在 install.php 文件第一行判断 config.inc.php 是否存在,如果存在,则退出代码执行。

<?php if (file_exists(dirname(__FILE__) . '/config.inc.php'))    exit('Access Denied');?>

结语

看完了上述分析,不知道大家是否对反序列化利用有了一定的了解,文中用到的CMS可以从 这里 下载,当然文中若有不当之处,还望各位斧正。如果你对我们的项目感兴趣,欢迎发送邮件到 hongrisec@gmail.com 联系我们。Day11 的分析文章就到这里,我们最后留了一道CTF题目给大家练手,题目如下:

<?phpinclude "config.php";class HITCON{    public $method;    public $args;    public $conn;    function __construct($method, $args) {        $this->method = $method;        $this->args = $args;        $this->__conn();    }    function __conn() {        global $db_host, $db_name, $db_user, $db_pass, $DEBUG;        if (!$this->conn)            $this->conn = mysql_connect($db_host, $db_user, $db_pass);        mysql_select_db($db_name, $this->conn);        if ($DEBUG) {            $sql = "DROP TABLE IF  EXISTS  users";            $this->__query($sql, $back=false);            $sql = "CREATE TABLE IF NOT EXISTS users (username VARCHAR(64),            password VARCHAR(64),role VARCHAR(256)) CHARACTER SET utf8";            $this->__query($sql, $back=false);            $sql = "INSERT INTO users VALUES ('orange', '$db_pass', 'admin'), ('phddaa', 'ddaa', 'user')";            $this->__query($sql, $back=false);        }        mysql_query("SET names utf8");        mysql_query("SET sql_mode = 'strict_all_tables'");    }    function __query($sql, $back=true) {        $result = @mysql_query($sql);        if ($back) {            return @mysql_fetch_object($result);        }    }    function login() {        list($username, $password) = func_get_args();        $sql = sprintf("SELECT * FROM users WHERE username='%s' AND password='%s'", $username, md5($password));        $obj = $this->__query($sql);        if ( $obj != false ) {            define('IN_FLAG', TRUE);            $this->loadData($obj->role);        }        else {          $this->__die("sorry!");        }    }    function loadData($data) {        if (substr($data, 0, 2) !== 'O:' && !preg_match('/O:d:/', $data)) {            return unserialize($data);        }        return [];    }    function __die($msg) {        $this->__close();        header("Content-Type: application/json");        die( json_encode( array("msg"=> $msg) ) );    }    function __close() {        mysql_close($this->conn);    }    function source() {        highlight_file(__FILE__);    }    function __destruct() {        $this->__conn();        if (in_array($this->method, array("login", "source"))) {            @call_user_func_array(array($this, $this->method), $this->args);        }        else {            $this->__die("What do you do?");        }        $this->__close();    }    function __wakeup() {        foreach($this->args as $k => $v) {            $this->args[$k] = strtolower(trim(mysql_escape_string($v)));        }    }}class SoFun{    public $file='index.php';    function __destruct(){        if(!empty($this->file)) {            include $this->file;        }    }    function __wakeup(){        $this-> file='index.php';    }}if(isset($_GET["data"])) {    @unserialize($_GET["data"]);}else {    new HITCON("source", array());}?>
//config.php<?php    $db_host = 'localhost';    $db_name = 'test';    $db_user = 'root';    $db_pass = '123';    $DEBUG = 'xx';?>
// flag.php<?php!defined('IN_FLAG') && exit('Access Denied');echo "flag{un3eri@liz3_i3_s0_fun}";?>

以上就是“php unserialize反序列化漏洞分析”这篇文章的所有内容,感谢各位的阅读!相信大家阅读完这篇文章都有很大的收获,小编每天都会为大家更新不同的知识,如果还想学习更多的知识,请关注亿速云行业资讯频道。

文章标题:php unserialize反序列化漏洞分析,发布者:亿速云,转载请注明出处:https://worktile.com/kb/p/21635

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022年8月30日 下午11:25
下一篇 2022年8月30日 下午11:26

相关推荐

  • 如何进行bee-box LDAP注入的环境配置

    一、综述 按照我的学习过程来说,我必须知道我进行web攻击的这个模型和漏洞的原理是什么,现在我就碰到个冷门,最初见到LDAP时是某次在某国企的渗透测试中发现一个冷门(经过授权的),激起了我对它的兴趣。 LDAP的概念: 全称:轻量级目录访问协议(Lightweight Directory Acces…

    2022年9月18日
    14100
  • win8如何取消开机账户登录

    win8取消开机账户登录的方法 1、win+r打开运行界面。 2、对话框输入“netplwiz”,回车确定。 3、然后把“要使用本计算机,用户必须输入用户名和密码”前面的勾去掉。 4、点击确定之后系统会再次弹出一个密码输入框,这个时候我们再次输入密码点击确定就可以了。 关于“win8如何取消开机账户…

    2022年9月24日
    8000
  • cad字体不显示数字怎么解决

    解决方法 1、首先我们打开软件,找到菜单栏上的格式,再找到下拉菜单上的标注样式管理器。 2、然后在跳转出来的对话框中,点击当前使用的标注样式,然后再点击右侧的修改。 3、然后在跳转的新页面里,我们点击文字的选项,在文字高度这一块把高度数值改大一些。 以上就是“cad字体不显示数字怎么解决”这篇文章的…

    2022年9月16日
    8700
  • css如何使用​禁用鼠标事件

    禁用鼠标事件 CSS3 新增的 pointer-events 让你能够禁用元素的鼠标事件,例如,一个连接如果设置了下面的样式就无法点击了。 .disabled { pointer-events: none; } 关于“css如何使用禁用鼠标事件”这篇文章就分享到这里了,希望以上内容可以对大家有一定的…

    2022年9月1日
    13500
  • APT组织使用的10大安全漏洞分别是什么

    概述 APT攻击(Advanced Persistent Threat,高级持续性威胁)是利用先进的攻击手段对特定目标进行长期持续性网络攻击的攻击形式。APT攻击的原理相对于其他攻击形式更为高级和先进,其高级性主要体现在精确的信息收集、高度的隐蔽性、以及使用各种复杂的目标系统/应用程序漏洞等方面。 …

    2022年9月21日
    21900
  • 电脑0x000007b蓝屏如何修复

    启动无限蓝屏0x000007b修复方法: 方法一: 1、先强制重启电脑,等待开机画面出现后按下快捷键“F12”进入bios系统中。 2、进入bios启动项设置界面,用方向键将光标移动到“advanced”。 3、然后再次选择“SATA Configuration”并按下回车键进行确认。 4、之后会出…

    2022年9月16日
    17400
  • Mysql怎么查看执行计划

    使用explain关键字可以模拟优化器执行SQL查询语句,从而知道MySQL是如何处理你的SQL语句的,分析你的查询语句或是表结构的性能瓶颈。 explain执行计划包含的信息 其中最重要的字段为:id、type、key、rows、Extra 各字段详解 id select查询的序列号,包含一组数字…

    2022年8月30日
    7300
  • mysql的concat()函数如何用

    在mysql中,concat()函数用于将两个或多个字符串拼接成一个字符串并返回,语法为“CONCAT(string1,string2, … );”;该函数需要至少一个参数,否则会引起错误。concat()函数在拼接之前会将所有参数转换为字符串类型;如果任何参数为NULL,则CONCAT…

    2022年9月21日
    8200
  • windows todesk如何卸载

    todesk卸载方法 1、右键todesk,找到“打开文件所在位置” 2、点击uninst.exe 3、确认卸载。 到此,关于“windows todesk如何卸载”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注亿速云网…

    2022年9月26日
    22400
  • word怎么制作目录页

    word制作目录的方法: 1、首先将光标放到文档标题下方,然后选择菜单栏依次点击“引用-目录-插入目录”。 2、然后根据情况选择显示级别点击确定,级别的选择只要大于自己需需求都可以。 3、此时如果将光标放置到目录下方,选择“插入-分页”可以使目录和正文分成两页。 4、如果文章的内容发生了更改,会导致…

    2022年9月19日
    13200
联系我们
站长微信
站长微信
分享本页
返回顶部