PHP變數覆蓋漏洞小結

雪痕*發表於2020-09-23

前言

變數覆蓋漏洞是需要我們需要值得注意的一個漏洞,下面就對變數覆蓋漏洞進行一個小總結。

變數覆蓋概述

變數覆蓋指的是可以用我們自定義的引數值替換程式原有的變數值,通常需要結合程式的其他功能來實現完整攻擊。那麼它是如何引起的?其實,大多數變數覆蓋漏洞是函式使用不當導致的。比如extract()函式和parse_str()。還有一個函式是import_request_variables(),它是在沒有開啟全域性變數註冊的時候,呼叫這個函式相當於開啟了全域性變數註冊,在PHP5.4之後,這個函式被取消了。還有一種是利用$$的方式來註冊變數,但是沒有驗證已有變數,導致被覆蓋。

extract()函式使用不當導致變數覆蓋

函式結構:
int extract( array &$var_array[, int $extract_type = EXTR_OVERWRITE[, string $prefix = NULL]] )
再看一下PHP手冊對這個函式的說明

說的通俗點就是將陣列中的鍵值對註冊成變數。extract()函式想要變數覆蓋,需要一定的條件。它最多允許三個引數,用表格說明一下這三個引數:

由上圖可知,該函式有三種情況會覆蓋掉已有變數。下面用一段簡單的程式碼來加深印象。

<?php
$b=2;
$a=array('b'=>'123');
extract($a);
echo $b;
?>

原來$b=2,經過extract()函式對$a處理後,$b被成功覆蓋為123。

parse_str()函式使用不當導致變數覆蓋

parse_str()函式的作用是解析字串並且註冊成變數,它在註冊變數之前不會驗證當前變數是否存在,所以會直接覆蓋掉原有變數。函式說明如下:
void parse_str( string $str[, array &$arr] )
函式有兩個引數,第一個是必須的,代表要解析註冊成變數的字串,比如“a=1”經過parse_str()函式後會註冊$a並複製為1,第二個引數是一個陣列,當第二個引數存在時,註冊的變數會放到這個陣列裡,如果原來有相同的鍵值,則會覆蓋掉它。
用一段簡單的程式碼加深印象:

<?php
$b=2;
parse_str($b=321);
print_r($b);
?>

我們發現$b的值被覆蓋為321。

$$變數覆蓋

先看引起覆蓋的一小段程式碼:

<?php
$a=1;
foreach (array('_COOKIE','_POST','_GET') as $_request){
    foreach ($$_request as $_key =>$_value){
        $$_key = addslashes($_value);
    }
}
echo $a;
?>

它為什麼會導致變數覆蓋呢?重點在$$符號,從程式碼中,我們可以看出$_key為COOKIR、POST、GET中的引數,如果我們提交?a=3,那麼$key的值就為3,還有一個$在a的前面,結合起來就是$a=addslashes($_value),所以會覆蓋原有a的值。上面的程式碼我們執行一下,如下圖,發現a被覆蓋成由GET方式傳的8。

變數覆蓋防範

變數覆蓋最常見的漏洞點是做變數註冊時沒有驗證變數是否存在。所以想要防範,推薦使用原始的變數陣列,如$_GET、$_POST等,或者在註冊變數前一定要驗證變數是否存在。

相關文章