"""Symantec AV Corporate Edition and Endpoint Protection log file parser."""
from dfdatetime import time_elements as dfdatetime_time_elements
from plaso.containers import events
from plaso.lib import errors
from plaso.parsers import dsv_parser
from plaso.parsers import manager
[docs]
class SymantecEventData(events.EventData):
"""Symantec event data.
Attributes:
access (str): access.
action0 (str): action0.
action1 (str): action1.
action1_status (str): action1 status.
action2 (str): action2.
action2_status (str): action2 status.
address (str): address.
backup_id (str): backup identifier.
cat (str): category.
cleaninfo (str): clean information.
clientgroup (str): client group.
compressed (str): compressed.
computer (str): computer.
definfo (str): definfo.
defseqnumber (str): def sequence number.
deleteinfo (str): delete information.
depth (str): depth.
description (str): description.
domain_guid (str): domain identifier (GUID).
domainname (str): domain name.
err_code (str): error code.
event_data (str): event data.
event (str): event.
extra (str): extra.
file (str): file.
flags (str): flags.
groupid (str): group identifier.
guid (str): guid.
last_written_time (dfdatetime.DateTimeValues): entry last written date and
time.
license_expiration_dt (str): license expiration date.
license_feature_name (str): license feature name.
license_feature_ver (str): license feature ver.
license_fulfillment_id (str): license fulfillment identifier.
license_lifecycle (str): license lifecycle.
license_seats_delta (str): license seats delta.
license_seats (str): license seats.
license_seats_total (str): license seats total.
license_serial_num (str): license serial number.
license_start_dt (str): license start date.
logger (str): logger.
login_domain (str): login domain.
log_session_guid (str): log session identifier (GUID).
macaddr (str): MAC address.
new_ext (str): new ext.
ntdomain (str): ntdomain.
offset (str): offset.
parent (str): parent.
quarfwd_status (str): quarfwd status.
remote_machine_ip (str): remote machine IP address.
remote_machine (str): remote machine.
scanid (str): scan identifier.
snd_status (str): snd status.
status (str): status.
still_infected (str): still infected.
time (str): time.
user (str): user.
vbin_id (str): vbin identifier.
vbin_session_id (str): vbin session identifier.
version (str): version.
virus_id (str): virus identifier.
virus (str): virus.
virustype (str): virustype.
"""
DATA_TYPE = "av:symantec:scanlog"
[docs]
def __init__(self):
"""Initializes event data."""
super().__init__(data_type=self.DATA_TYPE)
self.access = None
self.action0 = None
self.action1 = None
self.action1_status = None
self.action2 = None
self.action2_status = None
self.address = None
self.backup_id = None
self.cat = None
self.cleaninfo = None
self.clientgroup = None
self.compressed = None
self.computer = None
self.definfo = None
self.defseqnumber = None
self.deleteinfo = None
self.depth = None
self.description = None
self.domain_guid = None
self.domainname = None
self.err_code = None
self.event_data = None
self.event = None
self.extra = None
self.file = None
self.flags = None
self.groupid = None
self.guid = None
self.last_written_time = None
self.license_expiration_dt = None
self.license_feature_name = None
self.license_feature_ver = None
self.license_fulfillment_id = None
self.license_lifecycle = None
self.license_seats_delta = None
self.license_seats = None
self.license_seats_total = None
self.license_serial_num = None
self.license_start_dt = None
self.logger = None
self.login_domain = None
self.log_session_guid = None
self.macaddr = None
self.new_ext = None
self.ntdomain = None
self.offset = None
self.parent = None
self.quarfwd_status = None
self.remote_machine_ip = None
self.remote_machine = None
self.scanid = None
self.snd_status = None
self.status = None
self.still_infected = None
self.time = None
self.user = None
self.vbin_id = None
self.vbin_session_id = None
self.version = None
self.virus_id = None
self.virus = None
self.virustype = None
[docs]
class SymantecParser(dsv_parser.DSVParser):
"""Parses Symantec AV Corporate Edition and Endpoint Protection log files."""
NAME = "symantec_scanlog"
DATA_FORMAT = "Symantec AV Corporate Edition and Endpoint Protection log file"
# Define the columns that make up the structure of a Symantec log file.
# http://www.symantec.com/docs/TECH100099
COLUMNS = [
"time",
"event",
"cat",
"logger",
"computer",
"user",
"virus",
"file",
"action1",
"action2",
"action0",
"virustype",
"flags",
"description",
"scanid",
"new_ext",
"groupid",
"event_data",
"vbin_id",
"virus_id",
"quarfwd_status",
"access",
"snd_status",
"compressed",
"depth",
"still_infected",
"definfo",
"defseqnumber",
"cleaninfo",
"deleteinfo",
"backup_id",
"parent",
"guid",
"clientgroup",
"address",
"domainname",
"ntdomain",
"macaddr",
"version:",
"remote_machine",
"remote_machine_ip",
"action1_status",
"action2_status",
"license_feature_name",
"license_feature_ver",
"license_serial_num",
"license_fulfillment_id",
"license_start_dt",
"license_expiration_dt",
"license_lifecycle",
"license_seats_total",
"license_seats",
"err_code",
"license_seats_delta",
"status",
"domain_guid",
"log_session_guid",
"vbin_session_id",
"login_domain",
"extra",
]
def _ParseTimestamp(self, timestamp):
"""Parses a Symantec log timestamp.
A Symantec log timestamp consist of six hexadecimal octets, that represent:
First octet: Number of years since 1970
Second octet: Month, where 0 represents January.
Third octet: Day of the month
Fourth octet: Number of hours
Fifth octet: Number of minutes
Sixth octet: Number of seconds
For example, 200A13080122 represents November 19, 2002, 8:01:34 AM.
Args:
timestamp (str): hexadecimal encoded date and time values.
Returns:
dfdatetime.TimeElements: date and time value.
Raises:
ParseError: if a valid date and time value cannot be derived from
the time elements.
"""
try:
year, month, day_of_month, hours, minutes, seconds = (
int(hexdigit[0] + hexdigit[1], 16)
for hexdigit in zip(timestamp[::2], timestamp[1::2])
)
time_elements_tuple = (
1970 + year,
month + 1,
day_of_month,
hours,
minutes,
seconds,
)
date_time = dfdatetime_time_elements.TimeElements(
time_elements_tuple=time_elements_tuple
)
date_time.is_local_time = True
return date_time
except (TypeError, ValueError) as exception:
raise errors.ParseError(
f"Unable to parse time elements with error: {exception!s}"
)
[docs]
def ParseRow(self, parser_mediator, row_offset, row):
"""Parses a line of the log file and produces events.
Args:
parser_mediator (ParserMediator): mediates interactions between parsers
and other components, such as storage and dfVFS.
row_offset (int): line number of the row.
row (dict[str, str]): fields of a single row, as specified in COLUMNS.
"""
timestamp = row["time"]
# TODO: remove unused attributes.
event_data = SymantecEventData()
event_data.access = row.get("access")
event_data.action0 = row.get("action0")
event_data.action1 = row.get("action1")
event_data.action1_status = row.get("action1_status")
event_data.action2 = row.get("action2")
event_data.action2_status = row.get("action2_status")
event_data.address = row.get("address")
event_data.backup_id = row.get("backup_id")
event_data.cat = row.get("cat")
event_data.cleaninfo = row.get("cleaninfo")
event_data.clientgroup = row.get("clientgroup")
event_data.compressed = row.get("compressed")
event_data.computer = row.get("computer")
event_data.definfo = row.get("definfo")
event_data.defseqnumber = row.get("defseqnumber")
event_data.deleteinfo = row.get("deleteinfo")
event_data.depth = row.get("depth")
event_data.description = row.get("description")
event_data.domain_guid = row.get("domain_guid")
event_data.domainname = row.get("domainname")
event_data.err_code = row.get("err_code")
event_data.event_data = row.get("event_data")
event_data.event = row.get("event")
event_data.extra = row.get("extra")
event_data.file = row.get("file")
event_data.flags = row.get("flags")
event_data.groupid = row.get("groupid")
event_data.guid = row.get("guid")
event_data.last_written_time = self._ParseTimestamp(timestamp)
event_data.license_expiration_dt = row.get("license_expiration_dt")
event_data.license_feature_name = row.get("license_feature_name")
event_data.license_feature_ver = row.get("license_feature_ver")
event_data.license_fulfillment_id = row.get("license_fulfillment_id")
event_data.license_lifecycle = row.get("license_lifecycle")
event_data.license_seats_delta = row.get("license_seats_delta")
event_data.license_seats = row.get("license_seats")
event_data.license_seats_total = row.get("license_seats_total")
event_data.license_serial_num = row.get("license_serial_num")
event_data.license_start_dt = row.get("license_start_dt")
event_data.logger = row.get("logger")
event_data.login_domain = row.get("login_domain")
event_data.log_session_guid = row.get("log_session_guid")
event_data.macaddr = row.get("macaddr")
event_data.new_ext = row.get("new_ext")
event_data.ntdomain = row.get("ntdomain")
event_data.offset = row_offset
event_data.parent = row.get("parent")
event_data.quarfwd_status = row.get("quarfwd_status")
event_data.remote_machine_ip = row.get("remote_machine_ip")
event_data.remote_machine = row.get("remote_machine")
event_data.scanid = row.get("scanid")
event_data.snd_status = row.get("snd_status")
event_data.status = row.get("status")
event_data.still_infected = row.get("still_infected")
event_data.time = row.get("time")
event_data.user = row.get("user")
event_data.vbin_id = row.get("vbin_id")
event_data.vbin_session_id = row.get("vbin_session_id")
event_data.version = row.get("version:")
event_data.virus_id = row.get("virus_id")
event_data.virus = row.get("virus")
event_data.virustype = row.get("virustype")
parser_mediator.ProduceEventData(event_data)
[docs]
def VerifyRow(self, parser_mediator, row):
"""Verifies if a line of the file is in the expected format.
Args:
parser_mediator (ParserMediator): mediates interactions between parsers
and other components, such as storage and dfVFS.
row (dict[str, str]): fields of a single row, as specified in COLUMNS.
Returns:
bool: True if this is the correct parser, False otherwise.
"""
timestamp = row["time"]
try:
self._ParseTimestamp(timestamp)
except errors.ParseError:
return False
try:
my_event = int(row["event"], 10)
except (TypeError, ValueError):
return False
if my_event < 1 or my_event > 77:
return False
try:
category = int(row["cat"], 10)
except (TypeError, ValueError):
return False
if category < 1 or category > 4:
return False
return True
manager.ParsersManager.RegisterParser(SymantecParser)