* CR comments fixed

This commit is contained in:
maor.rayzin 2018-09-04 17:18:01 +03:00
parent c373bfbcfb
commit 9eb2895c49
9 changed files with 13 additions and 575 deletions

View File

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

View File

@ -21,10 +21,10 @@ class MimikatzCollector(object):
self._dll = ctypes.WinDLL(self._config.mimikatz_dll_name) self._dll = ctypes.WinDLL(self._config.mimikatz_dll_name)
collect_proto = ctypes.WINFUNCTYPE(ctypes.c_int) collect_proto = ctypes.WINFUNCTYPE(ctypes.c_int)
get_proto = ctypes.WINFUNCTYPE(MimikatzCollector.LogonData) get_proto = ctypes.WINFUNCTYPE(MimikatzCollector.LogonData)
getTextOutput = ctypes.WINFUNCTYPE(ctypes.c_wchar_p) get_text_output_proto = ctypes.WINFUNCTYPE(ctypes.c_wchar_p)
self._collect = collect_proto(("collect", self._dll)) self._collect = collect_proto(("collect", self._dll))
self._get = get_proto(("get", self._dll)) self._get = get_proto(("get", self._dll))
self._getTextOutput = getTextOutput(("getTextOutput", self._dll)) self._get_text_output_proto = get_text_output_proto(("getTextOutput", self._dll))
self._isInit = True self._isInit = True
except Exception: except Exception:
LOG.exception("Error initializing mimikatz collector") LOG.exception("Error initializing mimikatz collector")
@ -44,7 +44,7 @@ class MimikatzCollector(object):
logon_data_dictionary = {} logon_data_dictionary = {}
hostname = socket.gethostname() hostname = socket.gethostname()
self.mimikatz_text = self._getTextOutput() self.mimikatz_text = self._get_text_output_proto()
for i in range(entry_count): for i in range(entry_count):
entry = self._get() entry = self._get()

View File

@ -113,12 +113,11 @@ def fix_wmi_obj_for_mongo(o):
row[method_name[3:]] = value row[method_name[3:]] = value
except wmi.x_wmi: except wmi.x_wmi:
#LOG.error("Error running wmi method '%s'" % (method_name, ))
#LOG.error(traceback.format_exc())
continue continue
return row return row
class WindowsInfoCollector(InfoCollector): class WindowsInfoCollector(InfoCollector):
""" """
System information collecting module for Windows operating systems System information collecting module for Windows operating systems
@ -126,6 +125,7 @@ class WindowsInfoCollector(InfoCollector):
def __init__(self): def __init__(self):
super(WindowsInfoCollector, self).__init__() super(WindowsInfoCollector, self).__init__()
self.info['reg'] = {}
def get_info(self): def get_info(self):
""" """
@ -162,9 +162,6 @@ class WindowsInfoCollector(InfoCollector):
for wmi_class_name in WMI_CLASSES: for wmi_class_name in WMI_CLASSES:
self.info[wmi_class_name] = self.get_wmi_class(wmi_class_name) self.info[wmi_class_name] = self.get_wmi_class(wmi_class_name)
# for wmi_class_name, props in WMI_LDAP_CLASSES.iteritems():
# self.info[wmi_class_name] = self.get_wmi_class(wmi_class_name, "//./root/directory/ldap", props)
def get_wmi_class(self, class_name, moniker="//./root/cimv2", properties=None): def get_wmi_class(self, class_name, moniker="//./root/cimv2", properties=None):
_wmi = wmi.WMI(moniker=moniker) _wmi = wmi.WMI(moniker=moniker)
@ -175,8 +172,6 @@ class WindowsInfoCollector(InfoCollector):
wmi_class = getattr(_wmi, class_name)(properties) wmi_class = getattr(_wmi, class_name)(properties)
except wmi.x_wmi: except wmi.x_wmi:
#LOG.error("Error getting wmi class '%s'" % (class_name, ))
#LOG.error(traceback.format_exc())
return return
return fix_obj_for_mongo(wmi_class) return fix_obj_for_mongo(wmi_class)
@ -188,7 +183,7 @@ class WindowsInfoCollector(InfoCollector):
d = dict([_winreg.EnumValue(subkey, i)[:2] for i in xrange(_winreg.QueryInfoKey(subkey)[0])]) d = dict([_winreg.EnumValue(subkey, i)[:2] for i in xrange(_winreg.QueryInfoKey(subkey)[0])])
d = fix_obj_for_mongo(d) d = fix_obj_for_mongo(d)
self.info[subkey_path] = d self.info['reg'][subkey_path] = d
subkey.Close() subkey.Close()
key.Close() key.Close()

