Browse Source

move seed handling

remove seed handling in GenericTest
add seed param to BaseAttack
Jens Keim 6 years ago
parent
commit
9b00e6d3d0

+ 3 - 0
code/Attack/AttackParameters.py

@@ -45,6 +45,9 @@ class Parameter(Enum):
     CUSTOM_PAYLOAD = 'custom.payload'  # custom payload for ftp exploits
     CUSTOM_PAYLOAD_FILE = 'custom.payload.file'  # file that contains custom payload for ftp exploits
 
+    # benchmark
+    SEED = 'seed'
+
 
 class ParameterTypes(Enum):
     """

+ 6 - 1
code/Attack/BaseAttack.py

@@ -41,7 +41,7 @@ class BaseAttack(metaclass=ABCMeta):
         self.attack_description = description
         self.attack_type = attack_type
         self.params = {}
-        self.supported_params = {}
+        self.supported_params = {Parameter.SEED: ParameterTypes.TYPE_INTEGER_POSITIVE}
         self.attack_start_utime = 0
         self.attack_end_utime = 0
 
@@ -248,6 +248,11 @@ class BaseAttack(metaclass=ABCMeta):
     # HELPER METHODS
     #########################################
 
+    def set_seed(self, seed: int):
+        if seed:
+            self.add_param_value(Parameter.SEED, seed)
+            random.seed(self.get_param_value(Parameter.SEED))
+
     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

+ 2 - 2
code/Attack/DDoSAttack.py

@@ -28,7 +28,7 @@ class DDoSAttack(BaseAttack.BaseAttack):
                                         "Resource Exhaustion")
 
         # Define allowed parameters and their type
-        self.supported_params = {
+        self.supported_params.update({
             Param.IP_SOURCE: ParameterTypes.TYPE_IP_ADDRESS,
             Param.MAC_SOURCE: ParameterTypes.TYPE_MAC_ADDRESS,
             Param.PORT_SOURCE: ParameterTypes.TYPE_PORT,
@@ -41,7 +41,7 @@ class DDoSAttack(BaseAttack.BaseAttack):
             Param.NUMBER_ATTACKERS: ParameterTypes.TYPE_INTEGER_POSITIVE,
             Param.ATTACK_DURATION: ParameterTypes.TYPE_INTEGER_POSITIVE,
             Param.VICTIM_BUFFER: ParameterTypes.TYPE_INTEGER_POSITIVE
-        }
+        })
 
     def init_params(self):
         """

+ 2 - 2
code/Attack/EternalBlueExploit.py

@@ -34,7 +34,7 @@ class EternalBlueExploit(BaseAttack.BaseAttack):
                                         "Privilege elevation")
 
         # Define allowed parameters and their type
-        self.supported_params = {
+        self.supported_params.update({
             Param.MAC_SOURCE: ParameterTypes.TYPE_MAC_ADDRESS,
             Param.IP_SOURCE: ParameterTypes.TYPE_IP_ADDRESS,
             Param.PORT_SOURCE: ParameterTypes.TYPE_PORT,
@@ -44,7 +44,7 @@ class EternalBlueExploit(BaseAttack.BaseAttack):
             Param.INJECT_AT_TIMESTAMP: ParameterTypes.TYPE_FLOAT,
             Param.INJECT_AFTER_PACKET: ParameterTypes.TYPE_PACKET_POSITION,
             Param.PACKETS_PER_SECOND: ParameterTypes.TYPE_FLOAT
-        }
+        })
 
     def init_params(self):
         """

+ 2 - 2
code/Attack/FTPWinaXeExploit.py

@@ -29,7 +29,7 @@ class FTPWinaXeExploit(BaseAttack.BaseAttack):
                                                "Privilege elevation")
 
         # Define allowed parameters and their type
-        self.supported_params = {
+        self.supported_params.update({
             Param.IP_SOURCE: ParameterTypes.TYPE_IP_ADDRESS,
             Param.IP_DESTINATION: ParameterTypes.TYPE_IP_ADDRESS,
             Param.MAC_SOURCE: ParameterTypes.TYPE_MAC_ADDRESS,
@@ -40,7 +40,7 @@ class FTPWinaXeExploit(BaseAttack.BaseAttack):
             Param.PACKETS_PER_SECOND: ParameterTypes.TYPE_FLOAT,
             Param.CUSTOM_PAYLOAD: ParameterTypes.TYPE_STRING,
             Param.CUSTOM_PAYLOAD_FILE: ParameterTypes.TYPE_STRING
-        }
+        })
 
     def init_params(self):
         """

