Browse Source

Merge branch 'benchmark_final' of stefan.schmidt/ID2T-toolkit into master

Carlos Garcia 6 years ago
parent
commit
d9437bf5c8

+ 53 - 17
code/Attack/BaseAttack.py

@@ -5,6 +5,7 @@ import os
 import random
 import re
 import tempfile
+import time
 import numpy as np
 
 from abc import abstractmethod, ABCMeta
@@ -14,7 +15,7 @@ from scapy.utils import PcapWriter
 from Attack import AttackParameters
 from Attack.AttackParameters import Parameter
 from Attack.AttackParameters import ParameterTypes
-from ID2TLib.Utility import handle_most_used_outputs
+import ID2TLib.Utility as Util
 from lea import Lea
 import ID2TLib.libpcapreader as pr
 
@@ -44,6 +45,10 @@ class BaseAttack(metaclass=ABCMeta):
         self.supported_params = {}
         self.attack_start_utime = 0
         self.attack_end_utime = 0
+        self.start_time = 0
+        self.finish_time = 0
+        self.packets = []
+        self.path_attack_pcap = ""
 
     def set_statistics(self, statistics):
         """
@@ -64,6 +69,13 @@ class BaseAttack(metaclass=ABCMeta):
         """
         pass
 
+    @abstractmethod
+    def generate_attack_packets(self):
+        """
+        Creates the attack packets.
+        """
+        pass
+
     @abstractmethod
     def generate_attack_pcap(self):
         """
@@ -103,26 +115,44 @@ class BaseAttack(metaclass=ABCMeta):
         Verifies that the given string or list of IP addresses (strings) is a valid IPv4/IPv6 address.
         Accepts comma-separated lists of IP addresses, like "192.169.178.1, 192.168.178.2"
 
-        :param ip_address: The IP address(es) as list of strings or comma-separated string.
+        :param ip_address: The IP address(es) as list of strings, comma-separated or dash-separated string.
         :return: True if all IP addresses are valid, otherwise False. And a list of IP addresses as string.
         """
+        def append_ips(ip_address_input):
+            """
+            Recursive appending function to handle lists and ranges of IP addresses.
+
+            :param ip_address_input: The IP address(es) as list of strings, comma-separated or dash-separated string.
+            :return: List of all given IP addresses.
+            """
+            ip_list = []
+            is_valid = True
+            for ip in ip_address_input:
+                if '-' in ip:
+                    ip_range = ip.split('-')
+                    ip_range = Util.get_ip_range(ip_range[0], ip_range[1])
+                    is_valid, ips = append_ips(ip_range)
+                    ip_list.extend(ips)
+                else:
+                    try:
+                        ipaddress.ip_address(ip)
+                        ip_list.append(ip)
+                    except ValueError:
+                        return False, ip_list
+            return is_valid, ip_list
+
         ip_address_output = []
 
         # a comma-separated list of IP addresses must be splitted first
         if isinstance(ip_address, str):
             ip_address = ip_address.split(',')
 
-        for ip in ip_address:
-            try:
-                ipaddress.ip_address(ip)
-                ip_address_output.append(ip)
-            except ValueError:
-                return False, ip_address_output
+        result, ip_address_output = append_ips(ip_address)
 
         if len(ip_address_output) == 1:
-            return True, ip_address_output[0]
+            return result, ip_address_output[0]
         else:
-            return True, ip_address_output
+            return result, ip_address_output
 
     @staticmethod
     def _is_port(ports_input: str):
@@ -260,6 +290,15 @@ class BaseAttack(metaclass=ABCMeta):
         if isinstance(seed, int):
             random.seed(seed)
 
+    def set_start_time(self):
+        self.start_time = time.time()
+
+    def set_finish_time(self):
+        self.finish_time = time.time()
+
+    def get_packet_generation_time(self):
+        return self.finish_time - self.start_time
+
     def add_param_value(self, param, value):
         """
         Adds the pair param : value to the dictionary of attack parameters. Prints and error message and skips the
@@ -420,7 +459,7 @@ class BaseAttack(metaclass=ABCMeta):
         maxDelay = int(maxDelay) * 10 ** -6
         return minDelay, maxDelay
 
-    def packetsToConvs(self,exploit_raw_packets):
+    def packets_to_convs(self,exploit_raw_packets):
         """
            Classifies a bunch of packets to conversations groups. A conversation is a set of packets go between host A (IP,port)
            to host B (IP,port)
@@ -460,7 +499,6 @@ class BaseAttack(metaclass=ABCMeta):
                     conversations[conv_rep] = pktList
         return (conversations, orderList_conversations)
 
-
     def is_valid_ip_address(self,addr):
         """
         Checks if the IP address family is supported.
@@ -492,7 +530,6 @@ class BaseAttack(metaclass=ABCMeta):
             print("\nERROR: Invalid IP addresses; source IP is the same as destination IP: " + ip_destination + ".")
             sys.exit(0)
 
-
     def get_inter_arrival_time(self, packets, distribution:bool=False):
         """
         Gets the inter-arrival times array and its distribution of a set of packets.
@@ -525,7 +562,6 @@ class BaseAttack(metaclass=ABCMeta):
         else:
             return inter_arrival_times
 