View File

@ -19,8 +19,6 @@ from cc.resources.monkey import Monkey
from cc.resources.monkey_configuration import MonkeyConfiguration from cc.resources.monkey_configuration import MonkeyConfiguration
from cc.resources.monkey_download import MonkeyDownload from cc.resources.monkey_download import MonkeyDownload
from cc.resources.netmap import NetMap from cc.resources.netmap import NetMap
from cc.resources.pthmap import PthMap
from cc.resources.pthreport import PTHReport
from cc.resources.node import Node from cc.resources.node import Node
from cc.resources.report import Report from cc.resources.report import Report
from cc.resources.root import Root from cc.resources.root import Root
@ -108,7 +106,5 @@ def init_app(mongo_url):
api.add_resource(TelemetryFeed, '/api/telemetry-feed', '/api/telemetry-feed/') api.add_resource(TelemetryFeed, '/api/telemetry-feed', '/api/telemetry-feed/')
api.add_resource(Log, '/api/log', '/api/log/') api.add_resource(Log, '/api/log', '/api/log/')
api.add_resource(IslandLog, '/api/log/island/download', '/api/log/island/download/') api.add_resource(IslandLog, '/api/log/island/download', '/api/log/island/download/')
api.add_resource(PthMap, '/api/pthmap', '/api/pthmap/')
api.add_resource(PTHReport, '/api/pthreport', '/api/pthreport/')
return app return app

View File

@ -1,21 +0,0 @@
import copy
import flask_restful
from cc.auth import jwt_required
from cc.services.pth_report_utils import PassTheHashReport, Machine
class PthMap(flask_restful.Resource):
@jwt_required()
def get(self, **kw):
pth = PassTheHashReport()
v = copy.deepcopy(pth.vertices)
e = copy.deepcopy(pth.edges)
return \
{
"nodes": [{"id": x, "label": Machine(x).GetIp()} for x in v],
"edges": [{"id": str(s) + str(t), "from": s, "to": t, "label": label} for s, t, label in e]
}

View File

@ -1,13 +0,0 @@
import flask_restful
from cc.auth import jwt_required
from cc.services.pth_report import PTHReportService
__author__ = "maor.rayzin"
class PTHReport(flask_restful.Resource):
@jwt_required()
def get(self):
return PTHReportService.get_report()

View File

