- Created the exporter_init file, in there the exporter manager singleton is created and

populated with the relevant exporters (the aws exporter in this case)
- changed the report file to use the new exporter manager singleton
- changed the finding structure in the aws_exporter.py, divided it to creation functions
  and cleaned the code.
This commit is contained in:
maor.rayzin 2018-12-31 14:51:07 +02:00
parent 3ca761f492
commit 7f3ee69527
6 changed files with 261 additions and 453 deletions

View File

@ -0,0 +1,17 @@
from cc.environment.environment import load_env_from_file, AWS
from cc.report_exporter_manager import ReportExporterManager
from cc.resources.aws_exporter import AWSExporter
def populate_exporter_list():
manager = ReportExporterManager()
if is_aws_exporter_required():
manager.add_exporter_to_list(AWSExporter)
def is_aws_exporter_required():
if str(load_env_from_file()) == AWS:
return True
else:
return False

View File

@ -34,6 +34,8 @@ def main():
logger.info('Waiting for MongoDB server') logger.info('Waiting for MongoDB server')
time.sleep(1) time.sleep(1)
app = init_app(mongo_url) app = init_app(mongo_url)
if env.is_debug(): if env.is_debug():
app.run(host='0.0.0.0', debug=True, ssl_context=('monkey_island/cc/server.crt', 'monkey_island/cc/server.key')) app.run(host='0.0.0.0', debug=True, ssl_context=('monkey_island/cc/server.crt', 'monkey_island/cc/server.key'))
@ -44,6 +46,7 @@ def main():
http_server.listen(env.get_island_port()) http_server.listen(env.get_island_port())
logger.info( logger.info(
'Monkey Island Server is running on https://{}:{}'.format(local_ip_addresses()[0], env.get_island_port())) 'Monkey Island Server is running on https://{}:{}'.format(local_ip_addresses()[0], env.get_island_port()))
IOLoop.instance().start() IOLoop.instance().start()

View File

@ -0,0 +1,32 @@
import logging
logger = logging.getLogger(__name__)
class Singleton(type):
_instances = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
return cls._instances[cls]
class ReportExporterManager(object):
__metaclass__ = Singleton
def __init__(self):
self._exporters_set = set()
def get_exporters_list(self):
return self._exporters_set
def add_exporter_to_list(self, exporter):
self._exporters_set.add(exporter)
def export(self, report):
try:
for exporter in self._exporters_set:
exporter().handle_report(report)
except Exception as e:
logger.exception('Failed to export report')

View File

