-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathsyspce_parser.py
More file actions
280 lines (229 loc) · 7.55 KB
/
syspce_parser.py
File metadata and controls
280 lines (229 loc) · 7.55 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
import logging
import xml.etree.ElementTree as ET
import re
log = logging.getLogger('sysmoncorrelator')
class ParseError(Exception):
"""Base class for exceptions in this module."""
pass
class KeyNotFound(ParseError):
"""Exception raised for errors finding Sysmon registry key.
Attributes:
message -- explanation of the error
"""
def __init__(self, message):
self.log_message = "Missing Sysmon/Operational registry key: " + message
self.message = self.log_message
self.message += "\tAdd key located in RegistryKey directory"
self.message += "\tSee README for more info"
log.error(self.log_message)
class WrongSchema(ParseError):
"""Exception raised for errors parsing with a concrete schema.
Attributes:
message -- explanation of the error
"""
def __init__(self, message):
self.log_message = "[Error] Probably wrong Sysmon Schema version: " + message + "\n"
self.message = self.log_message
self.message += "\tUse: #sysmon -s > schemaVersion.xml\n"
self.message += "\tThen: #python syspce.py -s schemaVersion.xml\n"
log.error(self.log_message)
def get_image_fileName(image):
ImageFileName = ''
try:
ImageFileName = image.split('\\')[-1].lower()
except Exception , e:
log.error("Getting ImageFileName: %s" % str(e))
return ImageFileName
def get_sysmon_xml_schema(xmlfile):
try:
tree = ET.parse(xmlfile)
root = tree.getroot()
events = root[1]
except Exception, e:
log.error("Parsing XML Schema: %s" % e)
return {}
return events
def parse_eventlog_IDx(schema, event):
event_details = {'computer': '', 'idEvent': event.EventID}
message = event.StringInserts
i = 0
if not message:
raise KeyNotFound
for line in message:
#special case for error 255
if event.EventID == 255:
event.EventID = 0
try:
event_parameter = schema[event.EventID][i].attrib['name']
event_parameter = normalize_event_parameter(event_parameter)
event_details[ event_parameter ] = line
except Exception, e:
raise WrongSchema(str(e))
i += 1
try:
event_details['computer'] = get_machine_guid(event_details['ProcessGuid'])
except Exception, e:
raise WrongSchema(str(e))
return event_details
def get_machine_guid(ProcessGuid):
''' Function for getting MachineGUID from ProcessGUID
'''
trunk_guid = re.match(r"\{(\w{8})", ProcessGuid)
return trunk_guid.group(1)
def get_list_of_actions(action):
'''
There are special events that we need to manage as two diferent actions,
associated to Source and target Image process nodes:
Event 8, 10, 1 -> 108, 110, 100
So if we find an ID 8 we need to return both 8 and the new one 108
'''
try:
action_list = [action]
newreq = action.copy()
multi_action = False
if (action['idEvent'] == 8):
newreq['idEvent'] = 108
aux = newreq['TargetProcessGuid']
newreq['SourceProcessGuid'] = newreq['ProcessGuid']
newreq['ProcessGuid'] = aux
aux = newreq['TargetImage']
newreq['SourceImage'] = newreq['Image']
newreq['Image'] = aux
aux = newreq['TargetProcessId']
newreq['SourceProcessId'] = newreq['ProcessId']
newreq['ProcessId'] = aux
action_list.append(newreq)
elif (action['idEvent'] == 10):
newreq['idEvent'] = 110
aux = newreq['TargetProcessGuid']
newreq['SourceProcessGuid'] = newreq['ProcessGuid']
newreq['ProcessGuid'] = aux
aux = newreq['TargetImage']
newreq['SourceImage'] = newreq['Image']
newreq['Image'] = aux
aux = newreq['TargetProcessId']
newreq['SourceProcessId'] = newreq['ProcessId']
newreq['ProcessId'] = aux
action_list.append(newreq)
elif (action['idEvent'] == 1):
newreq = {}
newreq['computer'] = action['computer']
newreq['idEvent'] = 100
newreq['ChildProcessGuid'] = action['ProcessGuid']
newreq['ChildProcessId'] = action['ProcessId']
newreq['ChildCommandLine'] = action['CommandLine']
newreq['ChildLogonGuid'] = action['LogonGuid']
newreq['ChildImage'] = action['Image']
newreq['ProcessGuid'] = action['ParentProcessGuid']
newreq['ProcessId'] = action['ParentProcessId']
newreq['Image'] = action['ParentImage']
newreq['UtcTime'] = action['UtcTime']
action_list.append(newreq)
else:
newreq = {}
except Exception, e:
raise KeyNotFound(str(e))
return action_list
def normalize_event_parameter(parameter):
#Special case for events 10 and 8. Ej. SourceImage -> Image
parameter = parameter.replace('Source', '')
parameter = parameter.replace('GUID', 'Guid')
return parameter
def get_action_from_id(id):
if id == 1:
return "PROCESS CREATED"
elif id == 2:
return "[A] FILE TIME CHANGED"
elif id == 3:
return "[A] CONNECTION TO"
elif id == 5:
return "[A] PROCESS TERMINATE"
elif id == 7:
return "[A] IMAGE LOADED"
elif id == 8:
return "[A] CREATE REMOTE THREAD TO"
elif id == 9:
return "[A] RAW ACCESS READ"
elif id == 10:
return "[A] OPEN REMOTE PROCESS"
elif id == 11:
return "[A] FILE CREATE"
elif id == 12:
return "[A] REG KEY ADDED"
elif id == 13:
return "[A] REG KEY SET VALUE"
elif id == 14:
return "[A] REG KEY RENAMED"
elif id == 15:
return "[A] ALTERNATE DATA STREAM CREATED"
elif id == 17:
return "[A] PIPE CREATED"
elif id == 18:
return "[A] PIPE CONNECTED"
elif id == 22:
return "[A] DNS QUERY"
elif id == 23:
return "[A] FILE DELETE"
elif id == 100:
return "[A] CHILD PROCESS CREATED"
elif id == 101:
return "[A] THREAD CREATED"
elif id == 102:
return "[A] VAD CREATED"
elif id == 103:
return "[A] TOKEN CREATED"
elif id == 108:
return "[A] STARTED THREAD CREATED BY REMOTE PROCESS"
elif id == 110:
return "[A] PROCESS WAS OPENED BY"
else:
return ""
def get_default_parameter_from_id(id):
if id == 1:
return "Image"
elif id == 2:
return "TargetFilename"
elif id == 3:
return "DestinationIp"
elif id == 5:
return "Image"
elif id == 7:
return "ImageLoaded"
elif id == 8:
return "TargetImage"
elif id == 9:
return "Device"
elif id == 10:
return "TargetImage"
elif id == 11:
return "TargetFilename"
elif id == 12:
return "TargetObject"
elif id == 13:
return "TargetObject"
elif id == 14:
return "TargetObject"
elif id == 15:
return "TargetFilename"
elif id == 17:
return "PipeName"
elif id == 18:
return "PipeName"
elif id == 22:
return "QueryName"
elif id == 23:
return "TargetFilename"
elif id == 100:
return "ChildImage"
elif id == 101:
return "ThreadId"
elif id == 102:
return "VadNode"
elif id == 103:
return "User"
elif id == 108:
return "SourceImage"
elif id == 110:
return "SourceImage"
else:
return "UNKNOW ACTION"