我的日志分析之道:简单的Web日志分析脚本

来源:互联网 发布:奥尼尔数据统计 编辑:程序博客网 时间:2024/06/11 06:25

原创作者:北风飘然@金乌网络安全实验室,本文属FreeBuf原创奖励计划,未经许可禁止转载    

前言

长话短说,事情的起因是这样的,由于工作原因需要分析网站日志,服务器是windows,iis日志,在网上找了找,github找了找,居然没找到,看来只有自己动手丰衣足食。

那么分析方法我大致可分为三种:

1. 基于时间:将请求url按时间段分类,那么我们根据每个时间段的url数量及攻击数量就可以大致判断出哪个时间段有apt类型攻击,哪个时间段是扫描器行为;

2. 基于攻击ip:正常的攻击肯定会有请求被记录(当然你要是有0day当我没说,正常的探测总会有吧=。=!),然后每个ip去分析;

3. 基于访问请求的状态码,也大致可以判断出行为。

规则可以基于开源waf规则,分析扫描器写正则也可以,开源waf地址是

https://github.com/loveshell/ngx_lua_waf/tree/master/wafconf。

扫描器正则https://github.com/smarttang/w3a_SOCD的database里面有详细地址

https://github.com/smarttang/w3a_SOC/tree/master/db_sql。

Sql语句里面有想把它做的功能全一些,但是学python学习时间也不是很长,写出来的代码也没有pythonic,会慢慢写的。目前分三个模块,一个日志归类模块命名为url.py,攻击分析模块attac.py, ip地理位置查询模块ipfind.py,还有一个主函数。

日志归类模块url.py

import reimport osimport sysfrom datetime import datetimedt = datetime.now()date = str(dt.date())loglist = []   #   iplist = []    #   ip统计urllist = []   #    url统计列表needlist = []   #    需要统计的errorlist = []   #    格式错误的列表ipdict,urldict = {},{}  rizhi = str(input('请输入要分析的日志文件名'))def find_log():    print('>>>>>>>开始解析日志')    with open(rizhi,'r',encoding='UTF-8',errors='ignore') as f:        #loglist = f.readlines()        for i in f.readlines():   #            if i[0] != '#':                b = re.split(' ',i)                iplist.append(b[10])                urllist.append(b[6])                try:                    needlist.append([b[10],b[1],b[5],b[6],b[15]])                except:                    errorlist.append(i)    print('>>>>>>>日志解析完毕')def count(iplist,urllist):    #统计ip url访问量函数    print('>>>>>>>开始分析urlip访问量')    global ipdict,urldict    for i in set(iplist):        ipdict[i] = iplist.count(i)    for i in set(urllist):        urldict[i] = urllist.count(i)    ipdict = sorted(ipdict.items(),key=lambda d: d[1], reverse=True)        urldict = sorted(urldict.items(),key=lambda d: d[1], reverse=True)    print(type(urldict))    iplist = list(ipdict)    urllist = list(urldict)    ipdict,urldict = {},{}    print('>>>>>urlip分析完毕.......')    return [iplist,urllist]def save_count():    print('>>>>>>>正在保存分析结果')    ipname = 'ip-'+date+'.txt'    urlname = 'url-'+date+'.txt'    with open(ipname,'w') as f:        for i in iplist:            f.write(str(list(i))+'\n')    with open(urlname,'w') as f:        for i in urllist:            f.write(str(list(i))+'\n')    print('>>>>>>>分析结果保存完毕')find_log()[iplist,urllist] = count(iplist,urllist)save_count()

iis日志和apache日志觉得都差不多,就是切割时候改一下就行了。

配图1.png

Iis日志大概是这样的,用pythonreadlines然后切割出来就好了。

这个url.py我加了个功能把ip访问量及url访问量排序输出出来所以有点慢,=.=没办法野路子哪里会什么算法。将地址,时间,ip,状态码都扔进一个列表里就行了。

攻击分析模块attack.py

