当安全遇上NLP

前言

安全是一门应用科学,安全人员需要不断学习新的技术,解锁新的视角和能力来更好的解决安全问题。目前相对新的技术当属人工智能和区块链技术。大多数技术不可能单独存在,肯定有其应用领域和场景,人工智能技术的几大应用领域有图像、语音、自然语言处理等,众多研究者们在这几大领域不断研究不断产出着新的人工智能技术点。安全人员可以根据这些领域和安全领域的共同点来应用新技术尝试新思路解决安全问题。安全领域的信息大多和图像语音关系不大,如果硬要借鉴图像和语音方面的技术,需要把安全信息映射为图像和语音后再用领域内技术处理,处理流程中安全信息失真比较严重,效果和应用场景都比较局限。安全信息本身可以看成一种机器之间沟通的语言,安全信息处理和自然语言处理有很多相似之处,所以当安全遇到了NLP技术会发生什么呢?

NLP技术的安全实践

首先来了解一下NLP,自然语言处理,是研究计算机处理人类语言的一门技术,包括句法语义分析、信息抽取、文本挖掘、机器翻译、信息检索等。笔者觉着NLP技术中的语言模型在安全领域的应用比较可行。语言模型是对语句概率分布的建模,如果把安全信息,比如一条日志看成一个语句,就可以估算安全日志数据内在的联系和偏好,从而判断日志的属性。语言模型应该可以分为统计语言模型和神经网络语言模型,具体应用在特征工程和算法方面,其中特征工程方面占大多数。笔者认为统计、自然语言处理、神经网络是特征工程技术的"三驾马车“,而NLP的语言模型覆盖到了这三者(统计语言模型也是统计的一种,神经网络语言模型也涵盖了神经网络),这也验证了笔者以前的经历用NLP提取特征训练安全模型效果不错的原因。

统计语言模型

Char-level

之前认为自然语言处理在安全领域的应用有限,因为自然语言处理处理的大多是句子和长文本,而很多安全数据都较短,甚至就是个字符串,后来发现了字符级别的文本处理,问题迎刃而解。char-level这种思想可以用在统计语言模型里,也可以用在神经网络语言模型里,也可以用在神经网络模型,这里暂且归在统计语言模型里,因为笔者最早接触char-level是用来统计向量化。比如在cdxy师傅《LSTM识别恶意HTTP请求》文章中就有char-level这种用法:

tokenizer = Tokenizer(filters='\t\n', char_level=True)
tokenizer.fit_on_texts(X)

特征工程阶段使用字符级技术将HTTP请求的关键字段所对应的值转换成整数序列(每个整数都是词典中标记的索引),

X = tokenizer.texts_to_sequences(X)

然后使用LSTM进行序列建模识别恶意HTTP请求。

model = Sequential()
model.add(Embedding(num_words, 32, input_length=max_log_length))
model.add(Dropout(0.5))
model.add(LSTM(64, recurrent_dropout=0.5))
model.add(Dropout(0.5))
model.add(Dense(1, activation='sigmoid'))
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])

这其中的Embedding层涉及到了之后要说的神经网络语言模型word embedding。总的来说就是char-level+统计向量化+词嵌入+神经网络LSTM。
再比如char-level还有个神经网络例子Char-RNN:字符级循环神经网络。RNN擅长处理序列问题,序列数据前后有很强的关联性。Char-RNN模型是从字符的维度上让机器生成文本,即通过已经观测到的字符出发,预测下一个字符出现的概率,也就是序列数据的推测。RNN属于生成模型,既能用于检测序列,也能生成序列,Char-RNN同理,只是粒度更细。Char-RNN通过生成文本在安全领域的应用可以有Fuzzing、payload生成,比如iami师傅博客中提到的《Fuzzing测试与用例的随机性》。现在利用Char RNN实现写诗写词造句等文本生成的应用很多,在github上找了个生成英文的项目,把数据替换成我们的训练集payloads,分别用DGA域名和恶意URL做训练集payloads。

#训练
python train.py \
  --input_file data/dgaa.txt  \
  --name dga \
  --num_steps 50 \
  --num_seqs 32 \
  --learning_rate 0.01 \
  --max_steps 5000
#生成100个字符
python sample.py \
  --converter_path model/dga/converter.pkl \
  --checkpoint_path model/dga/ \
  --max_length 100

result:生成100个字符

-o.neto
ogeeoooy.eu
uwuyiwe.eu
ywoowou.eu
owuowed.eu
uowouie.eu
uwuowui.eu
ouwgyoo.eu
wgpgyuo.eu
gpyg

result:生成200个字符

<unk>.com
plpqbalioio.comt
bywre.com
npyyya.com
yyytgoa.com
ybyuuuyi.ddns.net
ouwueaudo.info
ouywiuu.info
uuuuuia.eu
oougyii.eu
gwouyou.eu
uwwywwe.info
wooyyee.ddns.net
nuiuuui.ndns.net
niooio.ddns.net
iao

生成1000个字符

