forked from p15670423/monkey
* CR comments fixed
This commit is contained in:
parent
c373bfbcfb
commit
9eb2895c49
|
@ -13,7 +13,6 @@ PyInstaller
|
|||
six
|
||||
ecdsa
|
||||
netifaces
|
||||
mock
|
||||
nos
|
||||
ipaddress
|
||||
wmi
|
||||
|
|
|
@ -21,10 +21,10 @@ class MimikatzCollector(object):
|
|||
self._dll = ctypes.WinDLL(self._config.mimikatz_dll_name)
|
||||
collect_proto = ctypes.WINFUNCTYPE(ctypes.c_int)
|
||||
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._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
|
||||
except Exception:
|
||||
LOG.exception("Error initializing mimikatz collector")
|
||||
|
@ -44,7 +44,7 @@ class MimikatzCollector(object):
|
|||
logon_data_dictionary = {}
|
||||
hostname = socket.gethostname()
|
||||
|
||||
self.mimikatz_text = self._getTextOutput()
|
||||
self.mimikatz_text = self._get_text_output_proto()
|
||||
|
||||
for i in range(entry_count):
|
||||
entry = self._get()
|
||||
|
|
|
@ -113,12 +113,11 @@ def fix_wmi_obj_for_mongo(o):
|
|||
row[method_name[3:]] = value
|
||||
|
||||
except wmi.x_wmi:
|
||||
#LOG.error("Error running wmi method '%s'" % (method_name, ))
|
||||
#LOG.error(traceback.format_exc())
|
||||
continue
|
||||
|
||||
return row
|
||||
|
||||
|
||||
class WindowsInfoCollector(InfoCollector):
|
||||
"""
|
||||
System information collecting module for Windows operating systems
|
||||
|
@ -126,6 +125,7 @@ class WindowsInfoCollector(InfoCollector):
|
|||
|
||||
def __init__(self):
|
||||
super(WindowsInfoCollector, self).__init__()
|
||||
self.info['reg'] = {}
|
||||
|
||||
def get_info(self):
|
||||
"""
|
||||
|
@ -162,9 +162,6 @@ class WindowsInfoCollector(InfoCollector):
|
|||
for wmi_class_name in WMI_CLASSES:
|
||||
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):
|
||||
_wmi = wmi.WMI(moniker=moniker)
|
||||
|
||||
|
@ -175,8 +172,6 @@ class WindowsInfoCollector(InfoCollector):
|
|||
wmi_class = getattr(_wmi, class_name)(properties)
|
||||
|
||||
except wmi.x_wmi:
|
||||
#LOG.error("Error getting wmi class '%s'" % (class_name, ))
|
||||
#LOG.error(traceback.format_exc())
|
||||
return
|
||||
|
||||
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 = fix_obj_for_mongo(d)
|
||||
|
||||
self.info[subkey_path] = d
|
||||
self.info['reg'][subkey_path] = d
|
||||
|
||||
subkey.Close()
|
||||
key.Close()
|
||||
key.Close()
|
||||
|
|
|
@ -19,8 +19,6 @@ from cc.resources.monkey import Monkey
|
|||
from cc.resources.monkey_configuration import MonkeyConfiguration
|
||||
from cc.resources.monkey_download import MonkeyDownload
|
||||
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.report import Report
|
||||
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(Log, '/api/log', '/api/log/')
|
||||
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
|
||||
|
|
|
@ -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]
|
||||
}
|
|
@ -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()
|
|
@ -257,178 +257,4 @@ class PTHReportService(object):
|
|||
'edges': pth.edges
|
||||
}
|
||||
}
|
||||
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>"""
|
||||
return report
|
|
@ -329,7 +329,6 @@ class Machine(object):
|
|||
if "cimv2:Win32_UserAccount" not in wmi_id:
|
||||
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]
|
||||
domain = wmi_id.split('cimv2:Win32_UserAccount.Domain="')[1].split('",Name="')[1][:-1]
|
||||
|
||||
|
@ -556,12 +555,6 @@ class Machine(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):
|
||||
self.vertices = self.GetAllMachines()
|
||||
|
@ -582,15 +575,12 @@ class PassTheHashReport(object):
|
|||
return GUIDs
|
||||
|
||||
@cache
|
||||
def ReprSidList(self, sid_list, attacker, victim):
|
||||
def ReprSidList(self, sid_list, victim):
|
||||
users_list = []
|
||||
|
||||
for sid in sid_list:
|
||||
username = Machine(victim).GetUsernameBySid(sid)
|
||||
|
||||
# if not username:
|
||||
# username = Machine(attacker).GetUsernameBySid(sid)
|
||||
|
||||
if username:
|
||||
users_list.append(username)
|
||||
|
||||
|
@ -631,7 +621,7 @@ class PassTheHashReport(object):
|
|||
cached_admins = [i for i in cached if i in admins]
|
||||
|
||||
if cached_admins:
|
||||
relevant_users_list = self.ReprSidList(cached_admins, attacker, victim)
|
||||
relevant_users_list = self.ReprSidList(cached_admins, victim)
|
||||
edges_list.append(
|
||||
{
|
||||
'from': attacker,
|
||||
|
@ -680,11 +670,6 @@ class PassTheHashReport(object):
|
|||
|
||||
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
|
||||
def GetPossibleAttackCountBySid(self, sid):
|
||||
return len(self.GetPossibleAttacksBySid(sid))
|
||||
|
@ -970,5 +955,6 @@ class PassTheHashReport(object):
|
|||
|
||||
#shared_admins |= (m.GetLocalAdminSids() & other.GetLocalAdminSids())
|
||||
|
||||
#shared_admins -= m.GetDomainAdminsOfMachine()
|
||||
return shared_admins
|
||||
shared_admins = [admin for admin in shared_admins if admin not in list(m.GetDomainAdminsOfMachine())]
|
||||
|
||||
return shared_admins
|
||||
|
|
|
@ -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()
|
Loading…
Reference in New Issue