工具开发 | Go实现带推送的文件监控工具

admin 2022年12月10日15:29:11评论46 views字数 9242阅读30分48秒阅读模式
工具开发 | Go实现带推送的文件监控工具
泛星安全团队
工具开发 | Go实现带推送的文件监控工具

泛星安全团队第16篇文章




声明

文章内容为学习记录,请勿利用文章内的相关技术从事非法测试,如因此产生的一切不良后果与文章作者和本公众号无关。


0x00 开发背景


这个工具开发想法最早是去年国hvv,客户那边云上资产linux服务器比较多,d盾可以监控windows上的文件变化但是没有linux版本,github上也有一些用python开发的文件监控工具,但是每次跑到服务器上看觉得有点麻烦,后面想法就是写个多平台带消息推送的文件监控工具。

在去年的7月份用python开发了一个版本,效果如下:


工具开发 | Go实现带推送的文件监控工具


最近一个客户那边做hvv,有老6非攻击时间半夜搞事情


工具开发 | Go实现带推送的文件监控工具


通过一个OA的nday打进内网,后端值守监控到frp的流量看到群消息同事立马上服务器看D盾文件监控日志,态势感知对流量分析监控还是有一定时间过程,如果没有态势感知完全不知道这老6干了什么,那么这个时候如果我们有个可以实时监控服务器文件指定后缀创建修改这些时间的bot,就可以及时响应处理这种事件,最近又电脑坏了之前python写的版本都在老的电脑上,没有备份到网盘这些,决定用go重写一个。


0x01 设计思路


工具功能设计的大概思路

工具开发 | Go实现带推送的文件监控工具

0x02 功能实现


这里只讲功能用go实现核心代码,目前工具的代码还没全部合到一块,需要使用的话可以使用之前的python版本的,实现了上面的大部分功能模块(bug比较多),python版本太久没更新了也一直没有用上。

命令行参数

命令行参数功能实现我使用的cobra,使用cobra生成命令,在我们的项目文件里面会自动生成一个cmd目录


工具开发 | Go实现带推送的文件监控工具


最初始的是生成一个root文件,我这里用cobra-cli生成了version和conf命令行。


/*Copyright © 2022 [email protected]
*/package cmd
import ( "fmt"
"github.com/spf13/cobra")
var EnableCommandSorting = false
// confCmd represents the init commandvar confCmd = &cobra.Command{ Use: "conf", Long: "Profile initialization", Run: func(cmd *cobra.Command, args []string) { fmt.Println("conf called") },}
func init() { rootCmd.AddCommand(confCmd)
confCmd.Flags().String("mu", "", "--mu [email protected]") confCmd.Flags().String("mp", "", "--mp admin@#!123") confCmd.Flags().String("dp", "", "--dp http://test.com") confCmd.Flags().String("wp", "", "--wp http://test.com")
confCmd.MarkFlagRequired("mu") confCmd.MarkFlagRequired("mp") confCmd.MarkFlagRequired("dp") confCmd.MarkFlagRequired("wp")
}


version


/*Copyright © 2022 [email protected]
*/package cmd
import ( "fmt"
"github.com/spf13/cobra")
var versionCmd = &cobra.Command{ Use: "version", Run: func(cmd *cobra.Command, args []string) { fmt.Println("Sentry V0.1") },}
func init() { rootCmd.AddCommand(versionCmd)
}


在root里面定义test功能参数,这个主要测试推送配置是否正常。


func init() {  rootCmd.AddCommand(test)}


test功能代码


