re-arranged the code and cleaned up a bit

This commit is contained in:
maor.rayzin 2018-10-18 17:10:14 +03:00
parent b443652b0e
commit c208d0ebe8
4 changed files with 162 additions and 146 deletions

View File

@ -1,5 +1,4 @@
import json import json
import traceback
import logging import logging
import copy import copy
from datetime import datetime from datetime import datetime
@ -10,11 +9,12 @@ from flask import request
from cc.auth import jwt_required from cc.auth import jwt_required
from cc.database import mongo from cc.database import mongo
from cc.services import user_info, group_info from cc.services import user_info
from cc.services.config import ConfigService from cc.services.config import ConfigService
from cc.services.edge import EdgeService from cc.services.edge import EdgeService
from cc.services.node import NodeService from cc.services.node import NodeService
from cc.encryptor import encryptor from cc.encryptor import encryptor
from cc.services.wmi_info_handler import WMIHandler
__author__ = 'Barak' __author__ = 'Barak'
@ -188,147 +188,17 @@ class Telemetry(flask_restful.Resource):
if 'mimikatz' in telemetry_json['data']: if 'mimikatz' in telemetry_json['data']:
users_secrets = user_info.extract_secrets_from_mimikatz(telemetry_json['data'].get('mimikatz', '')) users_secrets = user_info.extract_secrets_from_mimikatz(telemetry_json['data'].get('mimikatz', ''))
if 'wmi' in telemetry_json['data']: if 'wmi' in telemetry_json['data']:
info_for_mongo = {} wmi_handler = WMIHandler(monkey_id, telemetry_json['data']['wmi'], users_secrets)
users_info = telemetry_json['data']['wmi']['Win32_UserAccount'] wmi_handler.add_groups_to_collection()
groups_info = telemetry_json['data']['wmi']['Win32_Group'] wmi_handler.add_users_to_collection()
group_user_dict = telemetry_json['data']['wmi']['Win32_GroupUser'] wmi_handler.create_group_user_connection()
Telemetry.add_groups_to_collection(groups_info, info_for_mongo, monkey_id) wmi_handler.insert_info_to_mongo()
Telemetry.add_users_to_collection(users_info, info_for_mongo, users_secrets, monkey_id)
Telemetry.create_group_user_connection(info_for_mongo, group_user_dict)
for entity in info_for_mongo.values():
if entity['machine_id']:
# Handling for local entities.
mongo.db.groupsandusers.update({'SID': entity['SID'],
'machine_id': entity['machine_id']}, entity, upsert=True)
else:
# Handlings for domain entities.
if not mongo.db.groupsandusers.find_one({'SID': entity['SID']}):
mongo.db.groupsandusers.insert_one(entity)
else:
# if entity is domain entity, add the monkey id of current machine to secrets_location.
# (found on this machine)
if entity.get('NTLM_secret'):
mongo.db.groupsandusers.update_one({'SID': entity['SID'], 'type': 1},
{'$addToSet': {'secret_location': monkey_id}})
Telemetry.add_admin(info_for_mongo[group_info.ADMINISTRATORS_GROUP_KNOWN_SID], monkey_id)
Telemetry.update_admins_retrospective(info_for_mongo)
Telemetry.update_critical_services(telemetry_json['data']['wmi']['Win32_Service'],
telemetry_json['data']['wmi']['Win32_Product'],
monkey_id)
@staticmethod
def update_critical_services(wmi_services, wmi_products, machine_id):
critical_names = ("W3svc", "MSExchangeServiceHost", "MSSQLServer", "dns", 'MSSQL$SQLEXPRESS', 'SQL')
services_names_list = [str(i['Name'])[2:-1] for i in wmi_services]
products_names_list = [str(i['Name'])[2:-2] for i in wmi_products]
for name in critical_names:
if name in services_names_list or name in products_names_list:
logger.info('found a critical service')
mongo.db.monkey.update({'_id': machine_id}, {'$addToSet': {'critical_services': name}})
@staticmethod
def update_admins_retrospective(info_for_mongo):
for profile in info_for_mongo:
groups_from_mongo = mongo.db.groupsandusers.find({'SID': {'$in': info_for_mongo[profile]['member_of']}},
{'admin_on_machines': 1})
for group in groups_from_mongo:
if group['admin_on_machines']:
mongo.db.groupsandusers.update_one({'SID': info_for_mongo[profile]['SID']},
{'$addToSet': {'admin_on_machines': {
'$each': group['admin_on_machines']}}})
@staticmethod
def add_admin(group, machine_id):
for sid in group['entities_list']:
mongo.db.groupsandusers.update_one({'SID': sid},
{'$addToSet': {'admin_on_machines': machine_id}})
entity_details = mongo.db.groupsandusers.find_one({'SID': sid},
{'type': 1, 'entities_list': 1})
if entity_details.get('type') == 2:
Telemetry.add_admin(entity_details, machine_id)
@staticmethod
def add_groups_to_collection(groups_info, info_for_mongo, monkey_id):
for group in groups_info:
if not group.get('LocalAccount'):
base_entity = Telemetry.build_entity_document(group)
else:
base_entity = Telemetry.build_entity_document(group, monkey_id)
base_entity['entities_list'] = []
base_entity['type'] = 2
info_for_mongo[base_entity.get('SID')] = base_entity
@staticmethod
def add_users_to_collection(users_info, info_for_mongo, users_secrets, monkey_id):
for user in users_info:
if not user.get('LocalAccount'):
base_entity = Telemetry.build_entity_document(user)
else:
base_entity = Telemetry.build_entity_document(user, monkey_id)
base_entity['NTLM_secret'] = users_secrets.get(base_entity['name'], {}).get('ntlm')
base_entity['SAM_secret'] = users_secrets.get(base_entity['name'], {}).get('sam')
base_entity['secret_location'] = []
base_entity['type'] = 1
info_for_mongo[base_entity.get('SID')] = base_entity
@staticmethod
def build_entity_document(entity_info, monkey_id=None):
general_properties_dict = {
'SID': str(entity_info['SID'])[4:-1],
'name': str(entity_info['Name'])[2:-1],
'machine_id': monkey_id,
'member_of': [],
'admin_on_machines': []
}
if monkey_id:
general_properties_dict['domain_name'] = None
else:
general_properties_dict['domain_name'] = str(entity_info['Domain'])[2:-1]
return general_properties_dict
@staticmethod
def create_group_user_connection(info_for_mongo, group_user_list):
for group_user_couple in group_user_list:
group_part = group_user_couple['GroupComponent']
child_part = group_user_couple['PartComponent']
group_sid = str(group_part['SID'])[4:-1]
groups_entities_list = info_for_mongo[group_sid]['entities_list']
child_sid = ''
if type(child_part) in (unicode, str):
child_part = str(child_part)
if "cimv2:Win32_UserAccount" in child_part:
# domain user
domain_name = child_part.split('cimv2:Win32_UserAccount.Domain="')[1].split('",Name="')[0]
name = child_part.split('cimv2:Win32_UserAccount.Domain="')[1].split('",Name="')[1][:-2]
if "cimv2:Win32_Group" in child_part:
# domain group
domain_name = child_part.split('cimv2:Win32_Group.Domain="')[1].split('",Name="')[0]
name = child_part.split('cimv2:Win32_Group.Domain="')[1].split('",Name="')[1][:-2]
for entity in info_for_mongo:
if info_for_mongo[entity]['name'] == name and info_for_mongo[entity]['domain'] == domain_name:
child_sid = info_for_mongo[entity]['SID']
else:
child_sid = str(child_part['SID'])[4:-1]
if child_sid and child_sid not in groups_entities_list:
groups_entities_list.append(child_sid)
if child_sid: #and info_for_mongo.get(child_sid, {}).get('type') == 1:
if child_sid in info_for_mongo:
info_for_mongo[child_sid]['member_of'].append(group_sid)
################################################################
wmi_handler.add_admin(wmi_handler.info_for_mongo[wmi_handler.ADMINISTRATORS_GROUP_KNOWN_SID], monkey_id)
wmi_handler.update_admins_retrospective()
wmi_handler.update_critical_services(telemetry_json['data']['wmi']['Win32_Service'],
telemetry_json['data']['wmi']['Win32_Product'],
monkey_id)
@staticmethod @staticmethod
def add_ip_to_ssh_keys(ip, ssh_info): def add_ip_to_ssh_keys(ip, ssh_info):

