• 当magic_quotes_gpc=off


    Pstzine0x03里"[0x06] 高级PHP代码审核技术"一文中关于 "5.3.6 变量key与魔术引号" 部分的php源代码分析

    author: ryat#www.wolvez.org
    team:http://www.80vul.com
    date:2009-04-10

    一、综述

    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?ryat%00wst=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:

    http://www.80vul.com/exp/ecshop-pch-005.txt

    五、参考:

    http://bugs.php.net/bug.php?id=41093

  • 相关阅读:
    jquery ajax 赋值问题, 后面程序判断逻辑用
    jquery formValidator 表单验证插件, ajax无法传值到后台问题的解决
    学习写了一个点击按钮倒计时的jquery小插件
    点击按钮复制指定代码
    discuz 修改积分策略( 在周期中添加"每周" )
    php获取本周周一、周日时间,上周周一、周日时间,本月第一天,本月最后一天,上个月第一天,最后一天时间
    php用正则判断是否为数字
    discuz 标签详解
    用dwz时, 由于粗心产生的一些问题(记录方便自己查阅)
    yii mailer 扩展发送邮件
  • 原文地址:https://www.cnblogs.com/simpman/p/2854893.html
Copyright © 2020-2023  润新知