forked from p15670423/monkey
* fixed a lot of safe dict access
* some small fixed and typos
This commit is contained in:
parent
f97df84da9
commit
48e1d85eb0
|
@ -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,14 +139,15 @@ 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()
|
||||||
|
if mimikatz_info:
|
||||||
self.info["credentials"].update(mimikatz_info)
|
self.info["credentials"].update(mimikatz_info)
|
||||||
self.info["mimikatz"] = mimikatz_collector.get_mimikatz_text()
|
self.info["mimikatz"] = mimikatz_collector.get_mimikatz_text()
|
||||||
|
|
||||||
|
|
|
@ -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()),
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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>
|
||||||
|
|
Loading…
Reference in New Issue