import osimport sysimport urlsqllist,xsslist,senlist = [],[],[]otherurl,xssip,sqlip,senip = [],[],[],[]feifa = [] def find_attack(needlist):    print('>>>>>>>开始检测攻击')    sql = r'product.php|preg_\w+|execute|echo|print|print_r|var_dump|(fp)open|^eval$|file_get_contents|include|require|require_once|shell_exec|phpinfo|system|passthru|\(?:define|base64_decode\(|group\s+by.+\(|%20or%20|%20and%20|sleep|delay|nvarchar|exec|union|^select$|version|insert|information_schema|chr\(|concat|%bf|sleep\((\s*)(\d*)(\s*)\)|current|having|database'    xss = r'alert|^script$|<|>|%3E|%3c|&#x3E|\u003c|\u003e|&#x'    sen = r'\.{2,}|%2e{2,}|%252e{2,}|%uff0e{2,}0x2e{2,}|\./|\{FILE\}|%00+|json|\.shtml|\.pl|\.sh|\.do|\.action|zabbix|phpinfo|/var/|/opt/|/local/|/etc|/apache/|\.log|invest\b|\.xml|apple-touch-icon-152x152|\.zip|\.rar|\.asp\b|\.php|\.bak|\.tar\.gz|\bphpmyadmin\b|admin|\.exe|\.7z|\.zip|\battachments\b|\bupimg\b|uploadfiles|templets|template|data\b|forumdata|includes|cache|jmxinvokerservlet|vhost|bbs|host|wwwroot|\bsite\b|root|hytop|flashfxp|bak|old|mdb|sql|backup|^java$|class'        for i in needlist:        if i[2] == 'POST' or i[2] == 'HEAD' or i[2] == 'GET':            response = re.findall(sql,i[3],re.I)            if response == []:                responsexss = re.findall(xss,i[3],re.I)                if responsexss == []:                    responsesen = re.findall(sen,i[3],re.I)                    if responsesen == []:                        otherurl.append(i)                    else:                        senlist.append(i)                        senip.append(i[0])                        print(responsesen)                        print('检测出敏感目录扫描')                        print(i)                else:                    xsslist.append(i)                    xssip.append(i[0])                    print(responsexss)                    print('检测出xss攻击')                    print(i)            else:                sqllist.append(i)                sqlip.append(i[0])                print(responsexss)                print('检测出sql攻击')                print(i)        else:            feifa.append(i[0])    print('非法请求:'+str(len(feifa))+''+str(len(list(set(feifa))))+'ip')    print('>>>>>>>攻击检测完毕')    return [xssip,sqlip,senip,sqllist,xsslist,senlist,otherurl]这个就简单多了,基于正则分析的正则不是很完善,还有好多是根据自己公司情况来定,大牛轻喷,检索完毕返回ipurl

IP地理位置查询模块ipfind.py

Ipfind.py是查找ip地理位置的

import reimport urllib.requestdef url_open(ip):    url = 'http://www.ip138.com/ips138.asp?ip='+ip    response = urllib.request.urlopen(url)    html = response.read().decode('gb2312')    return htmldef find_ip(html):    a = r'本站数据.{20,}</li>'    p = re.compile(a,re.I)    response = re.findall(p,html)    for i in response:        b = i    response = re.split(r'</li><li>',b)    ipaddrs = str(response[0][5:])+','+str(response[1][6:])+','+str(response[2][6:-5])    return ipaddrsdef find_ipaddrs(ip):        html = url_open(ip)    ipaddrs = find_ip(html)    print(ip+' : '+ipaddrs)    这个简单我是直接像爬虫那样写的,用ip138的网址(接口没有找到,百度注册了好几次都不成功,有api的可以用api)

主函数

主函数main.py

import reimport osimport sysfrom datetime import datetimeimport urlimport attackimport ipfindneedlist = url.needlistsqllist,xsslist,senlist = [],[],[]otherurl,iplist = [],[][xssip,sqlip,senip,sqllist,xsslist,senlist,otherurl]=attack.find_attack(needlist)xssip = list(set(xssip))sqlip = list(set(sqlip))senip = list(set(senip))print('>>>>>>>检测出xss攻击'+str(len(xsslist))+''+'共计'+str(len(xssip))+'ip')print(xssip)print('>>>>>>>检测出sql攻击'+str(len(sqllist))+''+'共计'+str(len(sqlip))+'ip')print(sqlip)print('>>>>>>>检测出敏感目录扫描'+str(len(senlist))+''+'共计'+str(len(senip))+'ip')print(senip)iplist = list(set(xssip+sqlip+senip))print(len(iplist))print('开始分析ip地理位置')for i in iplist:    ipfind.find_ipaddrs(str(i))

要分析什么就把需要分析的和main.py放在一个目录下就行了

总结 

脚本大概说了一遍,说说不足及怎么分析吧。

现实不足:看了差不多有3个月日志了吧,先说一个最严重的问题,post请求data看不见,本身日志就看不到data,何况等到https普及了日志什么样也不知道,要是有能力最好做成和waf联动那样的。还有就是未知威胁从waf来看基于正则,基于关键词有很多都是能绕过的,但是有攻击行为没删日志的话,肯定是会留下攻击痕迹的,这样可以从检测出来的ip来看具体攻击的url,而未知威胁则不同了,就好比一个0day,攻击waf没用了,日志分析看不出来了,那么只能依靠应急响应以及服务器的报警了。

还有好多攻击类型没有加入到里面,后期打算把判断攻击类型写成函数,拿if,else判断,类型少还可以,类型多了感觉很容易乱,还有user-agent的收集与判断(虽然大多数扫描器都能改user-agent)。