+ 2 - 2
code/Attack/JoomlaRegPrivExploit.py

@@ -33,7 +33,7 @@ class JoomlaRegPrivExploit(BaseAttack.BaseAttack):
                                         "Privilege elevation")
 
         # Define allowed parameters and their type
-        self.supported_params = {
+        self.supported_params.update({
             Param.MAC_SOURCE: ParameterTypes.TYPE_MAC_ADDRESS,
             Param.IP_SOURCE: ParameterTypes.TYPE_IP_ADDRESS,
             Param.MAC_DESTINATION: ParameterTypes.TYPE_MAC_ADDRESS,
@@ -44,7 +44,7 @@ class JoomlaRegPrivExploit(BaseAttack.BaseAttack):
             Param.INJECT_AT_TIMESTAMP: ParameterTypes.TYPE_FLOAT,
             Param.INJECT_AFTER_PACKET: ParameterTypes.TYPE_PACKET_POSITION,
             Param.PACKETS_PER_SECOND: ParameterTypes.TYPE_FLOAT
-        }
+        })
 
     def init_params(self):
         """

+ 2 - 2
code/Attack/PortscanAttack.py

@@ -27,7 +27,7 @@ class PortscanAttack(BaseAttack.BaseAttack):
                                              "Scanning/Probing")
 
         # Define allowed parameters and their type
-        self.supported_params = {
+        self.supported_params.update({
             Param.IP_SOURCE: ParameterTypes.TYPE_IP_ADDRESS,
             Param.IP_DESTINATION: ParameterTypes.TYPE_IP_ADDRESS,
             Param.PORT_SOURCE: ParameterTypes.TYPE_PORT,
@@ -42,7 +42,7 @@ class PortscanAttack(BaseAttack.BaseAttack):
             Param.IP_SOURCE_RANDOMIZE: ParameterTypes.TYPE_BOOLEAN,
             Param.PACKETS_PER_SECOND: ParameterTypes.TYPE_FLOAT,
             Param.PORT_SOURCE_RANDOMIZE: ParameterTypes.TYPE_BOOLEAN
-        }
+        })
 
     def init_params(self):
         """

+ 9 - 10
code/Attack/SMBLorisAttack.py

@@ -1,6 +1,6 @@
 import logging
 
-from random import randint, uniform
+import random
 from lea import Lea
 from scapy.layers.inet import IP, Ether, TCP
 from scapy.layers.netbios import NBTSession
@@ -27,7 +27,7 @@ class SMBLorisAttack(BaseAttack.BaseAttack):
                                              "Resource Exhaustion")
 
         # Define allowed parameters and their type
-        self.supported_params = {
+        self.supported_params.update({
             Param.IP_SOURCE: ParameterTypes.TYPE_IP_ADDRESS,
             Param.IP_DESTINATION: ParameterTypes.TYPE_IP_ADDRESS,
             Param.MAC_SOURCE: ParameterTypes.TYPE_MAC_ADDRESS,
@@ -37,23 +37,22 @@ class SMBLorisAttack(BaseAttack.BaseAttack):
             Param.PACKETS_PER_SECOND: ParameterTypes.TYPE_FLOAT,
             Param.ATTACK_DURATION: ParameterTypes.TYPE_INTEGER_POSITIVE,
             Param.NUMBER_ATTACKERS: ParameterTypes.TYPE_INTEGER_POSITIVE
-        }
+        })
 
     def init_params(self):
         """
         Initialize the parameters of this attack using the user supplied command line parameters.
         Use the provided statistics to calculate default parameters and to process user
         supplied queries.
-
-        :param statistics: Reference to a statistics object.
         """
