re-arranged the code and cleaned up a bit
This commit is contained in:
parent
b443652b0e
commit
c208d0ebe8
|
@ -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):
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
|
||||
|
||||
ADMINISTRATORS_GROUP_KNOWN_SID = '1-5-32-544'
|
||||
|
|
@ -41,3 +41,5 @@ def extract_secrets_from_mimikatz(mim_string):
|
|||
extract_ntlm_secrets(mim_string, users_dict)
|
||||
|
||||
return users_dict
|
||||
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
Loading…
Reference in New Issue