@ -257,178 +257,4 @@ class PTHReportService(object):
'edges': pth.edges 'edges': pth.edges
} }
} }
return report return report
# print """<div class="hidden">"""
#
# print "<h2>Cached Passwords</h2>"
# print "<h3>On how many machines each secret is cached (possible attacker count)?</h3>"
# cache_counts = dict(map(lambda x: (x, pth.GetAttackCountBySecret(x)), pth.GetAllSecrets()))
#
# print """<table>"""
# print """<tr><th>Secret</th><th>Machine Count</th></tr>"""
# for secret, count in sorted(cache_counts.iteritems(), key=lambda (k,v): (v,k), reverse=True):
# if count <= 0:
# continue
# print """<tr><td><a href="#{secret}">{secret}</a></td><td>{count}</td>""".format(secret=secret, count=count)
# print """</table>"""
#
# print "<h2>User's Creds</h2>"
# print "<h3>To how many machines each user is able to connect with admin rights</h3>"
# attackable_counts = dict(map(lambda x: (x, pth.GetVictimCountBySid(x)), pth.GetAllSids()))
#
# print """<table>"""
# print """<tr><th>SID</th><th>Username</th><th>Machine Count</th></tr>"""
# for sid, count in sorted(attackable_counts.iteritems(), key=lambda (k,v): (v,k), reverse=True):
# if count <= 1:
# continue
# print """<tr><td><a href="#{sid}">{sid}</a></td><td>{username}</td><td>{count}</td>""".format(sid=sid, username=pth.GetUsernameBySid(sid), count=count)
# print """</table>"""
#
# print "<h2>Actual Possible Attacks By SID</h2>"
# print "<h3>How many attacks possible using each SID (aka len(attacker->victim pairs))</h3>"
# possible_attacks_by_sid = dict(map(lambda x: (x, pth.GetPossibleAttackCountBySid(x)), pth.GetAllSids()))
#
# print """<table>"""
# print """<tr><th>SID</th><th>Username</th><th>Machine Count</th></tr>"""
# for sid, count in sorted(possible_attacks_by_sid.iteritems(), key=lambda (k,v): (v,k), reverse=True):
# if count <= 1:
# continue
# print """<tr><td><a href="#{sid}">{sid}</a></td><td>{username}</td><td>{count}</td>""".format(sid=sid, username=pth.GetUsernameBySid(sid), count=count)
# print """</table>"""
#
# print "<h2>Machine's Creds</h2>"
# print "<h3>To how many machines each machine is able to directly connect with admin rights?</h3>"
# attackable_counts = dict(map(lambda m: (m, pth.GetVictimCountByMachine(m)), pth.machines))
#
# print """<table>"""
# print """<tr><th>Attacker Ip</th><th>Attacker Hostname</th><th>Domain Name</th><th>Victim Machine Count</th></tr>"""
# for m, count in sorted(attackable_counts.iteritems(), key=lambda (k,v): (v,k), reverse=True):
# if count <= 1:
# continue
# print """<tr><td><a href="#{ip}">{ip}</a></td><td>{hostname}</td><td>{domain}</td><td>{count}</td>""".format(ip=m.GetIp(), hostname=m.GetHostName(), domain=m.GetDomainName(), count=count)
# print """</table>"""
#
# print "<h2>Domain Controllers</h2>"
# print "<h3>List of domain controllers (we count them as critical points, so they are listed here)</h3>"
# DCs = dict(map(lambda m: (m, pth.GetInPathCountByVictim(m)), pth.GetAllDomainControllers()))
#
# print """<table>"""
# print """<tr><th>DC Ip</th><th>DC Hostname</th><th>Domain Name</th><th>In-Path Count</th></tr>"""
# for m, path_count in sorted(DCs.iteritems(), key=lambda (k,v): (v,k), reverse=True):
# print """<tr><td><a href="#{ip}">{ip}</a></td><td><a href="#{ip}">{hostname}</a></td><td>{domain}</td><td>{path_count}</td></tr>""".format(ip=m.GetIp(), hostname=m.GetHostName(), domain=m.GetDomainName(), path_count=path_count)
# print """</table>"""
#
# print "<h2>Most Vulnerable Machines</h2>"
# print "<h3>List all machines in the network sorted by the potincial to attack them</h3>"
# all_machines = dict(map(lambda m: (m, pth.GetInPathCountByVictim(m)), pth.machines))
#
# print """<table>"""
# print """<tr><th>Ip</th><th>Hostname</th><th>Domain Name</th><th>In-Path Count</th></tr>"""
# for m, path_count in sorted(all_machines.iteritems(), key=lambda (k,v): (v,k), reverse=True):
# if count <= 0:
# continue
# print """<tr><td><a href="#{ip}">{ip}</a></td><td><a href="#{ip}">{hostname}</a></td><td>{domain}</td><td>{path_count}</td></tr>""".format(ip=m.GetIp(), hostname=m.GetHostName(), domain=m.GetDomainName(), path_count=path_count)
# print """</table>"""
#
# print "<h2>Critical Servers</h2>"
# print "<h3>List of all machines identified as critical servers</h3>"
# critical_servers = pth.GetCritialServers()
#
# print """<table>"""
# print """<tr><th>Ip</th><th>Hostname</th><th>Domain Name</th></tr>"""
# for m in critical_servers:
# print """<tr><td><a href="#{ip}">{ip}</a></td><td><a href="#{ip}">{hostname}</a></td><td>{domain}</td></tr>""".format(ip=m.GetIp(), hostname=m.GetHostName(), domain=m.GetDomainName())
# print """</table>"""
#
# print "<hr />"
#
# for m in pth.machines:
# print """<a name="{ip}"><h2>Machine '{ip}'</h2></a>
# <h3>Hostname '{hostname}'</h3>""".format(ip=m.GetIp(), hostname=m.GetHostName())
#
# print """<h3>Cached SIDs</h3>"""
# print """<h4>SIDs cached on this machine</h4>"""
# print """<ul>"""
# for sid in pth.GetCachedSids(m):
# print """<li><a href="#{sid}">{username} ({sid})</a></li>""".format(username=pth.GetUsernameBySid(sid), sid=sid)
# print """</ul>"""
#
# print """<h3>Possible Attackers</h3>"""
# print """<h4>Machines that can attack this machine</h4>"""
# print """<ul>"""
# for attacker in pth.GetAttackersByVictim(m):
# print """<li><a href="#{ip}">{ip} ({hostname})</a></li>""".format(ip=attacker.GetIp(), hostname=attacker.GetHostName())
# print """</ul>"""
#
#
# print """<h3>Admins</h3>"""
# print """<h4>Users that have admin rights on this machine</h4>"""
# print """<ul>"""
# for sid in m.GetAdmins():
# print """<li><a href="#{sid}">{username} ({sid})</a></li>""".format(username=m.GetUsernameBySid(sid), sid=sid)
# print """</ul>"""
#
# print """<h3>Installed Critical Services</h3>"""
# print """<h4>List of crtical services found installed on machine</h4>"""
# print """<ul>"""
# for service_name in m.GetCriticalServicesInstalled():
# print """<li>{service_name}</li>""".format(service_name=service_name)
# print """</ul>"""
#
#
# print "<hr />"
#
# for username in pth.GetAllUsernames():
# print """<a name="{username}"><h2>User '{username}'</h2></a>""".format(username=username)
#
# print """<h3>Matching SIDs</h3>"""
# print """<ul>"""
# for sid in pth.GetSidsByUsername(username):
# print """<li><a href="#{sid}">{username} ({sid})</a></li>""".format(username=pth.GetUsernameBySid(sid),
# sid=sid)
# print """</ul>"""
#
# print "<hr />"
#
# for sid in pth.GetAllSids():
# print """<a name="{sid}"><h2>SID '{sid}'</h2></a>
# <h3>Username: '<a href="#{username}">{username}</a>'</h3>
# <h3>Domain: {domain}</h3>
# <h3>Secret: '<a href="#{secret}">{secret}</a>'</h3>
# """.format(username=pth.GetUsernameBySid(sid), sid=sid, secret=pth.GetSecretBySid(sid),
# domain=pth.GetSidInfo(sid)["Domain"])
#
# print """<h3>Machines the sid is local admin on</h3>"""
# print """<ul>"""
# for m in pth.GetVictimsBySid(sid):
# print """<li><a href="#{ip}">{ip} ({hostname})</a></li>""".format(ip=m.GetIp(), hostname=m.GetHostName())
# print """</ul>"""
#
# print """<h3>Machines the sid is in thier cache</h3>"""
# print """<ul>"""
# for m in pth.GetAttackersBySid(sid):
# print """<li><a href="#{ip}">{ip} ({hostname})</a></li>""".format(ip=m.GetIp(), hostname=m.GetHostName())
# print """</ul>"""
#
# for secret in pth.GetAllSecrets():
# print """<a name="{secret}"><h2>Secret '{secret}'</h2></a>""".format(secret=secret)
#
# print """<h3>SIDs that use that secret</h3>"""
# print """<ul>"""
# for sid in pth.GetSidsBySecret(secret):
# print """<li><a href="#{sid}">{username} ({sid})</a></li>""".format(username=pth.GetUsernameBySid(sid),
# sid=sid)
# print """</ul>"""
#
# print """<h3>Attackable Machines with that secret</h3>"""
# print """<ul>"""
# for m in pth.GetVictimsBySecret(secret):
# print """<li><a href="#{ip}">{hostname}</a></li>""".format(ip=m.GetIp(), hostname=m.GetHostName())
# print """</ul>"""
#
# print """<h3>Machines that have this secret cached and can use it to attack other machines</h3>"""
# print """<ul>"""
# for m in pth.GetAttackersBySecret(secret):
# print """<li><a href="#{ip}">{hostname}</a></li>""".format(ip=m.GetIp(), hostname=m.GetHostName())
# print """</ul>"""

