forked from p15670423/monkey
use the collected sam info
This commit is contained in:
parent
2013e706e5
commit
dd0b73519c
|
@ -1,3 +1,5 @@
|
|||
import hashlib
|
||||
import binascii
|
||||
from pymongo import MongoClient
|
||||
db = MongoClient().monkeyisland
|
||||
|
||||
|
@ -8,10 +10,27 @@ 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})
|
||||
|
||||
|
@ -26,6 +45,17 @@ class Machine(object):
|
|||
|
||||
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})
|
||||
|
||||
|
@ -107,16 +137,19 @@ class Machine(object):
|
|||
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,)})
|
||||
|
||||
SIDs = set()
|
||||
users = dict()
|
||||
|
||||
for doc in cur:
|
||||
for group_user in doc["data"]["Win32_GroupUser"]:
|
||||
if eval(group_user["GroupComponent"]["SID"]) != sid:
|
||||
continue
|
||||
|
||||
SIDs.add(eval(group_user["PartComponent"]["SID"]))
|
||||
if "PartComponent" not in group_user.keys():
|
||||
continue
|
||||
|
||||
return SIDs
|
||||
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,)})
|
||||
|
@ -134,7 +167,47 @@ class Machine(object):
|
|||
return GUIDs
|
||||
|
||||
def GetLocalAdmins(self):
|
||||
return self.GetUsersByGroupSid(self.GetGroupSidByGroupName("Administrators"))
|
||||
return self.GetUsersByGroupSid(self.GetGroupSidByGroupName("Administrators")).keys()
|
||||
|
||||
def GetLocalAdminNames(self):
|
||||
return 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()
|
||||
|
@ -143,13 +216,16 @@ class Machine(object):
|
|||
domain_admins = set()
|
||||
|
||||
for dc_monkey_guid in DCs:
|
||||
domain_admins += Machine(dc_monkey_guid).GetLocalAdmins()
|
||||
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})
|
||||
|
||||
|
@ -161,7 +237,26 @@ class Machine(object):
|
|||
|
||||
return SIDs
|
||||
|
||||
def GetAllMachines():
|
||||
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()
|
||||
|
@ -171,20 +266,65 @@ def GetAllMachines():
|
|||
|
||||
return GUIDs
|
||||
|
||||
vertices = GetAllMachines()
|
||||
edges = set()
|
||||
|
||||
for attacker in vertices:
|
||||
def GenerateEdgesBySid(self):
|
||||
for attacker in self.vertices:
|
||||
cached = Machine(attacker).GetCachedSids()
|
||||
|
||||
for victim in vertices:
|
||||
for victim in self.vertices:
|
||||
if attacker == victim:
|
||||
continue
|
||||
|
||||
admins = Machine(victim).GetAdmins()
|
||||
|
||||
if len(cached & admins) > 0:
|
||||
edges.add((attacker, victim))
|
||||
self.edges.add((attacker, victim))
|
||||
|
||||
print vertices
|
||||
print edges
|
||||
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