|
@@ -13,6 +13,7 @@ from multiprocessing import Process, SimpleQueue
|
|
from group import Group
|
|
from group import Group
|
|
import scanner_wrapper
|
|
import scanner_wrapper
|
|
import group_handler
|
|
import group_handler
|
|
|
|
+import report_fetcher
|
|
|
|
|
|
import ipv4
|
|
import ipv4
|
|
from utility import ip_str_to_bytes
|
|
from utility import ip_str_to_bytes
|
|
@@ -52,7 +53,7 @@ class ProbeResponseAttackLogic(object):
|
|
Implemenration of the probe response attack using dedicated scanner for probing.
|
|
Implemenration of the probe response attack using dedicated scanner for probing.
|
|
Workflow:
|
|
Workflow:
|
|
>> Stage 1:
|
|
>> Stage 1:
|
|
- - Send probes without creating initial groups (saves state information) -> create Groups WHILE scanning
|
|
|
|
|
|
+ - Send probes without creating initial groups (saves state information) -> create Groups WHILE getting feedback
|
|
- Get result and add Groups to _iterations[index_iteration]
|
|
- Get result and add Groups to _iterations[index_iteration]
|
|
- Create groups: Check scanner feedback and re-group per sub-group based on it
|
|
- Create groups: Check scanner feedback and re-group per sub-group based on it
|
|
|
|
|
|
@@ -64,7 +65,7 @@ class ProbeResponseAttackLogic(object):
|
|
source IP address, source port, destination port etc.
|
|
source IP address, source port, destination port etc.
|
|
|
|
|
|
Pre-filtering of noisy values:
|
|
Pre-filtering of noisy values:
|
|
- - Noisy marker values do not get pre-filtered as this problem can be effectively
|
|
|
|
|
|
+ - Noisy marker values don't need to get pre-filtered as this problem can be effectively
|
|
mitigated using a trade off between marker/checksum-bits.
|
|
mitigated using a trade off between marker/checksum-bits.
|
|
|
|
|
|
Detection mitigation:
|
|
Detection mitigation:
|
|
@@ -75,6 +76,8 @@ class ProbeResponseAttackLogic(object):
|
|
low number for a specific port "p", which is hard to detect as statistic anomaly.
|
|
low number for a specific port "p", which is hard to detect as statistic anomaly.
|
|
"""
|
|
"""
|
|
|
|
|
|
|
|
+ # Default parameters to be set. This is more efficient flexible
|
|
|
|
+ # than explicitly setting them in __init__() via self._xyz...
|
|
PROP_DEFAULTS = {
|
|
PROP_DEFAULTS = {
|
|
# network options
|
|
# network options
|
|
"interface_name": "eth0",
|
|
"interface_name": "eth0",
|
|
@@ -101,7 +104,6 @@ class ProbeResponseAttackLogic(object):
|
|
"_group_storeindex": 0,
|
|
"_group_storeindex": 0,
|
|
"use_feedback_ips": False,
|
|
"use_feedback_ips": False,
|
|
"use_plus1": False,
|
|
"use_plus1": False,
|
|
- # TODO: change for testing
|
|
|
|
"is_simulation": False,
|
|
"is_simulation": False,
|
|
# debugging options
|
|
# debugging options
|
|
# avoid scanning the whole network -> limit to a subnet (default is: scan whole IPv4 - blacklist)
|
|
# avoid scanning the whole network -> limit to a subnet (default is: scan whole IPv4 - blacklist)
|
|
@@ -109,7 +111,6 @@ class ProbeResponseAttackLogic(object):
|
|
"_cidr_bits_stage1": 0
|
|
"_cidr_bits_stage1": 0
|
|
}
|
|
}
|
|
|
|
|
|
-
|
|
|
|
def __init__(self, **kwargs):
|
|
def __init__(self, **kwargs):
|
|
# set default values, will be overwritten by config variables
|
|
# set default values, will be overwritten by config variables
|
|
# parameter hierarchy: default -> constructor
|
|
# parameter hierarchy: default -> constructor
|
|
@@ -138,6 +139,8 @@ class ProbeResponseAttackLogic(object):
|
|
self._filename_identified_monitors = os.path.join(self.base_dir_save, "identified_monitors.csv")
|
|
self._filename_identified_monitors = os.path.join(self.base_dir_save, "identified_monitors.csv")
|
|
self._dirname_scanner_logs = self.base_dir_save
|
|
self._dirname_scanner_logs = self.base_dir_save
|
|
|
|
|
|
|
|
+ # set default report Fetcher if anything goes wrong
|
|
|
|
+ self._reportfetcher_class = report_fetcher.TracingReportFetcher
|
|
self.set_report_fetcher_class(self.report_fetcher_classname)
|
|
self.set_report_fetcher_class(self.report_fetcher_classname)
|
|
self._report_fetcher = None
|
|
self._report_fetcher = None
|
|
|
|
|
|
@@ -157,7 +160,7 @@ class ProbeResponseAttackLogic(object):
|
|
self.marker_checksum_bytes_amount = math.ceil(self.markerbits_checksum / 8)
|
|
self.marker_checksum_bytes_amount = math.ceil(self.markerbits_checksum / 8)
|
|
|
|
|
|
# Groups which got/get scanned.
|
|
# Groups which got/get scanned.
|
|
- # [[start, stop], {marke: Group}, total groups, total addresses]
|
|
|
|
|
|
+ # [[start, stop], {marker: Group}, total groups, total addresses]
|
|
self._iterations = []
|
|
self._iterations = []
|
|
self._iterations.append([[0, 0], {}, 0, 0])
|
|
self._iterations.append([[0, 0], {}, 0, 0])
|
|
initial_group = Group(ip_network_object=IPv4Network(nw_ip_str=self._ip_stage1,
|
|
initial_group = Group(ip_network_object=IPv4Network(nw_ip_str=self._ip_stage1,
|
|
@@ -191,6 +194,9 @@ class ProbeResponseAttackLogic(object):
|
|
self._create_marker_bitlevel)
|
|
self._create_marker_bitlevel)
|
|
self._initial_count = 0
|
|
self._initial_count = 0
|
|
|
|
|
|
|
|
+ iterations = property(lambda self: self._iterations)
|
|
|
|
+ grouphandler = property(lambda self: self._grouphandler)
|
|
|
|
+
|
|
def set_report_fetcher_class(self, classname):
|
|
def set_report_fetcher_class(self, classname):
|
|
if self._running:
|
|
if self._running:
|
|
return
|
|
return
|
|
@@ -301,7 +307,7 @@ class ProbeResponseAttackLogic(object):
|
|
# 1.2.3.4 -> 1.2 = marker value
|
|
# 1.2.3.4 -> 1.2 = marker value
|
|
top_group_markervalue = address_obj.ip_int >> bits_shift_ip
|
|
top_group_markervalue = address_obj.ip_int >> bits_shift_ip
|
|
|
|
|
|
- if not top_group_markervalue in groups_stage1:
|
|
|
|
|
|
+ if top_group_markervalue not in groups_stage1:
|
|
#logger.derbug("skipping IP not belonging in initial groups: %r" % address_obj)
|
|
#logger.derbug("skipping IP not belonging in initial groups: %r" % address_obj)
|
|
continue
|
|
continue
|
|
except Exception as ex:
|
|
except Exception as ex:
|
|
@@ -470,7 +476,8 @@ class ProbeResponseAttackLogic(object):
|
|
fd_write.write(line)
|
|
fd_write.write(line)
|
|
#logger.debug(line.strip())
|
|
#logger.debug(line.strip())
|
|
fd_write.close()
|
|
fd_write.close()
|
|
- self._save_state()
|
|
|
|
|
|
+ # disable to save space
|
|
|
|
+ #self._save_state()
|
|
|
|
|
|
def _start_native_prober(self):
|
|
def _start_native_prober(self):
|
|
"""
|
|
"""
|
|
@@ -495,7 +502,8 @@ class ProbeResponseAttackLogic(object):
|
|
logger.debug("waiting some seconds for processess to settle")
|
|
logger.debug("waiting some seconds for processess to settle")
|
|
time.sleep(1)
|
|
time.sleep(1)
|
|
|
|
|
|
- def _probe_native_cycler(self, cnt, sockethndl, groupqueue, ip_blacklist, mac_src_s, mac_dst_s, ip_src_s, marker_encoding):
|
|
|
|
|
|
+ def _probe_native_cycler(self, cnt, sockethndl, groupqueue, ip_blacklist,
|
|
|
|
+ mac_src_s, mac_dst_s, ip_src_s, marker_encoding):
|
|
"""
|
|
"""
|
|
A native prober cycler to be used with processes.
|
|
A native prober cycler to be used with processes.
|
|
"""
|
|
"""
|
|
@@ -559,7 +567,8 @@ class ProbeResponseAttackLogic(object):
|
|
|
|
|
|
# after initial full scan
|
|
# after initial full scan
|
|
if self._group_storeindex >= 2:
|
|
if self._group_storeindex >= 2:
|
|
- logger.info("initiating subgrouping using group handler, top groups=%d" % len(self._iterations[self._group_storeindex - 1][1]))
|
|
|
|
|
|
+ logger.info("initiating subgrouping using group handler, top groups=%d" %
|
|
|
|
+ len(self._iterations[self._group_storeindex - 1][1]))
|
|
|
|
|
|
if self.use_feedback_ips and self._group_storeindex == 2:
|
|
if self.use_feedback_ips and self._group_storeindex == 2:
|
|
self._read_scanner_feedback_addresses()
|
|
self._read_scanner_feedback_addresses()
|
|
@@ -655,7 +664,6 @@ class ProbeResponseAttackLogic(object):
|
|
(group.amount_addresses, group, group.marker_value_int))
|
|
(group.amount_addresses, group, group.marker_value_int))
|
|
# time.sleep(2)
|
|
# time.sleep(2)
|
|
scan_timeout = -1
|
|
scan_timeout = -1
|
|
- # TODO: just for testing: stop scanning after x seconds
|
|
|
|
|
|
|
|
"""
|
|
"""
|
|
if self._group_storeindex == 1:
|
|
if self._group_storeindex == 1:
|
|
@@ -665,7 +673,7 @@ class ProbeResponseAttackLogic(object):
|
|
"""
|
|
"""
|
|
# group.markervalue: this is None in the first stage -> encode target address
|
|
# group.markervalue: this is None in the first stage -> encode target address
|
|
# checksum: ZMap module got his own implementation which is needed by stage 0
|
|
# checksum: ZMap module got his own implementation which is needed by stage 0
|
|
- # (create checksum of IP addresses from whole IPv4 address range)
|
|
|
|
|
|
+ # (create checksum of IP addresses)
|
|
scanner = scanner_wrapper.ZmapWrapper(
|
|
scanner = scanner_wrapper.ZmapWrapper(
|
|
filename_output_csv=filename_output_csv,
|
|
filename_output_csv=filename_output_csv,
|
|
filename_blacklist_target_ip=blacklist,
|
|
filename_blacklist_target_ip=blacklist,
|
|
@@ -709,13 +717,25 @@ class ProbeResponseAttackLogic(object):
|
|
int(self._iterations[self._group_storeindex][0][1] - self._iterations[self._group_storeindex][0][0]),
|
|
int(self._iterations[self._group_storeindex][0][1] - self._iterations[self._group_storeindex][0][0]),
|
|
len(self._iterations[self._group_storeindex][1])))
|
|
len(self._iterations[self._group_storeindex][1])))
|
|
|
|
|
|
|
|
+ # root -> 1st stage -> 2nd stage
|
|
if self._group_storeindex >= 2:
|
|
if self._group_storeindex >= 2:
|
|
if self.use_plus1:
|
|
if self.use_plus1:
|
|
group_handler_obj.update_plus1_subgroups(self._iterations[self._group_storeindex - 1][1])
|
|
group_handler_obj.update_plus1_subgroups(self._iterations[self._group_storeindex - 1][1])
|
|
|
|
+
|
|
|
|
+ # update amount of groups
|
|
|
|
+ logger.debug("updating amount of groups")
|
|
self._iterations[self._group_storeindex][2] = len(self._iterations[self._group_storeindex][1])
|
|
self._iterations[self._group_storeindex][2] = len(self._iterations[self._group_storeindex][1])
|
|
|
|
+ # update total addresses
|
|
|
|
+ logger.debug("updating total addresses")
|
|
self._iterations[self._group_storeindex][3] = sum([group.amount_addresses
|
|
self._iterations[self._group_storeindex][3] = sum([group.amount_addresses
|
|
- for _,group in self._iterations[self._group_storeindex][1].items()])
|
|
|
|
|
|
+ for _, group in self._iterations[self._group_storeindex][1].items()])
|
|
group_handler_obj.remove_empty_groups(self._iterations[self._group_storeindex][1])
|
|
group_handler_obj.remove_empty_groups(self._iterations[self._group_storeindex][1])
|
|
|
|
+
|
|
|
|
+ # now everything should be uptodate, cleanup groups of last round
|
|
|
|
+ if self._group_storeindex >= 2:
|
|
|
|
+ # TODO: activate if needed
|
|
|
|
+ group_handler_obj.cleanup_groups(self._iterations[self._group_storeindex - 1][1])
|
|
|
|
+
|
|
self.stop()
|
|
self.stop()
|
|
|
|
|
|
def get_amount_of_probes(self):
|
|
def get_amount_of_probes(self):
|