View File

@ -329,7 +329,6 @@ class Machine(object):
if "cimv2:Win32_UserAccount" not in wmi_id: if "cimv2:Win32_UserAccount" not in wmi_id:
continue continue
# u'\\\\WIN-BFA01FFQFLS\\root\\cimv2:Win32_UserAccount.Domain="MYDOMAIN",Name="WIN-BFA01FFQFLS$"'
username = wmi_id.split('cimv2:Win32_UserAccount.Domain="')[1].split('",Name="')[0] username = wmi_id.split('cimv2:Win32_UserAccount.Domain="')[1].split('",Name="')[0]
domain = wmi_id.split('cimv2:Win32_UserAccount.Domain="')[1].split('",Name="')[1][:-1] domain = wmi_id.split('cimv2:Win32_UserAccount.Domain="')[1].split('",Name="')[1][:-1]
@ -556,12 +555,6 @@ class Machine(object):
class PassTheHashReport(object): class PassTheHashReport(object):
# _instance = None
# def __new__(class_, *args, **kwargs):
# if not class_._instance:
# class_._instance = object.__new__(class_, *args, **kwargs)
#
# return class_._instance
def __init__(self): def __init__(self):
self.vertices = self.GetAllMachines() self.vertices = self.GetAllMachines()
@ -582,15 +575,12 @@ class PassTheHashReport(object):
return GUIDs return GUIDs
@cache @cache
def ReprSidList(self, sid_list, attacker, victim): def ReprSidList(self, sid_list, victim):
users_list = [] users_list = []
for sid in sid_list: for sid in sid_list:
username = Machine(victim).GetUsernameBySid(sid) username = Machine(victim).GetUsernameBySid(sid)
# if not username:
# username = Machine(attacker).GetUsernameBySid(sid)
if username: if username:
users_list.append(username) users_list.append(username)
@ -631,7 +621,7 @@ class PassTheHashReport(object):
cached_admins = [i for i in cached if i in admins] cached_admins = [i for i in cached if i in admins]
if cached_admins: if cached_admins:
relevant_users_list = self.ReprSidList(cached_admins, attacker, victim) relevant_users_list = self.ReprSidList(cached_admins, victim)
edges_list.append( edges_list.append(
{ {
'from': attacker, 'from': attacker,
@ -680,11 +670,6 @@ class PassTheHashReport(object):
return edges return edges
@cache
def Print(self):
print map(lambda x: Machine(x).GetIp(), self.vertices)
print map(lambda x: (Machine(x[0]).GetIp(), Machine(x[1]).GetIp()), self.edges)
@cache @cache
def GetPossibleAttackCountBySid(self, sid): def GetPossibleAttackCountBySid(self, sid):
return len(self.GetPossibleAttacksBySid(sid)) return len(self.GetPossibleAttacksBySid(sid))
@ -970,5 +955,6 @@ class PassTheHashReport(object):
#shared_admins |= (m.GetLocalAdminSids() & other.GetLocalAdminSids()) #shared_admins |= (m.GetLocalAdminSids() & other.GetLocalAdminSids())
#shared_admins -= m.GetDomainAdminsOfMachine() shared_admins = [admin for admin in shared_admins if admin not in list(m.GetDomainAdminsOfMachine())]
return shared_admins
return shared_admins

View File

@ -1,330 +0,0 @@
import hashlib
import binascii
from pymongo import MongoClient
db = MongoClient().monkeyisland
DsRole_RoleStandaloneWorkstation = 0
DsRole_RoleMemberWorkstation = 1
DsRole_RoleStandaloneServer = 2
DsRole_RoleMemberServer = 3
DsRole_RoleBackupDomainController = 4
DsRole_RolePrimaryDomainController = 5
def myntlm(x):
hash = hashlib.new('md4', x.encode('utf-16le')).digest()
return str(binascii.hexlify(hash))
class Machine(object):
def __init__(self, monkey_guid):
self.monkey_guid = str(monkey_guid)
def GetMimikatzOutput(self):
cur = db.telemetry.find({"telem_type":"system_info_collection", "monkey_guid": self.monkey_guid})
output = set()
for doc in cur:
output.add(doc["data"]["mimikatz"])
if len(output) == 1:
return output.pop()
return None
def GetHostName(self):
cur = db.telemetry.find({"telem_type":"system_info_collection", "monkey_guid": self.monkey_guid})
names = set()
for doc in cur:
for comp in doc["data"]["Win32_ComputerSystem"]:
names.add(eval(comp["Name"]))
if len(names) == 1:
return names.pop()
return None
def GetIp(self):
cur = db.telemetry.find({"telem_type":"system_info_collection", "monkey_guid": self.monkey_guid})
names = set()
for doc in cur:
for addr in doc["data"]["network_info"]["networks"]:
return str(addr["addr"])
return None
def GetDomainName(self):
cur = db.telemetry.find({"telem_type":"system_info_collection", "monkey_guid": self.monkey_guid})
names = set()
for doc in cur:
for comp in doc["data"]["Win32_ComputerSystem"]:
names.add(eval(comp["Domain"]))
if len(names) == 1:
return names.pop()
return None
def GetDomainRole(self):
cur = db.telemetry.find({"telem_type":"system_info_collection", "monkey_guid": self.monkey_guid})
roles = set()
for doc in cur:
for comp in doc["data"]["Win32_ComputerSystem"]:
roles.add(comp["DomainRole"])
if len(roles) == 1:
return roles.pop()
return None
def GetSidByUsername(self, username):
cur = db.telemetry.find({"telem_type":"system_info_collection", "monkey_guid": self.monkey_guid, "data.Win32_UserAccount.Name":"u'%s'" % (username,)})
SIDs = set()
for doc in cur:
for user in doc["data"]["Win32_UserAccount"]:
if eval(user["Name"]) != username:
continue
SIDs.add(eval(user["SID"]))
if len(SIDs) == 1:
return SIDs.pop()
return None
def GetUsernameBySid(self, sid):
cur = db.telemetry.find({"telem_type":"system_info_collection", "monkey_guid": self.monkey_guid, "data.Win32_UserAccount.SID":"u'%s'" % (sid,)})
names = set()
for doc in cur:
for user in doc["data"]["Win32_UserAccount"]:
if eval(user["SID"]) != sid:
continue
names.add(eval(user["Name"]))
if len(names) == 1:
return names.pop()
return None
def GetGroupSidByGroupName(self, group_name):
cur = db.telemetry.find({"telem_type":"system_info_collection", "monkey_guid": self.monkey_guid, "data.Win32_Group.Name":"u'%s'" % (group_name,)})
SIDs = set()
for doc in cur:
for group in doc["data"]["Win32_Group"]:
if eval(group["Name"]) != group_name:
continue
SIDs.add(eval(group["SID"]))
if len(SIDs) == 1:
return SIDs.pop()
return None
def GetUsersByGroupSid(self, sid):
cur = db.telemetry.find({"telem_type":"system_info_collection", "monkey_guid": self.monkey_guid, "data.Win32_GroupUser.GroupComponent.SID":"u'%s'" % (sid,)})
users = dict()
for doc in cur:
for group_user in doc["data"]["Win32_GroupUser"]:
if eval(group_user["GroupComponent"]["SID"]) != sid:
continue
if "PartComponent" not in group_user.keys():
continue
users[eval(group_user["PartComponent"]["SID"])] = eval(group_user["PartComponent"]["Name"])
return users
def GetDomainControllersMonkeyGuidByDomainName(self, domain_name):
cur = db.telemetry.find({"telem_type":"system_info_collection", "data.Win32_ComputerSystem.Domain":"u'%s'" % (domain_name,)})
GUIDs = set()
for doc in cur:
for comp in doc["data"]["Win32_ComputerSystem"]:
if ((comp["DomainRole"] != DsRole_RolePrimaryDomainController) and
(comp["DomainRole"] != DsRole_RoleBackupDomainController)):
continue
GUIDs.add(doc["monkey_guid"])
return GUIDs
def GetLocalAdmins(self):
return set(self.GetUsersByGroupSid(self.GetGroupSidByGroupName("Administrators")).keys())
def GetLocalAdminNames(self):
return set(self.GetUsersByGroupSid(self.GetGroupSidByGroupName("Administrators")).values())
def GetLocalAdminSecrets(self):
admin_names = self.GetLocalAdminNames()
sam_users = str(self.GetMimikatzOutput()).split("\nSAMKey :")[1].split("\n\n")[1:]
admin_secrets = set()
for sam_user_txt in sam_users:
sam_user = dict([map(str.strip, line.split(":")) for line in filter(lambda l: l.count(":") == 1, sam_user_txt.splitlines())])
if sam_user["User"] not in admin_names:
continue
admin_secrets.add(sam_user["NTLM"].replace("[hashed secret]", "").strip())
return admin_secrets
def GetCachedSecrets(self):
cur = db.telemetry.find({"telem_type":"system_info_collection", "monkey_guid": self.monkey_guid})
secrets = set()
for doc in cur:
for username in doc["data"]["credentials"]:
user = doc["data"]["credentials"][username]
if "password" in user.keys():
ntlm = myntlm(str(user["password"]))
elif "ntlm_hash" in user.keys():
ntlm = str(user["ntlm_hash"])
else:
continue
secret = hashlib.md5(ntlm.decode("hex")).hexdigest()
secrets.add(secret)
return secrets
def GetDomainAdminsOfMachine(self):
domain_name = self.GetDomainName()
DCs = self.GetDomainControllersMonkeyGuidByDomainName(domain_name)
domain_admins = set()
for dc_monkey_guid in DCs:
domain_admins |= Machine(dc_monkey_guid).GetLocalAdmins()
return domain_admins
def GetAdmins(self):
return self.GetLocalAdmins() | self.GetDomainAdminsOfMachine()
def GetAdminNames(self):
return set(map(lambda x: self.GetUsernameBySid(x), self.GetAdmins()))
def GetCachedSids(self):
cur = db.telemetry.find({"telem_type":"system_info_collection", "monkey_guid": self.monkey_guid})
SIDs = set()
for doc in cur:
for username in doc["data"]["credentials"]:
SIDs.add(self.GetSidByUsername(username))
return SIDs
def GetCachedUsernames(self):
cur = db.telemetry.find({"telem_type":"system_info_collection", "monkey_guid": self.monkey_guid})
SIDs = set()
for doc in cur:
for username in doc["data"]["credentials"]:
SIDs.add(username)
return SIDs
class PassTheHashMap(object):
def __init__(self):
self.vertices = self.GetAllMachines()
self.edges = set()
self.GenerateEdgesBySid() # Useful for non-cached domain users
self.GenerateEdgesBySamHash() # This will add edges based only on password hash without caring about username
def GetAllMachines(self):
cur = db.telemetry.find({"telem_type":"system_info_collection"})
GUIDs = set()
for doc in cur:
GUIDs.add(doc["monkey_guid"])
return GUIDs
def GenerateEdgesBySid(self):
for attacker in self.vertices:
cached = Machine(attacker).GetCachedSids()
for victim in self.vertices:
if attacker == victim:
continue
admins = Machine(victim).GetAdmins()
if len(cached & admins) > 0:
self.edges.add((attacker, victim))
def GenerateEdgesBySamHash(self):
for attacker in self.vertices:
cached = Machine(attacker).GetCachedSecrets()
for victim in self.vertices:
if attacker == victim:
continue
admins = Machine(victim).GetLocalAdminSecrets()
if len(cached & admins) > 0:
self.edges.add((attacker, victim))
def GenerateEdgesByUsername(self):
for attacker in self.vertices:
cached = Machine(attacker).GetCachedUsernames()
for victim in self.vertices:
if attacker == victim:
continue
admins = Machine(victim).GetAdminNames()
if len(cached & admins) > 0:
self.edges.add((attacker, victim))
def Print(self):
print map(lambda x: Machine(x).GetIp(), self.vertices)
print map(lambda x: (Machine(x[0]).GetIp(), Machine(x[1]).GetIp()), self.edges)
PassTheHashMap().Print()
#monkey_guid_island = 345051728334
#monkey_guid_c = 345051740363
#monkey_guid_d = 345051735830
#
#island = Machine(monkey_guid_island)
#c = Machine(monkey_guid_c)
#d = Machine(monkey_guid_d)
#
#assert str(island.GetIp()).endswith(".5")
#assert str(c.GetIp()).endswith(".203")
#assert str(d.GetIp()).endswith(".204")
#print "sam", island.GetLocalAdminSecrets()
#print "lsa", island.GetCachedSecrets()
#print "cached", c.GetCachedSids()
#print "admins", d.GetAdmins()