zoukankan      html  css  js  c++  java
  • ref:CodeIgniter框架内核设计缺陷可能导致任意代码执行

    ref:https://www.seebug.org/vuldb/ssvid-96217

    简要描述:

    为准备乌云深圳沙龙,准备几个0day做案例。 官方承认这个问题,说明会发布补丁,但不愿承认这是个『漏洞』……不过也无所谓,反正是不是都没美刀~

    详细说明:

    CI在加载模板的时候,会调用 $this->load->view('template_name', $data); 内核中,查看view函数源码: /system/core/Loader.php

    public function view($view, $vars = array(), $return = FALSE)
        {
            return $this->_ci_load(array('_ci_view' => $view, '_ci_vars' => $this->_ci_object_to_array($vars), '_ci_return' => $return));
        }
    ...
        protected function _ci_load($_ci_data)
        {
            // Set the default data variables
            foreach (array('_ci_view', '_ci_vars', '_ci_path', '_ci_return') as $_ci_val)
            {
                $$_ci_val = isset($_ci_data[$_ci_val]) ? $_ci_data[$_ci_val] : FALSE;
            }
            $file_exists = FALSE;
            // Set the path to the requested file
            if (is_string($_ci_path) && $_ci_path !== '')
            {
                $_ci_x = explode('/', $_ci_path);
                $_ci_file = end($_ci_x);
            }
            else
            {
                $_ci_ext = pathinfo($_ci_view, PATHINFO_EXTENSION);
                $_ci_file = ($_ci_ext === '') ? $_ci_view.'.php' : $_ci_view;
                foreach ($this->_ci_view_paths as $_ci_view_file => $cascade)
                {
                    if (file_exists($_ci_view_file.$_ci_file))
                    {
                        $_ci_path = $_ci_view_file.$_ci_file;
                        $file_exists = TRUE;
                        break;
                    }
                    if ( ! $cascade)
                    {
                        break;
                    }
                }
            }
            if ( ! $file_exists && ! file_exists($_ci_path))
            {
                show_error('Unable to load the requested file: '.$_ci_file);
            }
            // This allows anything loaded using $this->load (views, files, etc.)
            // to become accessible from within the Controller and Model functions.
            $_ci_CI =& get_instance();
            foreach (get_object_vars($_ci_CI) as $_ci_key => $_ci_var)
            {
                if ( ! isset($this->$_ci_key))
                {
                    $this->$_ci_key =& $_ci_CI->$_ci_key;
                }
            }
            /*
             * Extract and cache variables
             *
             * You can either set variables using the dedicated $this->load->vars()
             * function or via the second parameter of this function. We'll merge
             * the two types and cache them so that views that are embedded within
             * other views can have access to these variables.
             */
            if (is_array($_ci_vars))
            {
                $this->_ci_cached_vars = array_merge($this->_ci_cached_vars, $_ci_vars);
            }
            extract($this->_ci_cached_vars);
            /*
             * Buffer the output
             *
             * We buffer the output for two reasons:
             * 1. Speed. You get a significant speed boost.
             * 2. So that the final rendered template can be post-processed by
             *  the output class. Why do we need post processing? For one thing,
             *  in order to show the elapsed page load time. Unless we can
             *  intercept the content right before it's sent to the browser and
             *  then stop the timer it won't be accurate.
             */
            ob_start();
            // If the PHP installation does not support short tags we'll
            // do a little string replacement, changing the short tags
            // to standard PHP echo statements.
            if ( ! is_php('5.4') && ! ini_get('short_open_tag') && config_item('rewrite_short_tags') === TRUE)
            {
                echo eval('?>'.preg_replace('/;*s*?>/', '; ?>', str_replace('<?=', '<?php echo ', file_get_contents($_ci_path))));
            }
            else
            {
                include($_ci_path); // include() vs include_once() allows for multiple views with the same name
            }
            log_message('info', 'File loaded: '.$_ci_path);
            // Return the file data if requested
            if ($_ci_return === TRUE)
            {
                $buffer = ob_get_contents();
                [@ob_end_clean](/ob_end_clean)();
                return $buffer;
            }
            /*
             * Flush the buffer... or buff the flusher?
             *
             * In order to permit views to be nested within
             * other views, we need to flush the content back out whenever
             * we are beyond the first level of output buffering so that
             * it can be seen and included properly by the first included
             * template and any subsequent ones. Oy!
             */
            if (ob_get_level() > $this->_ci_ob_level + 1)
            {
                ob_end_flush();
            }
            else
            {
                $_ci_CI->output->append_output(ob_get_contents());
                [@ob_end_clean](/ob_end_clean)();
            }
            return $this;
        }
    

    且看这一段:

    if (is_array($_ci_vars))
    {
            $this->_ci_cached_vars = array_merge($this->_ci_cached_vars, $_ci_vars);
    }
    extract($this->_ci_cached_vars);
    

    这个extract将导致变量覆盖漏洞。 $this->_ci_cached_vars是来自$_ci_vars,而$_ci_vars是来自用户传给view方法的第二个参数。(正常情况下是开发者传给模板的变量) 而我们看到extract后面:

    extract($this->_ci_cached_vars);
    ob_start();
    // If the PHP installation does not support short tags we'll
    // do a little string replacement, changing the short tags
    // to standard PHP echo statements.
    if ( ! is_php('5.4') && ! ini_get('short_open_tag') && config_item('rewrite_short_tags') === TRUE)
    {
        echo eval('?>'.preg_replace('/;*s*?>/', '; ?>', str_replace('<?=', '<?php echo ', file_get_contents($_ci_path))));
    }
    else
    {
        include($_ci_path); // include() vs include_once() allows for multiple views with the same name
    }
    

    include($_ci_path),$_ci_path是模板地址,因为之前的变量覆盖,将会导致任意文件包含漏洞,进而getshell。 所以,只要我们可以控制view的第二个参数的『键值』,传入 _ci_path=file:///etc/passwd ,在被extract后覆盖原来的模板地址,将可以包含/etc/passwd。 这个漏洞和 http://**.**.**.**/bugs/wooyun-2014-051906 有点类似,就是在assign(CI里叫$this->load->vars或是$this->load->view)的时候传入数组导致的。

    漏洞证明:

    如下Controller将可导致漏洞:

    <?php
    defined('BASEPATH') OR exit('No direct script access allowed');
    class Welcome extends CI_Controller {
    
        public function index()
        {
            $data = $this->input->post();
            $this->load->view('welcome_message', $data);
        }
    }
    

    QQ20160310-6@2x.png

    这个也类似:

    public function index()
    {
        $data = $this->input->post('info');
        $this->load->vars($data);
        $this->load->view('welcome_message');
    }
    

    QQ20160310-7@2x.png

    当开启了远程文件包含的情况下,也可以直接包含php://input

    QQ20160310-8@2x.png

  • 相关阅读:
    C#的dll被其他程序调用时,获取此dll正确的物理路径
    用鼠标右键选择DataGridView单元格或行
    当心回车符破坏你的JSON数据
    WinForm中当TextBox重新获得焦点时输入法失效问题
    django-rest-framework登陆认证
    django-celery定时任务以及异步任务and服务器部署并且运行全部过程
    linux安装mysqlclient报错
    Dajngo的CBV和FBV
    五分钟看懂Celery定时任务
    Nginx+uWsgi生产部署Django
  • 原文地址:https://www.cnblogs.com/studyskill/p/9229521.html
Copyright © 2011-2022 走看看