var test = &cobra.Command{  Use:  "test",  Long: "Message push test",  Run: func(cmd *cobra.Command, args []string) {    fmt.Println("test...")  // 后面换成我们的功能代码  },}


其它参数在root.go


func init() {  rootCmd.AddCommand(test)    // 命令参数  rootCmd.Flags().StringP("dir", "d", "", "--dir c:/test")  rootCmd.Flags().StringP("excludedir", "e", "", "--excludedir c:/test")  rootCmd.Flags().StringP("config", "c", "conf.ini", "--config conf.ini")
}


效果:


工具开发 | Go实现带推送的文件监控工具


基本的命令行就构建完成了,当然这里不是最终的效果,后面优化帮助信息还有使用案例输出效果,cobra这个输出有点丑了,可以用cobra自定义模板信息做个美化

文件变化监控功能

使用的是fsnotify库

项目地址:https://github.com/fsnotify/fsnotify


package main
import ( "log"
"github.com/fsnotify/fsnotify")
func main() { watcher, err := fsnotify.NewWatcher() if err != nil { log.Fatal(err) } defer watcher.Close()
done := make(chan bool) go func() { for { select { case event, ok := <-watcher.Events: if !ok { return } log.Println("event:", event) if event.Op&fsnotify.Write == fsnotify.Write { log.Println("modified file:", event.Name) } case err, ok := <-watcher.Errors: if !ok { return } log.Println("error:", err) } } }()
err = watcher.Add("c:/") if err != nil { log.Fatal(err) } <-done}


基础代码、文件监控逻辑一些细节还得通过官方demo去修改,提取我们需要的信息,比如说指定的后缀修改告警


可执行文件检测

这个功能的想法是监控一些windows机器权限比较高的目录和web目录,对exe可执行文件上传到微步沙箱,微步给了每个月1000条限额完全够了

工具开发 | Go实现带推送的文件监控工具


微步在线api文档:https://x.threatbook.cn/v5/apiDocs

主要使用下面两个api接口,微步提供了go代码模板封装到函数里面加一个处理结果函数返回我们需要的结果就可以了。

  • https://x.threatbook.cn/v5/apiDocs

  • https://x.threatbook.cn/v5/apiDocs


工具开发 | Go实现带推送的文件监控工具

webshell在线检测

这里我用了两个在线检测的平台,百度webdir+和河马在线web检测。

百度webdir+

百度webdir+是有api接口的,可以直接调用。


// 百度webdir+ 扫描func WebDirScan(scanfile string) [3]string {  url := "https://scanner.baidu.com/enqueue"  r, w := io.Pipe()  m := multipart.NewWriter(w)  go func() {    defer w.Close()    defer m.Close()    part, err := m.CreateFormFile("archive", "scanfile.zip")    if err != nil {      return    }    file, err := os.Open(scanfile)    if err != nil {      return    }    defer file.Close()    if _, err = io.Copy(part, file); err != nil {      return    }  }()  a, _ := http.Post(url, m.FormDataContentType(), r)  rspBody, _ := ioutil.ReadAll(a.Body)  result := viper.New()  result.SetConfigType("json")  result.ReadConfig(bytes.NewBuffer(rspBody))  resulturl := result.GetString("url")  scanresult := bdresult(resulturl)    // 输出结果  return scanresult}


WebDirScan函数传参文件进来之后上传文件获取到文件扫描结果url传给bdresult函数返回扫描结果,扫描结果里面包含文件名、md5、威胁类型。


func bdresult(url string) [3]string {  client := &http.Client{}  req, _ := http.NewRequest("GET", url, nil)  // 请求头设置 设置长连接  req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.0.0 Safari/537.36")  req.Header.Set("Connection", "keep-alive")resetcheck:  // 开始请求  resp, err := client.Do(req)  if err != nil {    fmt.Println("Http get err:", err)  }  //if resp.StatusCode != 200 {  //  fmt.Println("status code:", err)  //}  defer resp.Body.Close()  body, _ := ioutil.ReadAll(resp.Body)  var scanresult [3]string    // 扫描结果判断扫描是否完成 未完成sleep 3s goto重新请求结果再次判断  if checkstatus := strings.Contains(string(body), "pending"); checkstatus {    time.Sleep(3 * time.Second)    goto resetcheck  } else {        // 临时调试输出 后面统一换成log输出到文件    fmt.Printf("百度webdir+扫描完成")  }  result := viper.New()  result.SetConfigType("json")
html := string(body) html = html[1 : len(html)-2] result.ReadConfig(bytes.NewBuffer([]byte(html))) if err := result.ReadConfig(bytes.NewBuffer([]byte(html))); err != nil { if _, ok := err.(viper.ConfigFileNotFoundError); ok { fmt.Println("找不到配置文件..") } else { fmt.Println("配置文件出错..") } } scanresult[1] = result.GetString(`md5`)
//fmt.Printf(result.GetString(`data.descr`)) //fmt.Printf(result.GetString(`md5`)) re_json := strings.Split(html, "],") re_json1 := re_json[0] results := re_json1[9:len(re_json1)] // path descr result.ReadConfig(bytes.NewBuffer([]byte(results))) if err := result.ReadConfig(bytes.NewBuffer([]byte(results))); err != nil { if _, ok := err.(viper.ConfigFileNotFoundError); ok { fmt.Println("找不到配置文件..") } else { fmt.Println("配置文件出错..") } } scanresult[0] = result.GetString(`path`) scanresult[2] = result.GetString(`descr`) return scanresult
}


测试效果


工具开发 | Go实现带推送的文件监控工具

河马webshell


河马官方没有提供api接口,我们在浏览器看下请求包分析下,写个简单的爬虫处理扫描结果。


工具开发 | Go实现带推送的文件监控工具

工具开发 | Go实现带推送的文件监控工具


文件上传后自动跳转到了https://n.shellpub.com/detail/59f0fea5-ca5a-42cb-b3dd-c265441b561c,根据上面的返回结果可以知道结果detail后面拼接的是返回的tid


工具开发 | Go实现带推送的文件监控工具


页面返回结果里面有一串json就是我们需要的结果内容


工具开发 | Go实现带推送的文件监控工具


代码实现如下

func Hmscan(scanfile string) []string {  // 上传到河马webshell在线检测  url := "https://n.shellpub.com/api/v1/zip"  r, w := io.Pipe()  m := multipart.NewWriter(w)  go func() {    defer w.Close()    defer m.Close()    part, err := m.CreateFormFile("userfile", "scanfile.zip")    if err != nil {      return    }    file, err := os.Open(scanfile)    if err != nil {      return    }    defer file.Close()    if _, err = io.Copy(part, file); err != nil {      return    }  }()  a, _ := http.Post(url, m.FormDataContentType(), r)  rspBody, _ := ioutil.ReadAll(a.Body)  result := viper.New()  // 设置配置文件类型为json 这里很重要 不是指的话会读取不到 踩坑踩坑  result.SetConfigType("json")  result.ReadConfig(bytes.NewBuffer(rspBody))  if err := result.ReadConfig(bytes.NewBuffer(rspBody)); err != nil {    if _, ok := err.(viper.ConfigFileNotFoundError); ok {      fmt.Println("找不到配置文件..")    } else {      fmt.Println("配置文件出错..")    }  }  // 结果url拼接  result_url := "https://n.shellpub.com/detail/" + result.GetString(`data.tid`)  scanresult := hmresult(result_url)  return scanresult}


拼接得到结果url处理返回页面的json信息


func hmresult(url string) []string {  client := &http.Client{}  req, _ := http.NewRequest("GET", url, nil)  // 请求头设置 设置长连接  req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.0.0 Safari/537.36")  req.Header.Set("Connection", "keep-alive")resetcheck:  // 开始请求  resp, err := client.Do(req)
if err != nil { fmt.Println("Http get err:", err) } //if resp.StatusCode != 200 { // fmt.Println("status code:", err) //} defer resp.Body.Close() body, _ := ioutil.ReadAll(resp.Body) if checkstatus := strings.Contains(string(body), "服务目前不可用"); checkstatus { time.Sleep(3 * time.Second) goto resetcheck } else { fmt.Printf("河马webshell扫描完成") } //fmt.Printf(string(body)) html := strings.Replace(string(body), "n", "", -1) re_json := regexp.MustCompile(`"results":[(.*?)]`) result_json := re_json.FindString(html) result_json = result_json[11 : len(result_json)-1] result := viper.New() // 设置配置文件类型为json 这里很重要 不是指的话会读取不到 踩坑踩坑 result.SetConfigType("json") result.ReadConfig(bytes.NewBuffer([]byte(result_json))) if err := result.ReadConfig(bytes.NewBuffer([]byte(result_json))); err != nil { if _, ok := err.(viper.ConfigFileNotFoundError); ok { fmt.Println("找不到配置文件..") } else { fmt.Println("配置文件出错..") } }
// 返回字符数组 var scanresult []string scanresult = append(scanresult, result.GetString(`filename`)) scanresult = append(scanresult, result.GetString(`md5`)) scanresult = append(scanresult, result.GetString(`description`)) return scanresult}


测试效果


工具开发 | Go实现带推送的文件监控工具


消息推送

钉钉推送

这里用的是github上面的一个库

项目地址:https://github.com/blinkbean/dingtalk

直接调用就可以了,基础推送代码

package main
import ( "fmt" "github.com/blinkbean/dingtalk" "os")
func main() { // 单个机器人有单位时间内消息条数的限制,如果有需要可以初始化多个token,发消息时随机发给其中一个机器人。 var dingToken = "*****************************" cli := dingtalk.InitDingTalkWithSecret(dingToken, "*****************************") //var testphone = "18888888888" //cli.SendTextMessage("test", dingtalk.WithAtMobiles([]string{"18888888888"})) //cli.SendLinkMessage("test", "test", "", "https://www.baidu.com") msg := []string{ "# Sentry 文件监控提醒", "---", "事件信息:<font color=#ff2a00 size=20>敏感文件后缀创建</font>n", "服务器主机名:testn", "服务器IP:127.0.0.1n", "服务器MAC:n", "百度Webdir+检测结果:<font color=#ff2a00 size=20>危险</font>n", } cli.SendMarkDownMessageBySlice("Markdown title", msg, dingtalk.WithAtAll()) fmt.Println(os.Hostname())}


测试效果


工具开发 | Go实现带推送的文件监控工具


日志记录

自定义Logger输出格式

package monitor
import ( "fmt" "io" "log" "os")
var ( Trace *log.Logger Info *log.Logger Warning *log.Logger Error *log.Logger)
func init() { dir, _ := os.Getwd() fmt.Println(dir) f, err := os.OpenFile(dir+"\logs\"+"test.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666) if err != nil { log.Fatalln(err) } Trace = log.New(io.MultiWriter(f, os.Stdout), "[TRACE] ", log.Ldate|log.Ltime) Info = log.New(io.MultiWriter(f, os.Stdout), "[INFO] ", log.Ldate|log.Ltime) Warning = log.New(io.MultiWriter(f, os.Stdout), "[WARNING] ", log.Ldate|log.Ltime) Error = log.New(io.MultiWriter(f, os.Stdout), "[ERROR] ", log.Ldate|log.Ltime)}


后面所有需要日志输出的地方都通过这个包去输出,统一日志输出格式


工具开发 | Go实现带推送的文件监控工具

0x03 结语

一个简单的带推送的文件监控工具,在一些特定的场景下可能有用,也有可能用处不大哈哈!算是go工具开发的小尝试,大佬们勿喷!



往期回顾

初窥JAVA代码审计

从sql注入到内网

HackTheBox:10.10.10.180靶机记录

vulnhub:CHILL HACK靶机记录

回炉重造 | 精通php反序列化之道


·END·
 


泛星安全团队

工具开发 | Go实现带推送的文件监控工具


原文始发于微信公众号(泛星安全团队):工具开发 | Go实现带推送的文件监控工具

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2022年12月10日15:29:11
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   工具开发 | Go实现带推送的文件监控工具https://cn-sec.com/archives/1453331.html

发表评论

匿名网友 填写信息