Apache的log日志分析(脚本编写思路)

作者: shiyan 分类: 脚本编写 发布时间: 2017-11-16 06:24

0x01

关于日志分析这个主要是用于溯源,追查黑客的时候用的比较多,其实对于大公司来说,WAF的日志不光能抵御进攻,还能通过分析日志获取到一些不可多得的 0day 。

而对于像我这样的小个体来说,更多是查看攻击来源和攻击所发动的 payload ,当然日志分析还能收集一些扫描器的 payload ,比如用一个扫描器去扫自己的服务器站点,然后通过查看日志分析,整理收集 payload ,方便自己使用。

0x02

通常关于日志分析这个,大部分都是用正则的方式来收集自己想要的,所以第一步肯定是分析下服务器日志的格式,这里我用的 Apache 服务器,下面是 access.log 的部分内容。

127.0.0.1 - - [31/Jul/2017:16:34:41 +0800] "GET /sqli-labs-master/Less-2/index.php-pid=1 HTTP/1.1" 404 1054 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:46.0) Gecko/20100101 Firefox/46.0"
127.0.0.1 - - [31/Jul/2017:16:34:42 +0800] "GET /sqli-labs-master/Less-2/index.php-pid=1 HTTP/1.1" 404 1054 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:46.0) Gecko/20100101 Firefox/46.0'&&(sleep(((select 0x552a) regexp 0x5e5b202d7e5d)*1))&&'6'='6"
127.0.0.1 - - [31/Jul/2017:16:35:20 +0800] "GET /sqli-labs-master/Less-2/index.php?id=1-p'&&extractvalue(1,concat%20(0x3a6c75616e3a,(select%200x552a),0x3a6c75616e3a))&&'6'='6 HTTP/1.1" 200 827 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:46.0) Gecko/20100101 Firefox/46.0"

通过分析,我看出来,分别由访问者IP、访问时间、请求的方式、请求的URL、HTTP协议、状态码、数据包大小、访问的浏览器信息和操作系统。而我主要关注访问者IP,请求时间还有请求的URL,
然后用先用正则匹配下这三个部分,方便接下来用上。

IP = r'(\d*.\d*.\d*.\d*) -'
times = r'- \[(.*)\] "'
gjurl = r'"GET(.*)HTTP/1.1"'

关于正则,我在我的知乎上有总结:https://zhuanlan.zhihu.com/p/27045156

0x03

写好需要正则匹配的内容后,剩下的就是小脚本的功能扩展了。

首先,我们先读取log日志里的内容,然后过滤出状态码是200的,最后把出现攻击的日志给显示出来。思路就是这个思路,当然为了不局限于单个脚本,我最后是用类的方法写,然后等需要添加其它功能的时候,直接添加就行了。

0x04

先创建一个读取文件的函数:

def file():
    global du_log
    log = open('access.log','r')
    du_log = log.readlines()
    log.close()

设置全局变 du_log 是方便另一个函数能顺利读取,这里用的 readlines() 是因为它会把读取的内容按行的形式,添加到一个数组里,正好方便我们遍历。

0x05

再写个获取日志中状态码是200的日志函数:

def state200():
    global state_two
    state_two = []
    for i in du_log:
        zz200 = r'HTTP/1.1" 200'
        cz200 = re.findall(zz200,i)
        if cz200:
            state_two.append(i)
        else:
            pass

这里同样的把获取到的状态码为200的添加一个空的列表中,方便我们使用。如果需要其它状态码也是完全可以把上面的正则匹配的改成其它状态码,再创个新的函数,方便调用。

0x06

额,由于正则匹配出来的都是在列表里面,我为了显示好看就又创了一个遍历函数,专门把列表里的内容遍历出来,,,纯粹图好看把。

def for_xh(xh):
    for i in xh:
        return i

其实杂说了吧,函数就是为了便利而存在的,当一个动作重复了好几遍,就可以用函数来代替这个动作。

0x07

那最后一步就是我们的关键函数了,把我们需要的展示的内容在页面上给显示出来,下面是代码:

def analysis():
    IP = r'(\d*.\d*.\d*.\d*) -'
    times = r'- \[(.*)\] "'
    gjurl = r'"GET(.*)HTTP/1.1"'
    for i in state_two:
        log_gj = re.findall(Features, i, re.I)
        if log_gj:
            gj_IP = re.findall(IP, i)
            gj_time = re.findall(times, i)
            gj_url = re.findall(gjurl, i)
            time.sleep(1)
            print '- - - - - - - - - - - - - - - - - - - - - - - - - -'
            print '攻击者IP:  ', for_xh(gj_IP)
            print '攻击时间:  ', for_xh(gj_time)
            print '攻击特征: ', for_xh(gj_url)
            # print '- - - - - - - - - - - - - - - - - - - - - - - - - -'
        else:
            pass

