用go实现web日志分析及网页挂马关键字检测

本程序主要实现网页挂马关键字检测,原理是这样的,通过定时分析用户访问的IIS web日志,对日志的里的URL进行访问,然后检索是否包含相关的关键字,有就入库,这只是go实现自动检索及入库,可以加个前端,实现加关键及报警功能

package main


import (
    "bufio"
    "code.google.com/p/mahonia"
    "fmt"
    "io"
    "io/ioutil"
    "labix.org/v2/mgo"
    "labix.org/v2/mgo/bson"
    "log"
    "net"
    "net/http"
    "os"
    "path/filepath"
    "strconv"
    "strings"
    "time"
    //qqwry为IP库
    //ftp "github.com/jlaffaye/ftp"
    //"github.com/yinheli/qqwry"
)

const Version = "CDN1.0"

//var ServerList []ServerMember
//PageKeyWord用来保存可疑Url及这个页面包含有哪些关键字,以及日志记录于哪台服务器及日志文件,并最终插入数据库
type PageHasKeyWord struct {
    Url string
    KeyWords []string
    //    UserIp string
    LogFile string
    ServerIp string
    Audit bool
    Auditor string //记录谁审核
    AuditTime string //记录审核时间
    Level int //可疑级别
}
type DoubtfulKeyWord struct {
    Id bson.ObjectId "_id"
    KeyWord string
    //Level string
}

type UrlsToAnalysit struct {
    Urls []string
    LogFile string
    ServerIp string
    Domain string
}

//定义MonthTOstr映射,用来将月份换为数字string,go里的月份用英文单词表示,要注意的go赋值要在函数体里赋值
var MonthTOstr = make(map[string]string)

func main() {

    //fmt.Printf("%s", getLogFileName())

    if len(os.Args) != 4 {
        log.Fatal("Usage:" + filepath.Base(os.Args[0]) + " log_dir " + "db_server_ip_address test")
        os.Exit(1)
    }

    logFileName, _, _ := getLogFileName()

    fmt.Println(time.Now())

    logDbServer := os.Args[2]
    dir := os.Args[1]
    dbname := "webmonitordb"
    //doubtfulKW为string数组,从数据库中获取可疑检索的URL,注意的是go是区分大小写的,因此要注意mongodb里的库名及collection名大小写
    //doubtfulKW := []string{}
    keyWords := getdoubtfulkeyword(logDbServer, dbname, "DangeroursWords")
    //wordlist := []string{"百家乐", "博彩网", "网上赌场", "娱乐城", "赌博网站", "皇冠投注", "皇冠开户", "真龙娱乐城", "三亚娱乐城"}
    /*for n, item := range keyWords {
        fmt.Println(n, item.KeyWord)
    }*/
    if os.Args[3] == "test" {
        fmt.Println("wait!")
        time.Sleep(time.Duration(90) * time.Second)
    }

    fmt.Println("start!")
    filepath.Walk(dir, func(path string, f os.FileInfo, err error) error {
        if f == nil {
            return err
        }
        if f.IsDir() {
            return nil
        }
        if f.Name() == logFileName {

            //fmt.Println(path)

            //fmt.Println(time.Now())
            urls := logFileAnalysit(path)
            //fmt.Println(urls)
            for _, v := range urls.Urls {
                //fmt.Println(n, ":", v)
                url := "http://" + urls.Domain + v
                //fmt.Println(n, url)
                pagestr := getPage(url)
                findWord(pagestr, url, urls.LogFile, urls.ServerIp, keyWords)

                //fmt.Println(n)
            }

        }

        return nil
    })

}
func logFileAnalysit(logFile string) UrlsToAnalysit {
    readLogFile, err := os.Open(logFile)
    if err != nil {
        log.Fatal(err)
    }
    defer readLogFile.Close()
    //pathFields的作用是将日志path解析成一个数据,从而可以得到日志的域名
    pathFields := strings.Split(logFile, "\\")
    var domainName string
    if len(pathFields) > 3 {
        domainName = pathFields[len(pathFields)-3]
    }
    var Urls UrlsToAnalysit
    Urls.Domain = domainName
    Urls.LogFile = logFile
    Urls.ServerIp = getLocalIpAddr()

    Urls.Urls = append(Urls.Urls, "/") //监控站点首页
    //    analysitTime := time.Now()
    bfLogFile := bufio.NewReader(readLogFile)
    //定义一个gbk转utf8解码器
    //enc := mahonia.NewDecoder("gbk")
    for {
        logRecordStr, err := bfLogFile.ReadString(‘\n‘)

        if err == io.EOF {
            //注意,这里要使用break,而不是return,return会使整个个程序退出了,break只是中断当前的for循环
            break
        }
        //以"#"开头的要跳过,iiS 日志前几行是做了注释的
        if strings.HasPrefix(logRecordStr, "#") {
            continue
        }
        //recordItems 是个string数组,用来临时保存每行记录里的字段
        //#Fields: date time s-sitename s-ip cs-method cs-uri-stem cs-uri-query s-port cs-username c-ip cs(User-Agent) sc-status sc-substatus sc-win32-status time-taken
        fields := strings.Split(logRecordStr, " ")
        //scstatus为服务器状态码的index
        if len(fields) < 13 { //不满16个字段的跳过
            continue
        }
        url := strings.ToLower(fields[5])
        //fields[9] != Urls.ServerIp 过滤掉自己访问的IP记录
        if (strings.HasSuffix(url, "htm") || strings.HasSuffix(url, "html")) && fields[12] == "200" && fields[9] != Urls.ServerIp {
            flag := true
            for _, v := range Urls.Urls {
                if v == url {
                    flag = false
                    break
                }
            }
            if flag {
                Urls.Urls = append(Urls.Urls, url)

            }

        }
    }
    return Urls
}