View File

@ -1,4 +0,0 @@
ADMINISTRATORS_GROUP_KNOWN_SID = '1-5-32-544'

View File

@ -41,3 +41,5 @@ def extract_secrets_from_mimikatz(mim_string):
extract_ntlm_secrets(mim_string, users_dict) extract_ntlm_secrets(mim_string, users_dict)
return users_dict return users_dict

View File

@ -0,0 +1,148 @@
from cc.database import mongo
class WMIHandler:
ADMINISTRATORS_GROUP_KNOWN_SID = '1-5-32-544'
def __init__(self, monkey_id, wmi_info, user_secrets):
self.monkey_id = monkey_id
self.info_for_mongo = {}
self.users_secrets = user_secrets
self.users_info = wmi_info['Win32_UserAccount']
self.groups_info = wmi_info['Win32_Group']
self.groups_and_users = wmi_info['Win32_GroupUser']
def process_and_handle(self):
self.add_groups_to_collection()
self.add_users_to_collection()
self.create_group_user_connection()
self.add_admin(self.info_for_mongo[self.ADMINISTRATORS_GROUP_KNOWN_SID], self.monkey_id)
self.update_admins_retrospective()
self.insert_info_to_mongo()
def update_critical_services(self, wmi_services, wmi_products, machine_id):
critical_names = ("W3svc", "MSExchangeServiceHost", "MSSQLServer", "dns", 'MSSQL$SQLEXPRESS', 'SQL')
services_names_list = [str(i['Name'])[2:-1] for i in wmi_services]
products_names_list = [str(i['Name'])[2:-2] for i in wmi_products]
for name in critical_names:
if name in services_names_list or name in products_names_list:
mongo.db.monkey.update({'_id': machine_id}, {'$addToSet': {'critical_services': name}})
def build_entity_document(self, entity_info, monkey_id=None):
general_properties_dict = {
'SID': str(entity_info['SID'])[4:-1],
'name': str(entity_info['Name'])[2:-1],
'machine_id': monkey_id,
'member_of': [],
'admin_on_machines': []
}
if monkey_id:
general_properties_dict['domain_name'] = None
else:
general_properties_dict['domain_name'] = str(entity_info['Domain'])[2:-1]
return general_properties_dict
def add_users_to_collection(self):
for user in self.users_info:
if not user.get('LocalAccount'):
base_entity = self.build_entity_document(user)
else:
base_entity = self.build_entity_document(user, self.monkey_id)
base_entity['NTLM_secret'] = self.users_secrets.get(base_entity['name'], {}).get('ntlm')
base_entity['SAM_secret'] = self.users_secrets.get(base_entity['name'], {}).get('sam')
base_entity['secret_location'] = []
base_entity['type'] = 1
self.info_for_mongo[base_entity.get('SID')] = base_entity
def add_groups_to_collection(self):
for group in self.groups_info:
if not group.get('LocalAccount'):
base_entity = self.build_entity_document(group)
else:
base_entity = self.build_entity_document(group, self.monkey_id)
base_entity['entities_list'] = []
base_entity['type'] = 2
self.info_for_mongo[base_entity.get('SID')] = base_entity
def create_group_user_connection(self):
for group_user_couple in self.groups_and_users:
group_part = group_user_couple['GroupComponent']
child_part = group_user_couple['PartComponent']
group_sid = str(group_part['SID'])[4:-1]
groups_entities_list = self.info_for_mongo[group_sid]['entities_list']
child_sid = ''
if type(child_part) in (unicode, str):
child_part = str(child_part)
name = None
domain_name = None
if "cimv2:Win32_UserAccount" in child_part:
# domain user
domain_name = child_part.split('cimv2:Win32_UserAccount.Domain="')[1].split('",Name="')[0]
name = child_part.split('cimv2:Win32_UserAccount.Domain="')[1].split('",Name="')[1][:-2]
if "cimv2:Win32_Group" in child_part:
# domain group
domain_name = child_part.split('cimv2:Win32_Group.Domain="')[1].split('",Name="')[0]
name = child_part.split('cimv2:Win32_Group.Domain="')[1].split('",Name="')[1][:-2]
for entity in self.info_for_mongo:
if self.info_for_mongo[entity]['name'] == name and \
self.info_for_mongo[entity]['domain'] == domain_name:
child_sid = self.info_for_mongo[entity]['SID']
else:
child_sid = str(child_part['SID'])[4:-1]
if child_sid and child_sid not in groups_entities_list:
groups_entities_list.append(child_sid)
if child_sid:
if child_sid in self.info_for_mongo:
self.info_for_mongo[child_sid]['member_of'].append(group_sid)
def insert_info_to_mongo(self):
for entity in self.info_for_mongo.values():
if entity['machine_id']:
# Handling for local entities.
mongo.db.groupsandusers.update({'SID': entity['SID'],
'machine_id': entity['machine_id']}, entity, upsert=True)
else:
# Handlings for domain entities.
if not mongo.db.groupsandusers.find_one({'SID': entity['SID']}):
mongo.db.groupsandusers.insert_one(entity)
else:
# if entity is domain entity, add the monkey id of current machine to secrets_location.
# (found on this machine)
if entity.get('NTLM_secret'):
mongo.db.groupsandusers.update_one({'SID': entity['SID'], 'type': 1},
{'$addToSet': {'secret_location': self.monkey_id}})
def update_admins_retrospective(self):
for profile in self.info_for_mongo:
groups_from_mongo = mongo.db.groupsandusers.find({
'SID': {'$in': self.info_for_mongo[profile]['member_of']}},
{'admin_on_machines': 1})
for group in groups_from_mongo:
if group['admin_on_machines']:
mongo.db.groupsandusers.update_one({'SID': self.info_for_mongo[profile]['SID']},
{'$addToSet': {'admin_on_machines': {
'$each': group['admin_on_machines']}}})
def add_admin(self, group, machine_id):
for sid in group['entities_list']:
mongo.db.groupsandusers.update_one({'SID': sid},
{'$addToSet': {'admin_on_machines': machine_id}})
entity_details = mongo.db.groupsandusers.find_one({'SID': sid},
{'type': 1, 'entities_list': 1})
if entity_details.get('type') == 2:
self.add_admin(entity_details, machine_id)