Kate Li (Taiwan)的部落格

首頁

機器學習實踐

作者 morcillo 時間 2020-03-15
all

什麼是DGA

DGA(Domain Generate Algorithm功能變數名稱生成算灋)是一種使用時間,字典,硬編碼的常數利用一定的算灋生成的功能變數名稱。DGA生成的功能變數名稱具有為隨機性,用於中心結構的僵屍網路中與C&C服務器的連接,以逃避功能變數名稱黑名單檢測科技。

DGA功能變數名稱使用的大致流程如下:首先攻擊者通過運行算灋生成DGA功能變數名稱,然後隨機選擇其中的少量功能變數名稱進行注册,並將功能變數名稱綁定到C&C服務器。受害者的機器被植入惡意程式後運行DGA算灋生成功能變數名稱,並檢測功能變數名稱是否可以連接,如果不能連接就嘗試下一個功能變數名稱,如果可以連接就選取該功能變數名稱作為該惡意程式的控制端服務器功能變數名稱。

DGA功能變數名稱特點主要有以下幾點:1)DGA功能變數名稱大部分都沒有註冊,因為註冊功能變數名稱需要一定的成本,而且從DGA功能變數名稱的使用流程來說只需要注册一個功能變數名稱就可以達到目的。2)DGA功能變數名稱具有偽隨機性,與正常的功能變數名稱具有一定的差別,一般正常的功能變數名稱在拼寫上符合一定的規律。3)DGA功能變數名稱一般長度較長,長度短的功能變數名稱往往已經被注册了。

DGA功能變數名稱舉例:

CryptoLocker(ryhqdtlbwacoikd.net)

Gameover(ocdjtg1pm9csac7cbzpx7r75a.com)

Necurs(mjlglqmatygruta.pw)

Wannacry(iuqerfsodp9ifjaposdfjhgosurijfaewrwergwea.com)

xshell(xmponmzmxkxkh.com)

ccleaner(ab3d685a0c37.com)

pykspa_v2_fake(sgsqoqmyceqm.org)

基於DGA功能變數名稱的特點,雖然採用傳統的功能變數名稱黑名單也可以檢測一些已知的DGA功能變數名稱,但是對於一些未知DGA功能變數名稱就束手無策了。我們還可以通過功能變數名稱長度,是否注册,以及注册的時間和注册資訊進行判斷,但是這種管道需要借助協力廠商信譽系統,而且效果往往也不是很理想。由於DGA功能變數名稱和正常功能變數名稱存在一定的差异,以及存在大量的正負樣本,所以可以嘗試使用機器學習來進行DGA功能變數名稱的檢測。

機器學習二分類算灋的衡量名額

1)混淆矩陣

說到二分類問題的性能指標,我們首先會想到混淆矩陣,下麵為混淆矩陣的示意圖

FP表示預測為YES實際為NO的數量

TP表示預測為YES實際為YES的數量

FN表示預測為NO實際為YES的數量

TN表示預測為NO實際為NO的數量

Y’=TP+FP 表示預測為YES的數量

N’=FN+TN表示預測為NO的數量

Y=TP+FN表示實際為YES的數量

N=FP+TN表示實際為NO的數量

有了混淆矩陣我們可以很方便的計算下麵的準確率,精確率,召回率等名額

2)準確率

準確率是使用最普遍和直觀的名額,意義是預測準確樣本的占所有樣本的比例,可表示為(TP+TN)/(Y+N)

3)精確率

精確率也叫查準率,意義是所有預測正確的正類占預測為正類的比例,可表示為P=TP/Y’

4)召回率

召回率也叫查全率,意義是所有預測正確的正類占實際為正類的比例,可表示為R=TP/Y

5)特异度

特异度也稱真陰性率,意義是所有預測正確的負類占實際為負的樣本負類的比例,可表示為TN/N

6)誤報率

誤報率意義是所有預測錯誤的正類占實際為負類的比例,可表示為FP/N

7)漏報率

漏報率意義是所有預測錯誤的負類占實際為正類的比例,可表示為FN/Y

8)綜合評價名額(F-Measure又稱為F-Score)

精確率和召回率時常會產生衝突的情况,需要綜合考量他們,於是就有了F-Measure(又稱為F-Score)。F-Measure是Precision和Recall加權調和平均F=(a*a+1)P*R/a*a*(P+R)

當參數α=1時,就是最常見的F1,也即F1=2P*R/(P+R)。可知F1綜合了P和R的結果,當F1較高時則能說明試驗方法比較有效。

9)ROC曲線

ROC曲線的全稱叫做Receiver Operating Characteristic,常常被用來判別一個分類器的好壞程度。如下圖所示:

上圖引自(http://alexkong.net/2013/06/introduction-to-auc-and-roc/)

橫坐標可表示為FPR=FP/N,也就是誤報率

縱坐標可表示為TPR=TP/Y,也就是查全率

一些分類器得到的結果往往不是0,1這樣的標籤,如神經網路得到諸如0.5,0.8這樣的分類結果。這時,我們人為取一個閾值比方說0.6,那麼小於0.6的歸為0類,大於等於0.6的歸為1類,可以得到一個分類結果。同樣,這個閾值我們可以取0.1或0.2等等。取不同的閾值,最後得到的分類情况也就不同。通過遍歷不同的閾值,分別計算FPR和TPR,作為一個點。將這些點連接起來就組成了ROC曲線。ROC曲線越靠近左上角,分類器效果越好。

10)AUC

AUC全稱Area Under ROC Curve。是一種用來度量分類模型好壞的一個標準,ROC雖然直觀,但是不够量化。AUC是對ROC的量化,其值為ROC曲線所覆蓋的區域面積,顯然,AUC越大,分類器分類效果越好。

AUC = 1,是完美分類器,但是絕大多數預測的場合,不存在完美分類器。

0.5 < AUC < 1,優於隨機猜測。這個分類器(模型)有預測價值。

AUC = 0.5,等同於隨機猜測,模型沒有意義。

AUC < 0.5,比隨機猜測還差;但只要反著預測,就優於隨機猜測。

訓練數據

DGA樣本數據,我們採用已知DGA生成算灋生成的數據加上360 netlab開放的黑樣本數據。360 netlab黑樣本數據的下載連結:http://data.netlab.360.com/feeds/dga/dga.txt。

正常功能變數名稱採用長度小於5的字串組合以及alexa發佈的排名前100萬的網站功能變數名稱,其下載地址為http://s3.amazonaws.com/alexa-static/top-1m.csv.zip

另外,在進行模型訓練時,儘量保證正常功能變數名稱數量和DGA功能變數名稱數量在一個量級。

DGA分類識別-樸素貝葉斯

特徵選取

從正常功能變數名稱拼寫符合一定拼寫規律,DGA功能變數名稱偽隨機性來看,可以使用N-GRAM模型進行建模,這裡我們採用2-GRAM,首先將功能變數名稱當作一個字串,去除頂級域然後進行建模。那pingan.com舉例:去除頂級域後得到字串pingan,進行2-gram處理得到字串清單’pi’  ‘in’ ’ng’ ‘ga’ ‘an’。我們可以使用python庫sklearn提供的CountVectorizer函數直接進行處理即可:

from sklearn.feature_extraction.text import CountVectorizerngram_vectorizer = CountVectorizer(analyzer='char',ngram_range=(2,2),dtype=np.int32)

模型工具

使用python庫sklearn提供的MultinomialNB

程式碼片段:

from sklearn.naive_bayes import MultinomialNB

程式碼流程介紹:

1)將數据集劃分訓練集和測試集

x_train,x_test,y_train,y_test = train_test_split(X,y,test_size=0.2)

2)將數据集進行2-GRAM處理,並進行數據擬合和標準化。

count_vec = CountVectorizer(analyzer='char',ngram_range=(2,2),dtype=np.int32)x_train = count_vec.fit_transform(x_train)x_test = count_vec.transform(x_test)

3)生成樸素貝葉斯算灋模型,並在訓練集上訓練,獲得模型數據

mtnb = MultinomialNB()mtnb.fit(x_train,y_train)

4)使用模型在測試集上進行預測,並列印各項分類性能指標

y_pred=mtnb.predict(x_test)print(classification_report(y_test,y_pred))//列印精確度,召回率 F1-score等名額print metrics.confusion_matrix(y_test,y_pred)//列印混淆矩陣t_probs = mtnb.predict_proba(x_test)[:,1 ]t_auc = sklearn.metrics.roc_auc_score(y_test,t_probs)print('MultinomialNB: auc = %f ' %(t_auc))//列印AUC

測試結果

如下圖所示:精確度77%,召回率76% f1-Score 76%,AUC 87%,效果不是很理想。

DGA分類識別-XGBoost

特徵選取

同樣採用2-GRAM進行處理

模型工具

使用python的xgboost庫,程式碼片段:

import xgboost as xgb

程式碼流程介紹

1)將數据集劃分訓練集和測試集

x_train,x_test,y_train,y_test = train_test_split(X,y,test_size=0.2)

2)將數据集進行2-GRAM處理,並進行數據擬合和標準化。

count_vec = CountVectorizer(analyzer='char',ngram_range=(2,2),dtype=np.int32)x_train = count_vec.fit_transform(x_train)x_test = count_vec.transform(x_test)

