def network_connection( self, event: dict ) -> Union[Tuple[Process, File, IPAddress], Tuple[Process, File, IPAddress, Domain]]: process_image, process_path = split_path(event["EventData_Image"]) proc = SysMonProc( host=event["Computer"], user=event["EventData_User"], process_guid=event["EventData_ProcessGuid"], process_id=int(event["EventData_ProcessId"]), process_image=process_image, process_image_path=process_path, ) proc_file = proc.get_file_node() proc_file.file_of[proc] dest_addr = IPAddress(ip_address=event["EventData_DestinationIp"]) proc.connected_to[dest_addr].append( timestamp=event["EventData_UtcTime"], port=event["EventData_DestinationPort"], protocol=event["EventData_Protocol"], ) if event.get("EventData_DestinationHostname"): hostname = Domain(event["EventData_DestinationHostname"]) hostname.resolves_to[dest_addr].append(timestamp=event["EventData_UtcTime"]) return (proc, proc_file, dest_addr, hostname) return (proc, proc_file, dest_addr)
def make_dnslookup( self, event: dict ) -> Union[Tuple[Process, File, Domain, IPAddress], Tuple[Process, File, Domain]]: process = Process( process_image=event[FieldNames.PROCESS_IMAGE], process_image_path=event[FieldNames.PROCESS_IMAGE_PATH], process_id=int(event[FieldNames.PROCESS_ID]), command_line=event[FieldNames.COMMAND_LINE], ) proc_file = process.get_file_node() proc_file.file_of[process] dom = Domain(event[FieldNames.HTTP_HOST]) process.dns_query_for[dom] # Sometimes we don't know what the domain resolved to. if FieldNames.IP_ADDRESS in event: addr = IPAddress(ip_address=event[FieldNames.IP_ADDRESS]) dom.resolves_to[addr] return (process, proc_file, dom, addr) else: return (process, proc_file, dom)
def make_http_req( self, event: dict ) -> Union[Tuple[Process, File, URI, Domain], Tuple[Process, File, URI, Domain, IPAddress]]: process = Process( process_image=event[FieldNames.PROCESS_IMAGE], process_image_path=event[FieldNames.PROCESS_IMAGE_PATH], process_id=int(event[FieldNames.PROCESS_ID]), command_line=event[FieldNames.COMMAND_LINE], ) proc_file = process.get_file_node() proc_file.file_of[process] dom = Domain(event[FieldNames.HTTP_HOST]) uri = URI(uri=event[FieldNames.URI]) uri.uri_of[dom] process.http_request_to[uri].append( method=event[FieldNames.HTTP_METHOD]) if FieldNames.IP_ADDRESS in event: ip = IPAddress(event[FieldNames.IP_ADDRESS]) dom.resolves_to[ip] process.connected_to[ip] return (process, proc_file, uri, dom, ip) else: return (process, proc_file, uri, dom)
def make_connection(self, event: dict) -> Tuple[Process, File, IPAddress]: process = Process( process_image=event[FieldNames.PROCESS_IMAGE], process_image_path=event[FieldNames.PROCESS_IMAGE_PATH], process_id=int(event[FieldNames.PROCESS_ID]), command_line=event[FieldNames.COMMAND_LINE], ) proc_file = process.get_file_node() proc_file.file_of[process] addr = IPAddress(ip_address=event[FieldNames.IP_ADDRESS]) if FieldNames.PORT in event and FieldNames.PROTOCOL in event: process.connected_to[addr].append( port=int(event[FieldNames.PORT]), protocol=event[FieldNames.PROTOCOL]) elif FieldNames.PORT in event: process.connected_to[addr].append(port=int(event[FieldNames.PORT])) elif FieldNames.PROTOCOL in event: process.connected_to[addr].append( protocol=event[FieldNames.PROTOCOL]) else: process.connected_to[addr] return (process, proc_file, addr)
def transform(self, event: Dict) -> Optional[Tuple[Node, ...]]: event_type = event["event_type"] # Skip all ether events, no src/dst IP if event_type in ["Ether", "IP" ] or "src_ip" not in event or "dst_ip" not in event: return None src = IPAddress(ip_address=event["src_ip"], mac=event["src_mac"]) dst = IPAddress(ip_address=event["dst_ip"], mac=event["dst_mac"]) src.connected_to[dst].append( port=event["dport"], protocol=event["protocol"], payload=event["payload"], timestamp=event["timestamp"], ) if event_type == "HTTPRequest": dom = Domain(event["http_dest"]) uri = URI(event["uri"]) src.http_request_to[uri].append(method=event["http_method"], timestamp=event["timestamp"]) dom.resolves_to[dst] uri.uri_of[dom] return (src, dst, dom, uri) if event_type == "DNS": if event["qname"][-1] == ".": event["qname"] = event["qname"][:-1] dom = Domain(event["qname"]) src.dns_query_for[dom].append(record_type=event["qtype"], timestamp=event["timestamp"]) if "qanswer" in event: ip = IPAddress(event["qanswer"]) dom.resolves_to[ip].append(timestamp=event["timestamp"]) return (src, dom, ip, dst) return (src, dom, dst) return (src, dst)
def dns_events( self, event: dict ) -> Union[Tuple[Process, File, Domain], Tuple[Process, File, Domain, IPAddress]]: """Transforms a single DNS event Example event:: { "mode": "dns_query", "protocol_type": "udp", "hostname": "foobar", "qtype": "Host Address", "processinfo": { "imagepath": "C:\\ProgramData\\bloop\\some_proc.exe", "tainted": true, "md5sum": "....", "pid": 3020 }, "timestamp": 27648 } Optionally, if the event is "dns_query_answer", we can also extract the response. Parameters ---------- event : dict source dns_query event Returns ------- Tuple[Process, File, Domain] Process and its image, and the domain looked up """ proc_info = event["processinfo"] process_image, process_image_path = split_path(proc_info["imagepath"]) proc = Process( process_id=int(proc_info["pid"]), process_image=process_image, process_image_path=process_image_path, ) proc_file = proc.get_file_node() proc_file.file_of[proc] domain = Domain(event["hostname"]) proc.dns_query_for[domain].append(timestamp=int(event["timestamp"])) if "ipaddress" in event: addr = IPAddress(event["ipaddress"]) domain.resolves_to[addr].append(timestamp=int(event["timestamp"])) return (proc, proc_file, domain, addr) else: return (proc, proc_file, domain)
def make_network(self, event: dict) -> Optional[Tuple[IPAddress, Process, File]]: """Converts a network connection event into a Process, File and IP Address node. Nodes: 1. IP Address communicated to. 2. Process contacting IP. 3. File process launched from. Edges: 1. Process - (Connected To) -> IP Address 2. File - (File Of) -> Process Parameters ---------- event : dict The ipv4NetworkEvent Returns ------- Optional[Tuple[IPAddress, Process, File]] The IP Address, Process, and Process's File object. """ # Pull out the process fields. process = Process( process_image=event["process"], process_image_path=event["processPath"], process_id=int(event["pid"]), user=event.get("username", None), ) # Pull out the image of the process file_node = process.get_file_node() # File - (File Of) -> Process file_node.file_of[process] # Create the network node ip_address = IPAddress(event["remoteIP"]) # Create the connection edge # Process - (Connected To) -> IP Address process.connected_to[ip_address].append(timestamp=event["event_time"], protocol=event["protocol"], port=int(event["remotePort"])) return (ip_address, process, file_node)
def conn_events(self, event: dict) -> Tuple[Process, File, IPAddress]: """Transforms a single connection event Example event:: { "mode": "connect", "protocol_type": "tcp", "ipaddress": "199.168.199.123", "destination_port": 3333, "processinfo": { "imagepath": "C:\\ProgramData\\bloop\\some_proc.exe", "tainted": true, "md5sum": "....", "pid": 3020 }, "timestamp": 27648 } Parameters ---------- event : dict source dns_query event Returns ------- Tuple[Process, File, IPAddress] Process and its image, and the destination address """ proc_info = event["processinfo"] process_image, process_image_path = split_path(proc_info["imagepath"]) proc = Process( process_id=int(proc_info["pid"]), process_image=process_image, process_image_path=process_image_path, ) proc_file = proc.get_file_node() proc_file.file_of[proc] addr = IPAddress(event["ipaddress"]) proc.connected_to[addr].append( protocol=event["protocol_type"], timestamp=event["timestamp"], port=int(event["destination_port"]), ) return (proc, proc_file, addr)
def make_url( self, event: dict ) -> Optional[Tuple[URI, Domain, Process, File, IPAddress]]: """Converts a URL access event and returns 5 nodes with 4 different relationships. Nodes created: 1. URI Accessed (e.g /foobar) 2. Domain Accessed (e.g omer.com) 3. Process performing URL request. 4. File object for the Process image. 5. IP Address the domain resolves to. Relationships created: 1. URI - (URI Of) -> Domain 2. Domain - (Resolves To) -> IP Address 3. Process - (`http method of event`) -> URI 4. Process - (Connected To) -> IP Address 5. File - (File Of) -> Process Parameters ---------- event : dict The urlMonitorEvent events Returns ------- Optional[Tuple[URI, Domain, Process, File, IPAddress]] 5 tuple of the nodes pulled out of the event (see function description). """ uri = URI(uri=event["requestUrl"]) domain = Domain(domain=event["hostname"]) ip_address = IPAddress(ip_address=event["remoteIpAddress"]) # Pull out the process fields. process = Process( process_image=event["process"], process_image_path=event["processPath"], command_line=event.get("processCmdLine"), process_id=int(event["pid"]), user=event.get("username", None), ) # Pull out the image of the process file_node = process.get_file_node() # File - (File Of) -> Process file_node.file_of[process] # Link up the URI and the domain # URI - (URI Of) -> Domain uri.uri_of[domain].append(timestamp=event["event_time"]) # HTTP Request to the URL from the process # Proc - (HTTP Request) -> URI process.http_request_to[uri].append( method=event.get("urlMethod"), user_agent=event.get("userAgent"), header=event.get("httpHeader"), timestamp=event["event_time"], ) # TCP Communication from process to IP of domain # Process - (Connected To) -> IP Address process.connected_to[ip_address].append(port=int(event["remotePort"]), protocol=Protocols.HTTP, timestamp=event["event_time"]) # Domain resolving to that IP # Domain - (Resolves To) -> IP Address domain.resolves_to[ip_address].append(timestamp=event["event_time"]) return (uri, domain, process, file_node, ip_address)
def http_requests( self, event: dict ) -> Union[Tuple[Process, File, IPAddress, URI, Domain], Tuple[ Process, File, IPAddress, URI], Tuple[Process, File, IPAddress], ]: """Transforms a single `http_request` network event. A typical event looks like:: { "mode": "http_request", "protocol_type": "tcp", "ipaddress": "199.168.199.1", "destination_port": 80, "processinfo": { "imagepath": "c:\\Windows\\System32\\svchost.exe", "tainted": false, "md5sum": "1234", "pid": 1292 }, "http_request": "GET /some_route.crl HTTP/1.1~~Cache-Control: max-age = 900~~User-Agent: Microsoft-CryptoAPI/10.0~~Host: crl.microsoft.com~~~~", "timestamp": 433750 } Parameters ---------- event : dict The source `network` event with mode `http_request` Returns ------- Tuple[Node] [description] """ proc_info = event["processinfo"] process_image, process_image_path = split_path(proc_info["imagepath"]) proc = Process( process_id=int(proc_info["pid"]), process_image=process_image, process_image_path=process_image_path, ) proc_file = proc.get_file_node() proc_file.file_of[proc] addr = IPAddress(event["ipaddress"]) proc.connected_to[addr].append( timestamp=event["timestamp"], protocol=event["protocol_type"], port=event["destination_port"], ) try: url, header = event["http_request"].split("~~", 1) method, uri_path, _ = url.split(" ") uri = URI(uri_path) headers = dict( email.message_from_string(header.replace("~~", "\n")).items()) proc.http_request_to[uri].append(timestamp=event["timestamp"], method=method) if "Host" in headers: domain = Domain(headers["Host"]) # type: ignore domain.resolves_to[addr].append(timestamp=event["timestamp"]) uri.uri_of[domain] return (proc, proc_file, addr, uri, domain) else: return (proc, proc_file, addr, uri) except (ValueError, KeyError): return (proc, proc_file, addr)