+
         # PARAMETERS: initialize with default values
         # (values are overwritten if user specifies them)
         most_used_ip_address = self.statistics.get_most_used_ip_address()
 
         # The most used IP class in background traffic
         most_used_ip_class = handle_most_used_outputs(self.statistics.process_db_query("most_used(ipClass)"))
-        num_attackers = randint(1, 16)
+        num_attackers = random.randint(1, 16)
         source_ip = self.generate_random_ipv4_address(most_used_ip_class, num_attackers)
 
         self.add_param_value(Param.IP_SOURCE, source_ip)
@@ -72,7 +71,7 @@ class SMBLorisAttack(BaseAttack.BaseAttack):
         self.add_param_value(Param.PACKETS_PER_SECOND,
                              (self.statistics.get_pps_sent(most_used_ip_address) +
                               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()))
+        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):
@@ -136,13 +135,13 @@ class SMBLorisAttack(BaseAttack.BaseAttack):
             # Get MSS, TTL and Window size value for source IP(attacker)
             source_mss_value, source_ttl_value, source_win_value = self.get_ip_data(ip_source_list[attacker])
 
-            attacker_seq = randint(1000, 50000)
-            victim_seq = randint(1000, 50000)
+            attacker_seq = random.randint(1000, 50000)
+            victim_seq = random.randint(1000, 50000)
 
             sport = 1025
 
             # Timestamps of first packets shouldn't be exactly the same to look more realistic
-            timestamp_next_pkt = uniform(first_timestamp, update_timestamp(first_timestamp, pps))
+            timestamp_next_pkt = random.uniform(first_timestamp, update_timestamp(first_timestamp, pps))
 
             while timestamp_next_pkt <= attack_ends_time:
                 # Establish TCP connection

+ 3 - 4
code/Attack/SMBScanAttack.py

@@ -32,7 +32,7 @@ class SMBScanAttack(BaseAttack.BaseAttack):
                                              "Scanning/Probing")
 
         # Define allowed parameters and their type
-        self.supported_params = {
+        self.supported_params.update({
             Param.IP_SOURCE: ParameterTypes.TYPE_IP_ADDRESS,
             Param.IP_DESTINATION: ParameterTypes.TYPE_IP_ADDRESS,
             Param.PORT_SOURCE: ParameterTypes.TYPE_PORT,
@@ -48,16 +48,15 @@ class SMBScanAttack(BaseAttack.BaseAttack):
             Param.SOURCE_PLATFORM: ParameterTypes.TYPE_STRING,
             Param.PROTOCOL_VERSION: ParameterTypes.TYPE_STRING,
             Param.IP_DESTINATION_END: ParameterTypes.TYPE_IP_ADDRESS
-        }
+        })
 
     def init_params(self):
         """
         Initialize the parameters of this attack using the user supplied command line parameters.
         Use the provided statistics to calculate default parameters and to process user
         supplied queries.
-
-        :param statistics: Reference to a statistics object.
         """
+
         # PARAMETERS: initialize with default values
         # (values are overwritten if user specifies them)
         most_used_ip_address = self.statistics.get_most_used_ip_address()

+ 14 - 15
code/Attack/SQLiAttack.py

@@ -1,6 +1,6 @@
 import logging
+import random
 
-from random import randint
 from lea import Lea
 from scapy.utils import RawPcapReader
 from scapy.layers.inet import Ether
@@ -33,7 +33,7 @@ class SQLiAttack(BaseAttack.BaseAttack):
                                         "Privilege elevation")
 
         # Define allowed parameters and their type
