1. 程式人生 > >用Snort巧妙檢測SQL注入和跨站指令碼攻擊

用Snort巧妙檢測SQL注入和跨站指令碼攻擊

指令碼攻擊是最近網路上最瘋狂的攻擊方法了,很多伺服器配置了先進的硬體防火牆、多層次的安全體系,可惜最後對80埠的SQL注入和跨站指令碼攻擊還是沒有辦法抵禦,只能看著資料被惡意入侵者改的面目全非而毫無辦法——把你的Snort武裝起來吧,用它來檢測這樣的攻擊!
我們將以使用開放原始碼的入侵檢測系統IDS為例,編寫基於規則的正則表示式來對這類攻擊進行監測。這裡順便提一下,在Snort中預設的規則設定包含了檢測跨站指令碼的關鍵字,是不是會產生衝突呢?不用擔心,這種衝突我們還是有辦法解決的,我們可以將它們用ASCII碼的十六進位制形式表示出來。例如在 Snort和指令碼中都存在的關鍵字<script>,我們就可以用%3C%73%63%72%69%70%74%3E來代替。
如果你想對每一種可能的SQL注入進行檢測,那麼你只要檢查任何SQL元字元的出現,如像單引號(’)、分號(;)和雙減號(--)。同樣的,一個監測跨站指令碼攻擊的很偏執的方法,就是檢視HTML標記的尖括號(<、>)。但是,前述的方法可能會引起大量的誤檢。為了避免誤檢,我們就必須將過濾規則設定的儘可能的準確,即使這樣,我們仍然不能保證不會產生誤檢,只能盡力而為了。
本文中,我們將就使用Snort對Perl中的字串進行檢測為例,做一詳細介紹。不熟悉Perl的讀者,可要回頭將Perl中的正則表示式部分仔細閱讀一下了。

