Browse Source

Add Carlos changes

aidmar.wainakh 6 years ago
parent
commit
01107a681c

+ 6 - 4
.gitignore

@@ -14,14 +14,16 @@ code_boost/src/build/*
 
 
 #captures
 #captures
 captures/*
 captures/*
+
+#labels
 tures/*
 tures/*
+
 code/*.pcap
 code/*.pcap
 code/*.xml
 code/*.xml
-code_boost/src/SQLiteCpp/
-code_boost/src/cmake-build-debug/*
-test.py
 dbs/
 dbs/
 *.csv
 *.csv
-code_boost/src/CMakeLists.txt
+*.stat
 code_boost/src/cxx/CMakeLists.txt
 code_boost/src/cxx/CMakeLists.txt
 code_boost/src/cxx/cmake-build-debug/
 code_boost/src/cxx/cmake-build-debug/
+code_boost/src/SQLiteCpp/
+code_boost/src/cmake-build-debug/

+ 11 - 4
build.sh

@@ -1,24 +1,31 @@
 #!/bin/bash
 #!/bin/bash
 
 
+# Create the Makefile using cmake, from a clean build directory
 cd code_boost/src/build/
 cd code_boost/src/build/
+if [ ${PWD##*/} = 'build' ]; then
+    # Only delete everything if we are in a folder called 'build'.
+    rm -rf ./*
+else
+    echo "Error: The 'build' directory was not found."
+    exit
+fi
 cmake ..
 cmake ..
 
 
 if [ -f Makefile ]; then
 if [ -f Makefile ]; then
     make
     make
 else
 else
-    echo "CMake did not finish successfully."
+    echo "Error: 'cmake' did not finish successfully."
     exit
     exit
 fi
 fi
 
 
 if [ $? -eq 0 ]; then
 if [ $? -eq 0 ]; then
     cp libpcapreader.so ../../../code/ID2TLib/
     cp libpcapreader.so ../../../code/ID2TLib/
 else
 else
-    echo "Make did not finish successfully."
+    echo "Error: 'make' did not finish successfully."
     exit
     exit
 fi
 fi
 
 
 cd ../../../
 cd ../../../
-#ln -s code/CLI.py id2t.py
 
 
 # Create the ID2T script
 # Create the ID2T script
 cat >./id2t  <<EOF
 cat >./id2t  <<EOF
@@ -34,5 +41,5 @@ EOF
 chmod +x ./code/CLI.py
 chmod +x ./code/CLI.py
 chmod +x ./id2t
 chmod +x ./id2t
 
 
-echo -e "\n\nAll is set. ID2T is ready to be used."
+echo -e "\n\nAll is set. ID2T is ready."
 echo -e "\nRun ID2T with the command './id2t'"
 echo -e "\nRun ID2T with the command './id2t'"

+ 35 - 14
code/Attack/BaseAttack.py

@@ -1,16 +1,13 @@
-# Aidmar
-from scapy.layers.inet import Ether
 import socket
 import socket
 import sys
 import sys
-from math import sqrt
-
 import ipaddress
 import ipaddress
 import os
 import os
 import random
 import random
 import re
 import re
 import tempfile
 import tempfile
 from abc import abstractmethod, ABCMeta
 from abc import abstractmethod, ABCMeta
-import numpy as np # TO-DO: it needs to be added to required packages
+from scapy.layers.inet import Ether
+import numpy as np
 
 
 import ID2TLib.libpcapreader as pr
 import ID2TLib.libpcapreader as pr
 from scapy.utils import PcapWriter
 from scapy.utils import PcapWriter
@@ -20,13 +17,12 @@ from Attack.AttackParameters import Parameter
 from Attack.AttackParameters import ParameterTypes
 from Attack.AttackParameters import ParameterTypes
 
 
 
 
-
 class BaseAttack(metaclass=ABCMeta):
 class BaseAttack(metaclass=ABCMeta):
     """
     """
     Abstract base class for all attack classes. Provides basic functionalities, like parameter validation.
     Abstract base class for all attack classes. Provides basic functionalities, like parameter validation.
     """
     """
 
 
-    def __init__(self, statistics, name, description, attack_type):
+    def __init__(self, name, description, attack_type):
         """
         """
         To be called within the individual attack class to initialize the required parameters.
         To be called within the individual attack class to initialize the required parameters.
 
 
@@ -36,7 +32,7 @@ class BaseAttack(metaclass=ABCMeta):
         :param attack_type: The type the attack belongs to, like probing/scanning, malware.
         :param attack_type: The type the attack belongs to, like probing/scanning, malware.
         """
         """
         # Reference to statistics class
         # Reference to statistics class
-        self.statistics = statistics
+        self.statistics = None
 
 
         # Class fields
         # Class fields
         self.attack_name = name
         self.attack_name = name
@@ -47,6 +43,25 @@ class BaseAttack(metaclass=ABCMeta):
         self.attack_start_utime = 0
         self.attack_start_utime = 0
         self.attack_end_utime = 0
         self.attack_end_utime = 0
 
 
+    def set_statistics(self, statistics):
+        """
+        Specify the statistics object that will be used to calculate the parameters of this attack.
+        The statistics are used to calculate default parameters and to process user supplied
+        queries.
+
+        :param statistics: Reference to a statistics object.
+        """
+        self.statistics = statistics
+
+    @abstractmethod
+    def init_params(self):
+        """
+        Initialize all required parameters taking into account user supplied values. If no value is supplied,
+        or if a user defined query is supplied, use a statistics object to do the calculations.
+        A call to this function requires a call to 'set_statistics' first.
+        """
+        pass
+
     @abstractmethod
     @abstractmethod
     def generate_attack_pcap(self):
     def generate_attack_pcap(self):
         """
         """
@@ -237,10 +252,16 @@ class BaseAttack(metaclass=ABCMeta):
         Adds the pair param : value to the dictionary of attack parameters. Prints and error message and skips the
         Adds the pair param : value to the dictionary of attack parameters. Prints and error message and skips the
         parameter if the validation fails.
         parameter if the validation fails.
 
 
-        :param param: The parameter name.
-        :param value: The parameter's value.
+        :param stats: Statistics used to calculate user queries or default values.
+        :param param: Name of the parameter that we wish to modify.
+        :param value: The value we wish to assign to the specifried parameter.
         :return: None.
         :return: None.
         """
         """
+        # This function call is valid only if there is a statistics object available.
+        if self.statistics is None:
+            print('Error: Attack parameter added without setting a statistics object first.')
+            exit(1)
+
         # by default no param is valid
         # by default no param is valid
         is_valid = False
         is_valid = False
 
 
@@ -479,10 +500,10 @@ class BaseAttack(metaclass=ABCMeta):
 
 
            """
            """
         result = self.statistics.process_db_query(
         result = self.statistics.process_db_query(
-            "SELECT AVG(minDelay), AVG(maxDelay) FROM conv_statistics WHERE ipAddressB='" + ip_dst + "';")
-        if result[0][1] and result[0][2]:
-            minDelay = result[0][1]
-            maxDelay = result[0][2]
+            "SELECT AVG(minDelay), AVG(maxDelay) FROM conv_statistics WHERE ipAddressB='6.6.6.6';") #" + ip_dst + "';")
+        if result[0][0] and result[0][1]:
+            minDelay = result[0][0]
+            maxDelay = result[0][1]
         else:
         else:
             allMinDelays = self.statistics.process_db_query("SELECT minDelay FROM conv_statistics LIMIT 500;")
             allMinDelays = self.statistics.process_db_query("SELECT minDelay FROM conv_statistics LIMIT 500;")
             minDelay = np.median(allMinDelays)
             minDelay = np.median(allMinDelays)

+ 10 - 3
code/Attack/DDoSAttack.py

@@ -15,14 +15,13 @@ from collections import deque
 
 
 
 
 class DDoSAttack(BaseAttack.BaseAttack):
 class DDoSAttack(BaseAttack.BaseAttack):
-    def __init__(self, statistics, pcap_file_path):
+    def __init__(self):
         """
         """
         Creates a new instance of the DDoS attack.
         Creates a new instance of the DDoS attack.
 
 
-        :param statistics: A reference to the statistics class.
         """
         """
         # Initialize attack
         # Initialize attack
-        super(DDoSAttack, self).__init__(statistics, "DDoS Attack", "Injects a DDoS attack'",
+        super(DDoSAttack, self).__init__("DDoS Attack", "Injects a DDoS attack'",
                                         "Resource Exhaustion")
                                         "Resource Exhaustion")
 
 
         # Define allowed parameters and their type
         # Define allowed parameters and their type
@@ -42,6 +41,14 @@ class DDoSAttack(BaseAttack.BaseAttack):
             Param.VICTIM_BUFFER: ParameterTypes.TYPE_INTEGER_POSITIVE
             Param.VICTIM_BUFFER: 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
         # PARAMETERS: initialize with default values
         # (values are overwritten if user specifies them)
         # (values are overwritten if user specifies them)
         self.add_param_value(Param.INJECT_AFTER_PACKET, randint(0, self.statistics.get_packet_count()))
         self.add_param_value(Param.INJECT_AFTER_PACKET, randint(0, self.statistics.get_packet_count()))

+ 10 - 3
code/Attack/EternalBlueExploit.py

@@ -21,14 +21,13 @@ class EternalBlueExploit(BaseAttack.BaseAttack):
     maxDefaultPort = 50000
     maxDefaultPort = 50000
     last_conn_dst_port = 4444
     last_conn_dst_port = 4444
 
 
-    def __init__(self, statistics, pcap_file_path):
+    def __init__(self):
         """
         """
         Creates a new instance of the EternalBlue Exploit.
         Creates a new instance of the EternalBlue Exploit.
 
 
-        :param statistics: A reference to the statistics class.
         """
         """
         # Initialize attack
         # Initialize attack
-        super(EternalBlueExploit, self).__init__(statistics, "EternalBlue Exploit", "Injects an EternalBlue exploit'",
+        super(EternalBlueExploit, self).__init__("EternalBlue Exploit", "Injects an EternalBlue exploit'",
                                         "Resource Exhaustion")
                                         "Resource Exhaustion")
 
 
         # Define allowed parameters and their type
         # Define allowed parameters and their type
@@ -42,6 +41,14 @@ class EternalBlueExploit(BaseAttack.BaseAttack):
             Param.PACKETS_PER_SECOND: ParameterTypes.TYPE_FLOAT
             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
         # PARAMETERS: initialize with default utilsvalues
         # (values are overwritten if user specifies them)
         # (values are overwritten if user specifies them)
         most_used_ip_address = self.statistics.get_most_used_ip_address()
         most_used_ip_address = self.statistics.get_most_used_ip_address()

+ 10 - 3
code/Attack/JoomlaRegPrivExploit.py

@@ -21,14 +21,13 @@ class JoomlaRegPrivExploit(BaseAttack.BaseAttack):
     minDefaultPort = 30000
     minDefaultPort = 30000
     maxDefaultPort = 50000
     maxDefaultPort = 50000
 
 
-    def __init__(self, statistics, pcap_file_path):
+    def __init__(self):
         """
         """
         Creates a new instance of the Joomla Registeration Privileges Escalation Exploit.
         Creates a new instance of the Joomla Registeration Privileges Escalation Exploit.
 
 
-        :param statistics: A reference to the statistics class.
         """
         """
         # Initialize attack
         # Initialize attack
-        super(JoomlaRegPrivExploit, self).__init__(statistics, "JoomlaRegPrivesc Exploit", "Injects an JoomlaRegPrivesc exploit'",
+        super(JoomlaRegPrivExploit, self).__init__("JoomlaRegPrivesc Exploit", "Injects an JoomlaRegPrivesc exploit'",
                                         "Resource Exhaustion")
                                         "Resource Exhaustion")
 
 
         # Define allowed parameters and their type
         # Define allowed parameters and their type
@@ -44,6 +43,14 @@ class JoomlaRegPrivExploit(BaseAttack.BaseAttack):
             Param.PACKETS_PER_SECOND: ParameterTypes.TYPE_FLOAT
             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
         # PARAMETERS: initialize with default utilsvalues
         # (values are overwritten if user specifies them)
         # (values are overwritten if user specifies them)
         most_used_ip_address = self.statistics.get_most_used_ip_address()
         most_used_ip_address = self.statistics.get_most_used_ip_address()

+ 37 - 29
code/Attack/PortscanAttack.py

@@ -15,41 +15,14 @@ from scapy.layers.inet import IP, Ether, TCP
 import numpy as np
 import numpy as np
 
 
 class PortscanAttack(BaseAttack.BaseAttack):
 class PortscanAttack(BaseAttack.BaseAttack):
-    # Aidmar
-    def get_ports_from_nmap_service_dst(self, ports_num):
-        """
-        Read the most ports_num frequently open ports from nmap-service-tcp file to be used in the port scan.
-
-        :return: Ports numbers to be used as default destination ports or default open ports in the port scan.
-        """
-        ports_dst = []
-        spamreader = csv.reader(open('resources/nmap-services-tcp.csv', 'rt'), delimiter=',')
-        for count in range(ports_num):
-            # escape first row (header)
-            next(spamreader)
-            # save ports numbers
-            ports_dst.append(next(spamreader)[0])
-        # shuffle ports numbers partially
-        if(ports_num==1000): # used for port.dst
-            temp_array = [[0 for i in range(10)] for i in range(100)]
-            port_dst_shuffled = []
-            for count in range(0, 9):
-                temp_array[count] = ports_dst[count * 100:count * 100 + 99]
-                shuffle(temp_array[count])
-                port_dst_shuffled += temp_array[count]
-        else: # used for port.open
-            shuffle(ports_dst)
-            port_dst_shuffled = ports_dst
-        return port_dst_shuffled
 
 
-    def __init__(self, statistics, pcap_file_path):
+    def __init__(self):
         """
         """
         Creates a new instance of the PortscanAttack.
         Creates a new instance of the PortscanAttack.
 
 
-        :param statistics: A reference to the statistics class.
         """
         """
         # Initialize attack
         # Initialize attack
-        super(PortscanAttack, self).__init__(statistics, "Portscan Attack", "Injects a nmap 'regular scan'",
+        super(PortscanAttack, self).__init__("Portscan Attack", "Injects a nmap 'regular scan'",
                                              "Scanning/Probing")
                                              "Scanning/Probing")
 
 
         # Define allowed parameters and their type
         # Define allowed parameters and their type
@@ -70,6 +43,14 @@ class PortscanAttack(BaseAttack.BaseAttack):
             Param.PORT_SOURCE_RANDOMIZE: ParameterTypes.TYPE_BOOLEAN
             Param.PORT_SOURCE_RANDOMIZE: ParameterTypes.TYPE_BOOLEAN
         }
         }
 
 
+    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
         # PARAMETERS: initialize with default values
         # (values are overwritten if user specifies them)
         # (values are overwritten if user specifies them)
         most_used_ip_address = self.statistics.get_most_used_ip_address()
         most_used_ip_address = self.statistics.get_most_used_ip_address()
@@ -102,6 +83,33 @@ class PortscanAttack(BaseAttack.BaseAttack):
                               self.statistics.get_pps_received(most_used_ip_address)) / 2)
                               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, randint(0, self.statistics.get_packet_count()))
 
 
+    # Aidmar
+    def get_ports_from_nmap_service_dst(self, ports_num):
+        """
+        Read the most ports_num frequently open ports from nmap-service-tcp file to be used in the port scan.
+
+        :return: Ports numbers to be used as default destination ports or default open ports in the port scan.
+        """
+        ports_dst = []
+        spamreader = csv.reader(open('resources/nmap-services-tcp.csv', 'rt'), delimiter=',')
+        for count in range(ports_num):
+            # escape first row (header)
+            next(spamreader)
+            # save ports numbers
+            ports_dst.append(next(spamreader)[0])
+        # shuffle ports numbers partially
+        if (ports_num == 1000):  # used for port.dst
+            temp_array = [[0 for i in range(10)] for i in range(100)]
+            port_dst_shuffled = []
+            for count in range(0, 9):
+                temp_array[count] = ports_dst[count * 100:count * 100 + 99]
+                shuffle(temp_array[count])
+                port_dst_shuffled += temp_array[count]
+        else:  # used for port.open
+            shuffle(ports_dst)
+            port_dst_shuffled = ports_dst
+        return port_dst_shuffled
+
     def generate_attack_pcap(self):
     def generate_attack_pcap(self):
         def update_timestamp(timestamp, pps, delay=0):
         def update_timestamp(timestamp, pps, delay=0):
             """
             """

+ 10 - 3
code/Attack/SQLiAttack.py

@@ -21,14 +21,13 @@ class SQLiAttack(BaseAttack.BaseAttack):
     minDefaultPort = 30000
     minDefaultPort = 30000
     maxDefaultPort = 50000
     maxDefaultPort = 50000
 
 
-    def __init__(self, statistics, pcap_file_path):
+    def __init__(self):
         """
         """
         Creates a new instance of the SQLi Attack.
         Creates a new instance of the SQLi Attack.
 
 
-        :param statistics: A reference to the statistics class.
         """
         """
         # Initialize attack
         # Initialize attack
-        super(SQLiAttack, self).__init__(statistics, "SQLi Attack", "Injects a SQLi attack'",
+        super(SQLiAttack, self).__init__("SQLi Attack", "Injects a SQLi attack'",
                                         "Resource Exhaustion")
                                         "Resource Exhaustion")
 
 
         # Define allowed parameters and their type
         # Define allowed parameters and their type
@@ -44,6 +43,14 @@ class SQLiAttack(BaseAttack.BaseAttack):
             Param.PACKETS_PER_SECOND: ParameterTypes.TYPE_FLOAT
             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
         # PARAMETERS: initialize with default utilsvalues
         # (values are overwritten if user specifies them)
         # (values are overwritten if user specifies them)
         most_used_ip_address = self.statistics.get_most_used_ip_address()
         most_used_ip_address = self.statistics.get_most_used_ip_address()

+ 101 - 73
code/CLI.py

@@ -23,13 +23,112 @@ class CLI(object):
         self.args = None
         self.args = None
         self.attack_config = None
         self.attack_config = None
 
 
+    def parse_arguments(self, args):
+        """
+        Defines the allowed application arguments and invokes the evaluation of the arguments.
+
+        :param args: The application arguments
+        """
+        # Create parser for arguments
+        parser = argparse.ArgumentParser(description="Intrusion Detection Dataset Toolkit (ID2T) - A toolkit for "
+                                         "injecting synthetically created attacks into PCAP files.",
+                                         prog="id2t")
+        # Required arguments
+        required_group = parser.add_argument_group('required arguments')
+        required_args_group = required_group.add_mutually_exclusive_group(required=True)
+        required_args_group.add_argument('-i', '--input', metavar="PCAP_FILE",
+                                         help='path to the input pcap file')
+        required_args_group.add_argument('-l', '--list-attacks', action='store_true')
+
+        # Optional arguments
+        parser.add_argument('-c', '--config', metavar='CONFIG_FILE', help='file containing configuration parameters.',
+                            action=LoadFromFile, type=open)
+        parser.add_argument('-e', '--export',
+                            help='store statistics as a ".stat" file',
+                            action='store_true', default=False)
+        parser.add_argument('-r', '--recalculate',
+                            help='recalculate statistics even if a cached version exists.',
+                            action='store_true', default=False)
+        parser.add_argument('-s', '--statistics', help='print file statistics to stdout.', action='store_true',
+                            default=False)
+        parser.add_argument('-p', '--plot', help='creates statistics plots.', action='append',
+                            nargs='?')
+        parser.add_argument('-q', '--query', metavar="QUERY",
+                            action='append', nargs='?',
+                            help='query the statistics database. If no query is provided, the application enters query mode.')
+        parser.add_argument('-t', '--extraTests', help='perform extra tests on the input pcap file, including calculating IP entropy'
+                                                       'in interval-wise, TCP checksum, and checking payload availability.', action='store_true')
+
+        # Attack arguments
+        parser.add_argument('-a', '--attack', metavar="ATTACK", action='append',
+                                       help='injects ATTACK into a PCAP file.', nargs='+')
+
+        # Parse arguments
+        self.args = parser.parse_args(args)
+
+        self.process_arguments()
+
     def process_arguments(self):
     def process_arguments(self):
+        """
+        Decide what to do with each  of the command line parameters.
+        """
+        if self.args.list_attacks:
+            # User wants to see the available attacks
+            self.process_attack_listing()
+        else:
+            # User wants to process a PCAP
+            self.process_pcap()
+
+    def process_attack_listing(self):
+        import pkgutil
+        import importlib
+        import Attack
+
+        # Find all attacks, exclude some classes
+        package = Attack
+        attack_names = []
+        for _, name, __ in pkgutil.iter_modules(package.__path__):
+            if name != 'BaseAttack' and name != 'AttackParameters':
+                attack_names.append(name)
+
+        # List the attacks and their parameters
+        emph_start = '\033[1m'
+        emph_end = '\033[0m'
+        for attack_name in attack_names:
+            attack_module = importlib.import_module('Attack.{}'.format(attack_name))
+            attack_class = getattr(attack_module, attack_name)
+            # Instantiate the attack to get to its definitions.
+            attack_obj = attack_class()
+            print('* {}{}{}'.format(emph_start, attack_obj.attack_name, emph_end))
+            print('\t- {}Description:{} {}'.format(emph_start, emph_end,
+                                                   attack_obj.attack_description))
+            print('\t- {}Type:{} {}'.format(emph_start, emph_end,
+                                            attack_obj.attack_type))
+            print('\t- {}Supported Parameters:{}'.format(emph_start, emph_end), end=' ')
+            # Get all the parameter names in a list and sort them
+            param_list = []
+            for key in attack_obj.supported_params:
+                param_list.append(key.value)
+            param_list.sort()
+            # Print each parameter type per line
+            last_prefix = None
+            current_prefix = None
+            for param in param_list:
+                current_prefix = param.split('.')[0]
+                if not last_prefix or current_prefix != last_prefix:
+                    print('\n\t + |', end=' ')
+                print(param, end=' | ')
+                last_prefix = current_prefix
+            # Print an empty line
+            print()
+
+    def process_pcap(self):
         """
         """
         Loads the application controller, the PCAP file statistics and if present, processes the given attacks. Evaluates
         Loads the application controller, the PCAP file statistics and if present, processes the given attacks. Evaluates
         given queries.
         given queries.
         """
         """
         # Create ID2T Controller
         # Create ID2T Controller
-        controller = Controller(self.args.input, self.args.tests)
+        controller = Controller(self.args.input, self.args.extraTests)
 
 
         # Load PCAP statistics
         # Load PCAP statistics
         controller.load_pcap_statistics(self.args.export, self.args.recalculate, self.args.statistics)
         controller.load_pcap_statistics(self.args.export, self.args.recalculate, self.args.statistics)
@@ -50,54 +149,6 @@ class CLI(object):
         elif self.args.query is not None:
         elif self.args.query is not None:
             controller.process_db_queries(self.args.query, True)
             controller.process_db_queries(self.args.query, True)
 
 
-    def parse_arguments(self, args):
-        """
-        Defines the allowed application arguments and invokes the evaluation of the arguments.
-
-        :param args: The application arguments
-        """
-        # Create parser for arguments
-        parser = argparse.ArgumentParser(description="Intrusion Detection Dataset Toolkit (ID2T) - A toolkit for "
-                                         "injection of synthetically created attacks into PCAP datasets.",
-                                         prog="id2t")
-        # Define required arguments
-        requiredNamed = parser.add_argument_group('required named arguments')
-        requiredNamed.add_argument('-i', '--input', metavar="FILEPATH", help='path to the input pcap file', required=True)
-
-        # Define optional arguments
-        parser.add_argument('-c', '--config', metavar='FILEPATH', help='file containing parameters used as input.',
-                            action=LoadFromFile, type=open)
-        parser.add_argument('-e', '--export',
-                            help='stores the statistics as a textfile with ending .stat into the dataset directory',
-                            action='store_true', default=False)
-        parser.add_argument('-a', '--attack', metavar="ATTACKNAME", action='append',
-                            help='injects a new attack into the given dataset. '
-                                 'Attacks parameters are: ip.src, ip.dst, ip.dns, mac.src, mac.dst, port.open, '
-                                 'port.dst, port.src, packets.limit, attackers.count, attack.duration, victim.buffer, '
-                                 'target.uri, target.host, packets.per-second, inject.at-timestamp, inject.after-pkt, '
-                                 'port.dst.shuffle, port.dst.order-desc, ip.src.shuffle, port.src.shuffle', nargs='+')
-        parser.add_argument('-r', '--recalculate',
-                            help='forces to recalculate the statistics in case of an already existing statistics database.',
-                            action='store_true', default=False)
-        parser.add_argument('-s', '--statistics', help='print general file statistics to stdout.', action='store_true',
-                            default=False)
-        parser.add_argument('-p', '--plot', help='creates a plot of common dataset statistics', action='append',
-                            nargs='?')
-        parser.add_argument('-q', '--query', metavar="QUERY",
-                            action='append', nargs='?',
-                            help='queries the statistics database. If no query is provided, the application enters into query mode.')
-        # Aidmar
-        parser.add_argument('-t', '--tests', help='perform defects tests on input pcap file.', action='store_true')
-
-        # Parse arguments
-        self.args = parser.parse_args(args)
-
-        # Either PCAP filepath or GUI mode must be enabled
-        if not self.args.input:
-            parser.error("Parameter -i/--input required. See available options with -h/--help ")
-
-        self.process_arguments()
-
 def main(args):
 def main(args):
     """
     """
     Creates a new CLI object and invokes the arguments parsing.
     Creates a new CLI object and invokes the arguments parsing.
@@ -108,29 +159,6 @@ def main(args):
     # Check arguments
     # Check arguments
     cli.parse_arguments(args)
     cli.parse_arguments(args)
 
 
-# Test main
-"""def main_0(args):
-    from scapy.utils import RawPcapReader
-    from scapy.layers.inet import IP, Ether, TCP
-
-    pkts = RawPcapReader("Win7_eternalblue_scan_vulnerable.pcap")
-    for pkt in pkts:
-        eth_frame = Ether(pkt[0])
-        ip_pkt = eth_frame.payload
-        tcp_pkt = ip_pkt.payload
-
-        new_pkt = (eth_frame / ip_pkt / tcp_pkt)
-        new_pkt.time = 0
-
-
-        print(tcp_pkt.getfieldval("sport"))
-"""
-
-
-
 # Uncomment to enable calling by terminal
 # Uncomment to enable calling by terminal
 if __name__ == '__main__':
 if __name__ == '__main__':
-    main(sys.argv[1:])
-
-
-
+    main(sys.argv[1:])

+ 10 - 19
code/ID2TLib/AttackController.py

@@ -1,16 +1,13 @@
 import importlib
 import importlib
 import sys
 import sys
 
 
-#Aidmar
-import time
-
 from Attack.AttackParameters import Parameter
 from Attack.AttackParameters import Parameter
 from ID2TLib import LabelManager
 from ID2TLib import LabelManager
 from ID2TLib import Statistics
 from ID2TLib import Statistics
 from ID2TLib.Label import Label
 from ID2TLib.Label import Label
 from ID2TLib.PcapFile import PcapFile
 from ID2TLib.PcapFile import PcapFile
 
 
- 
+
 class AttackController:
 class AttackController:
     def __init__(self, pcap_file: PcapFile, statistics_class: Statistics, label_manager: LabelManager):
     def __init__(self, pcap_file: PcapFile, statistics_class: Statistics, label_manager: LabelManager):
         """
         """
@@ -24,9 +21,6 @@ class AttackController:
         self.current_attack = None
         self.current_attack = None
         self.added_attacks = []
         self.added_attacks = []
 
 
-        # The PCAP where the attack should be injected into
-        self.base_pcap = self.statistics.pcap_filepath
-
     def create_attack(self, attack_name: str):
     def create_attack(self, attack_name: str):
         """
         """
         Creates dynamically a new class instance based on the given attack_name.
         Creates dynamically a new class instance based on the given attack_name.
@@ -38,8 +32,12 @@ class AttackController:
         attack_module = importlib.import_module("Attack." + attack_name)
         attack_module = importlib.import_module("Attack." + attack_name)
         attack_class = getattr(attack_module, attack_name)
         attack_class = getattr(attack_module, attack_name)
 
 
-        # Set current attack
-        self.current_attack = attack_class(self.statistics, self.base_pcap)
+        # Instantiate the desired attack
+        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.init_params()
+        # Record the attack
         self.added_attacks.append(self.current_attack)
         self.added_attacks.append(self.current_attack)
 
 
     def process_attack(self, attack: str, params: str):
     def process_attack(self, attack: str, params: str):
@@ -55,7 +53,7 @@ class AttackController:
         # Add attack parameters if provided
         # Add attack parameters if provided
         print("Validating and adding attack parameters.")
         print("Validating and adding attack parameters.")
         params_dict = []
         params_dict = []
-        if params is not None:
+        if isinstance(params, list) and params:
             # Convert attack param list into dictionary
             # Convert attack param list into dictionary
             for entry in params:
             for entry in params:
                 params_dict.append(entry.split('='))
                 params_dict.append(entry.split('='))
@@ -78,10 +76,7 @@ class AttackController:
             # Pass paramters to attack controller
             # Pass paramters to attack controller
             self.set_params(params_dict)
             self.set_params(params_dict)
         else:
         else:
-            attack_note = ""
-
-        # Aidmar
-        start_time = time.clock()
+            attack_note = "This attack used only (random) default parameters."
 
 
         # Write attack into pcap file
         # Write attack into pcap file
         print("Generating attack packets...", end=" ")
         print("Generating attack packets...", end=" ")
@@ -89,10 +84,6 @@ class AttackController:
         total_packets, temp_attack_pcap_path = self.current_attack.generate_attack_pcap()
         total_packets, temp_attack_pcap_path = self.current_attack.generate_attack_pcap()
         print("done. (total: " + str(total_packets) + " pkts.)")
         print("done. (total: " + str(total_packets) + " pkts.)")
 
 
-        # Aidmar
-        end_time = time.clock()
-        print("Generated Attack in " + str(end_time-start_time)[:4] + " sec")
-
         # Store label into LabelManager
         # Store label into LabelManager
         l = Label(attack, self.get_attack_start_utime(),
         l = Label(attack, self.get_attack_start_utime(),
                   self.get_attack_end_utime(), attack_note)
                   self.get_attack_end_utime(), attack_note)
@@ -119,4 +110,4 @@ class AttackController:
         :return: None
         :return: None
         """
         """
         for param_key, param_value in params.items():
         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)

+ 4 - 8
code/ID2TLib/Controller.py

@@ -8,7 +8,7 @@ from ID2TLib.Statistics import Statistics
 
 
 
 
 class Controller:
 class Controller:
-    def __init__(self, pcap_file_path: str, do_tests: bool): #Aidmar - do_tests
+    def __init__(self, pcap_file_path: str, do_extra_tests: bool):
         """
         """
         Creates a new Controller, acting as a central coordinator for the whole application.
         Creates a new Controller, acting as a central coordinator for the whole application.
         :param pcap_file_path:
         :param pcap_file_path:
@@ -17,17 +17,13 @@ class Controller:
         self.pcap_src_path = pcap_file_path.strip()
         self.pcap_src_path = pcap_file_path.strip()
         self.pcap_dest_path = ''
         self.pcap_dest_path = ''
         self.written_pcaps = []
         self.written_pcaps = []
-        # Aidmar
-        self.do_tests = do_tests
+        self.do_extra_tests = do_extra_tests
 
 
         # Initialize class instances
         # Initialize class instances
         print("Input file: %s" % self.pcap_src_path)
         print("Input file: %s" % self.pcap_src_path)
         self.pcap_file = PcapFile(self.pcap_src_path)
         self.pcap_file = PcapFile(self.pcap_src_path)
         self.label_manager = LabelManager(self.pcap_src_path)
         self.label_manager = LabelManager(self.pcap_src_path)
         self.statistics = Statistics(self.pcap_file)
         self.statistics = Statistics(self.pcap_file)
-        # Aidmar
-        self.statistics.do_tests = self.do_tests
-
         self.statisticsDB = self.statistics.get_statistics_database()
         self.statisticsDB = self.statistics.get_statistics_database()
         self.attack_controller = AttackController(self.pcap_file, self.statistics, self.label_manager)
         self.attack_controller = AttackController(self.pcap_file, self.statistics, self.label_manager)
 
 
@@ -75,7 +71,7 @@ class Controller:
         print("done.")
         print("done.")
 
 
         # delete intermediate PCAP files
         # delete intermediate PCAP files
-        print('Deleting intermediate attack pcap...', end="")
+        print('Deleting intermediate attack pcap...', end=" ")
         sys.stdout.flush()  # force python to print text immediately
         sys.stdout.flush()  # force python to print text immediately
         os.remove(attacks_pcap_path)
         os.remove(attacks_pcap_path)
         print("done.")
         print("done.")
@@ -130,4 +126,4 @@ class Controller:
             params_dict = dict([z.split("=") for z in params])
             params_dict = dict([z.split("=") for z in params])
             self.statistics.plot_statistics(format=params_dict['format'])
             self.statistics.plot_statistics(format=params_dict['format'])
         else:
         else:
-            self.statistics.plot_statistics()
+            self.statistics.plot_statistics()

+ 3 - 5
code/ID2TLib/Statistics.py

@@ -6,8 +6,6 @@ import os
 import time
 import time
 import ID2TLib.libpcapreader as pr
 import ID2TLib.libpcapreader as pr
 import matplotlib
 import matplotlib
-from numpy.random.mtrand import normal
-from scipy.linalg.misc import norm
 
 
 matplotlib.use('Agg')
 matplotlib.use('Agg')
 import matplotlib.pyplot as plt
 import matplotlib.pyplot as plt
@@ -55,7 +53,7 @@ class Statistics:
         if flag_recalculate_stats:
         if flag_recalculate_stats:
             print("Flag -r/--recalculate found. Recalculating statistics.")
             print("Flag -r/--recalculate found. Recalculating statistics.")
 
 
-        # Recalculate statistics if database not exists OR param -r/--recalculate was provided
+        # Recalculate statistics if database does not exist OR param -r/--recalculate is provided
         if (not self.stats_db.get_db_exists()) or flag_recalculate_stats:
         if (not self.stats_db.get_db_exists()) or flag_recalculate_stats:
             self.pcap_proc = pr.pcap_processor(self.pcap_filepath, str(self.do_tests)) # Aidmar - do_tests
             self.pcap_proc = pr.pcap_processor(self.pcap_filepath, str(self.do_tests)) # Aidmar - do_tests
             self.pcap_proc.collect_statistics()
             self.pcap_proc.collect_statistics()
@@ -85,7 +83,7 @@ class Statistics:
         :return: a list of tuples, each consisting of (description, value, unit), where unit is optional.
         :return: a list of tuples, each consisting of (description, value, unit), where unit is optional.
         """
         """
         return [("Pcap file", self.pcap_filepath),
         return [("Pcap file", self.pcap_filepath),
-                ("#Packets", self.get_packet_count(), "packets"),
+                ("Packets", self.get_packet_count(), "packets"),
                 ("Capture length", self.get_capture_duration(), "seconds"),
                 ("Capture length", self.get_capture_duration(), "seconds"),
                 ("Capture start", self.get_pcap_timestamp_start()),
                 ("Capture start", self.get_pcap_timestamp_start()),
                 ("Capture end", self.get_pcap_timestamp_end())]
                 ("Capture end", self.get_pcap_timestamp_end())]
@@ -567,7 +565,7 @@ class Statistics:
 
 
     def plot_statistics(self, format: str = 'pdf'): #'png'):
     def plot_statistics(self, format: str = 'pdf'): #'png'):
         """
         """
-        Plots the statistics associated with the dataset prior attack injection.
+        Plots the statistics associated with the dataset.
         :param format: The format to be used to save the statistics diagrams.
         :param format: The format to be used to save the statistics diagrams.
         """
         """
 
 

+ 0 - 40
code/capture_1.pcap.stat

@@ -1,40 +0,0 @@
-====================== 
-PCAP file information 
-====================== 
-Pcap file:	capture_1.pcap
-#Packets:	23211 packets
-Capture length:	32.503 seconds
-Capture start:	2017-06-12 15:40:36.142820
-Capture end:	2017-06-12 15:47:08.645789
-====================== 
-General statistics 
-====================== 
-Avg. packet rate:	714.1194 packets/sec
-Avg. packet size:	0.0 kbytes
-Avg. packets sent:	321.0 packets
-Avg. bandwidth in:	57.2475 kbit/s
-Avg. bandwidth out:	57.2475 kbit/s
-====================== 
-Tests statistics 
-====================== 
-Payload ratio:	60.0362 %
-Incorrect TCP checksum ratio:	0.0 %
-IP Src Entropy:	3.333 
-IP Src Normalized Entropy:	0.5494 
-IP Dst Entropy:	2.8234 
-IP Dst Normalized Entropy:	0.4606 
-Port 0 count:	0 
-Reserved ports:	0.0 %
-TTL Entropy:	2.8017 
-TTL Normalized Entropy:	0.5892 
-TTL Distribution Entropy:	0.8138 
-WinSize Entropy:	1.9959 
-WinSize Normalized Entropy:	0.6008 
-WinSize Distribution Entropy:	0.415 
-ToS Entropy:	0.3158 
-ToS Normalized Entropy:	0.1579 
-ToS Distribution Entropy:	0.2219 
-MSS Entropy:	1.5384 
-MSS Normalized Entropy:	0.7692 
-MSS Distribution Entropy:	0.2219 
-536 < MSS < 1460:	50.0 %

+ 82 - 0
code_boost/src/CMakeLists.txt

@@ -0,0 +1,82 @@
+##################################
+# DEFINITION OF C++ PROJECT
+##################################
+project(cpp-pcapreader)
+
+# Define CMake settings
+cmake_minimum_required(VERSION 3.2)
+
+IF(NOT CMAKE_BUILD_TYPE)
+   SET(CMAKE_BUILD_TYPE "Release")
+ENDIF()
+
+IF (CMAKE_BUILD_TYPE MATCHES Debug)
+    MESSAGE(STATUS "Running Debug configuration.")
+ELSEIF (CMAKE_BUILD_TYPE MATCHES Release)
+    MESSAGE(STATUS "Running Release configuration.")
+ENDIF()
+
+SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Wall")
+SET(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -Wall")
+
+SET(CMAKE_CXX_STANDARD 11)
+SET(CMAKE_CXX_STANDARD_REQUIRED ON)
+
+# Add the library source files
+SET(SOURCE_FILES cxx/pcap_processor.cpp cxx/pcap_processor.h cxx/statistics.cpp cxx/statistics.h cxx/statistics_db.cpp cxx/statistics_db.h cxx/utilities.h cxx/utilities.cpp)
+
+# Include SQLiteCpp library and build it
+option(SQLITECPP_RUN_CPPLINT OFF)
+include_directories(SQLiteCpp/include)
+add_subdirectory(SQLiteCpp)
+
+# Find libtins library
+FIND_LIBRARY(TINS_LIBRARY tins)
+IF(TINS_LIBRARY)
+  MESSAGE(STATUS "Tins library found in ${TINS_LIBRARY}")
+ELSE()
+  MESSAGE(FATAL_ERROR "Tins library not found.")
+ENDIF()
+
+FIND_PACKAGE(PythonLibs 3.0 REQUIRED)
+IF(PYTHONLIBS_FOUND)
+  INCLUDE_DIRECTORIES("${PYTHON_INCLUDE_DIRS}")
+  MESSAGE(STATUS "Python includes found in: " ${PYTHON_INCLUDE_DIRS} )
+  MESSAGE(STATUS "Python libs found in: " ${PYTHON_LIBRARIES} )
+ELSE()
+  MESSAGE(FATAL_ERROR "Unable to find Python libraries.")
+ENDIF()
+
+# Find and configure BOOST library
+FIND_PACKAGE(Boost 1.54 QUIET)
+IF (Boost_FOUND)
+    INCLUDE_DIRECTORIES("${Boost_INCLUDE_DIRS}")
+    MESSAGE(STATUS "Boots includes found in: " ${Boost_INCLUDE_DIRS} )
+    SET(Boost_USE_STATIC_LIBS OFF)
+    SET(Boost_USE_MULTITHREADED ON)
+    SET(Boost_USE_STATIC_RUNTIME OFF)
+    # Find the boost python 3 component
+    SET(PYTHON_VERSIONS python3 python-py35 python-py34 python-py33 python-py32)
+    FOREACH(VERSION ${PYTHON_VERSIONS})
+      FIND_PACKAGE(Boost COMPONENTS ${VERSION} QUIET)
+      IF(Boost_FOUND)
+        MESSAGE(STATUS "Python Boost found as '${VERSION}'.")
+        BREAK()
+      ENDIF()
+    ENDFOREACH(VERSION)
+    IF(NOT Boost_FOUND)
+      MESSAGE(FATAL_ERROR "Python Boost component not found.")
+    ENDIF()
+ELSE ()
+    MESSAGE(FATAL_ERROR "Unable to find the Boost libraries (version 1.54 or higher).")
+ENDIF ()
+
+SET_target_properties(sqlite3 PROPERTIES POSITION_INDEPENDENT_CODE ON)
+
+ADD_LIBRARY(pcapreader SHARED ${SOURCE_FILES})
+# Libs pthread and dl are prerequisites of SQLiteCpp
+TARGET_LINK_LIBRARIES(pcapreader ${Boost_LIBRARIES} "${TINS_LIBRARY}" ${PYTHON_LIBRARIES} SQLiteCpp sqlite3 pthread dl)
+
+# comment this out to build executable (for development)
+#ADD_EXECUTABLE(cpp-pcapreader ${SOURCE_FILES})
+#TARGET_LINK_LIBRARIES(cpp-pcapreader ${Boost_LIBRARIES} "${TINS_LIBRARY}" SQLiteCpp sqlite3 pthread dl)