def process_create(self, event) -> Tuple[Process, File, Process]: pid = -1 command_line = None match = re.match(r"PID: (\d*), Command line: (.*)", event["params"]) if match: pid, command_line = match.groups() process_image, process_image_path = split_path(event["path"]) proc = Process( process_id=int(pid), process_image=process_image, process_image_path=process_image_path, command_line=command_line, ) proc_file = proc.get_file_node() proc_file.file_of[proc] parent = Process(process_id=int(event["process_id"]), process_image=event["process_name"]) parent.launched[proc].append(timestamp=event["event_time"]) return (proc, proc_file, parent)
def test_add_nodes_no_overlap(nx): proc = Process(process_id=10, process_image="test.exe", command_line="test.exe /c foobar") other_proc = Process(process_id=12, process_image="best.exe", command_line="best.exe /c 123456") proc.launched[other_proc].append(timestamp=1) backend = NetworkX(consolidate_edges=True, nodes=[proc, other_proc]) G = backend.graph() assert len(G.nodes()) == 2 assert len(G.edges()) == 1 # Add in a new pair of nodes. proc2 = Process(process_id=4, process_image="malware.exe", command_line="malware.exe /c foobar") f = File(file_name="foo", file_path="bar") proc2.wrote[f] G = backend.add_nodes([proc2, f]) # Graph grew assert len(G.nodes()) == 4 assert len(G.edges()) == 2
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_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 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_basic_regkey(self, event: dict) -> Tuple[Process, File, RegistryKey]: 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] # RegistryKey Node Creation reg_node = RegistryKey( hive=event[FieldNames.HIVE], key_path=event[FieldNames.REG_KEY_PATH], key=event[FieldNames.REG_KEY], ) if event["event_type"] == EventTypes.REG_KEY_OPENED: process.read_key[reg_node] else: process.deleted_key[reg_node] return (process, proc_file, reg_node)
def make_file_copy(self, event: dict) -> Tuple[Process, File, File, File]: 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] # Source file src_file = File( file_path=event[FieldNames.SRC_FILE][FieldNames.FILE_PATH], file_name=event[FieldNames.SRC_FILE][FieldNames.FILE_NAME], hashes=event[FieldNames.SRC_FILE].get(FieldNames.HASHES), ) # Dest file src_file.set_extension() dest_file = File( file_path=event[FieldNames.DEST_FILE][FieldNames.FILE_PATH], file_name=event[FieldNames.DEST_FILE][FieldNames.FILE_NAME], hashes=event[FieldNames.DEST_FILE].get(FieldNames.HASHES), ) dest_file.set_extension() src_file.copied_to[dest_file] process.copied[src_file] return (process, proc_file, src_file, dest_file)
def make_regkey_set_value( self, event: dict) -> Tuple[Process, File, RegistryKey]: 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] # RegistryKey Node Creation reg_node = RegistryKey( hive=event[FieldNames.HIVE], key_path=event[FieldNames.REG_KEY_PATH], key=event[FieldNames.REG_KEY], value=event.get(FieldNames.REG_KEY_VALUE), ) if reg_node.value: process.changed_value[reg_node].append(value=reg_node.value) else: process.changed_value[reg_node] return (process, proc_file, reg_node)
def testEqualsMoreFields(): proc = Process(process_id=10, process_image="test.exe", command_line="test.exe /c foobar") other_proc = Process(process_id=10, process_image="test.exe", command_line="test.exe /c 123456") assert proc == other_proc assert hash(proc) == hash(other_proc)
def make_basic_file(self, event: dict) -> Tuple[Process, File, File]: """Transforms a file based event. Support events: 1. EventTypes.FILE_DELETED 2. EventTypes.FILE_OPENED 3. EventTypes.FILE_WRITTEN 4. EventTypes.LOADED_MODULE Parameters ---------- event : dict [description] Returns ------- Tuple[Process, File, File] [description] """ 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] file_node = File( file_path=event[FieldNames.FILE_PATH], file_name=event[FieldNames.FILE_NAME], hashes=event.get(FieldNames.HASHES), ) file_node.set_extension() # Switch based on the event type event_type = event[FieldNames.EVENT_TYPE] if event_type == EventTypes.FILE_OPENED: process.accessed[file_node] elif event_type == EventTypes.FILE_WRITTEN: process.wrote[file_node] elif event_type == EventTypes.LOADED_MODULE: process.loaded[file_node] else: process.deleted[file_node] return (process, proc_file, file_node)
def test_edge_has_no_name(nx): proc = Process(process_id=10, process_image="test.exe", command_line=None) other_proc = Process(process_id=12, process_image="best.exe", command_line="best.exe /c 123456") # append never called proc.launched[other_proc] # This shouldn't error. G = nx(nodes=[proc, other_proc]) len(G.nodes()) == 2 len(G.edges()) == 1
def process_creation(self, event: dict) -> Tuple[Process, File, Process]: """Transformers a process creation (event ID 4688) into a set of nodes. https://www.ultimatewindowssecurity.com/securitylog/encyclopedia/event.aspx?eventID=4688 Parameters ---------- event : dict [description] Returns ------- Optional[Tuple[Process, File, Process, File]] [description] """ # Get the parent PID parent_pid = int(event["data_name_processid"], 16) # Child PID child_pid = int(event["data_name_newprocessid"], 16) proc_name, proc_path = split_path(event["data_name_newprocessname"]) child = Process( host=event["computer"], process_id=child_pid, user=event["data_name_subjectusername"], process_image=proc_name, process_image_path=proc_path, command_line=event.get("data_name_commandline"), ) child_file = child.get_file_node() child_file.file_of[child] # Map the process for later self.seen_procs[child_pid] = child parent = self.seen_procs.get(parent_pid) if parent is None: # Create a dummy proc. If we haven't already seen the parent parent = Process(host=event["computer"], process_id=parent_pid) parent.launched[child].append( timestamp=event["timecreated_systemtime"]) # Don't need to pull out the parent's file, as it will have always # been created before being put into seen_procs return (child, child_file, parent)
def testLaunchedMultipleProces(): parent = Process(process_id=1, process_image="parent.exe") child = Process(process_id=2, process_image="child.exe") parent2 = Process(process_id=4, process_image="parent.exe") child2 = Process(process_id=3, process_image="child.exe") parent.launched[child].append(timestamp=12456) parent2.launched[child2].append(timestamp=2) assert {"timestamp": 12456} in parent.launched[child] assert {"timestamp": 2} not in parent.launched[child] assert {"timestamp": 2} in parent2.launched[child2] assert {"timestamp": 12456} not in parent2.launched[child2]
def test_node_updated(nx): """After pushing in the first process, the second process which has the same hash should cause the command line attribute to update""" proc = Process(process_id=10, process_image="test.exe", command_line=None) next_proc = Process(process_id=10, process_image="test.exe", command_line="best.exe /c 123456") G = nx(nodes=[proc, next_proc]) in_graph_proc = G.nodes(data=True)[hash(proc)]["data"] assert in_graph_proc.command_line == "best.exe /c 123456" assert in_graph_proc.process_id == 10 assert in_graph_proc.process_image == "test.exe" # Should only have one node, since both nodes inserted are equal assert len(G.nodes()) == 1
def test_from_json_object(nx): proc = Process(process_id=10, process_image="test.exe", command_line=None) other_proc = Process(process_id=12, process_image="best.exe", command_line="best.exe /c 123456") proc.launched[other_proc] G = nx(nodes=[proc, other_proc]) _json_output = NetworkX.graph_to_json(G) assert isinstance(_json_output, dict) G2 = NetworkX.from_json(_json_output) # Graphs should be equal. assert networkx.is_isomorphic(G, G2)
def test_file_of(): file_node = File(file_path="c:/windows", file_name="test.exe", extension=".exe") proc = Process(process_id=0, process_image="test.exe", process_image_path="c:/windows/test.exe") file_node.file_of[proc] assert proc in file_node.file_of
def test_one_edge(nx): proc = Process(process_id=10, process_image="test.exe", command_line="test.exe /c foobar") other_proc = Process(process_id=12, process_image="best.exe", command_line="best.exe /c 123456") proc.launched[other_proc].append(timestamp=1) G = nx(nodes=[proc, other_proc]) assert len(G.nodes()) == 2 assert len(G.edges()) == 1 u = hash(proc) v = hash(other_proc) assert networkx.has_path(G, u, v) assert "Launched" in G[u][v] assert {"timestamp": 1} == G[u][v]["Launched"]["data"][0]
def test_from_json_path(nx, tmpdir): proc = Process(process_id=10, process_image="test.exe", command_line=None) other_proc = Process(process_id=12, process_image="best.exe", command_line="best.exe /c 123456") proc.launched[other_proc] G = nx(nodes=[proc, other_proc]) _json_output = NetworkX.graph_to_json(G) # Save to file p = tmpdir.mkdir("networkx").join("data.json") p.write(json.dumps(_json_output)) G2 = NetworkX.from_json(p) # Graphs should be equal. assert networkx.is_isomorphic(G, G2)
def testNotFileOf(): file_node = File(file_path="c:/windows", file_name="test.exe", extension=".exe") proc = Process(process_id=0, process_image="best.exe", process_image_path="c:/windows/best.exe") assert proc not in file_node.file_of
def access_file(self, event) -> Tuple[Process, File]: proc = Process(process_id=int(event["process_id"]), process_image=event["process_name"]) file_name, file_path = split_path(event["path"]) target_file = File(file_name=file_name, file_path=file_path) proc.accessed[target_file].append(timestamp=event["event_time"]) return (proc, target_file)
def make_http_req(self, event: dict) -> Tuple[Process, File, URI, 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]) uri = URI(uri=event[FieldNames.URI]) uri.uri_of[dom] process.http_request_to[uri].append( method=event[FieldNames.HTTP_METHOD]) return (process, proc_file, uri, dom)
def make_process(self, event: dict) -> Tuple[Process, File, Process, File]: """Accepts a process with the `EventTypes.PROCESS_LAUNCHED` event_type. For example:: { FieldNames.PARENT_PROCESS_IMAGE: "cmd.exe", FieldNames.PARENT_PROCESS_IMAGE_PATH: "\\", FieldNames.PARENT_PROCESS_ID: "2568", FieldNames.PARENT_COMMAND_LINE: '/K name.exe"', FieldNames.PROCESS_IMAGE: "find.exe", FieldNames.PROCESS_IMAGE_PATH: "\\", FieldNames.COMMAND_LINE: 'find /i "svhost.exe"', FieldNames.PROCESS_ID: "3144", FieldNames.EVENT_TYPE: EventTypes.PROCESS_LAUNCHED, } Parameters ---------- event : dict [description] Returns ------- Tuple[Process, File, Process, File] [description] """ parent = Process( process_image=event[FieldNames.PARENT_PROCESS_IMAGE], process_image_path=event[FieldNames.PARENT_PROCESS_IMAGE_PATH], process_id=int(event[FieldNames.PARENT_PROCESS_ID]), command_line=event[FieldNames.PARENT_COMMAND_LINE], ) # Create the file node. # TODO: Integrate into the Process() init function? parent_file = parent.get_file_node() parent_file.file_of[parent] child = 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], ) child_file = child.get_file_node() child_file.file_of[child] if FieldNames.TIMESTAMP in event: parent.launched[child].append( timestamp=int(event[FieldNames.TIMESTAMP])) else: parent.launched[child] return (parent, parent_file, child, child_file)