按照我们一开始的想法,把日志的内容取出来,然后再单独取出来状态码为200的,最后,显示出我们想要的。每个过程都是一个小函数,可以来调用。

如果是面向过程的写,基本这个小脚本就结束了,但是如果以后再添加需求的话,肯定很麻烦,还容易忘记需要调用哪些函数,所以我这里直接改写成类的写法。

0x08

完整代码:

# coding:utf-8

import re
import time
logo = '''
          _         _      _  _                  
   ___   | |_      (_)    | || |  __ _    _ _    
  (_-<   | ' \     | |     \_, | / _` |  | ' \   
  /__/_  |_||_|   _|_|_   _|__/  \__,_|  |_||_|  
_|"""""|_|"""""|_|"""""|_| """"|_|"""""|_|"""""| 
"`-0-0-'"`-0-0-'"`-0-0-'"`-0-0-'"`-0-0-'"`-0-0-' 

   Code By shiyan     Blog: sh1yan.top
   
'''
class Log_analysis(object):

    def __init__(self,Route,Features):
        self.Route = Route
        self.Features = Features

    def file(self):
        global du_log
        log = open(self.Route,'r')
        du_log = log.readlines()
        log.close()

    def state200(self):
        global state_two
        state_two = []
        for i in du_log:
            zz200 = r'HTTP/1.1" 200'
            cz200 = re.findall(zz200,i)
            if cz200:
                state_two.append(i)
            else:
                pass

    def for_xh(self,xh):
        for i in xh:
            return i

    def analysis(self):
        IP = r'(\d*.\d*.\d*.\d*) -'
        times = r'- \[(.*)\] "'
        gjurl = r'"GET(.*)HTTP/1.1"'
        for i in state_two:
            log_gj = re.findall(self.Features, i, re.I)
            if log_gj:
                gj_IP = re.findall(IP, i)
                gj_time = re.findall(times, i)
                gj_url = re.findall(gjurl, i)
                time.sleep(1)
                print '- - - - - - - - - - - - - - - - - - - - - - - - - -'
                print u'攻击者IP:  ', self.for_xh(gj_IP)
                print u'攻击时间:  ', self.for_xh(gj_time)
                print u'攻击特征: ', self.for_xh(gj_url)
                # print '- - - - - - - - - - - - - - - - - - - - - - - - - -'
            else:
                pass

sql = r'select'
xss = r'script'

if __name__ == '__main__':

    print logo
    rzfx = Log_analysis('G://access.log',sql)
    rzfx.file()
    rzfx.state200()
    rzfx.analysis()

运行显示的结果:

- - - - - - - - - - - - - - - - - - - - - - - - - -
攻击者IP:   127.0.0.1
攻击时间:   31/Jul/2017:16:35:20 +0800
攻击特征:   /sqli-labs-master/Less-2/index.php?id=1-p'&&extractvalue(1,concat%20(0x3a6c75616e3a,(select%200x552a),0x3a6c75616e3a))&&'6'='6
- - - - - - - - - - - - - - - - - - - - - - - - - -
攻击者IP:   127.0.0.1
攻击时间:   31/Jul/2017:16:35:21 +0800
攻击特征:   /sqli-labs-master/Less-2/index.php?id=1-p'&&exp(~(select%20*%20from(select%20concat%20(0x3a6c75616e3a,(select%200x552a),0x3a6c75616e3a))a))&&'6'='6
- - - - - - - - - - - - - - - - - - - - - - - - - -
攻击者IP:   127.0.0.1
攻击时间:   31/Jul/2017:16:35:22 +0800
攻击特征:   /sqli-labs-master/Less-2/index.php?id=1-p'&&linestring((select%20*%20from(select%20*%20from(select%20concat%20(0x3a6c75616e3a,(select%200x552a),0x3a6c75616e3a))a)b))&&'6'='6
- - - - - - - - - - - - - - - - - - - - - - - - - -

0x09

关于Apache的日志分析的小脚本就这样没了,如果有新的需求可以直接在里面添加新的功能,然后去调用就行。不过如果直接用上面的代码还是建议在 pycharm 这个 IDE 中运行然后去分析日志中存在的问题点,还能根据实际情形改改正则,匹配需要的东西,最方便的还是可以暂停。#(滑稽笑….)

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!

发表评论

电子邮件地址不会被公开。 必填项已用*标注