ppntrasildeafeninguvuc.com
ptytrasildeafeninguvuc.com
ztnyrasildeafeninguvuc.com
pbtyrasildeafeninguvuc.com
tbgyrasildeafeninguvuc.com
zvyyrasildeafeninguvuc.com
znpyrasildeafeninguvuc.com
tnvvrasildeafeninguvuc.com
tvtprasildeafeninguvuc.com
tpvyeasildeafeninguvuc.com
nbvyrasildeafeninguvuc.com
tttvrasildaafeninguvuc.com
tpnpeasildeafeninguvuc.com
ttptrasildeafeninguvuc.com
vbvveasildeafeninguvuc.com
znvprasildeafeninguvuc.com
ntpvrasildeafeninguvuc.com

尾部都是相同的序列,开始以为有问题,想的是因为生成文本的长序列和训练集中dga域名的短序列的问题,才造成这种固定序列的生成,然后发现rasildeafeninguvuc.com是一个家族固定序列,在训练集中有很多。
生成恶意URL

<unk>script>
"<script>dacument.prossidectink&remexter="alert(1)</svr><a href="javascript:alert('XSS');</div>/script:confirm(')</script>
<avhrataraat confirm(1)" id="tint(1)><inamesonrore="xstend(113);"
/apts.deleseserror.php?script=http://192.168.201.328000000110019933999930191113901103310099900511199199093009053100021320251355301033033511125101305355515052135052525300000513311503300500000123310331105031022132)
/en-us/src/contenks/sriser.inc.php?proroc=XXpathXX?
/contentilesooromon.pl?mossinnid=/etc/passwd\x00
/examples/jsp/checkbox/pore.php?ment=../../../../../../../etc/passwd&nertast=1&set="....\xc0%25.exc/passwd
/examples/jsp/error/comain.php?stuff='\x0puname -n 1,1&rem
/main.php?logout="&rm;q92555225&rem,
/main.php?stuff='&lt\x09>
/examples/jsp/jsp2/jspx/cart_showererearm/esessions/soct/aselettor/cons/showers.php?dit=/etc/passwd\x00
/scripts/sesscripts/dispoller.php?module=../etc/passwd\x00
/main.php?logout="'del;q57391279&rem;
/javascript/charsidi/phpmodit.cgi?lase=/etc/passwd\x00
/ma

好像有那么点意思,但是用作实际payloads怕是不太行,用作fuzzing的话可能还行。当黑样本相对少的情况下,可以用来生成黑样本。

N-gram

n-gram的基本思想是将文本的内容按照字节进行大小为N的滑动窗口操作,形成长度是N的字节片段序列。相较于直接对文本进行统计词频的词袋方法和TF-IDF方法,笔者觉得n-gram带有了一点语法语意的意思,所以一般都是词袋模型与TF-IDF和n-gram结合在一起使用。

Bag of Words

词袋是一种统计某个词在一份文档中出现次数的算法,统计的词频数可以作为向量。

TF-IDF

TF-IDF(term frequency-Inverse document frequency),词频-逆文档频率,加入逆文档频率一定程度上弥补了单纯词频方法的不足。
Sklearn中有实现bag of words和tfidf方法的类:CountVectorizer和TfidfVectorizer,这两个类支持n-gram和char-level。
比如七雨师傅文章《基于机器学习的web异常检测》基于单分类的模型就是综合利用char-level+n-gram+词频来特征向量化,再用one-class svm建立单类去判断恶意url,还有一篇比较老的文章《Fwaf-Machine-Learning-driven-Web-Application-Firewall》也是用了类似的char-level+n-gram+tfidf方法来向量化,再用逻辑回归去检测恶意url。

vectorizer = TfidfVectorizer(min_df = 0.0, analyzer="char", sublinear_tf=True, ngram_range=(1,3)) #converting data to vectors

X = vectorizer.fit_transform(queries)

总的来说这char-level/word-level+n-gram+tfidf一把梭下来,可以解决很多问题了,包括较长文本和短文本,而安全中的很多关键信息都可以看成是长文本和短文本,比如域名请求,恶意代码,恶意文件。

神经网络语言模型

之前一直觉得神经网络不太友好,认为统计+自然语言处理中的统计语言模型+传统机器学习算法就可以很好地解决问题了,后来发现统计并不是万能的,神经网络能发挥的作用也很大,地方也很多,神经网络语言模型可以用来得到特征向量化中的词嵌入向量和做分类中的文本分类,神经网络算法也可以用来做分类等。神经网络训练语言模型中一个关键的点是word embedding(词嵌入,词的分布式表示),基于神经网络语言模型的word embedding(为什么不是基于word embedding的神经网络语言模型,这是因为word embedding是神经网络训练语言模型的副产品),相较于统计语言模型,相较于n-gram僵硬地体现语义,word embedding更好地表达了语义,因为词的分布式表示这类方法都基于分布假设:词的语义由上下文决定,方法核心是上下文的表示以及上下文与目标词之间的关系的建模。举个例子,这个可爱的 泰迪 舔了我的脸这个可爱的 京巴 舔了我的脸,用统计语言模型向量化,是两个不同的向量,是两个不同的句子,而神经网络语言模型根据上下文就会认为'泰迪'和'京巴'是同义词,从而判断这两个句子相似,产出的词嵌入向量也会相似。
word embedding是一种概念,几个比较有名的word embedding方法包括:word2vec (Google), GloVe, FastText (Facebook),这些都是word embedding的实现手段。

