基于访问日志的异常请求检测

1 前言

看了兜哥在freebuf上的专栏文章《学点算法搞安全之HMM(上篇)》,大意就是将URL参数进行范化,然后使用hmm算法来进行训练和测试,这里检测的重点是xss,但是带着我自己的疑问认真看了下方的评论,里面提到一个我非常认同的问题
图片[1]-基于访问日志的异常请求检测-安全小百科
这里原先是对相同url的参数进行数据提取和训练,那么我们知道一个网站,可能会有上千上万的页面,对应上千上万的url,那么按照这样的思路可能就真的需要去建立上千上万的模型,这显然是不现实的。
图片[2]-基于访问日志的异常请求检测-安全小百科
那么我们能否将模型范化,去建立一个模型检测一个业务网站的所有的url以及所有url中的异常参数?带着这样的疑问继续找文章,翻到了先知的《Web日志安全分析浅谈》,其中检测的原理就比较硬核了,通过编写不同的攻击规则来表示不同类型的攻击类型,但是这样会出现一个问题,那就是在真实环境中,你并不知道攻击payload到底长什么样,因此也就可能会造成0day的直接放行和变种payload的绕过。在文末jeary也提出了自己的思考,这也是本文的出发点。当然在文中jeary并没有给出具体方法,因此笔者凭着自己对日志分析的理解开始尝试实现这样一套基于访问日志的异常访问检测。
图片[3]-基于访问日志的异常请求检测-安全小百科
这里我第一个想到的思想就是聚类算法,正常的请求总是相似的,异常请求却各有千秋,那么如果我们能够通过无监督聚类算法来将正常请求给聚类到一块,那么异常请求就会自己凸显出来,打上异常的标签。理论上可行,下面开始实践。

2 数据清洗

这里的数据来源很简单,我从自己的vps上把博客的访问日志给拖下来了,大概是800M,数据量在480万条左右,既然想做的是通用的业务模型检测,那么这里拿博客日志或者电商日志数据,从理论上来说都没有太大的差别,这是因为虽然业务模型不一样,但是每一个业务模型都有一套自己的访问序列,也就是说基于博客日志的聚类可能是这样的分布,但是基于电商日志的聚类可能是那样的分布,本质上来说他们并没有区别,聚类只是为了凸显异常请求,所以对数据集来源上,思路上并没有觉得有什么问题。
先来看下博客的日志数据
图片[4]-基于访问日志的异常请求检测-安全小百科
这里用的国外某家的cdn,ip好像都是美国ip,但是这里是针对url参数进行检测,也没想着做溯源,所以这里ip暂不考虑,重点是url参数,这里一开始心比较大,在检测的模型中加入了访问请求方式(GET/POST)和访问状态码(200/302/404等),后来发现其实这两项其实没有什么必要,这是因为如果是异常请求,比如sql注入、xss等攻击,访问请求方式和状态码并不会改变其异常的本质,也就是说无论是GET还是POST,还是说200状态或者404状态,这个请求是实际存在的异常访问,所以我们只需要将关注的重点放在url请求即可,其中包含url的path和url的param。
图片[5]-基于访问日志的异常请求检测-安全小百科
这里主要是对pandas的第六列数据进行url的解码和解析,获取其中的path和params
图片[6]-基于访问日志的异常请求检测-安全小百科
这里主要是对一些特殊请求,比如“/”或者一些静态页面做处理,对于静态页面一般来说都是无害的,所以说这里将静态页面归为一类,感觉上也没有什么毛病。。最后进入到数据泛化的函数
图片[7]-基于访问日志的异常请求检测-安全小百科
这里有几个泛化规则1)对中文字符统一将其替换为cn;2)统一将数字替换为5;3)统一将特殊字符替换为_。对于中文字符,造成的差异性可能会比较大,比如说不同的中文字符在构建下面的词袋时可能就会造成很大的偏差,所以这里泛化中文字符,第二个就是泛化数字,这里在日常的业务模型上其实是比较常见的,比如说index.php?id=1、index.php?id=123等这样的访问请求,他们其实都是一类的,所以这里最后泛化其实就成了index.php?id=5,在聚类时就会自动聚为一类,特殊字符替换主要是方便统一分词,但是其实是不会影响结果的,虽然部分字符被替换,但是整体字符的顺序仍然是聚类的有效依据。
图片[8]-基于访问日志的异常请求检测-安全小百科
最终清洗下来效果如下,下面开始使用词袋模型将其转化为数组模型。