-        self.supported_params = {
+        self.supported_params.update({
             Param.MAC_SOURCE: ParameterTypes.TYPE_MAC_ADDRESS,
             Param.IP_SOURCE: ParameterTypes.TYPE_IP_ADDRESS,
             Param.MAC_DESTINATION: ParameterTypes.TYPE_MAC_ADDRESS,
@@ -44,16 +44,15 @@ class SQLiAttack(BaseAttack.BaseAttack):
             Param.INJECT_AT_TIMESTAMP: ParameterTypes.TYPE_FLOAT,
             Param.INJECT_AFTER_PACKET: ParameterTypes.TYPE_PACKET_POSITION,
             Param.PACKETS_PER_SECOND: ParameterTypes.TYPE_FLOAT
-        }
+        })
 
     def init_params(self):
         """
         Initialize the parameters of this attack using the user supplied command line parameters.
         Use the provided statistics to calculate default parameters and to process user
         supplied queries.
-
-        :param statistics: Reference to a statistics object.
         """
+
         # PARAMETERS: initialize with default utilsvalues
         # (values are overwritten if user specifies them)
         # Attacker configuration
@@ -74,7 +73,7 @@ class SQLiAttack(BaseAttack.BaseAttack):
         self.add_param_value(Param.TARGET_HOST, "www.hackme.com")
 
         # Attack configuration
-        self.add_param_value(Param.INJECT_AFTER_PACKET, randint(0, self.statistics.get_packet_count()))
+        self.add_param_value(Param.INJECT_AFTER_PACKET, random.randint(0, self.statistics.get_packet_count()))
         self.add_param_value(Param.PACKETS_PER_SECOND,
                              (self.statistics.get_pps_sent(most_used_ip_address) +
                               self.statistics.get_pps_received(most_used_ip_address)) / 2)
@@ -126,13 +125,13 @@ class SQLiAttack(BaseAttack.BaseAttack):
         timeSteps = Lea.fromValFreqsDict(inter_arrival_time_dist)
         exploit_raw_packets = RawPcapReader(self.template_attack_pcap_path)
 
-        port_source = randint(self.minDefaultPort,self.maxDefaultPort) # experiments show this range of ports
+        port_source = random.randint(self.minDefaultPort,self.maxDefaultPort) # experiments show this range of ports
 
         # Random TCP sequence numbers
         global attacker_seq
-        attacker_seq = randint(1000, 50000)
+        attacker_seq = random.randint(1000, 50000)
         global victim_seq
-        victim_seq = randint(1000, 50000)
+        victim_seq = random.randint(1000, 50000)
 
         for pkt_num, pkt in enumerate(exploit_raw_packets):
             eth_frame = Ether(pkt[0])
@@ -156,11 +155,11 @@ class SQLiAttack(BaseAttack.BaseAttack):
 
                     # There are 363 TCP connections with different source ports, for each of them we generate random port
                     if tcp_pkt.getfieldval("sport") != prev_orig_port_source and tcp_pkt.getfieldval("dport") != 4444:
-                        port_source = randint(self.minDefaultPort, self.maxDefaultPort)
+                        port_source = random.randint(self.minDefaultPort, self.maxDefaultPort)
                         prev_orig_port_source = tcp_pkt.getfieldval("sport")
                         # New connection, new random TCP sequence numbers
-                        attacker_seq = randint(1000, 50000)
-                        victim_seq = randint(1000, 50000)
+                        attacker_seq = random.randint(1000, 50000)
+                        victim_seq = random.randint(1000, 50000)
                         # First packet in a connection has ACK = 0
                         tcp_pkt.setfieldval("ack", 0)
 
@@ -219,11 +218,11 @@ class SQLiAttack(BaseAttack.BaseAttack):
             # The last connection
             else:
                 # New connection, new random TCP sequence numbers
