diff --git a/monkey_island/cc/resources/netmap.py b/monkey_island/cc/resources/netmap.py index f5ad4d06e..12418ef6b 100644 --- a/monkey_island/cc/resources/netmap.py +++ b/monkey_island/cc/resources/netmap.py @@ -11,12 +11,14 @@ class NetMap(flask_restful.Resource): def get(self, **kw): monkeys = [NodeService.monkey_to_net_node(x) for x in mongo.db.monkey.find({})] nodes = [NodeService.node_to_net_node(x) for x in mongo.db.node.find({})] - edges = [self.edge_to_net_edge(x) for x in mongo.db.edge.find({})] - monkey_island = [] + edges = [EdgeService.edge_to_net_edge(x) for x in mongo.db.edge.find({})] + if NodeService.get_monkey_island_monkey() is None: monkey_island = [NodeService.get_monkey_island_pseudo_net_node()] - # TODO: implement when monkey exists on island edges += EdgeService.get_monkey_island_pseudo_edges() + else: + monkey_island = [] + edges += EdgeService.get_infected_monkey_island_pseudo_edges() return \ { @@ -24,10 +26,4 @@ class NetMap(flask_restful.Resource): "edges": edges } - def edge_to_net_edge(self, edge): - return \ - { - "id": edge["_id"], - "from": edge["from"], - "to": edge["to"] - } + diff --git a/monkey_island/cc/resources/telemetry.py b/monkey_island/cc/resources/telemetry.py index 2a057f626..1c17c1fa0 100644 --- a/monkey_island/cc/resources/telemetry.py +++ b/monkey_island/cc/resources/telemetry.py @@ -47,8 +47,10 @@ class Telemetry(flask_restful.Resource): self.process_tunnel_telemetry(telemetry_json) elif telemetry_json.get('telem_type') == 'state': self.process_state_telemetry(telemetry_json) - elif telemetry_json.get('telem_type') in ['scan', 'exploit']: - self.process_scan_exploit_telemetry(telemetry_json) + elif telemetry_json.get('telem_type') == 'exploit': + self.process_exploit_telemetry(telemetry_json) + elif telemetry_json.get('telem_type') == 'scan': + self.process_scan_telemetry(telemetry_json) elif telemetry_json.get('telem_type') == 'system_info_collection': self.process_system_info_telemetry(telemetry_json) NodeService.update_monkey_modify_time(monkey["_id"]) @@ -58,6 +60,15 @@ class Telemetry(flask_restful.Resource): return mongo.db.telemetry.find_one_or_404({"_id": telem_id}) + def get_edge_by_scan_or_exploit_telemetry(self, telemetry_json): + dst_ip = telemetry_json['data']['machine']['ip_addr'] + src_monkey = NodeService.get_monkey_by_guid(telemetry_json['monkey_guid']) + dst_node = NodeService.get_monkey_by_ip(dst_ip) + if dst_node is None: + dst_node = NodeService.get_or_create_node(dst_ip) + + return EdgeService.get_or_create_edge(src_monkey["_id"], dst_node["_id"]) + def process_tunnel_telemetry(self, telemetry_json): monkey_id = NodeService.get_monkey_by_guid(telemetry_json['monkey_guid'])["_id"] if telemetry_json['data']['proxy'] is not None: @@ -74,29 +85,25 @@ class Telemetry(flask_restful.Resource): else: NodeService.set_monkey_dead(monkey, False) - def process_scan_exploit_telemetry(self, telemetry_json): - dst_ip = telemetry_json['data']['machine']['ip_addr'] - src_monkey = NodeService.get_monkey_by_guid(telemetry_json['monkey_guid']) - dst_node = NodeService.get_monkey_by_ip(dst_ip) - if dst_node is None: - dst_node = NodeService.get_or_create_node(dst_ip) + def process_exploit_telemetry(self, telemetry_json): + edge = self.get_edge_by_scan_or_exploit_telemetry(telemetry_json) + data = telemetry_json['data'] + data["machine"].pop("ip_addr") + new_exploit = \ + { + "timestamp": telemetry_json["timestamp"], + "data": data, + "exploiter": telemetry_json['data']['exploiter'] + } + mongo.db.edge.update( + {"_id": edge["_id"]}, + {"$push": {"exploits": new_exploit}} + ) + if data['result']: + EdgeService.set_edge_exploited(edge) - edge = EdgeService.get_or_create_edge(src_monkey["_id"], dst_node["_id"]) - - if telemetry_json.get('telem_type') == 'scan': - self.add_scan_to_edge(edge, telemetry_json) - else: - self.add_exploit_to_edge(edge, telemetry_json) - - def process_system_info_telemetry(self, telemetry_json): - if 'credentials' in telemetry_json['data']: - creds = telemetry_json['data']['credentials'] - for user in creds: - ConfigService.creds_add_username(user) - if 'password' in creds[user]: - ConfigService.creds_add_password(creds[user]['password']) - - def add_scan_to_edge(self, edge, telemetry_json): + def process_scan_telemetry(self, telemetry_json): + edge = self.get_edge_by_scan_or_exploit_telemetry(telemetry_json) data = telemetry_json['data']['machine'] data.pop("ip_addr") new_scan = \ @@ -123,17 +130,12 @@ class Telemetry(flask_restful.Resource): {"$set": {"os.version": scan_os["version"]}}, upsert=False) - def add_exploit_to_edge(self, edge, telemetry_json): - data = telemetry_json['data'] - data["machine"].pop("ip_addr") - new_exploit = \ - { - "timestamp": telemetry_json["timestamp"], - "data": data, - "exploiter": telemetry_json['data']['exploiter'] - } - mongo.db.edge.update( - {"_id": edge["_id"]}, - {"$push": {"exploits": new_exploit}} - ) + def process_system_info_telemetry(self, telemetry_json): + if 'credentials' in telemetry_json['data']: + creds = telemetry_json['data']['credentials'] + for user in creds: + ConfigService.creds_add_username(user) + if 'password' in creds[user]: + ConfigService.creds_add_password(creds[user]['password']) + diff --git a/monkey_island/cc/services/edge.py b/monkey_island/cc/services/edge.py index c4921bc8d..05159560f 100644 --- a/monkey_island/cc/services/edge.py +++ b/monkey_island/cc/services/edge.py @@ -1,6 +1,7 @@ from bson import ObjectId from cc.database import mongo +import cc.services.node __author__ = "itay.mizeretz" @@ -99,7 +100,8 @@ class EdgeService: "to": to_id, "scans": [], "exploits": [], - "tunnel": False + "tunnel": False, + "exploited": False }) return mongo.db.edge.find_one({"_id": edge_insert_result.inserted_id}) @@ -111,6 +113,16 @@ class EdgeService: return tunnel_edge + @staticmethod + def generate_pseudo_edge(edge_id, edge_from, edge_to): + return \ + { + "id": edge_id, + "from": edge_from, + "to": edge_to, + "group": "island" + } + @staticmethod def get_monkey_island_pseudo_edges(): edges = [] @@ -120,13 +132,26 @@ class EdgeService: count = 0 for monkey_id in monkey_ids: count += 1 - edges.append( - { - "id": ObjectId(hex(count)[2:].zfill(24)), - "from": monkey_id, - "to": ObjectId("000000000000000000000000") - } - ) + edges.append(EdgeService.generate_pseudo_edge( + ObjectId(hex(count)[2:].zfill(24)), monkey_id, ObjectId("000000000000000000000000"))) + + return edges + + @staticmethod + def get_infected_monkey_island_pseudo_edges(): + monkey = cc.services.node.NodeService.get_monkey_island_monkey() + existing_ids = [x["_id"] for x in mongo.db.edge.find({"to": monkey["_id"]})] + monkey_ids = [x["_id"] for x in mongo.db.monkey.find({}) + if ("tunnel" not in x) and (x["_id"] not in existing_ids)] + edges = [] + + # We're using fake ids because the frontend graph module requires unique ids. + # Collision with real id is improbable. + count = 0 + for monkey_id in monkey_ids: + count += 1 + edges.append(EdgeService.generate_pseudo_edge( + ObjectId(hex(count)[2:].zfill(24)), monkey_id, monkey["_id"])) return edges @@ -134,3 +159,33 @@ class EdgeService: def services_to_displayed_services(services): # TODO: Consider returning extended information on services. return [x + ": " + services[x]["name"] for x in services] + + @staticmethod + def edge_to_net_edge(edge): + return \ + { + "id": edge["_id"], + "from": edge["from"], + "to": edge["to"], + "group": EdgeService.get_edge_group(edge) + } + + @staticmethod + def get_edge_group(edge): + if edge["exploited"]: + return "exploited" + if edge["tunnel"]: + return "tunnel" + if (len(edge["scans"]) > 0) or (len(edge["exploits"]) > 0): + return "scan" + return "empty" + + @staticmethod + def set_edge_exploited(edge): + mongo.db.edge.update( + {"_id": edge["_id"]}, + {"$set": {"exploited": True}} + ) + + cc.services.node.NodeService.set_node_exploited(edge["to"]) + diff --git a/monkey_island/cc/services/node.py b/monkey_island/cc/services/node.py index db5a88abe..1b16571c2 100644 --- a/monkey_island/cc/services/node.py +++ b/monkey_island/cc/services/node.py @@ -89,7 +89,11 @@ class NodeService: @staticmethod def get_monkey_label(monkey): - return monkey["hostname"] + " : " + monkey["ip_addresses"][0] + label = monkey["hostname"] + " : " + monkey["ip_addresses"][0] + ip_addresses = local_ip_addresses() + if len(set(monkey["ip_addresses"]).intersection(ip_addresses)) > 0: + label = "MonkeyIsland - " + label + return label @staticmethod def get_monkey_group(monkey): @@ -98,6 +102,13 @@ class NodeService: return "manuallyInfected" if NodeService.get_monkey_manual_run(monkey) else "infected" + @staticmethod + def get_node_group(node): + if node["exploited"]: + return "exploited" + else: + return "clean" + @staticmethod def monkey_to_net_node(monkey): return \ @@ -115,7 +126,7 @@ class NodeService: { "id": node["_id"], "label": NodeService.get_node_label(node), - "group": "clean", + "group": NodeService.get_node_group(node), "os": node["os"]["type"] } @@ -148,6 +159,7 @@ class NodeService: new_node_insert_result = mongo.db.node.insert_one( { "ip_addresses": [ip_address], + "exploited": False, "os": { "type": "unknown", @@ -218,3 +230,10 @@ class NodeService: island_node = NodeService.get_monkey_island_pseudo_net_node() island_node["ip_addresses"] = local_ip_addresses() return island_node + + @staticmethod + def set_node_exploited(node_id): + mongo.db.node.update( + {"_id": node_id}, + {"$set": {"exploited": True}} + )