OLD | NEW |
1 # -*- coding: utf-8 -*- | 1 # -*- coding: utf-8 -*- |
2 """This file contains a Symantec parser in plaso.""" | 2 """This file contains a Symantec parser in plaso.""" |
3 | 3 |
4 from __future__ import unicode_literals | 4 from __future__ import unicode_literals |
5 | 5 |
| 6 from dfdatetime import time_elements as dfdatetime_time_elements |
| 7 |
6 from plaso.containers import events | 8 from plaso.containers import events |
7 from plaso.containers import time_events | 9 from plaso.containers import time_events |
8 from plaso.lib import errors | |
9 from plaso.lib import definitions | 10 from plaso.lib import definitions |
10 from plaso.lib import timelib | |
11 from plaso.parsers import dsv_parser | 11 from plaso.parsers import dsv_parser |
12 from plaso.parsers import manager | 12 from plaso.parsers import manager |
13 | 13 |
14 import pytz # pylint: disable=wrong-import-order | |
15 | |
16 | 14 |
17 class SymantecEventData(events.EventData): | 15 class SymantecEventData(events.EventData): |
18 """Symantec event data. | 16 """Symantec event data. |
19 | 17 |
20 Attributes: | 18 Attributes: |
21 access (str): access. | 19 access (str): access. |
22 action0 (str): action0. | 20 action0 (str): action0. |
23 action1 (str): action1. | 21 action1 (str): action1. |
24 action1_status (str): action1 status. | 22 action1_status (str): action1 status. |
25 action2 (str): action2. | 23 action2 (str): action2. |
26 action2_status (str): action2 status. | 24 action2_status (str): action2 status. |
27 address (str): address. | 25 address (str): address. |
28 backup_id (str): backup id. | 26 backup_id (str): backup identifier. |
29 cat (str): cat. | 27 cat (str): category. |
30 cleaninfo (str): cleaninfo. | 28 cleaninfo (str): clean information. |
31 clientgroup (str): clientgroup. | 29 clientgroup (str): client group. |
32 compressed (str): compressed. | 30 compressed (str): compressed. |
33 computer (str): computer. | 31 computer (str): computer. |
34 definfo (str): definfo. | 32 definfo (str): definfo. |
35 defseqnumber (str): defseqnumber. | 33 defseqnumber (str): def sequence number. |
36 deleteinfo (str): deleteinfo. | 34 deleteinfo (str): delete information. |
37 depth (str): depth. | 35 depth (str): depth. |
38 description (str): description. | 36 description (str): description. |
39 domain_guid (str): domain guid. | 37 domain_guid (str): domain identifier (GUID). |
40 domainname (str): domainname. | 38 domainname (str): domain name. |
41 err_code (str): err code. | 39 err_code (str): error code. |
42 event_data (str): event data. | 40 event_data (str): event data. |
43 event (str): event. | 41 event (str): event. |
44 extra (str): extra. | 42 extra (str): extra. |
45 file (str): file. | 43 file (str): file. |
46 flags (str): flags. | 44 flags (str): flags. |
47 groupid (str): groupid. | 45 groupid (str): group identifier. |
48 guid (str): guid. | 46 guid (str): guid. |
49 license_expiration_dt (str): license expiration dt. | 47 license_expiration_dt (str): license expiration date. |
50 license_feature_name (str): license feature name. | 48 license_feature_name (str): license feature name. |
51 license_feature_ver (str): license feature ver. | 49 license_feature_ver (str): license feature ver. |
52 license_fulfillment_id (str): license fulfillment id. | 50 license_fulfillment_id (str): license fulfillment identifier. |
53 license_lifecycle (str): license lifecycle. | 51 license_lifecycle (str): license lifecycle. |
54 license_seats_delta (str): license seats delta. | 52 license_seats_delta (str): license seats delta. |
55 license_seats (str): license seats. | 53 license_seats (str): license seats. |
56 license_seats_total (str): license seats total. | 54 license_seats_total (str): license seats total. |
57 license_serial_num (str): license serial num. | 55 license_serial_num (str): license serial number. |
58 license_start_dt (str): license start dt. | 56 license_start_dt (str): license start date. |
59 logger (str): logger. | 57 logger (str): logger. |
60 login_domain (str): login domain. | 58 login_domain (str): login domain. |
61 log_session_guid (str): log session guid. | 59 log_session_guid (str): log session identifier (GUID). |
62 macaddr (str): macaddr. | 60 macaddr (str): MAC address. |
63 new_ext (str): new ext. | 61 new_ext (str): new ext. |
64 ntdomain (str): ntdomain. | 62 ntdomain (str): ntdomain. |
65 offset (str): offset. | 63 offset (str): offset. |
66 parent (str): parent. | 64 parent (str): parent. |
67 quarfwd_status (str): quarfwd status. | 65 quarfwd_status (str): quarfwd status. |
68 remote_machine_ip (str): remote machine ip. | 66 remote_machine_ip (str): remote machine IP address. |
69 remote_machine (str): remote machine. | 67 remote_machine (str): remote machine. |
70 scanid (str): scanid. | 68 scanid (str): scan identifier. |
71 snd_status (str): snd status. | 69 snd_status (str): snd status. |
72 status (str): status. | 70 status (str): status. |
73 still_infected (str): still infected. | 71 still_infected (str): still infected. |
74 time (str): time. | 72 time (str): time. |
75 user (str): user. | 73 user (str): user. |
76 vbin_id (str): vbin id. | 74 vbin_id (str): vbin identifier. |
77 vbin_session_id (str): vbin session id. | 75 vbin_session_id (str): vbin session identifier. |
78 version (str): version. | 76 version (str): version. |
79 virus_id (str): virus id. | 77 virus_id (str): virus identifier. |
80 virus (str): virus. | 78 virus (str): virus. |
81 virustype (str): virustype. | 79 virustype (str): virustype. |
82 """ | 80 """ |
83 | 81 |
84 DATA_TYPE = 'av:symantec:scanlog' | 82 DATA_TYPE = 'av:symantec:scanlog' |
85 | 83 |
86 def __init__(self): | 84 def __init__(self): |
87 """Initializes event data.""" | 85 """Initializes event data.""" |
88 super(SymantecEventData, self).__init__(data_type=self.DATA_TYPE) | 86 super(SymantecEventData, self).__init__(data_type=self.DATA_TYPE) |
89 self.access = None | 87 self.access = None |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
143 self.user = None | 141 self.user = None |
144 self.vbin_id = None | 142 self.vbin_id = None |
145 self.vbin_session_id = None | 143 self.vbin_session_id = None |
146 self.version = None | 144 self.version = None |
147 self.virus_id = None | 145 self.virus_id = None |
148 self.virus = None | 146 self.virus = None |
149 self.virustype = None | 147 self.virustype = None |
150 | 148 |
151 | 149 |
152 class SymantecParser(dsv_parser.DSVParser): | 150 class SymantecParser(dsv_parser.DSVParser): |
153 """Parse Symantec AV Corporate Edition and Endpoint Protection log files.""" | 151 """Parses Symantec AV Corporate Edition and Endpoint Protection log files.""" |
154 | 152 |
155 NAME = 'symantec_scanlog' | 153 NAME = 'symantec_scanlog' |
156 DESCRIPTION = 'Parser for Symantec Anti-Virus log files.' | 154 DESCRIPTION = 'Parser for Symantec Anti-Virus log files.' |
157 | 155 |
158 # Define the columns that make up the structure of a Symantec log file. | 156 # Define the columns that make up the structure of a Symantec log file. |
159 # http://www.symantec.com/docs/TECH100099 | 157 # http://www.symantec.com/docs/TECH100099 |
160 COLUMNS = [ | 158 COLUMNS = [ |
161 'time', 'event', 'cat', 'logger', 'computer', 'user', | 159 'time', 'event', 'cat', 'logger', 'computer', 'user', |
162 'virus', 'file', 'action1', 'action2', 'action0', 'virustype', | 160 'virus', 'file', 'action1', 'action2', 'action0', 'virustype', |
163 'flags', 'description', 'scanid', 'new_ext', 'groupid', | 161 'flags', 'description', 'scanid', 'new_ext', 'groupid', |
164 'event_data', 'vbin_id', 'virus_id', 'quarfwd_status', | 162 'event_data', 'vbin_id', 'virus_id', 'quarfwd_status', |
165 'access', 'snd_status', 'compressed', 'depth', 'still_infected', | 163 'access', 'snd_status', 'compressed', 'depth', 'still_infected', |
166 'definfo', 'defseqnumber', 'cleaninfo', 'deleteinfo', | 164 'definfo', 'defseqnumber', 'cleaninfo', 'deleteinfo', |
167 'backup_id', 'parent', 'guid', 'clientgroup', 'address', | 165 'backup_id', 'parent', 'guid', 'clientgroup', 'address', |
168 'domainname', 'ntdomain', 'macaddr', 'version:', | 166 'domainname', 'ntdomain', 'macaddr', 'version:', |
169 'remote_machine', 'remote_machine_ip', 'action1_status', | 167 'remote_machine', 'remote_machine_ip', 'action1_status', |
170 'action2_status', 'license_feature_name', 'license_feature_ver', | 168 'action2_status', 'license_feature_name', 'license_feature_ver', |
171 'license_serial_num', 'license_fulfillment_id', 'license_start_dt', | 169 'license_serial_num', 'license_fulfillment_id', 'license_start_dt', |
172 'license_expiration_dt', 'license_lifecycle', 'license_seats_total', | 170 'license_expiration_dt', 'license_lifecycle', 'license_seats_total', |
173 'license_seats', 'err_code', 'license_seats_delta', 'status', | 171 'license_seats', 'err_code', 'license_seats_delta', 'status', |
174 'domain_guid', 'log_session_guid', 'vbin_session_id', | 172 'domain_guid', 'log_session_guid', 'vbin_session_id', |
175 'login_domain', 'extra'] | 173 'login_domain', 'extra'] |
176 | 174 |
177 def _ConvertToTimestamp(self, date_time_values, timezone=pytz.UTC): | 175 def _GetTimeElementsTuple(self, timestamp): |
178 """Converts the given parsed date and time values to a timestamp. | 176 """Retrieves a time elements tuple from the timestamp. |
179 | 177 |
180 The date and time values consist of six hexadecimal octets. | 178 A Symantec log timestamp consist of six hexadecimal octets, that represent: |
181 They represent the following: | |
182 First octet: Number of years since 1970 | 179 First octet: Number of years since 1970 |
183 Second octet: Month, where January = 0 | 180 Second octet: Month, where January is represented by 0 |
184 Third octet: Day | 181 Third octet: Day of the month |
185 Fourth octet: Hour | 182 Fourth octet: Number of hours |
186 Fifth octet: Minute | 183 Fifth octet: Number of minutes |
187 Sixth octet: Second | 184 Sixth octet: Number of seconds |
188 | 185 |
189 For example, 200A13080122 represents November 19, 2002, 8:01:34 AM. | 186 For example, 200A13080122 represents November 19, 2002, 8:01:34 AM. |
190 | 187 |
191 Args: | 188 Args: |
192 date_time_values: The hexadecimal encoded date and time values. | 189 timestamp (str): hexadecimal encoded date and time values. |
193 timezone: Optional timezone (instance of pytz.timezone). | |
194 | 190 |
195 Returns: | 191 Returns: |
196 A timestamp value, contains the number of micro seconds since | 192 tuple: contains: |
197 January 1, 1970, 00:00:00 UTC. | 193 year (int): year. |
| 194 month (int): month, where 1 represents January. |
| 195 day_of_month (int): day of month, where 1 is the first day of the month. |
| 196 hours (int): hours. |
| 197 minutes (int): minutes. |
| 198 seconds (int): seconds. |
198 """ | 199 """ |
199 if not date_time_values: | 200 year, month, day_of_month, hours, minutes, seconds = ( |
200 return timelib.Timestamp.NONE_TIMESTAMP | 201 int(hexdigit[0] + hexdigit[1], 16) for hexdigit in zip( |
| 202 timestamp[::2], timestamp[1::2])) |
201 | 203 |
202 year, month, day, hours, minutes, seconds = ( | 204 return (year + 1970, month + 1, day_of_month, hours, minutes, seconds) |
203 int(hexdigit[0] + hexdigit[1], 16) for hexdigit in zip( | |
204 date_time_values[::2], date_time_values[1::2])) | |
205 | |
206 return timelib.Timestamp.FromTimeParts( | |
207 year + 1970, month + 1, day, hours, minutes, seconds, timezone=timezone) | |
208 | 205 |
209 def ParseRow(self, parser_mediator, row_offset, row): | 206 def ParseRow(self, parser_mediator, row_offset, row): |
210 """Parses a line of the log file and produces events. | 207 """Parses a line of the log file and produces events. |
211 | 208 |
212 Args: | 209 Args: |
213 parser_mediator (ParserMediator): mediates interactions between parsers | 210 parser_mediator (ParserMediator): mediates interactions between parsers |
214 and other components, such as storage and dfvfs. | 211 and other components, such as storage and dfvfs. |
215 row_offset (int): line number of the row. | 212 row_offset (int): line number of the row. |
216 row (dict[str, str]): fields of a single row, as specified in COLUMNS. | 213 row (dict[str, str]): fields of a single row, as specified in COLUMNS. |
217 """ | 214 """ |
| 215 time_elements_tuple = self._GetTimeElementsTuple(row['time']) |
| 216 |
218 try: | 217 try: |
219 timestamp = self._ConvertToTimestamp( | 218 date_time = dfdatetime_time_elements.TimeElements( |
220 row['time'], timezone=parser_mediator.timezone) | 219 time_elements_tuple=time_elements_tuple) |
221 except (TypeError, ValueError, errors.TimestampError) as exception: | 220 date_time.is_local_time = True |
222 timestamp = timelib.Timestamp.NONE_TIMESTAMP | 221 except ValueError: |
223 parser_mediator.ProduceExtractionError( | 222 parser_mediator.ProduceExtractionError( |
224 'unable to determine timestamp with error: {0!s}'.format( | 223 'invalid date time value: {0!s}'.format(time_elements_tuple)) |
225 exception)) | 224 return |
226 | 225 |
227 # TODO: remove unused attributes. | 226 # TODO: remove unused attributes. |
228 event_data = SymantecEventData() | 227 event_data = SymantecEventData() |
229 event_data.access = row.get('access', None) | 228 event_data.access = row.get('access', None) |
230 event_data.action0 = row.get('action0', None) | 229 event_data.action0 = row.get('action0', None) |
231 event_data.action1 = row.get('action1', None) | 230 event_data.action1 = row.get('action1', None) |
232 event_data.action1_status = row.get('action1_status', None) | 231 event_data.action1_status = row.get('action1_status', None) |
233 event_data.action2 = row.get('action2', None) | 232 event_data.action2 = row.get('action2', None) |
234 event_data.action2_status = row.get('action2_status', None) | 233 event_data.action2_status = row.get('action2_status', None) |
235 event_data.address = row.get('address', None) | 234 event_data.address = row.get('address', None) |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
281 event_data.still_infected = row.get('still_infected', None) | 280 event_data.still_infected = row.get('still_infected', None) |
282 event_data.time = row.get('time', None) | 281 event_data.time = row.get('time', None) |
283 event_data.user = row.get('user', None) | 282 event_data.user = row.get('user', None) |
284 event_data.vbin_id = row.get('vbin_id', None) | 283 event_data.vbin_id = row.get('vbin_id', None) |
285 event_data.vbin_session_id = row.get('vbin_session_id', None) | 284 event_data.vbin_session_id = row.get('vbin_session_id', None) |
286 event_data.version = row.get('version:', None) | 285 event_data.version = row.get('version:', None) |
287 event_data.virus_id = row.get('virus_id', None) | 286 event_data.virus_id = row.get('virus_id', None) |
288 event_data.virus = row.get('virus', None) | 287 event_data.virus = row.get('virus', None) |
289 event_data.virustype = row.get('virustype', None) | 288 event_data.virustype = row.get('virustype', None) |
290 | 289 |
291 event = time_events.TimestampEvent( | 290 event = time_events.DateTimeValuesEvent( |
292 timestamp, definitions.TIME_DESCRIPTION_WRITTEN) | 291 date_time, definitions.TIME_DESCRIPTION_WRITTEN) |
293 parser_mediator.ProduceEventWithEventData(event, event_data) | 292 parser_mediator.ProduceEventWithEventData(event, event_data) |
294 | 293 |
295 def VerifyRow(self, parser_mediator, row): | 294 def VerifyRow(self, parser_mediator, row): |
296 """Verifies if a line of the file is in the expected format. | 295 """Verifies if a line of the file is in the expected format. |
297 | 296 |
298 Args: | 297 Args: |
299 parser_mediator (ParserMediator): mediates interactions between parsers | 298 parser_mediator (ParserMediator): mediates interactions between parsers |
300 and other components, such as storage and dfvfs. | 299 and other components, such as storage and dfvfs. |
301 row (dict[str, str]): fields of a single row, as specified in COLUMNS. | 300 row (dict[str, str]): fields of a single row, as specified in COLUMNS. |
302 | 301 |
303 Returns: | 302 Returns: |
304 bool: True if this is the correct parser, False otherwise. | 303 bool: True if this is the correct parser, False otherwise. |
305 """ | 304 """ |
| 305 time_elements_tuple = self._GetTimeElementsTuple(row['time']) |
| 306 |
306 try: | 307 try: |
307 timestamp = self._ConvertToTimestamp( | 308 dfdatetime_time_elements.TimeElements( |
308 row['time'], timezone=parser_mediator.timezone) | 309 time_elements_tuple=time_elements_tuple) |
309 except (TypeError, ValueError, errors.TimestampError): | 310 except ValueError: |
310 return False | 311 return False |
311 | 312 |
312 if not timestamp: | |
313 return False | |
314 | |
315 # Check few entries. | |
316 try: | 313 try: |
317 my_event = int(row['event']) | 314 my_event = int(row['event'], 10) |
318 except (TypeError, ValueError): | 315 except (TypeError, ValueError): |
319 return False | 316 return False |
320 | 317 |
321 if my_event < 1 or my_event > 77: | 318 if my_event < 1 or my_event > 77: |
322 return False | 319 return False |
323 | 320 |
324 try: | 321 try: |
325 category = int(row['cat']) | 322 category = int(row['cat'], 10) |
326 except (TypeError, ValueError): | 323 except (TypeError, ValueError): |
327 return False | 324 return False |
328 | 325 |
329 if category < 1 or category > 4: | 326 if category < 1 or category > 4: |
330 return False | 327 return False |
331 | 328 |
332 return True | 329 return True |
333 | 330 |
334 | 331 |
335 manager.ParsersManager.RegisterParser(SymantecParser) | 332 manager.ParsersManager.RegisterParser(SymantecParser) |
OLD | NEW |