-
     def clean_white_spaces(self, str):
         """
         Delete extra backslash from white spaces. This function is used to process the payload of packets.
@@ -567,7 +603,7 @@ class BaseAttack(metaclass=ABCMeta):
             mss_prob_dict = Lea.fromValFreqsDict(mss_dist)
             mss_value = mss_prob_dict.random()
         else:
-            mss_value = handle_most_used_outputs(self.statistics.process_db_query("most_used(mssValue)"))
+            mss_value = Util.handle_most_used_outputs(self.statistics.process_db_query("most_used(mssValue)"))
 
         # Set TTL based on TTL distribution of IP address
         ttl_dist = self.statistics.get_ttl_distribution(ip_address)
@@ -575,7 +611,7 @@ class BaseAttack(metaclass=ABCMeta):
             ttl_prob_dict = Lea.fromValFreqsDict(ttl_dist)
             ttl_value = ttl_prob_dict.random()
         else:
-            ttl_value = handle_most_used_outputs(self.statistics.process_db_query("most_used(ttlValue)"))
+            ttl_value = Util.handle_most_used_outputs(self.statistics.process_db_query("most_used(ttlValue)"))
 
         # Set Window Size based on Window Size distribution of IP address
         win_dist = self.statistics.get_win_distribution(ip_address)
@@ -583,7 +619,7 @@ class BaseAttack(metaclass=ABCMeta):
             win_prob_dict = Lea.fromValFreqsDict(win_dist)
             win_value = win_prob_dict.random()
         else:
-            win_value = handle_most_used_outputs(self.statistics.process_db_query("most_used(winSize)"))
+            win_value = Util.handle_most_used_outputs(self.statistics.process_db_query("most_used(winSize)"))
 
         return mss_value, ttl_value, win_value
 

+ 23 - 19
code/Attack/DDoSAttack.py

@@ -27,6 +27,9 @@ class DDoSAttack(BaseAttack.BaseAttack):
         super(DDoSAttack, self).__init__("DDoS Attack", "Injects a DDoS attack'",
                                         "Resource Exhaustion")
 
+        self.last_packet = None
+        self.total_pkt_num = 0
+
         # Define allowed parameters and their type
         self.supported_params.update({
             Param.IP_SOURCE: ParameterTypes.TYPE_IP_ADDRESS,
@@ -74,7 +77,7 @@ class DDoSAttack(BaseAttack.BaseAttack):
         self.add_param_value(Param.MAC_DESTINATION, destination_mac)
         self.add_param_value(Param.VICTIM_BUFFER, randint(1000,10000))
 
-    def generate_attack_pcap(self):
+    def generate_attack_packets(self):
         BUFFER_SIZE = 1000
 
         # Determine source IP and MAC address
@@ -93,7 +96,7 @@ class DDoSAttack(BaseAttack.BaseAttack):
             num_attackers = len(ip_source_list)
 
         # Initialize parameters
-        packets = deque(maxlen=BUFFER_SIZE)
+        self.packets = deque(maxlen=BUFFER_SIZE)
         port_source_list = self.get_param_value(Param.PORT_SOURCE)
         mac_destination = self.get_param_value(Param.MAC_DESTINATION)
         ip_destination = self.get_param_value(Param.IP_DESTINATION)
@@ -134,7 +137,7 @@ class DDoSAttack(BaseAttack.BaseAttack):
         alpha, loc, beta = (2.3261710235, -0.188306914406, 44.4853123884)
         gd = gamma.rvs(alpha, loc=loc, scale=beta, size=len(ip_source_list))
 
-        path_attack_pcap = None
+        self.path_attack_pcap = None
 
         timestamp_prv_reply, timestamp_confirm = 0, 0
         minDelay, maxDelay = self.get_reply_delay(ip_destination)
@@ -162,7 +165,7 @@ class DDoSAttack(BaseAttack.BaseAttack):
         mss_dst = handle_most_used_outputs(mss_dst)
 
         replies_count = 0
-        total_pkt_num = 0
+        self.total_pkt_num = 0
         # For each attacker, generate his own packets, then merge all packets
         for attacker in range(num_attackers):
             # Timestamp
@@ -188,8 +191,8 @@ class DDoSAttack(BaseAttack.BaseAttack):
                 request = (request_ether / request_ip / request_tcp)
                 request.time = timestamp_next_pkt
                 # Append request
-                packets.append(request)
-                total_pkt_num +=1
+                self.packets.append(request)
+                self.total_pkt_num +=1
 
                 # Build reply package
                 if replies_count <= victim_buffer:
@@ -204,29 +207,30 @@ class DDoSAttack(BaseAttack.BaseAttack):
                     timestamp_prv_reply = timestamp_reply
 
                     reply.time = timestamp_reply
-                    packets.append(reply)
+                    self.packets.append(reply)
                     replies_count+=1
-                    total_pkt_num += 1
+                    self.total_pkt_num += 1
 
                 attacker_pps = max(get_interval_pps(complement_interval_attacker_pps, timestamp_next_pkt), (pps / num_attackers) / 2)
                 timestamp_next_pkt = update_timestamp(timestamp_next_pkt, attacker_pps)
 
                 # Store timestamp of first packet (for attack label)
-                if total_pkt_num <= 2 :
-                    self.attack_start_utime = packets[0].time
+                if self.total_pkt_num <= 2 :
+                    self.attack_start_utime = self.packets[0].time
                 elif pkt_num % BUFFER_SIZE == 0: # every 1000 packets write them to the pcap file (append)
-                    last_packet = packets[-1]
-                    packets = sorted(packets, key=lambda pkt: pkt.time)
-                    path_attack_pcap = self.write_attack_pcap(packets, True, path_attack_pcap)
-                    packets = []
+                    self.last_packet = self.packets[-1]
+                    self.packets = sorted(self.packets, key=lambda pkt: pkt.time)
+                    self.path_attack_pcap = self.write_attack_pcap(self.packets, True, self.path_attack_pcap)
+                    self.packets = []
 
-        if len(packets) > 0:
-            packets = sorted(packets, key=lambda pkt: pkt.time)
-            path_attack_pcap = self.write_attack_pcap(packets, True, path_attack_pcap)
+    def generate_attack_pcap(self):
+        if len(self.packets) > 0:
+            self.packets = sorted(self.packets, key=lambda pkt: pkt.time)
+            self.path_attack_pcap = self.write_attack_pcap(self.packets, True, self.path_attack_pcap)
 
         # Store timestamp of last packet
-        self.attack_end_utime = last_packet.time
+        self.attack_end_utime = self.last_packet.time
 
         # Return packets sorted by packet time_sec_start
         # pkt_num+1: because pkt_num starts at 0
-        return total_pkt_num , path_attack_pcap
+        return self.total_pkt_num, self.path_attack_pcap

+ 22 - 22
code/Attack/EternalBlueExploit.py

@@ -78,8 +78,7 @@ class EternalBlueExploit(BaseAttack.BaseAttack):
                               self.statistics.get_pps_received(most_used_ip_address)) / 2)
         self.add_param_value(Param.INJECT_AFTER_PACKET, randint(0, self.statistics.get_packet_count()))
 
-    def generate_attack_pcap(self):
-
+    def generate_attack_packets(self):
 
         # Timestamp
         timestamp_next_pkt = self.get_param_value(Param.INJECT_AT_TIMESTAMP)
@@ -89,7 +88,7 @@ class EternalBlueExploit(BaseAttack.BaseAttack):
         complement_interval_pps = self.statistics.calculate_complement_packet_rates(pps)
 
         # Initialize parameters
-        packets = []
+        self.packets = []
         mac_source = self.get_param_value(Param.MAC_SOURCE)
         ip_source = self.get_param_value(Param.IP_SOURCE)
         port_source = self.get_param_value(Param.PORT_SOURCE)
@@ -100,7 +99,7 @@ class EternalBlueExploit(BaseAttack.BaseAttack):
         # Check ip.src == ip.dst
         self.ip_src_dst_equal_check(ip_source, ip_destination)
 
-        path_attack_pcap = None
+        self.path_attack_pcap = None
 
         # Set TTL based on TTL distribution of IP address
         source_ttl_dist = self.statistics.get_ttl_distribution(ip_source)
@@ -144,7 +143,7 @@ class EternalBlueExploit(BaseAttack.BaseAttack):
 
         port_source = randint(self.minDefaultPort,self.maxDefaultPort) # experiments show this range of ports
         # conversations = {(ip.src, ip.dst, port.src, port.dst): packets}
-        conversations, orderList_conversations = self.packetsToConvs(exploit_raw_packets)
+        conversations, orderList_conversations = self.packets_to_convs(exploit_raw_packets)
         exploit_raw_packets.close()
 
         conv_start_timesamp = timestamp_next_pkt
@@ -156,16 +155,16 @@ class EternalBlueExploit(BaseAttack.BaseAttack):
             inter_arrival_times = self.get_inter_arrival_time(conv_pkts)
 
             if conv_index == len(orderList_conversations) - 2:  # Not the last conversation
-                timestamp_next_pkt = packets[-1].time + uniform(0.001,0.01)
+                timestamp_next_pkt = self.packets[-1].time + uniform(0.001,0.01)
 
             if conv_index != len(orderList_conversations)-1: # Not the last conversation
                 port_source += 2
-                for pkt_num, pkt in enumerate(conv_pkts):
+                for self.pkt_num, pkt in enumerate(conv_pkts):
                     eth_frame = Ether(pkt[0])
                     ip_pkt = eth_frame.payload
                     tcp_pkt = ip_pkt.payload
 
-                    if pkt_num == 0:
+                    if self.pkt_num == 0:
                         if tcp_pkt.getfieldval("dport") == smb_port:
                             orig_ip_dst = ip_pkt.getfieldval("dst")
 
@@ -198,7 +197,7 @@ class EternalBlueExploit(BaseAttack.BaseAttack):
                         new_pkt.time = timestamp_next_pkt
 
                         pps = max(Util.get_interval_pps(complement_interval_pps, timestamp_next_pkt), 10)
-                        timestamp_next_pkt = Util.update_timestamp(timestamp_next_pkt, pps) + inter_arrival_times[pkt_num] #float(timeSteps.random())
+                        timestamp_next_pkt = Util.update_timestamp(timestamp_next_pkt, pps) + inter_arrival_times[self.pkt_num] #float(timeSteps.random())
 
                     # Reply
                     else:
@@ -228,16 +227,16 @@ class EternalBlueExploit(BaseAttack.BaseAttack):
                         new_pkt = (eth_frame / ip_pkt / tcp_pkt)
 
                         pps = max(Util.get_interval_pps(complement_interval_pps, timestamp_next_pkt), 10)
-                        timestamp_next_pkt = Util.update_timestamp(timestamp_next_pkt, pps) + inter_arrival_times[pkt_num]#float(timeSteps.random())
+                        timestamp_next_pkt = Util.update_timestamp(timestamp_next_pkt, pps) + inter_arrival_times[self.pkt_num]#float(timeSteps.random())
 
                         new_pkt.time = timestamp_next_pkt
 
-                    packets.append(new_pkt)
+                    self.packets.append(new_pkt)
 
             else: # Last conversation where the victim start a connection with the attacker
-                timestamp_next_pkt = packets[-1].time + uniform(0.001, 0.01)
+                timestamp_next_pkt = self.packets[-1].time + uniform(0.001, 0.01)
                 port_source = randint(self.minDefaultPort,self.maxDefaultPort)
-                for pkt_num, pkt in enumerate(conv_pkts):
+                for self.pkt_num, pkt in enumerate(conv_pkts):
                     eth_frame = Ether(pkt[0])
                     ip_pkt = eth_frame.payload
                     tcp_pkt = ip_pkt.payload
@@ -271,7 +270,7 @@ class EternalBlueExploit(BaseAttack.BaseAttack):
                         new_pkt.time = timestamp_next_pkt
 
                         pps = max(Util.get_interval_pps(complement_interval_pps, timestamp_next_pkt), 10)
-                        timestamp_next_pkt = Util.update_timestamp(timestamp_next_pkt, pps) + inter_arrival_times[pkt_num]# float(timeSteps.random())
+                        timestamp_next_pkt = Util.update_timestamp(timestamp_next_pkt, pps) + inter_arrival_times[self.pkt_num]# float(timeSteps.random())
 
                     # Reply
                     else:
@@ -301,20 +300,21 @@ class EternalBlueExploit(BaseAttack.BaseAttack):
                         new_pkt = (eth_frame / ip_pkt / tcp_pkt)
 
                         pps = max(Util.get_interval_pps(complement_interval_pps, timestamp_next_pkt), 10)
-                        timestamp_next_pkt = Util.update_timestamp(timestamp_next_pkt, pps) + inter_arrival_times[pkt_num]# float(timeSteps.random())
+                        timestamp_next_pkt = Util.update_timestamp(timestamp_next_pkt, pps) + inter_arrival_times[self.pkt_num]# float(timeSteps.random())
 
                         new_pkt.time = timestamp_next_pkt
 
-                    packets.append(new_pkt)
+                    self.packets.append(new_pkt)
 
+    def generate_attack_pcap(self):
         # Store timestamp of first packet (for attack label)
-        self.attack_start_utime = packets[0].time
-        self.attack_end_utime = packets[-1].time
+        self.attack_start_utime = self.packets[0].time
+        self.attack_end_utime = self.packets[-1].time
 
-        if len(packets) > 0:
-            packets = sorted(packets, key=lambda pkt: pkt.time)
-            path_attack_pcap = self.write_attack_pcap(packets, True, path_attack_pcap)
+        if len(self.packets) > 0:
+            self.packets = sorted(self.packets, key=lambda pkt: pkt.time)
+            self.path_attack_pcap = self.write_attack_pcap(self.packets, True, self.path_attack_pcap)
 
         # return packets sorted by packet time_sec_start
         # pkt_num+1: because pkt_num starts at 0
-        return pkt_num + 1, path_attack_pcap
+        return self.pkt_num + 1, self.path_attack_pcap

+ 13 - 12
code/Attack/FTPWinaXeExploit.py

@@ -77,7 +77,7 @@ class FTPWinaXeExploit(BaseAttack.BaseAttack):
         self.add_param_value(Param.CUSTOM_PAYLOAD, '')
         self.add_param_value(Param.CUSTOM_PAYLOAD_FILE, '')
 
-    def generate_attack_pcap(self):
+    def generate_attack_packets(self):
 
         pps = self.get_param_value(Param.PACKETS_PER_SECOND)
 
@@ -97,7 +97,7 @@ class FTPWinaXeExploit(BaseAttack.BaseAttack):
         custom_payload_limit = 1000
         check_payload_len(custom_payload_len, custom_payload_limit)
 
-        packets = []
+        self.packets = []
 
         # Create random victim if specified
         if self.get_param_value(Param.IP_SOURCE_RANDOMIZE):
@@ -126,7 +126,7 @@ class FTPWinaXeExploit(BaseAttack.BaseAttack):
         syn = (victim_ether / victim_ip / request_tcp)
         syn.time = timestamp_next_pkt
         timestamp_next_pkt = update_timestamp(timestamp_next_pkt, pps, minDelay)
-        packets.append(syn)
+        self.packets.append(syn)
 
         # response from attacker (server)
         attacker_ether = Ether(src=mac_attacker, dst=mac_victim)
@@ -137,7 +137,7 @@ class FTPWinaXeExploit(BaseAttack.BaseAttack):
         synack = (attacker_ether / attacker_ip / reply_tcp)
         synack.time = timestamp_next_pkt
         timestamp_next_pkt = update_timestamp(timestamp_next_pkt, pps, minDelay)
-        packets.append(synack)
+        self.packets.append(synack)
 
         # acknowledgement from victim (client)
         ack_tcp = TCP(sport=sport, dport=ftp_port, seq=victim_seq, ack=attacker_seq, flags='A',
@@ -145,7 +145,7 @@ class FTPWinaXeExploit(BaseAttack.BaseAttack):
         ack = (victim_ether / victim_ip / ack_tcp)
         ack.time = timestamp_next_pkt
         timestamp_next_pkt = update_timestamp(timestamp_next_pkt, pps)
-        packets.append(ack)
+        self.packets.append(ack)
 
         # FTP exploit packet
         ftp_tcp = TCP(sport=ftp_port, dport=sport, seq=attacker_seq, ack=victim_seq, flags='PA',
@@ -179,7 +179,7 @@ class FTPWinaXeExploit(BaseAttack.BaseAttack):
         ftp_buff = (attacker_ether / attacker_ip / ftp_tcp)
         ftp_buff.time = timestamp_next_pkt
         timestamp_next_pkt = update_timestamp(timestamp_next_pkt, pps)
-        packets.append(ftp_buff)
+        self.packets.append(ftp_buff)
         attacker_seq += len(ftp_tcp.payload)
 
         # Fin Ack from attacker
@@ -189,7 +189,7 @@ class FTPWinaXeExploit(BaseAttack.BaseAttack):
         fin_ack = (attacker_ether / attacker_ip / fin_ack_tcp)
         fin_ack.time = timestamp_next_pkt
         timestamp_next_pkt = update_timestamp(timestamp_next_pkt, pps, minDelay)
-        packets.append(fin_ack)
+        self.packets.append(fin_ack)
 
         # Ack from victim on FTP packet
         ftp_ack_tcp = TCP(sport=sport, dport=ftp_port, seq=victim_seq, ack=attacker_seq, flags='A',
@@ -197,20 +197,21 @@ class FTPWinaXeExploit(BaseAttack.BaseAttack):
         ftp_ack = (victim_ether / victim_ip / ftp_ack_tcp)
         ftp_ack.time = timestamp_next_pkt
         timestamp_next_pkt = update_timestamp(timestamp_next_pkt, pps)
-        packets.append(ftp_ack)
+        self.packets.append(ftp_ack)
 
         # Ack from victim on Fin/Ack of attacker
         fin_ack_ack_tcp = TCP(sport=sport, dport=ftp_port, seq=victim_seq, ack=attacker_seq+1, flags='A',
                       window=victim_win_value, options=[('MSS', victim_mss_value)])
         fin_ack_ack = (victim_ether / victim_ip / fin_ack_ack_tcp)
         fin_ack_ack.time = timestamp_next_pkt
-        packets.append(fin_ack_ack)
+        self.packets.append(fin_ack_ack)
 
+    def generate_attack_pcap(self):
         # store end time of attack
-        self.attack_end_utime = packets[-1].time
+        self.attack_end_utime = self.packets[-1].time
 
         # write attack packets to pcap
-        pcap_path = self.write_attack_pcap(sorted(packets, key=lambda pkt: pkt.time))
+        pcap_path = self.write_attack_pcap(sorted(self.packets, key=lambda pkt: pkt.time))
 
         # return packets sorted by packet time_sec_start
-        return len(packets), pcap_path
+        return len(self.packets), pcap_path

+ 15 - 13
code/Attack/JoomlaRegPrivExploit.py

@@ -77,8 +77,7 @@ class JoomlaRegPrivExploit(BaseAttack.BaseAttack):
                              (self.statistics.get_pps_sent(most_used_ip_address) +
                               self.statistics.get_pps_received(most_used_ip_address)) / 2)
 
-    def generate_attack_pcap(self):
-
+    def generate_attack_packets(self):
         # Timestamp
         timestamp_next_pkt = self.get_param_value(Param.INJECT_AT_TIMESTAMP)
 
@@ -88,7 +87,7 @@ class JoomlaRegPrivExploit(BaseAttack.BaseAttack):
         complement_interval_pps = self.statistics.calculate_complement_packet_rates(pps)
 
         # Initialize parameters
-        packets = []
+        self.packets = []
         mac_source = self.get_param_value(Param.MAC_SOURCE)
         ip_source = self.get_param_value(Param.IP_SOURCE)
         port_source = randint(self.minDefaultPort, self.maxDefaultPort)
@@ -102,7 +101,7 @@ class JoomlaRegPrivExploit(BaseAttack.BaseAttack):
         # Check ip.src == ip.dst
         self.ip_src_dst_equal_check(ip_source, ip_destination)
 
-        path_attack_pcap = None
+        self.path_attack_pcap = None
 
         # Set TTL based on TTL distribution of IP address
         source_ttl_dist = self.statistics.get_ttl_distribution(ip_source)
@@ -134,7 +133,7 @@ class JoomlaRegPrivExploit(BaseAttack.BaseAttack):
         global victim_seq
         victim_seq = randint(1000,50000)
 
-        for pkt_num, pkt in enumerate(exploit_raw_packets):
+        for self.pkt_num, pkt in enumerate(exploit_raw_packets):
             eth_frame = Ether(pkt[0])
             ip_pkt = eth_frame.payload
             tcp_pkt = ip_pkt.payload
@@ -145,7 +144,7 @@ class JoomlaRegPrivExploit(BaseAttack.BaseAttack):
             ip_pkt.payload = b''
             tcp_pkt.payload = b''
 
-            if pkt_num == 0:
+            if self.pkt_num == 0:
                 prev_orig_port_source = tcp_pkt.getfieldval("sport")
                 if tcp_pkt.getfieldval("dport") == self.http_port:
                     orig_ip_dst = ip_pkt.getfieldval("dst") # victim IP
@@ -215,17 +214,20 @@ class JoomlaRegPrivExploit(BaseAttack.BaseAttack):
                 timestamp_next_pkt = Util.update_timestamp(timestamp_next_pkt, pps) + float(timeSteps.random())
                 new_pkt.time = timestamp_next_pkt
 
-            packets.append(new_pkt)
+            self.packets.append(new_pkt)
 
         exploit_raw_packets.close()
+
+    def generate_attack_pcap(self):
+
         # Store timestamp of first packet (for attack label)
-        self.attack_start_utime = packets[0].time
-        self.attack_end_utime = packets[-1].time
+        self.attack_start_utime = self.packets[0].time
+        self.attack_end_utime = self.packets[-1].time
 
-        if len(packets) > 0:
-            packets = sorted(packets, key=lambda pkt: pkt.time)
-            path_attack_pcap = self.write_attack_pcap(packets, True, path_attack_pcap)
+        if len(self.packets) > 0:
+            self.packets = sorted(self.packets, key=lambda pkt: pkt.time)
+            self.path_attack_pcap = self.write_attack_pcap(self.packets, True, self.path_attack_pcap)
 
         # return packets sorted by packet time_sec_start
         # pkt_num+1: because pkt_num starts at 0
-        return pkt_num + 1, path_attack_pcap
+        return self.pkt_num + 1, self.path_attack_pcap

+ 15 - 14
code/Attack/MS17ScanAttack.py

@@ -77,7 +77,7 @@ class MS17ScanAttack(BaseAttack.BaseAttack):
                               self.statistics.get_pps_received(most_used_ip_address)) / 2)
         self.add_param_value(Param.INJECT_AFTER_PACKET, randint(0, self.statistics.get_packet_count()))
 
-    def generate_attack_pcap(self):
+    def generate_attack_packets(self):
 
         # Timestamp
         timestamp_next_pkt = self.get_param_value(Param.INJECT_AT_TIMESTAMP)
@@ -87,7 +87,7 @@ class MS17ScanAttack(BaseAttack.BaseAttack):
         complement_interval_pps = self.statistics.calculate_complement_packet_rates(pps)
 
         # Initialize parameters
-        packets = []
+        self.packets = []
         mac_source = self.get_param_value(Param.MAC_SOURCE)
         ip_source = self.get_param_value(Param.IP_SOURCE)
         port_source = self.get_param_value(Param.PORT_SOURCE)
@@ -98,7 +98,7 @@ class MS17ScanAttack(BaseAttack.BaseAttack):
         # Check ip.src == ip.dst
         self.ip_src_dst_equal_check(ip_source, ip_destination)
 
-        path_attack_pcap = None
+        self.path_attack_pcap = None
 
         # Set TTL based on TTL distribution of IP address
         source_ttl_dist = self.statistics.get_ttl_distribution(ip_source)
@@ -146,12 +146,12 @@ class MS17ScanAttack(BaseAttack.BaseAttack):
 
         source_origin_wins, destination_origin_wins = {}, {}
 
-        for pkt_num, pkt in enumerate(exploit_raw_packets):
+        for self.pkt_num, pkt in enumerate(exploit_raw_packets):
             eth_frame = Ether(pkt[0])
             ip_pkt = eth_frame.payload
             tcp_pkt = ip_pkt.payload
 
-            if pkt_num == 0:
+            if self.pkt_num == 0:
                 if tcp_pkt.getfieldval("dport") == smb_port:
                     orig_ip_dst = ip_pkt.getfieldval("dst")  # victim IP
 
@@ -185,7 +185,7 @@ class MS17ScanAttack(BaseAttack.BaseAttack):
 
                 pps = max(Util.get_interval_pps(complement_interval_pps, timestamp_next_pkt), 10)
                 timestamp_next_pkt = Util.update_timestamp(timestamp_next_pkt, pps) + inter_arrival_times[
-                    pkt_num]  # float(timeSteps.random())
+                    self.pkt_num]  # float(timeSteps.random())
             # Reply
             else:
                 # Ether
@@ -213,21 +213,22 @@ class MS17ScanAttack(BaseAttack.BaseAttack):
 
                 new_pkt = (eth_frame / ip_pkt / tcp_pkt)
                 timestamp_next_pkt = Util.update_timestamp(timestamp_next_pkt, pps) + inter_arrival_times[
-                    pkt_num]  # + float(timeSteps.random())
+                    self.pkt_num]  # + float(timeSteps.random())
                 new_pkt.time = timestamp_next_pkt
 
-            packets.append(new_pkt)
+            self.packets.append(new_pkt)
 
         exploit_raw_packets.close()
 
+    def generate_attack_pcap(self):
         # Store timestamp of first packet (for attack label)
-        self.attack_start_utime = packets[0].time
-        self.attack_end_utime = packets[-1].time
+        self.attack_start_utime = self.packets[0].time
+        self.attack_end_utime = self.packets[-1].time
 
-        if len(packets) > 0:
-            packets = sorted(packets, key=lambda pkt: pkt.time)
-            path_attack_pcap = self.write_attack_pcap(packets, True, path_attack_pcap)
+        if len(self.packets) > 0:
+            self.packets = sorted(self.packets, key=lambda pkt: pkt.time)
+            self.path_attack_pcap = self.write_attack_pcap(self.packets, True, self.path_attack_pcap)
 
         # return packets sorted by packet time_sec_start
         # pkt_num+1: because pkt_num starts at 0
-        return pkt_num + 1, path_attack_pcap
+        return self.pkt_num + 1, self.path_attack_pcap

+ 13 - 8
code/Attack/PortscanAttack.py

@@ -108,7 +108,7 @@ class PortscanAttack(BaseAttack.BaseAttack):
             port_dst_shuffled = ports_dst
         return port_dst_shuffled
 
-    def generate_attack_pcap(self):
+    def generate_attack_packets(self):
         mac_source = self.get_param_value(Param.MAC_SOURCE)
         mac_destination = self.get_param_value(Param.MAC_DESTINATION)
         pps = self.get_param_value(Param.PACKETS_PER_SECOND)
@@ -134,9 +134,13 @@ class PortscanAttack(BaseAttack.BaseAttack):
         timestamp_prv_reply, timestamp_confirm = 0,0
 
         # Initialize parameters
-        packets = []
+        self.packets = []
         ip_source = self.get_param_value(Param.IP_SOURCE)
+        if isinstance(ip_source, list):
+            ip_source = ip_source[0]
         ip_destination = self.get_param_value(Param.IP_DESTINATION)
+        if isinstance(ip_destination, list):
+            ip_destination = ip_destination[0]
 
         # Check ip.src == ip.dst
         self.ip_src_dst_equal_check(ip_source, ip_destination)
@@ -222,7 +226,7 @@ class PortscanAttack(BaseAttack.BaseAttack):
 
             request.time = timestamp_next_pkt
             # Append request
-            packets.append(request)
+            self.packets.append(request)
 
             # 2) Build reply (for open ports) package
             if dport in ports_open:  # destination port is OPEN
@@ -238,7 +242,7 @@ class PortscanAttack(BaseAttack.BaseAttack):
                 timestamp_prv_reply = timestamp_reply
 
                 reply.time = timestamp_reply
-                packets.append(reply)
+                self.packets.append(reply)
 
                 # requester confirms
                 confirm_ether = request_ether
@@ -247,18 +251,19 @@ class PortscanAttack(BaseAttack.BaseAttack):
                 confirm = (confirm_ether / confirm_ip / confirm_tcp)
                 timestamp_confirm = Util.update_timestamp(timestamp_reply,pps,minDelay)
                 confirm.time = timestamp_confirm
-                packets.append(confirm)
+                self.packets.append(confirm)
 
                 # else: destination port is NOT OPEN -> no reply is sent by target
 
             pps = max(Util.get_interval_pps(complement_interval_pps, timestamp_next_pkt), 10)
             timestamp_next_pkt = Util.update_timestamp(timestamp_next_pkt, pps)
 
+    def generate_attack_pcap(self):
         # store end time of attack
-        self.attack_end_utime = packets[-1].time
+        self.attack_end_utime = self.packets[-1].time
 
         # write attack packets to pcap
-        pcap_path = self.write_attack_pcap(sorted(packets, key=lambda pkt: pkt.time))
+        pcap_path = self.write_attack_pcap(sorted(self.packets, key=lambda pkt: pkt.time))
 
         # return packets sorted by packet time_sec_start
-        return len(packets), pcap_path
+        return len(self.packets), pcap_path

+ 13 - 13
code/Attack/SMBLorisAttack.py

@@ -74,8 +74,7 @@ class SMBLorisAttack(BaseAttack.BaseAttack):
         self.add_param_value(Param.INJECT_AFTER_PACKET, random.randint(0, self.statistics.get_packet_count()))
         self.add_param_value(Param.ATTACK_DURATION, 30)
 
-    def generate_attack_pcap(self):
-
+    def generate_attack_packets(self):
         pps = self.get_param_value(Param.PACKETS_PER_SECOND)
 
         # Timestamp
@@ -84,7 +83,7 @@ class SMBLorisAttack(BaseAttack.BaseAttack):
         self.attack_start_utime = first_timestamp
 
         # Initialize parameters
-        packets = []
+        self.packets = []
         ip_destination = self.get_param_value(Param.IP_DESTINATION)
         mac_destination = self.get_param_value(Param.MAC_DESTINATION)
 
@@ -140,7 +139,7 @@ class SMBLorisAttack(BaseAttack.BaseAttack):
 
             sport = 1025
 
-            # Timestamps of first packets shouldn't be exactly the same to look more realistic
+            # Timestamps of first self.packets shouldn't be exactly the same to look more realistic
             timestamp_next_pkt = random.uniform(first_timestamp, update_timestamp(first_timestamp, pps))
 
             while timestamp_next_pkt <= attack_ends_time:
@@ -161,7 +160,7 @@ class SMBLorisAttack(BaseAttack.BaseAttack):
                 syn = (attacker_ether / attacker_ip / syn_tcp)
                 syn.time = timestamp_next_pkt
                 timestamp_next_pkt = update_timestamp(timestamp_next_pkt, victim_pps, minDelay)
-                packets.append(syn)
+                self.packets.append(syn)
 
                 # response from victim (server)
                 synack_tcp = TCP(sport=smb_port, dport=sport, seq=victim_seq, ack=attacker_seq, flags='SA',
@@ -170,7 +169,7 @@ class SMBLorisAttack(BaseAttack.BaseAttack):
                 synack = (victim_ether / victim_ip / synack_tcp)
                 synack.time = timestamp_next_pkt
                 timestamp_next_pkt = update_timestamp(timestamp_next_pkt, pps, minDelay)
-                packets.append(synack)
+                self.packets.append(synack)
 
                 # acknowledgement from attacker (client)
                 ack_tcp = TCP(sport=sport, dport=smb_port, seq=attacker_seq, ack=victim_seq, flags='A',
@@ -178,7 +177,7 @@ class SMBLorisAttack(BaseAttack.BaseAttack):
                 ack = (attacker_ether / attacker_ip / ack_tcp)
                 ack.time = timestamp_next_pkt
                 timestamp_next_pkt = update_timestamp(timestamp_next_pkt, pps)
-                packets.append(ack)
+                self.packets.append(ack)
 
                 # send NBT session header paket with maximum LENGTH-field
                 req_tcp = TCP(sport=sport, dport=smb_port, seq=attacker_seq, ack=victim_seq, flags='AP',
@@ -189,7 +188,7 @@ class SMBLorisAttack(BaseAttack.BaseAttack):
                 req = (attacker_ether / attacker_ip / req_tcp / req_payload)
                 req.time = timestamp_next_pkt
                 timestamp_next_pkt = update_timestamp(timestamp_next_pkt, victim_pps, minDelay)
-                packets.append(req)
+                self.packets.append(req)
 
                 # final ack from victim (server)
                 last_ack_tcp = TCP(sport=smb_port, dport=sport, seq=victim_seq, ack=attacker_seq, flags='A',
@@ -197,15 +196,16 @@ class SMBLorisAttack(BaseAttack.BaseAttack):
                 last_ack = (victim_ether / victim_ip / last_ack_tcp)
                 last_ack.time = timestamp_next_pkt
                 timestamp_next_pkt = update_timestamp(timestamp_next_pkt, pps, minDelay)
-                packets.append(last_ack)
+                self.packets.append(last_ack)
 
                 sport += 1
 
+    def generate_attack_pcap(self):
         # store end time of attack
-        self.attack_end_utime = packets[-1].time
+        self.attack_end_utime = self.packets[-1].time
 
-        # write attack packets to pcap
-        pcap_path = self.write_attack_pcap(sorted(packets, key=lambda pkt: pkt.time))
+        # write attack self.packets to pcap
+        pcap_path = self.write_attack_pcap(sorted(self.packets, key=lambda pkt: pkt.time))
 
         # return packets sorted by packet time_sec_start
-        return len(packets), pcap_path
+        return len(self.packets), pcap_path

+ 21 - 24
code/Attack/SMBScanAttack.py

@@ -46,8 +46,7 @@ class SMBScanAttack(BaseAttack.BaseAttack):
             Param.HOSTING_IP: ParameterTypes.TYPE_IP_ADDRESS,
             Param.HOSTING_VERSION: ParameterTypes.TYPE_STRING,
             Param.SOURCE_PLATFORM: ParameterTypes.TYPE_STRING,
-            Param.PROTOCOL_VERSION: ParameterTypes.TYPE_STRING,
-            Param.IP_DESTINATION_END: ParameterTypes.TYPE_IP_ADDRESS
+            Param.PROTOCOL_VERSION: ParameterTypes.TYPE_STRING
         })
 
     def init_params(self):
@@ -91,9 +90,8 @@ class SMBScanAttack(BaseAttack.BaseAttack):
         self.add_param_value(Param.HOSTING_VERSION, get_smb_version(platform=self.host_os))
         self.add_param_value(Param.SOURCE_PLATFORM, ID2TLib.Utility.get_rnd_os())
         self.add_param_value(Param.PROTOCOL_VERSION, "1")
-        self.add_param_value(Param.IP_DESTINATION_END, "0.0.0.0")
 
-    def generate_attack_pcap(self):
+    def generate_attack_packets(self):
 
         pps = self.get_param_value(Param.PACKETS_PER_SECOND)
 
@@ -111,7 +109,6 @@ class SMBScanAttack(BaseAttack.BaseAttack):
         ip_source = self.get_param_value(Param.IP_SOURCE)
         ip_destinations = self.get_param_value(Param.IP_DESTINATION)
         hosting_ip = self.get_param_value(Param.HOSTING_IP)
-        ip_range_end = self.get_param_value(Param.IP_DESTINATION_END)
         mac_source = self.get_param_value(Param.MAC_SOURCE)
         mac_dest = self.get_param_value(Param.MAC_DESTINATION)
 
@@ -124,7 +121,7 @@ class SMBScanAttack(BaseAttack.BaseAttack):
             invalid_smb_version(hosting_version)
         # Check source platform
         src_platform = self.get_param_value(Param.SOURCE_PLATFORM).lower()
-        packets = []
+        self.packets = []
 
         # randomize source ports according to platform, if specified
         if self.get_param_value(Param.PORT_SOURCE_RANDOMIZE):
@@ -146,9 +143,7 @@ class SMBScanAttack(BaseAttack.BaseAttack):
         else:
             ip_dests.append(ip_destinations)
 
-        # Generate IPs of destination IP range, if specified
-        if ip_range_end != "0.0.0.0":
-            ip_dests = get_ip_range(ip_dests[0], ip_range_end)
+        if isinstance(ip_dests, list):
             shuffle(ip_dests)
 
         # Randomize source IP, if specified
@@ -203,7 +198,7 @@ class SMBScanAttack(BaseAttack.BaseAttack):
                 request.time = timestamp_next_pkt
 
                 # Append request
-                packets.append(request)
+                self.packets.append(request)
 
                 # Update timestamp for next package
                 timestamp_reply = update_timestamp(timestamp_next_pkt, pps, minDelay)
@@ -223,7 +218,7 @@ class SMBScanAttack(BaseAttack.BaseAttack):
                     victim_seq += 1
                     reply = (reply_ether / reply_ip / reply_tcp)
                     reply.time = timestamp_reply
-                    packets.append(reply)
+                    self.packets.append(reply)
 
                     # requester confirms, ACK
                     confirm_ether = request_ether
@@ -233,7 +228,7 @@ class SMBScanAttack(BaseAttack.BaseAttack):
                     confirm = (confirm_ether / confirm_ip / confirm_tcp)
                     timestamp_confirm = update_timestamp(timestamp_reply, pps, minDelay)
                     confirm.time = timestamp_confirm
-                    packets.append(confirm)
+                    self.packets.append(confirm)
 
                     smb_MID = randint(1, 65535)
                     smb_PID = randint(1, 65535)
@@ -269,7 +264,7 @@ class SMBScanAttack(BaseAttack.BaseAttack):
 
                     timestamp_smb_req = update_timestamp(timestamp_confirm, pps, minDelay)
                     smb_req_combined.time = timestamp_smb_req
-                    packets.append(smb_req_combined)
+                    self.packets.append(smb_req_combined)
 
                     # destination confirms SMB request package
                     reply_tcp = TCP(sport=smb_port, dport=sport, seq=victim_seq, ack=attacker_seq,
@@ -277,7 +272,7 @@ class SMBScanAttack(BaseAttack.BaseAttack):
                     confirm_smb_req = (reply_ether / reply_ip / reply_tcp)
                     timestamp_reply = update_timestamp(timestamp_smb_req, pps, minDelay)
                     confirm_smb_req.time = timestamp_reply
-                    packets.append(confirm_smb_req)
+                    self.packets.append(confirm_smb_req)
 
                     # smb response package
                     first_timestamp = time.mktime(time.strptime(self.statistics.get_pcap_timestamp_start()[:19],
@@ -316,7 +311,7 @@ class SMBScanAttack(BaseAttack.BaseAttack):
                         smb_rsp_combined = (smb_rsp_combined / smb_rsp_negotiate_body)
 
                     smb_rsp_combined.time = timestamp_smb_rsp
-                    packets.append(smb_rsp_combined)
+                    self.packets.append(smb_rsp_combined)
 
 
                     # source confirms SMB response package
@@ -325,7 +320,7 @@ class SMBScanAttack(BaseAttack.BaseAttack):
                     confirm_smb_res = (confirm_ether / confirm_ip / confirm_tcp)
                     timestamp_confirm = update_timestamp(timestamp_smb_rsp, pps, minDelay)
                     confirm_smb_res.time = timestamp_confirm
-                    packets.append(confirm_smb_res)
+                    self.packets.append(confirm_smb_res)
 
                     # attacker sends FIN ACK
                     confirm_tcp = TCP(sport=sport, dport=smb_port, seq=attacker_seq, ack=victim_seq,
@@ -334,7 +329,7 @@ class SMBScanAttack(BaseAttack.BaseAttack):
                     timestamp_src_fin_ack = update_timestamp(timestamp_confirm, pps, minDelay)
                     source_fin_ack.time = timestamp_src_fin_ack
                     attacker_seq += 1
-                    packets.append(source_fin_ack)
+                    self.packets.append(source_fin_ack)
 
                     # victim sends FIN ACK
                     reply_tcp = TCP(sport=smb_port, dport=sport, seq=victim_seq, ack=attacker_seq,
@@ -343,7 +338,7 @@ class SMBScanAttack(BaseAttack.BaseAttack):
                     timestamp_dest_fin_ack = update_timestamp(timestamp_src_fin_ack, pps, minDelay)
                     victim_seq += 1
                     destination_fin_ack.time = timestamp_dest_fin_ack
-                    packets.append(destination_fin_ack)
+                    self.packets.append(destination_fin_ack)
 
                     # source sends final ACK
                     confirm_tcp = TCP(sport=sport, dport=smb_port, seq=attacker_seq, ack=victim_seq,
@@ -351,7 +346,7 @@ class SMBScanAttack(BaseAttack.BaseAttack):
                     final_ack = (confirm_ether / confirm_ip / confirm_tcp)
                     timestamp_final_ack = update_timestamp(timestamp_dest_fin_ack, pps, minDelay)
                     final_ack.time = timestamp_final_ack
-                    packets.append(final_ack)
+                    self.packets.append(final_ack)
 
                 else:
                     # Build RST package
@@ -361,16 +356,18 @@ class SMBScanAttack(BaseAttack.BaseAttack):
                                     window=destination_win_value, options=[('MSS', destination_mss_value)])
                     reply = (reply_ether / reply_ip / reply_tcp)
                     reply.time = timestamp_reply
-                    packets.append(reply)
+                    self.packets.append(reply)
 
             pps = max(get_interval_pps(complement_interval_pps, timestamp_next_pkt), 10)
             timestamp_next_pkt = update_timestamp(timestamp_next_pkt, pps)
 
+    def generate_attack_pcap(self):
+
         # store end time of attack
-        self.attack_end_utime = packets[-1].time
+        self.attack_end_utime = self.packets[-1].time
 
-        # write attack packets to pcap
-        pcap_path = self.write_attack_pcap(sorted(packets, key=lambda pkt: pkt.time))
+        # write attack self.packets to pcap
+        pcap_path = self.write_attack_pcap(sorted(self.packets, key=lambda pkt: pkt.time))
 
         # return packets sorted by packet time_sec_start
-        return len(packets), pcap_path
+        return len(self.packets), pcap_path

+ 20 - 13
code/Attack/SQLiAttack.py

@@ -77,7 +77,7 @@ class SQLiAttack(BaseAttack.BaseAttack):
                              (self.statistics.get_pps_sent(most_used_ip_address) +
                               self.statistics.get_pps_received(most_used_ip_address)) / 2)
 
-    def generate_attack_pcap(self):
+    def generate_attack_packets(self):
         # Timestamp
         timestamp_next_pkt = self.get_param_value(Param.INJECT_AT_TIMESTAMP)
         pps = self.get_param_value(Param.PACKETS_PER_SECOND)
@@ -86,11 +86,15 @@ class SQLiAttack(BaseAttack.BaseAttack):
         complement_interval_pps = self.statistics.calculate_complement_packet_rates(pps)
 
         # Initialize parameters
-        packets = []
+        self.packets = []
         mac_source = self.get_param_value(Param.MAC_SOURCE)
         ip_source = self.get_param_value(Param.IP_SOURCE)
+        if isinstance(ip_source, list):
+            ip_source = ip_source[0]
         mac_destination = self.get_param_value(Param.MAC_DESTINATION)
         ip_destination = self.get_param_value(Param.IP_DESTINATION)
+        if isinstance(ip_destination, list):
+            ip_destination = ip_destination[0]
         port_destination = self.get_param_value(Param.PORT_DESTINATION)
 
         target_host = self.get_param_value(Param.TARGET_HOST)
@@ -99,7 +103,7 @@ class SQLiAttack(BaseAttack.BaseAttack):
         # Check ip.src == ip.dst
         self.ip_src_dst_equal_check(ip_source, ip_destination)
 
-        path_attack_pcap = None
+        self.path_attack_pcap = None
 
         # Set TTL based on TTL distribution of IP address
         source_ttl_dist = self.statistics.get_ttl_distribution(ip_source)
@@ -133,7 +137,7 @@ class SQLiAttack(BaseAttack.BaseAttack):
         global victim_seq
         victim_seq = random.randint(1000, 50000)
 
-        for pkt_num, pkt in enumerate(exploit_raw_packets):
+        for self.pkt_num, pkt in enumerate(exploit_raw_packets):
             eth_frame = Ether(pkt[0])
             ip_pkt = eth_frame.payload
             tcp_pkt = ip_pkt.payload
@@ -144,7 +148,7 @@ class SQLiAttack(BaseAttack.BaseAttack):
             ip_pkt.payload = b''
             tcp_pkt.payload = b''
 
-            if pkt_num == 0:
+            if self.pkt_num == 0:
                 prev_orig_port_source = tcp_pkt.getfieldval("sport")
                 orig_ip_dst = ip_pkt.getfieldval("dst")  # victim IP
 
@@ -231,17 +235,20 @@ class SQLiAttack(BaseAttack.BaseAttack):
                 timestamp_next_pkt = Util.update_timestamp(timestamp_next_pkt, pps) + float(timeSteps.random())
                 new_pkt.time = timestamp_next_pkt
 
-            packets.append(new_pkt)
+            self.packets.append(new_pkt)
 
         exploit_raw_packets.close()
+
+    def generate_attack_pcap(self):
+
         # Store timestamp of first packet (for attack label)
-        self.attack_start_utime = packets[0].time
-        self.attack_end_utime = packets[-1].time
+        self.attack_start_utime = self.packets[0].time
+        self.attack_end_utime = self.packets[-1].time
 
-        if len(packets) > 0:
-            packets = sorted(packets, key=lambda pkt: pkt.time)
-            path_attack_pcap = self.write_attack_pcap(packets, True, path_attack_pcap)
+        if len(self.packets) > 0:
+            self.packets = sorted(self.packets, key=lambda pkt: pkt.time)
+            self.path_attack_pcap = self.write_attack_pcap(self.packets, True, self.path_attack_pcap)
 
-        # return packets sorted by packet time_sec_start
+        # return self.packets sorted by packet time_sec_start
         # pkt_num+1: because pkt_num starts at 0
-        return pkt_num + 1, path_attack_pcap
+        return self.pkt_num + 1, self.path_attack_pcap

+ 13 - 11
code/Attack/SalityBotnet.py

@@ -55,7 +55,7 @@ class SalityBotnet(BaseAttack.BaseAttack):
                              (self.statistics.get_pps_sent(most_used_ip_address) +
                               self.statistics.get_pps_received(most_used_ip_address)) / 2)
 
-    def generate_attack_pcap(self):
+    def generate_attack_packets(self):
 
         # Timestamp
         timestamp_next_pkt = self.get_param_value(Param.INJECT_AT_TIMESTAMP)
@@ -66,7 +66,7 @@ class SalityBotnet(BaseAttack.BaseAttack):
         complement_interval_pps = self.statistics.calculate_complement_packet_rates(pps)
 
         # Initialize parameters
-        packets = []
+        self.packets = []
         mac_source = self.get_param_value(Param.MAC_SOURCE)
         ip_source = self.get_param_value(Param.IP_SOURCE)
 
@@ -89,13 +89,13 @@ class SalityBotnet(BaseAttack.BaseAttack):
         ip_map = {origin_ip_src : ip_source, origin_ip_dns_server: ip_dns_server}
         mac_map = {origin_mac_src : mac_source, origin_mac_dns_server: mac_dns_server}
 
-        path_attack_pcap = None
+        self.path_attack_pcap = None
 
         # Inject Sality botnet
         # Read sality_botnet pcap file
         exploit_raw_packets = RawPcapReader(self.template_attack_pcap_path)
 
-        for pkt_num, pkt in enumerate(exploit_raw_packets):
+        for self.pkt_num, pkt in enumerate(exploit_raw_packets):
             eth_frame = Ether(pkt[0])
             ip_pkt = eth_frame.payload
 
@@ -127,17 +127,19 @@ class SalityBotnet(BaseAttack.BaseAttack):
             pps = max(Util.get_interval_pps(complement_interval_pps, timestamp_next_pkt), 10)
             timestamp_next_pkt = Util.update_timestamp(timestamp_next_pkt, pps)
 
-            packets.append(new_pkt)
+            self.packets.append(new_pkt)
 
         exploit_raw_packets.close()
+
+    def generate_attack_pcap(self):
         # Store timestamp of first packet (for attack label)
-        self.attack_start_utime = packets[0].time
-        self.attack_end_utime = packets[-1].time
+        self.attack_start_utime = self.packets[0].time
+        self.attack_end_utime = self.packets[-1].time
 
-        if len(packets) > 0:
-            packets = sorted(packets, key=lambda pkt: pkt.time)
-            path_attack_pcap = self.write_attack_pcap(packets, True, path_attack_pcap)
+        if len(self.packets) > 0:
+            self.packets = sorted(self.packets, key=lambda pkt: pkt.time)
+            self.path_attack_pcap = self.write_attack_pcap(self.packets, True, self.path_attack_pcap)
 
         # return packets sorted by packet time_sec_start
         # pkt_num+1: because pkt_num starts at 0
-        return pkt_num + 1, path_attack_pcap
+        return self.pkt_num + 1, self.path_attack_pcap

+ 2 - 1
code/CLI.py

@@ -63,6 +63,7 @@ class CLI(object):
                                                        'in interval-wise, TCP checksum, and checking payload availability.', action='store_true')
         parser.add_argument('-S', '--randomSeed', action='append', help='sets random seed for testing or benchmarking',
                             nargs='+', default=[])
+        parser.add_argument('-T', '--time', help='measures packet generation time', action='store_true', default=False)
 
         # Attack arguments
         parser.add_argument('-a', '--attack', metavar="ATTACK", action='append',
@@ -151,7 +152,7 @@ class CLI(object):
         # Process attack(s) with given attack params
         if self.args.attack is not None:
             # If attack is present, load attack with params
-            controller.process_attacks(self.args.attack, self.args.randomSeed)
+            controller.process_attacks(self.args.attack, self.args.randomSeed, self.args.time)
 
         # Parameter -q without arguments was given -> go into query loop
         if self.args.query == [None]:

+ 14 - 5
code/ID2TLib/AttackController.py

@@ -52,7 +52,7 @@ class AttackController:
         # Record the attack
         self.added_attacks.append(self.current_attack)
 
-    def process_attack(self, attack: str, params: str):
+    def process_attack(self, attack: str, params: str, time=False):
         """
         Takes as input the name of an attack (classname) and the attack parameters as string. Parses the string of
         attack parameters, creates the attack by writing the attack packets and returns the path of the written pcap.
