Sending finding to AWS security hub without creds

This commit is contained in:
Shay Nehmad 2019-04-23 12:02:13 +03:00
parent 17aa9f57ca
commit e0ec62b057
1 changed files with 37 additions and 39 deletions

View File

@ -1,17 +1,17 @@
import logging import logging
import uuid import uuid
from datetime import datetime from datetime import datetime
import boto3 import boto3
from botocore.exceptions import UnknownServiceError from botocore.exceptions import UnknownServiceError
from common.cloud.aws_instance import AwsInstance
from monkey_island.cc.environment.environment import load_server_configuration_from_file
from monkey_island.cc.resources.exporter import Exporter from monkey_island.cc.resources.exporter import Exporter
from monkey_island.cc.services.config import ConfigService from monkey_island.cc.services.config import ConfigService
from monkey_island.cc.environment.environment import load_server_configuration_from_file
from common.cloud.aws_instance import AwsInstance
__author__ = 'maor.rayzin' __author__ = 'maor.rayzin'
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
AWS_CRED_CONFIG_KEYS = [['cnc', 'aws_config', 'aws_access_key_id'], AWS_CRED_CONFIG_KEYS = [['cnc', 'aws_config', 'aws_access_key_id'],
@ -23,18 +23,21 @@ class AWSExporter(Exporter):
@staticmethod @staticmethod
def handle_report(report_json): def handle_report(report_json):
aws = AwsInstance()
findings_list = [] findings_list = []
issues_list = report_json['recommendations']['issues'] issues_list = report_json['recommendations']['issues']
if not issues_list: if not issues_list:
logger.info('No issues were found by the monkey, no need to send anything') logger.info('No issues were found by the monkey, no need to send anything')
return True return True
current_aws_region = AwsInstance().get_region()
for machine in issues_list: for machine in issues_list:
for issue in issues_list[machine]: for issue in issues_list[machine]:
if issue.get('aws_instance_id', None): if issue.get('aws_instance_id', None):
findings_list.append(AWSExporter._prepare_finding(issue, aws.get_region())) findings_list.append(AWSExporter._prepare_finding(issue, current_aws_region))
if not AWSExporter._send_findings(findings_list, AWSExporter._get_aws_keys(), aws.get_region()): if not AWSExporter._send_findings(findings_list, current_aws_region):
logger.error('Exporting findings to aws failed') logger.error('Exporting findings to aws failed')
return False return False
@ -100,17 +103,11 @@ class AWSExporter(Exporter):
return AWSExporter.merge_two_dicts(finding, findings_dict[issue['type']](issue, instance_arn)) return AWSExporter.merge_two_dicts(finding, findings_dict[issue['type']](issue, instance_arn))
@staticmethod @staticmethod
def _send_findings(findings_list, creds_dict, region): def _send_findings(findings_list, region):
try: try:
if not creds_dict: securityhub = boto3.client('securityhub', region_name=region)
logger.info('No AWS access credentials received in configuration') # Assumes the machine has the correct IAM role to do this, @see
return False # https://github.com/guardicore/monkey/wiki/Monkey-Island:-Running-the-monkey-on-AWS-EC2-instances
securityhub = boto3.client('securityhub',
aws_access_key_id=creds_dict.get('aws_access_key_id', ''),
aws_secret_access_key=creds_dict.get('aws_secret_access_key', ''),
region_name=region)
import_response = securityhub.batch_import_findings(Findings=findings_list) import_response = securityhub.batch_import_findings(Findings=findings_list)
if import_response['ResponseMetadata']['HTTPStatusCode'] == 200: if import_response['ResponseMetadata']['HTTPStatusCode'] == 200:
return True return True
@ -159,7 +156,7 @@ class AWSExporter(Exporter):
title="Weak segmentation - Machines were able to communicate over unused ports.", title="Weak segmentation - Machines were able to communicate over unused ports.",
description="Use micro-segmentation policies to disable communication other than the required.", description="Use micro-segmentation policies to disable communication other than the required.",
recommendation="Machines are not locked down at port level. Network tunnel was set up from {0} to {1}" recommendation="Machines are not locked down at port level. Network tunnel was set up from {0} to {1}"
.format(issue['machine'], issue['dest']), .format(issue['machine'], issue['dest']),
instance_arn=instance_arn, instance_arn=instance_arn,
instance_id=issue['aws_instance_id'] if 'aws_instance_id' in issue else None instance_id=issue['aws_instance_id'] if 'aws_instance_id' in issue else None
) )
@ -171,9 +168,9 @@ class AWSExporter(Exporter):
severity=10, severity=10,
title="Samba servers are vulnerable to 'SambaCry'", title="Samba servers are vulnerable to 'SambaCry'",
description="Change {0} password to a complex one-use password that is not shared with other computers on the network. Update your Samba server to 4.4.14 and up, 4.5.10 and up, or 4.6.4 and up." \ description="Change {0} password to a complex one-use password that is not shared with other computers on the network. Update your Samba server to 4.4.14 and up, 4.5.10 and up, or 4.6.4 and up." \
.format(issue['username']), .format(issue['username']),
recommendation="The machine {0} ({1}) is vulnerable to a SambaCry attack. The Monkey authenticated over the SMB protocol with user {2} and its password, and used the SambaCry vulnerability.".format( recommendation="The machine {0} ({1}) is vulnerable to a SambaCry attack. The Monkey authenticated over the SMB protocol with user {2} and its password, and used the SambaCry vulnerability.".format(
issue['machine'], issue['ip_address'], issue['username']), issue['machine'], issue['ip_address'], issue['username']),
instance_arn=instance_arn, instance_arn=instance_arn,
instance_id=issue['aws_instance_id'] if 'aws_instance_id' in issue else None instance_id=issue['aws_instance_id'] if 'aws_instance_id' in issue else None
) )
@ -185,9 +182,9 @@ class AWSExporter(Exporter):
severity=5, severity=5,
title="Machines are accessible using passwords supplied by the user during the Monkey's configuration.", title="Machines are accessible using passwords supplied by the user during the Monkey's configuration.",
description="Change {0}'s password to a complex one-use password that is not shared with other computers on the network.".format( description="Change {0}'s password to a complex one-use password that is not shared with other computers on the network.".format(
issue['username']), issue['username']),
recommendation="The machine {0}({1}) is vulnerable to a SMB attack. The Monkey used a pass-the-hash attack over SMB protocol with user {2}.".format( recommendation="The machine {0}({1}) is vulnerable to a SMB attack. The Monkey used a pass-the-hash attack over SMB protocol with user {2}.".format(
issue['machine'], issue['ip_address'], issue['username']), issue['machine'], issue['ip_address'], issue['username']),
instance_arn=instance_arn, instance_arn=instance_arn,
instance_id=issue['aws_instance_id'] if 'aws_instance_id' in issue else None instance_id=issue['aws_instance_id'] if 'aws_instance_id' in issue else None
) )
@ -199,9 +196,9 @@ class AWSExporter(Exporter):
severity=1, severity=1,
title="Machines are accessible using SSH passwords supplied by the user during the Monkey's configuration.", title="Machines are accessible using SSH passwords supplied by the user during the Monkey's configuration.",
description="Change {0}'s password to a complex one-use password that is not shared with other computers on the network.".format( description="Change {0}'s password to a complex one-use password that is not shared with other computers on the network.".format(
issue['username']), issue['username']),
recommendation="The machine {0} ({1}) is vulnerable to a SSH attack. The Monkey authenticated over the SSH protocol with user {2} and its password.".format( recommendation="The machine {0} ({1}) is vulnerable to a SSH attack. The Monkey authenticated over the SSH protocol with user {2} and its password.".format(
issue['machine'], issue['ip_address'], issue['username']), issue['machine'], issue['ip_address'], issue['username']),
instance_arn=instance_arn, instance_arn=instance_arn,
instance_id=issue['aws_instance_id'] if 'aws_instance_id' in issue else None instance_id=issue['aws_instance_id'] if 'aws_instance_id' in issue else None
) )
@ -214,7 +211,7 @@ class AWSExporter(Exporter):
title="Machines are accessible using SSH passwords supplied by the user during the Monkey's configuration.", title="Machines are accessible using SSH passwords supplied by the user during the Monkey's configuration.",
description="Protect {ssh_key} private key with a pass phrase.".format(ssh_key=issue['ssh_key']), description="Protect {ssh_key} private key with a pass phrase.".format(ssh_key=issue['ssh_key']),
recommendation="The machine {machine} ({ip_address}) is vulnerable to a SSH attack. The Monkey authenticated over the SSH protocol with private key {ssh_key}.".format( recommendation="The machine {machine} ({ip_address}) is vulnerable to a SSH attack. The Monkey authenticated over the SSH protocol with private key {ssh_key}.".format(
machine=issue['machine'], ip_address=issue['ip_address'], ssh_key=issue['ssh_key']), machine=issue['machine'], ip_address=issue['ip_address'], ssh_key=issue['ssh_key']),
instance_arn=instance_arn, instance_arn=instance_arn,
instance_id=issue['aws_instance_id'] if 'aws_instance_id' in issue else None instance_id=issue['aws_instance_id'] if 'aws_instance_id' in issue else None
) )
@ -227,7 +224,7 @@ class AWSExporter(Exporter):
title="Elastic Search servers are vulnerable to CVE-2015-1427", title="Elastic Search servers are vulnerable to CVE-2015-1427",
description="Update your Elastic Search server to version 1.4.3 and up.", description="Update your Elastic Search server to version 1.4.3 and up.",
recommendation="The machine {0}({1}) is vulnerable to an Elastic Groovy attack. The attack was made possible because the Elastic Search server was not patched against CVE-2015-1427.".format( recommendation="The machine {0}({1}) is vulnerable to an Elastic Groovy attack. The attack was made possible because the Elastic Search server was not patched against CVE-2015-1427.".format(
issue['machine'], issue['ip_address']), issue['machine'], issue['ip_address']),
instance_arn=instance_arn, instance_arn=instance_arn,
instance_id=issue['aws_instance_id'] if 'aws_instance_id' in issue else None instance_id=issue['aws_instance_id'] if 'aws_instance_id' in issue else None
) )
@ -243,7 +240,8 @@ class AWSExporter(Exporter):
{0} in the networks {1} \ {0} in the networks {1} \
could directly access the Monkey Island server in the networks {2}.".format(issue['machine'], could directly access the Monkey Island server in the networks {2}.".format(issue['machine'],
issue['networks'], issue['networks'],
issue['server_networks']), issue[
'server_networks']),
instance_arn=instance_arn, instance_arn=instance_arn,
instance_id=issue['aws_instance_id'] if 'aws_instance_id' in issue else None instance_id=issue['aws_instance_id'] if 'aws_instance_id' in issue else None
) )
@ -269,7 +267,7 @@ class AWSExporter(Exporter):
description="Update your Bash to a ShellShock-patched version.", description="Update your Bash to a ShellShock-patched version.",
recommendation="The machine {0} ({1}) is vulnerable to a ShellShock attack. " recommendation="The machine {0} ({1}) is vulnerable to a ShellShock attack. "
"The attack was made possible because the HTTP server running on TCP port {2} was vulnerable to a shell injection attack on the paths: {3}.".format( "The attack was made possible because the HTTP server running on TCP port {2} was vulnerable to a shell injection attack on the paths: {3}.".format(
issue['machine'], issue['ip_address'], issue['port'], issue['paths']), issue['machine'], issue['ip_address'], issue['port'], issue['paths']),
instance_arn=instance_arn, instance_arn=instance_arn,
instance_id=issue['aws_instance_id'] if 'aws_instance_id' in issue else None instance_id=issue['aws_instance_id'] if 'aws_instance_id' in issue else None
) )
@ -281,9 +279,9 @@ class AWSExporter(Exporter):
severity=1, severity=1,
title="Machines are accessible using passwords supplied by the user during the Monkey's configuration.", title="Machines are accessible using passwords supplied by the user during the Monkey's configuration.",
description="Change {0}'s password to a complex one-use password that is not shared with other computers on the network.".format( description="Change {0}'s password to a complex one-use password that is not shared with other computers on the network.".format(
issue['username']), issue['username']),
recommendation="The machine {0} ({1}) is vulnerable to a SMB attack. The Monkey authenticated over the SMB protocol with user {2} and its password.".format( recommendation="The machine {0} ({1}) is vulnerable to a SMB attack. The Monkey authenticated over the SMB protocol with user {2} and its password.".format(
issue['machine'], issue['ip_address'], issue['username']), issue['machine'], issue['ip_address'], issue['username']),
instance_arn=instance_arn, instance_arn=instance_arn,
instance_id=issue['aws_instance_id'] if 'aws_instance_id' in issue else None instance_id=issue['aws_instance_id'] if 'aws_instance_id' in issue else None
) )
@ -296,7 +294,7 @@ class AWSExporter(Exporter):
title="Machines are accessible using passwords supplied by the user during the Monkey's configuration.", title="Machines are accessible using passwords supplied by the user during the Monkey's configuration.",
description="Change {0}'s password to a complex one-use password that is not shared with other computers on the network.", description="Change {0}'s password to a complex one-use password that is not shared with other computers on the network.",
recommendation="The machine machine ({ip_address}) is vulnerable to a WMI attack. The Monkey authenticated over the WMI protocol with user {username} and its password.".format( recommendation="The machine machine ({ip_address}) is vulnerable to a WMI attack. The Monkey authenticated over the WMI protocol with user {username} and its password.".format(
machine=issue['machine'], ip_address=issue['ip_address'], username=issue['username']), machine=issue['machine'], ip_address=issue['ip_address'], username=issue['username']),
instance_arn=instance_arn, instance_arn=instance_arn,
instance_id=issue['aws_instance_id'] if 'aws_instance_id' in issue else None instance_id=issue['aws_instance_id'] if 'aws_instance_id' in issue else None
) )
@ -308,9 +306,9 @@ class AWSExporter(Exporter):
severity=1, severity=1,
title="Machines are accessible using passwords supplied by the user during the Monkey's configuration.", title="Machines are accessible using passwords supplied by the user during the Monkey's configuration.",
description="Change {0}'s password to a complex one-use password that is not shared with other computers on the network.".format( description="Change {0}'s password to a complex one-use password that is not shared with other computers on the network.".format(
issue['username']), issue['username']),
recommendation="The machine machine ({ip_address}) is vulnerable to a WMI attack. The Monkey used a pass-the-hash attack over WMI protocol with user {username}".format( recommendation="The machine machine ({ip_address}) is vulnerable to a WMI attack. The Monkey used a pass-the-hash attack over WMI protocol with user {username}".format(
machine=issue['machine'], ip_address=issue['ip_address'], username=issue['username']), machine=issue['machine'], ip_address=issue['ip_address'], username=issue['username']),
instance_arn=instance_arn, instance_arn=instance_arn,
instance_id=issue['aws_instance_id'] if 'aws_instance_id' in issue else None instance_id=issue['aws_instance_id'] if 'aws_instance_id' in issue else None
) )
@ -322,9 +320,9 @@ class AWSExporter(Exporter):
severity=1, severity=1,
title="Machines are accessible using passwords supplied by the user during the Monkey's configuration.", title="Machines are accessible using passwords supplied by the user during the Monkey's configuration.",
description="Change {0}'s password to a complex one-use password that is not shared with other computers on the network.".format( description="Change {0}'s password to a complex one-use password that is not shared with other computers on the network.".format(
issue['username']), issue['username']),
recommendation="The machine machine ({ip_address}) is vulnerable to a RDP attack. The Monkey authenticated over the RDP protocol with user {username} and its password.".format( recommendation="The machine machine ({ip_address}) is vulnerable to a RDP attack. The Monkey authenticated over the RDP protocol with user {username} and its password.".format(
machine=issue['machine'], ip_address=issue['ip_address'], username=issue['username']), machine=issue['machine'], ip_address=issue['ip_address'], username=issue['username']),
instance_arn=instance_arn, instance_arn=instance_arn,
instance_id=issue['aws_instance_id'] if 'aws_instance_id' in issue else None instance_id=issue['aws_instance_id'] if 'aws_instance_id' in issue else None
) )
@ -337,7 +335,7 @@ class AWSExporter(Exporter):
title="Multiple users have the same password.", title="Multiple users have the same password.",
description="Some domain users are sharing passwords, this should be fixed by changing passwords.", description="Some domain users are sharing passwords, this should be fixed by changing passwords.",
recommendation="These users are sharing access password: {shared_with}.".format( recommendation="These users are sharing access password: {shared_with}.".format(
shared_with=issue['shared_with']), shared_with=issue['shared_with']),
instance_arn=instance_arn, instance_arn=instance_arn,
instance_id=issue['aws_instance_id'] if 'aws_instance_id' in issue else None instance_id=issue['aws_instance_id'] if 'aws_instance_id' in issue else None
) )
@ -350,7 +348,7 @@ class AWSExporter(Exporter):
title="Shared local administrator account - Different machines have the same account as a local administrator.", title="Shared local administrator account - Different machines have the same account as a local administrator.",
description="Make sure the right administrator accounts are managing the right machines, and that there isn\'t an unintentional local admin sharing.", description="Make sure the right administrator accounts are managing the right machines, and that there isn\'t an unintentional local admin sharing.",
recommendation="Here is a list of machines which the account {username} is defined as an administrator: {shared_machines}".format( recommendation="Here is a list of machines which the account {username} is defined as an administrator: {shared_machines}".format(
username=issue['username'], shared_machines=issue['shared_machines']), username=issue['username'], shared_machines=issue['shared_machines']),
instance_arn=instance_arn, instance_arn=instance_arn,
instance_id=issue['aws_instance_id'] if 'aws_instance_id' in issue else None instance_id=issue['aws_instance_id'] if 'aws_instance_id' in issue else None
) )
@ -363,7 +361,7 @@ class AWSExporter(Exporter):
title="Mimikatz found login credentials of a user who has admin access to a server defined as critical.", title="Mimikatz found login credentials of a user who has admin access to a server defined as critical.",
description="This critical machine is open to attacks via strong users with access to it.", description="This critical machine is open to attacks via strong users with access to it.",
recommendation="The services: {services} have been found on the machine thus classifying it as a critical machine. These users has access to it:{threatening_users}.".format( recommendation="The services: {services} have been found on the machine thus classifying it as a critical machine. These users has access to it:{threatening_users}.".format(
services=issue['services'], threatening_users=issue['threatening_users']), services=issue['services'], threatening_users=issue['threatening_users']),
instance_arn=instance_arn, instance_arn=instance_arn,
instance_id=issue['aws_instance_id'] if 'aws_instance_id' in issue else None instance_id=issue['aws_instance_id'] if 'aws_instance_id' in issue else None
) )
@ -377,7 +375,7 @@ class AWSExporter(Exporter):
description="Upgrade Struts2 to version 2.3.32 or 2.5.10.1 or any later versions.", description="Upgrade Struts2 to version 2.3.32 or 2.5.10.1 or any later versions.",
recommendation="Struts2 server at {machine} ({ip_address}) is vulnerable to remote code execution attack." recommendation="Struts2 server at {machine} ({ip_address}) is vulnerable to remote code execution attack."
" The attack was made possible because the server is using an old version of Jakarta based file upload Multipart parser.".format( " The attack was made possible because the server is using an old version of Jakarta based file upload Multipart parser.".format(
machine=issue['machine'], ip_address=issue['ip_address']), machine=issue['machine'], ip_address=issue['ip_address']),
instance_arn=instance_arn, instance_arn=instance_arn,
instance_id=issue['aws_instance_id'] if 'aws_instance_id' in issue else None instance_id=issue['aws_instance_id'] if 'aws_instance_id' in issue else None
) )
@ -392,7 +390,7 @@ class AWSExporter(Exporter):
"Vulnerable versions are 10.3.6.0.0, 12.1.3.0.0, 12.2.1.1.0 and 12.2.1.2.0.", "Vulnerable versions are 10.3.6.0.0, 12.1.3.0.0, 12.2.1.1.0 and 12.2.1.2.0.",
recommendation="Oracle WebLogic server at {machine} ({ip_address}) is vulnerable to remote code execution attack." recommendation="Oracle WebLogic server at {machine} ({ip_address}) is vulnerable to remote code execution attack."
" The attack was made possible due to incorrect permission assignment in Oracle Fusion Middleware (subcomponent: WLS Security).".format( " The attack was made possible due to incorrect permission assignment in Oracle Fusion Middleware (subcomponent: WLS Security).".format(
machine=issue['machine'], ip_address=issue['ip_address']), machine=issue['machine'], ip_address=issue['ip_address']),
instance_arn=instance_arn, instance_arn=instance_arn,
instance_id=issue['aws_instance_id'] if 'aws_instance_id' in issue else None instance_id=issue['aws_instance_id'] if 'aws_instance_id' in issue else None
) )