【PHP程式設計+MySQL資料庫+PHPMaker整合教學+技術諮詢】 本月特價優惠中! 動態的架站程式時代,要自訂PHP程式頁面有那麼難嗎? MySQL『資料庫』與『資料表』,用PHP程式有那麼難控制嗎? 你不用死背『PHP程式』與『MySQL資料庫』語法也能獨自設計完成! 這是自動化軟體程式的年代 (用PHPMaker 設計在彈指之間就能自動生成整個 PHP 程式系統) 這不是:神話!程式軟體模組取代了這一切複雜的工程。 你可以自己建構自己專屬的: 訂購表單、會員名單、擴增購物車特殊頁面 →POS 系統、CRM 系統、ERP 系統、HRM 系統...等等 (更可以加入數據資源銷售賺錢!) 該是:【見證奇蹟】的時候了! 非親眼所見....真的無法相信此神兵利器!

當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