我的日志分析之道:簡單的Web日志分析腳本

msoc0751 8年前發布 | 13K 次閱讀 日志分析 數據庫 Python開發

前言

長話短說,事情的起因是這樣的,由于工作原因需要分析網站日志,服務器是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 re
import os
import sys
from datetime import datetime

dt = datetime.now()

date = str(dt.date())

loglist = [] # iplist = [] # ip統計 urllist = [] # url統計列表 needlist = [] # 需要統計的 errorlist = [] # 格式錯誤的列表 ipdict,urldict = {},{}

rizhi = str(input('請輸入要分析的日志文件名'))

def find_log():

print(<strong>'>>>>>>></strong><strong>開始解析日志'</strong>)

<strong>with </strong>open(rizhi,<strong>'r'</strong>,encoding=<strong>'UTF-8'</strong>,errors=<strong>'ignore'</strong>) <strong>as </strong>f:

    <em>#loglist = f.readlines() </em><strong>for </strong>i <strong>in </strong>f.readlines():   <em># </em><strong>if </strong>i[0] != <strong>'#'</strong>:

            b = re.split(<strong>' '</strong>,i)

            iplist.append(b[10])

            urllist.append(b[6])

            <strong>try</strong>:

                needlist.append([b[10],b[1],b[5],b[6],b[15]])

            <strong>except</strong>:

                errorlist.append(i)

print(<strong>'>>>>>>></strong><strong>日志解析完畢'</strong>)

def count(iplist,urllist): #統計ip url訪問量函數 print('>>>>>>>開始分析url與ip訪問量')

<strong>global </strong>ipdict,urldict

<strong>for </strong>i <strong>in </strong>set(iplist):

    ipdict[i] = iplist.count(i)

<strong>for </strong>i <strong>in </strong>set(urllist):

    urldict[i] = urllist.count(i)


ipdict = sorted(ipdict.items(),key=<strong>lambda </strong>d: d[1], reverse=<strong>True</strong>)    

urldict = sorted(urldict.items(),key=<strong>lambda </strong>d: d[1], reverse=<strong>True</strong>)

print(type(urldict))

iplist = list(ipdict)

urllist = list(urldict)

ipdict,urldict = {},{}

print(<strong>'>>>>>url</strong><strong>與ip分析完畢.......'</strong>)


<strong>return </strong>[iplist,urllist]

def save_count():

print(<strong>'>>>>>>></strong><strong>正在保存分析結果'</strong>)

ipname = <strong>'ip-'</strong>+date+<strong>'.txt' </strong>urlname = <strong>'url-'</strong>+date+<strong>'.txt' </strong><strong>with </strong>open(ipname,<strong>'w'</strong>) <strong>as </strong>f:

    <strong>for </strong>i <strong>in </strong>iplist:

        f.write(str(list(i))+<strong>'</strong><strong>\n</strong><strong>'</strong>)

<strong>with </strong>open(urlname,<strong>'w'</strong>) <strong>as </strong>f:

    <strong>for </strong>i <strong>in </strong>urllist:

        f.write(str(list(i))+<strong>'</strong><strong>\n</strong><strong>'</strong>)

print(<strong>'>>>>>>></strong><strong>分析結果保存完畢'</strong>)

find_log()

[iplist,urllist] = count(iplist,urllist)

save_count()</code></pre>

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

Iis日志大概是這樣的,用pythonreadlines然后切割出來就好了。

這個url.py我加了個功能把ip訪問量及url訪問量排序輸出出來所以有點慢,=.=沒辦法野路子哪里會什么算法。將地址,時間,ip,狀態碼都扔進一個列表里就行了。

攻擊分析模塊attack.py

import os
import sys
import url

sqllist,xsslist,senlist = [],[],[]

otherurl,xssip,sqlip,senip = [],[],[],[]

feifa = [] def find_attack(needlist):

print(<strong>'>>>>>>></strong><strong>開始檢測攻擊'</strong>)