具体分析:我都是用脚本跑一遍,然后按ip来看会比较方便些,而这里缺少机器识别,我单独写了一个简易的机器识别的东西,其实要实现很简单,把全部日志按时间,url,ip扔进一个列表里统计一下相同时间相同ip的就可以了。我写的是识别短信轰炸的,后期还会渐渐的完善,如果有能力就把它结合django来弄成图形化,毕竟脚本始终是脚本,终究听着不好听。

效果如下

配图2.png

具体规则有待完善。

原创作者:北风飘然@金乌网络安全实验室,本文属FreeBuf原创奖励计划,未经许可禁止转载  

发表评论

已有 24 条评论

  • 乔不死  2017-02-14回复1楼

    不错不错

    亮了(0)
  • 攻城狮  2017-02-14回复2楼

    正在找这类日志分析的工具,感谢楼主的分享。

    亮了(4)
  • taylorwin (5级) 2017-02-14 回复3楼

    把文件 打包一下就更完美了

    亮了(0)
    • pine (1级) 2017-02-14 回复

      @ taylorwin  我给上传到 http://www.cuijianxiong.com/iis.zip 这里了 要是想改成exe 用pyinstaller -F main.py打包一下 但是main.py中的 if __name__==’__main__’ 下面需要改一下 不然程序跑完了 在cmd上就退出了

      亮了(0)
      • taylorwin (5级) 2017-02-14 回复

        @ pine  谢谢

        亮了(0)
  • n0nbeing (1级) 关注信息安全行业发展、产品、创业、投融资 2017-02-14 回复4楼

    不错,有研究精神

    亮了(1)
  • 戒贤 (4级) 一只混迹在安全圈子边缘的调酒师 2017-02-14 回复5楼

    三年前我自己搭的一套ELK今天还在用,分析IIS,Apache,Nginx日志(post数据在nginx的request_body字段)不在话下,最近又加了Squid日志的分析。
    轮子是个好轮子,简单明了,基本的功能算是有了。

    亮了(1)
    • pine (1级) 2017-02-14 回复

      @ 戒贤  请问下iis日志在哪看? 没有post中的data数据 缺失了很大一部分能够发现的攻击行为 兄弟能留个联系方式么

      亮了(0)
      • 戒贤 (4级) 一只混迹在安全圈子边缘的调酒师 2017-02-14 回复

        @ pine  iis记录post数据的案例我还没见过,绝大部分都是在nginx上实现的,更自由一些。

        亮了(0)
  • 痛恨半月板  2017-02-14回复6楼

    转发微博

    亮了(0)
  • an_time (1级) 2017-02-14 回复7楼

    这个不错,很实用

    亮了(0)
  • caish2007 (1级) 2017-02-14 回复8楼

    大家都不是专门搞开发的,能用就行了。
    思路还是很清晰易懂。

    亮了(0)
  • shadowblade (1级) 2017-02-14 回复9楼

    模块化以后还能再加功能还是不错的

    亮了(0)
    • pine (1级) 2017-02-15 回复

      @ shadowblade  太过奖了== 自己觉得还是不是那么好

      亮了(0)
  • asd  2017-02-14回复10楼

    如果有一个post注入,怎么判断人家拖没拖库,好多网站日志都只能看到POST请求的是哪个文件,不能看到post发的数据

    亮了(1)
    • pine (1级) 2017-02-15 回复

      @ asd 我也疑惑其实 不过楼上说了绝大部分都是在nginx上实现的 这个只能看请求方式和相应的状态码来看了

      亮了(0)
    • evil7 (4级) 入梦落樱满熏香,梦醒犹记四月谎 2017-02-15 回复

      @ asd 可以在数据查询的接口写个对每次接受的post参数值进行记录,拖库出现的语句会有规律模型的,一般是按索引值逐步遍历,或者盲注按字节逐步遍历,并且都是固定型。那么分析post过来的参数,去掉干扰值,接收到的模型框架,相似度超过80%的,不是参数遍历进行爆破就是在绕过语句进行拖库。

      亮了(0)
      • pine (1级) 2017-02-15 回复

        @ evil7  这个方法nice啊 相当于变相搞个数据库审计了

        亮了(0)
  • softbug (7级) 四川建设网安全工程师 2017-02-14 回复11楼

    有潜力,比splunk好! 那玩意贼贵!要的东西都要自己动手才好。

    亮了(0)
    • pine (1级) 2017-02-15 回复

      @ softbug  感谢夸奖了 没有没有 其实好多想实现的功能没写呢 正则还不全==

      亮了(0)
  • 墨霝 (2级) 2017-02-15 回复12楼

    谢谢师傅大佬分享!测试ing

    亮了(0)
  • 千秋丶千年 (4级) 2017-02-15 回复13楼

    数字公司的星图还是很不错的

    亮了(0)
  • daliang  2017-02-15回复14楼

    有时候会有1个文件几个g的日志,不知道python的日志分析工具分析起来效率怎么样。

    亮了(0)
    • pine (1级) 2017-02-15 回复

      @ daliang 没试过啊 不知道太大会不会内存溢出了

0 0