1. 程式人生 > >[web安全] 變數覆蓋漏洞

[web安全] 變數覆蓋漏洞

一、全域性變數覆蓋
當register_global=ON時,變數來源可能是各個不同的地方,比如頁面的表單,Cookie等。
<?php
echo "Register_globals: ".(int)ini_get("register_globals")."<br/>";

if ($auth){
   echo "private!";
}
?>
當register_globals=OFF時,這段程式碼不會出問題。
但是當register_globals=ON時,提交請求URL:http://www.a.com/test.php?auth=1,變數$auth將自動得到賦值。得到的結果為
Register_globals:1

private!

小記:如果上面的程式碼中,已經對變數$auth賦了初始值,比如$auth=0,那麼即使在URL中有/test.php?auth=1,也不會將變數覆蓋,也就是說不會打印出private!

通過$GLOBALS獲取的變數,也可能導致變數覆蓋。
<?php
echo "Register_globals:".(int)ini_get("register_globals")."<br/>";
if (ini_get('register_globals')) foreach($_REQUEST as $k=>$v) unset(${$k});
print $a;
print $_GET[b];
?>
變數$a未初始化,在register_globals=ON時,再嘗試控制“$a”的值(http://www.a.com/test1.php?a=1&b=2),會因為這段程式碼而出錯。
而當嘗試注入“GLOBALS[a]”以覆蓋全域性變數時(http://www.a.com/test1.php?GLOBALS[a]=1&b=2),則可以成功控制變數“$a”的值。這是因為unset()預設只會銷燬區域性變數,要銷燬全域性變數必須使用$GLOBALS。
而在register_globals=OFF時,則無法覆蓋到全域性變數。
小記:register_globals的意思是註冊為全域性變數,所以當On的時候,傳遞過來的值會被直接註冊為全域性變數而直接使用,當為OFF的時候,就需要到特定的陣列中去得到它。unset用於釋放給定的變數

二、extract()變數覆蓋
<?php

$auth = '0';
extract($_GET);

if($auth==1){
echo "private!";
}else{
echo "public!";
}
?>
假設使用者構造以下連結:http://www.a.com/test1.php?auth=1
介面上會打印出private!

安全的做法是確定register_globals=OFF後,在呼叫extract()時使用EXTR_SKIP保證已有變數不會被覆蓋。

小記:PHP extract() 函式從陣列中把變數匯入到當前的符號表中。對於陣列中的每個元素,鍵名用於變數名,鍵值用於變數值。

三、遍歷初始化變數

常見的一些以遍歷的方式釋放變數的程式碼,可能會導致變數覆蓋。

<?
$chs = '';
if($_POST && $charset != 'utf-8'){
	$chs = new Chinese('UTF-8', $charset);
	foreach($_POST as $key => $value){
		$$key = $chs->Convert($value);
	}
	unset($chs);
}
?>
若提交引數chs,則可覆蓋變數"$chs"的值。

小記:在程式碼審計時需要注意類似“$$k”的變數賦值方式有可能覆蓋已有的變數,從而導致一些不可控制的結果。

四、import_request_variables變數覆蓋
<?php
$auth = '0';
import_request_variables('G');

if($auth == 1){
  echo "private!";
}else{
  echo "public!";
}
?>
當用戶輸入http://www.a.com/test1.php?auth=1時,網頁上會輸出private!

import_request_variables('G')指定匯入GET請求中的變數,從而導致變數覆蓋。

小記:import_request_variables — 將 GET/POST/Cookie 變數匯入到全域性作用域中。如果你禁止了 register_globals,但又想用到一些全域性變數,那麼此函式就很有用。

五、parse_str()變數覆蓋
//var.php?var=new
$var='init';
parse_str($_SERVER['QUERY_STRING']);
print $var;

與parse_str()類似的函式還有mb_parse_str()

小記:parse_str — 將字串解析成多個變數,如果引數str是URL傳遞入的查詢字串(query string),則將它解析為變數並設定到當前作用域。