1.針對SQL注入的正則表示式
在為SQL注入選擇正則表示式的時候,需要記住的是:攻擊者除了可以從Cookie的域中進行攻擊之外,還可以通過表單(Form)的Input輸入框。所以,你在對輸入進行邏輯驗證的時候,還應該對來自使用者的每種輸入資訊都要考慮到,像表單域和Cookie資訊都應該作為懷疑的物件。同樣的,如果你發現許多針對單引號和分號的報警的時候,也可能是因為是由Web應用的Cookie中的資訊引起的。因此,必須對特定的Web應用來評估這樣的特殊符號。
如前所述,一個用來檢測SQL注入攻擊的最弱的正則表示式,就是通過檢查上面提到的元字元(’;--)。要檢測這樣的元字元,或者它們的16進位制的等價表示,我們可以使用如下的正則表示式:
/(%27)|(’)|(--)|(%23)|(#)/ix
這裡,%27是單引號的16進位制值,%23是’#’的16進位制值。像單引號和短橫槓都是MS SQL Server和Oracle中的特殊字元,如果我們使用的是MySQL,還必須檢測’#’的出現。這裡需要說明的就是“—”,不需要檢查它的16進位制值,因為它不是HTML元字元,不會被瀏覽器編碼。同樣的,如果攻擊者試圖手動修改“—”為它的16進位制值%2D的話,SQL注入操作會失敗。為了照顧一下不熟悉Perl的同志,接下來我將上面的這個正則表示式簡要解釋一下://是Perl中用來引起要進行模式匹配的程式碼,其完整形式為m//,通常,我們在使用雙斜槓引起模式匹配程式碼的時候,可以將m省略不寫。符號“|”是或的作用,如同在其他語言中or的通常意義。這裡的小括號是為了更容易讓讀者看明白的情況下而寫出來的,完全可以不用。第二個/後面的i表示對要匹配的字母不區分大小寫。第二個/後面的x表示忽略模式中的空白。
我們可以將上面的這個表示式新增到Snort的規則裡面去:alert tcp $EXTERNAL_NET any -> $HTTP_SERVERS $HTTP_PORTS (msg:"SQL Injection - Paranoid"; flow:to_server,established;uricontent:".pl";pcre:"/(%27)|(’)|(--)|(%23)|(#)/i"; classtype:Web-application-attack; sid:9099; rev:5;)
在這個例子裡面,uriconten 關鍵字部分,我們使用了“.pl”,因為在我們的測試環境中,我們的CGI指令碼是使用Perl寫成的。這部分內容取決於你的特定應用,可能是 “.php”、 “.asp”、“.jsp”等。Pcre關鍵字的內容,就是將要對.pl檔案進行檢查的模式。你可以從這個正則表示式受到啟發,以便寫出更多的Snort 規則。
SQL查詢中還有可能在Where語句中包含純數字,像這樣:
select value1, value2, num_value3 from database where num_value3=some_user_supplied_number
在這個例子中,攻擊者可能執行一條附加的SQL查詢語句,像這樣就可以:
3; insert values into some_other_table
上面的那條Snort規則可以擴充套件一下,用來過濾分號(;)的出現。然而,分號也可能出現在正常的HTTP互動中。為了減少誤檢,上面的規則可以修改為從等號(=)之後的部分進行匹配。當用戶使用GET或者POST作請求時,輸入域一般會像這樣出現:
username=some_user_supplied_value&password=some_user_supplied_value
因此,對使用者的SQL注入嘗試的檢測可以從等號(=)或者它的16進位制值開始檢測,修改後的SQL元字元檢測的正則表示式如下:
/((%3D)|(=))[^n]*((%27)|(’)|(--)|(%3B)|(;))/ix
這個規則首先檢查等號(=)或者它的16進位制%3D。接下來,[^n]*的含義就是匹配零個或者多個非換行符字元,其中,n是Perl中的換行符,^是排除符號,也就是說非換行符,*的含義就是對它前面的字元進行零次或者多次匹配。接下來的部分,跟前面沒有什麼不同了。
一個典型的SQL注入嘗試過程,通常會圍繞著單引號來製造一下查詢,來看一下返回的結果正確與否,從而確定是否存在SQL注入漏洞。大多數的例子都是使用了字串1’or’1’= ’1。然而,要對這類字串進行檢測可不是件容易的事情,因為攻擊者可以輕易的構造出一些具有等價作用的字串,如1’or2>1--。這樣,唯一不變的部分也就剩下了一個常數和接下來的字串’or’了。對於這類攻擊,我們可以構造如下的正則表示式,來進行檢測,典型的SQL注入攻擊的正則表示式:
/w*((%27)|(’))((%6F)|o|(%4F))((%72)|r|(%52))/ix
w(注意,這裡的w是小寫的,Perl中的用於模式匹配的w和W意義截然不同)指的是大小寫字母或者數字,加了*之後的意義就是用來匹配一個或者多個數字或者字母。(%27)|’用來匹配單引號或者它的16進位制值。(%6F)|o|(%4F))((%72)|r|(%52),%6F和%4F分別為字母o的小大寫16進位制值,%72和%52分別為字母r的小大寫16進位制值。因為使用的i選項,所以沒有必要將字母o和r的大小寫形式都寫出來。這樣,單詞 or的各種形式,我們都已經考慮到了。
同樣的,在SQL注入中,我們也經常會用到union關鍵字,我們可以如下設定規則,針對UNION關鍵字的SQL注入的檢測的正則表示式:
/((%27)|(’))union/ix
有了上面的基礎,這句規則就不需要多作解釋了。對於同樣會經常碰到的select,insert,update,delete,drop等語句,我們可以舉一反三,靈活運用規則進行設定了。
在SQL 注入中,我們為了使得SQL伺服器返回錯誤,然後通過錯誤來獲得有用的資訊,經常會出現諸如1=(select name from student where sno=’200021’)。這個子查詢語句返回的值是字元型別,而1是數字,這時候就會有錯誤爆出,從而洩漏了name欄位的內容。這樣就引出了,我們必須能夠對這種常見的注入進行監測。對於這類攻擊,我們不能夠從1開始做限制,因為這樣可能導致大量的誤檢,顯然,解決方法就是對select關鍵字進行監測,因為URL中提交的資訊,正常情況下是不會包含select關鍵字的。

2.5對1=(select name from student where sno=’200021’)類似的查詢進行監測的正則表示式:
/((%27)|(’))select/ix
在MS SQL Server中,經常被利用的還有擴充套件儲存過程xp_cmdshell、xp_regread 、xp_regwrite等。這類儲存過程在呼叫的時候,都要使用到exec關鍵字。另外,系統的儲存過程通常都是以sp或者xp開頭的,所以,我們針對這類SQL注入,可以如下配置正則表示式。針對MS SQL Server的SQL注入進行檢測的正則表示式:
/exec(s|+)+(s|x)pw+/ix
exec為呼叫儲存過程的關鍵字。(s|+)代表空格或者它的HTTP編碼的等價替換。+用於使前面的和後面的字元至少匹配一次,這樣,(s|+)+(s|x)的意思就是使空格和s與x中的一個進行至少一次的匹配。w+在前面已經解釋過了,這裡不多說了。
上面,我們僅僅是對SQL注入的一些最基本的方法進行監測,但是,熟悉SQL注入的人都知道,SQL注入中用的方法還有很多,我們在這裡不可能一一寫到,所以請讀者體諒。

2.針對跨站指令碼攻擊的正則表示式
在發動一次跨站指令碼攻擊之前,為了測試網站的漏洞,攻擊者通常要做一個簡單的HTML測試,這可能要涉及到HTML中的tag像<b>、 <i>、<u>等。同樣的,也可以使用一個簡單的指令碼如<script>alert("OK")< /script>。這可能是因為大多數的關於CSS的討論文件,都是使用了這樣一個簡單的指令碼例子來判斷一個站點是否可以進行CSS攻擊。這類嘗試,我們可以通過Snort進行檢測。一些高階一些的入侵者可能會使用變換的方式進行測試,如將起對應的16進位制值進行等價替換,如< script>可以使用%3C%73%63%72%69%70%74%3E進行替換。
下面的這個正則表示式就可以針對這類攻擊進行檢測。它將捕獲使用<b>、<u>或者<script>的嘗試。這個正則表示式也是不區分大小寫的。我們必須對尖括號的符號和它的16進位制值都進行匹配,左尖括號<的16進位制值為%3C,右尖括號>的16進位制值為%3E。簡單CSS攻擊的正則表示式:
/((%3C)|<)((%2F)|/)*[a-z0-9%]+((%3E)|>)/ix
(( %3C)|<)是對左尖括號進行檢測。((%2F)|/)*對錶示tag標誌結束的斜槓或者16進位制值進行匹配。[a-z0-9%]+對一個以上的小寫字母或者阿拉伯數字進行匹配。((%3E)|>)對右尖括號或者它的16進位制值進行匹配。再將這個寫成Snort規則就成了: alert tcp $EXTERNAL_NET any -> $HTTP_SERVERS $HTTP_PORTS (msg:"NII Cross-site scripting attempt"; flow:to_server,established; pcre:"/((%3C)|<)((%2F)|/)*[a-z0-9%]+((%3E)|>)/i";classtype:Web-application-attack; sid:9000; rev:5;)
跨站指令碼也可以通過使用<img src=>技術來實現,對於這一類攻擊,我們可以這樣配置,來使得CSS攻擊不容易實現。針對<img src>的CSS攻擊的正則表示式:
/((%3C)|<)((%69)|i|(%49))((%6D)|m|(%4D))((%67)|g|(%47))[^n]+((%3E)|>)/i
左右尖括號不再解釋。(%69)|i|(%49))((%6D)|m|(%4D))((%67)|g|(%47)是針對img的匹配。[^n]+在前面也已經說過了。還有一種最偏執的針對CSS攻擊的正則表示式:
/((%3C)|<)[^n]+((%3E)|>)/i
這個正則表示式採用了最“惡毒”的辦法,就是將所有出現<>的地方全都認為是CSS攻擊,夠毒吧,呵呵!但是,這種方法最容易引起誤檢,但是它卻實實在在的能夠有效防止CSS攻擊。
從某種程度上來說,跨站指令碼攻擊似乎更好控制一些,其實不然,經常關注黑防的讀者自有深刻的體會,我就不多說了。

3.自己動手編寫規則
當編寫Snort規則時,首先考慮的是效率和速度,好的規則要包含content選項。2.0版本以後,Snort改變了檢測引擎的工作方式,在第一階段就作一個集合模式匹配。一個content選項越長,這個匹配就越精確。如果一條規則不包含content選項,它們將使整個系統慢下來。
當編寫規則時,儘量要把目標定位在攻擊的地方(例如,將目標定位在1025的偏移量等等)而不僅僅是泛泛的指定(如,在這匹配指令碼程式碼)。Content規則是大小寫敏感的(除非你使用了nocase選項)。不要忘記content是大小寫敏感的和大多數程式的命令都是大寫字母。FTP就是一個很好的例子。考慮如下的規則:
alert tcp any any -> 192.168.1.0/24 21 (content: "user root"; msg: "FTP root login";)
alert tcp any any -> 192.168.1.0/24 21 (content: "USER root"; msg: "FTP root login";)
上面的第二條規則能檢測出大多數的自動以root登陸的嘗試,而第一條規則就不行。Internet 守護程序在接受輸入時是很隨便的。在編寫規則時,很好的理解協議規範將降低錯過攻擊的機會。

4.結論
本文中,我們給出了各種各樣的針對SQL注入和跨站指令碼攻擊的正則表示式。雖然有一些是很偏執和粗暴的,因為即使有一點發起攻擊的企圖,這樣的正則表示式都會引起Snort的報警。這樣的一些偏執的正則表示式最容易引起誤檢,為了儘量減少這樣的誤檢,我們要儘量的精確設定正則表示式。同時,我們前面介紹的方法也只是針對現在比較常見的攻擊做出的檢測,黑客的對抗技術中,總是此起彼長,“道高一尺,魔高一丈”,當我們發現了新的入侵的方法時,要對某些規則做出適當的調整甚至新增新的規則,才能夠適應新的安全要求。這點相信各位早都深有體會了,本文結合我的一點理解寫出,希望和大家共同學習