summaryrefslogtreecommitdiffstats
path: root/src/organize.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/organize.go')
-rw-r--r--src/organize.go361
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在操作系统运行期间是唯一的
16var eventTable sync.Map
17
18// 事件信息
19var tmp any
20var ok bool
21var event Event
22var pEvent *Event
23var eventId, argc int
24var err [6]error
25
26// 要用的正则匹配列表
27var (
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
14func orgnaze() { 37func 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
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 // 捕获基础信息
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
154func 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
182func 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
196func 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
222func 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
238func 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}