ctf變量覆蓋漏洞


1.變量覆蓋:

①:針對extract函數的變量覆蓋漏洞:

 1 <?php
 2 @error_reporting(E_ALL^E_NOTICE);
 3 require('config.php');
 4 
 5 if($_GET['show_source'] === '1') {
 6     highlight_file(__FILE__);
 7     exit;
 8 }
 9 
10 $user = null;
11 
12 // connect to database
13 
14 if(!empty($_POST['data'])) {
15     try {
16         $data = json_decode($_POST['data'], true);
17     } catch (Exception $e) {
18         $data = [];
19     }
20     extract($data);
21     if($users[$username] && strcmp($users[$username], $password) == 0) {
22         $user = $username;
23     }
24 }
1  <?php if($user == 'admin') printf("<code>%s</code>", htmlentities($flag)); ?>

當$user=“admin”時,輸出flag

向上看,$user =$username

則需要使$username="admin"

if成立的條件是$users[$username]不為空並且需要滿足$users[$username]=$password

我們在不知道$password的情況下需要使$users[$username]=$password成立。

再向上看extract()函數,此函數為變量注冊函數,將數組中的數據以鍵名為變量名,鍵值為變量值的形式注冊變量。

那在這就存在變量覆蓋問題,我們可以傳入任意構造$password的值覆蓋原有的$password的值。

即構造data={"username":"admin","password":"123","users":{"admin":"123"}}即可得到flag

 ②:基於parse_str()函數的變量覆蓋漏洞

 1 <meta charset="utf-8">
 2 error_reporting(0);
 3 if (empty($_GET['b'])) {
 4     show_source(__FILE__);
 5     die();
 6 }else{
 7     include('flag.php');
 8 $a = "www.XMAN.com";
 9 $b = $_GET['b'];
10 @parse_str($b);
11 if ($a[0] != 'QNKCDZO' && md5($a[0]) == md5('QNKCDZO')) {
12     echo $flag;
13 }else{
14 exit('你的答案不對0.0');
15 }
16 }

輸出flag的條件為$a[0] != 'QNKCDZO' && md5($a[0]) == md5('QNKCDZO')

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

由於此函數的作用可以將$a[0]的值覆蓋,則在需要找一對md5碰撞即可。

即傳b=a[0]=s155964671a即可得到flag。

③:基於register_globals的變量覆蓋漏洞:

1 <?php  
2 echo "Register_globals: ".(int)ini_get("register_globals")."<br/>";  
3   
4 if ($auth){  
5    echo "private!";  
6 }  
7 ?> 

當register_globals=OFF時,這段代碼不會出問題。
但是當register_globals=ON時,提交請求URL:http://www.a.com/test.php?auth=1,變量$auth將自動得到賦值。得到的結果為
Register_globals:1

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

 

通過$GLOBALS獲取的變量,也可能導致變量覆蓋。

1 <?php  
2 echo "Register_globals:".(int)ini_get("register_globals")."<br/>";  
3 if (ini_get('register_globals')) foreach($_REQUEST as $k=>$v) unset(${$k});  
4 print $a;  
5 print $_GET[b];  
6 ?> 

變量$a未初始化,在register_globals=ON時,再嘗試控制“$a”的值(http://www.a.com/test1.php?a=1&b=2),會因為這段代碼而出錯(因為$a沒有值)。
而當嘗試注入“GLOBALS[a]”以覆蓋全局變量時(http://www.a.com/test1.php?GLOBALS[a]=1&b=2),則可以成功控制變量“$a”的值。這是因為unset()默認只會銷毀局部變量,要銷毀全局變量必須使用$GLOBALS。
而在register_globals=OFF時,則無法覆蓋到全局變量。
小記:register_globals的意思是注冊為全局變量,所以當On的時候,傳遞過來的值會被直接注冊為全局變量而直接使用,當為OFF的時候,就需要到特定的數組中去得到它。unset用於釋放給定的變量

④:遍歷初始化變量

 1 <?  
 2 $chs = '';  
 3 if($_POST && $charset != 'utf-8'){  
 4     $chs = new Chinese('UTF-8', $charset);  
 5     foreach($_POST as $key => $value){  
 6         $$key = $chs->Convert($value);  
 7     }  
 8     unset($chs);  
 9 }  
10 ?>

由於php中可以使用$$聲明變量,因此當在遍歷數組時可能會覆蓋原來的值。

若提交參數chs,則可覆蓋變量"$chs"的值。

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

⑤:import_request_variables變量覆蓋

 1 <?php  
 2 $auth = '0';  
 3 import_request_variables('G');  
 4   
 5 if($auth == 1){  
 6   echo "private!";  
 7 }else{  
 8   echo "public!";  
 9 }  
10 ?>  

當用戶輸入http://www.a.com/test1.php?auth=1時,網頁上會輸出private!

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

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM