AI安全初探——利用深度學習檢測DNS隱蔽通道
目錄
AI安全初探——利用深度學習檢測DNS隱蔽通道
1、DNS 隱蔽通道簡介
2、 算法前的准備工作——數據采集
3、 利用深度學習進行DNS隱蔽通道檢測
4、 驗證XShell的檢測效果
5、 結語
1、DNS 隱蔽通道簡介
DNS 通道是隱蔽通道的一種,通過將其他協議封裝在DNS協議中進行數據傳輸。由於大部分防火牆和入侵檢測設備很少會過濾DNS流量,這就給DNS作為隱蔽通道提供了條件,從而可以利用它實現諸如遠程控制、文件傳輸等操作,DNS隱蔽通道也經常在僵屍網絡和APT攻擊中扮演着重要的角色。
DNS隱蔽通道可以分為直連和中繼兩種模式。直連也就是Client直接和指定的目標DNS Server(授權的NS 服務器)連接,通過將數據編碼封裝在DNS協議中進行通信,這種方式速度快,但是限制比較多,很多場景不允許用戶指定DNS Server。而中繼模式的DNS通道則更為隱蔽,但同時也因為數據包到達目標DNS Server前需要經過多個DNS查詢服務器,所以速度上較直連模式慢很多。中繼模式的DNS通道原理如圖1所示。
圖1 中繼模式下的DNS隱蔽通道原理
例如,前段時間著名的XShell DNS通道攻擊,黑客在Xshell中植入惡意代碼,通過DNS隱蔽通道外發用戶敏感數據的示例如圖2 所示,黑客將外發數據藏在nylalobghyhirgh.com子域名中。
圖2 Xshell DNS隱蔽通道,黑客將外發數據藏在nylalobghyhirgh.com子域名中
DNS 隱蔽通道從提出到現在已經有了很多實現工具,歷史比較早的有NSTX、Ozymandns,目前比較活躍的有iodine、dnscat2、dns2tcp,其他不太常見的還有DeNise、Heyoka等。不同工具的核心原理相似,但在編碼、實現細節和應用場景方面存在一定的差異。
本文使用卷積神經網絡(CNN)來檢測DNS隱蔽通道。第一步工作是樣本數據采集。
2、算法前的准備工作——數據采集
利用上述DNS隱蔽通道工具進行“黑”樣本采集工作見另一篇博文《DNS隱蔽通道檢測——數據收集,利用iodine進行DNS隱蔽通道樣本收集》,其流程是先抓取DNS隱蔽通道工具攻擊過程中的網絡流量pcap包,然后利用wireshark工具將pcap包轉換為機器學習算法能夠識別文本文件。這是一個體力活,我收集到的業界流行的DNS 隱蔽通道工具的數據樣本如圖3所示。
圖3 收集的DNS隱蔽通道工具示意樣本
以dnscat2工具為例,其生成的一個樣本見圖4,可以看到DNS報文里包含了大量的較長子域名,而外發數據便藏在這些子域名中(我使用的主域名是friendsakka.xyz)。
圖4 dnscat2工具生成的示意樣本
至於“白”樣本收集,我們使用的是某高校的校園網絡流量。黑白樣本收集好以后,就可以進入檢測算法環節了。
3、利用深度學習進行DNS隱蔽通道檢測
本文使用CNN(卷積神經網絡)來檢測DNS隱蔽通道,在介紹算法前,先簡單介紹下CNN。
CNN(卷積神經網絡)常用於圖像識別並取得了極佳的效果。圖5展示的是一個典型的卷積神經網絡結構。該網絡包含兩個卷積層(convolution layer),兩個池化層(pooling layer)和一個全連接層(fully connected layer)。
圖5 典型的卷積神經網絡結構
卷積神經網絡的基本思想和我們人類大腦識別圖像的機制是一致的。例如,當看到一張“喵星人”圖像時,我們之所以認為它是“喵星人”,是因為我們看到它有萌萌的頭、長長的尾巴、柔軟光滑的皮毛等明顯特征,通過組合(更高層次的抽象)這些特征,我們的大腦最終便可做出准確的判斷。卷積神經網絡的基本思想也是類似,核心理念包括:
- 局部感受野:這是通過卷積層來完成的,形象地說,就是模仿你的眼睛,想想看,你在看東西的時候,目光是聚焦在一個相對較小的局部吧?比如喵星人的圖像上有爪子或者萌頭等明顯的局部特征。而在卷積神經網絡中,每個隱層節點只連接到圖像的某些局部像素點上。
- 池化:形象地說,當你看向遠方,然后閉上眼睛,你仍然記得看到了些什么,但是你能完全記住你剛剛看到的每一個細節嗎?答案是不能。同樣,在卷積神經網絡中,沒有必要對原圖像所有細節做處理,而是使用某種“壓縮”方法,這就是池化,也就是每次將原圖像卷積后,都通過一個采樣的過程,來減小圖像的規模。
- 權值共享:在卷積神經網中,同一個卷積核內,所有的神經元的權值是相同的,從而大大減少需要訓練的參數。之所以如此設計,就如同人類大腦的某個神經中樞中的神經細胞,它們的結構、功能是相同的,甚至可以互相替代。
如果你還沒有理解的話,我們再看下面這個例子,專家們設計了包含10個卷積層,4個池化層和2個全連接層的卷積神經網絡,見圖6所示,該網絡主要用於圖像識別。專家們發現,在比較低的層,神經元傾向於學習一些簡單的模式,比如圖像邊緣、顏色、條帶燈;而在比較高的層,神經元能夠檢測到一些更為高層次的抽象特征,比如整輛轎車等。
圖6 專家構建的用於圖像識別的卷積神經網絡
CNN的誕生是為了解決圖像處理問題。在安全界,瀚思科技開發出了基於深度學習的二進制病毒樣本檢測技術,可以做到沙箱同等水平的 99% 的檢測准確率,而誤報率低於 1/1000。
CNN檢測的圖像通常是二維數據,而作為DNS隱蔽通道傳輸的子域名雖是一維的文本數據,但同樣可以用CNN進行處理。在本文的DNS隱蔽通道檢測中,我們使用一維的卷積函數處理DNS子域名片段,以提煉高級特征進一步分析。
利用CNN進行DNS隱蔽通道檢測的代碼框架如下:
def run(): X, Y, max_len, volcab_size = get_data() trainX, testX, trainY, testY = train_test_split(X, Y, test_size=0.2, random_state=42) model = get_cnn_model(max_len, volcab_size) model.fit(trainX, trainY, validation_set=(testX, testY), show_metric=True, batch_size=32)
大致流程是先獲取黑白樣本數據,然后將80%的數據用於訓練,剩下20%的數據用於CNN模型驗證。
其中,get_cnn_model使用了python的TensorFlow庫tflearn,其代碼如下:
def get_cnn_model(max_len, volcab_size): # 構建CNN模型 network = tflearn.input_data(shape=[None, max_len], name='input') # 為了進行數據降維加入了embedding層 network = tflearn.embedding(network, input_dim=volcab_size, output_dim=64) # 卷積層使用了一維的卷積函數 branch1 = conv_1d(network, 128, 3, padding='valid', activation='relu', regularizer="L2") branch2 = conv_1d(network, 128, 4, padding='valid', activation='relu', regularizer="L2") branch3 = conv_1d(network, 128, 5, padding='valid', activation='relu', regularizer="L2") network = merge([branch1, branch2, branch3], mode='concat', axis=1) network = tf.expand_dims(network, 2) # 最大池化操作 network = global_max_pool(network) # 加入dropout防止過擬合 network = dropout(network, 0.5) # 全連接 network = fully_connected(network, 2, activation='softmax') # 回歸操作 network = regression(network, optimizer='adam', learning_rate=0.001, loss='categorical_crossentropy', name='target') # 構建深度神經網絡模型 model = tflearn.DNN(network, tensorboard_verbose=0) return model
在上述模型中,為了進行數據降維先加入了embedding層,其本質和word2vec一樣,因為在DNS 隱蔽通道的子域名中包含了大量的字符而導致數據輸入維度過高,代碼中output_dim=64表示將數據輸入降低維度到64維。接下來我們使用一維的卷積函數conv_1d處理DNS子域名片段,提煉高級特征進一步分析。由於典型的一維卷積函數處理文字片段的大小通常為3、4、5,我們也使用這些典型參數。此外,模型中加入了dropout,用於防止過擬合。
獲取黑白樣本數據的代碼如下,其中包括對原始的子域名字符進行字典編碼(先得到黑白樣本所有子域名字符集合),並使用pad_sequences函數按照固定長度進行子域名長度對齊操作(因CNN要求各樣本數據輸入維度一致,而某些子域名很短,某些子域名很長,pad_sequences將短的子域名采用特殊數字進行填充補齊,使它們長度一致):
def get_data(): black_x, white_x = get_local_data() black_y, white_y = [LABEL.black]*len(black_x), [LABEL.white]*len(white_x) X = black_x + white_x labels = black_y + white_y # Generate a dictionary of valid characters valid_chars = {x:idx+1 for idx, x in enumerate(set(''.join(X)))} max_features = len(valid_chars) + 1 maxlen = np.max([len(x) for x in X]) # Convert characters to int and pad X = [[valid_chars[y] for y in x] for x in X] X = pad_sequences(X, maxlen=maxlen, value=0.) # Convert labels to 0-1 Y = to_categorical(labels, nb_classes=2) return X, Y, maxlen, max_features
其中,get_local_data主要是從樣本文件中提取DNS子域名。
def get_local_data(tag="labeled"): data_path = "latest_metadata_sample" black_data, white_data = [], [] for dir_name in ("black", "white_like"): dir_path = "%s/%s_%s" % (data_path, tag, dir_name) for path in iterbrowse(dir_path): with open(path) as f: for line in f: _, subdomain = extract_subdomain(line) if subdomain is not None: if "white_like" in path: white_data.append(subdomain) elif "black" in path: black_data.append(subdomain) return black_data, white_data
核心代碼講解完畢,開始進行模型訓練。在我的個人電腦上,算法運行時間大概17小時,最后的結果如下:
Run id: 6U1KPD Log directory: /tmp/tflearn_logs/ -- Training Step: 5131 | total loss: 0.03967 | time: 6406.696s | Adam | epoch: 001 | loss: 0.03967 - acc: 0.9888 | val_loss: 0.02546 - val_acc: 0.9926 -- iter: 164165/164165 -- Training Step: 10262 | total loss: 0.03562 | time: 6422.500s5776/164165 | Adam | epoch: 002 | loss: 0.03562 - acc: 0.9917 | val_loss: 0.01793 - val_acc: 0.9948 -- iter: 164165/164165 -- Training Step: 15393 | total loss: 0.03433 | time: 6357.422s | Adam | epoch: 003 | loss: 0.03433 - acc: 0.9888 | val_loss: 0.01432 - val_acc: 0.9962 -- iter: 164165/164165 -- Training Step: 20524 | total loss: 0.02852 | time: 6312.083s | Adam | epoch: 004 | loss: 0.02852 - acc: 0.9892 | val_loss: 0.01186 - val_acc: 0.9972 -- iter: 164165/164165 -- Training Step: 25655 | total loss: 0.02441 | time: 6292.232s | Adam | epoch: 005 | loss: 0.02441 - acc: 0.9947 | val_loss: 0.01398 - val_acc: 0.9960 -- iter: 164165/164165 -- Training Step: 30786 | total loss: 0.01890 | time: 6286.252s | Adam | epoch: 006 | loss: 0.01890 - acc: 0.9930 | val_loss: 0.01373 - val_acc: 0.9963 -- iter: 164165/164165 -- Training Step: 35917 | total loss: 0.00921 | time: 6261.734s | Adam | epoch: 007 | loss: 0.00921 - acc: 0.9984 | val_loss: 0.01290 - val_acc: 0.9966 -- iter: 164165/164165 -- Training Step: 41048 | total loss: 0.00780 | time: 6266.017s | Adam | epoch: 008 | loss: 0.00780 - acc: 0.9994 | val_loss: 0.01177 - val_acc: 0.9970 -- iter: 164165/164165 -- Training Step: 46179 | total loss: 0.01850 | time: 6257.918s | Adam | epoch: 009 | loss: 0.01850 - acc: 0.9951 | val_loss: 0.01109 - val_acc: 0.9971 -- iter: 164165/164165 -- Training Step: 51310 | total loss: 0.02062 | time: 6258.476s | Adam | epoch: 010 | loss: 0.02062 - acc: 0.9953 | val_loss: 0.00966 - val_acc: 0.9974 -- iter: 164165/164165
可以看到算法迭代了10次,每次訓練時間一個多小時,最終的檢測精度在99.53%,使用CNN進行DNS隱蔽通道的檢測效果初步看來還不錯。但是,因為訓練樣本和測試樣本的內在數據分布規律是相同的,該精度再高也可能存在一定的過擬合風險。下面我們利用前段時間著名的XShell DNS隱蔽通道攻擊來評估算法的檢測能力。
4、驗證XShell的檢測效果
我們嘗試用訓練出的算法檢測前段時間著名的XShell隱蔽通道攻擊,其進行攻擊的域名為nylalobghyhirgh.com,將包含該攻擊的DNS樣本加入到模型預測中:
def predict(): testX, testY = get_xshell_data() model = get_cnn_model() .... predictions = model.predict(testX) cnt = 0 for i,p in enumerate(predictions): if abs(p[2]-testY[i][2]) < 0.1: cnt += 1 print cnt/(len(predictions)+.0)
代碼運行后得到的檢測准確率為97.3%,也就意味着nylalobghyhirgh.com下97.3%的子域名都可能是在利用DNS隱蔽通道傳輸數據。
上述驗證表明,使用CNN可以有效地檢測DNS隱蔽通道。當然,最終的檢測准確率還需在真實而復雜的網絡環境中長期運行觀察而定。
5、結語
本文只是AI安全初探的一次嘗試,大致說明了使用深度學習算法CNN進行安全檢測的基本流程,文中有寫得不明白的地方,歡迎大家留言一起探討。
轉載請注明出處:http://www.cnblogs.com/bonelee/p/8109172.html
參考資料:
1、http://blog.csdn.net/baobei0112/article/details/54906309