機器學習與威脅情報的融合:一種基於AI檢測惡意域名的方法
前言
黑客在攻擊過程中或者對目標網路實施控制時經常使用域名。我們在做流量分析時不僅要通過流量的指紋特徵識別威脅,也可以通過檢測是否解析了惡意域名來判斷網路中是否存在肉雞。
不直接用威脅情報的原因
公司購買了一批威脅情報資料,其中一項重要的資料就是就是惡意域名列表。
因此可以在客戶流量裡面匯出DNS解析日誌,去跟威脅情報的惡意域名情報直接匹配來找出惡意外鏈。但威脅情報往往有以下的缺陷:
誤報多。 威脅情報誤報較多。從我手上的這份資料來看,不少正規中小網站、過期的域名、甚至Alexa排名一千以內的都被列為惡意域名。猜測有可能是網站被掛過黑頁,或者論壇上被傳過帶毒附件,導致整個域名被列入黑名單。而後期維護沒有跟上,導致沒有及時刪除誤報資訊。
漏報更多。 從威脅情報的性質上來看,越是大範圍/長時間的攻擊的行為、大面積傳播的病毒,越容易被威脅情報所捕獲。反之,針對性的APT特徵攻擊則不容易被收錄,造成漏報。而我們公司的客戶主要是政企類,資訊更為敏感,更容易被境外黑客盯上併發起針對性攻擊。
不可控。 我允許安全系統的誤報和漏報,這畢竟是不可避免的,但我無法接受的是誤報和漏報的不可控。可控的安全系統你知道什麼條件下會產生誤報,所以你可以用其它策略去降低誤報;你會知道什麼樣的攻擊會被系統遺漏掉,所以可以用其它的安全方案來彌補這部分缺失。而威脅情報雖然內容可讀,但採集過程就是個“黑盒子”,你不知道里面的資料是怎麼來的,告警出來的東西也不知道如何降低誤報,更不知道它會遺漏哪些資訊。
因此我決定用這批威脅情報作為AI訓練集,學習威脅情報背後的資料特徵,通過AI強大的泛化能力,可以減少漏報,並讓安全系統變得可控。
選擇AI維度
選擇維度是很重要一項工作,你做的是人工智慧還是人工智障,是神經網路還是神經病網路,很大程度上取決於選擇的維度。
Alexa排名
一般情況下,惡意域名不會是流量非常高的網站域名。因此抓取Alexa排名作為維度。
通過介面抓取Alexa排名,如果域名沒有Alexa排名資料,則認為它的排名非常靠後,設定一個非常大的數值:99999999。
如果是多級域名的話,除了抓取多級域名的Alexa,還要抓取主域名的Alexa。這樣便共享了兩個維度。
搜狗rank
搜狗rank和Alexa排名一樣,反應的是網站的規模和流量的大小。不同的是Alexa是越小站越大,搜狗rank是值越大站越大。對於沒有搜狗rank的站點,認為rank為0。
搜狗與百度的收錄數量
一般情況下,惡意域名要多低調就有多低調,不會專門去做SEO的,也不會希望搜尋引擎搜到到。
通過某個SEO介面爬取百度和搜狗收錄頁面的數量,對於搜不到的域名,認為收錄數量為0。
必應收錄數量
與“百度和搜狗收錄數量”形成互補,因為必應對於境外域名收錄的更全一些,而百度搜狗對國內收錄的更好一些。本來想用Google的,但是Google太頻繁的抓取會有驗證碼,沒必要把精力花費在破解驗證碼上面。
必應的收錄數量並沒有查詢介面,因此直接用site:domain.com的方式直接抓取收錄數量,相比SEO查詢介面,這樣直接抓取也更準確一些。
網站首頁完整度
很多域名會解析到web伺服器,一般情況下,正規域名解析到正常的網站,而惡意域名的解析ip要麼沒有web服務,要麼是沒有內容的首頁。例如404頁面、Apache預設頁面、空白頁面等等。
那麼怎麼判斷首頁是不是正常的、完整的呢。最好的方法就是用head less瀏覽器(如phantomjs)去訪問,檢查首頁(包括多媒體資源)的大小,以及媒體資源是否成功載入。這是後續可以優化的一個點。
奈何懶癌晚期,我用了一個取巧的辦法,直接判斷首頁各個媒體標籤的數量。精心設計的首頁肯定有img link script等標籤,滿足的越多,完整度level遍越高。如下圖所示,取level值作為完整度。如果沒開放web服務,則level為0。
圖1 通過標籤給網頁完整度評分
是否是主流域名字尾
一般情況下,普通域名大多數常用.com、.net.、.cn等主流字尾,而惡意域名往往會喜歡註冊小國家域名,如.io、.ru等。
Cn域名一般都要求實名備案,惡意域名很少有cn域名。
地理位置
國內對主機審查比較嚴,除了被黑的肉雞,很少有專門申請國內主機用於黑客行為的。
另外公司客戶主要是政府國企類,向境外的反連本來就是可疑行為,因此把域名的地理位置作為一個維度。
A記錄與CNAME
正規公司如果有註冊企業郵箱的,企業域名一般都會註冊A記錄和CNAME。而惡意域名可能只會註冊A記錄。
如果一個域名既沒有A也沒有CNAME,維度值為0。
待加入維度
WHOIS匿名: 惡意域名的whois資訊一般都選擇匿名,因此whois資訊是否匿名應當作為一個判斷維度。在實際測試過程中,發現很多匿名域名的註冊人、聯絡方式等欄位,不是為空,而是nameserver或者域名註冊商的聯絡方式,因此要建立一個域名商匿名資訊的黑名單來判斷是否匿名。維護成本有些高,在第一個版本中暫不加入該維度。
域名更新的頻繁程度: 使用域名的ttl值或者歷史解析記錄。一般認為惡意域名的解析更換的比較頻繁。做壞事嘛,總是喜歡打一槍換一個地方。
是否使用CDN: 檢測域名是否使用了CDN。CDN一般用於流量比較大的站點進行加速,木馬或shell的C&C域名一般是不會用的。
清洗資料
本文定義的惡意域名為黑客實施攻擊時用的域名,包括但不限於:木馬回連、病毒通訊、反彈shell、SSRF、XSS、DDoS、掛馬、礦機、DNS隧道木馬等等。總之都是黑客攻擊所用。
威脅情報裡的域名中有不少我們不需要的,這些資訊要人工剔除。例如博彩網站、色情站、垃圾郵件域名。用AI也可以識別:抓取網站內容後直接上樸素貝葉斯,或者走NLP情感分析的套路即可,這不在本文的討論範圍內。還有釣魚站也要剔除,識別釣魚站是另一個話題了。
由於擔心誤報影響樣本質量,只取置信度較高的那部分域名。
惡意域名作為正樣本,正常域名作為負樣本,正負樣本比例大約為1:1。
取威脅情報中9月10日的全量惡意域名作為訓練集,另取9月11-17日的增量部分作為測試集。
圖2 整理後的惡意域名樣本
建立模型
筆者訓練了兩種模型,一個是機器學習的代表演算法支援向量機SVM,另一個是卷積神經網路CNN。最後通過多方面對比絕對線上業務使用哪個。
支援向量機
在神經網路沒火之前,SVM是應用最廣泛的機器學習演算法之一,對於線性可分的樣本集識別率很高,那也就註定了本次我們用SVM的效果不會差。
#載入訓練集資料 x_data, y_label = data.load_tran_data() #資料歸一化。由於有些維度值特別高,如百度收錄量和Alexa值,有些維度則特別低,只有1或者0。因此等比縮小是不可取的,否則收斂特別慢。這裡將資料縮小至方差為1均值0的陣列 x_data = preprocessing.scale(x_data) svc = svm.SVC() parameters = [ { 'C': [0.5, 0.8, 0.9, 1, 1.1, 1.2,1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2, 3, 5, 7, 9, 11, 13, 15, 17, 19, 30, 50], 'gamma': [0.1, 0.5, 0.6, 0.7, 0.8,0.9, 1, 1.2, 1.3, 1.5, 2, 2.5, 3, 4, 5, 6, 7, 8, 9, 10, 11], 'kernel': ['rbf'] }, { 'C': [0.5, 0.8, 0.9, 1, 2, 3, 4,4.1, 4.2, 4.3, 4.4, 4.5, 4.6, 5, 5.5, 6, 7, 9, 11, 13, 15, 17, 19, 30, 50], 'kernel': ['linear'] } ] # 使用rbf和linear兩種核函式進行對比,同時使用“爆破”的方式尋找最優引數組合 clf = GridSearchCV(svc, parameters, cv=5,n_jobs=8) clf.fit(x_data,y_label) # 列印最優引數組合 print(clf.best_params_) best_model= clf.best_estimator_ joblib.dump(best_model,"svm2.2.m")
最終確定的最優引數組合是核函式linear和C引數4.2,證明樣本是線性可分的。
在測試集上進行測試,結果準確率97.2% 、召回率97.3%,翻譯成我們熟悉的指標,誤報率為2.8%、漏報率都為2.7%。
卷積神經網路
卷積神經網路CNN可以說憑一己之力掀起了近幾年AI熱潮。CNN的特點是強調顯細節的特徵,大家熟悉的是CNN在影象方面的應用,其實一維的文字、二維的影象、三維的空間、四維的宇宙、五維度的量子態……都可以卷,頗有“大餅卷一切”的趨勢,連三體人的智子都望塵莫及。
好吧,今天有點喝多了。吹牛x的習慣又犯了。
總之,理論上CNN可以擬合任意函式,自然包括線性函數了。
x_data, y_label = data.load_test_data() #載入訓練集並歸一化 x_data = preprocessing.scale(x_data) x_data = np.expand_dims(x_data, axis=2) dim = len(x_data[0]) y_len = len(y_label) model = Sequential() # 輸入層、卷基層 model.add(Conv1D(4, 3, input_shape=(dim, 1), padding='same', activation='relu', use_bias=True)) # BN演算法,使輸出訊號規範為“均值0,方差1”,目的是加速收斂 model.add(BatchNormalization()) # 最大池化層 model.add(MaxPooling1D(3)) # 放棄層,防止過擬合 model.add(Dropout(0.5)) # 再來一次卷積,經過BN演算法規範化後,進行平均池化 model.add(Conv1D(8, 3, padding='same', activation='relu')) model.add(BatchNormalization()) model.add(GlobalAveragePooling1D()) model.add(Dropout(0.5)) # 兩層全連線 model.add(Dense(4, activation='relu')) model.add(Dense(1, activation='sigmoid')) # 訓練模型 model.compile(loss='binary_crossentropy', optimizer='sgd', metrics=['accuracy']) model.fit(x_data, y_label, batch_size=20, epochs=600) model.save("cnn1.22.h5")
該模型在測試集上準確率為97.5%,召回率96.7%。
線上應用
SVM和CNN模型對比資料如下:
模型名稱 | 準確率 | 召回率 |
---|---|---|
SVM | 97.2% (誤報率2.8%) | 97.3% (漏報率2.7%) |
CNN | 97.5% (誤報率2.5%) | 96.7% (漏報率3.3%) |
兩種模型相對而言,SVM誤報略高漏報低,而CNN誤報低漏報高。整體而言兩個模型指標相近,SVM略好於CNN,最終線上決定使用SVM作為檢測演算法。
SVM的2.8%的誤報率反映在出口流量上有點多,需要配合其他策略如黑白名單降低誤報。後來在實際線上應用中,發現誤報的一部分來自於程式所用的API的域名,這類域名在訓練集中沒有包含。修正過程本文不再贅述。
*本文作者:山東星維九州安全技術有限公司,轉載請註明來自FreeBuf.COM