//getLogFileName()根据当前的时间,生成一个将要被分析日志文件名,因为不同IIS站点每小时时生成一个日志文件,命名格式不exyymmddhh.log
func getLogFileName() (string, string, string) {
    MonthTOstr := map[string]string{"January": "01",
        "February": "02",
        "March": "03",
        "April": "04",
        "May": "05",
        "June": "06",
        "July": "07",
        "August": "08",
        "September": "09",
        "October": "10",
        "November": "11",
        "December": "12"}
    timenow := time.Now()
    year, month, day := timenow.Date()
    //monthStr := month.String()

    hour, _, _ := timenow.Clock()
    yearStr := strings.TrimLeft(strconv.Itoa(year), "20") //去掉前面的四位数年份如"2014"年的“20”
    dayStr, hourStr := strconv.Itoa(day), strconv.Itoa(hour)
    if day < 10 {
        dayStr = "0" + dayStr
    }
    if hour < 10 {
        hourStr = "0" + hourStr
    }

    fileName := "ex" + yearStr + MonthTOstr[month.String()] + dayStr + hourStr + ".log"
    logDay := yearStr + MonthTOstr[month.String()] + dayStr
    logMonth := yearStr + MonthTOstr[month.String()]

    //monthSrt := strconv.Itoa(timenow.Month())
    //fmt.Println(fileName, logDay)
    return fileName, logDay, logMonth
    //fmt.Println(fileName)

}
func getPage(page string) string {
    resp, err := http.Get(page)
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()
    enc := mahonia.NewDecoder("gb2312")
    pageData, _ := ioutil.ReadAll(resp.Body)
    //return string(pageData)
    PageStr := enc.ConvertString(string(pageData))
    return PageStr

}
func findWord(str, url, logfile, serverip string, wordlist []DoubtfulKeyWord) {
    var phkw PageHasKeyWord
    flag := false
    for _, item := range wordlist {

        if strings.Contains(str, item.KeyWord) {
            //fmt.Println("the page contains the word:", item.KeyWord, url)

            phkw.KeyWords = append(phkw.KeyWords, item.KeyWord)
            flag = true

        }
    }
    if flag {
        phkw.Url = url
        phkw.LogFile = logfile
        phkw.ServerIp = serverip
        phkw.Audit = false
        phkw.Level = len(phkw.KeyWords)
        interdatadb("192.168.111.28", "webmonitordb", "dangerPage", phkw)

    }
}

func interdatadb(dbserver, dbname, celection string, items PageHasKeyWord) {
    session, err := mgo.Dial(dbserver)
    if err != nil {
        panic(err)
    }
    defer session.Close()

    // Optional. Switch the session to a monotonic behavior.
    session.SetMode(mgo.Monotonic, true)

    c := session.DB(dbname).C(celection)
    //fmt.Println(items)
    //time.Sleep(time.Duration(90) * time.Second)
    err = c.Insert(&PageHasKeyWord{items.Url, items.KeyWords, items.LogFile, items.ServerIp, items.Audit, items.Auditor, items.AuditTime, items.Level})
    //err = c.Insert(&LogItems(logItem))
    if err != nil {
        panic(err)
    }

}

func getdoubtfulkeyword(dbserver, dbname, collection string) []DoubtfulKeyWord {
    // 连接数据库
    session, err := mgo.Dial(dbserver)
    if err != nil {
        panic(err)
    }
    defer session.Close()

    // 获取数据库,获取集合
    c := session.DB(dbname).C(collection)

    kws := []DoubtfulKeyWord{}
    //kw := []string{}
    //var ta task
    err = c.Find(bson.M{}).All(&kws)

    if err != nil {
        panic(err)
    }
    /*for n, item := range kws {
        fmt.Println(n, item.Id, item.KeyWord)
    }*/
    return kws
}
func getLocalIpAddr() string {
    //这里使用一个合法的IP就行了,端口随便,即使没有打开也行,也许因为使用UDP,如果用TCP的话,对端不打开就会有问题
    conn, err := net.Dial("udp", "192.168.18.51:80")
    if err != nil {
        //fmt.Println(err.Error())
        return "127.0.0.1"
    }
    defer conn.Close()
    //fmt.Println(conn.LocalAddr().String())
    //conn.
    //fmt.Println(strings.Split(conn.LocalAddr().String(), ":")[0])
    return strings.Split(conn.LocalAddr().String(), ":")[0]
}
				
