forked from p15670423/monkey
Add Azure password stealing to the report.
This commit is contained in:
parent
21abdb5cef
commit
93fee0d2c5
|
@ -126,5 +126,7 @@ class InfoCollector(object):
|
|||
# we might be losing passwords in case of multiple reset attempts on same username
|
||||
# or in case another collector already filled in a password for this user
|
||||
self.info["credentials"][username]['Password'] = password
|
||||
self.info["credentials"][username]['Azure'] = True
|
||||
|
||||
if len(azure_creds) != 0:
|
||||
self.info["Azure"] = True
|
||||
|
|
|
@ -33,6 +33,7 @@ class ReportService:
|
|||
SAMBACRY = 3
|
||||
SHELLSHOCK = 4
|
||||
CONFICKER = 5
|
||||
AZURE = 6
|
||||
|
||||
class WARNINGS_DICT(Enum):
|
||||
CROSS_SEGMENT = 0
|
||||
|
@ -71,6 +72,19 @@ class ReportService:
|
|||
}
|
||||
for tunnel in mongo.db.monkey.find({'tunnel': {'$exists': True}}, {'tunnel': 1})]
|
||||
|
||||
@staticmethod
|
||||
def get_azure_issues():
|
||||
creds = ReportService.get_azure_creds()
|
||||
machines = set([instance['origin'] for instance in creds])
|
||||
|
||||
return [
|
||||
{
|
||||
'type': 'azure_password',
|
||||
'machine': machine,
|
||||
'users': set([instance['username'] for instance in creds if instance['origin']==machine])
|
||||
}
|
||||
for machine in machines]
|
||||
|
||||
@staticmethod
|
||||
def get_scanned():
|
||||
nodes = \
|
||||
|
@ -135,6 +149,26 @@ class ReportService:
|
|||
)
|
||||
return creds
|
||||
|
||||
@staticmethod
|
||||
def get_azure_creds():
|
||||
"""
|
||||
Recover all credentials marked as being from an Azure machine
|
||||
:return: List of credentials.
|
||||
"""
|
||||
creds = []
|
||||
for telem in mongo.db.telemetry.find(
|
||||
{'telem_type': 'system_info_collection', 'data.Azure': {'$exists': True}},
|
||||
{'data.credentials': 1, 'monkey_guid': 1}
|
||||
):
|
||||
monkey_creds = telem['data']['credentials']
|
||||
if len(monkey_creds) == 0:
|
||||
continue
|
||||
origin = NodeService.get_monkey_by_guid(telem['monkey_guid'])['hostname']
|
||||
new_creds = [{'username': user.replace(',', '.'), 'type': 'Clear Password',
|
||||
'origin': origin} for user in monkey_creds if 'Azure' in user]
|
||||
creds.extend(new_creds)
|
||||
return creds
|
||||
|
||||
@staticmethod
|
||||
def process_general_exploit(exploit):
|
||||
ip_addr = exploit['data']['machine']['ip_addr']
|
||||
|
@ -277,7 +311,7 @@ class ReportService:
|
|||
|
||||
@staticmethod
|
||||
def get_issues():
|
||||
issues = ReportService.get_exploits() + ReportService.get_tunnels() + ReportService.get_cross_segment_issues()
|
||||
issues = ReportService.get_exploits() + ReportService.get_tunnels() + ReportService.get_cross_segment_issues() + ReportService.get_azure_issues()
|
||||
issues_dict = {}
|
||||
for issue in issues:
|
||||
machine = issue['machine']
|
||||
|
@ -337,6 +371,8 @@ class ReportService:
|
|||
issues_byte_array[ReportService.ISSUES_DICT.SHELLSHOCK.value] = True
|
||||
elif issue['type'] == 'conficker':
|
||||
issues_byte_array[ReportService.ISSUES_DICT.CONFICKER.value] = True
|
||||
elif issue['type'] == 'azure_password':
|
||||
issues_byte_array[ReportService.ISSUES_DICT.AZURE.value] = True
|
||||
elif issue['type'].endswith('_password') and issue['password'] in config_passwords and \
|
||||
issue['username'] in config_users:
|
||||
issues_byte_array[ReportService.ISSUES_DICT.WEAK_PASSWORD.value] = True
|
||||
|
@ -397,7 +433,8 @@ class ReportService:
|
|||
{
|
||||
'scanned': ReportService.get_scanned(),
|
||||
'exploited': ReportService.get_exploited(),
|
||||
'stolen_creds': ReportService.get_stolen_creds()
|
||||
'stolen_creds': ReportService.get_stolen_creds(),
|
||||
'azure_passwords': ReportService.get_azure_creds(),
|
||||
},
|
||||
'recommendations':
|
||||
{
|
||||
|
|
|
@ -21,7 +21,8 @@ class ReportPageComponent extends AuthComponent {
|
|||
ELASTIC: 2,
|
||||
SAMBACRY: 3,
|
||||
SHELLSHOCK: 4,
|
||||
CONFICKER: 5
|
||||
CONFICKER: 5,
|
||||
AZURE: 6
|
||||
};
|
||||
|
||||
Warning =
|
||||
|
@ -313,6 +314,11 @@ class ReportPageComponent extends AuthComponent {
|
|||
{this.state.report.overview.issues[this.Issue.WEAK_PASSWORD] ?
|
||||
<li>Machines are accessible using passwords supplied by the user during the Monkey’s
|
||||
configuration.</li> : null}
|
||||
{this.state.report.overview.issues[this.Issue.AZURE] ?
|
||||
<li>Machines contained plain text passwords accessible to attackers. For more info see <a
|
||||
href="https://www.guardicore.com/2018/03/recovering-plaintext-passwords-azure/"
|
||||
>Harvesting Azure Passwords</a>.</li> : null}
|
||||
|
||||
</ul>
|
||||
</div>
|
||||
:
|
||||
|
@ -587,6 +593,21 @@ class ReportPageComponent extends AuthComponent {
|
|||
);
|
||||
}
|
||||
|
||||
generateAzureIssue(issue) {
|
||||
return (
|
||||
<li>
|
||||
Azure VM Access configuration files should be deleted after use to avoid credential leakage.
|
||||
<CollapsibleWellComponent>
|
||||
VM Access plugin configuration files were left on the machine. Credentials could be stolen from <span
|
||||
className="label label-primary">{issue.machine}</span> for the following users<span
|
||||
className="label label-primary">{issue.users}</span>. Read more about the security issue and remediation <a
|
||||
href="https://www.guardicore.com/2018/03/recovering-plaintext-passwords-azure/"
|
||||
>here</a>.
|
||||
</CollapsibleWellComponent>
|
||||
</li>
|
||||
);
|
||||
}
|
||||
|
||||
generateConfickerIssue(issue) {
|
||||
return (
|
||||
<li>
|
||||
|
@ -631,6 +652,8 @@ class ReportPageComponent extends AuthComponent {
|
|||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
generateIssue = (issue) => {
|
||||
let data;
|
||||
switch (issue.type) {
|
||||
|
@ -670,6 +693,9 @@ class ReportPageComponent extends AuthComponent {
|
|||
case 'tunnel':
|
||||
data = this.generateTunnelIssue(issue);
|
||||
break;
|
||||
case 'azure_password':
|
||||
data = this.generateAzureIssue(issue);
|
||||
break;
|
||||
}
|
||||
return data;
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue