aboutsummaryrefslogtreecommitdiffstats
path: root/listener/organize.go
diff options
context:
space:
mode:
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}