3)生成樸素貝葉斯算灋模型,並在訓練集上訓練,獲得模型數據

model = xgb.XGBClassifier()model.fit(x_train,y_train)

4)使用模型在測試集上進行預測,並列印各項分類性能指標

y_pred=model .predict(x_test)print(classification_report(y_test,y_pred))//列印精確度,召回率 F1-score等名額print metrics.confusion_matrix(y_test,y_pred)//列印混淆矩陣t_probs = model.predict_proba(x_test)[:,1]t_auc = sklearn.metrics.roc_auc_score(y_test,t_probs)print('XGBClassifier: auc = %f ' %(t_auc))//列印AUC

測試結果

如下圖所示:精確度84%,召回率81% f1-Score 81%,AUC 91.7264%,效果尚可。

DGA分類識別-神經網路多層感知機

特徵選取

同樣採用2-GRAM進行處理

模型工具

Keras是一個高層級的python神經網路框架,Keras後端可以在Tensorflow或者Theano上運行,Keras 是為支持快速實驗而生,具有高度模組化,極簡,和可擴充特性。我們選用keras進行神經網路多層感知機模型的測試。

程式碼流程介紹

1)將數据集進行2-GRAM處理,並進行數據擬合和標準化。然後將數据集劃分訓練集和測試集

ngram_vectorizer = CountVectorizer(analyzer='char',ngram_range=(2,2),dtype=np.int32)count_vec = ngram_vectorizer.fit_transform(X)//數據擬合和標準化max_features = count_vec.shape[1] //計算輸入維度

//劃分訓練集和測試集

X_train,X_test,y_train,y_test,_,label_test = train_test_split(count_vec,y,labels,test_size=0.2)X_train,X_holdout,y_train,y_holdout = train_test_split(X_train,y_train,test_size=0.05)

2)利用keras生成神經網路多層感知機模型。這裡簡要介紹下其中一些概念:啟動函數activation:啟動函數的主要作用是提供網絡的非線性建模能力,常見的有 sigmoid函數,tanh函數,ReLU函數, ELU函數, PReLU函數,softmax函數等

損失函數loss:就是一個評分函數,用來對模型預測準確性進行打分,模型的訓練就是要通過樣本將損失函數最小化,常見的有:0-1損失函數,平方損失函數,絕對損失函數,對數損失函數等

優化器optimizer:最小化損失函數的求解方法。(常用的有最小二乘法,梯度下降法)

//創建一個Sequential模型

model = Sequential()//添加一個全連接層,啟動函數使用sigmoid,輸出維度128model.add(Dense(128,input_dim=max_features,activation='sigmoid'))//添加一個Dropout層,用於防止過擬合model.add(Dropout(0.5))model.add(Dense(64,activation='relu'))model.add(Dropout(0.5))model.add(Dense(1,activation='sigmoid'))//編譯模型,損失函數採用對數損失函數,優化器選用adammodel.compile(loss='binary_crossentropy',optimizer='adam')

3)使用模型進行最多50輪訓練,並記錄訓練每輪AUC的值,在相隔兩輪的AUC值沒有新增時退出訓練

for ep in range(50):  model.fit(X_train,y_train,batch_size=batch_size,nb_epoch=1)  t_probs = model.predict_proba(X_holdout)  t_auc = sklearn.metrics.roc_auc_score(y_holdout,t_probs)//計算AUC值  if t_auc > best_auc:    best_auc = t_auc    best_iter = ep    //列印分類模型名額    probs =model.predict_proba(X_test)    print(classification_report(y_test,probs > .5))    print('mlp: auc = %f ' %confusion_matrix(y_test,probs > .5))  else:    if(ep-best_iter)> 2:      Break

測試結果

如下圖所示:精確度99%,召回率99% f1-Score 99%,AUC 99.9138%,效果很好。

DGA分類識別-迴圈神經網路單層LSTM

特徵選取

簡單的將功能變數名稱轉換為整數下標清單,然後使用keras的Embedding嵌入層轉換為固定大小的向量

模型工具

我們選用keras進行迴圈神經網路單層LSTM的測試。

程式碼流程介紹

1)將數据集轉換為整數下標數組的模式,並將數據劃分為訓練集和測試集

site_chars=“0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_”valid_chars = {x:idx+1 for idx,x in enumerate(set(''.join(site_chars)))}max_features = len(valid_chars)+ 1 //計算特徵字元長度maxlen = np.max([ len(x)for x in X])//記錄最長的功能變數名稱長度X = [[valid_chars[y] for y in x] for x in X] //轉換為下標數組X =sequence.pad_sequences(X,maxlen=maxlen)//進行長度填充//劃分訓練集和測試集X_train,X_test,y_train,y_test,_,label_test = train_test_split(X,y,labels,test_size=0.2)X_train,X_holdout,y_train,y_holdout = train_test_split(X_train,y_train,test_size=0.05)

