aboutsummaryrefslogtreecommitdiffstats
path: root/listener/organize.go
diff options
context:
space:
mode:
authorWe-unite <3205135446@qq.com>2024-08-09 13:56:37 +0800
committerWe-unite <3205135446@qq.com>2024-08-12 14:16:51 +0800
commit3e49a044d22635157916651f0acb5a062397b34b (patch)
tree254cd9a2605fa003f4579e7c5510e6e2aea19375 /listener/organize.go
parentea32e017e579f168d87732893335c38d539ac2f1 (diff)
downloadgodo-3e49a044d22635157916651f0acb5a062397b34b.tar.gz
godo-3e49a044d22635157916651f0acb5a062397b34b.zip
Add db structure, fix filePath, start filtering
This commit I made several changes: - Use structure instead of simple bson.M(interface{}). bson.M has some shortcomings: 1) It makes the database in chaos and hard to read, but this's not important; 2) Some entrys may has more or less content than others, which makes it hard to decode and filt. So I design new data structure to encode and decode. Hopes that there's no bugs. - Fix the way to calculate file path. The original method is to add all the PATH entries together, that's totally wrong! PATH entry has several types, as it shows in "objtype". I can't find it in the kernel src code, so what i know is just "PARENT" means the dir the file is in, while the filename itself has the path, so we whould ignore all "PARENT"s. When the src code is found, we should check it again. - Fix bugs in updating. The update function of mongodb is set to required to has a '$' such as 'set'/'push', so when we update a whole doc, we should use replace but not update function. And, we should never ignore the error infomation it gives us. Hope that there's no more bugs for this Big Change. Now its' time to write filter as well as viewer. Best wishes with NO BUGS!
Diffstat (limited to 'listener/organize.go')
-rw-r--r--listener/organize.go291
1 files changed, 291 insertions, 0 deletions
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}