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
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
LOG.info('started windows info collector')
|
||||
|
||||
__author__ = 'uri'
|
||||
|
||||
|
@ -138,16 +139,17 @@ class WindowsInfoCollector(InfoCollector):
|
|||
self.get_hostname()
|
||||
self.get_process_list()
|
||||
self.get_network_info()
|
||||
self.get_azure_info()
|
||||
#self.get_azure_info()
|
||||
|
||||
self.get_wmi_info()
|
||||
self.get_reg_key(r"SYSTEM\CurrentControlSet\Control\Lsa")
|
||||
#self.get_wmi_info()
|
||||
#self.get_reg_key(r"SYSTEM\CurrentControlSet\Control\Lsa")
|
||||
self.get_installed_packages()
|
||||
|
||||
mimikatz_collector = MimikatzCollector()
|
||||
mimikatz_info = mimikatz_collector.get_logon_info()
|
||||
self.info["credentials"].update(mimikatz_info)
|
||||
self.info["mimikatz"] = mimikatz_collector.get_mimikatz_text()
|
||||
if mimikatz_info:
|
||||
self.info["credentials"].update(mimikatz_info)
|
||||
self.info["mimikatz"] = mimikatz_collector.get_mimikatz_text()
|
||||
|
||||
return self.info
|
||||
|
||||
|
|
|
@ -112,7 +112,7 @@ class PTHReportService(object):
|
|||
for node_id in pth.vertices:
|
||||
machine = Machine(node_id)
|
||||
node = {
|
||||
"id": machine.get_monkey_id,
|
||||
"id": str(machine.get_monkey_id()),
|
||||
"label": '{0} : {1}'.format(machine.GetHostName(), machine.GetIp()),
|
||||
'group': 'critical' if machine.IsCriticalServer() else 'normal',
|
||||
'users': list(machine.GetCachedUsernames()),
|
||||
|
|
|
@ -115,14 +115,14 @@ class Machine(object):
|
|||
if not doc:
|
||||
return None
|
||||
|
||||
return doc["data"]["mimikatz"]
|
||||
return doc.get("data").get("mimikatz")
|
||||
|
||||
@cache
|
||||
def GetHostName(self):
|
||||
doc = self.latest_system_info
|
||||
|
||||
for comp in doc["data"]["Win32_ComputerSystem"]:
|
||||
return eval(comp["Name"])
|
||||
for comp in doc.get("data").get("Win32_ComputerSystem", {}):
|
||||
return eval(comp.get("Name"))
|
||||
|
||||
return None
|
||||
|
||||
|
@ -130,7 +130,7 @@ class Machine(object):
|
|||
def GetIp(self):
|
||||
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 None
|
||||
|
@ -139,14 +139,14 @@ class Machine(object):
|
|||
def get_monkey_id(self):
|
||||
doc = self.monkey_info
|
||||
|
||||
return str(doc['_id'])
|
||||
return str(doc.get('_id'))
|
||||
|
||||
@cache
|
||||
def GetDomainName(self):
|
||||
doc = self.latest_system_info
|
||||
|
||||
for comp in doc["data"]["Win32_ComputerSystem"]:
|
||||
return eval(comp["Domain"])
|
||||
for comp in doc.get("data").get("Win32_ComputerSystem", {}):
|
||||
return eval(comp.get("Domain"))
|
||||
|
||||
return None
|
||||
|
||||
|
@ -154,8 +154,8 @@ class Machine(object):
|
|||
def GetDomainRole(self):
|
||||
doc = self.latest_system_info
|
||||
|
||||
for comp in doc["data"]["Win32_ComputerSystem"]:
|
||||
return comp["DomainRole"]
|
||||
for comp in doc.get("data").get("Win32_ComputerSystem", {}):
|
||||
return comp.get("DomainRole")
|
||||
|
||||
return None
|
||||
|
||||
|
@ -167,17 +167,17 @@ class Machine(object):
|
|||
def GetSidByUsername(self, username, domain=None):
|
||||
doc = self.latest_system_info
|
||||
|
||||
for user in doc["data"]["Win32_UserAccount"]:
|
||||
if eval(user["Name"]) != username:
|
||||
for user in doc.get("data").get("Win32_UserAccount", {}):
|
||||
if eval(user.get("Name")) != username:
|
||||
continue
|
||||
|
||||
if user["SIDType"] != SidTypeUser:
|
||||
if user.get("SIDType") != SidTypeUser:
|
||||
continue
|
||||
|
||||
if domain and user["Domain"] != domain:
|
||||
if domain and user.get("Domain") != domain:
|
||||
continue
|
||||
|
||||
return eval(user["SID"])
|
||||
return eval(user.get("SID"))
|
||||
|
||||
if not self.IsDomainController():
|
||||
for dc in self.GetDomainControllers():
|
||||
|
@ -195,24 +195,24 @@ class Machine(object):
|
|||
if not info:
|
||||
return None
|
||||
|
||||
return info["Domain"] + "\\" + info["Username"]
|
||||
return str(info.get("Domain")) + "\\" + str(info.get("Username"))
|
||||
|
||||
@cache
|
||||
def GetSidInfo(self, sid):
|
||||
doc = self.latest_system_info
|
||||
|
||||
for user in doc["data"]["Win32_UserAccount"]:
|
||||
if eval(user["SID"]) != sid:
|
||||
for user in doc.get("data").get("Win32_UserAccount",{}):
|
||||
if eval(user.get("SID")) != sid:
|
||||
continue
|
||||
|
||||
if user["SIDType"] != SidTypeUser:
|
||||
if user.get("SIDType") != SidTypeUser:
|
||||
continue
|
||||
|
||||
return {"Domain": eval(user["Domain"]),
|
||||
"Username": eval(user["Name"]),
|
||||
"Disabled": user["Disabled"] == "true",
|
||||
"PasswordRequired": user["PasswordRequired"] == "true",
|
||||
"PasswordExpires": user["PasswordExpires"] == "true", }
|
||||
return {"Domain": eval(user.get("Domain")),
|
||||
"Username": eval(user.get("Name")),
|
||||
"Disabled": user.get("Disabled") == "true",
|
||||
"PasswordRequired": user.get("PasswordRequired") == "true",
|
||||
"PasswordExpires": user.get("PasswordExpires") == "true", }
|
||||
|
||||
if not self.IsDomainController():
|
||||
for dc in self.GetDomainControllers():
|
||||
|
@ -247,21 +247,21 @@ class Machine(object):
|
|||
if self.IsDomainController():
|
||||
found.append("Domain Controller")
|
||||
|
||||
for product in doc["data"]["Win32_Product"]:
|
||||
service_name = eval(product["Name"])
|
||||
for product in doc.get("data").get("Win32_Product", {}):
|
||||
service_name = eval(product.get("Name"))
|
||||
|
||||
if not IsNameOfCriticalService(service_name):
|
||||
continue
|
||||
|
||||
found.append(service_name)
|
||||
|
||||
for service in doc["data"]["Win32_Service"]:
|
||||
service_name = eval(service["Name"])
|
||||
for service in doc.get("data").get("Win32_Service", {}):
|
||||
service_name = eval(service.get("Name"))
|
||||
|
||||
if not IsNameOfCriticalService(service_name):
|
||||
continue
|
||||
|
||||
if eval(service["State"]) != "Running":
|
||||
if eval(service.get("State")) != "Running":
|
||||
continue
|
||||
|
||||
found.append(service_name)
|
||||
|
@ -293,14 +293,14 @@ class Machine(object):
|
|||
def GetGroupSidByGroupName(self, group_name):
|
||||
doc = self.latest_system_info
|
||||
|
||||
for group in doc["data"]["Win32_Group"]:
|
||||
if eval(group["Name"]) != group_name:
|
||||
for group in doc.get('data').get("Win32_Group", {}):
|
||||
if eval(group.get("Name")) != group_name:
|
||||
continue
|
||||
|
||||
if not is_group_sid_type(group["SIDType"]):
|
||||
if not is_group_sid_type(group.get("SIDType")):
|
||||
continue
|
||||
|
||||
return eval(group["SID"])
|
||||
return eval(group.get("SID"))
|
||||
|
||||
return None
|
||||
|
||||
|
@ -310,20 +310,20 @@ class Machine(object):
|
|||
|
||||
users = dict()
|
||||
|
||||
for group_user in doc["data"]["Win32_GroupUser"]:
|
||||
if eval(group_user["GroupComponent"]["SID"]) != sid:
|
||||
for group_user in doc.get('data').get("Win32_GroupUser", {}):
|
||||
if eval(group_user.get("GroupComponent", {}).get("SID")) != sid:
|
||||
continue
|
||||
|
||||
if not is_group_sid_type(group_user["GroupComponent"]["SIDType"]):
|
||||
if not is_group_sid_type(group_user.get("GroupComponent", {}).get("SIDType")):
|
||||
continue
|
||||
|
||||
if "PartComponent" not in group_user.keys():
|
||||
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
|
||||
|
||||
wmi_id = group_user["PartComponent"]
|
||||
wmi_id = group_user.get("PartComponent")
|
||||
|
||||
if "cimv2:Win32_UserAccount" not in wmi_id:
|
||||
continue
|
||||
|
@ -336,10 +336,11 @@ class Machine(object):
|
|||
users[sid] = username
|
||||
|
||||
else:
|
||||
if group_user["PartComponent"]["SIDType"] != SidTypeUser:
|
||||
if group_user.get("PartComponent", {}).get("SIDType") != SidTypeUser:
|
||||
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
|
||||
|
||||
|
@ -351,10 +352,10 @@ class Machine(object):
|
|||
GUIDs = set()
|
||||
|
||||
for doc in cur:
|
||||
if not Machine(doc["monkey_guid"]).IsDomainController():
|
||||
if not Machine(doc.get("monkey_guid")).IsDomainController():
|
||||
continue
|
||||
|
||||
GUIDs.add(doc["monkey_guid"])
|
||||
GUIDs.add(doc.get("monkey_guid"))
|
||||
|
||||
return GUIDs
|
||||
|
||||
|
@ -377,11 +378,11 @@ class Machine(object):
|
|||
|
||||
SIDs = set()
|
||||
|
||||
for user in doc["data"]["Win32_UserAccount"]:
|
||||
if user["SIDType"] != SidTypeUser:
|
||||
for user in doc.get('data').get("Win32_UserAccount", {}):
|
||||
if user.get("SIDType") != SidTypeUser:
|
||||
continue
|
||||
|
||||
SIDs.add(eval(user["SID"]))
|
||||
SIDs.add(eval(user.get("SID")))
|
||||
|
||||
return SIDs
|
||||
|
||||
|
@ -408,11 +409,11 @@ class Machine(object):
|
|||
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"]
|
||||
ntlm = sam_user.get("NTLM")
|
||||
if "[hashed secret]" not in ntlm:
|
||||
continue
|
||||
|
||||
sam[sam_user["User"]] = ntlm.replace("[hashed secret]", "").strip()
|
||||
sam[sam_user.get("User")] = ntlm.replace("[hashed secret]", "").strip()
|
||||
|
||||
return sam
|
||||
|
||||
|
@ -533,7 +534,7 @@ class Machine(object):
|
|||
|
||||
SIDs = set()
|
||||
|
||||
for username in doc["data"]["credentials"]:
|
||||
for username in doc.get('data').get("credentials", {}):
|
||||
sid = self.GetSidByUsername(username)
|
||||
|
||||
if not sid:
|
||||
|
@ -549,7 +550,7 @@ class Machine(object):
|
|||
|
||||
names = set()
|
||||
|
||||
for username in doc["data"]["credentials"]:
|
||||
for username in doc.get('data').get("credentials", {}):
|
||||
names.add(username)
|
||||
|
||||
return names
|
||||
|
@ -576,7 +577,7 @@ class PassTheHashReport(object):
|
|||
GUIDs = set()
|
||||
|
||||
for doc in cur:
|
||||
GUIDs.add(doc["monkey_guid"])
|
||||
GUIDs.add(doc.get("monkey_guid"))
|
||||
|
||||
return GUIDs
|
||||
|
||||
|
|
|
@ -41,6 +41,8 @@ class ReportPageComponent extends AuthComponent {
|
|||
super(props);
|
||||
this.state = {
|
||||
report: {},
|
||||
pthreport: {},
|
||||
pthmap: {},
|
||||
graph: {nodes: [], edges: []},
|
||||
allMonkeysAreDead: false,
|
||||
runStarted: true
|
||||
|
@ -49,6 +51,7 @@ class ReportPageComponent extends AuthComponent {
|
|||
|
||||
componentDidMount() {
|
||||
this.updateMonkeysRunning().then(res => this.getReportFromServer(res));
|
||||
this.getPTHReportFromServer();
|
||||
this.updateMapFromServer();
|
||||
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) {
|
||||
if (res['completed_steps']['run_monkey']) {
|
||||
this.authFetch('/api/report')
|
||||
|
@ -432,29 +446,13 @@ class ReportPageComponent extends AuthComponent {
|
|||
<StolenPasswords data={this.state.report.glance.stolen_creds}/>
|
||||
</div>
|
||||
<div style={{marginBottom: '20px'}}>
|
||||
{ /* TODO: use dynamic data */}
|
||||
<SharedCreds data = {[{cred_group: ['MyDomain\\user1', 'user2', 'user3']}, {cred_group: ['user2', 'user4']}]} />
|
||||
<SharedCreds data = {this.state.pthreport.same_password} />
|
||||
</div>
|
||||
<div style={{marginBottom: '20px'}}>
|
||||
{ /* TODO: use dynamic data */}
|
||||
<SharedAdmins data = {[
|
||||
{
|
||||
username: 'SharedLocalAdmin',
|
||||
domain: 'MyDomain',
|
||||
machines: ['hello : 1.2.3.4']
|
||||
}
|
||||
]} />
|
||||
<SharedAdmins data = {this.state.pthreport.local_admin_shared} />
|
||||
</div>
|
||||
<div>
|
||||
{ /* TODO: use dynamic data */}
|
||||
<StrongUsers data = {[
|
||||
{
|
||||
username: 'SharedLocalAdmin',
|
||||
domain: 'MyDomain',
|
||||
machines: ['hello : 1.2.3.4'],
|
||||
services: ['DC', 'DNS']
|
||||
}
|
||||
]} />
|
||||
<StrongUsers data = {this.state.pthreport.strong_users_on_crit_services} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
@ -488,7 +486,7 @@ class ReportPageComponent extends AuthComponent {
|
|||
Credential Map
|
||||
</h3>
|
||||
<div style={{position: 'relative', height: '100vh'}}>
|
||||
<PassTheHashMapPageComponent graph={my_map} />
|
||||
<PassTheHashMapPageComponent graph={this.state.pthmap} />
|
||||
</div>
|
||||
<br />
|
||||
</div>
|
||||
|
|
Loading…
Reference in New Issue