word2vec

webber师傅的文章《使用深度学习检测XSS》中使用了word2vec对已分词的文本进行向量化操作,又结合了LSTM、RNN、CNN三种算法检测XSS,对比SVM具有相对更好的泛化能力,说明神经网络算法较传统算法效果更佳,这可能是因为神经网络处理自然语言时可以识别词位置和词与词之间的关系(词的位置可以理解,词与词之间的关系不大懂,word2vec在向量化的时候不是已经解决了词与词之间关系的问题了吗,神经网络相较于SVM作为分类算法,应该只有词位置识别方面的提升吧)。

model=Word2Vec(data_set,size=embedding_size,window=skip_window,negative=num_sampled,iter=num_iter)
embeddings=model.wv
embeddings['0']

array([ 0.06356055, -0.19921948,  0.3356784 ,  0.15330128,  0.31883803,
       -0.6977568 ,  0.13472763, -0.39462927, -0.02651692,  0.97309947,
        1.0602285 , -0.07370728, -0.7246065 ,  0.06775752,  1.109377  ,
       -0.34577966,  0.42254186, -0.13481887, -0.24872543,  0.9183436 ,
       -1.4428607 , -0.10109176,  0.7711238 ,  0.67028177,  0.5955905 ,
       -0.18963751,  0.4201649 , -0.5992032 , -0.7136238 , -0.73436624,
       -0.3201587 ,  0.03583186, -0.68885845,  0.6004483 ,  0.4784428 ,
       -0.5739937 , -0.5768896 ,  0.6175184 , -0.3029108 ,  0.01734808,
        0.04042359,  0.76293707,  0.52277046,  0.4090956 ,  0.47357482,
       -0.5972618 ,  0.6259779 , -0.4994182 , -0.7634801 ,  1.6244601 ,
       -0.44355297,  0.7109609 ,  0.9468291 ,  0.2866395 ,  0.25637504,
       -0.53924143, -1.0911181 ,  0.4528728 , -0.43621692, -0.17867813,
       -1.0109166 , -0.44911763, -0.27320656,  0.23866493,  0.15664867,
        0.6409447 , -0.23423721, -0.1837575 ,  0.12108286,  0.11966047,
       -0.1325919 , -0.17609857,  1.1720567 , -0.50236636, -0.6033684 ,
       -0.71848387, -0.03429153, -1.2958349 , -0.93953687, -0.1944222 ,
       -0.32847854, -0.30283213,  0.7113749 , -0.7551358 ,  0.57266515,
        0.137828  ,  0.26785246,  0.51493126,  0.31305224,  0.40927702,
        0.11831629, -0.64689773,  0.15885882, -1.0438223 ,  0.19861834,
       -0.71079874,  0.02020928, -1.2383761 , -0.5699059 ,  0.6994687 ,
        0.4998379 ,  0.23062779,  0.68073547,  0.5560602 , -0.30087334,
        0.65758115,  0.06739169,  0.5384448 ,  0.29031464,  0.44346014,
       -0.53719974, -1.0638485 , -0.84434575, -0.0850719 ,  0.63114655,
        0.13165227, -1.0634255 ,  0.19242877, -0.02073849, -0.07671507,
       -0.21831703, -0.45622998, -0.163901  , -0.21681851, -0.23947589,
       -0.64384156, -0.41555977,  0.39319035], dtype=float32)

fastText

fastText和word2vec都可以无监督学习词向量,fastText功能更强,不仅加入了字符级n-gram作为特征,还可以直接有监督学习进行文本分类,正如iami师傅的文章《使用fasttext进行DGA检测》

./fasttext supervised -input ./demo/data.train  -output dga.model
./fasttext test dga.model.bin test.valid 1

TextCNN

TextCNN是利用卷积神经网络对文本进行分类的算法,适合做一些长文本分类,又想到了第三届阿里云安全算法第一名队伍就是利用了TextCNN算法对API长序列进行建模。单独的TextCNN在安全方面的应用感觉还比较局限。

总结

本文主要介绍了各种算法的功能以及在安全方面的应用,缺少对算法的原理和结构的介绍,也缺少对各种算法之间的横向对比,比如在特征工程阶段,使用神经网络语言模型提取的词嵌入向量特征和统计语言模型提取的统计特征的对比(猜测神经语言模型效果会更好);在分类算法阶段,使用神经网络算法和使用传统算法的对比(猜测神经网络算法效果会更好)。笔者认为NLP是一种联系安全的媒介,仅从算法角度考虑,把NLP处理的越好,安全上也会处理的更好。从安全人员的角度来看,算法是一种工具和手段,当个"调包侠”和“调参怪”已经够用,重点还得从安全本身出发,深入理解攻击行为模式和数据。

Ref

标签: none

添加新评论