sql = <strong>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' </strong>xss = <strong>r'alert|^script$|<|>|%3E|%3c|>|\u003c|\u003e|&#x' </strong>sen = <strong>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' </strong><strong>for </strong>i <strong>in </strong>needlist:

    <strong>if </strong>i[2] == <strong>'POST' </strong><strong>or </strong>i[2] == <strong>'HEAD' </strong><strong>or </strong>i[2] == <strong>'GET'</strong>:

        response = re.findall(sql,i[3],re.I)

        <strong>if </strong>response == []:

            responsexss = re.findall(xss,i[3],re.I)

            <strong>if </strong>responsexss == []:

                responsesen = re.findall(sen,i[3],re.I)

                <strong>if </strong>responsesen == []:

                    otherurl.append(i)

                <strong>else</strong>:

                    senlist.append(i)

                    senip.append(i[0])

                    print(responsesen)

                    print(<strong>'</strong><strong>檢測出敏感目錄掃描'</strong>)

                    print(i)

            <strong>else</strong>:

                xsslist.append(i)

                xssip.append(i[0])

                print(responsexss)

                print(<strong>'</strong><strong>檢測出xss攻擊'</strong>)

                print(i)

        <strong>else</strong>:

            sqllist.append(i)

            sqlip.append(i[0])

            print(responsexss)

            print(<strong>'</strong><strong>檢測出sql攻擊'</strong>)

            print(i)

    <strong>else</strong>:

        feifa.append(i[0])

print(<strong>'</strong><strong>非法請求:'</strong>+str(len(feifa))+<strong>'</strong><strong>次'</strong>+str(len(list(set(feifa))))+<strong>'</strong><strong>個ip'</strong>)

print(<strong>'>>>>>>></strong><strong>攻擊檢測完畢'</strong>)

<strong>return </strong>[xssip,sqlip,senip,sqllist,xsslist,senlist,otherurl]

這個就簡單多了,基于正則分析的正則不是很完善,還有好多是根據自己公司情況來定,大牛輕噴,檢索完畢返回ip及url。</code></pre>

IP 地理位置查詢模塊 ipfind.py

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

import re
import urllib.request

def url_open(ip):

url = <strong>'http://www.ip138.com/ips138.asp?ip='</strong>+ip

response = urllib.request.urlopen(url)

html = response.read().decode(<strong>'gb2312'</strong>)

<strong>return </strong>html


def find_ip(html):

a = <strong>r'</strong><strong>本站數據.{20,}</li>' </strong>p = re.compile(a,re.I)

response = re.findall(p,html)

<strong>for </strong>i <strong>in </strong>response:

    b = i

response = re.split(<strong>r'</li><li>'</strong>,b)

ipaddrs = str(response[0][5:])+<strong>','</strong>+str(response[1][6:])+<strong>','</strong>+str(response[2][6:-5])

<strong>return </strong>ipaddrs


def find_ipaddrs(ip):

html = url_open(ip)

ipaddrs = find_ip(html)


print(ip+<strong>' : '</strong>+ipaddrs)

這個簡單我是直接像爬蟲那樣寫的,用ip138的網址(接口沒有找到,百度注冊了好幾次都不成功,有api的可以用api)。</code></pre> 

主函數

主函數main.py

import re
import os
import sys
from datetime import datetime
import url
import attack
import ipfind

needlist = url.needlist

sqllist,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))</code></pre> 

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

總結

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

現實不足:看了差不多有3個月日志了吧,先說一個最嚴重的問題,post請求data看不見,本身日志就看不到data,何況等到https普及了日志什么樣也不知道,要是有能力最好做成和waf聯動那樣的。還有就是未知威脅從waf來看基于正則,基于關鍵詞有很多都是能繞過的,但是有攻擊行為沒刪日志的話,肯定是會留下攻擊痕跡的,這樣可以從檢測出來的ip來看具體攻擊的url,而未知威脅則不同了,就好比一個0day,攻擊waf沒用了,日志分析看不出來了,那么只能依靠應急響應以及服務器的報警了。

還有好多攻擊類型沒有加入到里面,后期打算把判斷攻擊類型寫成函數,拿if,else判斷,類型少還可以,類型多了感覺很容易亂,還有user-agent的收集與判斷(雖然大多數掃描器都能改user-agent)。

具體分析:我都是用腳本跑一遍,然后按ip來看會比較方便些,而這里缺少機器識別,我單獨寫了一個簡易的機器識別的東西,其實要實現很簡單,把全部日志按時間,url,ip扔進一個列表里統計一下相同時間相同ip的就可以了。我寫的是識別短信轟炸的,后期還會漸漸的完善,如果有能力就把它結合django來弄成圖形化,畢竟腳本始終是腳本,終究聽著不好聽。

效果如下

 

來自:http://www.freebuf.com/sectool/126698.html

 

 本文由用戶 msoc0751 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!