@ -87,6 +87,7 @@ class AWSExporter(Exporter):
"ProductArn": product_arn, "ProductArn": product_arn,
"GeneratorId": issue['type'], "GeneratorId": issue['type'],
"AwsAccountId": account_id, "AwsAccountId": account_id,
"RecordState": "ACTIVE",
"Types": [ "Types": [
"Software and Configuration Checks/Vulnerabilities/CVE" "Software and Configuration Checks/Vulnerabilities/CVE"
], ],
@ -120,488 +121,288 @@ class AWSExporter(Exporter):
return False return False
@staticmethod @staticmethod
def _handle_tunnel_issue(issue, instance_arn): def _get_finding_resource(instance_id, instance_arn):
finding = \ if instance_id:
{"Severity": { return [{
"Product": 5, "Type": "AwsEc2Instance",
"Id": instance_arn.format(instance_id=instance_id)
}]
else:
return [{'Type': 'Other'}]
@staticmethod
def _build_generic_finding(severity, title, description, recommendation, instance_arn, instance_id=None):
finding = {
"Severity": {
"Product": severity,
"Normalized": 100 "Normalized": 100
}, "RecordState": "ACTIVE", },
"Title": "Weak segmentation - Machines were able to communicate over unused ports.", 'Resource': AWSExporter._get_finding_resource(instance_id, instance_arn),
"Description": "Use micro-segmentation policies to disable communication other than the required.", "Title": title,
"Description": description,
"Remediation": { "Remediation": {
"Recommendation": { "Recommendation": {
"Text": "Machines are not locked down at port level. Network tunnel was set up from {0} to {1}" "Text": recommendation
.format(issue['machine'], issue['dest'])
} }
}} }}
if 'aws_instance_id' in issue:
finding["Resources"] = [{
"Type": "AwsEc2Instance",
"Id": instance_arn.format(instance_id=issue['aws_instance_id'])
}]
else:
finding["Resources"] = [{'Type': 'Other'}]
return finding return finding
@staticmethod
def _handle_tunnel_issue(issue, instance_arn):
return AWSExporter._build_generic_finding(
severity=5,
title="Weak segmentation - Machines were able to communicate over unused ports.",
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}"
.format(issue['machine'], issue['dest']),
instance_arn=instance_arn,
instance_id=issue['aws_instance_id'] if 'aws_instance_id' in issue else None
)
@staticmethod @staticmethod
def _handle_sambacry_issue(issue, instance_arn): def _handle_sambacry_issue(issue, instance_arn):
finding = \
{"Severity": {
"Product": 10,
"Normalized": 100
}, "RecordState": "ACTIVE", "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." \
.format(issue['username']), "Remediation": {
"Recommendation": {
"Text": "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'])
}
}}
if 'aws_instance_id' in issue: return AWSExporter._build_generic_finding(
finding["Resources"] = [{ severity=10,
"Type": "AwsEc2Instance", title="Samba servers are vulnerable to 'SambaCry'",
"Id": instance_arn.format(instance_id=issue['aws_instance_id']) 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']),
else: 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(
finding["Resources"] = [{'Type': 'Other'}] issue['machine'], issue['ip_address'], issue['username']),
instance_arn=instance_arn,
return finding instance_id=issue['aws_instance_id'] if 'aws_instance_id' in issue else None
)
@staticmethod @staticmethod
def _handle_smb_pth_issue(issue, instance_arn): def _handle_smb_pth_issue(issue, instance_arn):
finding = \
{"Severity": {
"Product": 5,
"Normalized": 100
}, "RecordState": "ACTIVE",
"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(
issue['username']), "Remediation": {
"Recommendation": {
"Text": "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'])
}
}}
if 'aws_instance_id' in issue: return AWSExporter._build_generic_finding(
finding["Resources"] = [{ severity=5,
"Type": "AwsEc2Instance", title="Machines are accessible using passwords supplied by the user during the Monkey's configuration.",
"Id": instance_arn.format(instance_id=issue['aws_instance_id']) description="Change {0}'s password to a complex one-use password that is not shared with other computers on the network.".format(
}] issue['username']),
else: 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(
finding["Resources"] = [{'Type': 'Other'}] issue['machine'], issue['ip_address'], issue['username']),
instance_arn=instance_arn,
return finding instance_id=issue['aws_instance_id'] if 'aws_instance_id' in issue else None
)
@staticmethod @staticmethod
def _handle_ssh_issue(issue, instance_arn): def _handle_ssh_issue(issue, instance_arn):
finding = \
{"Severity": {
"Product": 1,
"Normalized": 100
}, "RecordState": "ACTIVE",
"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(
issue['username']), "Remediation": {
"Recommendation": {
"Text": "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'])
}
}}
if 'aws_instance_id' in issue: return AWSExporter._build_generic_finding(
finding["Resources"] = [{ severity=1,
"Type": "AwsEc2Instance", title="Machines are accessible using SSH passwords supplied by the user during the Monkey's configuration.",
"Id": instance_arn.format(instance_id=issue['aws_instance_id']) description="Change {0}'s password to a complex one-use password that is not shared with other computers on the network.".format(
}] issue['username']),
else: 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(
finding["Resources"] = [{'Type': 'Other'}] issue['machine'], issue['ip_address'], issue['username']),
instance_arn=instance_arn,
return finding instance_id=issue['aws_instance_id'] if 'aws_instance_id' in issue else None
)
@staticmethod @staticmethod
def _handle_ssh_key_issue(issue, instance_arn): def _handle_ssh_key_issue(issue, instance_arn):
finding = \
{"Severity": {
"Product": 1,
"Normalized": 100
}, "RecordState": "ACTIVE",
"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']),
"Remediation": {
"Recommendation": {
"Text": "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'])
}
}}
if 'aws_instance_id' in issue: return AWSExporter._build_generic_finding(
finding["Resources"] = [{ severity=1,
"Type": "AwsEc2Instance", title="Machines are accessible using SSH passwords supplied by the user during the Monkey's configuration.",
"Id": instance_arn.format(instance_id=issue['aws_instance_id']) 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(
else: machine=issue['machine'], ip_address=issue['ip_address'], ssh_key=issue['ssh_key']),
finding["Resources"] = [{'Type': 'Other'}] instance_arn=instance_arn,
return finding instance_id=issue['aws_instance_id'] if 'aws_instance_id' in issue else None
)
@staticmethod @staticmethod
def _handle_elastic_issue(issue, instance_arn): def _handle_elastic_issue(issue, instance_arn):
finding = \
{"Severity": {
"Product": 10,
"Normalized": 100
}, "RecordState": "ACTIVE", "Title": "Elasticsearch servers are vulnerable to CVE-2015-1427",
"Description": "Update your Elastic Search server to version 1.4.3 and up.", "Remediation": {
"Recommendation": {
"Text": "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'])
}
}}
if 'aws_instance_id' in issue: return AWSExporter._build_generic_finding(
finding["Resources"] = [{ severity=10,
"Type": "AwsEc2Instance", title="Elastic Search servers are vulnerable to CVE-2015-1427",
"Id": instance_arn.format(instance_id=issue['aws_instance_id']) 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(
else: issue['machine'], issue['ip_address']),
finding["Resources"] = [{'Type': 'Other'}] instance_arn=instance_arn,
instance_id=issue['aws_instance_id'] if 'aws_instance_id' in issue else None
return finding )
@staticmethod @staticmethod
def _handle_island_cross_segment_issue(issue, instance_arn): def _handle_island_cross_segment_issue(issue, instance_arn):
finding = \
{"Severity": { return AWSExporter._build_generic_finding(
"Product": 1, severity=1,
"Normalized": 100 title="Weak segmentation - Machines from different segments are able to communicate.",
}, "RecordState": "ACTIVE", description="Segment your network and make sure there is no communication between machines from different segments.",
"Title": "Weak segmentation - Machines from different segments are able to communicate.", recommendation="The network can probably be segmented. A monkey instance on \
"Description": "Segment your network and make sure there is no communication between machines from different segments.",
"Remediation": {
"Recommendation": {
"Text": "The network can probably be segmented. A monkey instance on \
{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_id=issue['aws_instance_id'] if 'aws_instance_id' in issue else None
)
if 'aws_instance_id' in issue:
finding["Resources"] = [{
"Type": "AwsEc2Instance",
"Id": instance_arn.format(instance_id=issue['aws_instance_id'])
}]
else:
finding["Resources"] = [{'Type': 'Other'}]
return finding
@staticmethod @staticmethod
def _handle_shared_passwords_issue(issue, instance_arn): def _handle_shared_passwords_issue(issue, instance_arn):
finding = \
{"Severity": {
"Product": 1,
"Normalized": 100
}, "RecordState": "ACTIVE", "Title": "Multiple users have the same password",
"Description": "Some users are sharing passwords, this should be fixed by changing passwords.",
"Remediation": {
"Recommendation": {
"Text": "These users are sharing access password: {0}.".format(issue['shared_with'])
}
}}
if 'aws_instance_id' in issue: return AWSExporter._build_generic_finding(
finding["Resources"] = [{ severity=1,
"Type": "AwsEc2Instance", title="Multiple users have the same password",
"Id": instance_arn.format(instance_id=issue['aws_instance_id']) description="Some users are sharing passwords, this should be fixed by changing passwords.",
}] recommendation="These users are sharing access password: {0}.".format(issue['shared_with']),
else: instance_arn=instance_arn,
finding["Resources"] = [{'Type': 'Other'}] instance_id=issue['aws_instance_id'] if 'aws_instance_id' in issue else None
)
return finding
@staticmethod @staticmethod
def _handle_shellshock_issue(issue, instance_arn): def _handle_shellshock_issue(issue, instance_arn):
finding = \
{"Severity": { return AWSExporter._build_generic_finding(
"Product": 10, severity=10,
"Normalized": 100 title="Machines are vulnerable to 'Shellshock'",
}, "RecordState": "ACTIVE", "Title": "Machines are vulnerable to 'Shellshock'", description="Update your Bash to a ShellShock-patched version.",
"Description": "Update your Bash to a ShellShock-patched version.", "Remediation": { recommendation="The machine {0} ({1}) is vulnerable to a ShellShock attack. "
"Recommendation": {
"Text": "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_id=issue['aws_instance_id'] if 'aws_instance_id' in issue else None
)
if 'aws_instance_id' in issue:
finding["Resources"] = [{
"Type": "AwsEc2Instance",
"Id": instance_arn.format(instance_id=issue['aws_instance_id'])
}]
else:
finding["Resources"] = [{'Type': 'Other'}]
return finding
@staticmethod @staticmethod
def _handle_smb_password_issue(issue, instance_arn): def _handle_smb_password_issue(issue, instance_arn):
finding = \
{"Severity": {
"Product": 1,
"Normalized": 100
}, "RecordState": "ACTIVE",
"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(
issue['username']), "Remediation": {
"Recommendation": {
"Text": "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'])
}
}}
if 'aws_instance_id' in issue: return AWSExporter._build_generic_finding(
finding["Resources"] = [{ severity=1,
"Type": "AwsEc2Instance", title="Machines are accessible using passwords supplied by the user during the Monkey's configuration.",
"Id": instance_arn.format(instance_id=issue['aws_instance_id']) description="Change {0}'s password to a complex one-use password that is not shared with other computers on the network.".format(
}] issue['username']),
else: 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(
finding["Resources"] = [{'Type': 'Other'}] issue['machine'], issue['ip_address'], issue['username']),
instance_arn=instance_arn,
return finding instance_id=issue['aws_instance_id'] if 'aws_instance_id' in issue else None
)
@staticmethod @staticmethod
def _handle_wmi_password_issue(issue, instance_arn): def _handle_wmi_password_issue(issue, instance_arn):
finding = \
{"Severity": {
"Product": 1,
"Normalized": 100
}, "RecordState": "ACTIVE",
"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.",
"Remediation": {
"Recommendation": {
"Text": "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'])
}
}}
if 'aws_instance_id' in issue: return AWSExporter._build_generic_finding(
finding["Resources"] = [{ severity=1,
"Type": "AwsEc2Instance", title="Machines are accessible using passwords supplied by the user during the Monkey's configuration.",
"Id": instance_arn.format(instance_id=issue['aws_instance_id']) 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(
else: machine=issue['machine'], ip_address=issue['ip_address'], username=issue['username']),
finding["Resources"] = [{'Type': 'Other'}] instance_arn=instance_arn,
instance_id=issue['aws_instance_id'] if 'aws_instance_id' in issue else None
return finding )
@staticmethod @staticmethod
def _handle_wmi_pth_issue(issue, instance_arn): def _handle_wmi_pth_issue(issue, instance_arn):
finding = \
{"Severity": {
"Product": 1,
"Normalized": 100
}, "RecordState": "ACTIVE",
"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(
issue['username']), "Remediation": {
"Recommendation": {
"Text": "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'])
}
}}
if 'aws_instance_id' in issue: return AWSExporter._build_generic_finding(
finding["Resources"] = [{ severity=1,
"Type": "AwsEc2Instance", title="Machines are accessible using passwords supplied by the user during the Monkey's configuration.",
"Id": instance_arn.format(instance_id=issue['aws_instance_id']) description="Change {0}'s password to a complex one-use password that is not shared with other computers on the network.".format(
}] issue['username']),
else: 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(
finding["Resources"] = [{'Type': 'Other'}] machine=issue['machine'], ip_address=issue['ip_address'], username=issue['username']),
instance_arn=instance_arn,
return finding instance_id=issue['aws_instance_id'] if 'aws_instance_id' in issue else None
)
@staticmethod @staticmethod
def _handle_rdp_issue(issue, instance_arn): def _handle_rdp_issue(issue, instance_arn):
finding = \
{"Severity": {
"Product": 1,
"Normalized": 100
}, "RecordState": "ACTIVE",
"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(
issue['username']), "Remediation": {
"Recommendation": {
"Text": "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'])
}
}}
if 'aws_instance_id' in issue: return AWSExporter._build_generic_finding(
finding["Resources"] = [{ severity=1,
"Type": "AwsEc2Instance", title="Machines are accessible using passwords supplied by the user during the Monkey's configuration.",
"Id": instance_arn.format(instance_id=issue['aws_instance_id']) description="Change {0}'s password to a complex one-use password that is not shared with other computers on the network.".format(
}] issue['username']),
else: 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(
finding["Resources"] = [{'Type': 'Other'}] machine=issue['machine'], ip_address=issue['ip_address'], username=issue['username']),
instance_arn=instance_arn,
return finding instance_id=issue['aws_instance_id'] if 'aws_instance_id' in issue else None
)
@staticmethod @staticmethod
def _handle_shared_passwords_domain_issue(issue, instance_arn): def _handle_shared_passwords_domain_issue(issue, instance_arn):
finding = \
{"Severity": {
"Product": 1,
"Normalized": 100
}, "RecordState": "ACTIVE", "Title": "Multiple users have the same password.",
"Description": "Some domain users are sharing passwords, this should be fixed by changing passwords.",
"Remediation": {
"Recommendation": {
"Text": "These users are sharing access password: {shared_with}.".format(
shared_with=issue['shared_with'])
}
}}
if 'aws_instance_id' in issue: return AWSExporter._build_generic_finding(
finding["Resources"] = [{ severity=1,
"Type": "AwsEc2Instance", title="Multiple users have the same password.",
"Id": instance_arn.format(instance_id=issue['aws_instance_id']) description="Some domain users are sharing passwords, this should be fixed by changing passwords.",
}] recommendation="These users are sharing access password: {shared_with}.".format(
else: shared_with=issue['shared_with']),
finding["Resources"] = [{'Type': 'Other'}] instance_arn=instance_arn,
instance_id=issue['aws_instance_id'] if 'aws_instance_id' in issue else None
return finding )
@staticmethod @staticmethod
def _handle_shared_admins_domain_issue(issue, instance_arn): def _handle_shared_admins_domain_issue(issue, instance_arn):
finding = \
{"Severity": {
"Product": 1,
"Normalized": 100
}, "RecordState": "ACTIVE",
"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.",
"Remediation": {
"Recommendation": {
"Text": "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'])
}
}}
if 'aws_instance_id' in issue: return AWSExporter._build_generic_finding(
finding["Resources"] = [{ severity=1,
"Type": "AwsEc2Instance", title="Shared local administrator account - Different machines have the same account as a local administrator.",
"Id": instance_arn.format(instance_id=issue['aws_instance_id']) 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(
else: username=issue['username'], shared_machines=issue['shared_machines']),
finding["Resources"] = [{'Type': 'Other'}] instance_arn=instance_arn,
instance_id=issue['aws_instance_id'] if 'aws_instance_id' in issue else None
return finding )
@staticmethod @staticmethod
def _handle_strong_users_on_crit_issue(issue, instance_arn): def _handle_strong_users_on_crit_issue(issue, instance_arn):
finding = \
{"Severity": {
"Product": 1,
"Normalized": 100
}, "RecordState": "ACTIVE",
"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.",
"Remediation": {
"Recommendation": {
"Text": "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'])
}
}}
if 'aws_instance_id' in issue: return AWSExporter._build_generic_finding(
finding["Resources"] = [{ severity=1,
"Type": "AwsEc2Instance", title="Mimikatz found login credentials of a user who has admin access to a server defined as critical.",
"Id": instance_arn.format(instance_id=issue['aws_instance_id']) 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(
else: services=issue['services'], threatening_users=issue['threatening_users']),
finding["Resources"] = [{'Type': 'Other'}] instance_arn=instance_arn,
instance_id=issue['aws_instance_id'] if 'aws_instance_id' in issue else None
return finding )
@staticmethod @staticmethod
def _handle_struts2_issue(issue, instance_arn): def _handle_struts2_issue(issue, instance_arn):
finding = \
{"Severity": { return AWSExporter._build_generic_finding(
"Product": 10, severity=10,
"Normalized": 100 title="Struts2 servers are vulnerable to remote code execution.",
}, "RecordState": "ACTIVE", "Title": "Struts2 servers are vulnerable to remote code execution.", 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.", "Remediation": { recommendation="Struts2 server at {machine} ({ip_address}) is vulnerable to remote code execution attack."
"Recommendation": {
"Text": "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_id=issue['aws_instance_id'] if 'aws_instance_id' in issue else None
)
if 'aws_instance_id' in issue:
finding["Resources"] = [{
"Type": "AwsEc2Instance",
"Id": instance_arn.format(instance_id=issue['aws_instance_id'])
}]
else:
finding["Resources"] = [{'Type': 'Other'}]
return finding
@staticmethod @staticmethod
def _handle_weblogic_issue(issue, instance_arn): def _handle_weblogic_issue(issue, instance_arn):
finding = \
{"Severity": { return AWSExporter._build_generic_finding(
"Product": 10, severity=10,
"Normalized": 100 title="Oracle WebLogic servers are vulnerable to remote code execution.",
}, "RecordState": "ACTIVE", "Title": "Oracle WebLogic servers are vulnerable to remote code execution.", description="Install Oracle critical patch updates. Or update to the latest version. " \
"Description": "Install Oracle critical patch updates. Or update to the latest version. " \
"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.",
"Remediation": { recommendation="Oracle WebLogic server at {machine} ({ip_address}) is vulnerable to remote code execution attack."
"Recommendation": {
"Text": "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_id=issue['aws_instance_id'] if 'aws_instance_id' in issue else None
)
if 'aws_instance_id' in issue:
finding["Resources"] = [{
"Type": "AwsEc2Instance",
"Id": instance_arn.format(instance_id=issue['aws_instance_id'])
}]
else:
finding["Resources"] = [{'Type': 'Other'}]
return finding
@staticmethod @staticmethod
def _handle_hadoop_issue(issue, instance_arn): def _handle_hadoop_issue(issue, instance_arn):
finding = \
{"Severity": {
"Product": 10,
"Normalized": 100
}, "RecordState": "ACTIVE", "Title": "Hadoop/Yarn servers are vulnerable to remote code execution.",
"Description": "Run Hadoop in secure mode, add Kerberos authentication.", "Remediation": {
"Recommendation": {
"Text": "The Hadoop server at {machine} ({ip_address}) is vulnerable to remote code execution attack."
" The attack was made possible due to default Hadoop/Yarn configuration being insecure."
}
}}
if 'aws_instance_id' in issue: return AWSExporter._build_generic_finding(
finding["Resources"] = [{ severity=10,
"Type": "AwsEc2Instance", title="Hadoop/Yarn servers are vulnerable to remote code execution.",
"Id": instance_arn.format(instance_id=issue['aws_instance_id']) description="Run Hadoop in secure mode, add Kerberos authentication.",
}] recommendation="The Hadoop server at {machine} ({ip_address}) is vulnerable to remote code execution attack."
else: "The attack was made possible due to default Hadoop/Yarn configuration being insecure.",
finding["Resources"] = [{'Type': 'Other'}] instance_arn=instance_arn,
instance_id=issue['aws_instance_id'] if 'aws_instance_id' in issue else None
return finding )

View File

@ -8,7 +8,7 @@ from enum import Enum
from six import text_type from six import text_type
from cc.database import mongo from cc.database import mongo
from cc.resources.aws_exporter import AWSExporter from cc.report_exporter_manager import ReportExporterManager
from cc.services.config import ConfigService from cc.services.config import ConfigService
from cc.services.edge import EdgeService from cc.services.edge import EdgeService
from cc.services.node import NodeService from cc.services.node import NodeService
@ -723,7 +723,7 @@ class ReportService:
'latest_monkey_modifytime': monkey_latest_modify_time 'latest_monkey_modifytime': monkey_latest_modify_time
} }
} }
ReportService.export_to_exporters(report) ReportExporterManager().export(report)
mongo.db.report.drop() mongo.db.report.drop()
mongo.db.report.insert_one(report) mongo.db.report.insert_one(report)
@ -755,8 +755,3 @@ class ReportService:
return mongo.db.edge.count( return mongo.db.edge.count(
{'exploits': {'$elemMatch': {'exploiter': exploit_type, 'result': True}}}, {'exploits': {'$elemMatch': {'exploiter': exploit_type, 'result': True}}},
limit=1) > 0 limit=1) > 0
@staticmethod
def export_to_exporters(report):
for exporter in ReportService.get_active_exporters():
exporter.handle_report(report)

View File

@ -1,40 +0,0 @@
from cc.environment.environment import load_env_from_file, AWS
from cc.resources.aws_exporter import AWSExporter
import logging
logger = logging.getLogger(__name__)
class Borg:
_shared_state = {}
def __init__(self):
self.__dict__ = self._shared_state
class ReportExporterManager(Borg):
def __init__(self):
Borg.__init__(self)
self._exporters_list = []
self._init_exporters()
def get_exporters_list(self):
return self._exporters_list
def _init_exporters(self):
self._init_aws_exporter()
def _init_aws_exporter(self):
if str(load_env_from_file()) == AWS:
self._exporters_list.append(AWSExporter)
def export(self):
try:
for exporter in self._exporters_list:
exporter().handle_report()
except Exception as e:
logger.exception('Failed to export report')
if __name__ == '__main__':
print ReportExporterManager().get_exporters_list()
print ReportExporterManager().get_exporters_list()