Add Azure password stealing to the report.

This commit is contained in:
Daniel Goldberg 2018-03-25 11:27:57 +03:00
parent 21abdb5cef
commit 93fee0d2c5
3 changed files with 68 additions and 3 deletions

View File

@ -126,5 +126,7 @@ class InfoCollector(object):
# we might be losing passwords in case of multiple reset attempts on same username # 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 # or in case another collector already filled in a password for this user
self.info["credentials"][username]['Password'] = password self.info["credentials"][username]['Password'] = password
self.info["credentials"][username]['Azure'] = True
if len(azure_creds) != 0: if len(azure_creds) != 0:
self.info["Azure"] = True self.info["Azure"] = True

View File

@ -33,6 +33,7 @@ class ReportService:
SAMBACRY = 3 SAMBACRY = 3
SHELLSHOCK = 4 SHELLSHOCK = 4
CONFICKER = 5 CONFICKER = 5
AZURE = 6
class WARNINGS_DICT(Enum): class WARNINGS_DICT(Enum):
CROSS_SEGMENT = 0 CROSS_SEGMENT = 0
@ -71,6 +72,19 @@ class ReportService:
} }
for tunnel in mongo.db.monkey.find({'tunnel': {'$exists': True}}, {'tunnel': 1})] 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 @staticmethod
def get_scanned(): def get_scanned():
nodes = \ nodes = \
@ -135,6 +149,26 @@ class ReportService:
) )
return creds 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 @staticmethod
def process_general_exploit(exploit): def process_general_exploit(exploit):
ip_addr = exploit['data']['machine']['ip_addr'] ip_addr = exploit['data']['machine']['ip_addr']
@ -277,7 +311,7 @@ class ReportService:
@staticmethod @staticmethod
def get_issues(): 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 = {} issues_dict = {}
for issue in issues: for issue in issues:
machine = issue['machine'] machine = issue['machine']
@ -337,6 +371,8 @@ class ReportService:
issues_byte_array[ReportService.ISSUES_DICT.SHELLSHOCK.value] = True issues_byte_array[ReportService.ISSUES_DICT.SHELLSHOCK.value] = True
elif issue['type'] == 'conficker': elif issue['type'] == 'conficker':
issues_byte_array[ReportService.ISSUES_DICT.CONFICKER.value] = True 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 \ elif issue['type'].endswith('_password') and issue['password'] in config_passwords and \
issue['username'] in config_users: issue['username'] in config_users:
issues_byte_array[ReportService.ISSUES_DICT.WEAK_PASSWORD.value] = True issues_byte_array[ReportService.ISSUES_DICT.WEAK_PASSWORD.value] = True
@ -397,7 +433,8 @@ class ReportService:
{ {
'scanned': ReportService.get_scanned(), 'scanned': ReportService.get_scanned(),
'exploited': ReportService.get_exploited(), 'exploited': ReportService.get_exploited(),
'stolen_creds': ReportService.get_stolen_creds() 'stolen_creds': ReportService.get_stolen_creds(),
'azure_passwords': ReportService.get_azure_creds(),
}, },
'recommendations': 'recommendations':
{ {

View File

@ -21,7 +21,8 @@ class ReportPageComponent extends AuthComponent {
ELASTIC: 2, ELASTIC: 2,
SAMBACRY: 3, SAMBACRY: 3,
SHELLSHOCK: 4, SHELLSHOCK: 4,
CONFICKER: 5 CONFICKER: 5,
AZURE: 6
}; };
Warning = Warning =
@ -313,6 +314,11 @@ class ReportPageComponent extends AuthComponent {
{this.state.report.overview.issues[this.Issue.WEAK_PASSWORD] ? {this.state.report.overview.issues[this.Issue.WEAK_PASSWORD] ?
<li>Machines are accessible using passwords supplied by the user during the Monkeys <li>Machines are accessible using passwords supplied by the user during the Monkeys
configuration.</li> : null} 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> </ul>
</div> </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) { generateConfickerIssue(issue) {
return ( return (
<li> <li>
@ -631,6 +652,8 @@ class ReportPageComponent extends AuthComponent {
); );
} }
generateIssue = (issue) => { generateIssue = (issue) => {
let data; let data;
switch (issue.type) { switch (issue.type) {
@ -670,6 +693,9 @@ class ReportPageComponent extends AuthComponent {
case 'tunnel': case 'tunnel':
data = this.generateTunnelIssue(issue); data = this.generateTunnelIssue(issue);
break; break;
case 'azure_password':
data = this.generateAzureIssue(issue);
break;
} }
return data; return data;
}; };