Source code for dynamite_sdk.objects.events

import pandas as pd

from ipaddress import ip_address
from dateutil.parser import parse as date_parse


[docs]class InvalidEventError(Exception): """ Thrown when an unexpected raw event format is encountered """ def __init__(self, message): """ :param message: A more specific error message """ msg = "An error occurred while parsing an event: {}".format(message) super(InvalidEventError, self).__init__(msg)
[docs]class InvalidConnectionEventError(Exception): """ Thrown when an unexpected raw conn event format is encountered """ def __init__(self, message): """ :param message: A more specific error message """ msg = "An error occurred while parsing a conn event: {}".format(message) super(InvalidConnectionEventError, self).__init__(msg)
[docs]class InvalidDhcpEventError(Exception): """ Thrown when an unexpected raw dhcp event format is encountered """ def __init__(self, message): """ :param message: A more specific error message """ msg = "An error occurred while parsing a dhcp event: {}".format(message) super(InvalidDhcpEventError, self).__init__(msg)
[docs]class InvalidDnsEventError(Exception): """ Thrown when an unexpected raw dns event format is encountered """ def __init__(self, message): """ :param message: A more specific error message """ msg = "An error occurred while parsing a dns event: {}".format(message) super(InvalidDnsEventError, self).__init__(msg)
[docs]class InvalidHttpEventError(Exception): """ Thrown when an unexpected raw http event format is encountered """ def __init__(self, message): """ :param message: A more specific error message """ msg = "An error occurred while parsing a http event: {}".format(message) super(InvalidHttpEventError, self).__init__(msg)
[docs]class InvalidSipEventError(Exception): """ Thrown when an unexpected raw sip event format is encountered """ def __init__(self, message): """ :param message: A more specific error message """ msg = "An error occurred while parsing a sip event: {}".format(message) super(InvalidSipEventError, self).__init__(msg)
[docs]class InvalidSnmpEventError(Exception): """ Thrown when an unexpected raw snmp event format is encountered """ def __init__(self, message): """ :param message: A more specific error message """ msg = "An error occurred while parsing a snmp event: {}".format(message) super(InvalidSnmpEventError, self).__init__(msg)
[docs]class InvalidSshEventError(Exception): """ Thrown when an unexpected raw ssh event format is encountered """ def __init__(self, message): """ :param message: A more specific error message """ msg = "An error occurred while parsing a ssh event: {}".format(message) super(InvalidSshEventError, self).__init__(msg)
[docs]class Event: """ Super generic Event; any Zeek/Flow event can be normalized into this object """ def __init__(self, raw_event_document: dict): self.raw_event_document = raw_event_document self.event_type = None #: The type of event (Either "flow" or a Zeek log prefix) self.event_time = None #: The UTC-0 time at which the event occurred self.source_ip_address = None #: The sender IP in the event self.destination_ip_address = None #: The recipient IP in the event self.source_port = None #: The sender port in the event self.destination_port = None #: The recipient port in the event self.elasticsearch_index = None #: The ElasticSearch index where the event was found self.originating_agent_tag = None #: The friendly name of the agent (Zeek events only) self.forwarder_type = None #: Either "zeek" or "netflow" self.node_ip_address = None #: The ip_address of the originating host (collector/agent IP) self.node_hostname = None #: The hostname of the originating host (collector/agent hostname) self.uid = None #: The unique id for the Zeek connection self._parse_raw_event() def _parse_raw_event(self) -> None: """ Parse common zeek/flow fields :return: None """ try: self.elasticsearch_index = self.raw_event_document['_index'] except KeyError: raise InvalidEventError('Missing index field') try: _source = self.raw_event_document['_source'] except KeyError: raise InvalidEventError('Missing _source section') try: self.node_ip_address = ip_address(_source['node']['ipaddr']) except KeyError: raise InvalidEventError('Missing node_ip_address field') except ValueError: raise InvalidEventError('Invalid node_ip_address field [{}]'.format(_source['node']['ipaddr'])) try: self.originating_agent_tag = _source['fields']['originating_agent_tag'] self.forwarder_type = 'zeek' except KeyError: self.forwarder_type = 'netflow' try: self.node_hostname = _source['node']['hostname'] except KeyError: raise InvalidEventError('Missing node_hostname field') try: self.event_type = _source['event_type'] except KeyError: raise InvalidEventError('Missing event_type field') try: self.event_time = date_parse(_source['@timestamp']) except KeyError: raise InvalidEventError('Missing event_time field') except ValueError: raise InvalidEventError('Invalid event_time field [{}]'.format(_source['@timestamp'])) try: self.source_ip_address = _source['flow']['src_addr'] except KeyError: try: self.source_ip_address = _source['zeek']['id.orig_h'] except KeyError: try: self.source_ip_address = _source['zeek']['client_addr'] except KeyError: InvalidEventError('Missing source_ip_addressess field') try: self.source_ip_address = ip_address(self.source_ip_address) except ValueError: raise InvalidEventError('Invalid source_ip_address field [{}]'.format(self.source_ip_address)) try: self.destination_ip_address = _source['flow']['dst_addr'] except KeyError: try: self.destination_ip_address = _source['zeek']['id.resp_h'] except KeyError: try: self.destination_ip_address = _source['zeek']['server_addr'] except KeyError: InvalidEventError('Missing destination_ip_address field') try: self.destination_ip_address = ip_address(self.destination_ip_address) except ValueError: raise ('Invalid destination_ip_addr field [{}]'.format(self.destination_ip_address)) try: self.source_port = _source['flow']['src_port'] except KeyError: try: self.source_port = _source['zeek']['id.orig_p'] except KeyError: try: self.source_port = _source['zeek']['client_port'] except KeyError: pass try: self.destination_port = _source['flow']['dst_port'] except KeyError: try: self.destination_port = _source['zeek']['id.resp_p'] except KeyError: try: self.destination_port = _source['zeek']['server_port'] except KeyError: pass try: self.uid = _source['zeek']['uid'] except KeyError: try: self.uid = _source['zeek']['uids'][0] except (KeyError, IndexError): pass def __str__(self): """ :return: High-level representation of the connection [ssl][2017-10-09 15:52:34+00:00]192.168.1.201:39334 -> 192.168.1.250:443 """ return '[{}][{}][{}]{}:{} -> {}:{}'.format(self.forwarder_type, self.event_type, self.event_time, self.source_ip_address, self.source_port, self.destination_ip_address, self.destination_port)
[docs] def to_dataframe(self) -> pd.DataFrame: """ :return: DataFrame containng the field headings and single of of values """ ignore_vars = ['raw_event_document', 'attributes'] headers = [var for var in vars(self) if var not in ignore_vars] data = [[getattr(self, header) for header in headers]] return pd.DataFrame(data, columns=headers)
[docs]class ConnectionEvent(Event): """ Represents a log generated either by a NetFlow forwarder OR Zeek conn.log https://docs.zeek.org/en/stable/scripts/base/protocols/conn/main.zeek.html#type-Conn::Info """ def __init__(self, raw_event_document: dict): super().__init__(raw_event_document) self.ip_protocol = None #: Layer3 transport protocol TCP/UDP/ICMP self.total_bytes = None #: Total bytes both sent and received self.total_packets = None #: Total packets sent self.service_port = None #: A recognized service port (non-ephemeral) self.client_ip_address = None #: The IP address of the client in the conversation self.server_ip_address = None #: The IP address of the server in the conversation self.client_hostname = None #: The hostname of the client in the conversation self.server_hostname = None #: The hostname of the server in the conversation self.source_mac_address = None #: The Layer2 MAC address of the source device self.destination_mac_address = None #: The Layer2 MAC address of the destination device self.source_autonomous_system = None #: The name corresponding to an ASN for the source system self.destination_autonomous_system = None #: The name corresponding to an ASN for the destination system self.client_autonomous_system = None #: The name corresponding to an ASN for the client system self.server_autonomous_system = None #: The name corresponding to an ASN for the server system self.source_city = None #: The city for the source in the conversation self.source_country = None #: The country for the source in the conversation self.source_country_code = None #: The country code for the source in the conversation self.source_geo_location = None #: The geographical coordinates for the source in the conversation self.destination_city = None #: The city for the destination in the conversation self.destination_country = None #: The country for the destination in the conversation self.destination_country_code = None #: The country code for the destination in the conversation self.destination_geo_location = None #: The geographical coordinates for the dst in the conversation self.client_city = None #: The city for the client in the conversation self.client_country = None #: The country for the client in the conversation self.client_country_code = None #: The country code for the client in the conversation self.client_geo_location = None #: The geographical coordinates for the client in the conversation self.server_city = None #: The city for the server in the conversation self.server_country = None #: The country for the server in the conversation self.server_country_code = None #: The country code for the server in the conversation self.server_geo_location = None #: The geographical coordinates for the server in the conversation # Zeek Only self.service = None #: An identification of an application protocol being sent self.connection_state = None #: The state of the connection self.duration = None #: The number of seconds for a given connection self.originated_locally = None #: True, if the connection originated from inside the network self.source_bytes = None #: The number of bytes sent self.destination_bytes = None #: The number of bytes received self.source_packets = None #: The number of packets sent self.destination_packets = None #: The number of packets received self.history = None #: The state history of connections as a string of letters self.uid = None #: A unique identifier for the connection self._parse_raw_conn_event() delattr(self, 'raw_event_document') def _parse_raw_conn_event(self) -> None: if self.event_type != 'conn': raise InvalidConnectionEventError('Invalid conn record, got [{}]'.format(self.event_type)) _source = self.raw_event_document['_source'] self.ip_protocol = _source['flow'].get('ip_protocol') self.total_bytes = _source['flow'].get('bytes') self.total_packets = _source['flow'].get('packets') self.service_port = _source['flow'].get('service_port') self.client_ip_address = _source['flow'].get('client_addr') self.server_ip_address = _source['flow'].get('server_addr') self.client_hostname = _source['flow'].get('client_hostname') self.server_hostname = _source['flow'].get('server_hostname') self.source_mac_address = _source['flow'].get('source_mac_address') self.destination_mac_address = _source['flow'].get('destination_mac_address') self.source_autonomous_system = _source['flow'].get('src_autonomous_system') self.destination_autonomous_system = _source['flow'].get('dst_autonomous_system') self.client_autonomous_system = _source['flow'].get('client_autonomous_system') self.server_autonomous_system = _source['flow'].get('server_autonomous_system') self.source_city = _source['flow'].get('src_city') self.source_country = _source['flow'].get('src_country') self.source_country_code = _source['flow'].get('src_country_code') self.destination_city = _source['flow'].get('dst_city') self.destination_country = _source['flow'].get('dst_country') self.destination_country_code = _source['flow'].get('dst_country_code') self.client_city = _source['flow'].get('client_city') self.client_country = _source['flow'].get('client_country') self.client_country_code = _source['flow'].get('client_country_code') self.server_city = _source['flow'].get('server_city') self.server_country = _source['flow'].get('server_country') self.server_country_code = _source['flow'].get('server_country_code') source_geo_location = _source['flow'].get('src_geo_location') destination_geo_location = _source['flow'].get('dst_geo_location') if isinstance(source_geo_location, dict): self.source_geo_location = source_geo_location.get('lat'), source_geo_location.get('lon') if isinstance(destination_geo_location, dict): self.destination_geo_location = destination_geo_location.get('lat'), destination_geo_location.get('lon') self.client_geo_location = _source['flow'].get('client_geo_location') self.server_geo_location = _source['flow'].get('server_geo_location') try: self.client_ip_address = ip_address(self.client_ip_address) except ValueError: InvalidConnectionEventError('Invalid client_ip_address field') try: self.server_ip_address = ip_address(self.server_ip_address) except ValueError: InvalidConnectionEventError('Invalid server_ip_address field') # Get Zeek specific conn.log fields try: self.service = _source['zeek'].get('service') self.connection_state = _source['zeek'].get('conn_state') self.duration = _source['zeek'].get('duration') self.originated_locally = _source['zeek'].get('local_orig') self.history = _source['zeek'].get('history') self.uid = _source['zeek'].get('uid') orig_ip_bytes = _source['zeek'].get('orig_ip_bytes') orig_bytes = _source['zeek'].get('orig_ip_bytes') resp_ip_bytes = _source['zeek'].get('resp_ip_bytes') resp_bytes = _source['zeek'].get('resp_bytes') if orig_bytes and orig_ip_bytes: self.source_bytes = max([orig_ip_bytes, orig_bytes]) if resp_bytes and resp_ip_bytes: self.destination_bytes = max([resp_ip_bytes, resp_bytes]) self.source_packets = _source['zeek'].get('orig_pkts') self.destination_packets = _source['zeek'].get('resp_pkts') except KeyError: pass def __str__(self) -> str: """ :return: A JSON representation of the ConnectionEvent """ return str(vars(self))
[docs]class DhcpEvent(Event): """ Represents a Zeek dhcp.log https://docs.zeek.org/en/stable/scripts/base/protocols/dhcp/main.zeek.html#type-DHCP::Info """ def __init__(self, raw_event_document: dict): super().__init__(raw_event_document) self.client_ip_address = None #: The IP address of the client requesting the DHCP lease self.server_ip_address = None #: The IP address of the server involved in actually handing out the lease self.client_port = None #: Client port # seen at time of server handing out IP (expected as 68/udp) self.server_port = None #: Server port # seen at time of server handing out IP (expected as 67/udp). self.mac_address = None #: Client’s hardware address self.hostname = None #: Name given by client in Hostname self.client_fqdn = None #: FQDN given by client in Client FQDN self.domain = None #: Domain given by the server self.requested_ip_address = None #: IP address requested by the client self.assigned_ip_address = None #: IP address assigned by the server self.lease_time = None #: IP address lease interval (seconds) self.client_message = None #: Message typically accompanied with a DHCP_DECLINE self.server_message = None #: Message typically accompanied with a DHCP_NAK self.message_types = None #: The DHCP message types seen by this DHCP transaction self.duration = None #: The time from the first message to the last self.uids = None #: Series of unique ids of the connections over which DHCP is occurring. self._parse_raw_dhcp_event() delattr(self, 'raw_event_document') def _parse_raw_dhcp_event(self) -> None: if self.event_type != 'dhcp': raise InvalidDhcpEventError('Invalid dhcp record, got [{}]'.format(self.event_type)) _source = self.raw_event_document['_source'] try: self.client_port = _source['zeek'].get('client_port') self.server_port = _source['zeek'].get('server_port') self.mac_address = _source['zeek'].get('mac') self.hostname = _source['zeek'].get('host_name') self.client_fqdn = _source['zeek'].get('client_fqdn') self.domain = _source['zeek'].get('domain') self.requested_ip_address = _source['zeek'].get('requested_addr') self.assigned_ip_address = _source['zeek'].get('assigned_addr') self.lease_time = _source['zeek'].get('lease_time') self.client_message = _source['zeek'].get('client_message') self.server_message = _source['zeek'].get('server_message') self.message_types = _source['zeek'].get('msg_types') self.duration = _source['zeek'].get('duration') self.uids = _source['zeek'].get('uids') try: self.client_ip_address = ip_address(_source['zeek'].get('client_addr')) except ValueError: raise InvalidDhcpEventError('Invalid client_ip_address field [{}]'.format(self.client_ip_address)) try: self.server_ip_address = _source['zeek'].get('server_addr') except ValueError: raise InvalidDhcpEventError('Invalid server_ip_address field [{}]'.format(self.server_ip_address)) except KeyError: raise InvalidDhcpEventError('Invalid dhcp record, missing "zeek" section') def __str__(self) -> str: """ :return: A JSON representation of the DhcpEvent """ return str(vars(self))
[docs]class DnsEvent(Event): """ Represents a Zeek dns.log https://docs.zeek.org/en/stable/scripts/base/protocols/dns/main.zeek.html#type-DNS::Info """ def __init__(self, raw_event_document: dict): super().__init__(raw_event_document) self.authoritative_answer = None #: True if the responding server is an authority for the domain name self.recursion_available = None #: True if server supports recursive queries self.recursion_desired = None #: True if the client wants recursive service for this query self.message_truncated = None #: True if the message was truncated self.rejected = None #: True if the DNS query was rejected by the server self.answers = None #: A set of resource descriptions in the query answer self.query_type = None #: A QTYPE value specifying the type of the query self.query_type_name = None #: A descriptive name for the type of the query self.query_class = None #: The QCLASS value specifying the class of the query self.query_class_name = None #: A descriptive name for the class of the query self.query = None #: The domain name that is the subject of the DNS query self.response_code = None #: The response code value in DNS response messages self.response_code_name = None #: A descriptive name for the response code value self.transaction_id = None #: A 16-bit identifier assigned by the program that generated the DNS query self.round_trip_time = None #: The delay between when the request was seen until the answer started self._parse_raw_dns_event() delattr(self, 'raw_event_document') def _parse_raw_dns_event(self) -> None: if self.event_type != 'dns': raise InvalidDnsEventError('Invalid dns record, got [{}]'.format(self.event_type)) _source = self.raw_event_document['_source'] try: self.authoritative_answer = _source['zeek'].get('AA') self.recursion_available = _source['zeek'].get('RA') self.recursion_desired = _source['zeek'].get('RD') self.message_truncated = _source['zeek'].get('TC') self.rejected = _source['zeek'].get('rejected') self.answers = _source['zeek'].get('answers') self.query_type = _source['zeek'].get('qtype') self.query_type_name = _source['zeek'].get('qtype_name') self.query_class = _source['zeek'].get('qclass') self.query_class_name = _source['zeek'].get('qclass_name') self.query = _source['zeek'].get('query') self.response_code = _source['zeek'].get('rcode') self.response_code_name = _source['zeek'].get('rcode_name') self.transaction_id = _source['zeek'].get('trans_id') self.round_trip_time = _source['zeek'].get('rtt') except KeyError: raise InvalidDnsEventError('Invalid dns record, missing "zeek" section') def __str__(self) -> str: """ :return: A JSON representation of the DnsEvent """ return str(vars(self))
[docs]class HttpEvent(Event): """ Represents a Zeek http.log https://docs.zeek.org/en/stable/scripts/base/protocols/http/main.zeek.html#type-HTTP::Info """ def __init__(self, raw_event_document: dict): super().__init__(raw_event_document) self.transaction_depth = None #: The depth into the connection of this request/response transaction self.method = None #: Verb used in the HTTP request (GET, POST, HEAD, etc.) self.host = None #: Value of the HOST header self.uri = None #: URI used in the request self.referrer = None #: Value of the “referer” header self.version = None #: Value of the version portion of the request self.user_agent = None #: Value of the User-Agent header from the client self.origin = None #: Value of the Origin header from the client self.request_body_length = None #: Actual uncompressed content size of the data transferred from the client self.response_body_length = None #: Actual uncompressed content size of the data transferred from the server self.status_code = None #: Status code returned by the server self.status_message = None #: Status message returned by the server self.info_code = None #: Last seen 1xx informational reply code returned by the server self.info_message = None #: Last seen 1xx informational reply message returned by the server self.username = None #: Username if basic-auth is performed for the request self.password = None #: Password if basic-auth is performed for the request self.proxied = None #: All of the headers that may indicate if the request was proxied self.originating_fuids = None #: An ordered list of file unique IDs from the client self.originating_filenames = None #: An ordered list of filenames from the client self.originating_mime_types = None #: An ordered list of mime types from the client self.recipient_fuids = None #: An ordered list of file unique IDs from the server self.recipient_filenames = None #: An ordered list of filenames from the server self.recipient_mime_types = None #: An ordered list of mime types from the server self.client_header_names = None #: The list of HTTP header names sent by the client self.server_header_names = None #: The list of HTTP header names sent by the server self.cookie_variables = None #: Variable names extracted from all cookies self.uri_variables = None #: Variable names from the URI self._parse_raw_http_event() delattr(self, 'raw_event_document') def _parse_raw_http_event(self) -> None: if self.event_type != 'http': raise InvalidHttpEventError('Invalid http record, got [{}]'.format(self.event_type)) _source = self.raw_event_document['_source'] try: self.transaction_depth = _source['zeek'].get('trans_depth') self.method = _source['zeek'].get('method') self.host = _source['zeek'].get('host') self.uri = _source['zeek'].get('uri') self.referrer = _source['zeek'].get('referrer') self.version = _source['zeek'].get('version') self.user_agent = _source['zeek'].get('user_agent') self.origin = _source['zeek'].get('origin') self.request_body_length = _source['zeek'].get('request_body_len') self.response_body_length = _source['zeek'].get('response_body_len') self.status_code = _source['zeek'].get('status_code') self.status_message = _source['zeek'].get('status_msg') self.info_code = _source['zeek'].get('info_code') self.info_message = _source['zeek'].get('info_msg') self.username = _source['zeek'].get('username') self.password = _source['zeek'].get('password') self.proxied = _source['zeek'].get('proxied') self.originating_fuids = _source['zeek'].get('orig_fuids') self.originating_filenames = _source['zeek'].get('orig_filenames') self.originating_mime_types = _source['zeek'].get('orig_mime_types') self.recipient_fuids = _source['zeek'].get('resp_fuids') self.recipient_filenames = _source['zeek'].get('resp_filenames') self.recipient_mime_types = _source['zeek'].get('resp_mime_types') self.client_header_names = _source['zeek'].get('client_header_names') self.server_header_names = _source['zeek'].get('server_header_names') self.cookie_variables = _source['zeek'].get('cookie_variables') self.uri_variables = _source['zeek'].get('uri_variables') except KeyError: raise InvalidHttpEventError('Invalid http record, missing "zeek" section') def __str__(self) -> str: """ :return: A JSON representation of the HttpEvent """ return str(vars(self))
[docs]class SipEvent(Event): """ Represents a Zeek sip.log https://docs.zeek.org/en/stable/scripts/base/protocols/sip/main.zeek.html#type-SIP::Info """ def __init__(self, raw_event_document: dict): super().__init__(raw_event_document) self.transaction_depth = None #: The depth into the connection of this request/response transaction self.method = None #: Verb used in the SIP request (INVITE, REGISTER etc) self.uri = None #: URI used in the request self.request_from = None #: Contents of the request From: header self.request_to = None #: Contents of the To: header self.response_from = None #: Contents of the response From: header self.response_to = None #: Contents of the response To: header self.reply_to = None #: Contents of the Reply-To: header self.call_id = None #: Contents of the Call-ID: header from the client self.c_sequence = None #: Contents of the CSeq: header from the client self.subject = None #: Contents of the Subject: header from the client self.request_path = None #: The client message transmission path, as extracted from the headers self.response_path = None #: The server message transmission path, as extracted from the headers self.user_agent = None #: Contents of the User-Agent: header from the client self.status_code = None #: Status code returned by the server self.status_message = None #: Status message returned by the server self.warning = None #: Contents of the Warning: header self.request_body_length = None #: Contents of the Content-Length: header from the client self.response_body_length = None #: Contents of the Content-Length: header from the server self.content_type = None #: Contents of the Content-Type: header from the server self._parse_raw_sip_event() delattr(self, 'raw_event_document') def _parse_raw_sip_event(self) -> None: if self.event_type != 'sip': raise InvalidHttpEventError('Invalid sip record, got [{}]'.format(self.event_type)) _source = self.raw_event_document['_source'] try: self.transaction_depth = _source['zeek'].get('trans_depth') self.method = _source['zeek'].get('method') self.uri = _source['zeek'].get('uri') self.request_from = _source['zeek'].get('request_from') self.request_to = _source['zeek'].get('request_to') self.response_from = _source['zeek'].get('response_from') self.response_to = _source['zeek'].get('response_to') self.reply_to = _source['zeek'].get('reply_to') self.call_id = _source['zeek'].get('call_id') self.c_sequence = _source['zeek'].get('seq') self.subject = _source['zeek'].get('subject') self.request_path = _source['zeek'].get('request_path') self.response_path = _source['zeek'].get('response_path') self.user_agent = _source['zeek'].get('user_agent') self.status_code = _source['zeek'].get('status_code') self.status_message = _source['zeek'].get('status_message') self.warning = _source['zeek'].get('warning') self.request_body_length = _source['zeek'].get('request_body_len') self.response_body_length = _source['zeek'].get('response_body_len') except KeyError: raise InvalidSipEventError('Invalid sip record, missing "zeek" section') def __str__(self) -> str: """ :return: A JSON representation of the SipEvent """ return str(vars(self))
[docs]class SnmpEvent(Event): """ Represents a Zeek snmp.log https://docs.zeek.org/en/stable/scripts/base/protocols/snmp/main.zeek.html#type-SNMP::Info """ def __init__(self, raw_event_document: dict): super().__init__(raw_event_document) self.duration = None #: The time between first/last packet sent in SNMP session self.version = None #: The version of SNMP being used self.community_string = None #: The community string of the first SNMP packet associated with the session self.get_requests = None #: The number of variable bindings in GetRequest/GetNextRequest PDUs seen self.get_bulk_requests = None #: The number of variable bindings in GetBulkRequest PDUs seen self.get_responses = None #: The number of variable bindings in GetResponse/Response PDUs self.set_requests = None #: The number of variable bindings in SetRequest PDUs seen for the session self.display_string = None #: The system description of the SNMP responder endpoint self.up_since = None #: The time at which the SNMP responder endpoint claims it’s been up since self._parse_raw_snmp_event() delattr(self, 'raw_event_document') def _parse_raw_snmp_event(self) -> None: if self.event_type != 'snmp': raise InvalidHttpEventError('Invalid snmp record, got [{}]'.format(self.event_type)) _source = self.raw_event_document['_source'] try: self.duration = _source['zeek'].get('duration') self.version = _source['zeek'].get('version') self.community_string = _source['zeek'].get('community') self.get_requests = _source['zeek'].get('get_requests') self.get_bulk_requests = _source['zeek'].get('get_bulk_requests') self.get_responses = _source['zeek'].get('get_responses') self.set_requests = _source['zeek'].get('set_requests') self.display_string = _source['zeek'].get('display_string') self.up_since = _source['zeek'].get('up_since') except KeyError: raise InvalidSipEventError('Invalid snmp record, missing "zeek" section') def __str__(self) -> str: """ :return: A JSON representation of the SnmpEvent """ return str(vars(self))
[docs]class SshEvent(Event): """ Represents a Zeek ssh.log https://docs.zeek.org/en/stable/scripts/base/protocols/ssh/main.zeek.html#type-SSH::Info """ def __init__(self, raw_event_document: dict): super().__init__(raw_event_document) self.version = None #: SSH major version (1 or 2) self.authentication_success = None #: True if successfully authenticated self.authentication_attempts = None #: The number of authentication attempts observed self.direction = None #: Direction of the connection (Outbound/Inbound) self.client_version_string = None #: The client's version string self.server_version_string = None #: The server's version string self.cipher_algorithm = None #: The encryption algorithm in use self.mac_algorithm = None #: The signing (MAC) algorithm in use self.compression_algorithm = None #: The compression algorithm in use self.key_algorithm = None #: The key exchange algorithm in use self.host_key_algorithm = None #: The server host key’s algorithm self.host_key = None #: The server’s key fingerprint self._parse_raw_ssh_event() delattr(self, 'raw_event_document') def _parse_raw_ssh_event(self) -> None: if self.event_type != 'ssh': raise InvalidSshEventError('Invalid ssh record, got [{}]'.format(self.event_type)) _source = self.raw_event_document['_source'] try: self.version = _source['zeek'].get('version') self.authentication_success = _source['zeek'].get('auth_success') self.authentication_attempts = _source['zeek'].get('auth_attempts') self.direction = _source['zeek'].get('direction') self.client_version_string = _source['zeek'].get('client') self.server_version_string = _source['zeek'].get('server') self.cipher_algorithm = _source['zeek'].get('cipher_alg') self.mac_algorithm = _source['zeek'].get('mac_alg') self.compression_algorithm = _source['zeek'].get('compression_alg') self.key_algorithm = _source['zeek'].get('key_alg') self.host_key_algorithm = _source['zeek'].get('host_key_alg') self.host_key = _source['zeek'].get('host_key') except KeyError: raise InvalidSshEventError('Invalid ssh record, missing "zeek" section') def __str__(self) -> str: """ :return: A JSON representation of the SshEvent """ return str(vars(self))