3 词袋模型

词袋模型兜哥在hmm里曾经使用nltk来构建日志词典,这个模型相对好理解一点,就是说现在比如说出现“alice”、”bob”,那么根据词典的原理,alice可能就是1,bob就是2,那么最终每一组词都能转化为其在词典中的位置。但是我这里使用的tfidf,这是一个根据字词在文中出现的次数和整个语料中出现的文档频率来计算一个字词在整个语料的重要程度。
这里笔者认为用什么算法其实不是很重要,重点在于怎么将泛化的日志数据转化为能够唯一标记的数据向量。那么经过这一步其实所有的url路径和参数就已经能够转化为数组模型。
图片[9]-基于访问日志的异常请求检测-安全小百科

4 无监督聚类

这里无监督聚类用的比较多的一个是kmeans,一个是dbscan。kmeans不太适用于当前场景的原因是kmeans你需要指定簇数,也就是你需要提前知道当面业务模型的url分布数,比如说新闻页面、评论页面、产品页面,那么可能会对应三个簇数,但是在实际环境中,没人能够说得清到底有几个业务功能,所以说这里直接放弃了kmeans,采用dbscan。
dbscan是一个比较有代表性的基于密度的聚类算法。与划分和层次聚类方法不同,它将簇定义为密度相连的点的最大集合,能够把具有足够高密度的区域划分为簇,并可在噪声的空间数据库中发现任意形状的聚类。dbscan的使用实在是太简单,只需要填上eps和minpts参数,即能进行聚类,然后输出聚类标签,一开始看到webber的这篇文章《基于大数据和机器学习的web异常参数检测系统》,他用到了大数据的思想可以做到实时检测,不过其中检测思想并没有涉及多少,针对我在文章开头提出的问题也没有给出具体的解释,,所以继续按照我的思路来做。。(多扯一句,这位大佬好像是我当时阿里实习二面面试官,人很nice!虽然最后挂在三面。。)
这里回到主题,为什么不能做成实时检测?这是由于聚类算法的重点在于对当前数据做分析,并没有对新数据的检测功能,所以这里只能说是基于离线日志,应用场景也就是说只能每天定时跑一遍,检测某个时间段的请求。继续来研究dbscan的参数设置,本文的前提是想做一个针对任意业务模型的异常访问检测,那么参数设置如果能够做成根据业务模型自动化调整,这最好不过了。。接下来就是看论文找方法。。这里找到一篇博士的论文,并根据其算法思想做了实现,应用在这里。这里稍微讲下那两个参数eps和minpts的含义。
eps表示以对象p为中心,以eps为半径的区域内的所有对象,通俗点讲这个参数就是包含数据集D中与对象p距离不大于eps的所有对象。而minpts则表示领域密度阈值,表示对象p的eps领域个数,那么dbscan算法的思想大概就是通过设定领域半径和领域个数来实现一个密度聚类,这里拿中国地图来将,我们知道江浙沪比较小,城市相邻都比较近,那么如果运用dbscan算法来实现中国城市的聚类,很大概率江浙沪可能就会形成一类标签,而像海南,因为是海岛,与相邻城市的距离较远,所以会自成一类标签。
图片[10]-基于访问日志的异常请求检测-安全小百科
这里引入了密度阈值Density参数来定义密度阈值Density为以eps为半径的园内存在minpts个数据点,这里原论文中提到密度阈值太大,可能会导致同簇集合内部被划分为多个集合;密度阈值太小,可能导致不同簇集合之间被合并,论文最后的结论是聚类结果簇数正确的前提下,密度阈值越小则聚类效果越好,因此这里通过比对不同的密度阈值,得到最小密度阈值时的eps参数和minpts参数。这中间还引入了K-平均最近邻算法,,这个就不多说了。。
图片[11]-基于访问日志的异常请求检测-安全小百科
具体代码如上,主要是引入了一个kann,可能有点复杂了。。
图片[12]-基于访问日志的异常请求检测-安全小百科
这里可以看到当K为331时,eps为0.47,minpts为4.92,此时Density参数到达临界点。所以通过这样的计算,我们就能够自动化获得最佳的eps参数和minpts参数。最后我们就能获得分类的总标签数和每一条日志对应的分类标签。
图片[13]-基于访问日志的异常请求检测-安全小百科
这里可以看到一共分成了10个标签,其中feed对应的是标签1,像archives应该对应的是文章查阅,标签为2,所以在上述方法在进行聚类时的确有一定的效果,因为我重点关注的是异常请求,其对应的标签应该是-1,表示这是一个噪声数据,所以下面重点来看看-1标签对应的日志记录
图片[14]-基于访问日志的异常请求检测-安全小百科
看着分明就像是目录爆破页面,当然这里的ip有点问题,如果是实际场景,这类ip可以直接加入ban的列表里,那么针对目录扫描这种恶意行为,使用这种聚类思想是可以检测出来的。
图片[15]-基于访问日志的异常请求检测-安全小百科
这里是比较明显的nikto扫描器页面,也能够检测出来。由于扫描器大多是针对单个页面进行尝试,所以这种在统计分布上具有天然的凸出,检测出来理所当然。。
图片[16]-基于访问日志的异常请求检测-安全小百科
这个应该是顺后门行为和已知的漏洞攻击
图片[17]-基于访问日志的异常请求检测-安全小百科
看到这里仿佛这玩意好像很牛逼,直接替代waf得了,但是现实狠狠打了脸,在实践结果混入了大量的无关页面,这些无关页面一般都有一个比较统一的特征,那就是参数随机化,当遇到像token或者其他一些随机生成的参数时,在聚类时由于参数比较特殊,所以一般都会独成一类,也就是变成噪声数据。
图片[18]-基于访问日志的异常请求检测-安全小百科
上面四条数据将上文结果可以彻底推翻,其中像hid参数还是img参数这种,都是经过服务器随机化生成的,在做数据清洗的时候很难将这类数据单独处理,前文也讲了想做的是一个通用的业务模型检测,这里其实也能解决,用白名单即可解决,但是不够通用,后来就放弃了,其实用白名单的效果真的非常好,如果说报了50条异常,使用白名单将这些随机化参数给过滤掉,最终留下来的可能就只有5条数据了,而这些随机化参数往往的确是无害的,所以这是本文实践第一个比较失败的点。第二个就是上面/archives/tag/iis/feed,按理来说这是一个iis的标签链接,为什么会这种访问请求会被标记为异常呢?回到dbscan的算法思想,一定区域内密度足够大就能够自成一派,那么当某些正常的访问请求,可能的确比较少见,他们的密度不够,也就不能自成一派,这时候也就出现了误报,这种场景其实更常见在后台某些页面,管理员由于只有一个人操作,那么访问的页面数比较有限,所以运用聚类可能效果就会很差,这是第二个我觉得比较难处理的点。(老实讲,针对不同业务模型设立不同的白名单感觉是最直接最好的处理办法了。。)

5 降维可视化

最后用tsne来做了个降维可视化看一看数据分布
图片[19]-基于访问日志的异常请求检测-安全小百科
这里-1其实比较密集,这里推测这类标签可能就是上述随机化参数导致的数据偏移。其他类型的标签就汇聚的比较明显了。。

6 后记

回过头来想一想利用访问请求来做无监督聚类,的确是可以发现潜在的攻击漏洞和扫描器行为的,这点来说一定是有意义的,但是针对那种随机化参数和部分访问量比较少的请求的确可能误报上会比较多,如果能够在数据清洗时针对这类标签做特殊处理,这个基于业务模型的自动化聚类的检测思想可能会发挥更大的作用。
上述如有不当之处,敬请指出~

相关推荐: ysoserial – Clojure分析

0x00 前言 最近一直在研究Java安全,从ysoserial看起,发现Clojure这个Gadget链网上并没有分析文章,所以对这条攻击链进行了简单的分析,动态调试过程中由于计算器一直在弹,所以顺着动态分析的内容静态跟了许久,最后总算把这条攻击链给理顺了。…

© 版权声明
THE END
喜欢就支持一下吧
点赞0
分享
评论 抢沙发

请登录后发表评论