时间: 2024-10-13 01:24:35

用go实现web日志分析及网页挂马关键字检测的相关文章

海量WEB日志分析

Hadoop家族系列文章,主要介绍Hadoop家族产品,常用的项目包括Hadoop, Hive, Pig, HBase, Sqoop, Mahout, Zookeeper, Avro, Ambari, Chukwa,新增加的项目包括,YARN, Hcatalog, Oozie, Cassandra, Hama, Whirr, Flume, Bigtop, Crunch, Hue等. 从2011年开始,中国进入大数据风起云涌的时代,以Hadoop为代表的家族软件,占据了大数据处理的广阔地盘.开源界

海量Web日志分析 用Hadoop提取KPI统计指标

前言 Web日志包括着站点最重要的信息,通过日志分析.我们能够知道站点的訪问量,哪个网页訪问人数最多,哪个网页最有价值等.一般中型的站点(10W的PV以上),每天会产生1G以上Web日志文件. 大型或超大型的站点,可能每小时就会产生10G的数据量. 对于日志的这样的规模的数据,用Hadoop进行日志分析,是最适合只是的了. 文件夹 Web日志分析概述 需求分析:KPI指标设计 算法模型:Hadoop并行算法 架构设计:日志KPI系统架构 程序开发1:用Maven构建Hadoop项目 程序开发2:

Hadoop 提取KPI 进行海量Web日志分析

Hadoop 提取KPI 进行海量Web日志分析 Web日志包含着网站最重要的信息,通过日志分析,我们可以知道网站的访问量,哪个网页访问人数最多,哪个网页最有价值等.一般中型的网站(10W的PV以上),每天会产生1G以上Web日志文件.大型或超大型的网站,可能每小时就会产生10G的数据量. Web日志分析概述 需求分析:KPI指标设计 算法模型:Hadoop并行算法 架构设计:日志KPI系统架构 程序开发:MapReduce程序实现 1. Web日志分析概述 Web日志由Web服务器产生,可能是

linux系统web日志分析脚本

linux系统web日志分析这方面工具比较多,比如logwatch或awstats等使用perl语言开发,功能都非常强大.但这些软件都需要进行一些配置,很多朋友往往在技术方面没有投入太多力量,即便参照互联网上图文教程也无从下手.对于此情况我编写了一个web日志分析脚本,功能比较简单,无需配置,有需要的朋友可以再尝试一下.  脚本地址: gbk版(一般ssh客户端不用调整直接可用: wget http://jinxiang.oss-cn-hangzhou.aliyuncs.com/weblogch

Hadoop应用开发实战案例 第2周 Web日志分析项目 张丹

课程内容 本文链接: 张丹博客 http://www.fens.me 用Maven构建Hadoop项目 http://blog.fens.me/hadoop-maven-eclipse/程序源代码下载:https://github.com/bsspirit/maven_hadoop_template/releases/tag/kpi_v1Flume部署:  http://blog.csdn.net/zhouleilei/article/details/8568147  周雷雷博客Chukwa部署

web日志分析脚本nginx&http

1,http日志分析 #!/bin/bash for i in [email protected];do         echo ===================== "$i" =============================>>weblog.txt         echo "IP data">>weblog.txt         awk '{print $1}' $i |wc -l>>weblog.txt

Linux------------GoAccess-可视化WEB日志分析工具

目录 一.GoAccess简介 1.1 存储方式 1.2 编译配置参数 1.2 使用选项 1.21 日志/日期/时间 格式 1.22 用户交互选项 1.23 服务器选项 1.24 FILE OPTIONS 1.25 解析选项 1.26 地理位置选项 1.27 其他选项 1.28 磁盘存储选项 1.3 自定义日志/日期格式 1.31 自定义示例 1.4 使用示例 1.41 不同的输出 1.42多日志文件 1.43 实时 HTML 输出 1.44 日期处理 1.45 虚拟主机 1.46 文件 & 状

网页挂马大全集 -中国寒龙出品 转载写明出处www.hackerschina.org

一:框架挂马<iframe src=地址 width=0 height=0></iframe>二:js文件挂马首先将以下代码document.write("<iframe width='0' height='0' src='地址'></iframe>");保存为xxx.js,则JS挂马代码为<script language=javascript src=xxx.js></script>三:js变形加密<SCR

如何预防和检测网页挂马?

在网站优化设计当中,检测网页木马也是很重要的一项工作,目前流行的网站被黑,是在相应的asp,htm,js等文件中,插入以js调用方式的.本文主要介绍网页挂马的工作原理及种类.常见方式.执行方式.如何检测网页是否被挂马.如何清除网页木马.如何防止网页被挂马. 1:网页挂马工作原理的种类. (1)工作原理: 作为网页挂马的散布者,其目的是将木马下载到用户本地,并进一步执行,当木马获得执行之后,就意味着会有更多的木马被下载,进一步被执行,进入一个恶性的循环,从而使用户的电脑遭到攻击和控制.为达到目的首