@@ -94,15 +94,24 @@ class AttackController:
         # Write attack into pcap file
         print("Generating attack packets...", end=" ")
         sys.stdout.flush()  # force python to print text immediately
-        total_packets, temp_attack_pcap_path = self.current_attack.generate_attack_pcap()
-        print("done. (total: " + str(total_packets) + " pkts.)")
+        if time:
+            self.current_attack.set_start_time()
+        self.current_attack.generate_attack_packets()
+        if time:
+            self.current_attack.set_finish_time()
+        duration = self.current_attack.get_packet_generation_time()
+        self.total_packets, temp_attack_pcap_path = self.current_attack.generate_attack_pcap()
+        print("done. (total: " + str(self.total_packets) + " pkts", end="")
+        if time:
+            print(" in ", duration, " seconds", end="")
+        print(".)")
 
         # Store label into LabelManager
         l = Label(attack, self.get_attack_start_utime(),
                   self.get_attack_end_utime(), attack_note)
         self.label_mgr.add_labels(l)
 
-        return temp_attack_pcap_path
+        return temp_attack_pcap_path, duration
 
     def get_attack_start_utime(self):
         """
@@ -123,4 +132,4 @@ class AttackController:
         :return: None
         """
         for param_key, param_value in params.items():
-            self.current_attack.add_param_value(param_key, param_value)
+            self.current_attack.add_param_value(param_key, param_value)

