From 7ee0ceda750e3fd22f098a2dbcf0f45a5f69bfd7 Mon Sep 17 00:00:00 2001 From: Itay Mizeretz Date: Tue, 20 Feb 2018 16:15:40 +0200 Subject: [PATCH 01/12] Support ranges in fixed_ip_list --- chaos_monkey/network/range.py | 65 +++++++++++++++++++++++++---------- 1 file changed, 46 insertions(+), 19 deletions(-) diff --git a/chaos_monkey/network/range.py b/chaos_monkey/network/range.py index b07828f4b..732749e3e 100644 --- a/chaos_monkey/network/range.py +++ b/chaos_monkey/network/range.py @@ -3,6 +3,8 @@ import socket import struct from abc import ABCMeta, abstractmethod +import ipaddress + from model.host import VictimHost __author__ = 'itamar' @@ -16,6 +18,14 @@ class NetworkRange(object): self._shuffle = shuffle self._config = __import__('config').WormConfiguration + @staticmethod + def _ip_to_number(address): + return struct.unpack(">L", socket.inet_aton(address))[0] + + @staticmethod + def _number_to_ip(num): + return socket.inet_ntoa(struct.pack(">L", num)) + @abstractmethod def _get_range(self): raise NotImplementedError() @@ -26,7 +36,7 @@ class NetworkRange(object): random.shuffle(base_range) for x in base_range: - yield VictimHost(socket.inet_ntoa(struct.pack(">L", self._base_address + x))) + yield VictimHost(self._number_to_ip(self._base_address + x)) class ClassCRange(NetworkRange): @@ -35,8 +45,8 @@ class ClassCRange(NetworkRange): super(ClassCRange, self).__init__(base_address, shuffle=shuffle) def __repr__(self): - return "" % (socket.inet_ntoa(struct.pack(">L", self._base_address + 1)), - socket.inet_ntoa(struct.pack(">L", self._base_address + 254))) + return "" % (self._number_to_ip(self._base_address + 1), + self._number_to_ip(self._base_address + 254)) def _get_range(self): return range(1, 254) @@ -49,8 +59,8 @@ class RelativeRange(NetworkRange): self._size = 1 def __repr__(self): - return "" % (socket.inet_ntoa(struct.pack(">L", self._base_address - self._size)), - socket.inet_ntoa(struct.pack(">L", self._base_address + self._size))) + return "" % (self._number_to_ip(self._base_address - self._size), + self._number_to_ip(self._base_address + self._size)) def _get_range(self): lower_end = -(self._size / 2) @@ -59,24 +69,41 @@ class RelativeRange(NetworkRange): class FixedRange(NetworkRange): - def __init__(self, fixed_addresses=None, shuffle=True): + def __init__(self, fixed_addresses, shuffle=True): base_address = 0 super(FixedRange, self).__init__(base_address, shuffle=shuffle) - if not fixed_addresses: - self._fixed_addresses = self._config.range_fixed - else: - if type(fixed_addresses) is str: - self._fixed_addresses = [fixed_addresses] - else: - self._fixed_addresses = list(fixed_addresses) + self._fixed_addresses = fixed_addresses def __repr__(self): return "" % (",".join(self._fixed_addresses)) + @staticmethod + def _cidr_range_to_ip_list(address_str): + return [FixedRange._ip_to_number(str(x)) for x in ipaddress.ip_network(unicode(address_str), strict=False)] + + @staticmethod + def _ip_range_to_ip_list(address_str): + addresses = address_str.split('-') + if len(addresses) != 2: + raise ValueError('Illegal address format: %s' % address_str) + lower_end, higher_end = [FixedRange._ip_to_number(x.strip()) for x in addresses] + if higher_end < lower_end: + raise ValueError('Illegal address range: %s' % address_str) + return range(lower_end, higher_end + 1) + + @staticmethod + def _parse_address_str(address_str): + address_str = address_str.strip() + if not address_str: # Empty string + return [] + if -1 != address_str.find('-'): + return FixedRange._ip_range_to_ip_list(address_str) + if -1 != address_str.find('/'): + return FixedRange._cidr_range_to_ip_list(address_str) + return [FixedRange._ip_to_number(address_str)] + def _get_range(self): - address_range = [] - for address in self._fixed_addresses: - if not address: # Empty string - continue - address_range.append(struct.unpack(">L", socket.inet_aton(address.strip()))[0]) - return address_range + ip_list = list(reduce( + lambda x, y: x.union(y), + [set(self._parse_address_str(z)) for z in self._fixed_addresses])) + return [x for x in ip_list if (x & 0xFF != 0)] # remove broadcast ips From d3ce9562242f6e2af4052af4f78db8cfea0eeb04 Mon Sep 17 00:00:00 2001 From: Itay Mizeretz Date: Tue, 20 Feb 2018 16:21:23 +0200 Subject: [PATCH 02/12] Change description of config value --- monkey_island/cc/services/config.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/monkey_island/cc/services/config.py b/monkey_island/cc/services/config.py index ea755312f..361854f05 100644 --- a/monkey_island/cc/services/config.py +++ b/monkey_island/cc/services/config.py @@ -223,7 +223,7 @@ SCHEMA = { " Class C Range will scan machines in the Class C network the monkey's on." }, "range_fixed": { - "title": "Fixed range IP list", + "title": "Fixed range IP/subnet list", "type": "array", "uniqueItems": True, "items": { @@ -232,8 +232,9 @@ SCHEMA = { "default": [ ], "description": - "List of IPs to include when using FixedRange" - " (Only relevant for Fixed Range)" + "List of IPs/subnets to include when using FixedRange" + " (Only relevant for Fixed Range)." + " Examples: \"192.168.0.1\", \"192.168.0.5-192.168.0.20\", \"192.168.0.5/24\"" } } } From 898644df7bfb13f993f8fbafd219201155d0756c Mon Sep 17 00:00:00 2001 From: Itay Mizeretz Date: Mon, 26 Feb 2018 16:11:52 +0200 Subject: [PATCH 03/12] Remove range classes in config network now scans several range classes according to config --- chaos_monkey/config.py | 2 - chaos_monkey/example.conf | 1 - chaos_monkey/network/info.py | 14 +-- chaos_monkey/network/network_scanner.py | 15 +-- chaos_monkey/network/range.py | 127 +++++++++++++++--------- monkey_island/cc/services/config.py | 22 +--- monkey_island/cc/services/report.py | 2 - 7 files changed, 96 insertions(+), 87 deletions(-) diff --git a/chaos_monkey/config.py b/chaos_monkey/config.py index e62820816..b9a597f8b 100644 --- a/chaos_monkey/config.py +++ b/chaos_monkey/config.py @@ -8,7 +8,6 @@ from itertools import product from exploit import WmiExploiter, Ms08_067_Exploiter, SmbExploiter, RdpExploiter, SSHExploiter, ShellShockExploiter, \ SambaCryExploiter, ElasticGroovyExploiter from network import TcpScanner, PingScanner, SMBFinger, SSHFinger, HTTPFinger, MySQLFinger, ElasticFinger -from network.range import FixedRange __author__ = 'itamar' @@ -182,7 +181,6 @@ class Configuration(object): # Auto detect and scan local subnets local_network_scan = True - range_class = FixedRange range_fixed = ['', ] blocked_ips = ['', ] diff --git a/chaos_monkey/example.conf b/chaos_monkey/example.conf index 6f70f888a..b100cf111 100644 --- a/chaos_monkey/example.conf +++ b/chaos_monkey/example.conf @@ -7,7 +7,6 @@ "www.google.com" ], "keep_tunnel_open_time": 60, - "range_class": "RelativeRange", "range_fixed": [ "" ], diff --git a/chaos_monkey/network/info.py b/chaos_monkey/network/info.py index 3bab8cb17..30a75780e 100644 --- a/chaos_monkey/network/info.py +++ b/chaos_monkey/network/info.py @@ -8,6 +8,7 @@ import itertools import netifaces from subprocess import check_output from random import randint +from range import CidrRange def get_host_subnets(): @@ -129,7 +130,7 @@ def check_internet_access(services): return False -def get_ips_from_interfaces(): +def get_interfaces_ranges(): """ Returns a list of IPs accessible in the host in each network interface, in the subnet. Limits to a single class C if the network is larger @@ -138,15 +139,14 @@ def get_ips_from_interfaces(): res = [] ifs = get_host_subnets() for net_interface in ifs: - address_str = unicode(net_interface['addr']) - netmask_str = unicode(net_interface['netmask']) - host_address = ipaddress.ip_address(address_str) + address_str = net_interface['addr'] + netmask_str = net_interface['netmask'] ip_interface = ipaddress.ip_interface(u"%s/%s" % (address_str, netmask_str)) # limit subnet scans to class C only if ip_interface.network.num_addresses > 255: - ip_interface = ipaddress.ip_interface(u"%s/24" % address_str) - addrs = [str(addr) for addr in ip_interface.network.hosts() if addr != host_address] - res.extend(addrs) + res.append(CidrRange(cidr_range="%s/24" % (address_str, ))) + else: + res.append(CidrRange(cidr_range="%s/%s" % (address_str, netmask_str))) return res diff --git a/chaos_monkey/network/network_scanner.py b/chaos_monkey/network/network_scanner.py index 9c1cf897e..a62f4950e 100644 --- a/chaos_monkey/network/network_scanner.py +++ b/chaos_monkey/network/network_scanner.py @@ -2,7 +2,7 @@ import logging import time from config import WormConfiguration -from info import local_ips, get_ips_from_interfaces +from info import local_ips, get_interfaces_ranges from range import * from . import HostScanner @@ -20,9 +20,8 @@ class NetworkScanner(object): def initialize(self): """ - Set up scanning based on configuration - FixedRange -> Reads from range_fixed field in configuration - otherwise, takes a range from every IP address the current host has. + Set up scanning. + based on configuration: scans local network and/or scans fixed list of IPs/subnets. :return: """ # get local ip addresses @@ -33,13 +32,9 @@ class NetworkScanner(object): LOG.info("Found local IP addresses of the machine: %r", self._ip_addresses) # for fixed range, only scan once. - if WormConfiguration.range_class is FixedRange: - self._ranges = [WormConfiguration.range_class(fixed_addresses=WormConfiguration.range_fixed)] - else: - self._ranges = [WormConfiguration.range_class(ip_address) - for ip_address in self._ip_addresses] + self._ranges = [NetworkRange.get_range_obj(address_str=x) for x in WormConfiguration.range_fixed] if WormConfiguration.local_network_scan: - self._ranges += [FixedRange([ip_address for ip_address in get_ips_from_interfaces()])] + self._ranges += get_interfaces_ranges() LOG.info("Base local networks to scan are: %r", self._ranges) def get_victim_machines(self, scan_type, max_find=5, stop_callback=None): diff --git a/chaos_monkey/network/range.py b/chaos_monkey/network/range.py index 732749e3e..2698d6803 100644 --- a/chaos_monkey/network/range.py +++ b/chaos_monkey/network/range.py @@ -18,6 +18,32 @@ class NetworkRange(object): self._shuffle = shuffle self._config = __import__('config').WormConfiguration + def get_range(self): + return [x for x in self._get_range() if (x & 0xFF != 0)] # remove broadcast ips + + def __iter__(self): + base_range = self.get_range() + if self._shuffle: + random.shuffle(base_range) + + for x in base_range: + yield VictimHost(self._number_to_ip(self._base_address + x)) + + @abstractmethod + def _get_range(self): + raise NotImplementedError() + + @staticmethod + def get_range_obj(address_str): + address_str = address_str.strip() + if not address_str: # Empty string + return None + if -1 != address_str.find('-'): + return IpRange(ip_range=address_str) + if -1 != address_str.find('/'): + return CidrRange(cidr_range=address_str) + return SingleIpRange(ip_address=address_str) + @staticmethod def _ip_to_number(address): return struct.unpack(">L", socket.inet_aton(address))[0] @@ -26,18 +52,6 @@ class NetworkRange(object): def _number_to_ip(num): return socket.inet_ntoa(struct.pack(">L", num)) - @abstractmethod - def _get_range(self): - raise NotImplementedError() - - def __iter__(self): - base_range = self._get_range() - if self._shuffle: - random.shuffle(base_range) - - for x in base_range: - yield VictimHost(self._number_to_ip(self._base_address + x)) - class ClassCRange(NetworkRange): def __init__(self, base_address, shuffle=True): @@ -68,42 +82,65 @@ class RelativeRange(NetworkRange): return range(lower_end, higher_end + 1) -class FixedRange(NetworkRange): - def __init__(self, fixed_addresses, shuffle=True): +class CidrRange(NetworkRange): + def __init__(self, cidr_range, shuffle=True): base_address = 0 - super(FixedRange, self).__init__(base_address, shuffle=shuffle) - self._fixed_addresses = fixed_addresses + super(CidrRange, self).__init__(base_address, shuffle=shuffle) + self._cidr_range = cidr_range.strip() + self._ip_network = ipaddress.ip_network(unicode(self._cidr_range), strict=False) def __repr__(self): - return "" % (",".join(self._fixed_addresses)) + return "" % (self._cidr_range, ) - @staticmethod - def _cidr_range_to_ip_list(address_str): - return [FixedRange._ip_to_number(str(x)) for x in ipaddress.ip_network(unicode(address_str), strict=False)] - - @staticmethod - def _ip_range_to_ip_list(address_str): - addresses = address_str.split('-') - if len(addresses) != 2: - raise ValueError('Illegal address format: %s' % address_str) - lower_end, higher_end = [FixedRange._ip_to_number(x.strip()) for x in addresses] - if higher_end < lower_end: - raise ValueError('Illegal address range: %s' % address_str) - return range(lower_end, higher_end + 1) - - @staticmethod - def _parse_address_str(address_str): - address_str = address_str.strip() - if not address_str: # Empty string - return [] - if -1 != address_str.find('-'): - return FixedRange._ip_range_to_ip_list(address_str) - if -1 != address_str.find('/'): - return FixedRange._cidr_range_to_ip_list(address_str) - return [FixedRange._ip_to_number(address_str)] + def is_in_range(self, ip_address): + return ipaddress.ip_address(ip_address) in self._ip_network def _get_range(self): - ip_list = list(reduce( - lambda x, y: x.union(y), - [set(self._parse_address_str(z)) for z in self._fixed_addresses])) - return [x for x in ip_list if (x & 0xFF != 0)] # remove broadcast ips + return [CidrRange._ip_to_number(str(x)) for x in self._ip_network] + + +class IpRange(NetworkRange): + def __init__(self, ip_range=None, lower_end_ip=None, higher_end_ip=None, shuffle=True): + base_address = 0 + super(IpRange, self).__init__(base_address, shuffle=shuffle) + if ip_range is not None: + addresses = ip_range.split('-') + if len(addresses) != 2: + raise ValueError('Illegal IP range format: %s' % ip_range) + self._lower_end_ip, self._higher_end_ip = [x.strip() for x in addresses] + if self._higher_end_ip < self._lower_end_ip: + raise ValueError('Higher end IP is smaller than lower end IP: %s' % ip_range) + elif (lower_end_ip is not None) and (higher_end_ip is not None): + self._lower_end_ip = lower_end_ip + self._higher_end_ip = higher_end_ip + else: + raise ValueError('Illegal IP range: %s' % ip_range) + + self._lower_end_ip_num = IpRange._ip_to_number(self._lower_end_ip) + self._higher_end_ip_num = IpRange._ip_to_number(self._higher_end_ip) + + def __repr__(self): + return "" % (self._lower_end_ip, self._higher_end_ip) + + def is_in_range(self, ip_address): + return self._lower_end_ip_num <= IpRange._ip_to_number(ip_address) <= self._higher_end_ip_num + + def _get_range(self): + return range(self._lower_end_ip_num, self._higher_end_ip_num + 1) + + +class SingleIpRange(NetworkRange): + def __init__(self, ip_address, shuffle=True): + base_address = 0 + super(SingleIpRange, self).__init__(base_address, shuffle=shuffle) + self._ip_address = ip_address + + def __repr__(self): + return "" % (self._ip_address,) + + def is_in_range(self, ip_address): + return self._ip_address == ip_address + + def _get_range(self): + return [SingleIpRange._ip_to_number(self._ip_address)] + diff --git a/monkey_island/cc/services/config.py b/monkey_island/cc/services/config.py index 361854f05..f5aae69b4 100644 --- a/monkey_island/cc/services/config.py +++ b/monkey_island/cc/services/config.py @@ -205,25 +205,8 @@ SCHEMA = { "title": "Network range", "type": "object", "properties": { - "range_class": { - "title": "Range class", - "type": "string", - "default": "FixedRange", - "enum": [ - "FixedRange", - "ClassCRange" - ], - "enumNames": [ - "Fixed Range", - "Class C Range" - ], - "description": - "Determines which class to use to determine scan range." - " Fixed Range will scan only specific IPs listed under Fixed range IP list." - " Class C Range will scan machines in the Class C network the monkey's on." - }, "range_fixed": { - "title": "Fixed range IP/subnet list", + "title": "Scan IP/subnet list", "type": "array", "uniqueItems": True, "items": { @@ -232,8 +215,7 @@ SCHEMA = { "default": [ ], "description": - "List of IPs/subnets to include when using FixedRange" - " (Only relevant for Fixed Range)." + "List of IPs/subnets the monkey should scan." " Examples: \"192.168.0.1\", \"192.168.0.5-192.168.0.20\", \"192.168.0.5/24\"" } } diff --git a/monkey_island/cc/services/report.py b/monkey_island/cc/services/report.py index c197c55f3..848b572bc 100644 --- a/monkey_island/cc/services/report.py +++ b/monkey_island/cc/services/report.py @@ -315,8 +315,6 @@ class ReportService: @staticmethod def get_config_ips(): - if ConfigService.get_config_value(['basic_network', 'network_range', 'range_class'], True) != 'FixedRange': - return [] return ConfigService.get_config_value(['basic_network', 'network_range', 'range_fixed'], True) @staticmethod From 0de15736ac54c68061f88d6471d74b4df598e131 Mon Sep 17 00:00:00 2001 From: Itay Mizeretz Date: Mon, 26 Feb 2018 16:34:23 +0200 Subject: [PATCH 04/12] rename and move range_fixed --- infection_monkey/config.py | 2 +- infection_monkey/example.conf | 2 +- infection_monkey/network/network_scanner.py | 2 +- monkey_island/cc/services/config.py | 10 ++-------- monkey_island/cc/services/report.py | 2 +- 5 files changed, 6 insertions(+), 12 deletions(-) diff --git a/infection_monkey/config.py b/infection_monkey/config.py index b9a597f8b..d4710f906 100644 --- a/infection_monkey/config.py +++ b/infection_monkey/config.py @@ -181,7 +181,7 @@ class Configuration(object): # Auto detect and scan local subnets local_network_scan = True - range_fixed = ['', ] + subnet_scan_list = ['', ] blocked_ips = ['', ] diff --git a/infection_monkey/example.conf b/infection_monkey/example.conf index b100cf111..852c366d0 100644 --- a/infection_monkey/example.conf +++ b/infection_monkey/example.conf @@ -7,7 +7,7 @@ "www.google.com" ], "keep_tunnel_open_time": 60, - "range_fixed": [ + "subnet_scan_list": [ "" ], "blocked_ips": [""], diff --git a/infection_monkey/network/network_scanner.py b/infection_monkey/network/network_scanner.py index a62f4950e..7bdddc904 100644 --- a/infection_monkey/network/network_scanner.py +++ b/infection_monkey/network/network_scanner.py @@ -32,7 +32,7 @@ class NetworkScanner(object): LOG.info("Found local IP addresses of the machine: %r", self._ip_addresses) # for fixed range, only scan once. - self._ranges = [NetworkRange.get_range_obj(address_str=x) for x in WormConfiguration.range_fixed] + self._ranges = [NetworkRange.get_range_obj(address_str=x) for x in WormConfiguration.subnet_scan_list] if WormConfiguration.local_network_scan: self._ranges += get_interfaces_ranges() LOG.info("Base local networks to scan are: %r", self._ranges) diff --git a/monkey_island/cc/services/config.py b/monkey_island/cc/services/config.py index 133890760..a4b31728d 100644 --- a/monkey_island/cc/services/config.py +++ b/monkey_island/cc/services/config.py @@ -198,14 +198,8 @@ SCHEMA = { "Amount of hops allowed for the monkey to spread from the island. " + WARNING_SIGN + " Note that setting this value too high may result in the monkey propagating too far" - } - } - }, - "network_range": { - "title": "Network range", - "type": "object", - "properties": { - "range_fixed": { + }, + "subnet_scan_list": { "title": "Scan IP/subnet list", "type": "array", "uniqueItems": True, diff --git a/monkey_island/cc/services/report.py b/monkey_island/cc/services/report.py index 848b572bc..250acc17a 100644 --- a/monkey_island/cc/services/report.py +++ b/monkey_island/cc/services/report.py @@ -315,7 +315,7 @@ class ReportService: @staticmethod def get_config_ips(): - return ConfigService.get_config_value(['basic_network', 'network_range', 'range_fixed'], True) + return ConfigService.get_config_value(['basic_network', 'general', 'subnet_scan_list'], True) @staticmethod def get_config_scan(): From 4730480db96c1642582afa26f2325f1619195bdd Mon Sep 17 00:00:00 2001 From: Itay Mizeretz Date: Mon, 26 Feb 2018 17:35:00 +0200 Subject: [PATCH 05/12] Remove ClassCRange and RelativeRange --- infection_monkey/network/range.py | 29 ----------------------------- 1 file changed, 29 deletions(-) diff --git a/infection_monkey/network/range.py b/infection_monkey/network/range.py index 2698d6803..4e100378e 100644 --- a/infection_monkey/network/range.py +++ b/infection_monkey/network/range.py @@ -53,35 +53,6 @@ class NetworkRange(object): return socket.inet_ntoa(struct.pack(">L", num)) -class ClassCRange(NetworkRange): - def __init__(self, base_address, shuffle=True): - base_address = struct.unpack(">L", socket.inet_aton(base_address))[0] & 0xFFFFFF00 - super(ClassCRange, self).__init__(base_address, shuffle=shuffle) - - def __repr__(self): - return "" % (self._number_to_ip(self._base_address + 1), - self._number_to_ip(self._base_address + 254)) - - def _get_range(self): - return range(1, 254) - - -class RelativeRange(NetworkRange): - def __init__(self, base_address, shuffle=True): - base_address = struct.unpack(">L", socket.inet_aton(base_address))[0] - super(RelativeRange, self).__init__(base_address, shuffle=shuffle) - self._size = 1 - - def __repr__(self): - return "" % (self._number_to_ip(self._base_address - self._size), - self._number_to_ip(self._base_address + self._size)) - - def _get_range(self): - lower_end = -(self._size / 2) - higher_end = lower_end + self._size - return range(lower_end, higher_end + 1) - - class CidrRange(NetworkRange): def __init__(self, cidr_range, shuffle=True): base_address = 0 From 816be5191bd127ef73caa48bb66ebf93cfad8c23 Mon Sep 17 00:00:00 2001 From: Itay Mizeretz Date: Mon, 26 Feb 2018 17:35:32 +0200 Subject: [PATCH 06/12] Add is_in_range as abstract method --- infection_monkey/network/range.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/infection_monkey/network/range.py b/infection_monkey/network/range.py index 4e100378e..4eb4e122c 100644 --- a/infection_monkey/network/range.py +++ b/infection_monkey/network/range.py @@ -29,6 +29,10 @@ class NetworkRange(object): for x in base_range: yield VictimHost(self._number_to_ip(self._base_address + x)) + @abstractmethod + def is_in_range(self, ip_address): + raise NotImplementedError() + @abstractmethod def _get_range(self): raise NotImplementedError() From e57ce1099f4a830113ee31094118638c6cb7cf84 Mon Sep 17 00:00:00 2001 From: Itay Mizeretz Date: Mon, 26 Feb 2018 17:53:16 +0200 Subject: [PATCH 07/12] Remove unecessary parameters and members. Create better abstraction --- infection_monkey/network/network_scanner.py | 3 ++- infection_monkey/network/range.py | 20 ++++++-------------- 2 files changed, 8 insertions(+), 15 deletions(-) diff --git a/infection_monkey/network/network_scanner.py b/infection_monkey/network/network_scanner.py index 7bdddc904..df1b4f369 100644 --- a/infection_monkey/network/network_scanner.py +++ b/infection_monkey/network/network_scanner.py @@ -45,7 +45,8 @@ class NetworkScanner(object): for net_range in self._ranges: LOG.debug("Scanning for potential victims in the network %r", net_range) - for victim in net_range: + for ip_addr in net_range: + victim = VictimHost(ip_addr) if stop_callback and stop_callback(): LOG.debug("Got stop signal") break diff --git a/infection_monkey/network/range.py b/infection_monkey/network/range.py index 4eb4e122c..31a88e0df 100644 --- a/infection_monkey/network/range.py +++ b/infection_monkey/network/range.py @@ -5,18 +5,14 @@ from abc import ABCMeta, abstractmethod import ipaddress -from model.host import VictimHost - __author__ = 'itamar' class NetworkRange(object): __metaclass__ = ABCMeta - def __init__(self, base_address, shuffle=True): - self._base_address = base_address + def __init__(self, shuffle=True): self._shuffle = shuffle - self._config = __import__('config').WormConfiguration def get_range(self): return [x for x in self._get_range() if (x & 0xFF != 0)] # remove broadcast ips @@ -27,7 +23,7 @@ class NetworkRange(object): random.shuffle(base_range) for x in base_range: - yield VictimHost(self._number_to_ip(self._base_address + x)) + yield self._number_to_ip(x) @abstractmethod def is_in_range(self, ip_address): @@ -59,13 +55,12 @@ class NetworkRange(object): class CidrRange(NetworkRange): def __init__(self, cidr_range, shuffle=True): - base_address = 0 - super(CidrRange, self).__init__(base_address, shuffle=shuffle) + super(CidrRange, self).__init__(shuffle=shuffle) self._cidr_range = cidr_range.strip() self._ip_network = ipaddress.ip_network(unicode(self._cidr_range), strict=False) def __repr__(self): - return "" % (self._cidr_range, ) + return "" % (self._cidr_range,) def is_in_range(self, ip_address): return ipaddress.ip_address(ip_address) in self._ip_network @@ -76,8 +71,7 @@ class CidrRange(NetworkRange): class IpRange(NetworkRange): def __init__(self, ip_range=None, lower_end_ip=None, higher_end_ip=None, shuffle=True): - base_address = 0 - super(IpRange, self).__init__(base_address, shuffle=shuffle) + super(IpRange, self).__init__(shuffle=shuffle) if ip_range is not None: addresses = ip_range.split('-') if len(addresses) != 2: @@ -106,8 +100,7 @@ class IpRange(NetworkRange): class SingleIpRange(NetworkRange): def __init__(self, ip_address, shuffle=True): - base_address = 0 - super(SingleIpRange, self).__init__(base_address, shuffle=shuffle) + super(SingleIpRange, self).__init__(shuffle=shuffle) self._ip_address = ip_address def __repr__(self): @@ -118,4 +111,3 @@ class SingleIpRange(NetworkRange): def _get_range(self): return [SingleIpRange._ip_to_number(self._ip_address)] - From 1d07e5f98fc792cbf3ea513b6106570a72d3a181 Mon Sep 17 00:00:00 2001 From: Itay Mizeretz Date: Mon, 26 Feb 2018 18:39:49 +0200 Subject: [PATCH 08/12] Move range to common code folder --- common/__init__.py | 1 + common/network/__init__.py | 1 + {infection_monkey => common}/network/range.py | 0 infection_monkey/monkey-linux.spec | 2 +- infection_monkey/monkey.spec | 2 +- infection_monkey/network/info.py | 2 +- infection_monkey/network/network_scanner.py | 3 ++- 7 files changed, 7 insertions(+), 4 deletions(-) create mode 100644 common/__init__.py create mode 100644 common/network/__init__.py rename {infection_monkey => common}/network/range.py (100%) diff --git a/common/__init__.py b/common/__init__.py new file mode 100644 index 000000000..ee5b79ad0 --- /dev/null +++ b/common/__init__.py @@ -0,0 +1 @@ +__author__ = 'itay.mizeretz' diff --git a/common/network/__init__.py b/common/network/__init__.py new file mode 100644 index 000000000..ee5b79ad0 --- /dev/null +++ b/common/network/__init__.py @@ -0,0 +1 @@ +__author__ = 'itay.mizeretz' diff --git a/infection_monkey/network/range.py b/common/network/range.py similarity index 100% rename from infection_monkey/network/range.py rename to common/network/range.py diff --git a/infection_monkey/monkey-linux.spec b/infection_monkey/monkey-linux.spec index c8c4c631b..fac69536e 100644 --- a/infection_monkey/monkey-linux.spec +++ b/infection_monkey/monkey-linux.spec @@ -4,7 +4,7 @@ block_cipher = None a = Analysis(['main.py'], - pathex=['.'], + pathex=['.', '..'], binaries=None, datas=None, hiddenimports=['_cffi_backend'], diff --git a/infection_monkey/monkey.spec b/infection_monkey/monkey.spec index 8e004145b..cb9c6130e 100644 --- a/infection_monkey/monkey.spec +++ b/infection_monkey/monkey.spec @@ -2,7 +2,7 @@ import os import platform a = Analysis(['main.py'], - pathex=['.'], + pathex=['.', '..'], hiddenimports=['_cffi_backend', 'queue'], hookspath=None, runtime_hooks=None) diff --git a/infection_monkey/network/info.py b/infection_monkey/network/info.py index 30a75780e..da30e7b0f 100644 --- a/infection_monkey/network/info.py +++ b/infection_monkey/network/info.py @@ -8,7 +8,7 @@ import itertools import netifaces from subprocess import check_output from random import randint -from range import CidrRange +from common.network.range import CidrRange def get_host_subnets(): diff --git a/infection_monkey/network/network_scanner.py b/infection_monkey/network/network_scanner.py index df1b4f369..7837e36c3 100644 --- a/infection_monkey/network/network_scanner.py +++ b/infection_monkey/network/network_scanner.py @@ -3,7 +3,8 @@ import time from config import WormConfiguration from info import local_ips, get_interfaces_ranges -from range import * +from common.network.range import * +from model import VictimHost from . import HostScanner __author__ = 'itamar' From fcb5b8f85d91ddf831fb22f8c09c05ed035e9b1f Mon Sep 17 00:00:00 2001 From: Itay Mizeretz Date: Wed, 11 Apr 2018 11:28:59 +0300 Subject: [PATCH 09/12] Fix CR --- common/network/{range.py => network_range.py} | 4 ++-- infection_monkey/network/info.py | 2 +- infection_monkey/network/network_scanner.py | 2 +- infection_monkey/requirements.txt | 1 + 4 files changed, 5 insertions(+), 4 deletions(-) rename common/network/{range.py => network_range.py} (97%) diff --git a/common/network/range.py b/common/network/network_range.py similarity index 97% rename from common/network/range.py rename to common/network/network_range.py index 31a88e0df..b7ca686aa 100644 --- a/common/network/range.py +++ b/common/network/network_range.py @@ -15,7 +15,7 @@ class NetworkRange(object): self._shuffle = shuffle def get_range(self): - return [x for x in self._get_range() if (x & 0xFF != 0)] # remove broadcast ips + return self._get_range() def __iter__(self): base_range = self.get_range() @@ -66,7 +66,7 @@ class CidrRange(NetworkRange): return ipaddress.ip_address(ip_address) in self._ip_network def _get_range(self): - return [CidrRange._ip_to_number(str(x)) for x in self._ip_network] + return [CidrRange._ip_to_number(str(x)) for x in self._ip_network if x != self._ip_network.broadcast_address] class IpRange(NetworkRange): diff --git a/infection_monkey/network/info.py b/infection_monkey/network/info.py index da30e7b0f..7c208dce4 100644 --- a/infection_monkey/network/info.py +++ b/infection_monkey/network/info.py @@ -8,7 +8,7 @@ import itertools import netifaces from subprocess import check_output from random import randint -from common.network.range import CidrRange +from common.network.network_range import CidrRange def get_host_subnets(): diff --git a/infection_monkey/network/network_scanner.py b/infection_monkey/network/network_scanner.py index 7837e36c3..563b04b6d 100644 --- a/infection_monkey/network/network_scanner.py +++ b/infection_monkey/network/network_scanner.py @@ -3,7 +3,7 @@ import time from config import WormConfiguration from info import local_ips, get_interfaces_ranges -from common.network.range import * +from common.network.network_range import * from model import VictimHost from . import HostScanner diff --git a/infection_monkey/requirements.txt b/infection_monkey/requirements.txt index 2c96e311c..bd7689886 100644 --- a/infection_monkey/requirements.txt +++ b/infection_monkey/requirements.txt @@ -14,3 +14,4 @@ ecdsa netifaces mock nose +ipaddress \ No newline at end of file From 7eb2a5c98b26697a29870f051e04eb3fb0840c64 Mon Sep 17 00:00:00 2001 From: Daniel Goldberg Date: Thu, 12 Apr 2018 14:57:22 +0300 Subject: [PATCH 10/12] Remove class C limitation when getting local subnet --- infection_monkey/network/info.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/infection_monkey/network/info.py b/infection_monkey/network/info.py index 7c208dce4..179befd4f 100644 --- a/infection_monkey/network/info.py +++ b/infection_monkey/network/info.py @@ -143,10 +143,7 @@ def get_interfaces_ranges(): netmask_str = net_interface['netmask'] ip_interface = ipaddress.ip_interface(u"%s/%s" % (address_str, netmask_str)) # limit subnet scans to class C only - if ip_interface.network.num_addresses > 255: - res.append(CidrRange(cidr_range="%s/24" % (address_str, ))) - else: - res.append(CidrRange(cidr_range="%s/%s" % (address_str, netmask_str))) + res.append(CidrRange(cidr_range="%s/%s" % (address_str, netmask_str))) return res From 84a678ba5a6e09b0960f34d69198bc8be60c7d16 Mon Sep 17 00:00:00 2001 From: Daniel Goldberg Date: Thu, 12 Apr 2018 15:53:31 +0300 Subject: [PATCH 11/12] Bugfix in creating IpRange object + clearer error message --- common/network/network_range.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/common/network/network_range.py b/common/network/network_range.py index b7ca686aa..66910ff0d 100644 --- a/common/network/network_range.py +++ b/common/network/network_range.py @@ -75,24 +75,24 @@ class IpRange(NetworkRange): if ip_range is not None: addresses = ip_range.split('-') if len(addresses) != 2: - raise ValueError('Illegal IP range format: %s' % ip_range) + raise ValueError('Illegal IP range format: %s. Format is 192.168.0.5-192.168.0.20' % ip_range) self._lower_end_ip, self._higher_end_ip = [x.strip() for x in addresses] - if self._higher_end_ip < self._lower_end_ip: - raise ValueError('Higher end IP is smaller than lower end IP: %s' % ip_range) elif (lower_end_ip is not None) and (higher_end_ip is not None): - self._lower_end_ip = lower_end_ip - self._higher_end_ip = higher_end_ip + self._lower_end_ip = lower_end_ip.strip() + self._higher_end_ip = higher_end_ip.strip() else: raise ValueError('Illegal IP range: %s' % ip_range) - self._lower_end_ip_num = IpRange._ip_to_number(self._lower_end_ip) - self._higher_end_ip_num = IpRange._ip_to_number(self._higher_end_ip) + self._lower_end_ip_num = self._ip_to_number(self._lower_end_ip) + self._higher_end_ip_num = self._ip_to_number(self._higher_end_ip) + if self._higher_end_ip_num < self._lower_end_ip_num: + raise ValueError('Higher end IP %s is smaller than lower end IP %s' % (self._lower_end_ip,self._higher_end_ip)) def __repr__(self): return "" % (self._lower_end_ip, self._higher_end_ip) def is_in_range(self, ip_address): - return self._lower_end_ip_num <= IpRange._ip_to_number(ip_address) <= self._higher_end_ip_num + return self._lower_end_ip_num <= self._ip_to_number(ip_address) <= self._higher_end_ip_num def _get_range(self): return range(self._lower_end_ip_num, self._higher_end_ip_num + 1) From a77044dbf015b45feb0ead16bc095fcbe018d4dc Mon Sep 17 00:00:00 2001 From: Daniel Goldberg Date: Thu, 12 Apr 2018 15:58:58 +0300 Subject: [PATCH 12/12] Add quick documentation for get_range and __iter__ in base class --- common/network/network_range.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/common/network/network_range.py b/common/network/network_range.py index 66910ff0d..0173b5810 100644 --- a/common/network/network_range.py +++ b/common/network/network_range.py @@ -15,9 +15,17 @@ class NetworkRange(object): self._shuffle = shuffle def get_range(self): + """ + :return: Returns a sequence of IPs in an internal format (might be numbers) + """ return self._get_range() def __iter__(self): + """ + Iterator of ip addresses (strings) from the current range. + Use get_range if you want it in one go. + :return: + """ base_range = self.get_range() if self._shuffle: random.shuffle(base_range) @@ -86,7 +94,8 @@ class IpRange(NetworkRange): self._lower_end_ip_num = self._ip_to_number(self._lower_end_ip) self._higher_end_ip_num = self._ip_to_number(self._higher_end_ip) if self._higher_end_ip_num < self._lower_end_ip_num: - raise ValueError('Higher end IP %s is smaller than lower end IP %s' % (self._lower_end_ip,self._higher_end_ip)) + raise ValueError( + 'Higher end IP %s is smaller than lower end IP %s' % (self._lower_end_ip, self._higher_end_ip)) def __repr__(self): return "" % (self._lower_end_ip, self._higher_end_ip)