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 traceback
import logging
import copy
from datetime import datetime
@ -10,11 +9,12 @@ from flask import request
from cc.auth import jwt_required
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.edge import EdgeService
from cc.services.node import NodeService
from cc.encryptor import encryptor
from cc.services.wmi_info_handler import WMIHandler
__author__ = 'Barak'
@ -188,147 +188,17 @@ class Telemetry(flask_restful.Resource):
if 'mimikatz' in telemetry_json['data']:
users_secrets = user_info.extract_secrets_from_mimikatz(telemetry_json['data'].get('mimikatz', ''))
if 'wmi' in telemetry_json['data']:
info_for_mongo = {}
users_info = telemetry_json['data']['wmi']['Win32_UserAccount']
groups_info = telemetry_json['data']['wmi']['Win32_Group']
group_user_dict = telemetry_json['data']['wmi']['Win32_GroupUser']
Telemetry.add_groups_to_collection(groups_info, info_for_mongo, monkey_id)
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 = WMIHandler(monkey_id, telemetry_json['data']['wmi'], users_secrets)
wmi_handler.add_groups_to_collection()
wmi_handler.add_users_to_collection()
wmi_handler.create_group_user_connection()
wmi_handler.insert_info_to_mongo()
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
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)
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)