diff options
Diffstat (limited to 'src/organize.go')
-rw-r--r-- | src/organize.go | 361 |
1 files changed, 224 insertions, 137 deletions
diff --git a/src/organize.go b/src/organize.go index d963288..679f361 100644 --- a/src/organize.go +++ b/src/organize.go | |||
@@ -6,34 +6,40 @@ import ( | |||
6 | "strconv" | 6 | "strconv" |
7 | "strings" | 7 | "strings" |
8 | "sync" | 8 | "sync" |
9 | "syscall" | ||
9 | 10 | ||
10 | "github.com/elastic/go-libaudit/v2" | 11 | "github.com/elastic/go-libaudit/v2" |
11 | "github.com/elastic/go-libaudit/v2/auparse" | 12 | "github.com/elastic/go-libaudit/v2/auparse" |
12 | ) | 13 | ) |
13 | 14 | ||
15 | // 为每个事务id存储其信息,事务id在操作系统运行期间是唯一的 | ||
16 | var eventTable sync.Map | ||
17 | |||
18 | // 事件信息 | ||
19 | var tmp any | ||
20 | var ok bool | ||
21 | var event Event | ||
22 | var pEvent *Event | ||
23 | var eventId, argc int | ||
24 | var err [6]error | ||
25 | |||
26 | // 要用的正则匹配列表 | ||
27 | var ( | ||
28 | syscallRegex = regexp.MustCompile(`audit\((\d+\.\d+):(\d+)\).*?syscall=(\d+).*?(exit=([-+]?\d+))?.*?ppid=(\d+) pid=(\d+).*?$`) | ||
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+)\):.*?name="(.*?)"`) | ||
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 | |||
14 | func orgnaze() { | 37 | func orgnaze() { |
15 | defer wg.Done() | 38 | defer wg.Done() |
16 | defer close(cookedChan) | 39 | defer close(cookedChan) |
17 | // 接收信息 | 40 | // 接收信息 |
18 | var raw interface{} | 41 | var raw interface{} |
19 | var ok bool | ||
20 | var rawEvent libaudit.RawAuditMessage | 42 | var rawEvent libaudit.RawAuditMessage |
21 | // 事件信息 | ||
22 | var eventId, argc int | ||
23 | var err [6]error | ||
24 | var event Event | ||
25 | var pEvent *Event | ||
26 | var tmp any | ||
27 | // 为每个事务id存储其信息,事务id在操作系统运行期间是唯一的 | ||
28 | var eventTable sync.Map | ||
29 | |||
30 | // 要用的正则匹配列表 | ||
31 | syscallRegex := regexp.MustCompile(`audit\((\d+\.\d+):(\d+)\).*?syscall=(\d+).*?(exit=([-+]?\d+))? a0=([0-9a-fA-F]+).*?ppid=(\d+) pid=(\d+).*?$`) | ||
32 | execveRegex := regexp.MustCompile(`audit\(\d+\.\d+:(\d+)\): argc=(\d+)`) | ||
33 | argsRegex := regexp.MustCompile(`a\d+=("(.*?)"|([0-9a-fA-F]+))`) | ||
34 | cwdRegex := regexp.MustCompile(`audit\(\d+\.\d+:(\d+)\): cwd="(.*?)"`) | ||
35 | proctitleRegex := regexp.MustCompile(`audit\(\d+\.\d+:(\d+)\): proctitle=("(.*?)"|([0-9a-fA-F]+))$`) | ||
36 | eoeRegex := regexp.MustCompile(`audit\(\d+\.\d+:(\d+)\)`) | ||
37 | 43 | ||
38 | for { | 44 | for { |
39 | raw, ok = <-rawChan | 45 | raw, ok = <-rawChan |
@@ -44,132 +50,213 @@ func orgnaze() { | |||
44 | 50 | ||
45 | switch rawEvent.Type { | 51 | switch rawEvent.Type { |
46 | case auparse.AUDIT_SYSCALL: | 52 | case auparse.AUDIT_SYSCALL: |
47 | if syscallRegex.Match(rawEvent.Data) { | 53 | syscallRaw(rawEvent) |
48 | match := syscallRegex.FindSubmatch(rawEvent.Data) | ||
49 | event.timestamp, err[0] = getTimeFromStr(string(match[1])) | ||
50 | eventId, err[1] = strconv.Atoi(string(match[2])) | ||
51 | event.syscall, err[2] = strconv.Atoi(string(match[3])) | ||
52 | var exit int | ||
53 | var a0 uint64 | ||
54 | if string(match[5]) == "" { | ||
55 | // exit没捕获到 | ||
56 | exit = 0 | ||
57 | } else { | ||
58 | exit, err[3] = strconv.Atoi(string(match[5])) | ||
59 | } | ||
60 | if string(match[6]) == "" { | ||
61 | a0 = 0 | ||
62 | } else { | ||
63 | // 系统调用的第一个参数 | ||
64 | // exit和exit_group都是syscall_define1,只有一个参数 | ||
65 | // fork没参数,clone几个参数不重要 | ||
66 | // execve三个参数咱也不关心 | ||
67 | // 所以看第一个就够了 | ||
68 | a0, err[4] = strconv.ParseUint(string(match[6]), 16, 64) | ||
69 | } | ||
70 | event.ppid, err[4] = strconv.Atoi(string(match[7])) | ||
71 | event.pid, err[5] = strconv.Atoi(string(match[8])) | ||
72 | if syscallTable[event.syscall] == "clone" { | ||
73 | if exit == 0 || event.pid > exit { | ||
74 | // exit=0是给新进程的返回,没用 | ||
75 | // pid>exit,证明有问题,抛弃 | ||
76 | break | ||
77 | } else { | ||
78 | eventTable.Store(eventId, &Event{ | ||
79 | timestamp: event.timestamp, | ||
80 | syscall: event.syscall, | ||
81 | exit_code: 0, | ||
82 | ppid: event.pid, | ||
83 | pid: exit, | ||
84 | argc: 0, | ||
85 | argv: make([]string, 0), | ||
86 | cwd: "", | ||
87 | }) | ||
88 | } | ||
89 | } else { | ||
90 | eventTable.Store(eventId, &Event{ | ||
91 | timestamp: event.timestamp, | ||
92 | syscall: event.syscall, | ||
93 | exit_code: a0, | ||
94 | ppid: event.ppid, | ||
95 | pid: event.pid, | ||
96 | argc: 0, | ||
97 | argv: make([]string, 0), | ||
98 | cwd: "", | ||
99 | }) | ||
100 | } | ||
101 | } | ||
102 | case auparse.AUDIT_EXECVE: | 54 | case auparse.AUDIT_EXECVE: |
103 | if execveRegex.Match(rawEvent.Data) { | 55 | execve(rawEvent) |
104 | match := execveRegex.FindSubmatch(rawEvent.Data) | ||
105 | eventId, err[0] = strconv.Atoi(string(match[1])) | ||
106 | argc, err[1] = strconv.Atoi(string(match[2])) | ||
107 | tmp, ok = eventTable.Load(eventId) | ||
108 | if !ok { | ||
109 | break | ||
110 | } | ||
111 | pEvent = tmp.(*Event) | ||
112 | if err[0] == nil && err[1] == nil && argsRegex.Match(rawEvent.Data) { | ||
113 | match := argsRegex.FindAllSubmatch(rawEvent.Data, -1) | ||
114 | for i := 0; i < argc; i++ { | ||
115 | if len(match[i][2]) == 0 { | ||
116 | // 代表着匹配到的是十六进制数 | ||
117 | str := hexToAscii(string(match[i][3])) | ||
118 | pEvent.argv = append(pEvent.argv, str) | ||
119 | } else { | ||
120 | pEvent.argv = append(pEvent.argv, string(match[i][2])) | ||
121 | } | ||
122 | } | ||
123 | pEvent.argc = argc | ||
124 | } | ||
125 | } | ||
126 | case auparse.AUDIT_CWD: | 56 | case auparse.AUDIT_CWD: |
127 | if cwdRegex.Match(rawEvent.Data) { | 57 | cwd(rawEvent) |
128 | match := cwdRegex.FindSubmatch(rawEvent.Data) | 58 | case auparse.AUDIT_PATH: |
129 | eventId, err[0] = strconv.Atoi(string(match[1])) | 59 | path(rawEvent) |
130 | tmp, ok = eventTable.Load(eventId) | ||
131 | if !ok { | ||
132 | break | ||
133 | } | ||
134 | tmp.(*Event).cwd = string(match[2]) | ||
135 | } | ||
136 | case auparse.AUDIT_PROCTITLE: | 60 | case auparse.AUDIT_PROCTITLE: |
137 | if proctitleRegex.Match(rawEvent.Data) { | 61 | proctitle(rawEvent) |
138 | var cmdline string | ||
139 | match := proctitleRegex.FindSubmatch(rawEvent.Data) | ||
140 | eventId, err[0] = strconv.Atoi(string(match[1])) | ||
141 | tmp, ok = eventTable.Load(eventId) | ||
142 | if !ok { | ||
143 | break | ||
144 | } | ||
145 | pEvent = tmp.(*Event) | ||
146 | if pEvent.argc == 0 { | ||
147 | // 只有等于0,才证明没经过EXECVE提取参数,才允许使用PROCTITLE提取参数 | ||
148 | if match[3] == nil { | ||
149 | // PROCTITLE写的是十六进制,转换为字符串 | ||
150 | cmdline = hexToAscii(string(match[4])) | ||
151 | } else { | ||
152 | cmdline = string(match[3]) | ||
153 | } | ||
154 | pEvent.argv = strings.Split(cmdline, " ") | ||
155 | pEvent.argc = len(pEvent.argv) | ||
156 | } | ||
157 | } | ||
158 | case auparse.AUDIT_EOE: | 62 | case auparse.AUDIT_EOE: |
159 | if eoeRegex.Match(rawEvent.Data) { | 63 | eoe(rawEvent) |
160 | match := eoeRegex.FindSubmatch(rawEvent.Data) | ||
161 | eventId, err[0] = strconv.Atoi(string(match[1])) | ||
162 | tmp, ok = eventTable.Load(eventId) | ||
163 | if !ok { | ||
164 | break | ||
165 | } | ||
166 | cooked := *(tmp.(*Event)) | ||
167 | cookedChan <- cooked | ||
168 | eventTable.Delete(eventId) // 死人别占地 | ||
169 | fmt.Printf("%d: %3d %6d %6d\n", eventId, cooked.syscall, cooked.ppid, cooked.pid) | ||
170 | } | ||
171 | default: | 64 | default: |
172 | // ATTENTION: 这里也需要做防护 | 65 | // ATTENTION: 这里也需要做防护 |
173 | } | 66 | } |
174 | } | 67 | } |
175 | } | 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 | // 捕获基础信息 | ||
78 | match := syscallRegex.FindSubmatch(rawEvent.Data) | ||
79 | event.timestamp, err[0] = getTimeFromStr(string(match[1])) | ||
80 | eventId, err[1] = strconv.Atoi(string(match[2])) | ||
81 | event.syscall, err[2] = strconv.Atoi(string(match[3])) | ||
82 | if string(match[5]) == "" { | ||
83 | // exit没捕获到 | ||
84 | exit = 0 | ||
85 | } else { | ||
86 | exit, err[3] = strconv.Atoi(string(match[5])) | ||
87 | } | ||
88 | event.ppid, err[4] = strconv.Atoi(string(match[6])) | ||
89 | event.pid, err[5] = strconv.Atoi(string(match[7])) | ||
90 | |||
91 | // 捕获参数 | ||
92 | if !argsRegex.Match(rawEvent.Data) { | ||
93 | fmt.Printf("Error: don't get args in syscall event!\n") | ||
94 | return | ||
95 | } | ||
96 | argsMatch := argsRegex.FindAllSubmatch(rawEvent.Data, -1) | ||
97 | for i := 0; i < 4; i++ { | ||
98 | a[i], err[0] = strconv.ParseUint(string(argsMatch[i][2]), 16, 64) | ||
99 | } | ||
100 | |||
101 | switch syscallTable[event.syscall] { | ||
102 | case "clone": | ||
103 | if exit == 0 || event.pid > exit { | ||
104 | // exit=0是给新进程的返回,没用 | ||
105 | // pid>exit,证明有问题,抛弃 | ||
106 | break | ||
107 | } else { | ||
108 | eventTable.Store(eventId, &Event{ | ||
109 | tag: NEWPID, | ||
110 | timestamp: event.timestamp, | ||
111 | syscall: event.syscall, | ||
112 | exit_code: 0, | ||
113 | ppid: event.pid, | ||
114 | pid: exit, | ||
115 | argc: 0, | ||
116 | argv: make([]string, 0), | ||
117 | cwd: "", | ||
118 | }) | ||
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: uint64(exit), | ||
131 | ppid: event.ppid, | ||
132 | pid: event.pid, | ||
133 | argc: 0, | ||
134 | argv: make([]string, 0), | ||
135 | cwd: "", | ||
136 | syscallParam: a, | ||
137 | pathName: "", | ||
138 | }) | ||
139 | case "exit", "exit_group": | ||
140 | eventTable.Store(eventId, &Event{ | ||
141 | tag: PIDEXIT, | ||
142 | timestamp: event.timestamp, | ||
143 | syscall: event.syscall, | ||
144 | exit_code: a[0], | ||
145 | ppid: event.ppid, | ||
146 | pid: event.pid, | ||
147 | argc: 0, | ||
148 | argv: make([]string, 0), | ||
149 | cwd: "", | ||
150 | }) | ||
151 | } | ||
152 | } | ||
153 | |||
154 | func execve(rawEvent libaudit.RawAuditMessage) { | ||
155 | if !execveRegex.Match(rawEvent.Data) { | ||
156 | return | ||
157 | } | ||
158 | |||
159 | match := execveRegex.FindSubmatch(rawEvent.Data) | ||
160 | eventId, err[0] = strconv.Atoi(string(match[1])) | ||
161 | argc, err[1] = strconv.Atoi(string(match[2])) | ||
162 | tmp, ok = eventTable.Load(eventId) | ||
163 | if !ok { | ||
164 | return | ||
165 | } | ||
166 | pEvent = tmp.(*Event) | ||
167 | if err[0] == nil && err[1] == nil && argsRegex.Match(rawEvent.Data) { | ||
168 | match := argsRegex.FindAllSubmatch(rawEvent.Data, -1) | ||
169 | for i := 0; i < argc; i++ { | ||
170 | if len(match[i][2]) == 0 { | ||
171 | // 代表着匹配到的是十六进制数 | ||
172 | str := hexToAscii(string(match[i][3])) | ||
173 | pEvent.argv = append(pEvent.argv, str) | ||
174 | } else { | ||
175 | pEvent.argv = append(pEvent.argv, string(match[i][2])) | ||
176 | } | ||
177 | } | ||
178 | pEvent.argc = argc | ||
179 | } | ||
180 | } | ||
181 | |||
182 | func cwd(rawEvent libaudit.RawAuditMessage) { | ||
183 | if !cwdRegex.Match(rawEvent.Data) { | ||
184 | return | ||
185 | } | ||
186 | |||
187 | match := cwdRegex.FindSubmatch(rawEvent.Data) | ||
188 | eventId, err[0] = strconv.Atoi(string(match[1])) | ||
189 | tmp, ok = eventTable.Load(eventId) | ||
190 | if !ok { | ||
191 | return | ||
192 | } | ||
193 | tmp.(*Event).cwd = string(match[2]) | ||
194 | } | ||
195 | |||
196 | func proctitle(rawEvent libaudit.RawAuditMessage) { | ||
197 | if !proctitleRegex.Match(rawEvent.Data) { | ||
198 | return | ||
199 | } | ||
200 | |||
201 | var cmdline string | ||
202 | match := proctitleRegex.FindSubmatch(rawEvent.Data) | ||
203 | eventId, err[0] = strconv.Atoi(string(match[1])) | ||
204 | tmp, ok = eventTable.Load(eventId) | ||
205 | if !ok { | ||
206 | return | ||
207 | } | ||
208 | pEvent = tmp.(*Event) | ||
209 | if pEvent.argc == 0 { | ||
210 | // 只有等于0,才证明没经过EXECVE提取参数,才允许使用PROCTITLE提取参数 | ||
211 | if match[3] == nil { | ||
212 | // PROCTITLE写的是十六进制,转换为字符串 | ||
213 | cmdline = hexToAscii(string(match[4])) | ||
214 | } else { | ||
215 | cmdline = string(match[3]) | ||
216 | } | ||
217 | pEvent.argv = strings.Split(cmdline, " ") | ||
218 | pEvent.argc = len(pEvent.argv) | ||
219 | } | ||
220 | } | ||
221 | |||
222 | func eoe(rawEvent libaudit.RawAuditMessage) { | ||
223 | if !eoeRegex.Match(rawEvent.Data) { | ||
224 | return | ||
225 | } | ||
226 | |||
227 | match := eoeRegex.FindSubmatch(rawEvent.Data) | ||
228 | eventId, err[0] = strconv.Atoi(string(match[1])) | ||
229 | tmp, ok = eventTable.Load(eventId) | ||
230 | if !ok { | ||
231 | return | ||
232 | } | ||
233 | cooked := *(tmp.(*Event)) | ||
234 | cookedChan <- cooked | ||
235 | eventTable.Delete(eventId) // 死人别占地 | ||
236 | } | ||
237 | |||
238 | func path(rawEvent libaudit.RawAuditMessage) { | ||
239 | if !pathRegex.Match(rawEvent.Data) { | ||
240 | return | ||
241 | } | ||
242 | match := pathRegex.FindSubmatch(rawEvent.Data) | ||
243 | eventId, err[0] = strconv.Atoi(string(match[1])) | ||
244 | name := string(match[2]) | ||
245 | |||
246 | tmp, ok = eventTable.Load(eventId) | ||
247 | if !ok { | ||
248 | return | ||
249 | } | ||
250 | pEvent = tmp.(*Event) | ||
251 | |||
252 | // 先看看是不是文件操作 | ||
253 | if pEvent.tag != FILEOPEN { | ||
254 | return | ||
255 | } | ||
256 | |||
257 | if pEvent.pathName == "" { | ||
258 | pEvent.pathName = name | ||
259 | } else { | ||
260 | pEvent.pathName += "/" + name | ||
261 | } | ||
262 | } | ||