aboutsummaryrefslogtreecommitdiffstats
path: root/listener
diff options
context:
space:
mode:
Diffstat (limited to 'listener')
-rw-r--r--listener/audit.go84
-rw-r--r--listener/basefunc.go129
-rw-r--r--listener/deal.go269
-rw-r--r--listener/global.go84
-rw-r--r--listener/go.mod26
-rw-r--r--listener/go.sum96
-rw-r--r--listener/go.work6
-rw-r--r--listener/go.work.sum4
-rw-r--r--listener/godo.go176
-rw-r--r--listener/mongo.go122
m---------listener/netlink0
-rw-r--r--listener/organize.go291
-rw-r--r--listener/receive.go29
13 files changed, 1316 insertions, 0 deletions
diff --git a/listener/audit.go b/listener/audit.go
new file mode 100644
index 0000000..ed48691
--- /dev/null
+++ b/listener/audit.go
@@ -0,0 +1,84 @@
1package main
2
3import (
4 "fmt"
5 "io"
6 "log"
7 "os"
8
9 "github.com/elastic/go-libaudit/v2"
10)
11
12func read() error {
13 // Write netlink response to a file for further analysis or for writing
14 // tests cases.
15 var diagWriter io.Writer
16 if *diag != "" {
17 f, err := os.OpenFile(*diag, os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0o600)
18 if err != nil {
19 return err
20 }
21 defer f.Close()
22 diagWriter = f
23 }
24
25 log.Println("starting netlink client")
26
27 var err error
28 var client *libaudit.AuditClient
29 if *receiveOnly {
30 client, err = libaudit.NewMulticastAuditClient(diagWriter)
31 if err != nil {
32 return fmt.Errorf("failed to create receive-only audit client: %w", err)
33 }
34 defer client.Close()
35 } else {
36 client, err = libaudit.NewAuditClient(diagWriter)
37 if err != nil {
38 return fmt.Errorf("failed to create audit client: %w", err)
39 }
40 defer client.Close()
41
42 status, err := client.GetStatus()
43 if err != nil {
44 return fmt.Errorf("failed to get audit status: %w", err)
45 }
46 log.Printf("received audit status=%+v", status)
47
48 if status.Enabled == 0 {
49 log.Println("enabling auditing in the kernel")
50 if err = client.SetEnabled(true, libaudit.WaitForReply); err != nil {
51 return fmt.Errorf("failed to set enabled=true: %w", err)
52 }
53 }
54
55 if status.RateLimit != uint32(*rate) {
56 log.Printf("setting rate limit in kernel to %v", *rate)
57 if err = client.SetRateLimit(uint32(*rate), libaudit.NoWait); err != nil {
58 return fmt.Errorf("failed to set rate limit to unlimited: %w", err)
59 }
60 }
61
62 if status.BacklogLimit != uint32(*backlog) {
63 log.Printf("setting backlog limit in kernel to %v", *backlog)
64 if err = client.SetBacklogLimit(uint32(*backlog), libaudit.NoWait); err != nil {
65 return fmt.Errorf("failed to set backlog limit: %w", err)
66 }
67 }
68
69 if status.Enabled != 2 && *immutable {
70 log.Printf("setting kernel settings as immutable")
71 if err = client.SetImmutable(libaudit.NoWait); err != nil {
72 return fmt.Errorf("failed to set kernel as immutable: %w", err)
73 }
74 }
75
76 log.Printf("sending message to kernel registering our PID (%v) as the audit daemon", os.Getpid())
77 if err = client.SetPID(libaudit.NoWait); err != nil {
78 return fmt.Errorf("failed to set audit PID: %w", err)
79 }
80 }
81
82 coroutine(client)
83 return nil
84}
diff --git a/listener/basefunc.go b/listener/basefunc.go
new file mode 100644
index 0000000..2f39507
--- /dev/null
+++ b/listener/basefunc.go
@@ -0,0 +1,129 @@
1package main
2
3import (
4 "bufio"
5 "fmt"
6 "os"
7 "os/exec"
8 "path/filepath"
9 "strconv"
10 "strings"
11 "time"
12)
13
14func figureOutSyscalls() error {
15 cmd := exec.Command("ausyscall", "--dump")
16 stdout, err := cmd.StdoutPipe()
17 if err != nil {
18 return err
19 }
20
21 if err := cmd.Start(); err != nil {
22 return err
23 }
24
25 scanner := bufio.NewScanner(stdout)
26 for i := 0; scanner.Scan(); i++ {
27 if i == 0 {
28 continue
29 }
30 line := scanner.Text()
31 parts := strings.Split(line, "\t")
32 if len(parts) != 2 {
33 return fmt.Errorf("invalid ausyscall format")
34 }
35 num, err := strconv.Atoi(parts[0])
36 if err != nil {
37 return err
38 }
39 syscallTable[num] = parts[1]
40 }
41
42 if err := scanner.Err(); err != nil {
43 return err
44 }
45 if err := cmd.Wait(); err != nil {
46 return err
47 }
48 return nil
49}
50
51func getPid() (int, error) {
52 // 指定要搜索的关键词
53 keyword := "/usr/bin/containerd"
54
55 // 获取/proc目录下的所有子目录
56 procDir, err := filepath.Glob("/proc/*")
57 if err != nil {
58 return 0, err
59 }
60
61 // 遍历子目录,查找包含关键词的进程
62 for _, dir := range procDir {
63 pid, err := strconv.Atoi(filepath.Base(dir))
64 if err != nil {
65 continue // 跳过非PID的目录
66 }
67
68 // 检查进程是否包含关键词
69 if containsKeyword(pid, keyword) {
70 return pid, nil
71 }
72 }
73 err = fmt.Errorf("Error: no containerd process found.")
74 return 0, err
75}
76
77func containsKeyword(pid int, keyword string) bool {
78 // 构造完整的进程命令路径
79 cmdPath := fmt.Sprintf("/proc/%d/cmdline", pid)
80
81 // 打开文件
82 file, err := os.Open(cmdPath)
83 if err != nil {
84 return false
85 }
86 defer file.Close()
87
88 // 读取文件内容
89 scanner := bufio.NewScanner(file)
90 scanner.Split(bufio.ScanLines)
91 for scanner.Scan() {
92 line := scanner.Text()
93 if strings.Contains(line, keyword) {
94 return true
95 }
96 }
97 return false
98}
99
100func getTimeFromStr(timeStr string) (time.Time, error) {
101 timestampFloat, err := strconv.ParseFloat(timeStr, 64)
102 if err != nil {
103 return time.Unix(0, 0), err
104 }
105 secs := int64(timestampFloat)
106 nsecs := int64((timestampFloat - float64(secs)) * 1e9)
107
108 // 只精确到毫秒就够了
109 t := time.Unix(secs, nsecs).Truncate(time.Millisecond)
110 return t, nil
111}
112
113func hexToAscii(hexString string) string {
114 bytes := []byte{}
115 for i := 0; i < len(hexString); i += 2 {
116 hexPair := hexString[i : i+2]
117 // 将十六进制数转换为十进制数
118 decimal, err := strconv.ParseInt(hexPair, 16, 8)
119 if err != nil {
120 return "Invalid hex string"
121 }
122 char := byte(decimal)
123 bytes = append(bytes, char)
124 }
125
126 asciiString := strings.ReplaceAll(string(bytes), "\000", " ")
127
128 return asciiString
129}
diff --git a/listener/deal.go b/listener/deal.go
new file mode 100644
index 0000000..8f77431
--- /dev/null
+++ b/listener/deal.go
@@ -0,0 +1,269 @@
1package main
2
3import (
4 "fmt"
5 "os"
6 "syscall"
7 "time"
8
9 "go.mongodb.org/mongo-driver/bson"
10)
11
12const (
13 dbName string = "test"
14 pidColName string = "pids"
15 fdColName string = "fds"
16 fileColName string = "files"
17)
18
19var pidCol, fdCol, fileCol mongoClient
20var err error
21
22func deal() {
23 defer wg.Done()
24 var cooked Event
25 var ok bool
26
27 if err = pidCol.init(dbName, pidColName); err != nil {
28 fmt.Fprintf(os.Stderr, "Error while initing the mongodb: %v\n", err)
29 return
30 }
31 err = pidCol.InsertOne(Process{
32 Ppid: 1,
33 Pid: containerdPid,
34 Cwd: "/",
35 Children: make([]int, 0),
36 Star: true,
37 })
38 if err != nil {
39 fmt.Fprintf(os.Stderr, "Error while initing the mongodb: %v\n", err)
40 return
41 }
42
43 if err = fdCol.init(dbName, fdColName); err != nil {
44 fmt.Fprintf(os.Stderr, "Error while initing the mongodb: %v\n", err)
45 return
46 }
47 if err = fileCol.init(dbName, fileColName); err != nil {
48 fmt.Fprintf(os.Stderr, "Error while initing the mongodb: %v\n", err)
49 }
50
51 defer pidCol.Disconnect()
52 defer fdCol.Disconnect()
53 defer fileCol.Disconnect()
54
55 for {
56 cooked, ok = <-cookedChan
57 if !ok {
58 break
59 }
60
61 switch cooked.tag {
62 case NEWPID:
63 go dealNewPid(cooked)
64 case EXECVE:
65 go dealExecve(cooked)
66 case PIDEXIT:
67 go deletePid(cooked)
68 case FILEOPEN:
69 go fileOpen(cooked)
70 case FILEWRITE:
71 go fileWrite(cooked)
72 case FILECLOSE:
73 go fileClose(cooked)
74 case PIVOTROOT:
75 go pivotRoot(cooked)
76 }
77 }
78}
79
80func deletePid(cooked Event) {
81 // 在这套逻辑里,孩子是不需要收容的,因为我们根本就不看ppid来工作
82 // 父节点那里也不需要销户
83 // 理论上这里需要关闭所有文件描述符,但为了处理效率,留给后续流程
84 err := pidCol.UpdateOne(bson.M{"pid": cooked.pid}, bson.M{
85 "$set": bson.M{
86 "exit_timestamp": cooked.timestamp,
87 "exit_code": cooked.exit_code,
88 "exit_signal": cooked.exit_signal,
89 },
90 })
91 if err != nil {
92 fmt.Fprintf(os.Stderr, "Err updating: %v\n", err)
93 }
94}
95
96func dealNewPid(cooked Event) {
97 // 自身是否已经记录
98 var docRes []Process
99 err = pidCol.Finddoc(bson.M{"pid": cooked.pid}, &docRes)
100 if err != nil {
101 fmt.Fprintf(os.Stderr, "Err finding: %v\n", err)
102 return
103 }
104
105 if len(docRes) != 0 {
106 // 进程原本就存在,换言之别的消息先到了
107 // 所有先行抵达的消息必须保留execve/children字段
108 docRes[0].Ppid = cooked.ppid
109 docRes[0].ParentTgid = cooked.parentTgid
110 docRes[0].Pid = cooked.pid
111 docRes[0].Tgid = cooked.tgid
112 docRes[0].Cwd = cooked.cwd
113 docRes[0].Comm = cooked.comm
114 docRes[0].Args = cooked.argv
115
116 err := pidCol.ReplaceOne(bson.M{"pid": cooked.pid}, docRes[0])
117 if err != nil {
118 fmt.Fprintf(os.Stderr, "Err replaceing: %v\n", err)
119 }
120 } else {
121 // 这进程本是新修的
122 err := pidCol.InsertOne(Process{
123 StartTimestamp: cooked.timestamp,
124 Ppid: cooked.ppid,
125 ParentTgid: cooked.parentTgid,
126 Pid: cooked.pid,
127 Tgid: cooked.tgid,
128 Args: cooked.argv,
129 Comm: cooked.comm,
130 Cwd: cooked.cwd,
131 Execve: make([]Exec, 0),
132 Children: make([]int, 0),
133 })
134 if err != nil {
135 fmt.Fprintf(os.Stderr, "Err inserting: %v\n", err)
136 }
137 }
138
139 err := pidCol.UpdateOne(bson.M{"pid": cooked.ppid}, bson.M{
140 "$push": bson.M{
141 "children": cooked.pid,
142 },
143 })
144 if err != nil {
145 fmt.Fprintf(os.Stderr, "Err updating: %v\n", err)
146 }
147}
148
149func dealExecve(cooked Event) {
150 var docRes []Process
151 // 首先检查进程是否存在,如不存在则为之创建
152 err = pidCol.Finddoc(bson.M{"pid": cooked.pid}, &docRes)
153 if err != nil {
154 return
155 }
156
157 if len(docRes) == 1 {
158 // 自身已在,直接记录
159 docRes[0].Execve = append(docRes[0].Execve, Exec{
160 Timestamp: cooked.timestamp,
161 ExecArgs: cooked.argv,
162 })
163
164 err := pidCol.ReplaceOne(bson.M{"pid": cooked.pid}, docRes[0])
165 if err != nil {
166 fmt.Fprintf(os.Stderr, "Err replacing: %v\n", err)
167 }
168 } else {
169 // 先fork抵达,插入
170 process := Process{
171 Ppid: cooked.ppid,
172 Pid: cooked.pid,
173 Execve: make([]Exec, 0),
174 Children: make([]int, 0),
175 }
176 process.Execve = append(process.Execve, Exec{
177 Timestamp: cooked.timestamp,
178 ExecArgs: cooked.argv,
179 })
180
181 err := pidCol.InsertOne(process)
182 if err != nil {
183 fmt.Fprintf(os.Stderr, "Err inserting: %v\n", err)
184 }
185 }
186}
187
188func fileOpen(cooked Event) {
189 // 权限检查过了,不必再查
190 file := File{
191 OpenTimestamp: cooked.timestamp,
192 FileName: cooked.srcPath,
193 Pid: cooked.pid,
194 Fd: cooked.exit_code,
195 Flags: cooked.syscallParam,
196 Written: make([]time.Time, 0),
197 }
198 if cooked.syscallParam[1]&syscall.O_TRUNC != 0 {
199 // 文件以清空方式打开
200 file.Written = append(file.Written, cooked.timestamp)
201 }
202
203 err := fdCol.InsertOne(file)
204 if err != nil {
205 fmt.Fprintf(os.Stderr, "Err inserting: %v\n", err)
206 }
207}
208
209func fileClose(cooked Event) {
210 res, err := fdCol.FindOneAndDelete(bson.M{"pid": cooked.pid, "fd": cooked.syscallParam[0]})
211 if err != nil {
212 return
213 }
214 res["close_timestamp"] = cooked.timestamp
215
216 err = fileCol.InsertOne(res)
217 if err != nil {
218 fmt.Fprintf(os.Stderr, "Err inserting files: %v\n", err)
219 }
220}
221
222func fileWrite(cooked Event) {
223 var res []File
224 err := fdCol.Finddoc(bson.M{
225 "pid": cooked.pid,
226 "fd": cooked.syscallParam[0],
227 }, &res)
228 if err != nil {
229 fmt.Fprintf(os.Stderr, "Err closing fd %d of pid %d: %v\n", cooked.syscallParam[0], cooked.pid, err)
230 }
231 if len(res) == 0 {
232 return
233 }
234
235 err = fdCol.UpdateOne(bson.M{
236 "pid": cooked.pid,
237 "fd": cooked.syscallParam[0],
238 }, bson.M{"$push": bson.M{"written": cooked.timestamp}})
239 if err != nil {
240 fmt.Fprintf(os.Stderr, "Err updating: %v\n", err)
241 }
242}
243
244func pivotRoot(cooked Event) {
245 var docRes []Process
246 // docker的根目录信息,记录
247 err := pidCol.Finddoc(bson.M{"pid": cooked.pid}, &docRes)
248 if err != nil {
249 fmt.Fprintf(os.Stderr, "Err finding: %v\n", err)
250 return
251 }
252
253 if len(docRes) == 0 {
254 // fork还没到,等一下
255 pidCol.InsertOne(bson.M{
256 "start_timestamp": cooked.timestamp,
257 "ppid": cooked.ppid,
258 "pid": cooked.pid,
259 "rootfs": "cwd",
260 })
261 } else {
262 // 读取已有的工作目录
263 pidCol.UpdateOne(bson.M{"pid": cooked.pid}, bson.M{
264 "$set": bson.M{
265 "rootfs": docRes[0].Cwd,
266 },
267 })
268 }
269}
diff --git a/listener/global.go b/listener/global.go
new file mode 100644
index 0000000..11b18bf
--- /dev/null
+++ b/listener/global.go
@@ -0,0 +1,84 @@
1package main
2
3import (
4 "sync"
5 "time"
6)
7
8type eventType int
9
10const (
11 NEWPID eventType = iota
12 PIDEXIT
13 EXECVE
14 FILEOPEN
15 FILECLOSE
16 FILEWRITE
17 PIVOTROOT
18 TYPENUM
19)
20
21func (et eventType) String() string {
22 names := []string{"NEWPID", "PIDEXIT", "EXECVE", "FILEOPEN", "FILECLOSE", "FILEWRITE", "PIVOTROOT", "TYPENUM"}
23 if et < NEWPID || et > TYPENUM {
24 return "Unknown"
25 }
26 return names[et]
27}
28
29type Event struct {
30 tag eventType
31 timestamp time.Time
32 pid, tgid int
33 ppid, parentTgid int
34 syscall int
35 syscallParam [4]uint64
36 argc int
37 argv []string
38 comm string
39 cwd string
40 exit_code int
41 exit_signal int
42 srcPath string
43 destPath string
44}
45
46var wg sync.WaitGroup // 掌管协程
47var rawChan chan interface{} // 从接收到整理的管道
48var cookedChan chan Event // 整理好的信息的管道
49var syscallTable [500]string //记录一下系统调用
50var containerdPid int
51
52// 插入到数据库的结构
53type Exec struct {
54 Timestamp time.Time `bson:"timestamp"`
55 ExecArgs []string `bson:"execArgs"`
56}
57
58type Process struct {
59 Star bool `bson:"star"`
60 StartTimestamp time.Time `bson:"start_timestamp"`
61 Ppid int `bson:"ppid"`
62 ParentTgid int `bson:"parentTgid"`
63 Pid int `bson:"pid"`
64 Tgid int `bson:"tgid"`
65 Args []string `bson:"args"`
66 Comm string `bson:"comm"`
67 RootFS string `bson:"rootfs"`
68 Cwd string `bson:"cwd"`
69 Children []int `bson:"children"`
70 Execve []Exec `bson:"execve"`
71 ExitCode int `bson:"exit_code"`
72 ExitSignal int `bson:"exit_signal"`
73 ExitTimestamp time.Time `bson:"exit_timestamp"`
74}
75
76type File struct {
77 OpenTimestamp time.Time `bson:"timestamp"`
78 FileName string `bson:"fileName"`
79 Pid int `bson:"pid"`
80 Fd int `bson:"fd"`
81 Flags [4]uint64 `bson:"flags"`
82 Written []time.Time `bson:"written"`
83 CloseTimestamp time.Time `bson:"close_timestamp"`
84}
diff --git a/listener/go.mod b/listener/go.mod
new file mode 100644
index 0000000..ed40331
--- /dev/null
+++ b/listener/go.mod
@@ -0,0 +1,26 @@
1module godo
2
3go 1.21.5
4
5require (
6 github.com/elastic/go-libaudit/v2 v2.5.0
7 github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826
8 go.mongodb.org/mongo-driver v1.16.0
9)
10
11require (
12 github.com/golang/snappy v0.0.4 // indirect
13 github.com/klauspost/compress v1.13.6 // indirect
14 github.com/montanaflynn/stats v0.7.1 // indirect
15 github.com/xdg-go/pbkdf2 v1.0.0 // indirect
16 github.com/xdg-go/scram v1.1.2 // indirect
17 github.com/xdg-go/stringprep v1.0.4 // indirect
18 github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect
19 go.uber.org/atomic v1.7.0 // indirect
20 go.uber.org/multierr v1.7.0 // indirect
21 golang.org/x/crypto v0.22.0 // indirect
22 golang.org/x/sync v0.7.0 // indirect
23 golang.org/x/sys v0.19.0 // indirect
24 golang.org/x/text v0.14.0 // indirect
25 gopkg.in/yaml.v3 v3.0.1 // indirect
26)
diff --git a/listener/go.sum b/listener/go.sum
new file mode 100644
index 0000000..9164cd3
--- /dev/null
+++ b/listener/go.sum
@@ -0,0 +1,96 @@
1github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
2github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
3github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
4github.com/elastic/go-libaudit/v2 v2.5.0 h1:5OK919QRnGtcjVBz3n/cs5F42im1mPlVTA9TyIn2K54=
5github.com/elastic/go-libaudit/v2 v2.5.0/go.mod h1:AjlnhinP+kKQuUJoXLVrqxBM8uyhQmkzoV6jjsCFP4Q=
6github.com/elastic/go-licenser v0.4.1 h1:1xDURsc8pL5zYT9R29425J3vkHdt4RT5TNEMeRN48x4=
7github.com/elastic/go-licenser v0.4.1/go.mod h1:V56wHMpmdURfibNBggaSBfqgPxyT1Tldns1i87iTEvU=
8github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
9github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
10github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
11github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
12github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
13github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
14github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc=
15github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
16github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw=
17github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
18github.com/montanaflynn/stats v0.7.1 h1:etflOAAHORrCC44V+aR6Ftzort912ZU+YLiSTuV8eaE=
19github.com/montanaflynn/stats v0.7.1/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow=
20github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
21github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
22github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
23github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
24github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
25github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
26github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
27github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
28github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY=
29github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4=
30github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8=
31github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM=
32github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d h1:splanxYIlg+5LfHAM6xpdFEAYOk8iySO56hMFq6uLyA=
33github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=
34github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
35github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
36go.mongodb.org/mongo-driver v1.16.0 h1:tpRsfBJMROVHKpdGyc1BBEzzjDUWjItxbVSZ8Ls4BQ4=
37go.mongodb.org/mongo-driver v1.16.0/go.mod h1:oB6AhJQvFQL4LEHyXi6aJzQJtBiTQHiAd83l0GdFaiw=
38go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
39go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
40go.uber.org/multierr v1.7.0 h1:zaiO/rmgFjbmCXdSYJWQcdvOCsthmdaHfr3Gm2Kx4Ec=
41go.uber.org/multierr v1.7.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak=
42golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
43golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
44golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
45golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30=
46golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
47golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
48golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
49golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
50golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
51golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
52golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
53golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
54golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
55golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
56golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
57golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
58golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
59golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
60golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
61golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
62golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
63golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
64golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
65golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
66golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
67golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
68golang.org/x/sys v0.0.0-20211102192858-4dd72447c267/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
69golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
70golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
71golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
72golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
73golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
74golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
75golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
76golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
77golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
78golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
79golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
80golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
81golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
82golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
83golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
84golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
85golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
86golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
87golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
88golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
89golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
90golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
91gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
92gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
93gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
94gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
95gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
96gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/listener/go.work b/listener/go.work
new file mode 100644
index 0000000..5b6c957
--- /dev/null
+++ b/listener/go.work
@@ -0,0 +1,6 @@
1go 1.21.5
2
3use (
4 ./netlink
5 ./
6) \ No newline at end of file
diff --git a/listener/go.work.sum b/listener/go.work.sum
new file mode 100644
index 0000000..8201e39
--- /dev/null
+++ b/listener/go.work.sum
@@ -0,0 +1,4 @@
1golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
2golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
3golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk=
4golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
diff --git a/listener/godo.go b/listener/godo.go
new file mode 100644
index 0000000..efe9585
--- /dev/null
+++ b/listener/godo.go
@@ -0,0 +1,176 @@
1package main
2
3import (
4 "bufio"
5 "flag"
6 "fmt"
7 "log"
8 "netlink"
9 "os"
10 "os/exec"
11 "strings"
12 "syscall"
13 "time"
14
15 "github.com/elastic/go-libaudit/v2"
16)
17
18var (
19 fs = flag.NewFlagSet("audit", flag.ExitOnError)
20 diag = fs.String("diag", "", "dump raw information from kernel to file")
21 rate = fs.Uint("rate", 0, "rate limit in kernel (default 0, no rate limit)")
22 backlog = fs.Uint("backlog", 8192, "backlog limit")
23 immutable = fs.Bool("immutable", false, "make kernel audit settings immutable (requires reboot to undo)")
24 receiveOnly = fs.Bool("ro", false, "receive only using multicast, requires kernel 3.16+")
25)
26
27func main() {
28 // 检查用户身份,并添加auditd规则,监听所有syscall
29 if os.Geteuid() != 0 {
30 fmt.Fprintf(os.Stderr, "Err: Please run me as root, %d!\n", os.Getegid())
31 return
32 }
33
34 // 所有的系统调用号与名称的关系
35 err := figureOutSyscalls()
36 if err != nil {
37 fmt.Fprintf(os.Stderr, "Error figuring out syscall numbers: %v\n", err)
38 }
39
40 exec.Command("auditctl", "-D").Run()
41 exec.Command("auditctl", "-b", "1000000000").Run()
42 exec.Command("auditctl", "--reset-lost").Run()
43
44 var auditCmd *exec.Cmd
45
46 pidSyscall := []string{"execve", "pivot_root"}
47 // // 设置监听规则
48 for i := 0; i < len(pidSyscall); i++ {
49 auditCmd = exec.Command("auditctl", "-a", "exit,always", "-F", "arch=b64", "-S", pidSyscall[i])
50 auditCmd.Run()
51 }
52
53 // 监听文件的消息
54 fileSyscall := []string{"open", "close", "write"}
55 // fileSyscall := []string{"open", "write", "creat", "unlink", "opendir", "mkdir", "rmdir", "chmod", "fchmod", "chown", "fchown", "lchown", "flock"}
56 for i := 0; i < len(fileSyscall); i++ {
57 auditCmd = exec.Command("auditctl", "-a", "exit,always", "-F", "arch=b64", "-S", fileSyscall[i])
58 auditCmd.Run()
59 }
60
61 // 查找pid
62 containerdPid, err = getPid()
63 if err != nil {
64 fmt.Fprintf(os.Stderr, "Error finding containerd: %v\n", err)
65 return
66 }
67
68 // 开始运行,解析命令行参数后监听
69 if err := fs.Parse(os.Args[1:]); err != nil {
70 log.Fatal(err)
71 }
72
73 if err := read(); err != nil {
74 log.Fatalf("error: %v", err)
75 }
76}
77
78func coroutine(client *libaudit.AuditClient) {
79 // 各协程至此开始
80 rawChan = make(chan interface{}, 65536)
81 cookedChan = make(chan Event, 65536)
82
83 wg.Add(1)
84 go procWatch()
85
86 wg.Add(1)
87 go receive(client)
88 wg.Add(1)
89 go orgnaze()
90 wg.Add(1)
91 go deal()
92
93 wg.Wait()
94 time.Sleep(2 * time.Second)
95}
96
97func procWatch() error {
98 ns, err := netlink.NewNetlinkSocket(syscall.NETLINK_CONNECTOR, 12345)
99 if err != nil {
100 fmt.Fprintf(os.Stderr, "Error creating socket: %v\n", err)
101 return err
102 }
103 defer ns.Close()
104 for {
105 res, err := ns.Receive(20)
106 if err != nil {
107 fmt.Fprintf(os.Stderr, "Error recv: %v\n", err)
108 continue
109 }
110 for i := 0; i < len(res); i++ {
111 procEvent := netlink.ParseProcEvent(res[i].Data)
112 switch procEvent.What {
113 case netlink.PROC_EVENT_FORK:
114 data := procEvent.Data.(netlink.ProcEventFork)
115 cooked := Event{
116 tag: NEWPID,
117 timestamp: time.Now(),
118 pid: int(data.ChildPid),
119 tgid: int(data.ChildTgid),
120 ppid: int(data.ParentPid),
121 parentTgid: int(data.ParentTgid),
122 }
123 checkProc(&cooked)
124 cookedChan <- cooked
125 case netlink.PROC_EVENT_EXIT:
126 data := procEvent.Data.(netlink.ProcEventExit)
127 cooked := Event{
128 tag: PIDEXIT,
129 timestamp: time.Now(),
130 pid: int(data.ProcessPid),
131 exit_code: int(data.ExitCode),
132 exit_signal: int(data.ExitSignal),
133 }
134 cookedChan <- cooked
135 default:
136 }
137 }
138 }
139}
140
141func checkProc(pCooked *Event) {
142 fileName := fmt.Sprintf("/proc/%d/task/%d/", pCooked.tgid, pCooked.pid)
143 fd, err := os.Open(fileName + "cmdline")
144 if err != nil {
145 fmt.Fprintf(os.Stderr, "Err: %v\n", err)
146 return
147 }
148
149 scanner := bufio.NewScanner(fd)
150 scanner.Split(bufio.ScanLines)
151 for scanner.Scan() {
152 line := scanner.Text()
153 pCooked.argv = append(pCooked.argv, strings.Split(line, "\x00")...)
154 }
155 pCooked.argc = len(pCooked.argv)
156 fd.Close()
157
158 fd, err = os.Open(fileName + "comm")
159 if err != nil {
160 fmt.Fprintf(os.Stderr, "Err: %v\n", err)
161 return
162 }
163 scanner = bufio.NewScanner(fd)
164 scanner.Split(bufio.ScanLines)
165 for scanner.Scan() {
166 line := scanner.Text()
167 pCooked.comm = line
168 }
169 fd.Close()
170
171 pCooked.cwd, err = os.Readlink(fileName + "cwd")
172 if err != nil {
173 fmt.Fprintf(os.Stderr, "Err: %v\n", err)
174 pCooked.cwd = ""
175 }
176}
diff --git a/listener/mongo.go b/listener/mongo.go
new file mode 100644
index 0000000..a51350e
--- /dev/null
+++ b/listener/mongo.go
@@ -0,0 +1,122 @@
1package main
2
3import (
4 "context"
5 "fmt"
6 "reflect"
7 "time"
8
9 "go.mongodb.org/mongo-driver/bson"
10 "go.mongodb.org/mongo-driver/mongo"
11 "go.mongodb.org/mongo-driver/mongo/options"
12)
13
14type mongoClient struct {
15 dbName, colName string
16 client *mongo.Client
17 col *mongo.Collection
18}
19
20func (mc *mongoClient) init(dbName, colName string) error {
21 var err error
22 if err = mc.Connect(dbName, colName); err != nil {
23 return err
24 }
25 if err = mc.Drop(); err != nil {
26 return err
27 }
28
29 return nil
30}
31
32func (mc *mongoClient) Connect(dbName, colName string) error {
33 var err error
34 mc.client, err = mongo.NewClient(options.Client().ApplyURI("mongodb://localhost:27017"))
35
36 if err != nil {
37 return err
38 }
39
40 ctx, _ := context.WithTimeout(context.Background(), 10*time.Second)
41 err = mc.client.Connect(ctx)
42 if err != nil {
43 return err
44 }
45
46 mc.col = mc.client.Database(dbName).Collection(colName)
47 mc.dbName = dbName
48 mc.colName = colName
49 return nil
50}
51
52func (mc *mongoClient) InsertOne(document interface{}) error {
53 _, err := mc.col.InsertOne(context.Background(), document)
54 return err
55}
56
57func (mc *mongoClient) UpdateOne(filter, update interface{}) error {
58 _, err := mc.col.UpdateOne(context.Background(), filter, update)
59 return err
60}
61
62func (mc *mongoClient) UpdateMany(filter, update interface{}) error {
63 _, err := mc.col.UpdateMany(context.Background(), filter, update)
64 return err
65}
66
67func (mc *mongoClient) ReplaceOne(filter, new interface{}) error {
68 _, err := mc.col.ReplaceOne(context.Background(), filter, new)
69 return err
70}
71
72func (mc *mongoClient) Finddoc(filter bson.M, results interface{}) error {
73 sliceValue := reflect.ValueOf(results)
74
75 if sliceValue.Kind() != reflect.Ptr || sliceValue.Elem().Kind() != reflect.Slice {
76 return fmt.Errorf("Error: result argument must be pointer to slice")
77 }
78 cur, err := mc.col.Find(context.TODO(), filter)
79 if err != nil {
80 return err
81 }
82 defer cur.Close(context.TODO())
83
84 elemType := sliceValue.Elem().Type().Elem()
85
86 sliceValue = sliceValue.Elem()
87
88 for cur.Next(context.TODO()) {
89 elem := reflect.New(elemType).Interface()
90 err := cur.Decode(elem)
91 if err != nil {
92 return err
93 }
94 sliceValue = reflect.Append(sliceValue, reflect.ValueOf(elem).Elem())
95 }
96
97 reflect.ValueOf(results).Elem().Set(sliceValue)
98 return nil
99}
100
101func (mc *mongoClient) FindOneAndDelete(filter bson.M) (bson.M, error) {
102 res := mc.col.FindOneAndDelete(context.Background(), filter)
103 var result bson.M
104 err := res.Decode(&result)
105 return result, err
106}
107
108func (mc *mongoClient) Drop() error {
109 return mc.col.Drop(context.Background())
110}
111
112func (mc *mongoClient) Disconnect() error {
113 err := mc.client.Disconnect(context.Background())
114 if err != nil {
115 return err
116 }
117 mc.col = nil
118 mc.client = nil
119 mc.dbName = ""
120 mc.colName = ""
121 return nil
122}
diff --git a/listener/netlink b/listener/netlink
new file mode 160000
Subproject e53c2724725c5991cdd9ea088c26832c5c9fcf0
diff --git a/listener/organize.go b/listener/organize.go
new file mode 100644
index 0000000..0c05eb4
--- /dev/null
+++ b/listener/organize.go
@@ -0,0 +1,291 @@
1package main
2
3import (
4 "fmt"
5 "os"
6 "regexp"
7 "strconv"
8 "strings"
9 "sync"
10 "syscall"
11
12 "github.com/elastic/go-libaudit/v2"
13 "github.com/elastic/go-libaudit/v2/auparse"
14)
15
16// 为每个事务id存储其信息,事务id在操作系统运行期间是唯一的
17var eventTable sync.Map
18
19// 事件信息
20var tmp any
21var ok bool
22var event Event
23var pEvent *Event
24var eventId, argc int
25
26// 要用的正则匹配列表
27var (
28 syscallRegex = regexp.MustCompile(`audit\((\d+\.\d+):(\d+)\).*?syscall=(\d+)(?:.*?exit=([-+]?\d+))?.*?ppid=(\d+) pid=(\d+).*?subj=(.*?):(.*?):(.*?):(.*?) .*?$`)
29 execveRegex = regexp.MustCompile(`audit\(\d+\.\d+:(\d+)\): argc=(\d+)`)
30 argsRegex = regexp.MustCompile(`a\d+=("(.*?)"|([0-9a-fA-F]+))`)
31 pathRegex = regexp.MustCompile(`audit\(\d+\.\d+:(\d+)\): item=(\d+) name="(.*?)" .*objtype=([A-Z]+) `)
32 cwdRegex = regexp.MustCompile(`audit\(\d+\.\d+:(\d+)\): cwd="(.*?)"`)
33 proctitleRegex = regexp.MustCompile(`audit\(\d+\.\d+:(\d+)\): proctitle=("(.*?)"|([0-9a-fA-F]+))$`)
34 eoeRegex = regexp.MustCompile(`audit\(\d+\.\d+:(\d+)\)`)
35)
36
37func orgnaze() {
38 defer wg.Done()
39 defer close(cookedChan)
40 // 接收信息
41 var raw interface{}
42 var rawEvent libaudit.RawAuditMessage
43
44 for {
45 raw, ok = <-rawChan
46 if !ok {
47 break
48 }
49 rawEvent = raw.(libaudit.RawAuditMessage)
50 // fmt.Printf("type=%v msg=%s\n", rawEvent.Type, rawEvent.Data)
51
52 switch rawEvent.Type {
53 case auparse.AUDIT_SYSCALL:
54 syscallRaw(rawEvent)
55 case auparse.AUDIT_EXECVE:
56 execve(rawEvent)
57 case auparse.AUDIT_CWD:
58 cwd(rawEvent)
59 case auparse.AUDIT_PATH:
60 path(rawEvent)
61 case auparse.AUDIT_PROCTITLE:
62 proctitle(rawEvent)
63 case auparse.AUDIT_EOE:
64 eoe(rawEvent)
65 default:
66 }
67 }
68}
69
70func syscallRaw(rawEvent libaudit.RawAuditMessage) {
71 if !syscallRegex.Match(rawEvent.Data) {
72 return
73 }
74
75 var exit int
76 var a [4]uint64
77 var subj [4]string
78 // 捕获基础信息
79 match := syscallRegex.FindSubmatch(rawEvent.Data)
80 event.timestamp, _ = getTimeFromStr(string(match[1]))
81 eventId, _ = strconv.Atoi(string(match[2]))
82 event.syscall, _ = strconv.Atoi(string(match[3]))
83 if string(match[4]) == "" {
84 // exit没捕获到
85 exit = 0
86 } else {
87 exit, _ = strconv.Atoi(string(match[4]))
88 }
89 event.ppid, _ = strconv.Atoi(string(match[5]))
90 event.pid, _ = strconv.Atoi(string(match[6]))
91
92 // 几个subj,说不定会有用
93 for i := 0; i < 4; i++ {
94 subj[i] = string(match[7+i])
95 }
96
97 // 捕获参数
98 if !argsRegex.Match(rawEvent.Data) {
99 fmt.Fprintf(os.Stderr, "Error: don't get args in syscall event!\n")
100 return
101 }
102 argsMatch := argsRegex.FindAllSubmatch(rawEvent.Data, -1)
103 for i := 0; i < 4; i++ {
104 a[i], _ = strconv.ParseUint(string(argsMatch[i][3]), 16, 64)
105 }
106
107 switch syscallTable[event.syscall] {
108 case "execve":
109 eventTable.Store(eventId, &Event{
110 tag: EXECVE,
111 timestamp: event.timestamp,
112 syscall: event.syscall,
113 // exit_code: a[0], // 为啥这么写?
114 ppid: event.ppid,
115 pid: event.pid,
116 argc: 0,
117 argv: make([]string, 0),
118 cwd: "",
119 })
120 case "open":
121 // 检查打开的权限
122 if a[1]&(syscall.O_APPEND|syscall.O_WRONLY|syscall.O_RDWR|syscall.O_TRUNC) == 0 {
123 break
124 }
125 // TRUNC应该被直接标记为改变,而不是打开
126 eventTable.Store(eventId, &Event{
127 tag: FILEOPEN,
128 timestamp: event.timestamp,
129 syscall: event.syscall,
130 exit_code: exit,
131 ppid: event.ppid,
132 pid: event.pid,
133 argc: 0,
134 argv: make([]string, 0),
135 cwd: "",
136 syscallParam: a,
137 srcPath: "",
138 })
139 case "write":
140 eventTable.Store(eventId, &Event{
141 tag: FILEWRITE,
142 timestamp: event.timestamp,
143 syscall: event.syscall,
144 exit_code: exit,
145 ppid: event.ppid,
146 pid: event.pid,
147 argc: 0,
148 argv: make([]string, 0),
149 cwd: "",
150 syscallParam: a,
151 })
152 case "close":
153 // 文件关闭
154 eventTable.Store(eventId, &Event{
155 tag: FILECLOSE,
156 timestamp: event.timestamp,
157 syscall: event.syscall,
158 exit_code: exit,
159 ppid: event.ppid,
160 pid: event.pid,
161 argc: 0,
162 argv: make([]string, 0),
163 cwd: "",
164 syscallParam: a,
165 })
166 case "pivot_root":
167 if subj[2] == "container_runtime_t" {
168 eventTable.Store(eventId, &Event{
169 tag: PIVOTROOT,
170 timestamp: event.timestamp,
171 syscall: event.syscall,
172 ppid: event.ppid,
173 pid: event.pid,
174 syscallParam: a,
175 })
176 }
177 }
178}
179
180func execve(rawEvent libaudit.RawAuditMessage) {
181 if !execveRegex.Match(rawEvent.Data) {
182 return
183 }
184
185 match := execveRegex.FindSubmatch(rawEvent.Data)
186 eventId, _ = strconv.Atoi(string(match[1]))
187 argc, _ = strconv.Atoi(string(match[2]))
188 tmp, ok = eventTable.Load(eventId)
189 if !ok {
190 return
191 }
192 pEvent = tmp.(*Event)
193 if argsRegex.Match(rawEvent.Data) {
194 match := argsRegex.FindAllSubmatch(rawEvent.Data, -1)
195 for i := 0; i < argc; i++ {
196 if len(match[i][2]) == 0 {
197 // 代表着匹配到的是十六进制数
198 str := hexToAscii(string(match[i][3]))
199 pEvent.argv = append(pEvent.argv, str)
200 } else {
201 pEvent.argv = append(pEvent.argv, string(match[i][2]))
202 }
203 }
204 pEvent.argc = argc
205 }
206}
207
208func cwd(rawEvent libaudit.RawAuditMessage) {
209 if !cwdRegex.Match(rawEvent.Data) {
210 return
211 }
212
213 match := cwdRegex.FindSubmatch(rawEvent.Data)
214 eventId, _ = strconv.Atoi(string(match[1]))
215 tmp, ok = eventTable.Load(eventId)
216 if !ok {
217 return
218 }
219 tmp.(*Event).cwd = string(match[2])
220}
221
222func proctitle(rawEvent libaudit.RawAuditMessage) {
223 if !proctitleRegex.Match(rawEvent.Data) {
224 return
225 }
226
227 var cmdline string
228 match := proctitleRegex.FindSubmatch(rawEvent.Data)
229 eventId, _ = strconv.Atoi(string(match[1]))
230 tmp, ok = eventTable.Load(eventId)
231 if !ok {
232 return
233 }
234 pEvent = tmp.(*Event)
235 if pEvent.argc == 0 {
236 // 只有等于0,才证明没经过EXECVE提取参数,才允许使用PROCTITLE提取参数
237 if match[3] == nil {
238 // PROCTITLE写的是十六进制,转换为字符串
239 cmdline = hexToAscii(string(match[4]))
240 } else {
241 cmdline = string(match[3])
242 }
243 pEvent.argv = strings.Split(cmdline, " ")
244 pEvent.argc = len(pEvent.argv)
245 }
246}
247
248func eoe(rawEvent libaudit.RawAuditMessage) {
249 if !eoeRegex.Match(rawEvent.Data) {
250 return
251 }
252
253 match := eoeRegex.FindSubmatch(rawEvent.Data)
254 eventId, _ = strconv.Atoi(string(match[1]))
255 tmp, ok = eventTable.Load(eventId)
256 if !ok {
257 return
258 }
259 cooked := *(tmp.(*Event))
260 cookedChan <- cooked
261 eventTable.Delete(eventId) // 死人别占地
262}
263
264func path(rawEvent libaudit.RawAuditMessage) {
265 if !pathRegex.Match(rawEvent.Data) {
266 return
267 }
268 match := pathRegex.FindSubmatch(rawEvent.Data)
269 eventId, _ = strconv.Atoi(string(match[1]))
270 // item, _ := strconv.Atoi(string(match[2]))
271 name := string(match[3])
272 objtype := string(match[4])
273
274 tmp, ok = eventTable.Load(eventId)
275 if !ok {
276 return
277 }
278 pEvent = tmp.(*Event)
279
280 // 先看看是不是文件操作,再看是不是所在目录
281 if pEvent.tag != FILEOPEN || objtype == "PARENT" {
282 return
283 }
284
285 if pEvent.cwd == "/" || name[0] == '/' {
286 pEvent.srcPath = name
287 } else {
288 pEvent.srcPath = pEvent.cwd + "/" + name
289 }
290 // ATTENTION: 这里需要做路径简化,留给过滤清洗流程吧
291}
diff --git a/listener/receive.go b/listener/receive.go
new file mode 100644
index 0000000..c0dea00
--- /dev/null
+++ b/listener/receive.go
@@ -0,0 +1,29 @@
1package main
2
3import (
4 "fmt"
5
6 "github.com/elastic/go-libaudit/v2"
7 "github.com/elastic/go-libaudit/v2/auparse"
8 "github.com/mohae/deepcopy"
9)
10
11func receive(r *libaudit.AuditClient) error {
12 defer wg.Done()
13 defer close(rawChan)
14 for {
15 rawEvent, err := r.Receive(false)
16 if err != nil {
17 return fmt.Errorf("receive failed: %w", err)
18 }
19
20 // Messages from 1300-2999 are valid audit messages.
21 if rawEvent.Type < auparse.AUDIT_USER_AUTH ||
22 rawEvent.Type > auparse.AUDIT_LAST_USER_MSG2 {
23 continue
24 }
25
26 rawEventMessage := deepcopy.Copy(*rawEvent)
27 rawChan <- rawEventMessage
28 }
29}