+ 7 - 2
code/ID2TLib/Controller.py

@@ -41,21 +41,26 @@ class Controller:
         """
         self.statistics.load_pcap_statistics(flag_write_file, flag_recalculate_stats, flag_print_statistics)
 
-    def process_attacks(self, attacks_config: list, seeds=[]):
+    def process_attacks(self, attacks_config: list, seeds=[], time=False):
         """
         Creates the attack based on the attack name and the attack parameters given in the attacks_config. The
         attacks_config is a list of attacks, e.g.
         [['PortscanAttack', 'ip.src="192.168.178.2",'dst.port=80'],['PortscanAttack', 'ip.src="10.10.10.2"]].
         Merges the individual temporary attack pcaps into one single pcap and merges this single pcap with the
         input dataset.
+
         :param attacks_config: A list of attacks with their attack parameters.
+        :param seeds: A list of random seeds for the given attacks.
+        :param time: Measure time for packet generation.
         """
         # load attacks sequentially
+        self.durations = []
         i = 0
         for attack in attacks_config:
             if len(seeds) > i:
                 self.attack_controller.set_seed(seed=seeds[i][0])
-            temp_attack_pcap = self.attack_controller.process_attack(attack[0], attack[1:])
+            temp_attack_pcap, duration = self.attack_controller.process_attack(attack[0], attack[1:], time)
+            self.durations.append(duration)
             self.written_pcaps.append(temp_attack_pcap)
             i += 1
 

+ 9 - 0
code/ID2TLib/TestLibrary.py

@@ -124,3 +124,12 @@ def get_attacker_config(ip_source_list, ipAddress: str):
 
     return next_port, ttl
 
+
+def write_attack_pcap(self, packets: list, append_flag: bool = False, destination_path: str = None):
+    """
+    temporal efficiency test patch for write_attack_pcap (Attack.BaseAttack.py)
+
+    :return: The path to a dummy pcap file.
+    """
+    os.system("cp " + test_pcap + " " + test_resource_dir + "dummy.pcap")
+    return test_resource_dir + 'dummy.pcap'

+ 47 - 2
code/Test/ID2TAttackTest.py

@@ -13,7 +13,7 @@ class ID2TAttackTest(unittest.TestCase):
 
     def checksum_test(self, attack_args, sha256_checksum, seed=5, cleanup=True, pcap=Lib.test_pcap,
                       flag_write_file=False, flag_recalculate_stats=False, flag_print_statistics=False,
-                      attack_sub_dir=True, test_sub_dir=True):
+                      attack_sub_dir=True, test_sub_dir=True, time=False):
         """
         Runs the attack against a given sha256 checksum.
 
