* fixed a lot of safe dict access

* some small fixed and typos
This commit is contained in:
maor.rayzin 2018-07-24 19:09:19 +03:00
parent f97df84da9
commit 48e1d85eb0
4 changed files with 76 additions and 75 deletions

View File

@ -12,6 +12,7 @@ from mimikatz_collector import MimikatzCollector
from . import InfoCollector from . import InfoCollector
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
LOG.info('started windows info collector')
__author__ = 'uri' __author__ = 'uri'
@ -138,16 +139,17 @@ class WindowsInfoCollector(InfoCollector):
self.get_hostname() self.get_hostname()
self.get_process_list() self.get_process_list()
self.get_network_info() self.get_network_info()
self.get_azure_info() #self.get_azure_info()
self.get_wmi_info() #self.get_wmi_info()
self.get_reg_key(r"SYSTEM\CurrentControlSet\Control\Lsa") #self.get_reg_key(r"SYSTEM\CurrentControlSet\Control\Lsa")
self.get_installed_packages() self.get_installed_packages()
mimikatz_collector = MimikatzCollector() mimikatz_collector = MimikatzCollector()
mimikatz_info = mimikatz_collector.get_logon_info() mimikatz_info = mimikatz_collector.get_logon_info()
self.info["credentials"].update(mimikatz_info) if mimikatz_info:
self.info["mimikatz"] = mimikatz_collector.get_mimikatz_text() self.info["credentials"].update(mimikatz_info)
self.info["mimikatz"] = mimikatz_collector.get_mimikatz_text()
return self.info return self.info

View File

