├── .idea
├── .gitignore
├── vcs.xml
├── modules.xml
└── monitor-Go.iml
├── go.mod
├── README.md
├── .github
├── workflows
│ └── release1.yml
└── conf
│ └── .goreleaser.yml
├── go.sum
└── main.go
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # 默认忽略的文件
2 | /shelf/
3 | /workspace.xml
4 | # 基于编辑器的 HTTP 客户端请求
5 | /httpRequests/
6 | # Datasource local storage ignored files
7 | /dataSources/
8 | /dataSources.local.xml
9 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module monitor-Go
2 |
3 | go 1.21
4 |
5 | require github.com/gookit/color v1.5.4
6 |
7 | require (
8 | github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect
9 | golang.org/x/sys v0.10.0 // indirect
10 | )
11 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/monitor-Go.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 文件监控
2 |
3 | 用来监控文件以及其子目录下的所有文件的增删改
4 |
5 | 此脚本[基于](https://gitee.com/piri47/AWD-1/blob/master/%E6%96%87%E4%BB%B6%E7%9B%91%E6%8E%A7.py)
6 |
7 | 做出的改进:
8 |
9 | 1. 不会删除原文件,避免因为某些意外情况而导致的原文件被删除
10 | 2. 前端打印所有详细信息,包括文件路径、被修改的时间、内容等
11 |
12 | + 用法
13 |
14 | 在需要监控的目录下直接启动即可
15 | ```go
16 | monitor-Go.exe
17 | ```
18 |
19 | + 效果图
20 |
21 | 
--------------------------------------------------------------------------------
/.github/workflows/release1.yml:
--------------------------------------------------------------------------------
1 | name: goreleaser
2 |
3 | on:
4 | push:
5 | tags:
6 | - '*'
7 |
8 | permissions:
9 | contents: write
10 |
11 | jobs:
12 | goreleaser:
13 | runs-on: ubuntu-latest
14 | timeout-minutes: 60
15 | steps:
16 | -
17 | name: Checkout
18 | uses: actions/checkout@v2
19 | with:
20 | fetch-depth: 0
21 | -
22 | name: Set up Go
23 | uses: actions/setup-go@v2
24 | with:
25 | go-version: 1.21
26 | -
27 | name: Run GoReleaser
28 | uses: goreleaser/goreleaser-action@v2
29 | with:
30 | distribution: goreleaser
31 | version: latest
32 | args: -f .github/conf/.goreleaser.yml
33 | workdir: .
34 | env:
35 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
--------------------------------------------------------------------------------
/go.sum:
--------------------------------------------------------------------------------
1 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
2 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
3 | github.com/gookit/color v1.5.4 h1:FZmqs7XOyGgCAxmWyPslpiok1k05wmY3SJTytgvYFs0=
4 | github.com/gookit/color v1.5.4/go.mod h1:pZJOeOS8DM43rXbp4AZo1n9zCU2qjpcRko0b6/QJi9w=
5 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
6 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
7 | github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
8 | github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
9 | github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 h1:QldyIu/L63oPpyvQmHgvgickp1Yw510KJOqX7H24mg8=
10 | github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1zIOPMxZ5EncGwgmMJsa+9ucAQZXxsObs=
11 | golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA=
12 | golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
13 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
14 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
15 |
--------------------------------------------------------------------------------
/.github/conf/.goreleaser.yml:
--------------------------------------------------------------------------------
1 | before:
2 | hooks:
3 | - sudo apt -y install libprotobuf-dev protobuf-compiler protoc-gen-go
4 | - go mod tidy
5 | - go generate ./...
6 | builds:
7 | - id: "with-upx"
8 | env:
9 | - CGO_ENABLED=0
10 | goos:
11 | - linux
12 | - windows
13 | - darwin
14 | goarch:
15 | - amd64
16 | - arm64
17 | - arm
18 | - "386"
19 | goarm:
20 | - "6"
21 | - "7"
22 | flags:
23 | - -trimpath
24 | ldflags:
25 | - -s -w -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{ .CommitDate }} -X main.builtBy=goreleaser
26 | ignore:
27 | - goos: windows
28 | goarch: arm64
29 | - goos: windows
30 | goarch: arm
31 | - goos: linux
32 | goarch: mips64
33 | hooks:
34 | post: upx --best -f -q "{{ .Path }}"
35 |
36 | # UnknownExecutableFormatException
37 | # CantPackException: can't pack new-exe
38 | - id: "without-upx"
39 | env:
40 | - CGO_ENABLED=0
41 | goos:
42 | - linux
43 | - windows
44 | - darwin
45 | goarch:
46 | - mips64
47 | - arm
48 | goarm:
49 | - "6"
50 | - "7"
51 | flags:
52 | - -trimpath
53 | ldflags:
54 | - -s -w -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{ .CommitDate }} -X main.builtBy=goreleaser
55 | ignore:
56 | - goos: linux
57 | goarch: arm
58 |
59 |
60 | archives:
61 | - format: zip
62 | name_template: '{{ .ProjectName }}_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}'
63 | checksum:
64 | name_template: 'checksums.txt'
65 | snapshot:
66 | name_template: "{{ incpatch .Version }}-next"
67 | changelog:
68 | sort: asc
69 | filters:
70 | exclude:
71 | - '^docs:'
72 | - '^test:'
--------------------------------------------------------------------------------
/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "crypto/md5"
5 | "encoding/hex"
6 | "fmt"
7 | "github.com/gookit/color"
8 | "io"
9 | "os"
10 | "path/filepath"
11 | "strings"
12 | "time"
13 | )
14 |
15 | var specialPathStr = "drops_B0503373BDA6E3C5CD4E5118C02ED13A"
16 | var specialString = "drops_log"
17 | var fileMD5Dict = make(map[string]string)
18 | var originFileList []string
19 |
20 | func calcMD5(filePath string) string {
21 | data, err := os.ReadFile(filePath)
22 | if err != nil {
23 | fmt.Println("[*] 文件被删除 :", filePath)
24 | return ""
25 | }
26 | hash := md5.Sum(data)
27 | return hex.EncodeToString(hash[:])
28 | }
29 |
30 | func getFilesList(root string) []string {
31 | var files []string
32 | err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
33 | if err != nil {
34 | return err
35 | }
36 | if !info.IsDir() && !strings.Contains(path, specialPathStr) {
37 | files = append(files, path)
38 | }
39 | return nil
40 | })
41 | if err != nil {
42 | fmt.Println("[*] 错误:", err)
43 | }
44 | return files
45 | }
46 |
47 | func backupDirectory(srcDir string) error {
48 | // 创建备份目录
49 | backupDir := filepath.Join(srcDir, "backup")
50 | if err := os.MkdirAll(backupDir, 0755); err != nil {
51 | return err
52 | }
53 |
54 | // 读取源目录下的所有文件
55 | files, err := os.ReadDir(srcDir)
56 | if err != nil {
57 | return err
58 | }
59 |
60 | for _, file := range files {
61 | if !file.IsDir() {
62 | srcFile := filepath.Join(srcDir, file.Name())
63 | dstFile := filepath.Join(backupDir, file.Name())
64 |
65 | if err := copyFile(srcFile, dstFile); err != nil {
66 | return err
67 | }
68 | }
69 | }
70 |
71 | return nil
72 | }
73 |
74 | func copyFile(src, dst string) error {
75 | srcFile, err := os.Open(src)
76 | if err != nil {
77 | return err
78 | }
79 | defer srcFile.Close()
80 |
81 | dstFile, err := os.Create(dst)
82 | if err != nil {
83 | return err
84 | }
85 | defer dstFile.Close()
86 |
87 | _, err = io.Copy(dstFile, srcFile)
88 | return err
89 | }
90 |
91 | func replaceFileContent(targetFilePath, sourceFilePath string) error {
92 | sourceFile, err := os.Open(sourceFilePath)
93 | if err != nil {
94 | return err
95 | }
96 | defer sourceFile.Close()
97 | targetFile, err := os.Create(targetFilePath)
98 | if err != nil {
99 | return err
100 | }
101 | defer targetFile.Close()
102 | _, err = io.Copy(targetFile, sourceFile)
103 | return err
104 | }
105 |
106 | func main() {
107 | fmt.Println("---------持续监测文件中------------")
108 | cwd, _ := os.Getwd()
109 | if err := backupDirectory(cwd); err != nil {
110 | fmt.Println("Error:", err)
111 | } else {
112 | fmt.Println("Backup completed successfully!")
113 | }
114 | originFileList = getFilesList(cwd)
115 | for _, filePath := range originFileList {
116 | fileMD5Dict[filePath] = calcMD5(filePath)
117 | }
118 |
119 | for {
120 | fileList := getFilesList(cwd)
121 | diffFileList := []string{}
122 | for _, file := range fileList {
123 | if _, ok := fileMD5Dict[file]; !ok {
124 | diffFileList = append(diffFileList, file)
125 | }
126 | }
127 |
128 | // 移除新上传文件
129 | if len(diffFileList) != 0 {
130 | for _, filePath := range diffFileList {
131 | data, err := os.ReadFile(filePath)
132 | if err != nil {
133 | break
134 | }
135 | content := string(data)
136 | if !strings.Contains(content, specialString) {
137 | fmt.Println("[*] 发现疑似WebShell上传文件:", filePath, "时间为:", time.Now(), "内容为:", content)
138 | // 自动删除新上传的文件
139 | err1 := os.Remove(filePath)
140 | if err1 != nil {
141 | color.Red.Printf("删除文件时出错:%s\n", err)
142 | }
143 | color.Green.Println("[+] 新上传的文件已删除")
144 | }
145 | }
146 | }
147 |
148 | // 防止任意文件被修改,还原被修改文件
149 | for _, filePath := range originFileList {
150 | newMD5 := calcMD5(filePath)
151 | if newMD5 != fileMD5Dict[filePath] {
152 | data, err1 := os.ReadFile(filePath)
153 | if err1 != nil {
154 | break
155 | }
156 | content := string(data)
157 | if !strings.Contains(content, specialString) {
158 | fmt.Println("[*] 该文件被修改 :", filePath, "时间为:", time.Now(), "内容为:", content)
159 | // 自动还原被删除的文件
160 | dir, file := filepath.Split(filePath)
161 | backupFilePath := filepath.Join(dir, "backup", file)
162 | replaceFileContent(filePath, backupFilePath)
163 | color.Green.Println("[+] 被修改的文件已还原")
164 | }
165 | }
166 | }
167 |
168 | time.Sleep(5 * time.Second)
169 | }
170 | }
171 |
--------------------------------------------------------------------------------