diff options
Diffstat (limited to 'listener/organize.go')
-rw-r--r-- | listener/organize.go | 291 |
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 @@ | |||
1 | package main | ||
2 | |||
3 | import ( | ||
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在操作系统运行期间是唯一的 | ||
17 | var eventTable sync.Map | ||
18 | |||
19 | // 事件信息 | ||
20 | var tmp any | ||
21 | var ok bool | ||
22 | var event Event | ||
23 | var pEvent *Event | ||
24 | var eventId, argc int | ||
25 | |||
26 | // 要用的正则匹配列表 | ||
27 | var ( | ||
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 | |||
37 | func 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 | |||
70 | func 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 | |||
180 | func 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 | |||
208 | func 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 | |||
222 | func 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 | |||
248 | func 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 | |||
264 | func 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 | } | ||