@@ -27,11 +27,13 @@ class ID2TAttackTest(unittest.TestCase):
         :param flag_print_statistics: Prints the statistics on the terminal.
         :param attack_sub_dir: create sub-directory for each attack-class if True
         :param test_sub_dir: create sub-directory for each test-function/case if True
+        :param time: Measure time for packet generation.
         """
 
         controller = Ctrl.Controller(pcap_file_path=pcap, do_extra_tests=False)
         controller.load_pcap_statistics(flag_write_file, flag_recalculate_stats, flag_print_statistics)
-        controller.process_attacks(attack_args, [[seed]])
+
+        controller.process_attacks(attack_args, [[seed]], time)
 
         caller_function = inspect.stack()[1].function
 
@@ -46,6 +48,49 @@ class ID2TAttackTest(unittest.TestCase):
         else:
             Lib.rename_test_result_files(controller, caller_function, attack_sub_dir, test_sub_dir)
 
+    def temporal_efficiency_test(self, attack_args, time_limit=15, factor=1, seed=None, cleanup=True, pcap=Lib.test_pcap,
+                                 flag_write_file=False, flag_recalculate_stats=False, flag_print_statistics=False,
+                                 attack_sub_dir=True, test_sub_dir=True):
+        """
+        Runs the attack with given aruments and monitors time efficiency.
+
+        :param attack_args: A list of attacks with their attack parameters (as defined in Controller.process_attacks).
+        :param time_limit: The given time limit in seconds.
+        :param factor: A factor to scale the generation time (e.g. only 7 pkts generated -> *10000/7 for 15 seconds).
+        :param seed: A random seed to keep random values static (care for count and order of random generation).
+        :param cleanup: Clean up attack output after testing.
+        :param pcap: The input pcap for the attack.
+        :param flag_write_file: Writes the statistics to a file.
+        :param flag_recalculate_stats: Forces the recalculation of statistics.
+        :param flag_print_statistics: Prints the statistics on the terminal.
+        :param attack_sub_dir: create sub-directory for each attack-class if True
+        :param test_sub_dir: create sub-directory for each test-function/case if True
+        """
+
+        controller = Ctrl.Controller(pcap_file_path=pcap, do_extra_tests=False)
+        controller.load_pcap_statistics(flag_write_file, flag_recalculate_stats, flag_print_statistics)
+
+        if seed is None:
+            controller.process_attacks(attack_args, time=True)
+        else:
+            controller.process_attacks(attack_args, [[seed]], time=True)
+
+        duration = controller.durations[0]*factor/controller.attack_controller.total_packets
+        print(attack_args[0][0] + ' needs ' + str(duration) + ' seconds to generate ' + str(factor) + ' packets.')
+
+        caller_function = inspect.stack()[1].function
+
+        try:
+            self.assertLessEqual(duration, time_limit)
+        except self.failureException:
+            Lib.rename_test_result_files(controller, caller_function, attack_sub_dir, test_sub_dir)
+            raise
+
+        if cleanup:
+            Lib.clean_up(controller)
+        else:
+            Lib.rename_test_result_files(self.controller, caller_function, attack_sub_dir, test_sub_dir)
+
     def order_test(self, attack_args, seed=None, cleanup=True, pcap=Lib.test_pcap,
                    flag_write_file=False, flag_recalculate_stats=False, flag_print_statistics=False,
                    attack_sub_dir=True, test_sub_dir=True):

+ 70 - 0
code/Test/efficiency_testing.py

@@ -0,0 +1,70 @@
+import unittest.mock as mock
+
+import ID2TLib.TestLibrary as Lib
+import Test.ID2TAttackTest as Test
+
+
+class EfficiencyTests(Test.ID2TAttackTest):
+
+    def test_SMBLoris_10_000(self):
+        self.temporal_efficiency_test([['SMBLorisAttack', 'attackers.count=30', 'packets.per-second=8.0']],
+                                      time_limit=15, factor=10000)
+
+    def test_SMBLoris_100_000(self):
+        self.temporal_efficiency_test([['SMBLorisAttack', 'attackers.count=30', 'packets.per-second=98']],
+                                      time_limit=150, factor=100000)
+
+    def test_SMBScan_10_000(self):
+        self.temporal_efficiency_test([['SMBScanAttack', 'ip.src=192.168.178.1',
+                                        'ip.dst=192.168.178.10-192.168.197.145']], time_limit=15, factor=10000)
+
+    def test_SMBScan_100_000(self):
+        self.temporal_efficiency_test([['SMBScanAttack', 'ip.src=192.168.178.1', 'ip.dst=192.168.0.1-192.168.195.76']],
+                                      time_limit=150, factor=100000)
+
+    def test_SMBScan_hosting_10_000(self):
+        self.temporal_efficiency_test([['SMBScanAttack', 'ip.src=192.168.178.1',
+                                        'ip.dst=192.168.178.10-192.168.181.241',
+                                        'hosting.ip=192.168.178.10-192.168.181.241']], time_limit=15, factor=10000)
+
+    def test_SMBScan_hosting_100_000(self):
+        self.temporal_efficiency_test([['SMBScanAttack', 'ip.src=192.168.178.1', 'ip.dst=192.168.178.10-192.168.217.25',
+                                        'hosting.ip=192.168.178.10-192.168.217.25']], time_limit=150, factor=100000)
+
+    @mock.patch('ID2TLib.Utility.get_rnd_bytes', side_effect=Lib.get_bytes)
+    @mock.patch('ID2TLib.Utility.get_rnd_x86_nop', side_effect=Lib.get_x86_nop)
+    def test_FTPExploit(self, mock_get_rnd_x86_nop, mock_get_rnd_bytes):
+        self.temporal_efficiency_test([['FTPWinaXeExploit', 'ip.src=192.168.178.1', 'ip.dst=192.168.178.10']],
+                                      time_limit=15, factor=10000)
+
+    def test_PortscanAttack_open_10_000(self):
+        self.temporal_efficiency_test([['PortscanAttack', 'ip.src=192.168.178.1', 'port.open=80']], time_limit=15,
+                                      factor=10000)
+
+    def test_PortscanAttack_close_10_000(self):
+        self.temporal_efficiency_test([['PortscanAttack', 'ip.src=192.168.178.1', 'port.open=20']], time_limit=15,
+                                      factor=10000)
+
+    def test_SQLi_10_000(self):
+        # FIXME: sometimes it takes 15.34028493521018 instead of the normal 7.150923313737726 seconds
+        self.temporal_efficiency_test([['SQLiAttack', 'ip.dst=192.168.0.1']], time_limit=15, factor=10000)
+
+    def test_Joomla_10_000(self):
+        self.temporal_efficiency_test([['JoomlaRegPrivExploit', 'ip.src=192.168.178.1']], time_limit=15, factor=10000)
+
+    def test_SalityBotnet_10_000(self):
+        self.temporal_efficiency_test([['SalityBotnet']], time_limit=15, factor=10000)
+
+    @mock.patch('Attack.BaseAttack.BaseAttack.write_attack_pcap', side_effect=Lib.write_attack_pcap)
+    def test_DDoS_10_000(self, mock_write_attack_pcap):
+        # TODO: update attack args, when DDoS gets refactored
+        self.temporal_efficiency_test([['DDoSAttack', 'attackers.count=100', 'packets.per-second=95',
+                                        'attack.duration=150']], time_limit=15, factor=10000)
+
+    @mock.patch('Attack.BaseAttack.BaseAttack.write_attack_pcap', side_effect=Lib.write_attack_pcap)
+    def test_DDoS_100_000(self, mock_write_attack_pcap):
+        # TODO: update attack args, when DDoS gets refactored
+        self.temporal_efficiency_test([['DDoSAttack', 'attackers.count=1000', 'packets.per-second=950',
+                                        'attack.duration=300']], time_limit=150, factor=100000)
+
+    # TODO: add temporal efficiency test(s) for EternalBlue and MS17

+ 6 - 6
code/Test/test_SMBScan.py

@@ -2,14 +2,14 @@ import unittest.mock as mock
 
 import Test.ID2TAttackTest as Test
 
-sha_default = '213e194da7bc952cc093868c7450901b0fb93c7255d694eb37ea0b9b48bca65d'
+sha_default = 'ef321877edfd828f6e6cd4abbffb5ade9cb66b3acd54ba9f3a5e2bfbeac9c964'
 sha_one_victim_linux = '4928d421caaec8f2c4e5c5bb835b5521b705478779cbc8f343b77143a5a66995'
-sha_victim_range_winxp_hosting = '4c6cb5cb4f838e75b41af4feb2fd9a6fe7e1b226a38b3e8759ce3d31e5a2535e'
-sha_multiple_victims_macos = '0be79b9ad7346562f392e07a5156de978e02f4f25ae8d409b81cc6e0d726012c'
-sha_port_shuffle = '8ef501fa31135b8fea845a2be6a9605e0c3f9c4895b717f9206d485a669c2a73'
+sha_victim_range_winxp_hosting = '57a0b7dd69a5bba35404af574d4f06ef52ac2b3b292703596dabd2d1c31721b0'
+sha_multiple_victims_macos = '82d6d7e0471e6395c77df7b5bac141e48d50afe22841c7c53747bbfdd0de184d'
+sha_port_shuffle = '85d4fd1b44e41cfb30d5758c7264f4d5509701c04a0f12495b4155011fc3aaaa'
 sha_dest_mac_only = '0814dadb666e0056ef5b3a572a4971f333376b61e602acb84cb99c851845f016'
-sha_ip_src_shuffle = '6c0c9ccbedb631e4965ec36932276a1bd73b8a4aca5a5c46f01fd0a2800a064f'
-sha_smb2 = '8755a901295a90362d8041ecf1243a31fff582f5fe64555205625263c253476e'
+sha_ip_src_shuffle = 'f070db569ecf4e17003e60f9ac53c064279c732ccb2128c13c8a7e3b64adc846'
+sha_smb2 = '9d78ac62d76a811c62e0ba7f0ed88569fd133cc06756451a58021be5e1c9fb61'
 
 # TODO: improve coverage