-                attacker_seq = randint(1000, 50000)
-                victim_seq = randint(1000, 50000)
+                attacker_seq = random.randint(1000, 50000)
+                victim_seq = random.randint(1000, 50000)
                 # First packet in a connection has ACK = 0
                 tcp_pkt.setfieldval("ack", 0)
-                #port_source = randint(self.minDefaultPort, self.maxDefaultPort)
+                #port_source = random.randint(self.minDefaultPort, self.maxDefaultPort)
 
                 # Attacker --> vicitm
                 if ip_pkt.getfieldval("dst") == orig_ip_dst:  # victim IP

+ 2 - 2
code/Attack/SalityBotnet.py

@@ -26,13 +26,13 @@ class SalityBotnet(BaseAttack.BaseAttack):
                                         "Botnet")
 
         # Define allowed parameters and their type
-        self.supported_params = {
+        self.supported_params.update({
             Param.MAC_SOURCE: ParameterTypes.TYPE_MAC_ADDRESS,
             Param.IP_SOURCE: ParameterTypes.TYPE_IP_ADDRESS,
             Param.INJECT_AT_TIMESTAMP: ParameterTypes.TYPE_FLOAT,
             Param.INJECT_AFTER_PACKET: ParameterTypes.TYPE_PACKET_POSITION,
             Param.PACKETS_PER_SECOND: ParameterTypes.TYPE_FLOAT
-        }
+        })
 
     def init_params(self):
         """

+ 10 - 4
code/ID2TLib/AttackController.py

@@ -21,10 +21,11 @@ class AttackController:
         self.current_attack = None
         self.added_attacks = []
 
-    def create_attack(self, attack_name: str):
+    def create_attack(self, attack_name: str, seed: int):
         """
         Creates dynamically a new class instance based on the given attack_name.
         :param attack_name: The name of the attack, must correspond to the attack's class name.
+        :param seed: random seed for param generation
         :return: None
         """
         print("\nCreating attack instance of \033[1m" + attack_name + "\033[0m")
@@ -36,6 +37,7 @@ class AttackController:
         self.current_attack = attack_class()
         # Initialize the parameters of the attack with defaults or user supplied values.
         self.current_attack.set_statistics(self.statistics)
+        self.current_attack.set_seed(seed=seed)
         self.current_attack.init_params()
         # Record the attack
         self.added_attacks.append(self.current_attack)
@@ -48,9 +50,6 @@ class AttackController:
         :param params: The parameters for attack customization, see attack class for supported params.
         :return: The file path to the created pcap file.
         """
-        self.create_attack(attack)
-
-        # Add attack parameters if provided
         print("Validating and adding attack parameters.")
         params_dict = []
         if isinstance(params, list) and params:
@@ -58,6 +57,13 @@ class AttackController:
             for entry in params:
                 params_dict.append(entry.split('='))
             params_dict = dict(params_dict)
+
+        seed = params_dict['seed']
+
+        self.create_attack(attack, seed)
+
+        # Add attack parameters if provided
+        if params_dict is not []:
             # Check if Parameter.INJECT_AT_TIMESTAMP and Parameter.INJECT_AFTER_PACKET are provided at the same time
             # if TRUE: delete Paramter.INJECT_AT_TIMESTAMP (lower priority) and use Parameter.INJECT_AFTER_PACKET
             if (Parameter.INJECT_AFTER_PACKET.value in params_dict) and (

+ 1 - 2
code/Test/GenericTest.py

@@ -1,4 +1,3 @@
-import random
 import unittest
 import inspect
 
@@ -11,9 +10,9 @@ class GenericTest(unittest.TestCase):
     def generic_test(self, attack_args, sha_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):
         # TODO: move seed to attacks
-        random.seed(seed)
         controller = Ctrl.Controller(pcap_file_path=pcap, do_extra_tests=False)
         controller.load_pcap_statistics(flag_write_file, flag_recalculate_stats, flag_print_statistics)
+        attack_args[0].append("seed=" + str(seed))
         controller.process_attacks(attack_args)
 
         caller_function = inspect.stack()[1].function