From f45cebfd5ec8ea4e93a405170c69f49d2ecfe4a7 Mon Sep 17 00:00:00 2001 From: Vakaris Date: Fri, 25 May 2018 01:34:24 +0300 Subject: [PATCH] Does not store encrypted or already present ssh keys, shows all users from whom SSH private key were stolen under "stolen credentials" in report --- .../system_info/SSH_info_collector.py | 14 +++++++++--- monkey_island/cc/resources/telemetry.py | 10 ++++++++- monkey_island/cc/services/config.py | 14 +++++++++--- monkey_island/cc/services/report.py | 22 +++++++++++++++++++ .../cc/ui/src/components/pages/ReportPage.js | 2 +- 5 files changed, 54 insertions(+), 8 deletions(-) diff --git a/infection_monkey/system_info/SSH_info_collector.py b/infection_monkey/system_info/SSH_info_collector.py index 12244abac..af1915e4d 100644 --- a/infection_monkey/system_info/SSH_info_collector.py +++ b/infection_monkey/system_info/SSH_info_collector.py @@ -60,14 +60,19 @@ class SSHCollector(object): LOG.info("Found public key in %s" % public) try: with open(public) as f: - info['public_key'] = f.read() + info['public_key'] = f.read() # By default private key has the same name as public, only without .pub private = os.path.splitext(public)[0] if os.path.exists(private): try: with open(private) as f: - info['private_key'] = f.read() - LOG.info("Found private key in %s" % private) + # no use from ssh key if it's encrypted + private_key = f.read() + if private_key.find('ENCRYPTED') == -1: + info['private_key'] = private_key + LOG.info("Found private key in %s" % private) + else: + continue except (IOError, OSError): pass # By default known hosts file is called 'known_hosts' @@ -79,6 +84,9 @@ class SSHCollector(object): LOG.info("Found known_hosts in %s" % known_hosts) except (IOError, OSError): pass + # If private key found don't search more + if info['private_key']: + break except (IOError, OSError): pass except OSError: diff --git a/monkey_island/cc/resources/telemetry.py b/monkey_island/cc/resources/telemetry.py index 452a33818..ec05558d8 100644 --- a/monkey_island/cc/resources/telemetry.py +++ b/monkey_island/cc/resources/telemetry.py @@ -170,6 +170,8 @@ class Telemetry(flask_restful.Resource): if 'ssh_info' in telemetry_json['data']: ssh_info = telemetry_json['data']['ssh_info'] Telemetry.encrypt_system_info_creds({}, ssh_info) + if telemetry_json['data']['network_info']['networks']: + Telemetry.add_ip_to_ssh_keys(telemetry_json['data']['network_info']['networks'][0], ssh_info) Telemetry.add_system_info_creds_to_config({}, ssh_info) if 'credentials' in telemetry_json['data']: creds = telemetry_json['data']['credentials'] @@ -177,6 +179,11 @@ class Telemetry(flask_restful.Resource): Telemetry.add_system_info_creds_to_config(creds) Telemetry.replace_user_dot_with_comma(creds) + @staticmethod + def add_ip_to_ssh_keys(ip, ssh_info): + for key in ssh_info: + key['ip'] = ip['addr'] + @staticmethod def process_trace_telemetry(telemetry_json): # Nothing to do @@ -217,7 +224,8 @@ class Telemetry(flask_restful.Resource): ConfigService.creds_add_username(user['name']) # Public key is useless without private key if user['public_key'] and user['private_key']: - ConfigService.ssh_add_keys(user['public_key'], user['private_key']) + ConfigService.ssh_add_keys(user['public_key'], user['private_key'], + user['name'], user['ip']) diff --git a/monkey_island/cc/services/config.py b/monkey_island/cc/services/config.py index 1188c7d1e..46773c0fb 100644 --- a/monkey_island/cc/services/config.py +++ b/monkey_island/cc/services/config.py @@ -897,9 +897,17 @@ class ConfigService: ConfigService.add_item_to_config_set('internal.exploits.exploit_ntlm_hash_list', ntlm_hash) @staticmethod - def ssh_add_keys(public_key, private_key): - ConfigService.add_item_to_config_set('internal.exploits.exploit_ssh_keys', - {"public_key": public_key, "private_key": private_key}) + def ssh_add_keys(public_key, private_key, user, ip): + if not ConfigService.ssh_key_exists(ConfigService.get_config_value(['internal'], False, False) + ['exploits']['exploit_ssh_keys'], + user, ip): + ConfigService.add_item_to_config_set('internal.exploits.exploit_ssh_keys', + {"public_key": public_key, "private_key": private_key, + "user": user, "ip": ip}) + + @staticmethod + def ssh_key_exists(keys, user, ip): + return [key for key in keys if key['user'] == user and key['ip'] == ip] @staticmethod def update_config(config_json, should_encrypt): diff --git a/monkey_island/cc/services/report.py b/monkey_island/cc/services/report.py index f77e96dd9..0ceadc26b 100644 --- a/monkey_island/cc/services/report.py +++ b/monkey_island/cc/services/report.py @@ -149,6 +149,27 @@ class ReportService: ) return creds + @staticmethod + def get_ssh_keys(): + """ + Return private ssh keys found as credentials + :return: List of credentials + """ + creds = [] + for telem in mongo.db.telemetry.find( + {'telem_type': 'system_info_collection', 'data.ssh_info': {'$exists': True}}, + {'data.ssh_info': 1, 'monkey_guid': 1} + ): + origin = NodeService.get_monkey_by_guid(telem['monkey_guid'])['hostname'] + if telem['data']['ssh_info']: + # Pick out all ssh keys not yet included in creds + ssh_keys = [{'username': key_pair['name'], 'type': 'Clear SSH private key', + 'origin': origin} for key_pair in telem['data']['ssh_info'] + if key_pair['private_key'] and {'username': key_pair['name'], 'type': 'Clear SSH private key', + 'origin': origin} not in creds] + creds.extend(ssh_keys) + return creds + @staticmethod def get_azure_creds(): """ @@ -433,6 +454,7 @@ class ReportService: 'exploited': ReportService.get_exploited(), 'stolen_creds': ReportService.get_stolen_creds(), 'azure_passwords': ReportService.get_azure_creds(), + 'ssh_keys': ReportService.get_ssh_keys() }, 'recommendations': { diff --git a/monkey_island/cc/ui/src/components/pages/ReportPage.js b/monkey_island/cc/ui/src/components/pages/ReportPage.js index bec4f3625..393b1cc74 100644 --- a/monkey_island/cc/ui/src/components/pages/ReportPage.js +++ b/monkey_island/cc/ui/src/components/pages/ReportPage.js @@ -414,7 +414,7 @@ class ReportPageComponent extends AuthComponent {
- +
);