forked from p15670423/monkey
* WIP Refactoring the report info gathering file
* WIP Refactoring the report map information
This commit is contained in:
parent
6019432a2b
commit
865bb3489d
|
@ -15,18 +15,9 @@ LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
__author__ = 'uri'
|
__author__ = 'uri'
|
||||||
|
|
||||||
WMI_CLASSES = set(["Win32_OperatingSystem",
|
WMI_CLASSES = {"Win32_OperatingSystem", "Win32_ComputerSystem", "Win32_LoggedOnUser", "Win32_UserAccount",
|
||||||
"Win32_ComputerSystem",
|
"Win32_UserProfile", "Win32_Group", "Win32_GroupUser", "Win32_Product", "Win32_Service",
|
||||||
"Win32_LoggedOnUser",
|
"Win32_OptionalFeature"}
|
||||||
"Win32_UserAccount",
|
|
||||||
"Win32_UserProfile",
|
|
||||||
"Win32_Group",
|
|
||||||
"Win32_GroupUser",
|
|
||||||
"Win32_Product",
|
|
||||||
"Win32_Service",
|
|
||||||
"Win32_OptionalFeature",
|
|
||||||
#"Win32_Process",
|
|
||||||
])
|
|
||||||
|
|
||||||
# These wmi queries are able to return data about all the users & machines in the domain.
|
# These wmi queries are able to return data about all the users & machines in the domain.
|
||||||
# For these queries to work, the monkey shohuld be run on a domain machine and
|
# For these queries to work, the monkey shohuld be run on a domain machine and
|
||||||
|
|
|
@ -19,7 +19,7 @@ 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.pthmap import PthMap
|
||||||
from cc.resources.pthreporthtml import PthReportHtml
|
from cc.resources.pthreport import Report
|
||||||
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
|
||||||
|
@ -107,6 +107,6 @@ 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(PthMap, '/api/pthmap', '/api/pthmap/')
|
api.add_resource(PthMap, '/api/pthmap', '/api/pthmap/')
|
||||||
api.add_resource(PthReportHtml, '/api/pthreport', '/api/pthreport/')
|
api.add_resource(Report, '/api/pthreport', '/api/pthreport/')
|
||||||
|
|
||||||
return app
|
return app
|
||||||
|
|
|
@ -1,13 +1,10 @@
|
||||||
import hashlib
|
|
||||||
import binascii
|
|
||||||
import copy
|
import copy
|
||||||
import flask_restful
|
import flask_restful
|
||||||
from pthreport import PassTheHashReport, Machine
|
|
||||||
|
|
||||||
from cc.auth import jwt_required
|
from cc.auth import jwt_required
|
||||||
from cc.services.edge import EdgeService
|
from cc.services.pth_report_utils import PassTheHashReport, Machine
|
||||||
from cc.services.node import NodeService
|
|
||||||
from cc.database import mongo
|
|
||||||
|
|
||||||
class PthMap(flask_restful.Resource):
|
class PthMap(flask_restful.Resource):
|
||||||
@jwt_required()
|
@jwt_required()
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,21 +0,0 @@
|
||||||
import hashlib
|
|
||||||
import binascii
|
|
||||||
import copy
|
|
||||||
import flask_restful
|
|
||||||
from pthreport import PassTheHashReport, Machine, get_report_html
|
|
||||||
|
|
||||||
from cc.auth import jwt_required
|
|
||||||
from cc.services.edge import EdgeService
|
|
||||||
from cc.services.node import NodeService
|
|
||||||
from cc.database import mongo
|
|
||||||
|
|
||||||
class PthReportHtml(flask_restful.Resource):
|
|
||||||
@jwt_required()
|
|
||||||
def get(self, **kw):
|
|
||||||
pth = PassTheHashReport()
|
|
||||||
html = get_report_html()
|
|
||||||
|
|
||||||
return \
|
|
||||||
{
|
|
||||||
"html": html
|
|
||||||
}
|
|
|
@ -0,0 +1,302 @@
|
||||||
|
from cc.services.pth_report_utils import PassTheHashReport
|
||||||
|
|
||||||
|
|
||||||
|
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):
|
||||||
|
usernames_per_sid_list.append(pth.GetUsernameBySid(sid))
|
||||||
|
usernames_lists.append(usernames_per_sid_list)
|
||||||
|
|
||||||
|
return usernames_lists
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def 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):
|
||||||
|
if count <= 0:
|
||||||
|
continue
|
||||||
|
shared_admin_account_list = []
|
||||||
|
|
||||||
|
for sid in pth.GetSharedAdmins(m):
|
||||||
|
shared_admin_account_list.append(pth.GetUsernameBySid(sid))
|
||||||
|
|
||||||
|
machine = {
|
||||||
|
'ip': m.GetIp(),
|
||||||
|
'hostname': m.GetHostName(),
|
||||||
|
'domain': m.GetDomainName(),
|
||||||
|
'services_names': m.GetCriticalServicesInstalled(),
|
||||||
|
'user_count': count,
|
||||||
|
'admins_accounts': shared_admin_account_list
|
||||||
|
}
|
||||||
|
|
||||||
|
shared_admin_machines.append(machine)
|
||||||
|
|
||||||
|
return shared_admin_machines
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_strong_users_on_crit_services(pth):
|
||||||
|
threatening = dict(map(lambda x: (x, len(pth.GetThreateningUsersByVictim(x))), pth.GetCritialServers()))
|
||||||
|
strong_users_crit_list = []
|
||||||
|
|
||||||
|
for m, count in sorted(threatening.iteritems(), key=lambda (k, v): (v, k), reverse=True):
|
||||||
|
if count <= 0:
|
||||||
|
continue
|
||||||
|
|
||||||
|
threatening_users_attackers_dict = {}
|
||||||
|
for sid in pth.GetThreateningUsersByVictim(m):
|
||||||
|
username = pth.GetUsernameBySid(sid)
|
||||||
|
threatening_users_attackers_dict[username] = []
|
||||||
|
for mm in pth.GetAttackersBySid(sid):
|
||||||
|
if m == mm:
|
||||||
|
continue
|
||||||
|
threatening_users_attackers_dict[username] = mm.GetIp()
|
||||||
|
|
||||||
|
machine = {
|
||||||
|
'ip': m.GetIp(),
|
||||||
|
'hostname': m.GetHostName(),
|
||||||
|
'domain': m.GetDomainName(),
|
||||||
|
'services_names': m.GetCriticalServicesInstalled(),
|
||||||
|
'user_count': count,
|
||||||
|
'threatening_users': threatening_users_attackers_dict
|
||||||
|
}
|
||||||
|
strong_users_crit_list.append(machine)
|
||||||
|
return strong_users_crit_list
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_strong_users_on_non_crit_services(pth):
|
||||||
|
threatening = dict(map(lambda x: (x, len(pth.GetThreateningUsersByVictim(x))), pth.GetNonCritialServers()))
|
||||||
|
|
||||||
|
strong_users_non_crit_list = []
|
||||||
|
|
||||||
|
for m, count in sorted(threatening.iteritems(), key=lambda (k, v): (v, k), reverse=True):
|
||||||
|
if count <= 0:
|
||||||
|
continue
|
||||||
|
|
||||||
|
threatening_users_attackers_dict = {}
|
||||||
|
for sid in pth.GetThreateningUsersByVictim(m):
|
||||||
|
username = pth.GetUsernameBySid(sid)
|
||||||
|
threatening_users_attackers_dict[username] = []
|
||||||
|
for mm in pth.GetAttackersBySid(sid):
|
||||||
|
if m == mm:
|
||||||
|
continue
|
||||||
|
threatening_users_attackers_dict[username] = mm.GetIp()
|
||||||
|
|
||||||
|
machine = {
|
||||||
|
'ip': m.GetIp(),
|
||||||
|
'hostname': m.GetHostName(),
|
||||||
|
'domain': m.GetDomainName(),
|
||||||
|
'services_names': m.GetNonCritialServers(),
|
||||||
|
'user_count': count,
|
||||||
|
'threatening_users': threatening_users_attackers_dict
|
||||||
|
}
|
||||||
|
strong_users_non_crit_list.append(machine)
|
||||||
|
return strong_users_non_crit_list
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_report():
|
||||||
|
pth = PassTheHashReport()
|
||||||
|
|
||||||
|
report = \
|
||||||
|
{
|
||||||
|
'report_info':
|
||||||
|
{
|
||||||
|
'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(pth),
|
||||||
|
'strong_users_on_non_crit_services': PTHReportService.get_strong_users_on_non_crit_services(pth)
|
||||||
|
},
|
||||||
|
'map':
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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>"""
|
||||||
|
|
|
@ -0,0 +1,944 @@
|
||||||
|
import hashlib
|
||||||
|
import binascii
|
||||||
|
import copy
|
||||||
|
|
||||||
|
from cc.database import mongo
|
||||||
|
|
||||||
|
DsRole_RoleStandaloneWorkstation = 0
|
||||||
|
DsRole_RoleMemberWorkstation = 1
|
||||||
|
DsRole_RoleStandaloneServer = 2
|
||||||
|
DsRole_RoleMemberServer = 3
|
||||||
|
DsRole_RoleBackupDomainController = 4
|
||||||
|
DsRole_RolePrimaryDomainController = 5
|
||||||
|
|
||||||
|
SidTypeUser = 1
|
||||||
|
SidTypeGroup = 2
|
||||||
|
SidTypeDomain = 3
|
||||||
|
SidTypeAlias = 4
|
||||||
|
SidTypeWellKnownGroup = 5
|
||||||
|
SidTypeDeletedAccount = 6
|
||||||
|
SidTypeInvalid = 7
|
||||||
|
SidTypeUnknown = 8
|
||||||
|
SidTypeComputer = 9
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def is_group_sid_type(type):
|
||||||
|
return type in (SidTypeGroup, SidTypeAlias, SidTypeWellKnownGroup)
|
||||||
|
|
||||||
|
|
||||||
|
def myntlm(x):
|
||||||
|
hash = hashlib.new('md4', x.encode('utf-16le')).digest()
|
||||||
|
return str(binascii.hexlify(hash))
|
||||||
|
|
||||||
|
|
||||||
|
def cache(foo):
|
||||||
|
def hash(o):
|
||||||
|
if type(o) in (int, float, str, unicode):
|
||||||
|
return repr(o)
|
||||||
|
|
||||||
|
elif type(o) in (type(None),):
|
||||||
|
return "___None___"
|
||||||
|
|
||||||
|
elif type(o) in (list, tuple, set):
|
||||||
|
hashed = tuple([hash(x) for x in o])
|
||||||
|
|
||||||
|
if "NotHashable" in hashed:
|
||||||
|
return "NotHashable"
|
||||||
|
|
||||||
|
return hashed
|
||||||
|
|
||||||
|
elif type(o) == dict:
|
||||||
|
hashed_keys = tuple([hash(k) for k, v in o.iteritems()])
|
||||||
|
hashed_vals = tuple([hash(v) for k, v in o.iteritems()])
|
||||||
|
|
||||||
|
if "NotHashable" in hashed_keys or "NotHashable" in hashed_vals:
|
||||||
|
return "NotHashable"
|
||||||
|
|
||||||
|
return tuple(zip(hashed_keys, hashed_vals))
|
||||||
|
|
||||||
|
elif type(o) == Machine:
|
||||||
|
return o.monkey_guid
|
||||||
|
|
||||||
|
# elif type(o) == PthMap:
|
||||||
|
# return "PthMapSingleton"
|
||||||
|
|
||||||
|
elif type(o) == PassTheHashReport:
|
||||||
|
return "PassTheHashReportSingleton"
|
||||||
|
|
||||||
|
else:
|
||||||
|
assert False, "%s of type %s is not hashable" % (repr(o), type(o))
|
||||||
|
return "NotHashable"
|
||||||
|
|
||||||
|
def wrapper(*args, **kwargs):
|
||||||
|
hashed = (hash(args), hash(kwargs))
|
||||||
|
|
||||||
|
if "NotHashable" in hashed:
|
||||||
|
return foo(*args, **kwargs)
|
||||||
|
|
||||||
|
if not hasattr(foo, "_mycache_"):
|
||||||
|
foo._mycache_ = dict()
|
||||||
|
|
||||||
|
if hashed not in foo._mycache_.keys():
|
||||||
|
foo._mycache_[hashed] = foo(*args, **kwargs)
|
||||||
|
|
||||||
|
return copy.deepcopy(foo._mycache_[hashed])
|
||||||
|
|
||||||
|
return wrapper
|
||||||
|
|
||||||
|
|
||||||
|
class Machine(object):
|
||||||
|
def __init__(self, monkey_guid):
|
||||||
|
self.monkey_guid = str(monkey_guid)
|
||||||
|
|
||||||
|
self.latest_system_info = mongo.db.telemetry.find(
|
||||||
|
{"telem_type": "system_info_collection", "monkey_guid": self.monkey_guid}).sort([("timestamp", -1)]).limit(
|
||||||
|
1)
|
||||||
|
|
||||||
|
if self.latest_system_info.count() > 0:
|
||||||
|
self.latest_system_info = self.latest_system_info[0]
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
if isinstance(other, self.__class__):
|
||||||
|
return self.monkey_guid == other.monkey_guid
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
@cache
|
||||||
|
def GetMimikatzOutput(self):
|
||||||
|
doc = self.latest_system_info
|
||||||
|
|
||||||
|
if not doc:
|
||||||
|
return None
|
||||||
|
|
||||||
|
return doc["data"]["mimikatz"]
|
||||||
|
|
||||||
|
@cache
|
||||||
|
def GetHostName(self):
|
||||||
|
doc = self.latest_system_info
|
||||||
|
|
||||||
|
for comp in doc["data"]["Win32_ComputerSystem"]:
|
||||||
|
return eval(comp["Name"])
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
@cache
|
||||||
|
def GetIp(self):
|
||||||
|
doc = self.latest_system_info
|
||||||
|
|
||||||
|
for addr in doc["data"]["network_info"]["networks"]:
|
||||||
|
return str(addr["addr"])
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
@cache
|
||||||
|
def GetDomainName(self):
|
||||||
|
doc = self.latest_system_info
|
||||||
|
|
||||||
|
for comp in doc["data"]["Win32_ComputerSystem"]:
|
||||||
|
return eval(comp["Domain"])
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
@cache
|
||||||
|
def GetDomainRole(self):
|
||||||
|
doc = self.latest_system_info
|
||||||
|
|
||||||
|
for comp in doc["data"]["Win32_ComputerSystem"]:
|
||||||
|
return comp["DomainRole"]
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
@cache
|
||||||
|
def IsDomainController(self):
|
||||||
|
return self.GetDomainRole() in (DsRole_RolePrimaryDomainController, DsRole_RoleBackupDomainController)
|
||||||
|
|
||||||
|
@cache
|
||||||
|
def GetSidByUsername(self, username, domain=None):
|
||||||
|
doc = self.latest_system_info
|
||||||
|
|
||||||
|
for user in doc["data"]["Win32_UserAccount"]:
|
||||||
|
if eval(user["Name"]) != username:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if user["SIDType"] != SidTypeUser:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if domain and user["Domain"] != domain:
|
||||||
|
continue
|
||||||
|
|
||||||
|
return eval(user["SID"])
|
||||||
|
|
||||||
|
if not self.IsDomainController():
|
||||||
|
for dc in self.GetDomainControllers():
|
||||||
|
sid = dc.GetSidByUsername(username)
|
||||||
|
|
||||||
|
if sid != None:
|
||||||
|
return sid
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
@cache
|
||||||
|
def GetUsernameBySid(self, sid):
|
||||||
|
info = self.GetSidInfo(sid)
|
||||||
|
|
||||||
|
if not info:
|
||||||
|
return None
|
||||||
|
|
||||||
|
return info["Domain"] + "\\" + info["Username"]
|
||||||
|
|
||||||
|
@cache
|
||||||
|
def GetSidInfo(self, sid):
|
||||||
|
doc = self.latest_system_info
|
||||||
|
|
||||||
|
for user in doc["data"]["Win32_UserAccount"]:
|
||||||
|
if eval(user["SID"]) != sid:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if user["SIDType"] != SidTypeUser:
|
||||||
|
continue
|
||||||
|
|
||||||
|
return {"Domain": eval(user["Domain"]),
|
||||||
|
"Username": eval(user["Name"]),
|
||||||
|
"Disabled": user["Disabled"] == "true",
|
||||||
|
"PasswordRequired": user["PasswordRequired"] == "true",
|
||||||
|
"PasswordExpires": user["PasswordExpires"] == "true", }
|
||||||
|
|
||||||
|
if not self.IsDomainController():
|
||||||
|
for dc in self.GetDomainControllers():
|
||||||
|
domain = dc.GetSidInfo(sid)
|
||||||
|
|
||||||
|
if domain != None:
|
||||||
|
return domain
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
@cache
|
||||||
|
def GetCriticalServicesInstalled(self):
|
||||||
|
def IsNameOfCriticalService(name):
|
||||||
|
services = ("W3svc", "MSExchangeServiceHost", "MSSQLServer", "dns")
|
||||||
|
services = map(str.lower, services)
|
||||||
|
|
||||||
|
if not name:
|
||||||
|
return False
|
||||||
|
|
||||||
|
name = name.lower()
|
||||||
|
|
||||||
|
return name in services
|
||||||
|
# for ser in services:
|
||||||
|
# if ser in name:
|
||||||
|
# return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
doc = self.latest_system_info
|
||||||
|
found = []
|
||||||
|
|
||||||
|
if self.IsDomainController():
|
||||||
|
found.append("Domain Controller")
|
||||||
|
|
||||||
|
for product in doc["data"]["Win32_Product"]:
|
||||||
|
service_name = eval(product["Name"])
|
||||||
|
|
||||||
|
if not IsNameOfCriticalService(service_name):
|
||||||
|
continue
|
||||||
|
|
||||||
|
found.append(service_name)
|
||||||
|
|
||||||
|
for service in doc["data"]["Win32_Service"]:
|
||||||
|
service_name = eval(service["Name"])
|
||||||
|
|
||||||
|
if not IsNameOfCriticalService(service_name):
|
||||||
|
continue
|
||||||
|
|
||||||
|
if eval(service["State"]) != "Running":
|
||||||
|
continue
|
||||||
|
|
||||||
|
found.append(service_name)
|
||||||
|
|
||||||
|
return found
|
||||||
|
|
||||||
|
@cache
|
||||||
|
def IsCriticalServer(self):
|
||||||
|
return len(self.GetCriticalServicesInstalled()) > 0
|
||||||
|
|
||||||
|
@cache
|
||||||
|
def GetUsernamesBySecret(self, secret):
|
||||||
|
sam = self.GetLocalSecrets()
|
||||||
|
|
||||||
|
names = set()
|
||||||
|
|
||||||
|
for username, user_secret in sam.iteritems():
|
||||||
|
if secret == user_secret:
|
||||||
|
names.add(username)
|
||||||
|
|
||||||
|
return names
|
||||||
|
|
||||||
|
@cache
|
||||||
|
def GetSidsBySecret(self, secret):
|
||||||
|
usernames = self.GetUsernamesBySecret(secret)
|
||||||
|
return set(map(self.GetSidByUsername, usernames))
|
||||||
|
|
||||||
|
@cache
|
||||||
|
def GetGroupSidByGroupName(self, group_name):
|
||||||
|
doc = self.latest_system_info
|
||||||
|
|
||||||
|
for group in doc["data"]["Win32_Group"]:
|
||||||
|
if eval(group["Name"]) != group_name:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if not is_group_sid_type(group["SIDType"]):
|
||||||
|
continue
|
||||||
|
|
||||||
|
return eval(group["SID"])
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
@cache
|
||||||
|
def GetUsersByGroupSid(self, sid):
|
||||||
|
doc = self.latest_system_info
|
||||||
|
|
||||||
|
users = dict()
|
||||||
|
|
||||||
|
for group_user in doc["data"]["Win32_GroupUser"]:
|
||||||
|
if eval(group_user["GroupComponent"]["SID"]) != sid:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if not is_group_sid_type(group_user["GroupComponent"]["SIDType"]):
|
||||||
|
continue
|
||||||
|
|
||||||
|
if "PartComponent" not in group_user.keys():
|
||||||
|
continue
|
||||||
|
|
||||||
|
if type(group_user["PartComponent"]) in (str, unicode):
|
||||||
|
# PartComponent is an id to Win32_UserAccount table
|
||||||
|
|
||||||
|
wmi_id = group_user["PartComponent"]
|
||||||
|
|
||||||
|
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]
|
||||||
|
|
||||||
|
sid = self.GetSidByUsername(username, domain)
|
||||||
|
users[sid] = username
|
||||||
|
|
||||||
|
else:
|
||||||
|
if group_user["PartComponent"]["SIDType"] != SidTypeUser:
|
||||||
|
continue
|
||||||
|
|
||||||
|
users[eval(group_user["PartComponent"]["SID"])] = eval(group_user["PartComponent"]["Name"])
|
||||||
|
|
||||||
|
return users
|
||||||
|
|
||||||
|
@cache
|
||||||
|
def GetDomainControllersMonkeyGuidByDomainName(self, domain_name):
|
||||||
|
cur = mongo.db.telemetry.find(
|
||||||
|
{"telem_type": "system_info_collection", "data.Win32_ComputerSystem.Domain": "u'%s'" % (domain_name,)})
|
||||||
|
|
||||||
|
GUIDs = set()
|
||||||
|
|
||||||
|
for doc in cur:
|
||||||
|
if not Machine(doc["monkey_guid"]).IsDomainController():
|
||||||
|
continue
|
||||||
|
|
||||||
|
GUIDs.add(doc["monkey_guid"])
|
||||||
|
|
||||||
|
return GUIDs
|
||||||
|
|
||||||
|
@cache
|
||||||
|
def GetLocalAdmins(self):
|
||||||
|
admins = self.GetUsersByGroupSid(self.GetGroupSidByGroupName("Administrators"))
|
||||||
|
|
||||||
|
# debug = self.GetUsersByGroupSid(self.GetGroupSidByGroupName("Users"))
|
||||||
|
# admins.update(debug)
|
||||||
|
|
||||||
|
return admins
|
||||||
|
|
||||||
|
@cache
|
||||||
|
def GetLocalAdminSids(self):
|
||||||
|
return set(self.GetLocalAdmins().keys())
|
||||||
|
|
||||||
|
@cache
|
||||||
|
def GetLocalSids(self):
|
||||||
|
doc = self.latest_system_info
|
||||||
|
|
||||||
|
SIDs = set()
|
||||||
|
|
||||||
|
for user in doc["data"]["Win32_UserAccount"]:
|
||||||
|
if user["SIDType"] != SidTypeUser:
|
||||||
|
continue
|
||||||
|
|
||||||
|
SIDs.add(eval(user["SID"]))
|
||||||
|
|
||||||
|
return SIDs
|
||||||
|
|
||||||
|
@cache
|
||||||
|
def GetLocalAdminNames(self):
|
||||||
|
return set(self.GetLocalAdmins().values())
|
||||||
|
|
||||||
|
@cache
|
||||||
|
def GetSam(self):
|
||||||
|
if not self.GetMimikatzOutput():
|
||||||
|
return {}
|
||||||
|
|
||||||
|
mimikatz = self.GetMimikatzOutput()
|
||||||
|
|
||||||
|
if mimikatz.count("\n42.") != 2:
|
||||||
|
return {}
|
||||||
|
|
||||||
|
try:
|
||||||
|
sam_users = mimikatz.split("\n42.")[1].split("\nSAMKey :")[1].split("\n\n")[1:]
|
||||||
|
|
||||||
|
sam = {}
|
||||||
|
|
||||||
|
for sam_user_txt in sam_users:
|
||||||
|
sam_user = dict([map(unicode.strip, line.split(":")) for line in
|
||||||
|
filter(lambda l: l.count(":") == 1, sam_user_txt.splitlines())])
|
||||||
|
|
||||||
|
ntlm = sam_user["NTLM"]
|
||||||
|
if "[hashed secret]" not in ntlm:
|
||||||
|
continue
|
||||||
|
|
||||||
|
sam[sam_user["User"]] = ntlm.replace("[hashed secret]", "").strip()
|
||||||
|
|
||||||
|
return sam
|
||||||
|
|
||||||
|
except:
|
||||||
|
return {}
|
||||||
|
|
||||||
|
@cache
|
||||||
|
def GetNtds(self):
|
||||||
|
if not self.GetMimikatzOutput():
|
||||||
|
return {}
|
||||||
|
|
||||||
|
mimikatz = self.GetMimikatzOutput()
|
||||||
|
|
||||||
|
if mimikatz.count("\n42.") != 2:
|
||||||
|
return {}
|
||||||
|
|
||||||
|
ntds_users = mimikatz.split("\n42.")[2].split("\nRID :")[1:]
|
||||||
|
ntds = {}
|
||||||
|
|
||||||
|
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()
|
||||||
|
|
||||||
|
if ntlm:
|
||||||
|
ntds[user] = ntlm
|
||||||
|
|
||||||
|
return ntds
|
||||||
|
|
||||||
|
@cache
|
||||||
|
def GetLocalSecrets(self):
|
||||||
|
sam = self.GetSam()
|
||||||
|
ntds = self.GetNtds()
|
||||||
|
|
||||||
|
secrets = sam.copy()
|
||||||
|
secrets.update(ntds)
|
||||||
|
|
||||||
|
return secrets
|
||||||
|
|
||||||
|
@cache
|
||||||
|
def GetLocalAdminSecrets(self):
|
||||||
|
return set(self.GetLocalAdminCreds().values())
|
||||||
|
|
||||||
|
@cache
|
||||||
|
def GetLocalAdminCreds(self):
|
||||||
|
admin_names = self.GetLocalAdminNames()
|
||||||
|
sam = self.GetLocalSecrets()
|
||||||
|
|
||||||
|
admin_creds = dict()
|
||||||
|
|
||||||
|
for username, secret in sam.iteritems():
|
||||||
|
if username not in admin_names:
|
||||||
|
continue
|
||||||
|
|
||||||
|
admin_creds[username] = secret
|
||||||
|
|
||||||
|
return admin_creds
|
||||||
|
|
||||||
|
@cache
|
||||||
|
def GetCachedSecrets(self):
|
||||||
|
return set(self.GetCachedCreds().values())
|
||||||
|
|
||||||
|
@cache
|
||||||
|
def GetCachedCreds(self):
|
||||||
|
doc = self.latest_system_info
|
||||||
|
|
||||||
|
creds = dict()
|
||||||
|
|
||||||
|
if not self.GetMimikatzOutput():
|
||||||
|
return {}
|
||||||
|
|
||||||
|
mimikatz = self.GetMimikatzOutput()
|
||||||
|
|
||||||
|
for user in mimikatz.split("\n42.")[0].split("Authentication Id")[1:]:
|
||||||
|
username = None
|
||||||
|
secret = None
|
||||||
|
|
||||||
|
for line in user.splitlines():
|
||||||
|
if "User Name" in line:
|
||||||
|
username = line.split(":")[1].strip()
|
||||||
|
|
||||||
|
if ("NTLM" in line or "Password" in line) and "[hashed secret]" in line:
|
||||||
|
secret = line.split(":")[1].replace("[hashed secret]", "").strip()
|
||||||
|
|
||||||
|
if username and secret:
|
||||||
|
creds[username] = secret
|
||||||
|
|
||||||
|
return creds
|
||||||
|
|
||||||
|
@cache
|
||||||
|
def GetDomainControllers(self):
|
||||||
|
domain_name = self.GetDomainName()
|
||||||
|
DCs = self.GetDomainControllersMonkeyGuidByDomainName(domain_name)
|
||||||
|
return map(Machine, DCs)
|
||||||
|
|
||||||
|
@cache
|
||||||
|
def GetDomainAdminsOfMachine(self):
|
||||||
|
DCs = self.GetDomainControllers()
|
||||||
|
|
||||||
|
domain_admins = set()
|
||||||
|
|
||||||
|
for dc in DCs:
|
||||||
|
domain_admins |= set(dc.GetUsersByGroupSid(self.GetGroupSidByGroupName("Domain Admins")).keys())
|
||||||
|
|
||||||
|
return domain_admins
|
||||||
|
|
||||||
|
@cache
|
||||||
|
def GetAdmins(self):
|
||||||
|
return self.GetLocalAdminSids() | self.GetDomainAdminsOfMachine()
|
||||||
|
|
||||||
|
@cache
|
||||||
|
def GetAdminNames(self):
|
||||||
|
return set(map(lambda x: self.GetUsernameBySid(x), self.GetAdmins()))
|
||||||
|
|
||||||
|
@cache
|
||||||
|
def GetCachedSids(self):
|
||||||
|
doc = self.latest_system_info
|
||||||
|
|
||||||
|
SIDs = set()
|
||||||
|
|
||||||
|
for username in doc["data"]["credentials"]:
|
||||||
|
sid = self.GetSidByUsername(username)
|
||||||
|
|
||||||
|
if not sid:
|
||||||
|
sid = "__USERNAME__" + username
|
||||||
|
|
||||||
|
SIDs.add(sid)
|
||||||
|
|
||||||
|
return SIDs
|
||||||
|
|
||||||
|
@cache
|
||||||
|
def GetCachedUsernames(self):
|
||||||
|
doc = self.latest_system_info
|
||||||
|
|
||||||
|
names = set()
|
||||||
|
|
||||||
|
for username in doc["data"]["credentials"]:
|
||||||
|
names.add(username)
|
||||||
|
|
||||||
|
return names
|
||||||
|
|
||||||
|
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()
|
||||||
|
|
||||||
|
self.machines = map(Machine, self.vertices)
|
||||||
|
|
||||||
|
self.edges = set()
|
||||||
|
self.edges |= self.GetEdgesBySid() # Useful for non-cached domain users
|
||||||
|
self.edges |= self.GetEdgesBySamHash() # This will add edges based only on password hash without caring about username
|
||||||
|
|
||||||
|
@cache
|
||||||
|
def GetAllMachines(self):
|
||||||
|
cur = mongo.db.telemetry.find({"telem_type": "system_info_collection"})
|
||||||
|
|
||||||
|
GUIDs = set()
|
||||||
|
|
||||||
|
for doc in cur:
|
||||||
|
GUIDs.add(doc["monkey_guid"])
|
||||||
|
|
||||||
|
return GUIDs
|
||||||
|
|
||||||
|
@cache
|
||||||
|
def ReprSidList(self, sid_list, attacker, victim):
|
||||||
|
label = set()
|
||||||
|
|
||||||
|
for sid in sid_list:
|
||||||
|
username = Machine(victim).GetUsernameBySid(sid)
|
||||||
|
|
||||||
|
# if not username:
|
||||||
|
# username = Machine(attacker).GetUsernameBySid(sid)
|
||||||
|
|
||||||
|
if username:
|
||||||
|
label.add(username)
|
||||||
|
|
||||||
|
return ",\n".join(label)
|
||||||
|
|
||||||
|
@cache
|
||||||
|
def ReprSecretList(self, secret_list, victim):
|
||||||
|
label = set()
|
||||||
|
|
||||||
|
for secret in secret_list:
|
||||||
|
label |= Machine(victim).GetUsernamesBySecret(secret)
|
||||||
|
|
||||||
|
return ",\n".join(label)
|
||||||
|
|
||||||
|
@cache
|
||||||
|
def GetEdgesBySid(self):
|
||||||
|
edges = set()
|
||||||
|
|
||||||
|
for attacker in self.vertices:
|
||||||
|
cached = self.GetCachedSids(Machine(attacker))
|
||||||
|
|
||||||
|
for victim in self.vertices:
|
||||||
|
if attacker == victim:
|
||||||
|
continue
|
||||||
|
|
||||||
|
admins = Machine(victim).GetAdmins()
|
||||||
|
|
||||||
|
if len(cached & admins) > 0:
|
||||||
|
label = self.ReprSidList(cached & admins, attacker, victim)
|
||||||
|
edges.add((attacker, victim, label))
|
||||||
|
|
||||||
|
return edges
|
||||||
|
|
||||||
|
@cache
|
||||||
|
def GetEdgesBySamHash(self):
|
||||||
|
edges = set()
|
||||||
|
|
||||||
|
for attacker in self.vertices:
|
||||||
|
cached_creds = set(Machine(attacker).GetCachedCreds().items())
|
||||||
|
|
||||||
|
for victim in self.vertices:
|
||||||
|
if attacker == victim:
|
||||||
|
continue
|
||||||
|
|
||||||
|
admin_creds = set(Machine(victim).GetLocalAdminCreds().items())
|
||||||
|
|
||||||
|
if len(cached_creds & admin_creds) > 0:
|
||||||
|
label = self.ReprSecretList(set(dict(cached_creds & admin_creds).values()), victim)
|
||||||
|
edges.add((attacker, victim, label))
|
||||||
|
|
||||||
|
return edges
|
||||||
|
|
||||||
|
@cache
|
||||||
|
def GetEdgesByUsername(self):
|
||||||
|
edges = set()
|
||||||
|
|
||||||
|
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:
|
||||||
|
edges.add((attacker, victim))
|
||||||
|
|
||||||
|
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))
|
||||||
|
|
||||||
|
@cache
|
||||||
|
def GetPossibleAttacksByAttacker(self, attacker):
|
||||||
|
attacks = set()
|
||||||
|
|
||||||
|
cached_creds = set(Machine(attacker).GetCachedCreds().items())
|
||||||
|
|
||||||
|
for victim in self.vertices:
|
||||||
|
if attacker == victim:
|
||||||
|
continue
|
||||||
|
|
||||||
|
admin_creds = set(Machine(victim).GetLocalAdminCreds().items())
|
||||||
|
|
||||||
|
if len(cached_creds & admin_creds) > 0:
|
||||||
|
curr_attacks = dict(cached_creds & admin_creds)
|
||||||
|
attacks.add((attacker, victim, curr_attacks))
|
||||||
|
|
||||||
|
return attacks
|
||||||
|
|
||||||
|
@cache
|
||||||
|
def GetPossibleAttacksBySid(self, sid):
|
||||||
|
attacks = set()
|
||||||
|
|
||||||
|
for attacker in self.vertices:
|
||||||
|
tmp = self.GetPossibleAttacksByAttacker(attacker)
|
||||||
|
|
||||||
|
for _, victim, curr_attacks in tmp:
|
||||||
|
for username, secret in curr_attacks.iteritems():
|
||||||
|
if Machine(victim).GetSidByUsername(username) == sid:
|
||||||
|
attacks.add((attacker, victim))
|
||||||
|
|
||||||
|
return attacks
|
||||||
|
|
||||||
|
@cache
|
||||||
|
def GetSecretBySid(self, sid):
|
||||||
|
for m in self.machines:
|
||||||
|
for user, user_secret in m.GetLocalSecrets().iteritems():
|
||||||
|
if m.GetSidByUsername(user) == sid:
|
||||||
|
return user_secret
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
@cache
|
||||||
|
def GetVictimCountBySid(self, sid):
|
||||||
|
return len(self.GetVictimsBySid(sid))
|
||||||
|
|
||||||
|
@cache
|
||||||
|
def GetVictimCountByMachine(self, attacker):
|
||||||
|
return len(self.GetVictimsByAttacker(attacker))
|
||||||
|
|
||||||
|
@cache
|
||||||
|
def GetAttackCountBySecret(self, secret):
|
||||||
|
return len(self.GetAttackersBySecret(secret))
|
||||||
|
|
||||||
|
@cache
|
||||||
|
def GetAllUsernames(self):
|
||||||
|
names = set()
|
||||||
|
|
||||||
|
for sid in self.GetAllSids():
|
||||||
|
names.add(self.GetUsernameBySid(sid))
|
||||||
|
|
||||||
|
return names
|
||||||
|
|
||||||
|
@cache
|
||||||
|
def GetAllSids(self):
|
||||||
|
SIDs = set()
|
||||||
|
|
||||||
|
for m in self.machines:
|
||||||
|
SIDs |= m.GetLocalSids()
|
||||||
|
|
||||||
|
return SIDs
|
||||||
|
|
||||||
|
@cache
|
||||||
|
def GetAllSecrets(self):
|
||||||
|
secrets = set()
|
||||||
|
|
||||||
|
for m in self.machines:
|
||||||
|
for secret in m.GetLocalAdminSecrets():
|
||||||
|
secrets.add(secret)
|
||||||
|
|
||||||
|
return secrets
|
||||||
|
|
||||||
|
@cache
|
||||||
|
def GetUsernameBySid(self, sid):
|
||||||
|
for m in self.machines:
|
||||||
|
username = m.GetUsernameBySid(sid)
|
||||||
|
|
||||||
|
if username:
|
||||||
|
return username
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
@cache
|
||||||
|
def GetSidInfo(self, sid):
|
||||||
|
for m in self.machines:
|
||||||
|
info = m.GetSidInfo(sid)
|
||||||
|
|
||||||
|
if info:
|
||||||
|
return info
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
@cache
|
||||||
|
def GetSidsBySecret(self, secret):
|
||||||
|
SIDs = set()
|
||||||
|
|
||||||
|
for m in self.machines:
|
||||||
|
SIDs |= m.GetSidsBySecret(secret)
|
||||||
|
|
||||||
|
return SIDs
|
||||||
|
|
||||||
|
@cache
|
||||||
|
def GetAllDomainControllers(self):
|
||||||
|
DCs = set()
|
||||||
|
|
||||||
|
for m in self.machines:
|
||||||
|
if m.IsDomainController():
|
||||||
|
DCs.add(m)
|
||||||
|
|
||||||
|
return DCs
|
||||||
|
|
||||||
|
@cache
|
||||||
|
def GetSidsByUsername(self, username):
|
||||||
|
SIDs = set()
|
||||||
|
|
||||||
|
for m in self.machines:
|
||||||
|
sid = m.GetSidByUsername(username)
|
||||||
|
if sid:
|
||||||
|
SIDs.add(sid)
|
||||||
|
|
||||||
|
return SIDs
|
||||||
|
|
||||||
|
@cache
|
||||||
|
def GetVictimsBySid(self, sid):
|
||||||
|
machines = set()
|
||||||
|
|
||||||
|
for m in self.machines:
|
||||||
|
if sid in m.GetAdmins():
|
||||||
|
machines.add(m)
|
||||||
|
|
||||||
|
return machines
|
||||||
|
|
||||||
|
@cache
|
||||||
|
def GetVictimsBySecret(self, secret):
|
||||||
|
machines = set()
|
||||||
|
|
||||||
|
SIDs = self.GetSidsBySecret(secret)
|
||||||
|
|
||||||
|
for m in self.machines:
|
||||||
|
if len(SIDs & m.GetAdmins()) > 0:
|
||||||
|
machines.add(m)
|
||||||
|
|
||||||
|
return machines
|
||||||
|
|
||||||
|
@cache
|
||||||
|
def GetAttackersBySecret(self, secret):
|
||||||
|
machines = set()
|
||||||
|
|
||||||
|
for m in self.machines:
|
||||||
|
if secret in m.GetCachedSecrets():
|
||||||
|
machines.add(m)
|
||||||
|
|
||||||
|
return machines
|
||||||
|
|
||||||
|
@cache
|
||||||
|
def GetAttackersByVictim(self, victim):
|
||||||
|
if type(victim) != unicode:
|
||||||
|
victim = victim.monkey_guid
|
||||||
|
|
||||||
|
attackers = set()
|
||||||
|
|
||||||
|
for atck, vic, _ in self.edges:
|
||||||
|
if vic == victim:
|
||||||
|
attackers.add(atck)
|
||||||
|
|
||||||
|
return set(map(Machine, attackers))
|
||||||
|
|
||||||
|
@cache
|
||||||
|
def GetAttackersBySid(self, sid):
|
||||||
|
machines = set()
|
||||||
|
|
||||||
|
for m in self.machines:
|
||||||
|
if sid in self.GetCachedSids(m):
|
||||||
|
machines.add(m)
|
||||||
|
|
||||||
|
return machines
|
||||||
|
|
||||||
|
@cache
|
||||||
|
def GetVictimsByAttacker(self, attacker):
|
||||||
|
if type(attacker) != unicode:
|
||||||
|
attacker = attacker.monkey_guid
|
||||||
|
|
||||||
|
victims = set()
|
||||||
|
|
||||||
|
for atck, vic, _ in self.edges:
|
||||||
|
if atck == attacker:
|
||||||
|
victims.add(vic)
|
||||||
|
|
||||||
|
return set(map(Machine, victims))
|
||||||
|
|
||||||
|
@cache
|
||||||
|
def GetInPathCountByVictim(self, victim, already_processed=None):
|
||||||
|
if type(victim) != unicode:
|
||||||
|
victim = victim.monkey_guid
|
||||||
|
|
||||||
|
if not already_processed:
|
||||||
|
already_processed = set([victim])
|
||||||
|
|
||||||
|
count = 0
|
||||||
|
|
||||||
|
for atck, vic, _ in self.edges:
|
||||||
|
if atck == vic:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if vic != victim:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if atck in already_processed:
|
||||||
|
continue
|
||||||
|
|
||||||
|
count += 1
|
||||||
|
|
||||||
|
already_processed.add(atck)
|
||||||
|
count += self.GetInPathCountByVictim(atck, already_processed)
|
||||||
|
|
||||||
|
return count
|
||||||
|
|
||||||
|
@cache
|
||||||
|
def GetCritialServers(self):
|
||||||
|
machines = set()
|
||||||
|
|
||||||
|
for m in self.machines:
|
||||||
|
if m.IsCriticalServer():
|
||||||
|
machines.add(m)
|
||||||
|
|
||||||
|
return machines
|
||||||
|
|
||||||
|
@cache
|
||||||
|
def GetNonCritialServers(self):
|
||||||
|
return set(self.machines) - self.GetCritialServers()
|
||||||
|
|
||||||
|
@cache
|
||||||
|
def GetCachedSids(self, m):
|
||||||
|
sids = set()
|
||||||
|
tmp = m.GetCachedSids()
|
||||||
|
|
||||||
|
for sid in tmp:
|
||||||
|
if sid.startswith("__USERNAME__"):
|
||||||
|
|
||||||
|
s = self.GetSidsByUsername(sid[len("__USERNAME__"):])
|
||||||
|
if len(s) == 1:
|
||||||
|
sids.add(s.pop())
|
||||||
|
else:
|
||||||
|
sids.add(sid)
|
||||||
|
|
||||||
|
else:
|
||||||
|
sids.add(sid)
|
||||||
|
|
||||||
|
return sids
|
||||||
|
|
||||||
|
@cache
|
||||||
|
def GetThreateningUsersByVictim(self, victim):
|
||||||
|
threatening_users = set()
|
||||||
|
|
||||||
|
for attacker in self.GetAttackersByVictim(victim):
|
||||||
|
# For each attacker, get the cached users and check which of them is an admin on the victim
|
||||||
|
threatening_users |= (self.GetCachedSids(attacker) & victim.GetAdmins())
|
||||||
|
|
||||||
|
return threatening_users
|
||||||
|
|
||||||
|
@cache
|
||||||
|
def GetSharedAdmins(self, m):
|
||||||
|
shared_admins = set()
|
||||||
|
|
||||||
|
for other in self.machines:
|
||||||
|
if m == other:
|
||||||
|
continue
|
||||||
|
|
||||||
|
shared_admins |= (m.GetLocalAdminSids() & other.GetLocalAdminSids())
|
||||||
|
|
||||||
|
shared_admins -= m.GetDomainAdminsOfMachine()
|
||||||
|
return shared_admins
|
Loading…
Reference in New Issue