《web安全之機器學習入門》第7章樸素貝葉斯模型檢測webshell
阿新 • • 發佈:2018-12-25
N-gram演算法,認為第N個詞只與前面的第N-1個詞相關。
例如對於一個句子,I love my country.
那麼2-gram得到的詞集為:
["I love","love my","my country"]
例如對於一個句子,I love my country.
那麼2-gram得到的詞集為:
["I love","love my","my country"]
程式碼如下:
檢測webshell的第一種方式的思路為,將php webshell檔案按照單詞分詞後(正則\b\w+\b),按照2-gram演算法得到詞集,從而得到檔案每一行在該詞集上的分佈情況,得到特徵向量;然後將正常的php檔案也按照如上方法在如上詞集上得到特徵向量。
webshell檔案的行標記為1,正常php檔案的行標記為0,特徵向量和標記在一起組成資料集。再在樸素貝葉斯模型上使用交叉驗證的方式得的準確度。
程式碼如下:
#coding:utf-8 import os import numpy as np from sklearn.feature_extraction.text import CountVectorizer from sklearn.model_selection import cross_val_score from sklearn.naive_bayes import GaussianNB DATAPATH = os.path.dirname(os.path.abspath(__file__)) + "/data" BLACKPATH = DATAPATH + "/black" WHITEPATH = DATAPATH + "/white" def parse_files(path,rtn): files = os.listdir(path) for item in files: if item in ['.', '..']: continue cpath = path + "/" + item if os.path.isdir(cpath): parse_files(cpath, rtn) else: if cpath.endswith(".php"): with open(cpath, "r") as f: for line in f.readlines(): line = line.strip() rtn.append(line) if __name__ == '__main__': black_lines = list() parse_files(BLACKPATH, black_lines) white_lines = list() parse_files(WHITEPATH, white_lines) webshell_vectorizer = CountVectorizer(ngram_range=(2,2), decode_error="ignore", token_pattern=r'\b\w+\b') x1 = webshell_vectorizer.fit_transform(black_lines).toarray() vocabulary = webshell_vectorizer.vocabulary_ y1 = len(x1)*[1] white_vectorizer = CountVectorizer(ngram_range=(2,2), decode_error="ignore", token_pattern=r'\b\w+\b', vocabulary=vocabulary) x2 = white_vectorizer.fit_transform(white_lines).toarray() y2 = len(x2)*[0] x = np.concatenate((x1, x2)) y = np.concatenate((y1, y2)) model = GaussianNB() score = cross_val_score(model, x, y, cv=10) print score print "precision:", np.mean(score)*100
程式碼執行的效果如下:
檢測webshell的第二種方式的思路為,將php webshell檔案按照函式呼叫或者字串常量分詞後(正則\b\w+\b(|\'\w+\'),按照1-gram演算法得到詞集(1-gram應該就是指的單個詞了),從而得到檔案每一行在該詞集上的分佈情況,得到特徵向量;然後將正常的php檔案也按照如上方法在如上詞集上得到特徵向量。
webshell檔案的行標記為1,正常php檔案的行標記為0,特徵向量和標記在一起組成資料集。再在樸素貝葉斯模型上使用交叉驗證的方式得的準確度。
程式碼如下:
#coding:utf-8 import os import numpy as np from sklearn.feature_extraction.text import CountVectorizer from sklearn.model_selection import cross_val_score from sklearn.naive_bayes import GaussianNB DATAPATH = os.path.dirname(os.path.abspath(__file__)) + "/data" BLACKPATH = DATAPATH + "/black" WHITEPATH = DATAPATH + "/white" def parse_files(path,rtn): files = os.listdir(path) for item in files: if item in ['.', '..']: continue cpath = path + "/" + item if os.path.isdir(cpath): parse_files(cpath, rtn) else: if cpath.endswith(".php"): with open(cpath, "r") as f: for line in f.readlines(): line = line.strip() rtn.append(line) if __name__ == '__main__': black_lines = list() parse_files(BLACKPATH, black_lines) white_lines = list() parse_files(WHITEPATH, white_lines) webshell_vectorizer = CountVectorizer(ngram_range=(1,1), decode_error="ignore", token_pattern=r'\b\w+\b\(|\'\w+\'') x1 = webshell_vectorizer.fit_transform(black_lines).toarray() vocabulary = webshell_vectorizer.vocabulary_ y1 = len(x1)*[1] white_vectorizer = CountVectorizer(ngram_range=(1,1), decode_error="ignore", token_pattern=r'\b\w+\b\(|\'\w+\'', vocabulary=vocabulary) x2 = white_vectorizer.fit_transform(white_lines).toarray() y2 = len(x2)*[0] x = np.concatenate((x1, x2)) y = np.concatenate((y1, y2)) model = GaussianNB() score = cross_val_score(model, x, y, cv=10) print score print "precision:", np.mean(score)*100
程式碼執行的效果如下:
文章還提到了用樸素貝葉斯演算法識別DGA域名(將域名使用2-gram分詞後,得到每個域名在詞集上的分佈向量,然後使用樸素貝葉斯演算法),這個思路還是用得比較多的。另外提到的就是用樸素貝葉斯識別驗證碼(將驗證碼的灰度圖的每一個畫素點的值作為特徵向量的一維,再使用樸素貝葉斯演算法),不過我之前已經用卷積神經網路識別過驗證碼(Caffe的LeNet-5模型上修改),且準確率高達99.996%,一個驗證碼識別比賽的結果,所以就不再展開。