From 8923e80dc66e329b73749677a063e207a1dad96c Mon Sep 17 00:00:00 2001 From: VakarisZ Date: Tue, 15 Oct 2019 11:12:49 +0300 Subject: [PATCH 01/37] Fixed ring bugs --- monkey/monkey_island/cc/models/monkey.py | 14 +++++++++----- monkey/monkey_island/cc/models/test_monkey.py | 12 ++++++------ 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/monkey/monkey_island/cc/models/monkey.py b/monkey/monkey_island/cc/models/monkey.py index a8a7da2ec..55a5f9190 100644 --- a/monkey/monkey_island/cc/models/monkey.py +++ b/monkey/monkey_island/cc/models/monkey.py @@ -45,20 +45,24 @@ class Monkey(Document): aws_instance_id = StringField(required=False) # This field only exists when the monkey is running on an AWS # instance. See https://github.com/guardicore/monkey/issues/426. + @staticmethod + def __ring_key__(): + return Monkey.guid + # LOGIC @staticmethod def get_single_monkey_by_id(db_id): try: return Monkey.objects.get(id=db_id) except DoesNotExist as ex: - raise MonkeyNotFoundError("info: {0} | id: {1}".format(ex.message, str(db_id))) + raise MonkeyNotFoundError("info: {0} | id: {1}".format(ex, str(db_id))) @staticmethod def get_single_monkey_by_guid(monkey_guid): try: return Monkey.objects.get(guid=monkey_guid) except DoesNotExist as ex: - raise MonkeyNotFoundError("info: {0} | guid: {1}".format(ex.message, str(monkey_guid))) + raise MonkeyNotFoundError("info: {0} | guid: {1}".format(ex, str(monkey_guid))) @staticmethod def get_latest_modifytime(): @@ -88,8 +92,8 @@ class Monkey(Document): os = "windows" return os - @staticmethod @ring.lru() + @staticmethod def get_label_by_id(object_id): current_monkey = Monkey.get_single_monkey_by_id(object_id) label = Monkey.get_hostname_by_id(object_id) + " : " + current_monkey.ip_addresses[0] @@ -97,8 +101,8 @@ class Monkey(Document): label = "MonkeyIsland - " + label return label - @staticmethod @ring.lru() + @staticmethod def get_hostname_by_id(object_id): """ :param object_id: the object ID of a Monkey in the database. @@ -124,10 +128,10 @@ class Monkey(Document): """ return {'ips': self.ip_addresses, 'hostname': self.hostname} - @staticmethod @ring.lru( expire=1 # data has TTL of 1 second. This is useful for rapid calls for report generation. ) + @staticmethod def is_monkey(object_id): try: _ = Monkey.get_single_monkey_by_id(object_id) diff --git a/monkey/monkey_island/cc/models/test_monkey.py b/monkey/monkey_island/cc/models/test_monkey.py index 7a920409c..1bb805e76 100644 --- a/monkey/monkey_island/cc/models/test_monkey.py +++ b/monkey/monkey_island/cc/models/test_monkey.py @@ -126,7 +126,7 @@ class TestMonkey(IslandTestCase): linux_monkey.save() cache_info_before_query = Monkey.get_label_by_id.storage.backend.cache_info() - self.assertEquals(cache_info_before_query.hits, 0) + self.assertEqual(cache_info_before_query.hits, 0) # not cached label = Monkey.get_label_by_id(linux_monkey.id) @@ -138,7 +138,7 @@ class TestMonkey(IslandTestCase): # should be cached _ = Monkey.get_label_by_id(linux_monkey.id) cache_info_after_query = Monkey.get_label_by_id.storage.backend.cache_info() - self.assertEquals(cache_info_after_query.hits, 1) + self.assertEqual(cache_info_after_query.hits, 1) linux_monkey.set_hostname("Another hostname") @@ -146,8 +146,8 @@ class TestMonkey(IslandTestCase): label = Monkey.get_label_by_id(linux_monkey.id) cache_info_after_second_query = Monkey.get_label_by_id.storage.backend.cache_info() # still 1 hit only - self.assertEquals(cache_info_after_second_query.hits, 1) - self.assertEquals(cache_info_after_second_query.misses, 2) + self.assertEqual(cache_info_after_second_query.hits, 1) + self.assertEqual(cache_info_after_second_query.misses, 2) def test_is_monkey(self): self.fail_if_not_testing_env() @@ -157,7 +157,7 @@ class TestMonkey(IslandTestCase): a_monkey.save() cache_info_before_query = Monkey.is_monkey.storage.backend.cache_info() - self.assertEquals(cache_info_before_query.hits, 0) + self.assertEqual(cache_info_before_query.hits, 0) # not cached self.assertTrue(Monkey.is_monkey(a_monkey.id)) @@ -169,5 +169,5 @@ class TestMonkey(IslandTestCase): self.assertFalse(Monkey.is_monkey(fake_id)) cache_info_after_query = Monkey.is_monkey.storage.backend.cache_info() - self.assertEquals(cache_info_after_query.hits, 2) + self.assertEqual(cache_info_after_query.hits, 2) From 8046cddb8b7e53e1d15694709d6a1c0aec9b2a1a Mon Sep 17 00:00:00 2001 From: VakarisZ Date: Wed, 23 Oct 2019 09:19:03 +0300 Subject: [PATCH 02/37] Fixed ring bug with @staticmethod --- monkey/monkey_island/cc/models/monkey.py | 65 ++++++++++--------- monkey/monkey_island/cc/models/test_monkey.py | 26 ++++---- monkey/monkey_island/cc/services/edge.py | 8 +-- monkey/monkey_island/cc/services/node.py | 8 +-- 4 files changed, 54 insertions(+), 53 deletions(-) diff --git a/monkey/monkey_island/cc/models/monkey.py b/monkey/monkey_island/cc/models/monkey.py index 324903809..daeb9ea5b 100644 --- a/monkey/monkey_island/cc/models/monkey.py +++ b/monkey/monkey_island/cc/models/monkey.py @@ -97,25 +97,6 @@ class Monkey(Document): os = "windows" return os - @ring.lru() - @staticmethod - def get_label_by_id(object_id): - current_monkey = Monkey.get_single_monkey_by_id(object_id) - label = Monkey.get_hostname_by_id(object_id) + " : " + current_monkey.ip_addresses[0] - if len(set(current_monkey.ip_addresses).intersection(local_ip_addresses())) > 0: - label = "MonkeyIsland - " + label - return label - - @ring.lru() - @staticmethod - def get_hostname_by_id(object_id): - """ - :param object_id: the object ID of a Monkey in the database. - :return: The hostname of that machine. - :note: Use this and not monkey.hostname for performance - this is lru-cached. - """ - return Monkey.get_single_monkey_by_id(object_id).hostname - def set_hostname(self, hostname): """ Sets a new hostname for a machine and clears the cache for getting it. @@ -123,8 +104,8 @@ class Monkey(Document): """ self.hostname = hostname self.save() - Monkey.get_hostname_by_id.delete(self.id) - Monkey.get_label_by_id.delete(self.id) + get_monkey_hostname_by_id.delete(self.id) + get_monkey_label_by_id.delete(self.id) def get_network_info(self): """ @@ -133,17 +114,6 @@ class Monkey(Document): """ return {'ips': self.ip_addresses, 'hostname': self.hostname} - @ring.lru( - expire=1 # data has TTL of 1 second. This is useful for rapid calls for report generation. - ) - @staticmethod - def is_monkey(object_id): - try: - _ = Monkey.get_single_monkey_by_id(object_id) - return True - except: - return False - @staticmethod def get_tunneled_monkeys(): return Monkey.objects(tunnel__exists=True) @@ -153,5 +123,36 @@ class Monkey(Document): self.save() +# Can't make following methods static under Monkey class due to ring bug +@ring.lru( + expire=1 # data has TTL of 1 second. This is useful for rapid calls for report generation. +) +def is_monkey(object_id): + try: + _ = Monkey.get_single_monkey_by_id(object_id) + return True + except: + return False + + +@ring.lru() +def get_monkey_label_by_id(object_id): + current_monkey = Monkey.get_single_monkey_by_id(object_id) + label = get_monkey_hostname_by_id(object_id) + " : " + current_monkey.ip_addresses[0] + if len(set(current_monkey.ip_addresses).intersection(local_ip_addresses())) > 0: + label = "MonkeyIsland - " + label + return label + + +@ring.lru() +def get_monkey_hostname_by_id(object_id): + """ + :param object_id: the object ID of a Monkey in the database. + :return: The hostname of that machine. + :note: Use this and not monkey.hostname for performance - this is lru-cached. + """ + return Monkey.get_single_monkey_by_id(object_id).hostname + + class MonkeyNotFoundError(Exception): pass diff --git a/monkey/monkey_island/cc/models/test_monkey.py b/monkey/monkey_island/cc/models/test_monkey.py index 1bb805e76..fb9b329b1 100644 --- a/monkey/monkey_island/cc/models/test_monkey.py +++ b/monkey/monkey_island/cc/models/test_monkey.py @@ -2,7 +2,7 @@ import uuid from time import sleep from .monkey import Monkey -from monkey_island.cc.models.monkey import MonkeyNotFoundError +from monkey_island.cc.models.monkey import MonkeyNotFoundError, is_monkey, get_monkey_label_by_id from monkey_island.cc.testing.IslandTestCase import IslandTestCase from .monkey_ttl import MonkeyTtl @@ -125,26 +125,26 @@ class TestMonkey(IslandTestCase): ip_addresses=[ip_example]) linux_monkey.save() - cache_info_before_query = Monkey.get_label_by_id.storage.backend.cache_info() + cache_info_before_query = get_monkey_label_by_id.storage.backend.cache_info() self.assertEqual(cache_info_before_query.hits, 0) # not cached - label = Monkey.get_label_by_id(linux_monkey.id) + label = get_monkey_label_by_id(linux_monkey.id) self.assertIsNotNone(label) self.assertIn(hostname_example, label) self.assertIn(ip_example, label) # should be cached - _ = Monkey.get_label_by_id(linux_monkey.id) - cache_info_after_query = Monkey.get_label_by_id.storage.backend.cache_info() + _ = get_monkey_label_by_id(linux_monkey.id) + cache_info_after_query = get_monkey_label_by_id.storage.backend.cache_info() self.assertEqual(cache_info_after_query.hits, 1) linux_monkey.set_hostname("Another hostname") # should be a miss - label = Monkey.get_label_by_id(linux_monkey.id) - cache_info_after_second_query = Monkey.get_label_by_id.storage.backend.cache_info() + label = get_monkey_label_by_id(linux_monkey.id) + cache_info_after_second_query = get_monkey_label_by_id.storage.backend.cache_info() # still 1 hit only self.assertEqual(cache_info_after_second_query.hits, 1) self.assertEqual(cache_info_after_second_query.misses, 2) @@ -156,18 +156,18 @@ class TestMonkey(IslandTestCase): a_monkey = Monkey(guid=str(uuid.uuid4())) a_monkey.save() - cache_info_before_query = Monkey.is_monkey.storage.backend.cache_info() + cache_info_before_query = is_monkey.storage.backend.cache_info() self.assertEqual(cache_info_before_query.hits, 0) # not cached - self.assertTrue(Monkey.is_monkey(a_monkey.id)) + self.assertTrue(is_monkey(a_monkey.id)) fake_id = "123456789012" - self.assertFalse(Monkey.is_monkey(fake_id)) + self.assertFalse(is_monkey(fake_id)) # should be cached - self.assertTrue(Monkey.is_monkey(a_monkey.id)) - self.assertFalse(Monkey.is_monkey(fake_id)) + self.assertTrue(is_monkey(a_monkey.id)) + self.assertFalse(is_monkey(fake_id)) - cache_info_after_query = Monkey.is_monkey.storage.backend.cache_info() + cache_info_after_query = is_monkey.storage.backend.cache_info() self.assertEqual(cache_info_after_query.hits, 2) diff --git a/monkey/monkey_island/cc/services/edge.py b/monkey/monkey_island/cc/services/edge.py index ae3d2a2de..bf9417309 100644 --- a/monkey/monkey_island/cc/services/edge.py +++ b/monkey/monkey_island/cc/services/edge.py @@ -2,7 +2,7 @@ from bson import ObjectId from monkey_island.cc.database import mongo import monkey_island.cc.services.node -from monkey_island.cc.models import Monkey +from monkey_island.cc.models.monkey import get_monkey_label_by_id, is_monkey __author__ = "itay.mizeretz" @@ -145,13 +145,13 @@ class EdgeService: from_id = edge["from"] to_id = edge["to"] - from_label = Monkey.get_label_by_id(from_id) + from_label = get_monkey_label_by_id(from_id) if to_id == ObjectId("000000000000000000000000"): to_label = 'MonkeyIsland' else: - if Monkey.is_monkey(to_id): - to_label = Monkey.get_label_by_id(to_id) + if is_monkey(to_id): + to_label = get_monkey_label_by_id(to_id) else: to_label = NodeService.get_node_label(NodeService.get_node_by_id(to_id)) diff --git a/monkey/monkey_island/cc/services/node.py b/monkey/monkey_island/cc/services/node.py index 27d2d299a..0c0a873e8 100644 --- a/monkey/monkey_island/cc/services/node.py +++ b/monkey/monkey_island/cc/services/node.py @@ -4,7 +4,7 @@ from bson import ObjectId import monkey_island.cc.services.log from monkey_island.cc.database import mongo -from monkey_island.cc.models import Monkey +from monkey_island.cc.models.monkey import Monkey, get_monkey_hostname_by_id, get_monkey_label_by_id from monkey_island.cc.services.edge import EdgeService from monkey_island.cc.utils import local_ip_addresses import socket @@ -50,8 +50,8 @@ class NodeService: for edge in edges: from_node_id = edge["from"] - from_node_label = Monkey.get_label_by_id(from_node_id) - from_node_hostname = Monkey.get_hostname_by_id(from_node_id) + from_node_label = get_monkey_label_by_id(from_node_id) + from_node_hostname = get_monkey_hostname_by_id(from_node_id) accessible_from_nodes.append(from_node_label) accessible_from_nodes_hostnames.append(from_node_hostname) @@ -140,7 +140,7 @@ class NodeService: @staticmethod def monkey_to_net_node(monkey, for_report=False): monkey_id = monkey["_id"] - label = Monkey.get_hostname_by_id(monkey_id) if for_report else Monkey.get_label_by_id(monkey_id) + label = get_monkey_hostname_by_id(monkey_id) if for_report else get_monkey_label_by_id(monkey_id) monkey_group = NodeService.get_monkey_group(monkey) return \ { From 06bded65eb64b2074a3ac1a9a658500e643bf514 Mon Sep 17 00:00:00 2001 From: VakarisZ Date: Thu, 24 Oct 2019 16:15:33 +0300 Subject: [PATCH 03/37] Wmi fix, expected return code 0, but it is None --- monkey/infection_monkey/exploit/wmiexec.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/monkey/infection_monkey/exploit/wmiexec.py b/monkey/infection_monkey/exploit/wmiexec.py index 947fd57a1..a1da97efe 100644 --- a/monkey/infection_monkey/exploit/wmiexec.py +++ b/monkey/infection_monkey/exploit/wmiexec.py @@ -104,9 +104,9 @@ class WmiExploiter(HostExploiter): ntpath.split(remote_full_path)[0], None) - if (0 != result.ProcessId) and (0 == result.ReturnValue): - LOG.info("Executed dropper '%s' on remote victim %r (pid=%d, exit_code=%d, cmdline=%r)", - remote_full_path, self.host, result.ProcessId, result.ReturnValue, cmdline) + if (0 != result.ProcessId) and (not result.ReturnValue): + LOG.info("Executed dropper '%s' on remote victim %r (pid=%d, cmdline=%r)", + remote_full_path, self.host, result.ProcessId, cmdline) self.add_vuln_port(port='unknown') success = True From 4b84810fae4a69daf35592424802ca6a69c5be18 Mon Sep 17 00:00:00 2001 From: Shay Nehmad Date: Thu, 24 Oct 2019 18:54:20 +0300 Subject: [PATCH 04/37] Updated format errors in aws_exporter and lowered errors to infos in vsftpd exploiter --- monkey/infection_monkey/exploit/vsftpd.py | 6 +++--- monkey/monkey_island/cc/services/reporting/aws_exporter.py | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/monkey/infection_monkey/exploit/vsftpd.py b/monkey/infection_monkey/exploit/vsftpd.py index 136a8a36b..d4116c96c 100644 --- a/monkey/infection_monkey/exploit/vsftpd.py +++ b/monkey/infection_monkey/exploit/vsftpd.py @@ -45,7 +45,7 @@ class VSFTPDExploiter(HostExploiter): s.connect((ip_addr, port)) return True except socket.error as e: - LOG.error('Failed to connect to %s', self.host.ip_addr) + LOG.info('Failed to connect to %s: %s', self.host.ip_addr, str(e)) return False def socket_send_recv(self, s, message): @@ -53,7 +53,7 @@ class VSFTPDExploiter(HostExploiter): s.send(message) return s.recv(RECV_128).decode('utf-8') except socket.error as e: - LOG.error('Failed to send payload to %s', self.host.ip_addr) + LOG.info('Failed to send payload to %s: %s', self.host.ip_addr, str(e)) return False def socket_send(self, s, message): @@ -61,7 +61,7 @@ class VSFTPDExploiter(HostExploiter): s.send(message) return True except socket.error as e: - LOG.error('Failed to send payload to %s', self.host.ip_addr) + LOG.info('Failed to send payload to %s: %s', self.host.ip_addr, str(e)) return False def _exploit_host(self): diff --git a/monkey/monkey_island/cc/services/reporting/aws_exporter.py b/monkey/monkey_island/cc/services/reporting/aws_exporter.py index 0940be503..8690f6ee1 100644 --- a/monkey/monkey_island/cc/services/reporting/aws_exporter.py +++ b/monkey/monkey_island/cc/services/reporting/aws_exporter.py @@ -107,10 +107,10 @@ class AWSExporter(Exporter): else: return False except UnknownServiceError as e: - logger.warning('AWS exporter called but AWS-CLI securityhub service is not installed. Error: ' + e) + logger.warning('AWS exporter called but AWS-CLI security hub service is not installed. Error: {}'.format(e)) return False except Exception as e: - logger.exception('AWS security hub findings failed to send. Error: ' + e) + logger.exception('AWS security hub findings failed to send. Error: {}'.format(e)) return False @staticmethod From 2a7d196cb750d5cc88703720b749bbc760ecf312 Mon Sep 17 00:00:00 2001 From: VakarisZ Date: Fri, 25 Oct 2019 13:18:48 +0300 Subject: [PATCH 05/37] Smb fingerprinter fix --- monkey/infection_monkey/network/smbfinger.py | 105 ++++++++++--------- 1 file changed, 53 insertions(+), 52 deletions(-) diff --git a/monkey/infection_monkey/network/smbfinger.py b/monkey/infection_monkey/network/smbfinger.py index 1e765114c..8a267e9d1 100644 --- a/monkey/infection_monkey/network/smbfinger.py +++ b/monkey/infection_monkey/network/smbfinger.py @@ -12,7 +12,7 @@ SMB_SERVICE = 'tcp-445' LOG = logging.getLogger(__name__) -class Packet(object): +class Packet: fields = odict([ ("data", ""), ]) @@ -25,78 +25,79 @@ class Packet(object): else: self.fields[k] = v - def __str__(self): - return "".join(map(str, list(self.fields.values()))) + def to_byte_string(self): + content_list = [(x.to_byte_string() if hasattr(x, "to_byte_string") else x) for x in self.fields.values()] + return b"".join(content_list) ##### SMB Packets ##### class SMBHeader(Packet): fields = odict([ - ("proto", "\xff\x53\x4d\x42"), - ("cmd", "\x72"), - ("errorcode", "\x00\x00\x00\x00"), - ("flag1", "\x00"), - ("flag2", "\x00\x00"), - ("pidhigh", "\x00\x00"), - ("signature", "\x00\x00\x00\x00\x00\x00\x00\x00"), - ("reserved", "\x00\x00"), - ("tid", "\x00\x00"), - ("pid", "\x00\x00"), - ("uid", "\x00\x00"), - ("mid", "\x00\x00"), + ("proto", b"\xff\x53\x4d\x42"), + ("cmd", b"\x72"), + ("errorcode", b"\x00\x00\x00\x00"), + ("flag1", b"\x00"), + ("flag2", b"\x00\x00"), + ("pidhigh", b"\x00\x00"), + ("signature", b"\x00\x00\x00\x00\x00\x00\x00\x00"), + ("reserved", b"\x00\x00"), + ("tid", b"\x00\x00"), + ("pid", b"\x00\x00"), + ("uid", b"\x00\x00"), + ("mid", b"\x00\x00"), ]) class SMBNego(Packet): fields = odict([ - ("wordcount", "\x00"), - ("bcc", "\x62\x00"), + ("wordcount", b"\x00"), + ("bcc", b"\x62\x00"), ("data", "") ]) def calculate(self): - self.fields["bcc"] = struct.pack("i", len(packet_)) + packet_.encode() + packet_ = h.to_byte_string() + n.to_byte_string() + buffer = struct.pack(">i", len(packet_)) + packet_ s.send(buffer) data = s.recv(2048) - if data[8:10] == "\x72\x00": - header = SMBHeader(cmd="\x73", flag1="\x18", flag2="\x17\xc8", uid="\x00\x00") + if data[8:10] == b"\x72\x00": + header = SMBHeader(cmd=b"\x73", flag1=b"\x18", flag2=b"\x17\xc8", uid=b"\x00\x00") body = SMBSessionFingerData() body.calculate() - packet_ = str(header) + str(body) - buffer = struct.pack(">i", len(packet_)) + packet_.encode() + packet_ = header.to_byte_string() + body.to_byte_string() + buffer = struct.pack(">i", len(packet_)) + packet_ s.send(buffer) data = s.recv(2048) - if data[8:10] == "\x73\x16": + if data[8:10] == b"\x73\x16": length = struct.unpack(' Date: Fri, 25 Oct 2019 16:50:45 +0300 Subject: [PATCH 06/37] Smb exploiter py3 and bugfix --- monkey/infection_monkey/exploit/smbexec.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/monkey/infection_monkey/exploit/smbexec.py b/monkey/infection_monkey/exploit/smbexec.py index 18331e994..2eb30b2a1 100644 --- a/monkey/infection_monkey/exploit/smbexec.py +++ b/monkey/infection_monkey/exploit/smbexec.py @@ -108,16 +108,15 @@ class SmbExploiter(HostExploiter): cmdline = MONKEY_CMDLINE_DETACHED_WINDOWS % {'monkey_path': remote_full_path} + \ build_monkey_commandline(self.host, get_monkey_depth() - 1) - for str_bind_format, port in list(SmbExploiter.KNOWN_PROTOCOLS.values()): + smb_conn = False + for str_bind_format, port in SmbExploiter.KNOWN_PROTOCOLS.values(): rpctransport = transport.DCERPCTransportFactory(str_bind_format % (self.host.ip_addr,)) rpctransport.set_dport(port) - if hasattr(rpctransport, 'preferred_dialect'): rpctransport.preferred_dialect(SMB_DIALECT) if hasattr(rpctransport, 'set_credentials'): # This method exists only for selected protocol sequences. - rpctransport.set_credentials(user, password, '', - lm_hash, ntlm_hash, None) + rpctransport.set_credentials(user, password, '', lm_hash, ntlm_hash, None) rpctransport.set_kerberos(SmbExploiter.USE_KERBEROS) scmr_rpc = rpctransport.get_dce_rpc() @@ -127,11 +126,13 @@ class SmbExploiter(HostExploiter): except Exception as exc: LOG.warning("Error connecting to SCM on exploited machine %r: %s", self.host, exc) - return False + continue smb_conn = rpctransport.get_smb_connection() break + if not smb_conn: + return False # We don't wanna deal with timeouts from now on. smb_conn.setTimeout(100000) scmr_rpc.bind(scmr.MSRPC_UUID_SCMR) From 1d666e525d3895fbc184310f2aff1e418188a0c8 Mon Sep 17 00:00:00 2001 From: VakarisZ Date: Fri, 25 Oct 2019 17:50:32 +0300 Subject: [PATCH 07/37] Smb logging improved, mimikatz bugfix --- monkey/infection_monkey/exploit/smbexec.py | 3 +-- monkey/infection_monkey/system_info/mimikatz_collector.py | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/monkey/infection_monkey/exploit/smbexec.py b/monkey/infection_monkey/exploit/smbexec.py index 2eb30b2a1..348b6803d 100644 --- a/monkey/infection_monkey/exploit/smbexec.py +++ b/monkey/infection_monkey/exploit/smbexec.py @@ -124,8 +124,7 @@ class SmbExploiter(HostExploiter): try: scmr_rpc.connect() except Exception as exc: - LOG.warning("Error connecting to SCM on exploited machine %r: %s", - self.host, exc) + LOG.debug("Can't connect to SCM on exploited machine %r port %s : %s", self.host, port, exc) continue smb_conn = rpctransport.get_smb_connection() diff --git a/monkey/infection_monkey/system_info/mimikatz_collector.py b/monkey/infection_monkey/system_info/mimikatz_collector.py index 2951b7ebc..f73340a25 100644 --- a/monkey/infection_monkey/system_info/mimikatz_collector.py +++ b/monkey/infection_monkey/system_info/mimikatz_collector.py @@ -27,7 +27,7 @@ class MimikatzCollector(object): MIMIKATZ_ZIP_NAME = 'tmpzipfile123456.zip' # Password to Mimikatz zip file - MIMIKATZ_ZIP_PASSWORD = r'VTQpsJPXgZuXhX6x3V84G' + MIMIKATZ_ZIP_PASSWORD = b'VTQpsJPXgZuXhX6x3V84G' def __init__(self): self._config = infection_monkey.config.WormConfiguration From 6e2f1f0d760dcba7502208da0e0e69369ce24865 Mon Sep 17 00:00:00 2001 From: VakarisZ Date: Fri, 25 Oct 2019 18:11:21 +0300 Subject: [PATCH 08/37] Log download fix --- monkey/monkey_island/cc/services/log.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/monkey/monkey_island/cc/services/log.py b/monkey/monkey_island/cc/services/log.py index d58a4beac..ff3bf7304 100644 --- a/monkey/monkey_island/cc/services/log.py +++ b/monkey/monkey_island/cc/services/log.py @@ -20,7 +20,7 @@ class LogService: return \ { 'monkey_label': monkey_label, - 'log': log_file.read(), + 'log': log_file.read().decode(), 'timestamp': log['timestamp'] } From 05fbdafd9dbc68bc6e2f2778c0919761db294e43 Mon Sep 17 00:00:00 2001 From: Shay Nehmad Date: Sun, 27 Oct 2019 12:13:26 +0200 Subject: [PATCH 09/37] Updated travis file, let's test it --- .travis.yml | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/.travis.yml b/.travis.yml index b14482939..9e942af58 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,17 +2,20 @@ group: travis_latest language: python cache: pip python: - - 2.7 +- 3.7 install: - #- pip install -r requirements.txt - - pip install flake8 # pytest # add another testing frameworks later +- pip install -r monkey/monkey_island/requirements.txt +- pip install flake8 pytest dlint before_script: - # stop the build if there are Python syntax errors or undefined names - - flake8 . --count --select=E901,E999,F821,F822,F823 --show-source --statistics - # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide - - flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics +- flake8 . --count --select=E901,E999,F821,F822,F823 --show-source --statistics +- flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics script: - - true # pytest --capture=sys # add other tests here +- pytest --capture=sys notifications: + on_success: change + on_failure: always + slack: + rooms: + secure: wFddByqGGfwpjuisZhXQGAI7Y/7yZ+ON58R19D2ff+p1lT26BIdE+gSWQFWTbSNcyjVhAMCkbKgRblL2o0WcuiCyYjlcIoT/fEMuypxNTnlC1FtHlmEO/1JAyDVskzRWvu7q98szcDP+yKjUZSjUrLMnzUYtdB7hhAp8iRvEUTgtKQi27kmgBX9lLqAf93WO1Ocp2+fmDkNmegx2bBa9PQS4FYOtqN7DYZ0cHM7wLffyHZmSXZkwCcq+u7mSONrfQZprCvzQu9kntx/zEnjTuNHUZ8L0SNu035Yg2MtxnKDY1GPSox5ax5rZJID4aN+f7vDkIgIskMwVcjFoMS4bvp8xH1liWleR/VdOYhTP1bx5GcLvkUFC/xAwW730AZnU9Ihn3iSLK8iiowf7UMOYLB371KDlZWj2gwRvccRb7VwismLzcYt/So/5/xDa4IgDNNUu/fb9J+TPc+3jKPt3E6KSHseBcyk2ov7iC14pUz/AWEcWga2s5cRiWqBibUuiJUXZf0zExyEnj9dic5jF/UW8EVpDygy5TaAVq9VD30zslzPcIDbl1slEh2Nd6LXQWCiz9UMDN85OHkuXSgNyuSpna6W0+/qNv3SQLrcwTKTNj/ZSLTj5lZIyQ7l11xW36H+uyx4D8rYOpHw8HxrGXnh5hyWhOa4GCGzgSgFZlU8= on_success: change - on_failure: change # `always` will be the setting once code changes slow down + on_failure: always From c11d78c6a078ce179e5042c6dd81eeffde1e00f0 Mon Sep 17 00:00:00 2001 From: Shay Nehmad Date: Sun, 27 Oct 2019 12:24:46 +0200 Subject: [PATCH 10/37] cd-ing to source root --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 9e942af58..a5c2da172 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,6 +7,7 @@ install: - pip install -r monkey/monkey_island/requirements.txt - pip install flake8 pytest dlint before_script: +- cd monkey - flake8 . --count --select=E901,E999,F821,F822,F823 --show-source --statistics - flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics script: From cc674cac5731a8009d116846bb3d29747807777d Mon Sep 17 00:00:00 2001 From: Shay Nehmad Date: Sun, 27 Oct 2019 12:29:52 +0200 Subject: [PATCH 11/37] Trying to fix slack notifications from travis --- .travis.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index a5c2da172..dccf11dff 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,7 +16,7 @@ notifications: on_success: change on_failure: always slack: - rooms: - secure: wFddByqGGfwpjuisZhXQGAI7Y/7yZ+ON58R19D2ff+p1lT26BIdE+gSWQFWTbSNcyjVhAMCkbKgRblL2o0WcuiCyYjlcIoT/fEMuypxNTnlC1FtHlmEO/1JAyDVskzRWvu7q98szcDP+yKjUZSjUrLMnzUYtdB7hhAp8iRvEUTgtKQi27kmgBX9lLqAf93WO1Ocp2+fmDkNmegx2bBa9PQS4FYOtqN7DYZ0cHM7wLffyHZmSXZkwCcq+u7mSONrfQZprCvzQu9kntx/zEnjTuNHUZ8L0SNu035Yg2MtxnKDY1GPSox5ax5rZJID4aN+f7vDkIgIskMwVcjFoMS4bvp8xH1liWleR/VdOYhTP1bx5GcLvkUFC/xAwW730AZnU9Ihn3iSLK8iiowf7UMOYLB371KDlZWj2gwRvccRb7VwismLzcYt/So/5/xDa4IgDNNUu/fb9J+TPc+3jKPt3E6KSHseBcyk2ov7iC14pUz/AWEcWga2s5cRiWqBibUuiJUXZf0zExyEnj9dic5jF/UW8EVpDygy5TaAVq9VD30zslzPcIDbl1slEh2Nd6LXQWCiz9UMDN85OHkuXSgNyuSpna6W0+/qNv3SQLrcwTKTNj/ZSLTj5lZIyQ7l11xW36H+uyx4D8rYOpHw8HxrGXnh5hyWhOa4GCGzgSgFZlU8= - on_success: change - on_failure: always + rooms: + - secure: wFddByqGGfwpjuisZhXQGAI7Y/7yZ+ON58R19D2ff+p1lT26BIdE+gSWQFWTbSNcyjVhAMCkbKgRblL2o0WcuiCyYjlcIoT/fEMuypxNTnlC1FtHlmEO/1JAyDVskzRWvu7q98szcDP+yKjUZSjUrLMnzUYtdB7hhAp8iRvEUTgtKQi27kmgBX9lLqAf93WO1Ocp2+fmDkNmegx2bBa9PQS4FYOtqN7DYZ0cHM7wLffyHZmSXZkwCcq+u7mSONrfQZprCvzQu9kntx/zEnjTuNHUZ8L0SNu035Yg2MtxnKDY1GPSox5ax5rZJID4aN+f7vDkIgIskMwVcjFoMS4bvp8xH1liWleR/VdOYhTP1bx5GcLvkUFC/xAwW730AZnU9Ihn3iSLK8iiowf7UMOYLB371KDlZWj2gwRvccRb7VwismLzcYt/So/5/xDa4IgDNNUu/fb9J+TPc+3jKPt3E6KSHseBcyk2ov7iC14pUz/AWEcWga2s5cRiWqBibUuiJUXZf0zExyEnj9dic5jF/UW8EVpDygy5TaAVq9VD30zslzPcIDbl1slEh2Nd6LXQWCiz9UMDN85OHkuXSgNyuSpna6W0+/qNv3SQLrcwTKTNj/ZSLTj5lZIyQ7l11xW36H+uyx4D8rYOpHw8HxrGXnh5hyWhOa4GCGzgSgFZlU8= + on_success: change + on_failure: always From ee1e913291657dc2c032269c28081bb233e75a36 Mon Sep 17 00:00:00 2001 From: Shay Nehmad Date: Sun, 27 Oct 2019 13:48:09 +0200 Subject: [PATCH 12/37] using python -m for tests - and trying still to make slack integ work --- .travis.yml | 9 +++++---- monkey/monkey_island/cc/server_config.json | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index dccf11dff..3ab2b95a4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,17 +6,18 @@ python: install: - pip install -r monkey/monkey_island/requirements.txt - pip install flake8 pytest dlint +- pip install -r monkey/infection_monkey/requirements-linux.txt before_script: -- cd monkey - flake8 . --count --select=E901,E999,F821,F822,F823 --show-source --statistics - flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics script: -- pytest --capture=sys +- cd monkey # This is our source dir +- python -m pytest --capture=sys # Have to do this to add monkey to sys.path. notifications: on_success: change on_failure: always slack: rooms: - - secure: wFddByqGGfwpjuisZhXQGAI7Y/7yZ+ON58R19D2ff+p1lT26BIdE+gSWQFWTbSNcyjVhAMCkbKgRblL2o0WcuiCyYjlcIoT/fEMuypxNTnlC1FtHlmEO/1JAyDVskzRWvu7q98szcDP+yKjUZSjUrLMnzUYtdB7hhAp8iRvEUTgtKQi27kmgBX9lLqAf93WO1Ocp2+fmDkNmegx2bBa9PQS4FYOtqN7DYZ0cHM7wLffyHZmSXZkwCcq+u7mSONrfQZprCvzQu9kntx/zEnjTuNHUZ8L0SNu035Yg2MtxnKDY1GPSox5ax5rZJID4aN+f7vDkIgIskMwVcjFoMS4bvp8xH1liWleR/VdOYhTP1bx5GcLvkUFC/xAwW730AZnU9Ihn3iSLK8iiowf7UMOYLB371KDlZWj2gwRvccRb7VwismLzcYt/So/5/xDa4IgDNNUu/fb9J+TPc+3jKPt3E6KSHseBcyk2ov7iC14pUz/AWEcWga2s5cRiWqBibUuiJUXZf0zExyEnj9dic5jF/UW8EVpDygy5TaAVq9VD30zslzPcIDbl1slEh2Nd6LXQWCiz9UMDN85OHkuXSgNyuSpna6W0+/qNv3SQLrcwTKTNj/ZSLTj5lZIyQ7l11xW36H+uyx4D8rYOpHw8HxrGXnh5hyWhOa4GCGzgSgFZlU8= - on_success: change + - secure: wFddByqGGfwpjuisZhXQGAI7Y/7yZ+ON58R19D2ff+p1lT26BIdE+gSWQFWTbSNcyjVhAMCkbKgRblL2o0WcuiCyYjlcIoT/fEMuypxNTnlC1FtHlmEO/1JAyDVskzRWvu7q98szcDP+yKjUZSjUrLMnzUYtdB7hhAp8iRvEUTgtKQi27kmgBX9lLqAf93WO1Ocp2+fmDkNmegx2bBa9PQS4FYOtqN7DYZ0cHM7wLffyHZmSXZkwCcq+u7mSONrfQZprCvzQu9kntx/zEnjTuNHUZ8L0SNu035Yg2MtxnKDY1GPSox5ax5rZJID4aN+f7vDkIgIskMwVcjFoMS4bvp8xH1liWleR/VdOYhTP1bx5GcLvkUFC/xAwW730AZnU9Ihn3iSLK8iiowf7UMOYLB371KDlZWj2gwRvccRb7VwismLzcYt/So/5/xDa4IgDNNUu/fb9J+TPc+3jKPt3E6KSHseBcyk2ov7iC14pUz/AWEcWga2s5cRiWqBibUuiJUXZf0zExyEnj9dic5jF/UW8EVpDygy5TaAVq9VD30zslzPcIDbl1slEh2Nd6LXQWCiz9UMDN85OHkuXSgNyuSpna6W0+/qNv3SQLrcwTKTNj/ZSLTj5lZIyQ7l11xW36H+uyx4D8rYOpHw8HxrGXnh5hyWhOa4GCGzgSgFZlU8= + on_success: always on_failure: always diff --git a/monkey/monkey_island/cc/server_config.json b/monkey/monkey_island/cc/server_config.json index 420f1b303..7bf106194 100644 --- a/monkey/monkey_island/cc/server_config.json +++ b/monkey/monkey_island/cc/server_config.json @@ -1,4 +1,4 @@ { - "server_config": "standard", + "server_config": "testing", "deployment": "develop" } From 43048329d030c73c6ecfb41f507f0f853861e157 Mon Sep 17 00:00:00 2001 From: Shay Nehmad Date: Sun, 27 Oct 2019 13:50:13 +0200 Subject: [PATCH 13/37] Fix requirements path --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 3ab2b95a4..501814e6f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,7 +6,7 @@ python: install: - pip install -r monkey/monkey_island/requirements.txt - pip install flake8 pytest dlint -- pip install -r monkey/infection_monkey/requirements-linux.txt +- pip install -r monkey/infection_monkey/requirements_linux.txt before_script: - flake8 . --count --select=E901,E999,F821,F822,F823 --show-source --statistics - flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics From ceca7ce1277407f90ee1fe39e3c15bd2d44bb5a5 Mon Sep 17 00:00:00 2001 From: Shay Nehmad Date: Sun, 27 Oct 2019 17:55:24 +0200 Subject: [PATCH 14/37] Adding pytest to requirements and pytest.ini file for logging purposes --- monkey/monkey_island/requirements.txt | 1 + monkey/pytest.ini | 6 ++++++ 2 files changed, 7 insertions(+) create mode 100644 monkey/pytest.ini diff --git a/monkey/monkey_island/requirements.txt b/monkey/monkey_island/requirements.txt index 49c1e37a5..77ff9a620 100644 --- a/monkey/monkey_island/requirements.txt +++ b/monkey/monkey_island/requirements.txt @@ -1,3 +1,4 @@ +pytest bson python-dateutil tornado diff --git a/monkey/pytest.ini b/monkey/pytest.ini new file mode 100644 index 000000000..3d355a4ac --- /dev/null +++ b/monkey/pytest.ini @@ -0,0 +1,6 @@ +[pytest] +log_cli = 1 +log_cli_level = DEBUG +log_cli_format = %(asctime)s [%(levelname)s] %(module)s.%(funcName)s.%(lineno)d: %(message)s +log_cli_date_format=%H:%M:%S +addopts = -v --capture=sys From 7b153d29b25d4437c097bf9657f3ed19686c6f89 Mon Sep 17 00:00:00 2001 From: Shay Nehmad Date: Sun, 27 Oct 2019 17:55:34 +0200 Subject: [PATCH 15/37] Fix segmentation utils test --- monkey/common/network/segmentation_utils_test.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/monkey/common/network/segmentation_utils_test.py b/monkey/common/network/segmentation_utils_test.py index 56a560922..221f1d9bf 100644 --- a/monkey/common/network/segmentation_utils_test.py +++ b/monkey/common/network/segmentation_utils_test.py @@ -11,20 +11,20 @@ class TestSegmentationUtils(IslandTestCase): # IP not in both self.assertIsNone(get_ip_in_src_and_not_in_dst( - [text_type("3.3.3.3"), text_type("4.4.4.4")], source, target + ["3.3.3.3", "4.4.4.4"], source, target )) # IP not in source, in target self.assertIsNone(get_ip_in_src_and_not_in_dst( - [text_type("2.2.2.2")], source, target + ["2.2.2.2"], source, target )) # IP in source, not in target self.assertIsNotNone(get_ip_in_src_and_not_in_dst( - [text_type("8.8.8.8"), text_type("1.1.1.1")], source, target + ["8.8.8.8", "1.1.1.1"], source, target )) # IP in both subnets self.assertIsNone(get_ip_in_src_and_not_in_dst( - [text_type("8.8.8.8"), text_type("1.1.1.1")], source, source + ["8.8.8.8", "1.1.1.1"], source, source )) From f2297de6610b50029bd539d913e5aabad812649d Mon Sep 17 00:00:00 2001 From: Shay Nehmad Date: Sun, 27 Oct 2019 17:55:51 +0200 Subject: [PATCH 16/37] Fix TestMonkey to pytest --- monkey/monkey_island/cc/models/monkey.py | 3 +- monkey/monkey_island/cc/models/test_monkey.py | 38 ++++++++++++++----- 2 files changed, 30 insertions(+), 11 deletions(-) diff --git a/monkey/monkey_island/cc/models/monkey.py b/monkey/monkey_island/cc/models/monkey.py index daeb9ea5b..1a0e872f6 100644 --- a/monkey/monkey_island/cc/models/monkey.py +++ b/monkey/monkey_island/cc/models/monkey.py @@ -123,7 +123,8 @@ class Monkey(Document): self.save() -# Can't make following methods static under Monkey class due to ring bug +# TODO Can't make following methods static under Monkey class due to ring bug. When ring will support static methods, we +# should move to static methods in the Monkey class. @ring.lru( expire=1 # data has TTL of 1 second. This is useful for rapid calls for report generation. ) diff --git a/monkey/monkey_island/cc/models/test_monkey.py b/monkey/monkey_island/cc/models/test_monkey.py index fb9b329b1..472c5770b 100644 --- a/monkey/monkey_island/cc/models/test_monkey.py +++ b/monkey/monkey_island/cc/models/test_monkey.py @@ -1,11 +1,15 @@ import uuid +import logging from time import sleep -from .monkey import Monkey -from monkey_island.cc.models.monkey import MonkeyNotFoundError, is_monkey, get_monkey_label_by_id +import pytest + +from monkey_island.cc.models.monkey import Monkey, MonkeyNotFoundError, is_monkey, get_monkey_label_by_id from monkey_island.cc.testing.IslandTestCase import IslandTestCase from .monkey_ttl import MonkeyTtl +logger = logging.getLogger(__name__) + class TestMonkey(IslandTestCase): """ @@ -32,7 +36,7 @@ class TestMonkey(IslandTestCase): # MIA stands for Missing In Action mia_monkey_ttl = MonkeyTtl.create_ttl_expire_in(30) mia_monkey_ttl.save() - mia_monkey = Monkey(guid=str(uuid.uuid4()), dead=False, ttl_ref=mia_monkey_ttl) + mia_monkey = Monkey(guid=str(uuid.uuid4()), dead=False, ttl_ref=mia_monkey_ttl.id) mia_monkey.save() # Emulate timeout - ttl is manually deleted here, since we're using mongomock and not a real mongo instance. sleep(1) @@ -70,8 +74,10 @@ class TestMonkey(IslandTestCase): # Act + assert # Find the existing one self.assertIsNotNone(Monkey.get_single_monkey_by_id(a_monkey.id)) + # Raise on non-existent monkey - self.assertRaises(MonkeyNotFoundError, Monkey.get_single_monkey_by_id, "abcdefabcdefabcdefabcdef") + with pytest.raises(MonkeyNotFoundError) as e_info: + _ = Monkey.get_single_monkey_by_id("abcdefabcdefabcdefabcdef") def test_get_os(self): self.fail_if_not_testing_env() @@ -125,29 +131,41 @@ class TestMonkey(IslandTestCase): ip_addresses=[ip_example]) linux_monkey.save() + logger.debug(id(get_monkey_label_by_id)) + cache_info_before_query = get_monkey_label_by_id.storage.backend.cache_info() self.assertEqual(cache_info_before_query.hits, 0) + self.assertEqual(cache_info_before_query.misses, 0) # not cached label = get_monkey_label_by_id(linux_monkey.id) + cache_info_after_query_1 = get_monkey_label_by_id.storage.backend.cache_info() + self.assertEqual(cache_info_after_query_1.hits, 0) + self.assertEqual(cache_info_after_query_1.misses, 1) + logger.info("1) ID: {} label: {}".format(linux_monkey.id, label)) self.assertIsNotNone(label) self.assertIn(hostname_example, label) self.assertIn(ip_example, label) # should be cached - _ = get_monkey_label_by_id(linux_monkey.id) - cache_info_after_query = get_monkey_label_by_id.storage.backend.cache_info() - self.assertEqual(cache_info_after_query.hits, 1) + label = get_monkey_label_by_id(linux_monkey.id) + logger.info("2) ID: {} label: {}".format(linux_monkey.id, label)) + cache_info_after_query_2 = get_monkey_label_by_id.storage.backend.cache_info() + self.assertEqual(cache_info_after_query_2.hits, 1) + self.assertEqual(cache_info_after_query_2.misses, 1) + # set hostname deletes the id from the cache. linux_monkey.set_hostname("Another hostname") # should be a miss label = get_monkey_label_by_id(linux_monkey.id) - cache_info_after_second_query = get_monkey_label_by_id.storage.backend.cache_info() + logger.info("3) ID: {} label: {}".format(linux_monkey.id, label)) + cache_info_after_query_3 = get_monkey_label_by_id.storage.backend.cache_info() + logger.debug("Cache info: {}".format(str(cache_info_after_query_3))) # still 1 hit only - self.assertEqual(cache_info_after_second_query.hits, 1) - self.assertEqual(cache_info_after_second_query.misses, 2) + self.assertEqual(cache_info_after_query_3.hits, 1) + self.assertEqual(cache_info_after_query_3.misses, 2) def test_is_monkey(self): self.fail_if_not_testing_env() From ab348bb12a5330ffc1d967e5717be38a62b1ce3b Mon Sep 17 00:00:00 2001 From: Shay Nehmad Date: Sun, 27 Oct 2019 17:56:12 +0200 Subject: [PATCH 17/37] Fix zero_trust_service tests (comparison order problems) --- .../reporting/test_zero_trust_service.py | 315 ++++++++++-------- 1 file changed, 170 insertions(+), 145 deletions(-) diff --git a/monkey/monkey_island/cc/services/reporting/test_zero_trust_service.py b/monkey/monkey_island/cc/services/reporting/test_zero_trust_service.py index 06a730e05..d77e67aad 100644 --- a/monkey/monkey_island/cc/services/reporting/test_zero_trust_service.py +++ b/monkey/monkey_island/cc/services/reporting/test_zero_trust_service.py @@ -1,9 +1,151 @@ -from monkey_island.cc.services.reporting.zero_trust_service import ZeroTrustService - from common.data.zero_trust_consts import * from monkey_island.cc.models.zero_trust.finding import Finding +from monkey_island.cc.services.reporting.zero_trust_service import ZeroTrustService from monkey_island.cc.testing.IslandTestCase import IslandTestCase +EXPECTED_DICT = { + AUTOMATION_ORCHESTRATION: [], + DATA: [ + { + "principle": PRINCIPLES[PRINCIPLE_DATA_TRANSIT], + "status": STATUS_FAILED, + "tests": [ + { + "status": STATUS_FAILED, + "test": TESTS_MAP[TEST_DATA_ENDPOINT_HTTP][TEST_EXPLANATION_KEY] + }, + { + "status": STATUS_UNEXECUTED, + "test": TESTS_MAP[TEST_DATA_ENDPOINT_ELASTIC][TEST_EXPLANATION_KEY] + }, + ] + } + ], + DEVICES: [ + { + "principle": PRINCIPLES[PRINCIPLE_ENDPOINT_SECURITY], + "status": STATUS_FAILED, + "tests": [ + { + "status": STATUS_UNEXECUTED, + "test": TESTS_MAP[TEST_MACHINE_EXPLOITED][TEST_EXPLANATION_KEY] + }, + { + "status": STATUS_FAILED, + "test": TESTS_MAP[TEST_ENDPOINT_SECURITY_EXISTS][TEST_EXPLANATION_KEY] + }, + ] + } + ], + NETWORKS: [ + { + "principle": PRINCIPLES[PRINCIPLE_SEGMENTATION], + "status": STATUS_UNEXECUTED, + "tests": [ + { + "status": STATUS_UNEXECUTED, + "test": TESTS_MAP[TEST_SEGMENTATION][TEST_EXPLANATION_KEY] + } + ] + }, + { + "principle": PRINCIPLES[PRINCIPLE_USER_BEHAVIOUR], + "status": STATUS_VERIFY, + "tests": [ + { + "status": STATUS_VERIFY, + "test": TESTS_MAP[TEST_SCHEDULED_EXECUTION][TEST_EXPLANATION_KEY] + } + ] + }, + { + "principle": PRINCIPLES[PRINCIPLE_USERS_MAC_POLICIES], + "status": STATUS_UNEXECUTED, + "tests": [ + { + "status": STATUS_UNEXECUTED, + "test": TESTS_MAP[TEST_COMMUNICATE_AS_NEW_USER][TEST_EXPLANATION_KEY] + } + ] + }, + { + "principle": PRINCIPLES[PRINCIPLE_ANALYZE_NETWORK_TRAFFIC], + "status": STATUS_UNEXECUTED, + "tests": [ + { + "status": STATUS_UNEXECUTED, + "test": TESTS_MAP[TEST_MALICIOUS_ACTIVITY_TIMELINE][TEST_EXPLANATION_KEY] + } + ] + }, + { + "principle": PRINCIPLES[PRINCIPLE_RESTRICTIVE_NETWORK_POLICIES], + "status": STATUS_UNEXECUTED, + "tests": [ + { + "status": STATUS_UNEXECUTED, + "test": TESTS_MAP[TEST_TUNNELING][TEST_EXPLANATION_KEY] + } + ] + }, + ], + PEOPLE: [ + { + "principle": PRINCIPLES[PRINCIPLE_USER_BEHAVIOUR], + "status": STATUS_VERIFY, + "tests": [ + { + "status": STATUS_VERIFY, + "test": TESTS_MAP[TEST_SCHEDULED_EXECUTION][TEST_EXPLANATION_KEY] + } + ] + }, + { + "principle": PRINCIPLES[PRINCIPLE_USERS_MAC_POLICIES], + "status": STATUS_UNEXECUTED, + "tests": [ + { + "status": STATUS_UNEXECUTED, + "test": TESTS_MAP[TEST_COMMUNICATE_AS_NEW_USER][TEST_EXPLANATION_KEY] + } + ] + } + ], + VISIBILITY_ANALYTICS: [ + { + "principle": PRINCIPLES[PRINCIPLE_USERS_MAC_POLICIES], + "status": STATUS_UNEXECUTED, + "tests": [ + { + "status": STATUS_UNEXECUTED, + "test": TESTS_MAP[TEST_COMMUNICATE_AS_NEW_USER][TEST_EXPLANATION_KEY] + } + ] + }, + { + "principle": PRINCIPLES[PRINCIPLE_ANALYZE_NETWORK_TRAFFIC], + "status": STATUS_UNEXECUTED, + "tests": [ + { + "status": STATUS_UNEXECUTED, + "test": TESTS_MAP[TEST_MALICIOUS_ACTIVITY_TIMELINE][TEST_EXPLANATION_KEY] + } + ] + }, + { + "principle": PRINCIPLES[PRINCIPLE_RESTRICTIVE_NETWORK_POLICIES], + "status": STATUS_UNEXECUTED, + "tests": [ + { + "status": STATUS_UNEXECUTED, + "test": TESTS_MAP[TEST_TUNNELING][TEST_EXPLANATION_KEY] + } + ] + }, + ], + WORKLOADS: [] +} + def save_example_findings(): # arrange @@ -106,151 +248,24 @@ class TestZeroTrustService(IslandTestCase): save_example_findings() - expected = { - AUTOMATION_ORCHESTRATION: [], - DATA: [ - { - "principle": PRINCIPLES[PRINCIPLE_DATA_TRANSIT], - "status": STATUS_FAILED, - "tests": [ - { - "status": STATUS_FAILED, - "test": TESTS_MAP[TEST_DATA_ENDPOINT_HTTP][TEST_EXPLANATION_KEY] - }, - { - "status": STATUS_UNEXECUTED, - "test": TESTS_MAP[TEST_DATA_ENDPOINT_ELASTIC][TEST_EXPLANATION_KEY] - }, - ] - } - ], - DEVICES: [ - { - "principle": PRINCIPLES[PRINCIPLE_ENDPOINT_SECURITY], - "status": STATUS_FAILED, - "tests": [ - { - "status": STATUS_UNEXECUTED, - "test": TESTS_MAP[TEST_MACHINE_EXPLOITED][TEST_EXPLANATION_KEY] - }, - { - "status": STATUS_FAILED, - "test": TESTS_MAP[TEST_ENDPOINT_SECURITY_EXISTS][TEST_EXPLANATION_KEY] - }, - ] - } - ], - NETWORKS: [ - { - "principle": PRINCIPLES[PRINCIPLE_SEGMENTATION], - "status": STATUS_UNEXECUTED, - "tests": [ - { - "status": STATUS_UNEXECUTED, - "test": TESTS_MAP[TEST_SEGMENTATION][TEST_EXPLANATION_KEY] - } - ] - }, - { - "principle": PRINCIPLES[PRINCIPLE_USER_BEHAVIOUR], - "status": STATUS_VERIFY, - "tests": [ - { - "status": STATUS_VERIFY, - "test": TESTS_MAP[TEST_SCHEDULED_EXECUTION][TEST_EXPLANATION_KEY] - } - ] - }, - { - "principle": PRINCIPLES[PRINCIPLE_USERS_MAC_POLICIES], - "status": STATUS_UNEXECUTED, - "tests": [ - { - "status": STATUS_UNEXECUTED, - "test": TESTS_MAP[TEST_COMMUNICATE_AS_NEW_USER][TEST_EXPLANATION_KEY] - } - ] - }, - { - "principle": PRINCIPLES[PRINCIPLE_ANALYZE_NETWORK_TRAFFIC], - "status": STATUS_UNEXECUTED, - "tests": [ - { - "status": STATUS_UNEXECUTED, - "test": TESTS_MAP[TEST_MALICIOUS_ACTIVITY_TIMELINE][TEST_EXPLANATION_KEY] - } - ] - }, - { - "principle": PRINCIPLES[PRINCIPLE_RESTRICTIVE_NETWORK_POLICIES], - "status": STATUS_UNEXECUTED, - "tests": [ - { - "status": STATUS_UNEXECUTED, - "test": TESTS_MAP[TEST_TUNNELING][TEST_EXPLANATION_KEY] - } - ] - }, - ], - PEOPLE: [ - { - "principle": PRINCIPLES[PRINCIPLE_USER_BEHAVIOUR], - "status": STATUS_VERIFY, - "tests": [ - { - "status": STATUS_VERIFY, - "test": TESTS_MAP[TEST_SCHEDULED_EXECUTION][TEST_EXPLANATION_KEY] - } - ] - }, - { - "principle": PRINCIPLES[PRINCIPLE_USERS_MAC_POLICIES], - "status": STATUS_UNEXECUTED, - "tests": [ - { - "status": STATUS_UNEXECUTED, - "test": TESTS_MAP[TEST_COMMUNICATE_AS_NEW_USER][TEST_EXPLANATION_KEY] - } - ] - } - ], - VISIBILITY_ANALYTICS: [ - { - "principle": PRINCIPLES[PRINCIPLE_USERS_MAC_POLICIES], - "status": STATUS_UNEXECUTED, - "tests": [ - { - "status": STATUS_UNEXECUTED, - "test": TESTS_MAP[TEST_COMMUNICATE_AS_NEW_USER][TEST_EXPLANATION_KEY] - } - ] - }, - { - "principle": PRINCIPLES[PRINCIPLE_ANALYZE_NETWORK_TRAFFIC], - "status": STATUS_UNEXECUTED, - "tests": [ - { - "status": STATUS_UNEXECUTED, - "test": TESTS_MAP[TEST_MALICIOUS_ACTIVITY_TIMELINE][TEST_EXPLANATION_KEY] - } - ] - }, - { - "principle": PRINCIPLES[PRINCIPLE_RESTRICTIVE_NETWORK_POLICIES], - "status": STATUS_UNEXECUTED, - "tests": [ - { - "status": STATUS_UNEXECUTED, - "test": TESTS_MAP[TEST_TUNNELING][TEST_EXPLANATION_KEY] - } - ] - }, - ], - WORKLOADS: [] - } + expected = dict(EXPECTED_DICT) # new mutable result = ZeroTrustService.get_principles_status() - self.assertEqual(result, expected) + # Compare expected and result, no order: + for pillar_name, pillar_principles_status_result in result.items(): + for index, pillar_principle_status_expected in enumerate(expected.get(pillar_name)): + correct_one = None + for pillar_principle_status_result in pillar_principles_status_result: + if pillar_principle_status_result["principle"] == pillar_principle_status_expected["principle"]: + correct_one = pillar_principle_status_result + break + + # Compare tests no order + self.assertTrue(compare_lists_no_order(correct_one["tests"], pillar_principle_status_expected["tests"])) + # Compare the rest + del pillar_principle_status_expected["tests"] + del correct_one["tests"] + self.assertEqual(sorted(correct_one), sorted(pillar_principle_status_expected)) def test_get_pillars_to_statuses(self): self.fail_if_not_testing_env() @@ -283,3 +298,13 @@ class TestZeroTrustService(IslandTestCase): } self.assertEqual(ZeroTrustService.get_pillars_to_statuses(), expected) + + +def compare_lists_no_order(s, t): + t = list(t) # make a mutable copy + try: + for elem in s: + t.remove(elem) + except ValueError: + return False + return not t From 7c23065efafd10219e2dd9374f216b307d2e23e7 Mon Sep 17 00:00:00 2001 From: Shay Nehmad Date: Sun, 27 Oct 2019 18:31:44 +0200 Subject: [PATCH 18/37] Trying to get slack notifications to work. --- .travis.yml | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 501814e6f..b05dfbe94 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,12 +12,14 @@ before_script: - flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics script: - cd monkey # This is our source dir -- python -m pytest --capture=sys # Have to do this to add monkey to sys.path. +- python -m pytest # Have to use `python -m pytest` instead of `pytest` to add "{$builddir}/monkey/monkey" to sys.path. notifications: - on_success: change - on_failure: always slack: rooms: - - secure: wFddByqGGfwpjuisZhXQGAI7Y/7yZ+ON58R19D2ff+p1lT26BIdE+gSWQFWTbSNcyjVhAMCkbKgRblL2o0WcuiCyYjlcIoT/fEMuypxNTnlC1FtHlmEO/1JAyDVskzRWvu7q98szcDP+yKjUZSjUrLMnzUYtdB7hhAp8iRvEUTgtKQi27kmgBX9lLqAf93WO1Ocp2+fmDkNmegx2bBa9PQS4FYOtqN7DYZ0cHM7wLffyHZmSXZkwCcq+u7mSONrfQZprCvzQu9kntx/zEnjTuNHUZ8L0SNu035Yg2MtxnKDY1GPSox5ax5rZJID4aN+f7vDkIgIskMwVcjFoMS4bvp8xH1liWleR/VdOYhTP1bx5GcLvkUFC/xAwW730AZnU9Ihn3iSLK8iiowf7UMOYLB371KDlZWj2gwRvccRb7VwismLzcYt/So/5/xDa4IgDNNUu/fb9J+TPc+3jKPt3E6KSHseBcyk2ov7iC14pUz/AWEcWga2s5cRiWqBibUuiJUXZf0zExyEnj9dic5jF/UW8EVpDygy5TaAVq9VD30zslzPcIDbl1slEh2Nd6LXQWCiz9UMDN85OHkuXSgNyuSpna6W0+/qNv3SQLrcwTKTNj/ZSLTj5lZIyQ7l11xW36H+uyx4D8rYOpHw8HxrGXnh5hyWhOa4GCGzgSgFZlU8= + - infectionmonkey:QaXbsx4g7tHFJW0lhtiBmoAg#ci + - infectionmonkey:QaXbsx4g7tHFJW0lhtiBmoAg#github on_success: always on_failure: always + email: + on_success: change + on_failure: always From 681c0396c4a24fa2a16798b5de4abf2c797a5f26 Mon Sep 17 00:00:00 2001 From: Shay Nehmad Date: Sun, 27 Oct 2019 18:35:38 +0200 Subject: [PATCH 19/37] Added travis badges to readme --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 67b5b2e8b..b10ebbf8b 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,11 @@ Welcome to the Infection Monkey! The Infection Monkey is an open source security tool for testing a data center's resiliency to perimeter breaches and internal server infection. The Monkey uses various methods to self propagate across a data center and reports success to a centralized Monkey Island server. +#### Build status +* Development branch [![Build Status](https://travis-ci.com/guardicore/monkey.svg?branch=develop)](https://travis-ci.com/guardicore/monkey) +* Master [![Build Status](https://travis-ci.com/guardicore/monkey.svg?branch=master)](https://travis-ci.com/guardicore/monkey) + + From 984a280b66dc3a57956dc701c27ea42add6e832e Mon Sep 17 00:00:00 2001 From: Shay Nehmad Date: Sun, 27 Oct 2019 18:39:54 +0200 Subject: [PATCH 20/37] Changed bullets to table --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b10ebbf8b..070d6243d 100644 --- a/README.md +++ b/README.md @@ -9,8 +9,10 @@ Welcome to the Infection Monkey! The Infection Monkey is an open source security tool for testing a data center's resiliency to perimeter breaches and internal server infection. The Monkey uses various methods to self propagate across a data center and reports success to a centralized Monkey Island server. #### Build status -* Development branch [![Build Status](https://travis-ci.com/guardicore/monkey.svg?branch=develop)](https://travis-ci.com/guardicore/monkey) -* Master [![Build Status](https://travis-ci.com/guardicore/monkey.svg?branch=master)](https://travis-ci.com/guardicore/monkey) +| Branch | Status | +| ------ | :----: | +| Develop | [![Build Status](https://travis-ci.com/guardicore/monkey.svg?branch=develop)](https://travis-ci.com/guardicore/monkey) | +| Master | [![Build Status](https://travis-ci.com/guardicore/monkey.svg?branch=master)](https://travis-ci.com/guardicore/monkey) | From bb536755bf0034ee53f7faf2ebd239cdffae1e37 Mon Sep 17 00:00:00 2001 From: Shay Nehmad Date: Sun, 27 Oct 2019 18:44:38 +0200 Subject: [PATCH 21/37] reordered readme with badges --- README.md | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 070d6243d..462383969 100644 --- a/README.md +++ b/README.md @@ -1,19 +1,14 @@ Infection Monkey ==================== +[![Build Status](https://travis-ci.com/guardicore/monkey.svg?branch=develop)](https://travis-ci.com/guardicore/monkey) -### Data center Security Testing Tool +## Data center Security Testing Tool ------------------------ Welcome to the Infection Monkey! The Infection Monkey is an open source security tool for testing a data center's resiliency to perimeter breaches and internal server infection. The Monkey uses various methods to self propagate across a data center and reports success to a centralized Monkey Island server. -#### Build status -| Branch | Status | -| ------ | :----: | -| Develop | [![Build Status](https://travis-ci.com/guardicore/monkey.svg?branch=develop)](https://travis-ci.com/guardicore/monkey) | -| Master | [![Build Status](https://travis-ci.com/guardicore/monkey.svg?branch=master)](https://travis-ci.com/guardicore/monkey) | - @@ -57,6 +52,12 @@ If you only want to build the monkey from source, see [Setup](https://github.com and follow the instructions at the readme files under [infection_monkey](infection_monkey) and [monkey_island](monkey_island). +### Build status +| Branch | Status | +| ------ | :----: | +| Develop | [![Build Status](https://travis-ci.com/guardicore/monkey.svg?branch=develop)](https://travis-ci.com/guardicore/monkey) | +| Master | [![Build Status](https://travis-ci.com/guardicore/monkey.svg?branch=master)](https://travis-ci.com/guardicore/monkey) | + License ======= Copyright (c) Guardicore Ltd From 59a779822bde75c58eaf46ebb35717b29dfff8d9 Mon Sep 17 00:00:00 2001 From: Shay Nehmad Date: Mon, 28 Oct 2019 09:31:00 +0200 Subject: [PATCH 22/37] Added some badges (since we added the build badge and I don't want it to look alone) --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 462383969..2d7490bfe 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,9 @@ Infection Monkey ==================== [![Build Status](https://travis-ci.com/guardicore/monkey.svg?branch=develop)](https://travis-ci.com/guardicore/monkey) +[![GitHub release (latest by date)](https://img.shields.io/github/v/release/guardicore/monkey)](https://github.com/guardicore/monkey/releases) +![GitHub stars](https://img.shields.io/github/stars/guardicore/monkey) +![GitHub commit activity](https://img.shields.io/github/commit-activity/m/guardicore/monkey) ## Data center Security Testing Tool ------------------------ From 827c4942d910bca8ea5f8406440457f77ff44ce7 Mon Sep 17 00:00:00 2001 From: Shay Nehmad Date: Mon, 28 Oct 2019 13:37:18 +0200 Subject: [PATCH 23/37] Added script which changes the server_config to testing in travis so the default will be standard (for running) --- .travis.yml | 3 +- monkey/monkey_island/cc/server_config.json | 4 +- monkey/monkey_island/cc/set_server_config.py | 46 ++++++++++++++++++++ 3 files changed, 50 insertions(+), 3 deletions(-) create mode 100644 monkey/monkey_island/cc/set_server_config.py diff --git a/.travis.yml b/.travis.yml index b05dfbe94..06511e74b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,11 +5,12 @@ python: - 3.7 install: - pip install -r monkey/monkey_island/requirements.txt -- pip install flake8 pytest dlint +- pip install flake8 pytest dlint pylint - pip install -r monkey/infection_monkey/requirements_linux.txt before_script: - flake8 . --count --select=E901,E999,F821,F822,F823 --show-source --statistics - flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics +- monkey/monkey_island/cc/set_server_config.py testing script: - cd monkey # This is our source dir - python -m pytest # Have to use `python -m pytest` instead of `pytest` to add "{$builddir}/monkey/monkey" to sys.path. diff --git a/monkey/monkey_island/cc/server_config.json b/monkey/monkey_island/cc/server_config.json index 7bf106194..0b28d0b74 100644 --- a/monkey/monkey_island/cc/server_config.json +++ b/monkey/monkey_island/cc/server_config.json @@ -1,4 +1,4 @@ { - "server_config": "testing", - "deployment": "develop" + "server_config": "standard", + "deployment": "develop" } diff --git a/monkey/monkey_island/cc/set_server_config.py b/monkey/monkey_island/cc/set_server_config.py new file mode 100644 index 000000000..fc20747c9 --- /dev/null +++ b/monkey/monkey_island/cc/set_server_config.py @@ -0,0 +1,46 @@ +import argparse +import json +import logging +from pathlib import Path + +SERVER_CONFIG = "server_config" + +logger = logging.getLogger(__name__) +logger.addHandler(logging.StreamHandler()) +logger.setLevel(logging.DEBUG) + + +def main(): + args = parse_args() + file_path = get_config_file_path(args) + + # Read config + with open(file_path) as config_file: + config_data = json.load(config_file) + + # Edit the config + config_data[SERVER_CONFIG] = args.server_config + + # Write new config + logger.info("Writing the following config: {}".format(json.dumps(config_data, indent=4))) + with open(file_path, "w") as config_file: + json.dump(config_data, config_file, indent=4) + config_file.write("\n") # Have to add newline at end of file, since json.dump does not. + + +def get_config_file_path(args): + file_path = Path(__file__).parent.joinpath(args.file_name) + logger.info("Config file path: {}".format(file_path)) + return file_path + + +def parse_args(): + parser = argparse.ArgumentParser() + parser.add_argument("server_config", choices=["standard", "testing", "password"]) + parser.add_argument("-f", "--file_name", required=False, default="server_config.json") + args = parser.parse_args() + return args + + +if __name__ == '__main__': + main() From f8cf78a2928d1d7d078418053564f3c2eb932205 Mon Sep 17 00:00:00 2001 From: Shay Nehmad Date: Mon, 28 Oct 2019 13:40:22 +0200 Subject: [PATCH 24/37] Forgot python as command for running the script --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 06511e74b..608c8924f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,7 +10,7 @@ install: before_script: - flake8 . --count --select=E901,E999,F821,F822,F823 --show-source --statistics - flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics -- monkey/monkey_island/cc/set_server_config.py testing +- python monkey/monkey_island/cc/set_server_config.py testing script: - cd monkey # This is our source dir - python -m pytest # Have to use `python -m pytest` instead of `pytest` to add "{$builddir}/monkey/monkey" to sys.path. From 97baaabdd7086d324aaaca22eeaa0426d70ef551 Mon Sep 17 00:00:00 2001 From: Shay Nehmad Date: Mon, 28 Oct 2019 13:54:07 +0200 Subject: [PATCH 25/37] Remove pylint from travis installation + added some doc + fixed notifications for travis --- .travis.yml | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/.travis.yml b/.travis.yml index 608c8924f..d5103b989 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,25 +1,28 @@ +# Infection Monkey travis.yml. See Travis documentation for information about this file structure. + group: travis_latest language: python cache: pip python: - 3.7 install: -- pip install -r monkey/monkey_island/requirements.txt -- pip install flake8 pytest dlint pylint -- pip install -r monkey/infection_monkey/requirements_linux.txt +- pip install -r monkey/monkey_island/requirements.txt # for unit tests +- pip install flake8 pytest dlint # for next stages +- pip install -r monkey/infection_monkey/requirements_linux.txt # for unit tests before_script: -- flake8 . --count --select=E901,E999,F821,F822,F823 --show-source --statistics -- flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics -- python monkey/monkey_island/cc/set_server_config.py testing +- flake8 . --count --select=E901,E999,F821,F822,F823 --show-source --statistics # Check syntax errors +- flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics # warn about linter issues. --exit-zero + # means this stage will not fail the build. This is (hopefully) a temporary measure until all warnings are suppressed. +- python monkey/monkey_island/cc/set_server_config.py testing # Set the server config to `testing`, for the UTs to use + # mongomaock and pass. script: - cd monkey # This is our source dir - python -m pytest # Have to use `python -m pytest` instead of `pytest` to add "{$builddir}/monkey/monkey" to sys.path. notifications: - slack: + slack: # Notify to slack rooms: - - infectionmonkey:QaXbsx4g7tHFJW0lhtiBmoAg#ci - - infectionmonkey:QaXbsx4g7tHFJW0lhtiBmoAg#github - on_success: always + - infectionmonkey:QaXbsx4g7tHFJW0lhtiBmoAg#ci # room: #ci + on_success: change on_failure: always email: on_success: change From 2a34ec4995fbc5739694e0c74dd7f2e025cbead7 Mon Sep 17 00:00:00 2001 From: VakarisZ Date: Mon, 28 Oct 2019 15:03:41 +0200 Subject: [PATCH 26/37] Mimikatz fix and small sambacry fix --- monkey/infection_monkey/exploit/sambacry.py | 2 +- monkey/infection_monkey/system_info/mimikatz_collector.py | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/monkey/infection_monkey/exploit/sambacry.py b/monkey/infection_monkey/exploit/sambacry.py index e48a21616..e3825eac9 100644 --- a/monkey/infection_monkey/exploit/sambacry.py +++ b/monkey/infection_monkey/exploit/sambacry.py @@ -395,7 +395,7 @@ class SambaCryExploiter(HostExploiter): if fileName != '': smb2Create['Buffer'] = fileName.encode('utf-16le') else: - smb2Create['Buffer'] = '\x00' + smb2Create['Buffer'] = b'\x00' if createContexts is not None: smb2Create['Buffer'] += createContexts diff --git a/monkey/infection_monkey/system_info/mimikatz_collector.py b/monkey/infection_monkey/system_info/mimikatz_collector.py index f73340a25..8b62217cc 100644 --- a/monkey/infection_monkey/system_info/mimikatz_collector.py +++ b/monkey/infection_monkey/system_info/mimikatz_collector.py @@ -78,11 +78,11 @@ class MimikatzCollector(object): for i in range(entry_count): entry = self._get() - username = entry.username.encode('utf-8').strip() + username = entry.username - password = entry.password.encode('utf-8').strip() - lm_hash = binascii.hexlify(bytearray(entry.lm_hash)) - ntlm_hash = binascii.hexlify(bytearray(entry.ntlm_hash)) + password = entry.password + lm_hash = binascii.hexlify(bytearray(entry.lm_hash)).decode() + ntlm_hash = binascii.hexlify(bytearray(entry.ntlm_hash)).decode() if 0 == len(password): has_password = False From 65cfab30ddee560223e81a694e91ccce5f053cd1 Mon Sep 17 00:00:00 2001 From: VakarisZ Date: Mon, 28 Oct 2019 15:44:53 +0200 Subject: [PATCH 27/37] Revert "Fixed ring bug with @staticmethod" This reverts commit 8046cdd --- monkey/monkey_island/cc/models/monkey.py | 66 +++++++++---------- monkey/monkey_island/cc/models/test_monkey.py | 33 +++++----- monkey/monkey_island/cc/services/edge.py | 8 +-- monkey/monkey_island/cc/services/node.py | 8 +-- 4 files changed, 56 insertions(+), 59 deletions(-) diff --git a/monkey/monkey_island/cc/models/monkey.py b/monkey/monkey_island/cc/models/monkey.py index 1a0e872f6..324903809 100644 --- a/monkey/monkey_island/cc/models/monkey.py +++ b/monkey/monkey_island/cc/models/monkey.py @@ -97,6 +97,25 @@ class Monkey(Document): os = "windows" return os + @ring.lru() + @staticmethod + def get_label_by_id(object_id): + current_monkey = Monkey.get_single_monkey_by_id(object_id) + label = Monkey.get_hostname_by_id(object_id) + " : " + current_monkey.ip_addresses[0] + if len(set(current_monkey.ip_addresses).intersection(local_ip_addresses())) > 0: + label = "MonkeyIsland - " + label + return label + + @ring.lru() + @staticmethod + def get_hostname_by_id(object_id): + """ + :param object_id: the object ID of a Monkey in the database. + :return: The hostname of that machine. + :note: Use this and not monkey.hostname for performance - this is lru-cached. + """ + return Monkey.get_single_monkey_by_id(object_id).hostname + def set_hostname(self, hostname): """ Sets a new hostname for a machine and clears the cache for getting it. @@ -104,8 +123,8 @@ class Monkey(Document): """ self.hostname = hostname self.save() - get_monkey_hostname_by_id.delete(self.id) - get_monkey_label_by_id.delete(self.id) + Monkey.get_hostname_by_id.delete(self.id) + Monkey.get_label_by_id.delete(self.id) def get_network_info(self): """ @@ -114,6 +133,17 @@ class Monkey(Document): """ return {'ips': self.ip_addresses, 'hostname': self.hostname} + @ring.lru( + expire=1 # data has TTL of 1 second. This is useful for rapid calls for report generation. + ) + @staticmethod + def is_monkey(object_id): + try: + _ = Monkey.get_single_monkey_by_id(object_id) + return True + except: + return False + @staticmethod def get_tunneled_monkeys(): return Monkey.objects(tunnel__exists=True) @@ -123,37 +153,5 @@ class Monkey(Document): self.save() -# TODO Can't make following methods static under Monkey class due to ring bug. When ring will support static methods, we -# should move to static methods in the Monkey class. -@ring.lru( - expire=1 # data has TTL of 1 second. This is useful for rapid calls for report generation. -) -def is_monkey(object_id): - try: - _ = Monkey.get_single_monkey_by_id(object_id) - return True - except: - return False - - -@ring.lru() -def get_monkey_label_by_id(object_id): - current_monkey = Monkey.get_single_monkey_by_id(object_id) - label = get_monkey_hostname_by_id(object_id) + " : " + current_monkey.ip_addresses[0] - if len(set(current_monkey.ip_addresses).intersection(local_ip_addresses())) > 0: - label = "MonkeyIsland - " + label - return label - - -@ring.lru() -def get_monkey_hostname_by_id(object_id): - """ - :param object_id: the object ID of a Monkey in the database. - :return: The hostname of that machine. - :note: Use this and not monkey.hostname for performance - this is lru-cached. - """ - return Monkey.get_single_monkey_by_id(object_id).hostname - - class MonkeyNotFoundError(Exception): pass diff --git a/monkey/monkey_island/cc/models/test_monkey.py b/monkey/monkey_island/cc/models/test_monkey.py index 472c5770b..d399355a3 100644 --- a/monkey/monkey_island/cc/models/test_monkey.py +++ b/monkey/monkey_island/cc/models/test_monkey.py @@ -4,7 +4,7 @@ from time import sleep import pytest -from monkey_island.cc.models.monkey import Monkey, MonkeyNotFoundError, is_monkey, get_monkey_label_by_id +from monkey_island.cc.models.monkey import Monkey, MonkeyNotFoundError from monkey_island.cc.testing.IslandTestCase import IslandTestCase from .monkey_ttl import MonkeyTtl @@ -131,13 +131,12 @@ class TestMonkey(IslandTestCase): ip_addresses=[ip_example]) linux_monkey.save() - logger.debug(id(get_monkey_label_by_id)) - - cache_info_before_query = get_monkey_label_by_id.storage.backend.cache_info() + cache_info_before_query = Monkey.get_label_by_id.storage.backend.cache_info() self.assertEqual(cache_info_before_query.hits, 0) self.assertEqual(cache_info_before_query.misses, 0) # not cached + label = Monkey.get_label_by_id(linux_monkey.id) label = get_monkey_label_by_id(linux_monkey.id) cache_info_after_query_1 = get_monkey_label_by_id.storage.backend.cache_info() self.assertEqual(cache_info_after_query_1.hits, 0) @@ -149,23 +148,23 @@ class TestMonkey(IslandTestCase): self.assertIn(ip_example, label) # should be cached + _ = Monkey.get_label_by_id(linux_monkey.id) + cache_info_after_query = Monkey.get_label_by_id.storage.backend.cache_info() + self.assertEqual(cache_info_after_query.hits, 1) label = get_monkey_label_by_id(linux_monkey.id) logger.info("2) ID: {} label: {}".format(linux_monkey.id, label)) cache_info_after_query_2 = get_monkey_label_by_id.storage.backend.cache_info() self.assertEqual(cache_info_after_query_2.hits, 1) self.assertEqual(cache_info_after_query_2.misses, 1) - # set hostname deletes the id from the cache. linux_monkey.set_hostname("Another hostname") # should be a miss - label = get_monkey_label_by_id(linux_monkey.id) - logger.info("3) ID: {} label: {}".format(linux_monkey.id, label)) - cache_info_after_query_3 = get_monkey_label_by_id.storage.backend.cache_info() - logger.debug("Cache info: {}".format(str(cache_info_after_query_3))) + label = Monkey.get_label_by_id(linux_monkey.id) + cache_info_after_second_query = Monkey.get_label_by_id.storage.backend.cache_info() # still 1 hit only - self.assertEqual(cache_info_after_query_3.hits, 1) - self.assertEqual(cache_info_after_query_3.misses, 2) + self.assertEqual(cache_info_after_second_query.hits, 1) + self.assertEqual(cache_info_after_second_query.misses, 2) def test_is_monkey(self): self.fail_if_not_testing_env() @@ -174,18 +173,18 @@ class TestMonkey(IslandTestCase): a_monkey = Monkey(guid=str(uuid.uuid4())) a_monkey.save() - cache_info_before_query = is_monkey.storage.backend.cache_info() + cache_info_before_query = Monkey.is_monkey.storage.backend.cache_info() self.assertEqual(cache_info_before_query.hits, 0) # not cached - self.assertTrue(is_monkey(a_monkey.id)) + self.assertTrue(Monkey.is_monkey(a_monkey.id)) fake_id = "123456789012" - self.assertFalse(is_monkey(fake_id)) + self.assertFalse(Monkey.is_monkey(fake_id)) # should be cached - self.assertTrue(is_monkey(a_monkey.id)) - self.assertFalse(is_monkey(fake_id)) + self.assertTrue(Monkey.is_monkey(a_monkey.id)) + self.assertFalse(Monkey.is_monkey(fake_id)) - cache_info_after_query = is_monkey.storage.backend.cache_info() + cache_info_after_query = Monkey.is_monkey.storage.backend.cache_info() self.assertEqual(cache_info_after_query.hits, 2) diff --git a/monkey/monkey_island/cc/services/edge.py b/monkey/monkey_island/cc/services/edge.py index bf9417309..ae3d2a2de 100644 --- a/monkey/monkey_island/cc/services/edge.py +++ b/monkey/monkey_island/cc/services/edge.py @@ -2,7 +2,7 @@ from bson import ObjectId from monkey_island.cc.database import mongo import monkey_island.cc.services.node -from monkey_island.cc.models.monkey import get_monkey_label_by_id, is_monkey +from monkey_island.cc.models import Monkey __author__ = "itay.mizeretz" @@ -145,13 +145,13 @@ class EdgeService: from_id = edge["from"] to_id = edge["to"] - from_label = get_monkey_label_by_id(from_id) + from_label = Monkey.get_label_by_id(from_id) if to_id == ObjectId("000000000000000000000000"): to_label = 'MonkeyIsland' else: - if is_monkey(to_id): - to_label = get_monkey_label_by_id(to_id) + if Monkey.is_monkey(to_id): + to_label = Monkey.get_label_by_id(to_id) else: to_label = NodeService.get_node_label(NodeService.get_node_by_id(to_id)) diff --git a/monkey/monkey_island/cc/services/node.py b/monkey/monkey_island/cc/services/node.py index 0c0a873e8..27d2d299a 100644 --- a/monkey/monkey_island/cc/services/node.py +++ b/monkey/monkey_island/cc/services/node.py @@ -4,7 +4,7 @@ from bson import ObjectId import monkey_island.cc.services.log from monkey_island.cc.database import mongo -from monkey_island.cc.models.monkey import Monkey, get_monkey_hostname_by_id, get_monkey_label_by_id +from monkey_island.cc.models import Monkey from monkey_island.cc.services.edge import EdgeService from monkey_island.cc.utils import local_ip_addresses import socket @@ -50,8 +50,8 @@ class NodeService: for edge in edges: from_node_id = edge["from"] - from_node_label = get_monkey_label_by_id(from_node_id) - from_node_hostname = get_monkey_hostname_by_id(from_node_id) + from_node_label = Monkey.get_label_by_id(from_node_id) + from_node_hostname = Monkey.get_hostname_by_id(from_node_id) accessible_from_nodes.append(from_node_label) accessible_from_nodes_hostnames.append(from_node_hostname) @@ -140,7 +140,7 @@ class NodeService: @staticmethod def monkey_to_net_node(monkey, for_report=False): monkey_id = monkey["_id"] - label = get_monkey_hostname_by_id(monkey_id) if for_report else get_monkey_label_by_id(monkey_id) + label = Monkey.get_hostname_by_id(monkey_id) if for_report else Monkey.get_label_by_id(monkey_id) monkey_group = NodeService.get_monkey_group(monkey) return \ { From ea584e2d4617549d8ed6132918f088a6951b729a Mon Sep 17 00:00:00 2001 From: VakarisZ Date: Mon, 28 Oct 2019 16:59:01 +0200 Subject: [PATCH 28/37] Fixed monkey tests to test updated cached methods --- monkey/monkey_island/cc/models/test_monkey.py | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/monkey/monkey_island/cc/models/test_monkey.py b/monkey/monkey_island/cc/models/test_monkey.py index d399355a3..4ced7a9d7 100644 --- a/monkey/monkey_island/cc/models/test_monkey.py +++ b/monkey/monkey_island/cc/models/test_monkey.py @@ -131,14 +131,15 @@ class TestMonkey(IslandTestCase): ip_addresses=[ip_example]) linux_monkey.save() + logger.debug(id(Monkey.get_label_by_id)) + cache_info_before_query = Monkey.get_label_by_id.storage.backend.cache_info() self.assertEqual(cache_info_before_query.hits, 0) self.assertEqual(cache_info_before_query.misses, 0) # not cached label = Monkey.get_label_by_id(linux_monkey.id) - label = get_monkey_label_by_id(linux_monkey.id) - cache_info_after_query_1 = get_monkey_label_by_id.storage.backend.cache_info() + cache_info_after_query_1 = Monkey.get_label_by_id.storage.backend.cache_info() self.assertEqual(cache_info_after_query_1.hits, 0) self.assertEqual(cache_info_after_query_1.misses, 1) logger.info("1) ID: {} label: {}".format(linux_monkey.id, label)) @@ -148,23 +149,23 @@ class TestMonkey(IslandTestCase): self.assertIn(ip_example, label) # should be cached - _ = Monkey.get_label_by_id(linux_monkey.id) - cache_info_after_query = Monkey.get_label_by_id.storage.backend.cache_info() - self.assertEqual(cache_info_after_query.hits, 1) - label = get_monkey_label_by_id(linux_monkey.id) + label = Monkey.get_label_by_id(linux_monkey.id) logger.info("2) ID: {} label: {}".format(linux_monkey.id, label)) - cache_info_after_query_2 = get_monkey_label_by_id.storage.backend.cache_info() + cache_info_after_query_2 = Monkey.get_label_by_id.storage.backend.cache_info() self.assertEqual(cache_info_after_query_2.hits, 1) self.assertEqual(cache_info_after_query_2.misses, 1) + # set hostname deletes the id from the cache. linux_monkey.set_hostname("Another hostname") # should be a miss label = Monkey.get_label_by_id(linux_monkey.id) - cache_info_after_second_query = Monkey.get_label_by_id.storage.backend.cache_info() + logger.info("3) ID: {} label: {}".format(linux_monkey.id, label)) + cache_info_after_query_3 = Monkey.get_label_by_id.storage.backend.cache_info() + logger.debug("Cache info: {}".format(str(cache_info_after_query_3))) # still 1 hit only - self.assertEqual(cache_info_after_second_query.hits, 1) - self.assertEqual(cache_info_after_second_query.misses, 2) + self.assertEqual(cache_info_after_query_3.hits, 1) + self.assertEqual(cache_info_after_query_3.misses, 2) def test_is_monkey(self): self.fail_if_not_testing_env() From ca7cfb51b28d1469937b64c5d8dba7cbefb73145 Mon Sep 17 00:00:00 2001 From: vakaris_zilius Date: Tue, 29 Oct 2019 09:08:10 +0000 Subject: [PATCH 29/37] BB fix for python3, updated package.json --- .../cc/resources/test/log_test.py | 2 +- monkey/monkey_island/cc/ui/package-lock.json | 119 +++++++++--------- monkey/monkey_island/cc/ui/package.json | 4 +- 3 files changed, 62 insertions(+), 63 deletions(-) diff --git a/monkey/monkey_island/cc/resources/test/log_test.py b/monkey/monkey_island/cc/resources/test/log_test.py index e592e7214..0189cdbf0 100644 --- a/monkey/monkey_island/cc/resources/test/log_test.py +++ b/monkey/monkey_island/cc/resources/test/log_test.py @@ -15,4 +15,4 @@ class LogTest(flask_restful.Resource): if not log: return {'results': None} log_file = database.gridfs.get(log['file_id']) - return {'results': log_file.read()} + return {'results': log_file.read().decode()} diff --git a/monkey/monkey_island/cc/ui/package-lock.json b/monkey/monkey_island/cc/ui/package-lock.json index 14e547416..4a6f1f98a 100644 --- a/monkey/monkey_island/cc/ui/package-lock.json +++ b/monkey/monkey_island/cc/ui/package-lock.json @@ -737,9 +737,9 @@ "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" }, "process-nextick-args": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", - "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==" + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" }, "readable-stream": { "version": "2.3.6", @@ -749,7 +749,7 @@ "core-util-is": "1.0.2", "inherits": "2.0.3", "isarray": "1.0.0", - "process-nextick-args": "2.0.0", + "process-nextick-args": "2.0.1", "safe-buffer": "5.1.1", "string_decoder": "1.1.1", "util-deprecate": "1.0.2" @@ -5652,9 +5652,9 @@ "optional": true }, "filepond": { - "version": "4.7.1", - "resolved": "https://registry.npmjs.org/filepond/-/filepond-4.7.1.tgz", - "integrity": "sha512-AxZBhsGS9QEJfbLiASUJMuS3hLhq/HbkKaJx1gKYCQ0lbs/OfciKKdeFbtAVKk0o9o6DcITw2C+QqFcTP1QBCg==" + "version": "4.7.3", + "resolved": "https://registry.npmjs.org/filepond/-/filepond-4.7.3.tgz", + "integrity": "sha512-lt7UC2wwuoy1WN0zTeZRZ+jS9tHgICPYJB8l1OtHdCjGwaQzTq+M3PqKQQ7melKkGS1tQ1rUInKkSdSuojphWg==" }, "fill-range": { "version": "2.2.3", @@ -6288,8 +6288,8 @@ "dev": true, "optional": true, "requires": { - "co": "^4.6.0", - "json-stable-stringify": "^1.0.1" + "co": "4.6.0", + "json-stable-stringify": "1.0.1" } }, "ansi-regex": { @@ -6362,7 +6362,7 @@ "bundled": true, "dev": true, "requires": { - "inherits": "~2.0.0" + "inherits": "2.0.3" } }, "boom": { @@ -6485,7 +6485,7 @@ "dev": true, "optional": true, "requires": { - "jsbn": "~0.1.0" + "jsbn": "0.1.1" } }, "extend": { @@ -6606,8 +6606,8 @@ "dev": true, "optional": true, "requires": { - "ajv": "^4.9.1", - "har-schema": "^1.0.5" + "ajv": "4.11.8", + "har-schema": "1.0.5" } }, "has-unicode": { @@ -6695,14 +6695,13 @@ "dev": true, "optional": true, "requires": { - "jsbn": "~0.1.0" + "jsbn": "0.1.1" } }, "jsbn": { "version": "0.1.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "json-schema": { "version": "0.2.3", @@ -6716,7 +6715,7 @@ "dev": true, "optional": true, "requires": { - "jsonify": "~0.0.0" + "jsonify": "0.0.0" } }, "json-stringify-safe": { @@ -10954,9 +10953,9 @@ }, "dependencies": { "ajv": { - "version": "6.10.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.0.tgz", - "integrity": "sha512-nffhOpkymDECQyR0mnsUtoCE8RlX38G0rYP+wgLWFyZuUyuuojSSvi/+euOiQBIn63whYwYVIIH1TvE3tu4OEg==", + "version": "6.10.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz", + "integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==", "requires": { "fast-deep-equal": "2.0.1", "fast-json-stable-stringify": "2.0.0", @@ -10984,7 +10983,7 @@ "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", "requires": { - "ajv": "6.10.0", + "ajv": "6.10.2", "har-schema": "2.0.0" } }, @@ -11012,9 +11011,9 @@ "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" }, "psl": { - "version": "1.1.32", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.32.tgz", - "integrity": "sha512-MHACAkHpihU/REGGPLj4sEfc/XKW2bheigvHO1dUqjaKigMp1C8+WLQYRGgeKFMsw5PMfegZcaN8IDXK/cD0+g==" + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.4.0.tgz", + "integrity": "sha512-HZzqCGPecFLyoRj5HLfuDSKYTJkAfB5thKBIkRHtGjWwY7p1dAyveIbXIq4tO0KYfDF2tHqPUgY9SDnGm00uFw==" }, "request": { "version": "2.88.0", @@ -11037,16 +11036,16 @@ "oauth-sign": "0.9.0", "performance-now": "2.1.0", "qs": "6.5.2", - "safe-buffer": "5.1.2", + "safe-buffer": "5.2.0", "tough-cookie": "2.4.3", "tunnel-agent": "0.6.0", - "uuid": "3.3.2" + "uuid": "3.3.3" } }, "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", + "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==" }, "semver": { "version": "5.3.0", @@ -11058,14 +11057,14 @@ "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", "requires": { - "psl": "1.1.32", + "psl": "1.4.0", "punycode": "1.4.1" } }, "uuid": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", - "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.3.tgz", + "integrity": "sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ==" } } }, @@ -11169,9 +11168,9 @@ } }, "node-sass": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.12.0.tgz", - "integrity": "sha512-A1Iv4oN+Iel6EPv77/HddXErL2a+gZ4uBeZUy+a8O35CFYTXhgA8MgLCWBtwpGZdCvTvQ9d+bQxX/QC36GDPpQ==", + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.13.0.tgz", + "integrity": "sha512-W1XBrvoJ1dy7VsvTAS5q1V45lREbTlZQqFbiHb3R3OTTCma0XBtuG6xZ6Z4506nR4lmHPTqVRwxT6KgtWC97CA==", "requires": { "async-foreach": "0.1.3", "chalk": "1.1.3", @@ -11180,7 +11179,7 @@ "get-stdin": "4.0.1", "glob": "7.1.4", "in-publish": "2.0.0", - "lodash": "4.17.11", + "lodash": "4.17.15", "meow": "3.7.0", "mkdirp": "0.5.1", "nan": "2.14.0", @@ -11193,9 +11192,9 @@ }, "dependencies": { "ajv": { - "version": "6.10.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.0.tgz", - "integrity": "sha512-nffhOpkymDECQyR0mnsUtoCE8RlX38G0rYP+wgLWFyZuUyuuojSSvi/+euOiQBIn63whYwYVIIH1TvE3tu4OEg==", + "version": "6.10.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz", + "integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==", "requires": { "fast-deep-equal": "2.0.1", "fast-json-stable-stringify": "2.0.0", @@ -11232,7 +11231,7 @@ "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", "requires": { - "ajv": "6.10.0", + "ajv": "6.10.2", "har-schema": "2.0.0" } }, @@ -11242,9 +11241,9 @@ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" }, "lodash": { - "version": "4.17.11", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", - "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" }, "mime-db": { "version": "1.40.0", @@ -11270,9 +11269,9 @@ "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" }, "psl": { - "version": "1.1.32", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.32.tgz", - "integrity": "sha512-MHACAkHpihU/REGGPLj4sEfc/XKW2bheigvHO1dUqjaKigMp1C8+WLQYRGgeKFMsw5PMfegZcaN8IDXK/cD0+g==" + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.4.0.tgz", + "integrity": "sha512-HZzqCGPecFLyoRj5HLfuDSKYTJkAfB5thKBIkRHtGjWwY7p1dAyveIbXIq4tO0KYfDF2tHqPUgY9SDnGm00uFw==" }, "request": { "version": "2.88.0", @@ -11295,30 +11294,30 @@ "oauth-sign": "0.9.0", "performance-now": "2.1.0", "qs": "6.5.2", - "safe-buffer": "5.1.2", + "safe-buffer": "5.2.0", "tough-cookie": "2.4.3", "tunnel-agent": "0.6.0", - "uuid": "3.3.2" + "uuid": "3.3.3" } }, "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", + "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==" }, "tough-cookie": { "version": "2.4.3", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", "requires": { - "psl": "1.1.32", + "psl": "1.4.0", "punycode": "1.4.1" } }, "uuid": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", - "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.3.tgz", + "integrity": "sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ==" } } }, @@ -17544,9 +17543,9 @@ "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" }, "process-nextick-args": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", - "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==" + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" }, "readable-stream": { "version": "2.3.6", @@ -17556,7 +17555,7 @@ "core-util-is": "1.0.2", "inherits": "2.0.3", "isarray": "1.0.0", - "process-nextick-args": "2.0.0", + "process-nextick-args": "2.0.1", "safe-buffer": "5.1.1", "string_decoder": "1.1.1", "util-deprecate": "1.0.2" diff --git a/monkey/monkey_island/cc/ui/package.json b/monkey/monkey_island/cc/ui/package.json index aa85164ce..e5f6ed05a 100644 --- a/monkey/monkey_island/cc/ui/package.json +++ b/monkey/monkey_island/cc/ui/package.json @@ -74,12 +74,12 @@ "downloadjs": "^1.4.7", "fetch": "^1.1.0", "file-saver": "^2.0.2", - "filepond": "^4.7.1", + "filepond": "^4.7.3", "js-file-download": "^0.4.8", "json-loader": "^0.5.7", "jwt-decode": "^2.2.0", "moment": "^2.24.0", - "node-sass": "^4.11.0", + "node-sass": "^4.13.0", "normalize.css": "^8.0.0", "npm": "^6.11.3", "pluralize": "^7.0.0", From 64ec629306815c60fbfe3e8f56389616760fea85 Mon Sep 17 00:00:00 2001 From: VakarisZ Date: Tue, 29 Oct 2019 14:04:48 +0200 Subject: [PATCH 30/37] Machine name in BB fix --- envs/monkey_zoo/blackbox/test_blackbox.py | 34 +++++++++++------------ 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/envs/monkey_zoo/blackbox/test_blackbox.py b/envs/monkey_zoo/blackbox/test_blackbox.py index fc20c8b39..e67800b1d 100644 --- a/envs/monkey_zoo/blackbox/test_blackbox.py +++ b/envs/monkey_zoo/blackbox/test_blackbox.py @@ -13,7 +13,7 @@ from envs.monkey_zoo.blackbox.log_handlers.test_logs_handler import TestLogsHand DEFAULT_TIMEOUT_SECONDS = 5*60 MACHINE_BOOTUP_WAIT_SECONDS = 30 -GCP_TEST_MACHINE_LIST = ['sshkeys-11', 'sshkeys-12', 'elastic-4', 'elastic-5', 'haddop-2', 'hadoop-3', 'mssql-16', +GCP_TEST_MACHINE_LIST = ['sshkeys-11', 'sshkeys-12', 'elastic-4', 'elastic-5', 'hadoop-2', 'hadoop-3', 'mssql-16', 'mimikatz-14', 'mimikatz-15', 'struts2-23', 'struts2-24', 'tunneling-9', 'tunneling-10', 'tunneling-11', 'weblogic-18', 'weblogic-19', 'shellshock-8'] LOG_DIR_PATH = "./logs" @@ -72,29 +72,29 @@ class TestMonkeyBlackbox(object): def test_server_online(self, island_client): assert island_client.get_api_status() is not None - def test_ssh_exploiter(self, island_client): - TestMonkeyBlackbox.run_basic_test(island_client, "SSH.conf", "SSH_exploiter_and_keys") + #def test_ssh_exploiter(self, island_client): + # TestMonkeyBlackbox.run_basic_test(island_client, "SSH.conf", "SSH_exploiter_and_keys") def test_hadoop_exploiter(self, island_client): TestMonkeyBlackbox.run_basic_test(island_client, "HADOOP.conf", "Hadoop_exploiter", 6*60) - def test_mssql_exploiter(self, island_client): - TestMonkeyBlackbox.run_basic_test(island_client, "MSSQL.conf", "MSSQL_exploiter") - - def test_smb_and_mimikatz_exploiters(self, island_client): - TestMonkeyBlackbox.run_basic_test(island_client, "SMB_MIMIKATZ.conf", "SMB_exploiter_mimikatz") - - def test_smb_pth(self, island_client): - TestMonkeyBlackbox.run_basic_test(island_client, "SMB_PTH.conf", "SMB_PTH") - - def test_elastic_exploiter(self, island_client): - TestMonkeyBlackbox.run_basic_test(island_client, "ELASTIC.conf", "Elastic_exploiter") - + #def test_mssql_exploiter(self, island_client): + # TestMonkeyBlackbox.run_basic_test(island_client, "MSSQL.conf", "MSSQL_exploiter") +# + #def test_smb_and_mimikatz_exploiters(self, island_client): + # TestMonkeyBlackbox.run_basic_test(island_client, "SMB_MIMIKATZ.conf", "SMB_exploiter_mimikatz") +# + #def test_smb_pth(self, island_client): + # TestMonkeyBlackbox.run_basic_test(island_client, "SMB_PTH.conf", "SMB_PTH") +# + #def test_elastic_exploiter(self, island_client): + # TestMonkeyBlackbox.run_basic_test(island_client, "ELASTIC.conf", "Elastic_exploiter") +# def test_struts_exploiter(self, island_client): TestMonkeyBlackbox.run_basic_test(island_client, "STRUTS2.conf", "Strtuts2_exploiter") - def test_weblogic_exploiter(self, island_client): - TestMonkeyBlackbox.run_basic_test(island_client, "WEBLOGIC.conf", "Weblogic_exploiter") + #def test_weblogic_exploiter(self, island_client): + # TestMonkeyBlackbox.run_basic_test(island_client, "WEBLOGIC.conf", "Weblogic_exploiter") def test_shellshock_exploiter(self, island_client): TestMonkeyBlackbox.run_basic_test(island_client, "SHELLSHOCK.conf", "Shellschock_exploiter") From cdc30f56c7fd442d28a50fadfa4e20113469fa98 Mon Sep 17 00:00:00 2001 From: VakarisZ Date: Tue, 29 Oct 2019 15:00:01 +0200 Subject: [PATCH 31/37] Shellshock bugfix --- monkey/infection_monkey/exploit/shellshock.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/monkey/infection_monkey/exploit/shellshock.py b/monkey/infection_monkey/exploit/shellshock.py index edc4851e9..52be145cc 100644 --- a/monkey/infection_monkey/exploit/shellshock.py +++ b/monkey/infection_monkey/exploit/shellshock.py @@ -207,7 +207,7 @@ class ShellShockExploiter(HostExploiter): LOG.debug("Header is: %s" % header) LOG.debug("Attack is: %s" % attack) r = requests.get(url, headers={header: attack}, verify=False, timeout=TIMEOUT) - result = r.content + result = r.content.decode() return result except requests.exceptions.RequestException as exc: LOG.debug("Failed to run, exception %s" % exc) From 95c63d6cef8c40b71b92538b4fe1c2243eb0eb57 Mon Sep 17 00:00:00 2001 From: VakarisZ Date: Tue, 29 Oct 2019 16:29:51 +0200 Subject: [PATCH 32/37] Rollback of accidental changes --- envs/monkey_zoo/blackbox/test_blackbox.py | 32 +++++++++++------------ 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/envs/monkey_zoo/blackbox/test_blackbox.py b/envs/monkey_zoo/blackbox/test_blackbox.py index e67800b1d..8581b6fbe 100644 --- a/envs/monkey_zoo/blackbox/test_blackbox.py +++ b/envs/monkey_zoo/blackbox/test_blackbox.py @@ -72,29 +72,29 @@ class TestMonkeyBlackbox(object): def test_server_online(self, island_client): assert island_client.get_api_status() is not None - #def test_ssh_exploiter(self, island_client): - # TestMonkeyBlackbox.run_basic_test(island_client, "SSH.conf", "SSH_exploiter_and_keys") + def test_ssh_exploiter(self, island_client): + TestMonkeyBlackbox.run_basic_test(island_client, "SSH.conf", "SSH_exploiter_and_keys") def test_hadoop_exploiter(self, island_client): TestMonkeyBlackbox.run_basic_test(island_client, "HADOOP.conf", "Hadoop_exploiter", 6*60) - #def test_mssql_exploiter(self, island_client): - # TestMonkeyBlackbox.run_basic_test(island_client, "MSSQL.conf", "MSSQL_exploiter") -# - #def test_smb_and_mimikatz_exploiters(self, island_client): - # TestMonkeyBlackbox.run_basic_test(island_client, "SMB_MIMIKATZ.conf", "SMB_exploiter_mimikatz") -# - #def test_smb_pth(self, island_client): - # TestMonkeyBlackbox.run_basic_test(island_client, "SMB_PTH.conf", "SMB_PTH") -# - #def test_elastic_exploiter(self, island_client): - # TestMonkeyBlackbox.run_basic_test(island_client, "ELASTIC.conf", "Elastic_exploiter") -# + def test_mssql_exploiter(self, island_client): + TestMonkeyBlackbox.run_basic_test(island_client, "MSSQL.conf", "MSSQL_exploiter") + + def test_smb_and_mimikatz_exploiters(self, island_client): + TestMonkeyBlackbox.run_basic_test(island_client, "SMB_MIMIKATZ.conf", "SMB_exploiter_mimikatz") + + def test_smb_pth(self, island_client): + TestMonkeyBlackbox.run_basic_test(island_client, "SMB_PTH.conf", "SMB_PTH") + + def test_elastic_exploiter(self, island_client): + TestMonkeyBlackbox.run_basic_test(island_client, "ELASTIC.conf", "Elastic_exploiter") + def test_struts_exploiter(self, island_client): TestMonkeyBlackbox.run_basic_test(island_client, "STRUTS2.conf", "Strtuts2_exploiter") - #def test_weblogic_exploiter(self, island_client): - # TestMonkeyBlackbox.run_basic_test(island_client, "WEBLOGIC.conf", "Weblogic_exploiter") + def test_weblogic_exploiter(self, island_client): + TestMonkeyBlackbox.run_basic_test(island_client, "WEBLOGIC.conf", "Weblogic_exploiter") def test_shellshock_exploiter(self, island_client): TestMonkeyBlackbox.run_basic_test(island_client, "SHELLSHOCK.conf", "Shellschock_exploiter") From ec5de408b2454dd84477742b148025fd1a281761 Mon Sep 17 00:00:00 2001 From: VakarisZ Date: Wed, 30 Oct 2019 12:38:14 +0200 Subject: [PATCH 33/37] Blank screen (JWT token expiration) bugfix --- monkey/monkey_island/cc/ui/src/services/AuthService.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/monkey/monkey_island/cc/ui/src/services/AuthService.js b/monkey/monkey_island/cc/ui/src/services/AuthService.js index 9c62bde63..ec997da6a 100644 --- a/monkey/monkey_island/cc/ui/src/services/AuthService.js +++ b/monkey/monkey_island/cc/ui/src/services/AuthService.js @@ -7,6 +7,8 @@ export default class AuthService { "55e97c9dcfd22b8079189ddaeea9bce8125887e3237b800c6176c9afa80d2062" + "8d2c8d0b1538d2208c1444ac66535b764a3d902b35e751df3faec1e477ed3557"; + SECONDS_BEFORE_JWT_EXPIRES = 20; + login = (username, password) => { return this._login(username, this.hashSha3(password)); }; @@ -96,7 +98,7 @@ export default class AuthService { _isTokenExpired(token) { try { - return decode(token)['exp'] < Date.now() / 1000; + return decode(token)['exp'] + this.SECONDS_BEFORE_JWT_EXPIRES < Date.now() / 1000; } catch (err) { return false; From dba52fcbedb5e43036d8a2be37c3b4e87d7a1dae Mon Sep 17 00:00:00 2001 From: VakarisZ Date: Wed, 30 Oct 2019 14:38:17 +0200 Subject: [PATCH 34/37] BB tests bugfix of not refreshing JWT --- .../island_client/monkey_island_requests.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/envs/monkey_zoo/blackbox/island_client/monkey_island_requests.py b/envs/monkey_zoo/blackbox/island_client/monkey_island_requests.py index e62cb2121..8ac53996b 100644 --- a/envs/monkey_zoo/blackbox/island_client/monkey_island_requests.py +++ b/envs/monkey_zoo/blackbox/island_client/monkey_island_requests.py @@ -1,4 +1,5 @@ import requests +import functools # SHA3-512 of '1234567890!@#$%^&*()_nothing_up_my_sleeve_1234567890!@#$%^&*()' import logging @@ -8,6 +9,7 @@ NO_AUTH_CREDS = '55e97c9dcfd22b8079189ddaeea9bce8125887e3237b800c6176c9afa80d206 LOGGER = logging.getLogger(__name__) +# noinspection PyArgumentList class MonkeyIslandRequests(object): def __init__(self, server_address): self.addr = "https://{IP}/".format(IP=server_address) @@ -21,29 +23,43 @@ class MonkeyIslandRequests(object): "Unable to connect to island, aborting! Error information: {}. Server: {}".format(err, self.addr)) assert False + class _Decorators: + @classmethod + def refresh_jwt_token(cls, request_function): + @functools.wraps(request_function) + def request_function_wrapper(self, *args,**kwargs): + self.token = self.try_get_jwt_from_server() + # noinspection PyArgumentList + return request_function(self, *args, **kwargs) + return request_function_wrapper + def get_jwt_from_server(self): resp = requests.post(self.addr + "api/auth", json={"username": NO_AUTH_CREDS, "password": NO_AUTH_CREDS}, verify=False) return resp.json()["access_token"] + @_Decorators.refresh_jwt_token def get(self, url, data=None): return requests.get(self.addr + url, headers=self.get_jwt_header(), params=data, verify=False) + @_Decorators.refresh_jwt_token def post(self, url, data): return requests.post(self.addr + url, data=data, headers=self.get_jwt_header(), verify=False) + @_Decorators.refresh_jwt_token def post_json(self, url, dict_data): return requests.post(self.addr + url, json=dict_data, headers=self.get_jwt_header(), verify=False) + @_Decorators.refresh_jwt_token def get_jwt_header(self): return {"Authorization": "JWT " + self.token} From a6e61215f397cbb231d41394b28e641d0691c595 Mon Sep 17 00:00:00 2001 From: VakarisZ Date: Wed, 30 Oct 2019 14:45:30 +0200 Subject: [PATCH 35/37] SSH banner read timeout exception (tunneling) bugfix --- monkey/infection_monkey/exploit/sshexec.py | 54 +++++++++---------- .../exploit/tools/exceptions.py | 5 +- 2 files changed, 30 insertions(+), 29 deletions(-) diff --git a/monkey/infection_monkey/exploit/sshexec.py b/monkey/infection_monkey/exploit/sshexec.py index ce2e0d13c..4a88c4593 100644 --- a/monkey/infection_monkey/exploit/sshexec.py +++ b/monkey/infection_monkey/exploit/sshexec.py @@ -5,11 +5,11 @@ import time import paramiko import infection_monkey.monkeyfs as monkeyfs -from common.utils.exploit_enum import ExploitType from infection_monkey.exploit import HostExploiter from infection_monkey.exploit.tools.helpers import get_target_monkey, get_monkey_depth, build_monkey_commandline from infection_monkey.exploit.tools.helpers import get_interface_to_target from infection_monkey.model import MONKEY_ARG +from infection_monkey.exploit.tools.exceptions import FailedExploitationError from infection_monkey.network.tools import check_tcp_port from common.utils.exploit_enum import ExploitType from common.utils.attack_utils import ScanStatus @@ -38,15 +38,16 @@ class SSHExploiter(HostExploiter): LOG.debug("SFTP transferred: %d bytes, total: %d bytes", transferred, total) self._update_timestamp = time.time() - def exploit_with_ssh_keys(self, port, ssh): + def exploit_with_ssh_keys(self, port) -> paramiko.SSHClient: user_ssh_key_pairs = self._config.get_exploit_user_ssh_key_pairs() - exploited = False - for user, ssh_key_pair in user_ssh_key_pairs: # Creating file-like private key for paramiko pkey = io.StringIO(ssh_key_pair['private_key']) ssh_string = "%s@%s" % (ssh_key_pair['user'], ssh_key_pair['ip']) + + ssh = paramiko.SSHClient() + ssh.set_missing_host_key_policy(paramiko.WarningPolicy()) try: pkey = paramiko.RSAKey.from_private_key(pkey) except(IOError, paramiko.SSHException, paramiko.PasswordRequiredException): @@ -55,52 +56,49 @@ class SSHExploiter(HostExploiter): ssh.connect(self.host.ip_addr, username=user, pkey=pkey, - port=port, - timeout=None) + port=port) LOG.debug("Successfully logged in %s using %s users private key", self.host, ssh_string) - exploited = True self.report_login_attempt(True, user, ssh_key=ssh_string) - break - except Exception as exc: + return ssh + except Exception: + ssh.close() LOG.debug("Error logging into victim %r with %s" " private key", self.host, ssh_string) self.report_login_attempt(False, user, ssh_key=ssh_string) continue - return exploited + raise FailedExploitationError - def exploit_with_login_creds(self, port, ssh): + def exploit_with_login_creds(self, port) -> paramiko.SSHClient: user_password_pairs = self._config.get_exploit_user_password_pairs() - exploited = False - for user, current_password in user_password_pairs: + + ssh = paramiko.SSHClient() + ssh.set_missing_host_key_policy(paramiko.WarningPolicy()) try: ssh.connect(self.host.ip_addr, username=user, password=current_password, - port=port, - timeout=None) + port=port) LOG.debug("Successfully logged in %r using SSH. User: %s, pass (SHA-512): %s)", self.host, user, self._config.hash_sensitive_data(current_password)) - exploited = True self.add_vuln_port(port) self.report_login_attempt(True, user, current_password) - break + return ssh except Exception as exc: LOG.debug("Error logging into victim %r with user" " %s and password (SHA-512) '%s': (%s)", self.host, user, self._config.hash_sensitive_data(current_password), exc) self.report_login_attempt(False, user, current_password) + ssh.close() continue - return exploited + raise FailedExploitationError def _exploit_host(self): - ssh = paramiko.SSHClient() - ssh.set_missing_host_key_policy(paramiko.WarningPolicy()) port = SSH_PORT # if ssh banner found on different port, use that port. @@ -113,14 +111,14 @@ class SSHExploiter(HostExploiter): LOG.info("SSH port is closed on %r, skipping", self.host) return False - # Check for possible ssh exploits - exploited = self.exploit_with_ssh_keys(port, ssh) - if not exploited: - exploited = self.exploit_with_login_creds(port, ssh) - - if not exploited: - LOG.debug("Exploiter SSHExploiter is giving up...") - return False + try: + ssh = self.exploit_with_ssh_keys(port) + except FailedExploitationError: + try: + ssh = self.exploit_with_login_creds(port) + except FailedExploitationError: + LOG.debug("Exploiter SSHExploiter is giving up...") + return False if not self.host.os.get('type'): try: diff --git a/monkey/infection_monkey/exploit/tools/exceptions.py b/monkey/infection_monkey/exploit/tools/exceptions.py index eabe8d9d7..a322dc5bd 100644 --- a/monkey/infection_monkey/exploit/tools/exceptions.py +++ b/monkey/infection_monkey/exploit/tools/exceptions.py @@ -2,4 +2,7 @@ class ExploitingVulnerableMachineError(Exception): """ Raise when exploiter failed, but machine is vulnerable""" - pass + + +class FailedExploitationError(Exception): + """ Raise when exploiter fails instead of returning False""" From ac63797f4536c67feb81c4c6df5e61fb06d15ccc Mon Sep 17 00:00:00 2001 From: VakarisZ Date: Wed, 30 Oct 2019 15:11:50 +0200 Subject: [PATCH 36/37] Blank screen fix corrected --- monkey/monkey_island/cc/ui/src/services/AuthService.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/monkey/monkey_island/cc/ui/src/services/AuthService.js b/monkey/monkey_island/cc/ui/src/services/AuthService.js index ec997da6a..962329720 100644 --- a/monkey/monkey_island/cc/ui/src/services/AuthService.js +++ b/monkey/monkey_island/cc/ui/src/services/AuthService.js @@ -98,7 +98,7 @@ export default class AuthService { _isTokenExpired(token) { try { - return decode(token)['exp'] + this.SECONDS_BEFORE_JWT_EXPIRES < Date.now() / 1000; + return decode(token)['exp'] - this.SECONDS_BEFORE_JWT_EXPIRES < Date.now() / 1000; } catch (err) { return false; From 1f5acbc28709d121e0b59181039f3bba6594e5ef Mon Sep 17 00:00:00 2001 From: VakarisZ Date: Thu, 31 Oct 2019 10:48:02 +0200 Subject: [PATCH 37/37] Another white screen fix --- .../cc/ui/src/components/pages/MapPage.js | 28 +++++++++++-------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/monkey/monkey_island/cc/ui/src/components/pages/MapPage.js b/monkey/monkey_island/cc/ui/src/components/pages/MapPage.js index 4d074c835..f9d1f4a83 100644 --- a/monkey/monkey_island/cc/ui/src/components/pages/MapPage.js +++ b/monkey/monkey_island/cc/ui/src/components/pages/MapPage.js @@ -43,11 +43,13 @@ class MapPageComponent extends AuthComponent { this.authFetch('/api/netmap') .then(res => res.json()) .then(res => { - res.edges.forEach(edge => { - edge.color = {'color': edgeGroupToColor(edge.group)}; - }); - this.setState({graph: res}); - this.props.onStatusChange(); + if (res.hasOwnProperty("edges")) { + res.edges.forEach(edge => { + edge.color = {'color': edgeGroupToColor(edge.group)}; + }); + this.setState({graph: res}); + this.props.onStatusChange(); + } }); }; @@ -55,14 +57,16 @@ class MapPageComponent extends AuthComponent { this.authFetch('/api/telemetry-feed?timestamp='+this.state.telemetryLastTimestamp) .then(res => res.json()) .then(res => { - let newTelem = this.state.telemetry.concat(res['telemetries']); + if ('telemetries' in res) { + let newTelem = this.state.telemetry.concat(res['telemetries']); - this.setState( - { - telemetry: newTelem, - telemetryLastTimestamp: res['timestamp'] - }); - this.props.onStatusChange(); + this.setState( + { + telemetry: newTelem, + telemetryLastTimestamp: res['timestamp'] + }); + this.props.onStatusChange(); + } }); };