forked from p15670423/monkey
Does not store encrypted or already present ssh keys, shows all users from whom SSH private key were stolen under "stolen credentials" in report
This commit is contained in:
parent
5f194b70f2
commit
f45cebfd5e
|
@ -60,14 +60,19 @@ class SSHCollector(object):
|
||||||
LOG.info("Found public key in %s" % public)
|
LOG.info("Found public key in %s" % public)
|
||||||
try:
|
try:
|
||||||
with open(public) as f:
|
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
|
# By default private key has the same name as public, only without .pub
|
||||||
private = os.path.splitext(public)[0]
|
private = os.path.splitext(public)[0]
|
||||||
if os.path.exists(private):
|
if os.path.exists(private):
|
||||||
try:
|
try:
|
||||||
with open(private) as f:
|
with open(private) as f:
|
||||||
info['private_key'] = f.read()
|
# no use from ssh key if it's encrypted
|
||||||
LOG.info("Found private key in %s" % private)
|
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):
|
except (IOError, OSError):
|
||||||
pass
|
pass
|
||||||
# By default known hosts file is called 'known_hosts'
|
# 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)
|
LOG.info("Found known_hosts in %s" % known_hosts)
|
||||||
except (IOError, OSError):
|
except (IOError, OSError):
|
||||||
pass
|
pass
|
||||||
|
# If private key found don't search more
|
||||||
|
if info['private_key']:
|
||||||
|
break
|
||||||
except (IOError, OSError):
|
except (IOError, OSError):
|
||||||
pass
|
pass
|
||||||
except OSError:
|
except OSError:
|
||||||
|
|
|
@ -170,6 +170,8 @@ class Telemetry(flask_restful.Resource):
|
||||||
if 'ssh_info' in telemetry_json['data']:
|
if 'ssh_info' in telemetry_json['data']:
|
||||||
ssh_info = telemetry_json['data']['ssh_info']
|
ssh_info = telemetry_json['data']['ssh_info']
|
||||||
Telemetry.encrypt_system_info_creds({}, 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)
|
Telemetry.add_system_info_creds_to_config({}, ssh_info)
|
||||||
if 'credentials' in telemetry_json['data']:
|
if 'credentials' in telemetry_json['data']:
|
||||||
creds = telemetry_json['data']['credentials']
|
creds = telemetry_json['data']['credentials']
|
||||||
|
@ -177,6 +179,11 @@ class Telemetry(flask_restful.Resource):
|
||||||
Telemetry.add_system_info_creds_to_config(creds)
|
Telemetry.add_system_info_creds_to_config(creds)
|
||||||
Telemetry.replace_user_dot_with_comma(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
|
@staticmethod
|
||||||
def process_trace_telemetry(telemetry_json):
|
def process_trace_telemetry(telemetry_json):
|
||||||
# Nothing to do
|
# Nothing to do
|
||||||
|
@ -217,7 +224,8 @@ class Telemetry(flask_restful.Resource):
|
||||||
ConfigService.creds_add_username(user['name'])
|
ConfigService.creds_add_username(user['name'])
|
||||||
# Public key is useless without private key
|
# Public key is useless without private key
|
||||||
if user['public_key'] and user['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'])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -897,9 +897,17 @@ class ConfigService:
|
||||||
ConfigService.add_item_to_config_set('internal.exploits.exploit_ntlm_hash_list', ntlm_hash)
|
ConfigService.add_item_to_config_set('internal.exploits.exploit_ntlm_hash_list', ntlm_hash)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def ssh_add_keys(public_key, private_key):
|
def ssh_add_keys(public_key, private_key, user, ip):
|
||||||
ConfigService.add_item_to_config_set('internal.exploits.exploit_ssh_keys',
|
if not ConfigService.ssh_key_exists(ConfigService.get_config_value(['internal'], False, False)
|
||||||
{"public_key": public_key, "private_key": private_key})
|
['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
|
@staticmethod
|
||||||
def update_config(config_json, should_encrypt):
|
def update_config(config_json, should_encrypt):
|
||||||
|
|
|
@ -149,6 +149,27 @@ class ReportService:
|
||||||
)
|
)
|
||||||
return creds
|
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
|
@staticmethod
|
||||||
def get_azure_creds():
|
def get_azure_creds():
|
||||||
"""
|
"""
|
||||||
|
@ -433,6 +454,7 @@ class ReportService:
|
||||||
'exploited': ReportService.get_exploited(),
|
'exploited': ReportService.get_exploited(),
|
||||||
'stolen_creds': ReportService.get_stolen_creds(),
|
'stolen_creds': ReportService.get_stolen_creds(),
|
||||||
'azure_passwords': ReportService.get_azure_creds(),
|
'azure_passwords': ReportService.get_azure_creds(),
|
||||||
|
'ssh_keys': ReportService.get_ssh_keys()
|
||||||
},
|
},
|
||||||
'recommendations':
|
'recommendations':
|
||||||
{
|
{
|
||||||
|
|
|
@ -414,7 +414,7 @@ class ReportPageComponent extends AuthComponent {
|
||||||
<ScannedServers data={this.state.report.glance.scanned}/>
|
<ScannedServers data={this.state.report.glance.scanned}/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<StolenPasswords data={this.state.report.glance.stolen_creds}/>
|
<StolenPasswords data={this.state.report.glance.stolen_creds, this.state.report.glance.ssh_keys}/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
Loading…
Reference in New Issue