天天看點

學點算法搞安全之HMM(上篇)

<a href="http://jaq.alibaba.com/community/art/show?articleid=871">學點算法搞安全之hmm(上篇)</a>

前言

本篇重點介紹hmm最常見同時也比較基礎的基于url參數異常檢測的應用,後繼文章将介紹hmm結合nlp技術在xss、sql、rce方面的應用。”多一個公式少一半讀者”,是以霍金的《時間簡史》和《明朝那些事》一樣暢銷,我的機器學習系列文章都是盡量少講概念,多講例子,希望可以讓機器學習被更多人了解和使用。

hmm基礎原理

學點算法搞安全之HMM(上篇)

現實世界中有一類問題具有明顯的時序性,比如路口紅綠燈、連續幾天的天氣變化,我們說話的上下文,hmm的基礎假設就是,一個連續的時間序列事件,它的狀态受且僅受它前面的n個事件決定,對應的時間序列可以成為n階馬爾可夫鍊。

學點算法搞安全之HMM(上篇)

假設今天是否有霧霾隻由前天和昨天決定,于是就構成了一個2階馬爾可夫鍊,若昨天和前天都是晴天,那麼今天是晴天機率就是90%。

學點算法搞安全之HMM(上篇)

稍微再複雜點,假設你想知道2000公裡外一個城市的霧霾情況,但是你沒法直接去當地看到空氣情況,手頭隻有當地風力情況,也就是說空氣狀态是隐藏的,風力情況是可觀察的,需要觀察序列推測隐藏序列,由于風力确實對霧霾情況有較大影響,甚至可以假設風力大的情況下90%機率是晴天,是以通過樣本學習,确實可以達到從觀察序列推測隐藏序列的效果,這就是隐式馬爾可夫。

常見的基于get請求的xss、sql注入、rce,攻擊載荷主要集中在請求參數中,以xss為例:

/0_1/include/dialog/select_media.php?userid=%3cscript%3ealert(1)%3c/script%3e

正常的http請求中參數的取值範圍都是确定的,這裡說的确定是指可以用字母數字特殊字元來表示,并非說都可以用1-200這種數值範圍來确定。以下面的幾條日志為例:

/0_1/include/dialog/select_media.php?userid=admin123

/0_1/include/dialog/select_media.php?userid=root

/0_1/include/dialog/select_media.php?userid=maidou0806

/0_1/include/dialog/select_media.php?userid=52maidou

/0_1/include/dialog/select_media.php?userid=wjq_2014

/0_1/include/dialog/select_media.php?userid=mzc-cxy

肉眼觀察可以歸納出userid字段的由字母數字和特殊字元’-_’組成,如果你足夠強大可以看完上萬的正常樣本,甚至都可以總結取值範圍為[0-9a-za-z-_]{4,}。如果有上億的日志上百萬的參數,人工如何完成?這時候機器學習可以發揮作用了。

以uid字段為例,uid的取值作為觀察序列,簡化期間可以對uid的取值進行泛化,整個模型為3階hmm,隐藏序列的狀态隻有三個s1、s2、s3:

[a-za-z]泛化為a

[0-9]泛化為n

[\-_]泛化為c

其他字元泛化為t

學點算法搞安全之HMM(上篇)

admin123泛化為aaaaannn

root泛化為aaaa

wjq_2014泛化為aaaacnnn

學點算法搞安全之HMM(上篇)

隐藏序列就是s1-s4三個狀态間循環轉化,這個機率稱為轉移機率矩陣,同時四個狀态都以确定的機率,以觀察序列中的a、c、n、t四個狀态展現,這個轉換的機率稱為發射機率矩陣。hmm模組化過程就是通過學習樣本,生成這兩個矩陣的過程。生産環境中泛化需謹慎,至少域名、中文等特殊字元需要再單獨泛化。

由于每個域名的每個url的每個參數的範圍都可能不一樣,有的userid可能是[0-9]{4,},有的可能是[0-9a-za-z-_]{3,},是以需要按照不同域名的不同url不同參數分别學習。泛化過程如下:

def etl(str):

vers=[]

for i, c in enumerate(str):

c=c.lower()

if ord(c) &gt;= ord('a') and ord(c) &lt;= ord('z'):

vers.append([ord('a')])

elif ord(c) &gt;= ord('0') and ord(c) &lt;= ord('9'):

vers.append([ord('n')])

else:

vers.append([ord('c')])

return np.array(vers)

友情提示,為了避免中文等字元的幹擾,ascii大于127或者小于32的可以不處理直接跳過。

從weblog中提取url參數,需要解決url編碼、參數抽取等惡心問題,還好python有現成的接口:

with open(filename) as f:

for line in f:

#切割參數

result = urlparse.urlparse(line)

# url解碼

query=urllib.unquote(result.query)

params = urlparse.parse_qsl(query, true)

for k, v in params:

#k為參數名,v為參數值

友情提示,urlparse.parse_qsl解析url請求切割參數時,遇到’;’會截斷,導緻擷取的參數值缺失’;’後面的内容,這是個大坑,生産環境中一定要注意這個問題。

安裝hmmlearn

hmmlearn是python下的一個hmm實作,是從scikit-learn獨立出來的一個項目,依賴環境如下:

python &gt;= 2.6

numpy (tested to work with &gt;=1.9.3)

scipy (tested to work with &gt;=0.16.0)

scikit-learn &gt;= 0.16

安裝指令如下:

pip install -u --user hmmlearn

将泛化後的向量x以及對應的長度矩陣x_lens輸入即可,需要 x_lens的原因是參數樣本的長度可能不一緻,是以需要單獨輸入。

remodel = hmm.gaussianhmm(n_components=3, covariance_type="full", n_iter=100)

remodel.fit(x,x_lens)

訓練樣本得分為:

score:16 query param:admin123

score:9 query param:root

score:21 query param:maidou0806

score:16 query param:52maidou

score:15 query param:wjq_2014

score:12 query param:mzc-cxy

hmm模型完成訓練後通常可以解決三大類問題,一類就是輸入觀察序列擷取機率最大的隐藏序列,最典型的應用就是語音解碼以及詞性标注;一類是輸入部分觀察序列預測機率最大的下一個值,比如搜尋詞猜想補齊等;另外一類就是輸入觀察序列擷取機率,進而判斷觀察序列的合法性。參數異常檢測就輸入第三種。

我們定義t為門檻值,機率低于t的參數識别為異常,通常會把t定義比訓練集最小值略大,在此例中可以取10。

# 切割參數

query = urllib.unquote(result.query)

for k, v in params:

if ischeck(v) and len(v) &gt;=n :

vers = etl(v)

pro = remodel.score(vers)

if pro &lt;= t:

print "pro:%d v:%s line:%s " % (pro,v,line)

以userid=%3cscript%3ealert(1)%3c/script%3e為例子,經過解碼後為&lt;script&gt;alert(1)&lt;/script&gt;,範化後為taaaaaataaaaatntttaaaaaat,score為-13945,識别為異常。

學點算法搞安全之HMM(上篇)

本文介紹了hmm在web安全的基礎應用,由于僅依賴參數的文本特征進行異常檢測,雖然理論上隻要白樣本足夠多确實可以識别幾乎所有基于get請求參數的未知攻擊,但是由于缺乏語義層面異常檢測,誤報率比較高。另外掃描器等對結果的影響很大,如何進一步提升檢測能力,請看下篇。

本文來自合作夥伴“阿裡聚安全”,發表于2017年05月11日 11:24.