WIP pth feature

This commit is contained in:
maor.rayzin 2018-10-11 16:20:12 +03:00
parent 81694862b6
commit 9a05d0e87d
11 changed files with 1515 additions and 1101 deletions

View File

@ -13,7 +13,4 @@ PyInstaller
six
ecdsa
netifaces
nos
ipaddress
wmi

View File

@ -130,6 +130,7 @@ class WindowsInfoCollector(InfoCollector):
super(WindowsInfoCollector, self).__init__()
self._config = infection_monkey.config.WormConfiguration
self.info['reg'] = {}
self.info['wmi'] = {}
def get_info(self):
"""
@ -164,7 +165,7 @@ class WindowsInfoCollector(InfoCollector):
def get_wmi_info(self):
for wmi_class_name in WMI_CLASSES:
self.info[wmi_class_name] = self.get_wmi_class(wmi_class_name)
self.info['wmi'][wmi_class_name] = self.get_wmi_class(wmi_class_name)
def get_wmi_class(self, class_name, moniker="//./root/cimv2", properties=None):
_wmi = wmi.WMI(moniker=moniker)

View File

@ -17,7 +17,7 @@
"info_file_handler": {
"class": "logging.handlers.RotatingFileHandler",
"level": "INFO",
"level": "DEBUG",
"formatter": "simple",
"filename": "info.log",
"maxBytes": 10485760,
@ -27,7 +27,7 @@
},
"root": {
"level": "INFO",
"level": "DEBUG",
"handlers": ["console", "info_file_handler"]
}
}

View File

@ -10,6 +10,7 @@ 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.config import ConfigService
from cc.services.edge import EdgeService
from cc.services.node import NodeService
@ -170,6 +171,8 @@ class Telemetry(flask_restful.Resource):
@staticmethod
def process_system_info_telemetry(telemetry_json):
users_secrets = {}
monkey_id = NodeService.get_monkey_by_guid(telemetry_json['monkey_guid']).get('_id')
if 'ssh_info' in telemetry_json['data']:
ssh_info = telemetry_json['data']['ssh_info']
Telemetry.encrypt_system_info_ssh_keys(ssh_info)
@ -182,6 +185,142 @@ class Telemetry(flask_restful.Resource):
Telemetry.encrypt_system_info_creds(creds)
Telemetry.add_system_info_creds_to_config(creds)
Telemetry.replace_user_dot_with_comma(creds)
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']:
mongo.db.groupsandusers.update({'SID': entity['SID'],
'machine_id': entity['machine_id']}, entity, upsert=True)
else:
if not mongo.db.groupsandusers.find_one({'SID': entity['SID']}):
mongo.db.groupsandusers.insert_one(entity)
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)
################################################################
@staticmethod
def add_ip_to_ssh_keys(ip, ssh_info):

View File

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

View File

@ -1,4 +1,6 @@
from cc.services.pth_report_utils import PassTheHashReport, Machine
from cc.database import mongo
from bson import ObjectId
class PTHReportService(object):
@ -10,29 +12,95 @@ class PTHReportService(object):
def __init__(self):
pass
@staticmethod
def get_duplicated_password_nodes(pth):
"""
"""
usernames_lists = []
usernames_per_sid_list = []
dups = dict(map(lambda x: (x, len(pth.GetSidsBySecret(x))), pth.GetAllSecrets()))
for secret, count in sorted(dups.iteritems(), key=lambda (k, v): (v, k), reverse=True):
if count <= 1:
continue
for sid in pth.GetSidsBySecret(secret):
if sid:
usernames_per_sid_list.append(pth.GetUsernameBySid(sid))
usernames_lists.append({'cred_group': usernames_per_sid_list})
return usernames_lists
@staticmethod
def get_shared_local_admins_nodes(pth):
def get_duplicated_passwords_nodes():
users_cred_groups = []
pipeline = [
{"$match": {
'NTLM_secret': {
"$exists": "true", "$ne": None}
}},
{
"$group": {
"_id": {
"NTLM_secret": "$NTLM_secret"},
"count": {"$sum": 1},
"Docs": {"$push": {'_id': "$_id", 'name': '$name', 'domain_name': '$domain_name',
'machine_id': '$machine_id'}}
}},
{'$match': {'count': {'$gt': 1}}}
]
docs = mongo.db.groupsandusers.aggregate(pipeline)
for doc in docs:
users_list = []
for user in doc['Docs']:
hostname = None
if user['machine_id']:
machine = mongo.db.monkey.find_one({'_id': ObjectId(user['machine_id'])}, {'hostname': 1})
if machine.get('hostname'):
hostname = machine['hostname']
users_list.append({'username': user['name'], 'domain_name': user['domain_name'],
'hostname': hostname})
users_cred_groups.append({'cred_groups': users_list})
return users_cred_groups
@staticmethod
def get_duplicated_passwords_issues():
# TODO: Fix bug if both local and non local account share the same password
user_groups = PTHReportService.get_duplicated_passwords_nodes()
issues = []
users_gathered = []
for group in user_groups:
for user_info in group['cred_groups']:
users_gathered.append(user_info['username'])
issues.append(
{
'type': 'shared_passwords_domain' if user_info['domain_name'] else 'shared_passwords',
'machine': user_info['hostname'] if user_info['hostname'] else user_info['domain_name'],
'shared_with': [i['username'] for i in group['cred_groups']],
'is_local': False if user_info['domain_name'] else True
}
)
break
return issues
@staticmethod
def get_shared_admins_nodes():
admins = mongo.db.groupsandusers.find({'type': 1, 'admin_on_machines.1': {'$exists': True}},
{'admin_on_machines': 1, 'name': 1, 'domain_name': 1})
admins_info_list = []
for admin in admins:
machines = mongo.db.monkey.find({'_id': {'$in': admin['admin_on_machines']}}, {'hostname': 1})
# appends the host names of the machines this user is admin on.
admins_info_list.append({'name': admin['name'],'domain_name': admin['domain_name'],
'admin_on_machines': [i['hostname'] for i in list(machines)]})
return admins_info_list
@staticmethod
def get_shared_admins_issues():
admins_info = PTHReportService.get_shared_admins_nodes()
issues = []
for admin in admins_info:
issues.append(
{
'is_local': False,
'type': 'shared_admins_domain',
'machine': admin['domain_name'],
'username': admin['name'],
'shared_machines': admin['admin_on_machines'],
}
)
return issues
@staticmethod
def old_get_shared_local_admins_nodes(pth):
dups = dict(map(lambda x: (x, len(pth.GetSharedAdmins(x))), pth.machines))
shared_admin_machines = []
for m, count in sorted(dups.iteritems(), key=lambda (k, v): (v, k), reverse=True):
@ -135,41 +203,8 @@ class PTHReportService(object):
strong_users_non_crit_list.append(machine)
return strong_users_non_crit_list
@staticmethod
def get_duplicated_passwords_issues(pth, password_groups):
issues = []
previeous_group = []
for group in password_groups:
username = group['cred_group'][0]
if username in previeous_group:
continue
sid = list(pth.GetSidsByUsername(username.split('\\')[1]))
machine_info = pth.GetSidInfo(sid[0])
issues.append(
{
'type': 'shared_passwords',
'machine': machine_info.get('hostname').split('.')[0],
'shared_with': group['cred_group']
}
)
previeous_group += group['cred_group']
return issues
@staticmethod
def get_shared_local_admins_issues(shared_admins_machines):
issues = []
for machine in shared_admins_machines:
issues.append(
{
'type': 'shared_admins',
'machine': machine.get('hostname'),
'shared_accounts': machine.get('admins_accounts'),
'ip': machine.get('ip'),
}
)
return issues
@staticmethod
def strong_users_on_crit_issues(strong_users):
@ -227,25 +262,23 @@ class PTHReportService(object):
@staticmethod
def get_report():
issues = []
pth = PassTheHashReport()
same_password = PTHReportService.get_duplicated_password_nodes(pth)
local_admin_shared = PTHReportService.get_shared_local_admins_nodes(pth)
strong_users_on_crit_services = PTHReportService.get_strong_users_on_crit_services_by_user(pth)
strong_users_on_non_crit_services = PTHReportService.get_strong_users_on_non_crit_services(pth)
issues += PTHReportService.get_duplicated_passwords_issues(pth, same_password)
issues += PTHReportService.get_shared_local_admins_issues(local_admin_shared)
issues += PTHReportService.strong_users_on_crit_issues(
PTHReportService.get_strong_users_on_crit_services_by_machine(pth))
issues += PTHReportService.get_duplicated_passwords_issues()
# issues += PTHReportService.get_shared_local_admins_issues(local_admin_shared)
# issues += PTHReportService.strong_users_on_crit_issues(
# PTHReportService.get_strong_users_on_crit_services_by_machine(pth))
report = \
{
'report_info':
{
'same_password': same_password,
'local_admin_shared': local_admin_shared,
'strong_users_on_crit_services': strong_users_on_crit_services,
'strong_users_on_non_crit_services': strong_users_on_non_crit_services,
'pth_issues': issues

View File

@ -1,5 +1,6 @@
import itertools
import functools
import pprint
import ipaddress
import logging
@ -184,6 +185,10 @@ class ReportService:
logger.info('Stolen creds generated for reporting')
return creds
@staticmethod
def get_pth_shared_passwords():
pass
@staticmethod
def get_ssh_keys():
"""
@ -531,23 +536,42 @@ class ReportService:
return cross_segment_issues
@staticmethod
def get_domain_issues():
ISSUE_GENERATORS = [
PTHReportService.get_duplicated_passwords_issues,
PTHReportService.get_shared_admins_issues,
]
issues = functools.reduce(lambda acc, issue_gen: acc + issue_gen(), ISSUE_GENERATORS, [])
domain_issues_dict = {}
for issue in issues:
if not issue.get('is_local', True):
machine = issue.get('machine', '').upper()
if machine not in domain_issues_dict:
domain_issues_dict[machine] = []
domain_issues_dict[machine].append(issue)
logger.info('Domain issues generated for reporting')
return domain_issues_dict
@staticmethod
def get_issues():
ISSUE_GENERATORS = [
ReportService.get_exploits,
ReportService.get_tunnels,
ReportService.get_island_cross_segment_issues,
ReportService.get_azure_issues
ReportService.get_azure_issues,
PTHReportService.get_duplicated_passwords_issues
]
#TODO: PTHReportService.get_report().get('report_info').get('pth_issues', [])
issues = functools.reduce(lambda acc, issue_gen: acc + issue_gen(), ISSUE_GENERATORS, [])
issues_dict = {}
for issue in issues:
machine = issue.get('machine', '').upper()
if machine not in issues_dict:
issues_dict[machine] = []
issues_dict[machine].append(issue)
if issue.get('is_local', True):
machine = issue.get('machine', '').upper()
if machine not in issues_dict:
issues_dict[machine] = []
issues_dict[machine].append(issue)
logger.info('Issues generated for reporting')
return issues_dict
@ -657,13 +681,13 @@ class ReportService:
@staticmethod
def get_report():
domain_issues = ReportService.get_domain_issues()
issues = ReportService.get_issues()
config_users = ReportService.get_config_users()
config_passwords = ReportService.get_config_passwords()
cross_segment_issues = ReportService.get_cross_segment_issues()
pth_report = PTHReportService.get_report()
report = \
{
'overview':
@ -690,7 +714,8 @@ class ReportService:
},
'recommendations':
{
'issues': issues
'issues': issues,
'domain_issues': domain_issues
},
'pth':
{

View File

@ -0,0 +1,43 @@
def extract_sam_secrets(mim_string, users_dict):
users_secrets = mim_string.split("\n42.")[1].split("\nSAMKey :")[1].split("\n\n")[1:]
if mim_string.count("\n42.") != 2:
return {}
for sam_user_txt in users_secrets:
sam_user = dict([map(unicode.strip, line.split(":")) for line in
filter(lambda l: l.count(":") == 1, sam_user_txt.splitlines())])
username = sam_user.get("User")
users_dict[username] = {}
ntlm = sam_user.get("NTLM")
if "[hashed secret]" not in ntlm:
continue
users_dict[username]['SAM'] = ntlm.replace("[hashed secret]", "").strip()
def extract_ntlm_secrets(mim_string, users_dict):
if mim_string.count("\n42.") != 2:
return {}
ntds_users = mim_string.split("\n42.")[2].split("\nRID :")[1:]
for ntds_user_txt in ntds_users:
user = ntds_user_txt.split("User :")[1].splitlines()[0].replace("User :", "").strip()
ntlm = ntds_user_txt.split("* Primary\n NTLM :")[1].splitlines()[0].replace("NTLM :", "").strip()
ntlm = ntlm.replace("[hashed secret]", "").strip()
users_dict[user] = {}
if ntlm:
users_dict[user]['ntlm'] = ntlm
def extract_secrets_from_mimikatz(mim_string):
users_dict = {}
extract_sam_secrets(mim_string, users_dict)
extract_ntlm_secrets(mim_string, users_dict)
return users_dict

File diff suppressed because it is too large Load Diff

View File

@ -31,14 +31,14 @@
"babel-preset-react": "^6.24.1",
"babel-preset-stage-0": "^6.5.0",
"bower-webpack-plugin": "^0.1.9",
"chai": "^4.1.2",
"copyfiles": "^2.0.0",
"chai": "^4.2.0",
"copyfiles": "^2.1.0",
"css-loader": "^1.0.0",
"eslint": "^5.3.0",
"eslint-loader": "^2.1.0",
"eslint": "^5.6.1",
"eslint-loader": "^2.1.1",
"eslint-plugin-react": "^7.11.1",
"file-loader": "^1.1.11",
"glob": "^7.0.0",
"glob": "^7.1.3",
"html-loader": "^0.5.5",
"html-webpack-plugin": "^3.2.0",
"karma": "^3.0.0",
@ -48,44 +48,44 @@
"karma-mocha-reporter": "^2.2.5",
"karma-phantomjs-launcher": "^1.0.0",
"karma-sourcemap-loader": "^0.3.5",
"karma-webpack": "^3.0.0",
"karma-webpack": "^3.0.5",
"minimist": "^1.2.0",
"mocha": "^5.2.0",
"null-loader": "^0.1.1",
"open": "0.0.5",
"phantomjs-prebuilt": "^2.1.16",
"react-addons-test-utils": "^15.6.2",
"react-hot-loader": "^4.3.4",
"react-hot-loader": "^4.3.11",
"rimraf": "^2.6.2",
"style-loader": "^0.22.1",
"url-loader": "^1.1.0",
"webpack": "^4.16.5",
"webpack-cli": "^3.1.0",
"webpack-dev-server": "^3.1.5"
"url-loader": "^1.1.2",
"webpack": "^4.20.2",
"webpack-cli": "^3.1.2",
"webpack-dev-server": "^3.1.9"
},
"dependencies": {
"bootstrap": "3.3.7",
"core-js": "^2.5.7",
"downloadjs": "^1.4.7",
"fetch": "^1.1.0",
"js-file-download": "^0.4.1",
"js-file-download": "^0.4.4",
"json-loader": "^0.5.7",
"jwt-decode": "^2.2.0",
"moment": "^2.22.2",
"normalize.css": "^8.0.0",
"npm": "^6.3.0",
"npm": "^6.4.1",
"prop-types": "^15.6.2",
"rc-progress": "^2.2.5",
"react": "^16.4.2",
"react-bootstrap": "^0.32.1",
"rc-progress": "^2.2.6",
"react": "^16.5.2",
"react-bootstrap": "^0.32.4",
"react-copy-to-clipboard": "^5.0.1",
"react-data-components": "^1.2.0",
"react-dimensions": "^1.3.0",
"react-dom": "^16.4.2",
"react-dom": "^16.5.2",
"react-fa": "^5.0.0",
"react-graph-vis": "^1.0.2",
"react-json-tree": "^0.11.0",
"react-jsonschema-form": "^1.0.4",
"react-jsonschema-form": "^1.0.5",
"react-redux": "^5.0.7",
"react-router-dom": "^4.3.1",
"react-table": "^6.8.6",

View File

@ -39,7 +39,8 @@ class ReportPageComponent extends AuthComponent {
CROSS_SEGMENT: 0,
TUNNEL: 1,
SHARED_LOCAL_ADMIN: 2,
SHARED_PASSWORDS: 3
SHARED_PASSWORDS: 3,
SHARED_PASSWORDS_DOMAIN: 4
};
constructor(props) {
@ -375,6 +376,8 @@ class ReportPageComponent extends AuthComponent {
<li>Weak segmentation - Machines were able to communicate over unused ports.</li> : null}
{this.state.report.overview.warnings[this.Warning.SHARED_LOCAL_ADMIN] ?
<li>The monkey has found that some users have administrative rights on several machines.</li> : null}
{this.state.report.overview.warnings[this.Warning.SHARED_PASSWORDS_DOMAIN] ?
<li>The monkey has found that some users are sharing passwords on domain accounts.</li> : null}
{this.state.report.overview.warnings[this.Warning.SHARED_PASSWORDS] ?
<li>The monkey has found that some users are sharing passwords.</li> : null}
</ul>
@ -413,6 +416,12 @@ class ReportPageComponent extends AuthComponent {
<div>
{this.generateIssues(this.state.report.recommendations.issues)}
</div>
<h3>
Domain related recommendations
</h3>
<div>
{this.generateIssues(this.state.report.recommendations.domain_issues)}
</div>
</div>
);
}
@ -465,9 +474,6 @@ class ReportPageComponent extends AuthComponent {
<div style={{marginBottom: '20px'}}>
<StolenPasswords data={this.state.report.glance.stolen_creds.concat(this.state.report.glance.ssh_keys)}/>
</div>
<div>
<StolenPasswords data={this.state.report.glance.stolen_creds.concat(this.state.report.glance.ssh_keys)}/>
</div>
<div>
<StrongUsers data = {this.state.pthreport.strong_users_on_crit_services} />
</div>
@ -745,6 +751,18 @@ class ReportPageComponent extends AuthComponent {
);
}
generateSharedCredsDomainIssue(issue) {
return (
<li>
Some domain users are sharing passwords, this should be fixed by changing passwords.
<CollapsibleWellComponent>
These users are sharing access password:
{this.generateInfoBadges(issue.shared_with)}.
</CollapsibleWellComponent>
</li>
);
}
generateSharedCredsIssue(issue) {
return (
<li>
@ -760,10 +778,10 @@ class ReportPageComponent extends AuthComponent {
generateSharedLocalAdminsIssue(issue) {
return (
<li>
This machine shares a local admin account with another machine
Credentials for the user <span className="label label-primary">{issue.username}</span> could be found and the user is an administrator account on more than one machines in the domain.
<CollapsibleWellComponent>
Here is a list showing users that are acting as admins on this machine and others:
{this.generateInfoBadges(issue.shared_accounts)}
Here is a list of machines which has this account defined as an administrator:
{this.generateInfoBadges(issue.shared_machines)}
</CollapsibleWellComponent>
</li>
);
@ -892,7 +910,10 @@ class ReportPageComponent extends AuthComponent {
case 'shared_passwords':
data = this.generateSharedCredsIssue(issue);
break;
case 'shared_admins':
case 'shared_passwords_domain':
data = this.generateSharedCredsDomainIssue(issue);
break;
case 'shared_admins_domain':
data = this.generateSharedLocalAdminsIssue(issue);
break;
case 'strong_users_on_crit':