2)利用keras生成迴圈神經網路單層LSTM模型:

//創建一個Sequential模型model = Sequential()//添加一個嵌入層,輸出向量大小256,嵌入層是將正整數(下標)轉換為具有固定大小的向量,//其本質就是word2vec,底層實現是2-gram(詞頻)+神經網路model.add(Embedding(max_features,output_dim=256,input_length=maxlen))//添加長短期記憶網絡LSTM,從樣本中學習特徵,這個是核心層model.add(LSTM(128))//添加Dropout層防止過擬合model.add(Dropout(0.5))//添加全連接層,啟動函數使用'sigmoid'model.add(Dense(1,activation='sigmoid'))//編譯模型,損失函數採用對數損失函數,優化器選用rmsprop,//該優化器通常是面對遞迴神經網路時的一個良好選擇model.compile(loss='binary_crossentropy',optimizer='rmsprop')

3)使用模型進行最多25輪訓練,並記錄訓練每輪AUC的值,在相隔兩輪的AUC值沒有新增時退出訓練

for ep in range(25):  model.fit(X_train,y_train,batch_size=batch_size,nb_epoch=1)  t_probs = model.predict_proba(X_holdout)  t_auc = sklearn.metrics.roc_auc_score(y_holdout,t_probs)//計算AUC值    if t_auc > best_auc:      best_auc = t_auc      best_iter = ep      //列印分類模型名額      probs = model.predict_proba(X_test)      print(classification_report(y_test,probs > .5))      print('Single LSTM: auc = %f ' %confusion_matrix(y_test,probs > .5))    else:      if(ep-best_iter)> 2:        Break

測試結果

如下圖所示:精確度99%,召回率99% f1-Score 99%,AUC 99.9233%,效果很好。

DGA分類識別-迴圈神經網路多層LSTM

特徵選取和模型選擇同單層LSTM

程式碼流程介紹

1)將數据集轉換為整數下標數組的模式,並將數據劃分為訓練集和測試集

site_chars=“0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_”valid_chars = {x:idx+1 for idx,x in enumerate(set(''.join(site_chars)))}max_features = len(valid_chars)+ 1 //計算特徵字元長度maxlen = np.max([ len(x)for x in X])//記錄最長的功能變數名稱長度X = [[valid_chars[y] for y in x] for x in X] //轉換為下標數組X =sequence.pad_sequences(X,maxlen=maxlen)//進行長度填充//劃分訓練集和測試集X_train,X_test,y_train,y_test,_,label_test = train_test_split(X,y,labels,test_size=0.2)X_train,X_holdout,y_train,y_holdout = train_test_split(X_train,y_train,test_size=0.05)

2)利用keras生成迴圈神經網路多層LSTM模型:

//創建一個Sequential模型model = Sequential()//添加一個嵌入層,輸出向量大小256,嵌入層是將正整數(下標)轉換為具有固定大小的向量,//其本質就是word2vec,底層實現是2-gram(詞頻)+神經網路model.add(Embedding(max_features,output_dim=256,input_length=maxlen))//添加長短期記憶網絡LSTM,從樣本中學習特徵,這個是核心層model.add(LSTM(128,return_sequences=True)) //返回維度128的向量序列model.add(LSTM(64,return_sequences=True))  //返回維度64的向量序列model.add(LSTM(64))//返回維度64的單個向量//添加全連接層,啟動函數使用'sigmoid'model.add(Dense(1,activation='sigmoid'))//編譯模型,損失函數採用對數損失函數,優化器選用rmsprop,//該優化器通常是面對遞迴神經網路時的一個良好選擇model.compile(loss='binary_crossentropy',optimizer='rmsprop')

4)使用模型進行最多25輪訓練,並記錄訓練每輪AUC的值,在相隔兩輪的AUC值沒有新增時退出訓練

for ep in range(25):  model.fit(X_train,y_train,batch_size=batch_size,nb_epoch=1)  t_probs = model.predict_proba(X_holdout)  t_auc = sklearn.metrics.roc_auc_score(y_holdout,t_probs)//計算AUC值  if t_auc > best_auc:    best_auc = t_auc    best_iter = ep    //列印分類模型名額    probs =model.predict_proba(X_test)    print(classification_report(y_test,probs > .5))    print('Single LSTM: auc = %f ' %confusion_matrix(y_test,probs > .5))  else:    if(ep-best_iter)> 2:      Break

測試結果

如下圖所示:精確度99%,召回率99% f1-Score 99%,AUC 99.9476%,效果很好。