@ -112,7 +112,7 @@ class PTHReportService(object):
for node_id in pth.vertices: for node_id in pth.vertices:
machine = Machine(node_id) machine = Machine(node_id)
node = { node = {
"id": machine.get_monkey_id, "id": str(machine.get_monkey_id()),
"label": '{0} : {1}'.format(machine.GetHostName(), machine.GetIp()), "label": '{0} : {1}'.format(machine.GetHostName(), machine.GetIp()),
'group': 'critical' if machine.IsCriticalServer() else 'normal', 'group': 'critical' if machine.IsCriticalServer() else 'normal',
'users': list(machine.GetCachedUsernames()), 'users': list(machine.GetCachedUsernames()),

View File

@ -115,14 +115,14 @@ class Machine(object):
if not doc: if not doc:
return None return None
return doc["data"]["mimikatz"] return doc.get("data").get("mimikatz")
@cache @cache
def GetHostName(self): def GetHostName(self):
doc = self.latest_system_info doc = self.latest_system_info
for comp in doc["data"]["Win32_ComputerSystem"]: for comp in doc.get("data").get("Win32_ComputerSystem", {}):
return eval(comp["Name"]) return eval(comp.get("Name"))
return None return None
@ -130,7 +130,7 @@ class Machine(object):
def GetIp(self): def GetIp(self):
doc = self.latest_system_info doc = self.latest_system_info
for addr in doc["data"]["network_info"]["networks"]: for addr in doc.get("data").get("network_info", {}).get("networks", {}):
return str(addr["addr"]) return str(addr["addr"])
return None return None
@ -139,14 +139,14 @@ class Machine(object):
def get_monkey_id(self): def get_monkey_id(self):
doc = self.monkey_info doc = self.monkey_info
return str(doc['_id']) return str(doc.get('_id'))
@cache @cache
def GetDomainName(self): def GetDomainName(self):
doc = self.latest_system_info doc = self.latest_system_info
for comp in doc["data"]["Win32_ComputerSystem"]: for comp in doc.get("data").get("Win32_ComputerSystem", {}):
return eval(comp["Domain"]) return eval(comp.get("Domain"))
return None return None
@ -154,8 +154,8 @@ class Machine(object):
def GetDomainRole(self): def GetDomainRole(self):
doc = self.latest_system_info doc = self.latest_system_info
for comp in doc["data"]["Win32_ComputerSystem"]: for comp in doc.get("data").get("Win32_ComputerSystem", {}):
return comp["DomainRole"] return comp.get("DomainRole")
return None return None
@ -167,17 +167,17 @@ class Machine(object):
def GetSidByUsername(self, username, domain=None): def GetSidByUsername(self, username, domain=None):
doc = self.latest_system_info doc = self.latest_system_info
for user in doc["data"]["Win32_UserAccount"]: for user in doc.get("data").get("Win32_UserAccount", {}):
if eval(user["Name"]) != username: if eval(user.get("Name")) != username:
continue continue
if user["SIDType"] != SidTypeUser: if user.get("SIDType") != SidTypeUser:
continue continue
if domain and user["Domain"] != domain: if domain and user.get("Domain") != domain:
continue continue
return eval(user["SID"]) return eval(user.get("SID"))
if not self.IsDomainController(): if not self.IsDomainController():
for dc in self.GetDomainControllers(): for dc in self.GetDomainControllers():
@ -195,24 +195,24 @@ class Machine(object):
if not info: if not info:
return None return None
return info["Domain"] + "\\" + info["Username"] return str(info.get("Domain")) + "\\" + str(info.get("Username"))
@cache @cache
def GetSidInfo(self, sid): def GetSidInfo(self, sid):
doc = self.latest_system_info doc = self.latest_system_info
for user in doc["data"]["Win32_UserAccount"]: for user in doc.get("data").get("Win32_UserAccount",{}):
if eval(user["SID"]) != sid: if eval(user.get("SID")) != sid:
continue continue
if user["SIDType"] != SidTypeUser: if user.get("SIDType") != SidTypeUser:
continue continue
return {"Domain": eval(user["Domain"]), return {"Domain": eval(user.get("Domain")),
"Username": eval(user["Name"]), "Username": eval(user.get("Name")),
"Disabled": user["Disabled"] == "true", "Disabled": user.get("Disabled") == "true",
"PasswordRequired": user["PasswordRequired"] == "true", "PasswordRequired": user.get("PasswordRequired") == "true",
"PasswordExpires": user["PasswordExpires"] == "true", } "PasswordExpires": user.get("PasswordExpires") == "true", }
if not self.IsDomainController(): if not self.IsDomainController():
for dc in self.GetDomainControllers(): for dc in self.GetDomainControllers():
@ -247,21 +247,21 @@ class Machine(object):
if self.IsDomainController(): if self.IsDomainController():
found.append("Domain Controller") found.append("Domain Controller")
for product in doc["data"]["Win32_Product"]: for product in doc.get("data").get("Win32_Product", {}):
service_name = eval(product["Name"]) service_name = eval(product.get("Name"))
if not IsNameOfCriticalService(service_name): if not IsNameOfCriticalService(service_name):
continue continue
found.append(service_name) found.append(service_name)
for service in doc["data"]["Win32_Service"]: for service in doc.get("data").get("Win32_Service", {}):
service_name = eval(service["Name"]) service_name = eval(service.get("Name"))
if not IsNameOfCriticalService(service_name): if not IsNameOfCriticalService(service_name):
continue continue
if eval(service["State"]) != "Running": if eval(service.get("State")) != "Running":
continue continue
found.append(service_name) found.append(service_name)
@ -293,14 +293,14 @@ class Machine(object):
def GetGroupSidByGroupName(self, group_name): def GetGroupSidByGroupName(self, group_name):
doc = self.latest_system_info doc = self.latest_system_info
for group in doc["data"]["Win32_Group"]: for group in doc.get('data').get("Win32_Group", {}):
if eval(group["Name"]) != group_name: if eval(group.get("Name")) != group_name:
continue continue
if not is_group_sid_type(group["SIDType"]): if not is_group_sid_type(group.get("SIDType")):
continue continue
return eval(group["SID"]) return eval(group.get("SID"))
return None return None
@ -310,20 +310,20 @@ class Machine(object):
users = dict() users = dict()
for group_user in doc["data"]["Win32_GroupUser"]: for group_user in doc.get('data').get("Win32_GroupUser", {}):
if eval(group_user["GroupComponent"]["SID"]) != sid: if eval(group_user.get("GroupComponent", {}).get("SID")) != sid:
continue continue
if not is_group_sid_type(group_user["GroupComponent"]["SIDType"]): if not is_group_sid_type(group_user.get("GroupComponent", {}).get("SIDType")):
continue continue
if "PartComponent" not in group_user.keys(): if "PartComponent" not in group_user.keys():
continue continue
if type(group_user["PartComponent"]) in (str, unicode): if type(group_user.get("PartComponent")) in (str, unicode):
# PartComponent is an id to Win32_UserAccount table # PartComponent is an id to Win32_UserAccount table
wmi_id = group_user["PartComponent"] wmi_id = group_user.get("PartComponent")
if "cimv2:Win32_UserAccount" not in wmi_id: if "cimv2:Win32_UserAccount" not in wmi_id:
continue continue
@ -336,10 +336,11 @@ class Machine(object):
users[sid] = username users[sid] = username
else: else:
if group_user["PartComponent"]["SIDType"] != SidTypeUser: if group_user.get("PartComponent", {}).get("SIDType") != SidTypeUser:
continue continue
users[eval(group_user["PartComponent"]["SID"])] = eval(group_user["PartComponent"]["Name"]) users[eval(group_user.get("PartComponent", {}).get("SID"))] = eval(group_user.get("PartComponent")
.get("Name"))
return users return users
@ -351,10 +352,10 @@ class Machine(object):
GUIDs = set() GUIDs = set()
for doc in cur: for doc in cur:
if not Machine(doc["monkey_guid"]).IsDomainController(): if not Machine(doc.get("monkey_guid")).IsDomainController():
continue continue
GUIDs.add(doc["monkey_guid"]) GUIDs.add(doc.get("monkey_guid"))
return GUIDs return GUIDs
@ -377,11 +378,11 @@ class Machine(object):
SIDs = set() SIDs = set()
for user in doc["data"]["Win32_UserAccount"]: for user in doc.get('data').get("Win32_UserAccount", {}):
if user["SIDType"] != SidTypeUser: if user.get("SIDType") != SidTypeUser:
continue continue
SIDs.add(eval(user["SID"])) SIDs.add(eval(user.get("SID")))
return SIDs return SIDs
@ -408,11 +409,11 @@ class Machine(object):
sam_user = dict([map(unicode.strip, line.split(":")) for line in sam_user = dict([map(unicode.strip, line.split(":")) for line in
filter(lambda l: l.count(":") == 1, sam_user_txt.splitlines())]) filter(lambda l: l.count(":") == 1, sam_user_txt.splitlines())])
ntlm = sam_user["NTLM"] ntlm = sam_user.get("NTLM")
if "[hashed secret]" not in ntlm: if "[hashed secret]" not in ntlm:
continue continue
sam[sam_user["User"]] = ntlm.replace("[hashed secret]", "").strip() sam[sam_user.get("User")] = ntlm.replace("[hashed secret]", "").strip()
return sam return sam
@ -533,7 +534,7 @@ class Machine(object):
SIDs = set() SIDs = set()
for username in doc["data"]["credentials"]: for username in doc.get('data').get("credentials", {}):
sid = self.GetSidByUsername(username) sid = self.GetSidByUsername(username)
if not sid: if not sid:
@ -549,7 +550,7 @@ class Machine(object):
names = set() names = set()
for username in doc["data"]["credentials"]: for username in doc.get('data').get("credentials", {}):
names.add(username) names.add(username)
return names return names
@ -576,7 +577,7 @@ class PassTheHashReport(object):
GUIDs = set() GUIDs = set()
for doc in cur: for doc in cur:
GUIDs.add(doc["monkey_guid"]) GUIDs.add(doc.get("monkey_guid"))
return GUIDs return GUIDs

View File

@ -41,6 +41,8 @@ class ReportPageComponent extends AuthComponent {
super(props); super(props);
this.state = { this.state = {
report: {}, report: {},
pthreport: {},
pthmap: {},
graph: {nodes: [], edges: []}, graph: {nodes: [], edges: []},
allMonkeysAreDead: false, allMonkeysAreDead: false,
runStarted: true runStarted: true
@ -49,6 +51,7 @@ class ReportPageComponent extends AuthComponent {
componentDidMount() { componentDidMount() {
this.updateMonkeysRunning().then(res => this.getReportFromServer(res)); this.updateMonkeysRunning().then(res => this.getReportFromServer(res));
this.getPTHReportFromServer();
this.updateMapFromServer(); this.updateMapFromServer();
this.interval = setInterval(this.updateMapFromServer, 1000); this.interval = setInterval(this.updateMapFromServer, 1000);
} }
@ -108,6 +111,17 @@ class ReportPageComponent extends AuthComponent {
}); });
}; };
getPTHReportFromServer(res) {
this.authFetch('/api/pthreport')
.then(res => res.json())
.then(res => {
this.setState({
pthreport: res.report_info,
pthmap: res.map
});
});
}
getReportFromServer(res) { getReportFromServer(res) {
if (res['completed_steps']['run_monkey']) { if (res['completed_steps']['run_monkey']) {
this.authFetch('/api/report') this.authFetch('/api/report')
@ -432,29 +446,13 @@ class ReportPageComponent extends AuthComponent {
<StolenPasswords data={this.state.report.glance.stolen_creds}/> <StolenPasswords data={this.state.report.glance.stolen_creds}/>
</div> </div>
<div style={{marginBottom: '20px'}}> <div style={{marginBottom: '20px'}}>
{ /* TODO: use dynamic data */} <SharedCreds data = {this.state.pthreport.same_password} />
<SharedCreds data = {[{cred_group: ['MyDomain\\user1', 'user2', 'user3']}, {cred_group: ['user2', 'user4']}]} />
</div> </div>
<div style={{marginBottom: '20px'}}> <div style={{marginBottom: '20px'}}>
{ /* TODO: use dynamic data */} <SharedAdmins data = {this.state.pthreport.local_admin_shared} />
<SharedAdmins data = {[
{
username: 'SharedLocalAdmin',
domain: 'MyDomain',
machines: ['hello : 1.2.3.4']
}
]} />
</div> </div>
<div> <div>
{ /* TODO: use dynamic data */} <StrongUsers data = {this.state.pthreport.strong_users_on_crit_services} />
<StrongUsers data = {[
{
username: 'SharedLocalAdmin',
domain: 'MyDomain',
machines: ['hello : 1.2.3.4'],
services: ['DC', 'DNS']
}
]} />
</div> </div>
</div> </div>
); );
@ -488,7 +486,7 @@ class ReportPageComponent extends AuthComponent {
Credential Map Credential Map
</h3> </h3>
<div style={{position: 'relative', height: '100vh'}}> <div style={{position: 'relative', height: '100vh'}}>
<PassTheHashMapPageComponent graph={my_map} /> <PassTheHashMapPageComponent graph={this.state.pthmap} />
</div> </div>
<br /> <br />
</div> </div>