目錄html
AI安全初探——利用深度學習檢測DNS隱蔽通道python
1、DNS 隱蔽通道簡介算法
2、 算法前的準備工做——數據採集shell
3、 利用深度學習進行DNS隱蔽通道檢測安全
4、 驗證XShell的檢測效果服務器
5、 結語網絡
1、DNS 隱蔽通道簡介app
DNS 通道是隱蔽通道的一種,經過將其餘協議封裝在DNS協議中進行數據傳輸。因爲大部分防火牆和入侵檢測設備不多會過濾DNS流量,這就給DNS做爲隱蔽通道提供了條件,從而能夠利用它實現諸如遠程控制、文件傳輸等操做,DNS隱蔽通道也常常在僵屍網絡和APT攻擊中扮演着重要的角色。框架
DNS隱蔽通道能夠分爲直連和中繼兩種模式。直連也就是Client直接和指定的目標DNS Server(受權的NS 服務器)鏈接,經過將數據編碼封裝在DNS協議中進行通訊,這種方式速度快,可是限制比較多,不少場景不容許用戶指定DNS Server。而中繼模式的DNS通道則更爲隱蔽,但同時也由於數據包到達目標DNS Server前須要通過多個DNS查詢服務器,因此速度上較直連模式慢不少。中繼模式的DNS通道原理如圖1所示。dom
圖1 中繼模式下的DNS隱蔽通道原理
例如,前段時間著名的XShell DNS通道攻擊,黑客在Xshell中植入惡意代碼,經過DNS隱蔽通道外發用戶敏感數據的示例如圖2 所示,黑客將外發數據藏在nylalobghyhirgh.com子域名中。
圖2 Xshell DNS隱蔽通道,黑客將外發數據藏在nylalobghyhirgh.com子域名中
DNS 隱蔽通道從提出到如今已經有了不少實現工具,歷史比較早的有NSTX、Ozymandns,目前比較活躍的有iodine、dnscat2、dns2tcp,其餘不太常見的還有DeNise、Heyoka等。不一樣工具的核心原理類似,但在編碼、實現細節和應用場景方面存在必定的差別。
本文使用卷積神經網絡(CNN)來檢測DNS隱蔽通道。第一步工做是樣本數據採集。
利用上述DNS隱蔽通道工具進行「黑」樣本採集工做見另外一篇博文《DNS隱蔽通道檢測——數據收集,利用iodine進行DNS隱蔽通道樣本收集》,其流程是先抓取DNS隱蔽通道工具攻擊過程當中的網絡流量pcap包,而後利用wireshark工具將pcap包轉換爲機器學習算法可以識別文本文件。這是一個體力活,我收集到的業界流行的DNS 隱蔽通道工具的數據樣本如圖3所示。
圖3 收集的DNS隱蔽通道工具示意樣本
以dnscat2工具爲例,其生成的一個樣本見圖4,能夠看到DNS報文裏包含了大量的較長子域名,而外發數據便藏在這些子域名中(我使用的主域名是friendsakka.xyz)。
圖4 dnscat2工具生成的示意樣本
至於「白」樣本收集,咱們使用的是某高校的校園網絡流量。黑白樣本收集好之後,就能夠進入檢測算法環節了。
本文使用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隱蔽通道攻擊來評估算法的檢測能力。
咱們嘗試用訓練出的算法檢測前段時間著名的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隱蔽通道。固然,最終的檢測準確率還需在真實而複雜的網絡環境中長期運行觀察而定。
本文只是AI安全初探的一次嘗試,大體說明了使用深度學習算法CNN進行安全檢測的基本流程,文中有寫得不明白的地方,歡迎你們留言一塊兒探討。
轉載請註明出處:http://www.cnblogs.com/bonelee/p/8109172.html
參考資料:
一、http://blog.csdn.net/baobei0112/article/details/54906309