52 Commits c2f0cd3b45 ... 49facc020c

Author SHA1 Message Date
  Christof Jugel 49facc020c Merged both libraries 6 years ago
  Aidmar Wainakh 0863a7c2ce Merge branch 'query_input' of stefan.schmidt/ID2T-toolkit into master 6 years ago
  Aidmar Wainakh 7c45541b0a Merge branch 'sqlite_case' of stefan.schmidt/ID2T-toolkit into master 6 years ago
  Aidmar Wainakh 22e6700e08 Merge branch 'query_fix' of stefan.schmidt/ID2T-toolkit into master 6 years ago
  Aidmar Wainakh 7e56df7e6f Merge branch 'readd_logo' of stefan.schmidt/ID2T-toolkit into master 6 years ago
  Stefan Schmidt 08bad36cd0 Added new command to list attacks listed in the label file, if they are available 6 years ago
  Stefan Schmidt 702f4f1b69 Readd logo 6 years ago
  Stefan Schmidt d84dbbf88d Adjusted the help message for the "ipAddress" parameterized query 6 years ago
  Stefan Schmidt e37394d479 Fix: Type of pktsReceived is supposed to be INTEGER 6 years ago
  Stefan Schmidt dbb14983fc Fix: Specify case insensitivity for TEXT-fields for query-mode compatibility 6 years ago
  Stefan Schmidt 277d8e894f Added help command for query mode 6 years ago
  Stefan Schmidt b788c425a6 Fixed type-error occuring for single-element query results 6 years ago
  Stefan Schmidt d0fde87998 Added history persistence (stores 1000 entries) 6 years ago
  Stefan Schmidt e72a678e5f Added tab-completion support for queries 6 years ago
  Stefan Schmidt 5b75797d3c Added readline (enables command history and arrow keys) 6 years ago
  Carlos Garcia 121053b3cb Merge branch 'dep-fix' of stefan.schmidt/ID2T-toolkit into master 6 years ago
  Carlos Garcia 1eb2a34df3 Merge branch 'sqlitecpp' of stefan.schmidt/ID2T-toolkit into master 6 years ago
  Stefan Schmidt f066bb9fe4 Added SQLiteCpp 2.2.0 as a proper submodule 6 years ago
  Carlos Garcia 179bb45350 Merge branch 'smbfixes-final' of stefan.schmidt/ID2T-toolkit into master 6 years ago
  Stefano Acquaviti 9e6dea237f fix issues from previous pull requests 6 years ago
  Stefan Schmidt d22aa79c95 Fix for dependency-script to make it fail less cryptically on weird OSes missing lsb-release 6 years ago
  Carlos Garcia dc5f7ab255 Merge branch 'ftp-exploit-final' of stefan.schmidt/ID2T-toolkit into master 6 years ago
  Jonathan Speth 97845efceb add custom payload support 6 years ago
  Jens Keim 206ef8031f add WinaXe 7.7 FTP Exploit 6 years ago
  Carlos Garcia 6c6d80dbba Merge branch 'utility-lib-final' of stefan.schmidt/ID2T-toolkit into master 6 years ago
  Jens Keim 12318f86b1 refactor library imports 6 years ago
  Roey Regev a7518d61f8 move redundant functions to utility library 6 years ago
  Carlos Garcia 94ff039109 Merge branch 'smbloris-final' of stefan.schmidt/ID2T-toolkit into master 6 years ago
  Carlos Garcia c9c821a60e Merge branch 'smb-scan-final' of stefan.schmidt/ID2T-toolkit into master 6 years ago
  Carlos Garcia 94d6dbe2a2 Merge branch 'fix-inter_arrival_time' of stefan.schmidt/ID2T-toolkit into master 6 years ago
  Carlos Garcia ffc0fcd3f1 Merge branch 'dependency-installer-upstream' of stefan.schmidt/ID2T-toolkit into master 6 years ago
  Carlos Garcia bce320eeb1 Merge branch 'shell-syntax-fix' of stefan.schmidt/ID2T-toolkit into master 6 years ago
  Carlos Garcia 01ad7b4eb9 Merge branch 'fix-merge-attack-pcaps' of stefan.schmidt/ID2T-toolkit into master 6 years ago
  Stefano Acquaviti 9660bbd318 rework SMBLoris to be DDOS 6 years ago
  Stefan Schmidt 3d10fd3a4f add SMBLoris Attack 6 years ago
  Stefano Acquaviti de5b6d0b11 add lib function documentation 6 years ago
  Jonathan Speth c2215ce080 add library for SMB specific functions 6 years ago
  Jonathan Speth 581749ca07 add utility library 6 years ago
  Jens Keim caaddb2896 add platform specifics to SMB scan 6 years ago
  Stefano Acquaviti e0ddd39cab add functionality to SMB scan 6 years ago
  Jens Keim ee834d301e add OS probability distribution 6 years ago
  Stefano Acquaviti 19d1ea6e77 add SMB2 support 6 years ago
  Stefan Schmidt 4ab07b2385 add SMB scan attack 6 years ago
  Stefan Schmidt 92d12016d8 Implemented a dependency-checking and installation script for Arch Linux, Ubuntu and macOS 6 years ago
  Stefan Schmidt 7fac464d08 Fixed get_inter_arrival_time trying to access the interface with an index instead of the timestamp-tuple 6 years ago
  Stefano Acquaviti 4018b1bdb8 fixed filename length of temporary attack pcaps exceeding limit (under ubuntu) 6 years ago
  Stefan Schmidt 9cd1a39707 Syntax fix for non-bash shells 6 years ago
  Stefano Acquaviti e13b04ed6f Fixed merging more than two attack PCAP files 6 years ago
  Carlos Garcia f0d317a891 Merge branch 'macos-buildfix' of stefan.schmidt/ID2T-toolkit into master 6 years ago
  Carlos Garcia a57aa9bef3 Merge branch 'fix-portscan-offbyone' of stefan.schmidt/ID2T-toolkit into master 6 years ago
  Stefan Schmidt 1b2a300f50 Fix: Building and running on macOS 6 years ago
  Stefan Schmidt 7623da5c33 Fix: off-by-one errors in the portscan-attack resulted in only 891 scanned ports 6 years ago

+ 0 - 1
.gitignore

@@ -26,7 +26,6 @@ dbs/
 *pdf
 *pdf
 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/
 code_boost/src/cmake-build-debug/
 
 
 # the resulting executable
 # the resulting executable

+ 1 - 1
README.md

@@ -1,5 +1,5 @@
 <p align="center">
 <p align="center">
-<img src="https://git.tk.informatik.tu-darmstadt.de/attachments/6e9882bf-3b40-4397-9c0d-ac53375f232c"></p>
+<img src="https://git.tk.informatik.tu-darmstadt.de/SPIN/ID2T-toolkit/raw/master/logo/id2t.png"></p>
 
 
 # ID2T - Intrusion Detection Dataset Toolkit
 # ID2T - Intrusion Detection Dataset Toolkit
 A toolkit for injecting synthetic attacks into PCAP files.
 A toolkit for injecting synthetic attacks into PCAP files.

+ 8 - 0
build.sh

@@ -1,5 +1,10 @@
 #!/bin/bash
 #!/bin/bash
 
 
+# Install required packages
+if [ "$1" != '--non-interactive' ]; then
+    ./resources/install_dependencies.sh
+fi
+
 # Create the Makefile using cmake, from a clean build directory
 # Create the Makefile using cmake, from a clean build directory
 cd code_boost/src/build/
 cd code_boost/src/build/
 if [ ${PWD##*/} = 'build' ]; then
 if [ ${PWD##*/} = 'build' ]; then
@@ -31,6 +36,9 @@ cd ../../../
 cat >./id2t  <<EOF
 cat >./id2t  <<EOF
 #!/bin/sh
 #!/bin/sh
 # Find the executable
 # Find the executable
+if [ $(uname) = 'Darwin' ]; then
+    alias readlink='greadlink'
+fi
 ID2T_DIR=\$(readlink -f \$0)
 ID2T_DIR=\$(readlink -f \$0)
 SCRIPT_PATH=\${ID2T_DIR%/*}
 SCRIPT_PATH=\${ID2T_DIR%/*}
 cd \$SCRIPT_PATH
 cd \$SCRIPT_PATH

+ 10 - 0
code/Attack/AttackParameters.py

@@ -10,6 +10,8 @@ class Parameter(Enum):
     IP_SOURCE = 'ip.src'  # source IP address
     IP_SOURCE = 'ip.src'  # source IP address
     IP_DESTINATION = 'ip.dst'  # destination IP address
     IP_DESTINATION = 'ip.dst'  # destination IP address
     IP_DNS = 'ip.dns'  # IP address of DNS server
     IP_DNS = 'ip.dns'  # IP address of DNS server
+    HOSTING_IP = 'hosting.ip'
+    IP_DESTINATION_END = 'ip.dst.end'
     # recommended type: MAC address ------------------------------
     # recommended type: MAC address ------------------------------
     MAC_SOURCE = 'mac.src'  # MAC address of source
     MAC_SOURCE = 'mac.src'  # MAC address of source
     MAC_DESTINATION = 'mac.dst'  # MAC address of destination
     MAC_DESTINATION = 'mac.dst'  # MAC address of destination
@@ -37,6 +39,13 @@ class Parameter(Enum):
     PORT_DEST_ORDER_DESC = 'port.dst.order-desc'  # uses a descending port order instead of a ascending order
     PORT_DEST_ORDER_DESC = 'port.dst.order-desc'  # uses a descending port order instead of a ascending order
     IP_SOURCE_RANDOMIZE = 'ip.src.shuffle'  # randomizes the sources IP address if a list of IP addresses is given
     IP_SOURCE_RANDOMIZE = 'ip.src.shuffle'  # randomizes the sources IP address if a list of IP addresses is given
     PORT_SOURCE_RANDOMIZE = 'port.src.shuffle'  # randomizes the source port if a list of sources ports is given
     PORT_SOURCE_RANDOMIZE = 'port.src.shuffle'  # randomizes the source port if a list of sources ports is given
+
+    PROTOCOL_VERSION = 'protocol.version'
+    HOSTING_VERSION = 'hosting.version'
+    SOURCE_PLATFORM = 'src.platform'
+    CUSTOM_PAYLOAD = 'custom.payload'  # custom payload for ftp exploits
+    CUSTOM_PAYLOAD_FILE = 'custom.payload.file'  # file that contains custom payload for ftp exploits
+
     NAT_PRESENT = 'nat.present'  # if NAT is active, external computers cannot initiate a communication in MembersMgmtCommAttack
     NAT_PRESENT = 'nat.present'  # if NAT is active, external computers cannot initiate a communication in MembersMgmtCommAttack
     TTL_FROM_CAIDA = 'ttl.from.caida'  # if True, TTLs are assigned based on the TTL distributions from the CAIDA dataset
     TTL_FROM_CAIDA = 'ttl.from.caida'  # if True, TTLs are assigned based on the TTL distributions from the CAIDA dataset
     # recommended type: Filepath ------------------------------------
     # recommended type: Filepath ------------------------------------
@@ -69,3 +78,4 @@ class ParameterTypes(Enum):
     TYPE_COMM_TYPE = 10
     TYPE_COMM_TYPE = 10
     TYPE_PERCENTAGE = 11
     TYPE_PERCENTAGE = 11
     TYPE_PADDING = 12
     TYPE_PADDING = 12
+    TYPE_STRING = 9

+ 10 - 4
code/Attack/BaseAttack.py

@@ -5,6 +5,8 @@ import os
 import random
 import random
 import re
 import re
 import tempfile
 import tempfile
+import numpy as np
+
 from abc import abstractmethod, ABCMeta
 from abc import abstractmethod, ABCMeta
 from scapy.layers.inet import Ether
 from scapy.layers.inet import Ether
 import numpy as np, math
 import numpy as np, math
@@ -15,6 +17,7 @@ from scapy.utils import PcapWriter
 from Attack import AttackParameters
 from Attack import AttackParameters
 from Attack.AttackParameters import Parameter
 from Attack.AttackParameters import Parameter
 from Attack.AttackParameters import ParameterTypes
 from Attack.AttackParameters import ParameterTypes
+import ID2TLib.libpcapreader as pr
 
 
 class BaseAttack(metaclass=ABCMeta):
 class BaseAttack(metaclass=ABCMeta):
     """
     """
@@ -344,6 +347,9 @@ class BaseAttack(metaclass=ABCMeta):
             elif isinstance(value, str) and value.isdigit() and int(value) >= 0:
             elif isinstance(value, str) and value.isdigit() and int(value) >= 0:
                 is_valid = True
                 is_valid = True
                 value = int(value)
                 value = int(value)
+        elif param_type == ParameterTypes.TYPE_STRING:
+            if isinstance(value, str):
+                is_valid = True
         elif param_type == ParameterTypes.TYPE_FLOAT:
         elif param_type == ParameterTypes.TYPE_FLOAT:
             is_valid, value = self._is_float(value)
             is_valid, value = self._is_float(value)
             # this is required to avoid that the timestamp's microseconds of the first attack packet is '000000'
             # this is required to avoid that the timestamp's microseconds of the first attack packet is '000000'
@@ -381,7 +387,7 @@ class BaseAttack(metaclass=ABCMeta):
             is_valid, value = self._is_float(value)
             is_valid, value = self._is_float(value)
             if is_valid and (param_name in {Parameter.IP_REUSE_TOTAL, Parameter.IP_REUSE_LOCAL, Parameter.IP_REUSE_EXTERNAL}):
             if is_valid and (param_name in {Parameter.IP_REUSE_TOTAL, Parameter.IP_REUSE_LOCAL, Parameter.IP_REUSE_EXTERNAL}):
                 is_valid = self._is_percentage(value)
                 is_valid = self._is_percentage(value)
-            else: 
+            else:
                 is_valid = False
                 is_valid = False
         elif param_type == ParameterTypes.TYPE_PADDING:
         elif param_type == ParameterTypes.TYPE_PADDING:
             if isinstance(value, int):
             if isinstance(value, int):
@@ -389,9 +395,9 @@ class BaseAttack(metaclass=ABCMeta):
             elif isinstance(value, str) and value.isdigit():
             elif isinstance(value, str) and value.isdigit():
                 is_valid = True
                 is_valid = True
                 value = int(value)
                 value = int(value)
-                
+
             if is_valid:
             if is_valid:
-                is_valid = self._is_padding(value) 
+                is_valid = self._is_padding(value)
 
 
         # add value iff validation was successful
         # add value iff validation was successful
         if is_valid:
         if is_valid:
@@ -573,7 +579,7 @@ class BaseAttack(metaclass=ABCMeta):
         inter_arrival_times = []
         inter_arrival_times = []
         prvsPktTime = 0
         prvsPktTime = 0
         for index, pkt in enumerate(packets):
         for index, pkt in enumerate(packets):
-            timestamp = pkt[1][0] + pkt[1][1]/10**6
+            timestamp = pkt[2][0] + pkt[2][1]/10**6
 
 
             if index == 0:
             if index == 0:
                 prvsPktTime = timestamp
                 prvsPktTime = timestamp

+ 4 - 2
code/Attack/DDoSAttack.py

@@ -1,12 +1,15 @@
 import logging
 import logging
-from random import randint, uniform, choice
 
 
+from random import randint, choice
 from lea import Lea
 from lea import Lea
+from collections import deque
 from scipy.stats import gamma
 from scipy.stats import gamma
+from scapy.layers.inet import IP, Ether, TCP, RandShort
 
 
 from Attack import BaseAttack
 from Attack import BaseAttack
 from Attack.AttackParameters import Parameter as Param
 from Attack.AttackParameters import Parameter as Param
 from Attack.AttackParameters import ParameterTypes
 from Attack.AttackParameters import ParameterTypes
+from ID2TLib.Utility import update_timestamp, get_interval_pps, get_nth_random_element, index_increment
 
 
 logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
 logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
 # noinspection PyPep8
 # noinspection PyPep8
@@ -151,7 +154,6 @@ class DDoSAttack(BaseAttack.BaseAttack):
                 attacker_ttl_mapping[ipAddress] = ttl
                 attacker_ttl_mapping[ipAddress] = ttl
             # return port and TTL
             # return port and TTL
             return next_port, ttl
             return next_port, ttl
-
         BUFFER_SIZE = 1000
         BUFFER_SIZE = 1000
 
 
         # Determine source IP and MAC address
         # Determine source IP and MAC address

+ 5 - 0
code/Attack/EternalBlueExploit.py

@@ -1,11 +1,16 @@
 import logging
 import logging
+
 from random import randint, uniform
 from random import randint, uniform
 
 
 from lea import Lea
 from lea import Lea
+from scapy.utils import RawPcapReader
+from scapy.layers.inet import Ether
 
 
 from Attack import BaseAttack
 from Attack import BaseAttack
 from Attack.AttackParameters import Parameter as Param
 from Attack.AttackParameters import Parameter as Param
 from Attack.AttackParameters import ParameterTypes
 from Attack.AttackParameters import ParameterTypes
+from ID2TLib.Utility import update_timestamp, get_interval_pps
+from ID2TLib.SMBLib import smb_port
 
 
 logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
 logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
 # noinspection PyPep8
 # noinspection PyPep8

+ 259 - 0
code/Attack/FTPWinaXeExploit.py

@@ -0,0 +1,259 @@
+import logging
+
+from random import randint
+from lea import Lea
+from scapy.layers.inet import IP, Ether, TCP
+
+from Attack import BaseAttack
+from Attack.AttackParameters import Parameter as Param
+from Attack.AttackParameters import ParameterTypes
+from ID2TLib.Utility import update_timestamp, generate_source_port_from_platform, get_rnd_x86_nop, forbidden_chars,\
+    get_rnd_bytes, get_bytes_from_file
+
+logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
+# noinspection PyPep8
+
+ftp_port = 21
+
+
+class FTPWinaXeExploit(BaseAttack.BaseAttack):
+
+    def __init__(self):
+        """
+        Creates a new instance of the FTPWinaXeExploit.
+
+        """
+        # Initialize attack
+        super(FTPWinaXeExploit, self).__init__("FTPWinaXe Exploit", "Injects an WinaXe 7.7 FTP Exploit.",
+                                               "Privilege elevation")
+
+        # Define allowed parameters and their type
+        self.supported_params = {
+            Param.IP_SOURCE: ParameterTypes.TYPE_IP_ADDRESS,
+            Param.IP_DESTINATION: ParameterTypes.TYPE_IP_ADDRESS,
+            Param.MAC_SOURCE: ParameterTypes.TYPE_MAC_ADDRESS,
+            Param.MAC_DESTINATION: ParameterTypes.TYPE_MAC_ADDRESS,
+            Param.INJECT_AT_TIMESTAMP: ParameterTypes.TYPE_FLOAT,
+            Param.INJECT_AFTER_PACKET: ParameterTypes.TYPE_PACKET_POSITION,
+            Param.IP_SOURCE_RANDOMIZE: ParameterTypes.TYPE_BOOLEAN,
+            Param.PACKETS_PER_SECOND: ParameterTypes.TYPE_FLOAT,
+            Param.CUSTOM_PAYLOAD: ParameterTypes.TYPE_STRING,
+            Param.CUSTOM_PAYLOAD_FILE: ParameterTypes.TYPE_STRING
+        }
+
+    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.
+
+        """
+        # PARAMETERS: initialize with default values
+        # (values are overwritten if user specifies them)
+        most_used_ip_address = self.statistics.get_most_used_ip_address()
+        if isinstance(most_used_ip_address, list):
+            most_used_ip_address = most_used_ip_address[0]
+
+        # The most used IP class in background traffic
+        most_used_ip_class = self.statistics.process_db_query("most_used(ipClass)")
+        attacker_ip = self.generate_random_ipv4_address(most_used_ip_class)
+        self.add_param_value(Param.IP_DESTINATION, attacker_ip)
+        self.add_param_value(Param.MAC_DESTINATION, self.generate_random_mac_address())
+
+        random_ip_address = self.statistics.get_random_ip_address()
+        # victim should be valid and not equal to attacker
+        while not self.is_valid_ip_address(random_ip_address) or random_ip_address == attacker_ip:
+            random_ip_address = self.statistics.get_random_ip_address()
+
+        self.add_param_value(Param.IP_SOURCE, random_ip_address)
+        victim_mac = self.statistics.get_mac_address(random_ip_address)
+        if isinstance(victim_mac, list) and len(victim_mac) == 0:
+            victim_mac = self.generate_random_mac_address()
+        self.add_param_value(Param.MAC_SOURCE, victim_mac)
+        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.IP_SOURCE_RANDOMIZE, 'False')
+        self.add_param_value(Param.CUSTOM_PAYLOAD, '')
+        self.add_param_value(Param.CUSTOM_PAYLOAD_FILE, '')
+
+    def generate_attack_pcap(self):
+        def get_ip_data(ip_address: str):
+            """
+            :param ip_address: The ip of which (packet-)data shall be returned
+            :return: MSS, TTL and window size values of the given IP
+            """
+            # Set MSS (Maximum Segment Size) based on MSS distribution of IP address
+            mss_dist = self.statistics.get_mss_distribution(ip_address)
+            if len(mss_dist) > 0:
+                mss_prob_dict = Lea.fromValFreqsDict(mss_dist)
+                mss_value = mss_prob_dict.random()
+            else:
+                mss_value = 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)
+            if len(ttl_dist) > 0:
+                ttl_prob_dict = Lea.fromValFreqsDict(ttl_dist)
+                ttl_value = ttl_prob_dict.random()
+            else:
+                ttl_value = 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)
+            if len(win_dist) > 0:
+                win_prob_dict = Lea.fromValFreqsDict(win_dist)
+                win_value = win_prob_dict.random()
+            else:
+                win_value = self.statistics.process_db_query("most_used(winSize)")
+
+            return mss_value, ttl_value, win_value
+
+        def check_payload_len(payload_len: int, limit: int):
+            """
+            Checks if the len of the payload exceeds a given limit
+            :param payload_len: The length of the payload
+            :param limit: The limit of the length of the payload which is allowed
+            """
+
+            if payload_len > limit:
+                print("\nCustom payload too long: ", payload_len, " bytes. Should be a maximum of ", limit, " bytes.")
+                exit(1)
+
+
+        pps = self.get_param_value(Param.PACKETS_PER_SECOND)
+
+        # Timestamp
+        timestamp_next_pkt = self.get_param_value(Param.INJECT_AT_TIMESTAMP)
+        # store start time of attack
+        self.attack_start_utime = timestamp_next_pkt
+
+        # Initialize parameters
+        ip_victim = self.get_param_value(Param.IP_SOURCE)
+        ip_attacker = self.get_param_value(Param.IP_DESTINATION)
+        mac_victim = self.get_param_value(Param.MAC_SOURCE)
+        mac_attacker = self.get_param_value(Param.MAC_DESTINATION)
+
+        custom_payload = self.get_param_value(Param.CUSTOM_PAYLOAD)
+        custom_payload_len = len(custom_payload)
+        custom_payload_limit = 1000
+        check_payload_len(custom_payload_len, custom_payload_limit)
+
+        packets = []
+
+        # Create random victim if specified
+        if self.get_param_value(Param.IP_SOURCE_RANDOMIZE):
+            # The most used IP class in background traffic
+            most_used_ip_class = self.statistics.process_db_query("most_used(ipClass)")
+            ip_victim = self.generate_random_ipv4_address(most_used_ip_class, 1)
+            mac_victim = self.generate_random_mac_address()
+
+        # Get MSS, TTL and Window size value for victim/attacker IP
+        victim_mss_value, victim_ttl_value, victim_win_value = get_ip_data(ip_victim)
+        attacker_mss_value, attacker_ttl_value, attacker_win_value = get_ip_data(ip_attacker)
+
+        minDelay, maxDelay = self.get_reply_delay(ip_attacker)
+
+        attacker_seq = randint(1000, 50000)
+        victim_seq = randint(1000, 50000)
+
+        sport = generate_source_port_from_platform("win7")
+
+        # connection request from victim (client)
+        victim_ether = Ether(src=mac_victim, dst=mac_attacker)
+        victim_ip = IP(src=ip_victim, dst=ip_attacker, ttl=victim_ttl_value, flags='DF')
+        request_tcp = TCP(sport=sport, dport=ftp_port, window=victim_win_value, flags='S',
+                          seq=victim_seq, options=[('MSS', victim_mss_value)])
+        victim_seq += 1
+        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)
+
+        # response from attacker (server)
+        attacker_ether = Ether(src=mac_attacker, dst=mac_victim)
+        attacker_ip = IP(src=ip_attacker, dst=ip_victim, ttl=attacker_ttl_value, flags='DF')
+        reply_tcp = TCP(sport=ftp_port, dport=sport, seq=attacker_seq, ack=victim_seq, flags='SA',
+                        window=attacker_win_value, options=[('MSS', attacker_mss_value)])
+        attacker_seq += 1
+        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)
+
+        # acknowledgement from victim (client)
+        ack_tcp = TCP(sport=sport, dport=ftp_port, seq=victim_seq, ack=attacker_seq, flags='A',
+                      window=victim_win_value, options=[('MSS', victim_mss_value)])
+        ack = (victim_ether / victim_ip / ack_tcp)
+        ack.time = timestamp_next_pkt
+        timestamp_next_pkt = update_timestamp(timestamp_next_pkt, pps)
+        packets.append(ack)
+
+        # FTP exploit packet
+        ftp_tcp = TCP(sport=ftp_port, dport=sport, seq=attacker_seq, ack=victim_seq, flags='PA',
+                        window=attacker_win_value, options=[('MSS', attacker_mss_value)])
+
+        characters = b'220'
+        characters += get_rnd_bytes(2065, forbidden_chars)
+        characters += b'\x96\x72\x01\x68'
+        characters += get_rnd_x86_nop(10, False, forbidden_chars)
+
+        custom_payload_file = self.get_param_value(Param.CUSTOM_PAYLOAD_FILE)
+
+        if custom_payload == '':
+            if custom_payload_file == '':
+                payload = get_rnd_bytes(custom_payload_limit, forbidden_chars)
+            else:
+                payload = get_bytes_from_file(custom_payload_file)
+                check_payload_len(len(payload), custom_payload_limit)
+                payload += get_rnd_x86_nop(custom_payload_limit - len(payload), False, forbidden_chars)
+        else:
+            encoded_payload = custom_payload.encode()
+            payload = get_rnd_x86_nop(custom_payload_limit - custom_payload_len, False, forbidden_chars)
+            payload += encoded_payload
+
+        characters += payload
+        characters += get_rnd_x86_nop(20, False, forbidden_chars)
+        characters += b'\r\n'
+
+        ftp_tcp.add_payload(characters)
+
+        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)
+        attacker_seq += len(ftp_tcp.payload)
+
+        # Fin Ack from attacker
+        fin_ack_tcp = TCP(sport=ftp_port, dport=sport, seq=attacker_seq, ack=victim_seq, flags='FA',
+                        window=attacker_win_value, options=[('MSS', attacker_mss_value)])
+
+        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)
+
+        # Ack from victim on FTP packet
+        ftp_ack_tcp = TCP(sport=sport, dport=ftp_port, seq=victim_seq, ack=attacker_seq, flags='A',
+                      window=victim_win_value, options=[('MSS', victim_mss_value)])
+        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)
+
+        # 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)
+
+        # store end time of attack
+        self.attack_end_utime = packets[-1].time
+
+        # write attack packets to pcap
+        pcap_path = self.write_attack_pcap(sorted(packets, key=lambda pkt: pkt.time))
+
+        # return packets sorted by packet time_sec_start
+        return len(packets), pcap_path

+ 5 - 1
code/Attack/JoomlaRegPrivExploit.py

@@ -1,11 +1,15 @@
 import logging
 import logging
 from random import randint, uniform
 from random import randint, uniform
 
 
+from random import randint
 from lea import Lea
 from lea import Lea
+from scapy.utils import RawPcapReader
+from scapy.layers.inet import Ether
 
 
 from Attack import BaseAttack
 from Attack import BaseAttack
 from Attack.AttackParameters import Parameter as Param
 from Attack.AttackParameters import Parameter as Param
 from Attack.AttackParameters import ParameterTypes
 from Attack.AttackParameters import ParameterTypes
+from ID2TLib.Utility import update_timestamp, get_interval_pps
 
 
 logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
 logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
 # noinspection PyPep8
 # noinspection PyPep8
@@ -78,7 +82,7 @@ class JoomlaRegPrivExploit(BaseAttack.BaseAttack):
                              (self.statistics.get_pps_sent(most_used_ip_address) +
                              (self.statistics.get_pps_sent(most_used_ip_address) +
                               self.statistics.get_pps_received(most_used_ip_address)) / 2)
                               self.statistics.get_pps_received(most_used_ip_address)) / 2)
 
 
-    def generate_attack_pcap(self, context):
+    def generate_attack_pcap(self):
         def update_timestamp(timestamp, pps):
         def update_timestamp(timestamp, pps):
             """
             """
             Calculates the next timestamp to be used based on the packet per second rate (pps) and the maximum delay.
             Calculates the next timestamp to be used based on the packet per second rate (pps) and the maximum delay.

+ 3 - 0
code/Attack/PortscanAttack.py

@@ -4,10 +4,12 @@ import csv
 from random import shuffle, randint, choice, uniform
 from random import shuffle, randint, choice, uniform
 
 
 from lea import Lea
 from lea import Lea
+from scapy.layers.inet import IP, Ether, TCP
 
 
 from Attack import BaseAttack
 from Attack import BaseAttack
 from Attack.AttackParameters import Parameter as Param
 from Attack.AttackParameters import Parameter as Param
 from Attack.AttackParameters import ParameterTypes
 from Attack.AttackParameters import ParameterTypes
+from ID2TLib.Utility import update_timestamp, get_interval_pps
 
 
 logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
 logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
 # noinspection PyPep8
 # noinspection PyPep8
@@ -107,6 +109,7 @@ class PortscanAttack(BaseAttack.BaseAttack):
             port_dst_shuffled = ports_dst
             port_dst_shuffled = ports_dst
         return port_dst_shuffled
         return port_dst_shuffled
 
 
+
     def generate_attack_pcap(self, context):
     def generate_attack_pcap(self, context):
         def update_timestamp(timestamp, pps, delay=0):
         def update_timestamp(timestamp, pps, delay=0):
             """
             """

+ 244 - 0
code/Attack/SMBLorisAttack.py

@@ -0,0 +1,244 @@
+import logging
+
+from random import randint, uniform
+from lea import Lea
+from scapy.layers.inet import IP, Ether, TCP
+from scapy.layers.netbios import NBTSession
+
+from Attack import BaseAttack
+from Attack.AttackParameters import Parameter as Param
+from Attack.AttackParameters import ParameterTypes
+from ID2TLib.Utility import update_timestamp
+from ID2TLib.SMBLib import smb_port
+
+logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
+# noinspection PyPep8
+
+
+class SMBLorisAttack(BaseAttack.BaseAttack):
+
+    def __init__(self):
+        """
+        Creates a new instance of the SMBLorisAttack.
+
+        """
+        # Initialize attack
+        super(SMBLorisAttack, self).__init__("SMBLoris Attack", "Injects an SMBLoris (D)DoS Attack",
+                                             "Resource Exhaustion")
+
+        # Define allowed parameters and their type
+        self.supported_params = {
+            Param.IP_SOURCE: ParameterTypes.TYPE_IP_ADDRESS,
+            Param.IP_DESTINATION: ParameterTypes.TYPE_IP_ADDRESS,
+            Param.MAC_SOURCE: ParameterTypes.TYPE_MAC_ADDRESS,
+            Param.MAC_DESTINATION: ParameterTypes.TYPE_MAC_ADDRESS,
+            Param.INJECT_AT_TIMESTAMP: ParameterTypes.TYPE_FLOAT,
+            Param.INJECT_AFTER_PACKET: ParameterTypes.TYPE_PACKET_POSITION,
+            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()
+        if isinstance(most_used_ip_address, list):
+            most_used_ip_address = most_used_ip_address[0]
+
+        # The most used IP class in background traffic
+        most_used_ip_class = self.statistics.process_db_query("most_used(ipClass)")
+        num_attackers = 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)
+        self.add_param_value(Param.MAC_SOURCE, self.generate_random_mac_address(num_attackers))
+
+        random_ip_address = self.statistics.get_random_ip_address()
+        # ip-dst should be valid and not equal to ip.src
+        while not self.is_valid_ip_address(random_ip_address) or random_ip_address == source_ip:
+            random_ip_address = self.statistics.get_random_ip_address()
+
+        self.add_param_value(Param.IP_DESTINATION, random_ip_address)
+        destination_mac = self.statistics.get_mac_address(random_ip_address)
+        if isinstance(destination_mac, list) and len(destination_mac) == 0:
+            destination_mac = self.generate_random_mac_address()
+        self.add_param_value(Param.MAC_DESTINATION, destination_mac)
+        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.ATTACK_DURATION, 30)
+
+    def generate_attack_pcap(self):
+        def get_ip_data(ip_address: str):
+            """
+            :param ip_address: the ip of which (packet-)data shall be returned
+            :return: MSS, TTL and Window Size values of the given IP
+            """
+            # Set MSS (Maximum Segment Size) based on MSS distribution of IP address
+            mss_dist = self.statistics.get_mss_distribution(ip_address)
+            if len(mss_dist) > 0:
+                mss_prob_dict = Lea.fromValFreqsDict(mss_dist)
+                mss_value = mss_prob_dict.random()
+            else:
+                mss_value = 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)
+            if len(ttl_dist) > 0:
+                ttl_prob_dict = Lea.fromValFreqsDict(ttl_dist)
+                ttl_value = ttl_prob_dict.random()
+            else:
+                ttl_value = 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)
+            if len(win_dist) > 0:
+                win_prob_dict = Lea.fromValFreqsDict(win_dist)
+                win_value = win_prob_dict.random()
+            else:
+                win_value = self.statistics.process_db_query("most_used(winSize)")
+
+            return mss_value, ttl_value, win_value
+
+        pps = self.get_param_value(Param.PACKETS_PER_SECOND)
+
+        # Timestamp
+        first_timestamp = self.get_param_value(Param.INJECT_AT_TIMESTAMP)
+        # store start time of attack
+        self.attack_start_utime = first_timestamp
+
+        # Initialize parameters
+        packets = []
+        ip_destination = self.get_param_value(Param.IP_DESTINATION)
+        mac_destination = self.get_param_value(Param.MAC_DESTINATION)
+
+        # Determine source IP and MAC address
+        num_attackers = self.get_param_value(Param.NUMBER_ATTACKERS)
+        if (num_attackers is not None) and (num_attackers is not 0):  # user supplied Param.NUMBER_ATTACKERS
+            # The most used IP class in background traffic
+            most_used_ip_class = self.statistics.process_db_query("most_used(ipClass)")
+            # Create random attackers based on user input Param.NUMBER_ATTACKERS
+            ip_source = self.generate_random_ipv4_address(most_used_ip_class, num_attackers)
+            mac_source = self.generate_random_mac_address(num_attackers)
+        else:  # user did not supply Param.NUMBER_ATTACKS
+            # use default values for IP_SOURCE/MAC_SOURCE or overwritten values
+            # if user supplied any values for those params
+            ip_source = self.get_param_value(Param.IP_SOURCE)
+            mac_source = self.get_param_value(Param.MAC_SOURCE)
+
+        ip_source_list = []
+        mac_source_list = []
+
+        if isinstance(ip_source, list):
+            ip_source_list = ip_source
+        else:
+            ip_source_list.append(ip_source)
+
+        if isinstance(mac_source, list):
+            mac_source_list = mac_source
+        else:
+            mac_source_list.append(mac_source)
+
+        if (num_attackers is None) or (num_attackers is 0):
+            num_attackers = min(len(ip_source_list), len(mac_source_list))
+
+        # Check ip.src == ip.dst
+        self.ip_src_dst_equal_check(ip_source_list, ip_destination)
+
+        # Get MSS, TTL and Window size value for destination IP
+        destination_mss_value, destination_ttl_value, destination_win_value = get_ip_data(ip_destination)
+
+        minDelay,maxDelay = self.get_reply_delay(ip_destination)
+
+        attack_duration = self.get_param_value(Param.ATTACK_DURATION)
+        attack_ends_time = first_timestamp + attack_duration
+
+        victim_pps = pps*num_attackers
+
+        for attacker in range(num_attackers):
+            # Get MSS, TTL and Window size value for source IP(attacker)
+            source_mss_value, source_ttl_value, source_win_value = get_ip_data(ip_source_list[attacker])
+
+            attacker_seq = randint(1000, 50000)
+            victim_seq = 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))
+
+            while timestamp_next_pkt <= attack_ends_time:
+                # Establish TCP connection
+                if sport > 65535:
+                    sport = 1025
+
+                # prepare reusable Ethernet- and IP-headers
+                attacker_ether = Ether(src=mac_source_list[attacker], dst=mac_destination)
+                attacker_ip = IP(src=ip_source_list[attacker], dst=ip_destination, ttl=source_ttl_value, flags='DF')
+                victim_ether = Ether(src=mac_destination, dst=mac_source_list[attacker])
+                victim_ip = IP(src=ip_destination, dst=ip_source_list[attacker], ttl=destination_ttl_value, flags='DF')
+
+                # connection request from attacker (client)
+                syn_tcp = TCP(sport=sport, dport=smb_port, window=source_win_value, flags='S',
+                              seq=attacker_seq, options=[('MSS', source_mss_value)])
+                attacker_seq += 1
+                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)
+
+                # response from victim (server)
+                synack_tcp = TCP(sport=smb_port, dport=sport, seq=victim_seq, ack=attacker_seq, flags='SA',
+                                 window=destination_win_value, options=[('MSS', destination_mss_value)])
+                victim_seq += 1
+                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)
+
+                # acknowledgement from attacker (client)
+                ack_tcp = TCP(sport=sport, dport=smb_port, seq=attacker_seq, ack=victim_seq, flags='A',
+                              window=source_win_value, options=[('MSS', source_mss_value)])
+                ack = (attacker_ether / attacker_ip / ack_tcp)
+                ack.time = timestamp_next_pkt
+                timestamp_next_pkt = update_timestamp(timestamp_next_pkt, pps)
+                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',
+                              window=source_win_value, options=[('MSS', source_mss_value)])
+                req_payload = NBTSession(TYPE=0x00, LENGTH=0x1FFFF)
+
+                attacker_seq += len(req_payload)
+                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)
+
+                # final ack from victim (server)
+                last_ack_tcp = TCP(sport=smb_port, dport=sport, seq=victim_seq, ack=attacker_seq, flags='A',
+                                   window=destination_win_value, options=[('MSS', destination_mss_value)])
+                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)
+
+                sport += 1
+
+        # store end time of attack
+        self.attack_end_utime = packets[-1].time
+
+        # write attack packets to pcap
+        pcap_path = self.write_attack_pcap(sorted(packets, key=lambda pkt: pkt.time))
+
+        # return packets sorted by packet time_sec_start
+        return len(packets), pcap_path

+ 410 - 0
code/Attack/SMBScanAttack.py

@@ -0,0 +1,410 @@
+import logging
+
+from random import shuffle, randint
+from lea import Lea
+from scapy.layers.inet import IP, Ether, TCP
+from scapy.layers.smb import *
+from scapy.layers.netbios import *
+
+from Attack import BaseAttack
+from Attack.AttackParameters import Parameter as Param
+from Attack.AttackParameters import ParameterTypes
+from ID2TLib.SMB2 import *
+from ID2TLib.Utility import update_timestamp, get_interval_pps, get_rnd_os, get_ip_range,\
+    generate_source_port_from_platform, get_filetime_format
+from ID2TLib.SMBLib import smb_port, smb_versions, smb_dialects, get_smb_version, get_smb_platform_data,\
+    invalid_smb_version
+
+logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
+# noinspection PyPep8
+
+
+class SMBScanAttack(BaseAttack.BaseAttack):
+
+    def __init__(self):
+        """
+        Creates a new instance of the SMBScanAttack.
+
+        """
+        # Initialize attack
+        super(SMBScanAttack, self).__init__("SmbScan Attack", "Injects an SMB scan",
+                                             "Scanning/Probing")
+
+        # Define allowed parameters and their type
+        self.supported_params = {
+            Param.IP_SOURCE: ParameterTypes.TYPE_IP_ADDRESS,
+            Param.IP_DESTINATION: ParameterTypes.TYPE_IP_ADDRESS,
+            Param.PORT_SOURCE: ParameterTypes.TYPE_PORT,
+            Param.MAC_SOURCE: ParameterTypes.TYPE_MAC_ADDRESS,
+            Param.MAC_DESTINATION: ParameterTypes.TYPE_MAC_ADDRESS,
+            Param.INJECT_AT_TIMESTAMP: ParameterTypes.TYPE_FLOAT,
+            Param.INJECT_AFTER_PACKET: ParameterTypes.TYPE_PACKET_POSITION,
+            Param.IP_SOURCE_RANDOMIZE: ParameterTypes.TYPE_BOOLEAN,
+            Param.PACKETS_PER_SECOND: ParameterTypes.TYPE_FLOAT,
+            Param.PORT_SOURCE_RANDOMIZE: ParameterTypes.TYPE_BOOLEAN,
+            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
+        }
+
+    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()
+        if isinstance(most_used_ip_address, list):
+            most_used_ip_address = most_used_ip_address[0]
+
+        self.add_param_value(Param.IP_SOURCE, most_used_ip_address)
+        self.add_param_value(Param.IP_SOURCE_RANDOMIZE, 'False')
+        self.add_param_value(Param.MAC_SOURCE, self.statistics.get_mac_address(most_used_ip_address))
+
+        all_ips = self.statistics.get_ip_addresses()
+        if not isinstance(all_ips, list):
+            ip_destinations = []
+            ip_destinations.append(all_ips)
+        else:
+            ip_destinations = all_ips
+        self.add_param_value(Param.IP_DESTINATION, ip_destinations)
+        destination_mac = []
+        for ip in ip_destinations:
+            destination_mac.append(self.statistics.get_mac_address(str(ip)))
+        if isinstance(destination_mac, list) and len(destination_mac) == 0:
+            destination_mac = self.generate_random_mac_address()
+        self.add_param_value(Param.MAC_DESTINATION, destination_mac)
+        self.add_param_value(Param.PORT_SOURCE, randint(1024, 65535))
+        self.add_param_value(Param.PORT_SOURCE_RANDOMIZE, 'True')
+        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()))
+
+        rnd_ip_count = self.statistics.get_ip_address_count()/2
+        self.add_param_value(Param.HOSTING_IP, self.statistics.get_random_ip_address(rnd_ip_count))
+        self.host_os = get_rnd_os()
+        self.add_param_value(Param.HOSTING_VERSION, get_smb_version(platform=self.host_os))
+        self.add_param_value(Param.SOURCE_PLATFORM, 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 get_ip_data(ip_address: str):
+            """
+            Gets the MSS, TTL and Windows Size values of a given IP
+
+            :param ip_address: the ip of which (packet-)data shall be returned
+            :return: MSS, TTL and Window Size values of the given IP
+            """
+            # Set MSS (Maximum Segment Size) based on MSS distribution of IP address
+            mss_dist = self.statistics.get_mss_distribution(ip_address)
+            if len(mss_dist) > 0:
+                mss_prob_dict = Lea.fromValFreqsDict(mss_dist)
+                mss_value = mss_prob_dict.random()
+            else:
+                mss_value = 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)
+            if len(ttl_dist) > 0:
+                ttl_prob_dict = Lea.fromValFreqsDict(ttl_dist)
+                ttl_value = ttl_prob_dict.random()
+            else:
+                ttl_value = 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)
+            if len(win_dist) > 0:
+                win_prob_dict = Lea.fromValFreqsDict(win_dist)
+                win_value = win_prob_dict.random()
+            else:
+                win_value = self.statistics.process_db_query("most_used(winSize)")
+
+            return mss_value, ttl_value, win_value
+
+        pps = self.get_param_value(Param.PACKETS_PER_SECOND)
+
+        # Calculate complement packet rates of the background traffic for each interval
+        complement_interval_pps = self.statistics.calculate_complement_packet_rates(pps)
+
+
+        # Timestamp
+        timestamp_next_pkt = self.get_param_value(Param.INJECT_AT_TIMESTAMP)
+        # store start time of attack
+        self.attack_start_utime = timestamp_next_pkt
+        timestamp_prv_reply, timestamp_confirm = 0,0
+
+        # Initialize parameters
+        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)
+
+        # Check smb version
+        smb_version = self.get_param_value(Param.PROTOCOL_VERSION)
+        if smb_version not in smb_versions:
+            invalid_smb_version(smb_version)
+        hosting_version = self.get_param_value(Param.HOSTING_VERSION)
+        if hosting_version not in smb_versions:
+            invalid_smb_version(hosting_version)
+        # Check source platform
+        src_platform = self.get_param_value(Param.SOURCE_PLATFORM).lower()
+        packets = []
+
+        # randomize source ports according to platform, if specified
+        if self.get_param_value(Param.PORT_SOURCE_RANDOMIZE):
+            sport = generate_source_port_from_platform(src_platform)
+        else:
+            sport = self.get_param_value(Param.PORT_SOURCE)
+
+        # No destination IP was specified, but a destination MAC was specified, generate IP that fits MAC
+        if isinstance(ip_destinations, list) and isinstance(mac_dest, str):
+            ip_destinations = self.statistics.get_ip_address_from_mac(mac_dest)
+            if len(ip_destinations) == 0:
+                ip_destinations = self.generate_random_ipv4_address("Unknown", 1)
+            # Check ip.src == ip.dst
+            self.ip_src_dst_equal_check(ip_source, ip_destinations)
+
+        ip_dests = []
+        if isinstance(ip_destinations, list):
+            ip_dests = ip_destinations
+        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)
+            shuffle(ip_dests)
+
+        # Randomize source IP, if specified
+        if self.get_param_value(Param.IP_SOURCE_RANDOMIZE):
+            ip_source = self.generate_random_ipv4_address("Unknown", 1)
+            while ip_source in ip_dests:
+                ip_source = self.generate_random_ipv4_address("Unknown", 1)
+            mac_source = self.statistics.get_mac_address(str(ip_source))
+            if len(mac_source) == 0:
+                mac_source = self.generate_random_mac_address()
+
+        # Get MSS, TTL and Window size value for source IP
+        source_mss_value, source_ttl_value, source_win_value = get_ip_data(ip_source)
+
+        for ip in ip_dests:
+
+            if ip != ip_source:
+
+                # Get destination Mac Address
+                mac_destination = self.statistics.get_mac_address(str(ip))
+                if len(mac_destination) == 0:
+                    if isinstance(mac_dest, str):
+                        if len(self.statistics.get_ip_address_from_mac(mac_dest)) != 0:
+                            ip = self.statistics.get_ip_address_from_mac(mac_dest)
+                            self.ip_src_dst_equal_check(ip_source, ip)
+
+                        mac_destination = mac_dest
+
+                    else:
+                        mac_destination = self.generate_random_mac_address()
+
+                # Get MSS, TTL and Window size value for destination IP
+                destination_mss_value, destination_ttl_value, destination_win_value = get_ip_data(ip)
+
+                minDelay, maxDelay = self.get_reply_delay(ip)
+
+                # New connection, new random TCP sequence numbers
+                attacker_seq = randint(1000, 50000)
+                victim_seq = randint(1000, 50000)
+
+                # Randomize source port for each connection if specified
+                if self.get_param_value(Param.PORT_SOURCE_RANDOMIZE):
+                    sport = generate_source_port_from_platform(src_platform, sport)
+
+                # 1) Build request package
+                request_ether = Ether(src=mac_source, dst=mac_destination)
+                request_ip = IP(src=ip_source, dst=ip, ttl=source_ttl_value, flags='DF')
+                request_tcp = TCP(sport=sport, dport=smb_port, window=source_win_value, flags='S',
+                                  seq=attacker_seq, options=[('MSS', source_mss_value)])
+                attacker_seq += 1
+                request = (request_ether / request_ip / request_tcp)
+                request.time = timestamp_next_pkt
+
+                # Append request
+                packets.append(request)
+
+                # Update timestamp for next package
+                timestamp_reply = update_timestamp(timestamp_next_pkt, pps, minDelay)
+                while (timestamp_reply <= timestamp_prv_reply):
+                    timestamp_reply = update_timestamp(timestamp_prv_reply, pps, minDelay)
+                timestamp_prv_reply = timestamp_reply
+
+                if ip in hosting_ip:
+
+                    # 2) Build TCP packages for ip that hosts SMB
+
+                    # destination sends SYN, ACK
+                    reply_ether = Ether(src=mac_destination, dst=mac_source)
+                    reply_ip = IP(src=ip, dst=ip_source, ttl=destination_ttl_value, flags='DF')
+                    reply_tcp = TCP(sport=smb_port, dport=sport, seq=victim_seq, ack=attacker_seq, flags='SA',
+                                    window=destination_win_value, options=[('MSS', destination_mss_value)])
+                    victim_seq += 1
+                    reply = (reply_ether / reply_ip / reply_tcp)
+                    reply.time = timestamp_reply
+                    packets.append(reply)
+
+                    # requester confirms, ACK
+                    confirm_ether = request_ether
+                    confirm_ip = request_ip
+                    confirm_tcp = TCP(sport=sport, dport=smb_port, seq=attacker_seq, ack=victim_seq,
+                                      window=source_win_value, flags='A')
+                    confirm = (confirm_ether / confirm_ip / confirm_tcp)
+                    timestamp_confirm = update_timestamp(timestamp_reply, pps, minDelay)
+                    confirm.time = timestamp_confirm
+                    packets.append(confirm)
+
+                    smb_MID = randint(1, 65535)
+                    smb_PID = randint(1, 65535)
+                    smb_req_tail_arr = []
+                    smb_req_tail_size = 0
+
+                    # select dialects based on smb version
+                    if smb_version is "1":
+                        smb_req_dialects = smb_dialects[0:6]
+                    else:
+                        smb_req_dialects = smb_dialects
+                    if len(smb_req_dialects) == 0:
+                        smb_req_tail_arr.append(SMBNegociate_Protocol_Request_Tail())
+                        smb_req_tail_size = len(SMBNegociate_Protocol_Request_Tail())
+                    else:
+                        for dia in smb_req_dialects:
+                            smb_req_tail_arr.append(SMBNegociate_Protocol_Request_Tail(BufferData = dia))
+                            smb_req_tail_size += len(SMBNegociate_Protocol_Request_Tail(BufferData = dia))
+
+                    smb_req_head = SMBNegociate_Protocol_Request_Header\
+                        (Flags2=0x2801, PID=smb_PID, MID=smb_MID, ByteCount=smb_req_tail_size)
+                    smb_req_length = len(smb_req_head) + smb_req_tail_size
+                    smb_req_net_bio = NBTSession(TYPE=0x00, LENGTH=smb_req_length)
+                    smb_req_tcp = TCP(sport=sport, dport=smb_port, flags='PA', seq=attacker_seq, ack=victim_seq)
+                    smb_req_ip = IP(src=ip_source, dst=ip, ttl=source_ttl_value)
+                    smb_req_ether = Ether(src=mac_source, dst=mac_destination)
+                    attacker_seq += len(smb_req_net_bio) + len(smb_req_head) + smb_req_tail_size
+
+                    smb_req_combined = (smb_req_ether / smb_req_ip / smb_req_tcp / smb_req_net_bio / smb_req_head)
+
+                    for i in range(0 , len(smb_req_tail_arr)):
+                        smb_req_combined = smb_req_combined / smb_req_tail_arr[i]
+
+                    timestamp_smb_req = update_timestamp(timestamp_confirm, pps, minDelay)
+                    smb_req_combined.time = timestamp_smb_req
+                    packets.append(smb_req_combined)
+
+                    # destination confirms SMB request package
+                    reply_tcp = TCP(sport=smb_port, dport=sport, seq=victim_seq, ack=attacker_seq,
+                                    window=destination_win_value, flags='A')
+                    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)
+
+                    # smb response package
+                    first_timestamp = time.mktime(time.strptime(self.statistics.get_pcap_timestamp_start()[:19],
+                                                                "%Y-%m-%d %H:%M:%S"))
+                    server_Guid, security_blob, capabilities, data_size, server_start_time = get_smb_platform_data\
+                        (self.host_os, first_timestamp)
+
+                    timestamp_smb_rsp = update_timestamp(timestamp_reply, pps, minDelay)
+                    diff = timestamp_smb_rsp - timestamp_smb_req
+                    begin = get_filetime_format(timestamp_smb_req+diff*0.1)
+                    end = get_filetime_format(timestamp_smb_rsp-diff*0.1)
+                    system_time = randint(begin, end)
+
+                    if smb_version is not "1" and hosting_version is not "1":
+                        smb_rsp_paket = SMB2_SYNC_Header(Flags = 1)
+                        smb_rsp_negotiate_body = SMB2_Negotiate_Protocol_Response\
+                            (DialectRevision=0x02ff, SecurityBufferOffset=124, SecurityBufferLength=len(security_blob),
+                             SecurityBlob=security_blob, Capabilities=capabilities, MaxTransactSize=data_size,
+                             MaxReadSize=data_size, MaxWriteSize=data_size, SystemTime=system_time,
+                             ServerStartTime=server_start_time, ServerGuid=server_Guid)
+                        smb_rsp_length = len(smb_rsp_paket) + len(smb_rsp_negotiate_body)
+                    else:
+                        smb_rsp_paket = SMBNegociate_Protocol_Response_Advanced_Security\
+                            (Start="\xffSMB", PID=smb_PID, MID=smb_MID, DialectIndex=5, SecurityBlob=security_blob)
+                        smb_rsp_length = len(smb_rsp_paket)
+                    smb_rsp_net_bio = NBTSession(TYPE=0x00, LENGTH=smb_rsp_length)
+                    smb_rsp_tcp = TCP(sport=smb_port, dport=sport, flags='PA', seq=victim_seq, ack=attacker_seq)
+                    smb_rsp_ip = IP(src=ip, dst=ip_source, ttl=destination_ttl_value)
+                    smb_rsp_ether = Ether(src=mac_destination, dst=mac_source)
+                    victim_seq += len(smb_rsp_net_bio) + len(smb_rsp_paket)
+                    if smb_version is not "1"and hosting_version is not "1":
+                        victim_seq += len(smb_rsp_negotiate_body)
+
+                    smb_rsp_combined = (smb_rsp_ether / smb_rsp_ip / smb_rsp_tcp / smb_rsp_net_bio / smb_rsp_paket)
+                    if smb_version is not "1"and hosting_version is not "1":
+                        smb_rsp_combined = (smb_rsp_combined / smb_rsp_negotiate_body)
+
+                    smb_rsp_combined.time = timestamp_smb_rsp
+                    packets.append(smb_rsp_combined)
+
+
+                    # source confirms SMB response package
+                    confirm_tcp = TCP(sport=sport, dport=smb_port, seq=attacker_seq, ack=victim_seq,
+                                      window=source_win_value, flags='A')
+                    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)
+
+                    # attacker sends FIN ACK
+                    confirm_tcp = TCP(sport=sport, dport=smb_port, seq=attacker_seq, ack=victim_seq,
+                                      window=source_win_value, flags='FA')
+                    source_fin_ack = (confirm_ether / confirm_ip / confirm_tcp)
+                    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)
+
+                    # victim sends FIN ACK
+                    reply_tcp = TCP(sport=smb_port, dport=sport, seq=victim_seq, ack=attacker_seq,
+                                    window=destination_win_value, flags='FA')
+                    destination_fin_ack = (reply_ether / reply_ip / reply_tcp)
+                    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)
+
+                    # source sends final ACK
+                    confirm_tcp = TCP(sport=sport, dport=smb_port, seq=attacker_seq, ack=victim_seq,
+                                      window=source_win_value, flags='A')
+                    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)
+
+                else:
+                    # Build RST package
+                    reply_ether = Ether(src=mac_destination, dst=mac_source)
+                    reply_ip = IP(src=ip, dst=ip_source, ttl=destination_ttl_value, flags='DF')
+                    reply_tcp = TCP(sport=smb_port, dport=sport, seq=0, ack=attacker_seq, flags='RA',
+                                    window=destination_win_value, options=[('MSS', destination_mss_value)])
+                    reply = (reply_ether / reply_ip / reply_tcp)
+                    reply.time = timestamp_reply
+                    packets.append(reply)
+
+            pps = max(get_interval_pps(complement_interval_pps, timestamp_next_pkt), 10)
+            timestamp_next_pkt = update_timestamp(timestamp_next_pkt, pps)
+
+        # store end time of attack
+        self.attack_end_utime = packets[-1].time
+
+        # write attack packets to pcap
+        pcap_path = self.write_attack_pcap(sorted(packets, key=lambda pkt: pkt.time))
+
+        # return packets sorted by packet time_sec_start
+        return len(packets), pcap_path

+ 4 - 1
code/Attack/SalityBotnet.py

@@ -1,11 +1,14 @@
 import logging
 import logging
 from random import randint, uniform
 from random import randint, uniform
 
 
-from lea import Lea
+from random import randint
+from scapy.utils import RawPcapReader
+from scapy.layers.inet import Ether
 
 
 from Attack import BaseAttack
 from Attack import BaseAttack
 from Attack.AttackParameters import Parameter as Param
 from Attack.AttackParameters import Parameter as Param
 from Attack.AttackParameters import ParameterTypes
 from Attack.AttackParameters import ParameterTypes
+from ID2TLib.Utility import update_timestamp, get_interval_pps
 
 
 logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
 logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
 # noinspection PyPep8
 # noinspection PyPep8

+ 120 - 2
code/ID2TLib/Controller.py

@@ -1,6 +1,7 @@
 import os
 import os
 import sys
 import sys
 import shutil
 import shutil
+import readline
 
 
 from ID2TLib.AttackController import AttackController
 from ID2TLib.AttackController import AttackController
 from ID2TLib.LabelManager import LabelManager
 from ID2TLib.LabelManager import LabelManager
@@ -81,6 +82,7 @@ class Controller:
                 attacks_pcap = PcapFile(self.written_pcaps[i])
                 attacks_pcap = PcapFile(self.written_pcaps[i])
                 attacks_pcap_path = attacks_pcap.merge_attack(self.written_pcaps[i + 1])
                 attacks_pcap_path = attacks_pcap.merge_attack(self.written_pcaps[i + 1])
                 os.remove(self.written_pcaps[i + 1])  # remove merged pcap
                 os.remove(self.written_pcaps[i + 1])  # remove merged pcap
+                self.written_pcaps[i + 1] = attacks_pcap_path
             print("done.")
             print("done.")
         else:
         else:
             attacks_pcap_path = self.written_pcaps[0]
             attacks_pcap_path = self.written_pcaps[0]
@@ -140,13 +142,109 @@ class Controller:
         else:
         else:
             self.statisticsDB.process_db_query(query, print_results)
             self.statisticsDB.process_db_query(query, print_results)
 
 
+    @staticmethod
+    def process_help(params):
+        if not params:
+            print("Query mode allows you to enter SQL-queries as well as named queries.")
+            print()
+            print("Named queries:")
+            print("\tSelectors:")
+            print("\t\tmost_used(...)  -> Returns the most occurring element in all elements")
+            print("\t\tleast_used(...) -> Returns the least occurring element in all elements")
+            print("\t\tavg(...)        -> Returns the average of all elements")
+            print("\t\tall(...)        -> Returns all elements")
+            print("\tExtractors:")
+            print("\t\trandom(...)     -> Returns a random element from a list")
+            print("\t\tfirst(...)      -> Returns the first element from a list")
+            print("\t\tlast(...)       -> Returns the last element from a list")
+            print("\tParameterized selectors:")
+            print("\t\tipAddress(...)  -> Returns all IP addresses fulfilling the specified conditions")
+            print("\t\tmacAddress(...) -> Returns all MAC addresses fulfilling the specified conditions")
+            print()
+            print("Miscellaneous:")
+            print("\tlabels            -> List all attacks listed in the label file, if any")
+            print()
+            print("Additional information is available with 'help [KEYWORD];'")
+            print("To get a list of examples, type 'help examples;'")
+            print()
+            return
+
+        param = params[0].lower()
+        if param == "most_used":
+            print("most_used can be used as a selector for the following attributes:")
+            print("ipAddress | macAddress | portNumber | protocolName | ttlValue | mssValue | winSize | ipClass")
+            print()
+        elif param == "least_used":
+            print("least_used can be used as a selector for the following attributes:")
+            print("ipAddress | macAddress | portNumber | protocolName | ttlValue")
+            print()
+        elif param == "avg":
+            print("avg can be used as a selector for the following attributes:")
+            print("pktsReceived | pktsSent | kbytesSent | kbytesReceived | ttlValue | mss")
+            print()
+        elif param == "all":
+            print("all can be used as a selector for the following attributes:")
+            print("ipAddress | ttlValue | mss | macAddress | portNumber | protocolName")
+            print()
+        elif param in ["random", "first", "last"]:
+            print("No additional info available for this keyword.")
+            print()
+        elif param == "ipaddress":
+            print("ipAddress is a parameterized selector which fetches IP addresses based on (a list of) conditions.")
+            print("Conditions are of the following form: PARAMETER OPERATOR VALUE")
+            print("The following parameters can be specified:")
+            print("pktsReceived | pktsSent | kbytesReceived | kbytesSent | maxPktRate | minPktRate | ipClass\n"
+                  "macAddress | ttlValue | ttlCount | portDirection | portNumber | portCount | protocolCount\n"
+                  "protocolName")
+            print()
+            print("See 'help examples;' for usage examples.")
+            print()
+        elif param == "macaddress":
+            print("macAddress is a parameterized selector which fetches MAC addresses based on (a list of) conditions.")
+            print("Conditions are of the following form: PARAMETER OPERATOR VALUE")
+            print("The following parameters can be specified:")
+            print("ipAddress")
+            print()
+            print("See 'help examples;' for usage examples.")
+            print()
+        elif param == "examples":
+            print("Get the average amount of sent packets per IP:")
+            print("\tavg(pktsSent);")
+            print("Get a random IP from all addresses occuring in the pcap:")
+            print("\trandom(all(ipAddress));")
+            print("Return the MAC address of a specified IP:")
+            print("\tmacAddress(ipAddress=192.168.178.2);")
+            print("Get the average TTL-value with SQL:")
+            print("\tSELECT avg(ttlValue) from ip_ttl;")
+            print("Get a random IP address from all addresses that sent and received at least 10 packets:")
+            print("\trandom(ipAddress(pktsSent > 10, pktsReceived > 10));")
+            print()
+        else:
+            print("Unknown keyword '" + param + "', try 'help;' to get a list of allowed keywords'")
+            print()
+
     def enter_query_mode(self):
     def enter_query_mode(self):
         """
         """
         Enters into the query mode. This is a read-eval-print-loop, where the user can input named queries or SQL
         Enters into the query mode. This is a read-eval-print-loop, where the user can input named queries or SQL
         queries and the results are printed.
         queries and the results are printed.
         """
         """
+
+        def make_completer(vocabulary):
+            def custom_template(text, state):
+                results = [x for x in vocabulary if x.startswith(text)] + [None]
+                return results[state]
+            return custom_template
+
+        readline.parse_and_bind('tab: complete')
+        readline.set_completer(make_completer(self.statisticsDB.get_all_named_query_keywords()+self.statisticsDB.get_all_sql_query_keywords()))
+        history_file = os.path.join(os.path.expanduser('~'), 'ID2T_data', 'query_history')
+        try:
+            readline.read_history_file(history_file)
+        except IOError:
+            pass
         print("Entering into query mode...")
         print("Entering into query mode...")
-        print("Enter statement ending by ';' and press ENTER to send query. Exit by sending an empty query..")
+        print("Enter statement ending by ';' and press ENTER to send query. Exit by sending an empty query.")
+        print("Type 'help;' for information on possible queries.")
         buffer = ""
         buffer = ""
         while True:
         while True:
             line = input("> ")
             line = input("> ")
@@ -157,11 +255,31 @@ class Controller:
             if sqlite3.complete_statement(buffer):
             if sqlite3.complete_statement(buffer):
                 try:
                 try:
                     buffer = buffer.strip()
                     buffer = buffer.strip()
-                    self.statisticsDB.process_db_query(buffer, True)
+                    if buffer.lower().startswith('help'):
+                        buffer = buffer.strip(';')
+                        self.process_help(buffer.split(' ')[1:])
+                    elif buffer.lower().strip() == 'labels;':
+                        if not self.label_manager.labels:
+                            print("No labels found.")
+                        else:
+                            print("Attacks listed in the label file:")
+                            print()
+                            for label in self.label_manager.labels:
+                                print("Attack name:     " + str(label.attack_name))
+                                print("Attack note:     " + str(label.attack_note))
+                                print("Start timestamp: " + str(label.timestamp_start))
+                                print("End timestamp:   " + str(label.timestamp_end))
+                                print()
+                        print()
+                    else:
+                        self.statisticsDB.process_db_query(buffer, True)
                 except sqlite3.Error as e:
                 except sqlite3.Error as e:
                     print("An error occurred:", e.args[0])
                     print("An error occurred:", e.args[0])
                 buffer = ""
                 buffer = ""
 
 
+        readline.set_history_length(1000)
+        readline.write_history_file(history_file)
+
     def create_statistics_plot(self, params: str):
     def create_statistics_plot(self, params: str):
         """
         """
         Plots the statistics to a file by using the given customization parameters.
         Plots the statistics to a file by using the given customization parameters.

+ 45 - 0
code/ID2TLib/SMB2.py

@@ -0,0 +1,45 @@
+from scapy.packet import *
+from scapy.fields import *
+from scapy.layers.netbios import NBTSession
+
+
+class SMB2_SYNC_Header(Packet):
+    namez = "SMB2Negociate Protocol Response Header"
+    fields_desc = [StrFixedLenField("Start","\xfeSMB", 4),
+                   LEShortField("StructureSize", 64),
+                   LEShortField("CreditCharge", 0),
+                   LEIntField("Status", 0),
+                   LEShortField("Command", 0),
+                   LEShortField("CreditResponse", 0),
+                   LEIntField("Flags", 0),
+                   LEIntField("NextCommand", 0),
+                   LELongField("MessageID", 0),
+                   LEIntField("Reserved", 0),
+                   LEIntField("TreeID", 0x0),
+                   LELongField("SessionID", 0),
+                   LELongField("Signature1", 0),
+                   LELongField("Signature2", 0)]
+
+
+#No Support of Security Buffer , Padding or Dialect Revision 0x0311
+class SMB2_Negotiate_Protocol_Response(Packet):
+    namez = "SMB2Negociate Protocol Response"
+    fields_desc = [LEShortField("StructureSize", 65),
+                   LEShortField("SecurityMode", 0),
+                   LEShortField("DialectRevision", 0x0),
+                   LEShortField("NegotiateContentCount/Reserved", 0),
+                   StrFixedLenField("ServerGuid", "", 16),
+                   LEIntField("Capabilities", 0),
+                   LEIntField("MaxTransactSize", 0),
+                   LEIntField("MaxReadSize", 0),
+                   LEIntField("MaxWriteSize", 0),
+                   LELongField("SystemTime", 0),
+                   LELongField("ServerStartTime", 0),
+                   LEShortField("SecurityBufferOffset", 0),
+                   LEShortField("SecurityBufferLength", 0),
+                   StrLenField("SecurityBlob", "", length_from=lambda x: x.ByteCount + 16),
+                   LEIntField("NegotiateContextOffset/Reserved2", 0)]
+
+
+bind_layers(NBTSession, SMB2_SYNC_Header,)
+bind_layers(SMB2_SYNC_Header, SMB2_Negotiate_Protocol_Response,)

+ 108 - 0
code/ID2TLib/SMBLib.py

@@ -0,0 +1,108 @@
+from os import urandom
+from binascii import b2a_hex
+from random import random
+
+from ID2TLib.Utility import check_platform, get_filetime_format, get_rnd_boot_time
+
+# SMB port
+smb_port = 445
+
+# SMB versions
+smb_versions = {"1", "2.0", "2.1", "3.0", "3.0.2", "3.1.1"}
+smb_versions_per_win = {'win7': "2.1", 'win10': "3.1.1", 'winxp': "1", 'win8.1': "3.0.2", 'win8': "3.0",
+                        'winvista': "2.0", 'winnt': "1", "win2000": "1"}
+smb_versions_per_samba = {'3.6': "2.0", '4.0': "2.1", '4.1': "3.0", '4.3': "3.1.1"}
+# SMB dialects
+smb_dialects = ["PC NETWORK PROGRAM 1.0", "LANMAN1.0", "Windows for Workgroups 3.1a", "LM1.2X002", "LANMAN2.1",
+                "NT LM 0.12", "SMB 2.002", "SMB 2.???"]
+# SMB security blobs
+security_blob_windows = "\x60\x82\x01\x3c\x06\x06\x2b\x06\x01\x05\x05\x02\xa0\x82\x01\x30" \
+                        "\x30\x82\x01\x2c\xa0\x1a\x30\x18\x06\x0a\x2b\x06\x01\x04\x01\x82" \
+                        "\x37\x02\x02\x1e\x06\x0a\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a" \
+                        "\xa2\x82\x01\x0c\x04\x82\x01\x08\x4e\x45\x47\x4f\x45\x58\x54\x53" \
+                        "\x01\x00\x00\x00\x00\x00\x00\x00\x60\x00\x00\x00\x70\x00\x00\x00" \
+                        "\xbc\x84\x03\x97\x6f\x80\x3b\x81\xa6\x45\x1b\x05\x92\x39\xde\x3d" \
+                        "\xd6\x91\x85\x49\x8a\xd0\x3b\x58\x87\x99\xb4\x98\xdf\xa6\x1d\x73" \
+                        "\x3b\x57\xbf\x05\x63\x5e\x30\xea\xa8\xd8\xd8\x45\xba\x80\x52\xa5" \
+                        "\x00\x00\x00\x00\x00\x00\x00\x00\x60\x00\x00\x00\x01\x00\x00\x00" \
+                        "\x00\x00\x00\x00\x00\x00\x00\x00\x5c\x33\x53\x0d\xea\xf9\x0d\x4d" \
+                        "\xb2\xec\x4a\xe3\x78\x6e\xc3\x08\x4e\x45\x47\x4f\x45\x58\x54\x53" \
+                        "\x03\x00\x00\x00\x01\x00\x00\x00\x40\x00\x00\x00\x98\x00\x00\x00" \
+                        "\xbc\x84\x03\x97\x6f\x80\x3b\x81\xa6\x45\x1b\x05\x92\x39\xde\x3d" \
+                        "\x5c\x33\x53\x0d\xea\xf9\x0d\x4d\xb2\xec\x4a\xe3\x78\x6e\xc3\x08" \
+                        "\x40\x00\x00\x00\x58\x00\x00\x00\x30\x56\xa0\x54\x30\x52\x30\x27" \
+                        "\x80\x25\x30\x23\x31\x21\x30\x1f\x06\x03\x55\x04\x03\x13\x18\x54" \
+                        "\x6f\x6b\x65\x6e\x20\x53\x69\x67\x6e\x69\x6e\x67\x20\x50\x75\x62" \
+                        "\x6c\x69\x63\x20\x4b\x65\x79\x30\x27\x80\x25\x30\x23\x31\x21\x30" \
+                        "\x1f\x06\x03\x55\x04\x03\x13\x18\x54\x6f\x6b\x65\x6e\x20\x53\x69" \
+                        "\x67\x6e\x69\x6e\x67\x20\x50\x75\x62\x6c\x69\x63\x20\x4b\x65\x79"
+security_blob_ubuntu = "\x60\x48\x06\x06\x2b\x06\x01\x05\x05\x02\xa0\x3e\x30\x3c\xa0\x0e" \
+                       "\x30\x0c\x06\x0a\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a\xa3\x2a" \
+                       "\x30\x28\xa0\x26\x1b\x24\x6e\x6f\x74\x5f\x64\x65\x66\x69\x6e\x65" \
+                       "\x64\x5f\x69\x6e\x5f\x52\x46\x43\x34\x31\x37\x38\x40\x70\x6c\x65" \
+                       "\x61\x73\x65\x5f\x69\x67\x6e\x6f\x72\x65"
+security_blob_macos = "\x60\x7e\x06\x06\x2b\x06\x01\x05\x05\x02\xa0\x74\x30\x72\xa0\x44" \
+                      "\x30\x42\x06\x09\x2a\x86\x48\x82\xf7\x12\x01\x02\x02\x06\x09\x2a" \
+                      "\x86\x48\x86\xf7\x12\x01\x02\x02\x06\x06\x2a\x85\x70\x2b\x0e\x03" \
+                      "\x06\x06\x2b\x06\x01\x05\x05\x0e\x06\x0a\x2b\x06\x01\x04\x01\x82" \
+                      "\x37\x02\x02\x0a\x06\x06\x2b\x05\x01\x05\x02\x07\x06\x06\x2b\x06" \
+                      "\x01\x05\x02\x05\xa3\x2a\x30\x28\xa0\x26\x1b\x24\x6e\x6f\x74\x5f" \
+                      "\x64\x65\x66\x69\x6e\x65\x64\x5f\x69\x6e\x5f\x52\x46\x43\x34\x31" \
+                      "\x37\x38\x40\x70\x6c\x65\x61\x73\x65\x5f\x69\x67\x6e\x6f\x72\x65"
+
+
+def get_smb_version(platform: str):
+    """
+    Returns SMB version based on given platform
+
+    :param platform: the platform as string
+    :return: SMB version as string
+    """
+    check_platform(platform)
+    if platform is "linux":
+        return random.choice(list(smb_versions_per_samba.values()))
+    elif platform is "macos":
+        return "2.1"
+    else:
+        return smb_versions_per_win[platform]
+
+
+def get_smb_platform_data(platform: str, timestamp: float):
+    """
+    Gets platform-dependent data for SMB 2 packets
+
+    :param platform: the platform for which to get SMB 2 packet data
+    :param timestamp: a timestamp for calculating the boot-time
+    :return: server_guid, security_blob, capabilities, data_size and server_start_time of the given platform
+    """
+    check_platform(platform)
+    if platform == "linux":
+        server_guid = "ubuntu"
+        security_blob = security_blob_ubuntu
+        capabilities = 0x5
+        data_size = 0x800000
+        server_start_time = 0
+    elif platform == "macos":
+        server_guid = b2a_hex(urandom(15)).decode()
+        security_blob = security_blob_macos
+        capabilities = 0x6
+        data_size = 0x400000
+        server_start_time = 0
+    else:
+        server_guid = b2a_hex(urandom(15)).decode()
+        security_blob = security_blob_windows
+        capabilities = 0x7
+        data_size = 0x100000
+        server_start_time = get_filetime_format(get_rnd_boot_time(timestamp))
+    return server_guid, security_blob, capabilities, data_size, server_start_time
+
+
+def invalid_smb_version(version: str):
+    """
+    Prints an error and exits
+
+    :param version: the invalid SMB
+    """
+    print("\nInvalid smb version: " + version +
+          "\nPlease select one of the following versions: ", smb_versions)
+    exit(1)

+ 13 - 0
code/ID2TLib/Statistics.py

@@ -500,6 +500,12 @@ class Statistics:
         result_dict = {key: value for (key, value) in result}
         result_dict = {key: value for (key, value) in result}
         return result_dict
         return result_dict
 
 
+    def get_ip_address_count(self):
+        return self.process_db_query("SELECT COUNT(*) FROM ip_statistics")
+
+    def get_ip_addresses(self):
+        return self.process_db_query("SELECT ipAddress FROM ip_statistics")
+
     def get_random_ip_address(self, count: int = 1):
     def get_random_ip_address(self, count: int = 1):
         """
         """
         :param count: The number of IP addreses to return
         :param count: The number of IP addreses to return
@@ -514,6 +520,13 @@ class Statistics:
                 ip_address_list.append(self.process_db_query("random(all(ipAddress))"))
                 ip_address_list.append(self.process_db_query("random(all(ipAddress))"))
             return ip_address_list
             return ip_address_list
 
 
+    def get_ip_address_from_mac(self, macAddress: str):
+        """
+        :param macAddress: the MAC address of which the IP shall be returned, if existing in DB
+        :return: the IP address used in the dataset by a given MAC address
+        """
+        return self.process_db_query('ipAddress(macAddress=' + macAddress + ")")
+
     def get_mac_address(self, ipAddress: str):
     def get_mac_address(self, ipAddress: str):
         """
         """
         :return: The MAC address used in the dataset for the given IP address.
         :return: The MAC address used in the dataset for the given IP address.

+ 1 - 1
code/ID2TLib/StatsDatabase.py

@@ -298,7 +298,7 @@ class StatsDatabase:
 
 
         # Print results if option print_results is True
         # Print results if option print_results is True
         if print_results:
         if print_results:
-            if len(result) == 1 and isinstance(result, list):
+            if isinstance(result, list) and len(result) == 1:
                 result = result[0]
                 result = result[0]
                 print("Query returned 1 record:\n")
                 print("Query returned 1 record:\n")
                 for i in range(0, len(result)):
                 for i in range(0, len(result)):

+ 269 - 0
code/ID2TLib/Utility.py

@@ -0,0 +1,269 @@
+import ipaddress
+
+from random import randint, uniform
+from os import urandom
+from datetime import datetime
+from calendar import timegm
+from lea import Lea
+
+platforms = {"win7", "win10", "winxp", "win8.1", "macos", "linux", "win8", "winvista", "winnt", "win2000"}
+platform_probability = {"win7": 48.43, "win10": 27.99, "winxp": 6.07, "win8.1": 6.07, "macos": 5.94, "linux": 3.38,
+                        "win8": 1.35, "winvista": 0.46, "winnt": 0.31}
+
+x86_nops = {b'\x90', b'\xfc', b'\xfd', b'\xf8', b'\xf9', b'\xf5', b'\x9b'}
+x86_pseudo_nops = {b'\x97', b'\x96', b'\x95', b'\x93', b'\x92', b'\x91', b'\x99', b'\x4d', b'\x48', b'\x47', b'\x4f',
+                   b'\x40', b'\x41', b'\x37', b'\x3f', b'\x27', b'\x2f', b'\x46', b'\x4e', b'\x98', b'\x9f', b'\x4a',
+                   b'\x44', b'\x42', b'\x43', b'\x49', b'\x4b', b'\x45', b'\x4c', b'\x60', b'\x0e', b'\x1e', b'\x50',
+                   b'\x55', b'\x53', b'\x51', b'\x57', b'\x52', b'\x06', b'\x56', b'\x54', b'\x16', b'\x58', b'\x5d',
+                   b'\x5b', b'\x59', b'\x5f', b'\x5a', b'\x5e', b'\xd6'}
+forbidden_chars = [b'\x00', b'\x0a', b'\x0d']
+
+
+def update_timestamp(timestamp, pps, delay=0):
+    """
+    Calculates the next timestamp to be used based on the packet per second rate (pps) and the maximum delay.
+
+    :return: Timestamp to be used for the next packet.
+    """
+    if delay == 0:
+        # Calculate request timestamp
+        # To imitate the bursty behavior of traffic
+        randomdelay = Lea.fromValFreqsDict({1 / pps: 70, 2 / pps: 20, 5 / pps: 7, 10 / pps: 3})
+        return timestamp + uniform(1 / pps, randomdelay.random())
+    else:
+        # Calculate reply timestamp
+        randomdelay = Lea.fromValFreqsDict({2 * delay: 70, 3 * delay: 20, 5 * delay: 7, 10 * delay: 3})
+        return timestamp + uniform(1 / pps + delay, 1 / pps + randomdelay.random())
+
+
+def get_interval_pps(complement_interval_pps, timestamp):
+    """
+    Gets the packet rate (pps) for a specific time interval.
+
+    :param complement_interval_pps: an array of tuples (the last timestamp in the interval, the packet rate in the
+    corresponding interval).
+    :param timestamp: the timestamp at which the packet rate is required.
+    :return: the corresponding packet rate (pps) .
+    """
+    for row in complement_interval_pps:
+        if timestamp<=row[0]:
+            return row[1]
+    return complement_interval_pps[-1][1] # in case the timstamp > capture max timestamp
+
+
+def get_nth_random_element(*element_list):
+    """
+    Returns the n-th element of every list from an arbitrary number of given lists.
+    For example, list1 contains IP addresses, list 2 contains MAC addresses. Use of this function ensures that
+    the n-th IP address uses always the n-th MAC address.
+    :param element_list: An arbitrary number of lists.
+    :return: A tuple of the n-th element of every list.
+    """
+    range_max = min([len(x) for x in element_list])
+    if range_max > 0: range_max -= 1
+    n = randint(0, range_max)
+    return tuple(x[n] for x in element_list)
+
+
+def index_increment(number: int, max: int):
+            if number + 1 < max:
+                return number + 1
+            else:
+                return 0
+
+
+def get_rnd_os():
+    """
+    Chooses random platform over an operating system probability distribution
+
+    :return: random platform as string
+    """
+    os_dist = Lea.fromValFreqsDict(platform_probability)
+    return os_dist.random()
+
+
+def check_platform(platform: str):
+    """
+    Checks if the given platform is currently supported
+    if not exits with error
+
+    :param platform: the platform, which should be validated
+    """
+    if platform not in platforms:
+        print("\nERROR: Invalid platform: " + platform + "." +
+              "\n Please select one of the following platforms: ", platforms)
+        exit(1)
+
+
+def get_ip_range(start_ip: str, end_ip: str):
+    """
+    Generates a list of IPs of a given range. If the start_ip is greater than the end_ip, the reverse range is generated
+
+    :param start_ip: the start_ip of the desired IP-range
+    :param end_ip:  the end_ip of the desired IP-range
+    :return: a list of all IPs in the desired IP-range, including start-/end_ip
+    """
+    start = ipaddress.ip_address(start_ip)
+    end = ipaddress.ip_address(end_ip)
+    ips = []
+    if start < end:
+        while start <= end:
+            ips.append(start.exploded)
+            start = start+1
+    elif start > end:
+        while start >= end:
+            ips.append(start.exploded)
+            start = start-1
+    else:
+        ips.append(start_ip)
+    return ips
+
+
+def generate_source_port_from_platform(platform: str, previousPort=0):
+    """
+    Generates the next source port according to the TCP-port-selection strategy of the given platform
+
+    :param platform: the platform for which to generate source ports
+    :param previousPort: the previously used/generated source port. Must be 0 if no port was generated before
+    :return: the next source port for the given platform
+    """
+    check_platform(platform)
+    if platform in {"winnt", "winxp", "win2000"}:
+        if (previousPort == 0) or (previousPort + 1 > 5000):
+            return randint(1024, 5000)
+        else:
+            return previousPort + 1
+    elif platform == "linux":
+        return randint(32768, 61000)
+    else:
+        if (previousPort == 0) or (previousPort + 1 > 65535):
+            return randint(49152, 65535)
+        else:
+            return previousPort + 1
+
+
+def get_filetime_format(timestamp):
+    """
+    Converts a timestamp into MS FILETIME format
+
+    :param timestamp: a timestamp in seconds
+    :return: MS FILETIME timestamp
+    """
+    boot_datetime = datetime.fromtimestamp(timestamp)
+    if boot_datetime.tzinfo is None or boot_datetime.tzinfo.utcoffset(boot_datetime) is None:
+        boot_datetime = boot_datetime.replace(tzinfo=boot_datetime.tzname())
+    boot_filetime = 116444736000000000 + (timegm(boot_datetime.timetuple()) * 10000000)
+    return boot_filetime + (boot_datetime.microsecond * 10)
+
+
+def get_rnd_boot_time(timestamp, platform="winxp"):
+    """
+    Generates a random boot time based on a given timestamp and operating system
+
+    :param timestamp: a timestamp in seconds
+    :param platform: a platform as string as specified in check_platform above. default is winxp. this param is optional
+    :return: timestamp of random boot time in seconds since EPOCH
+    """
+    check_platform(platform)
+    if platform is "linux":
+        uptime_in_days = Lea.fromValFreqsDict({3: 50, 7: 25, 14: 12.5, 31: 6.25, 92: 3.125, 183: 1.5625,
+                                               365: 0.78125, 1461: 0.390625, 2922: 0.390625})
+    elif platform is "macos":
+        uptime_in_days = Lea.fromValFreqsDict({7: 50, 14: 25, 31: 12.5, 92: 6.25, 183: 3.125, 365: 3.076171875,
+                                               1461: 0.048828125})
+    else:
+        uptime_in_days = Lea.fromValFreqsDict({3: 50, 7: 25, 14: 12.5, 31: 6.25, 92: 3.125, 183: 1.5625,
+                                               365: 0.78125, 1461: 0.78125})
+    timestamp -= randint(0, uptime_in_days.random()*86400)
+    return timestamp
+
+
+def get_rnd_x86_nop(count=1, side_effect_free=False, char_filter=set()):
+    """
+    Generates a specified number of x86 single-byte (pseudo-)NOPs
+
+    :param count: The number of bytes to generate
+    :param side_effect_free: Determines whether NOPs with side-effects (to registers or the stack) are allowed
+    :param char_filter: A set of bytes which are forbidden to generate
+    :return: Random x86 NOP bytestring
+    """
+    result = b''
+    nops = x86_nops
+    if not side_effect_free:
+        nops |= x86_pseudo_nops
+
+    if not isinstance(char_filter, set):
+        char_filter = set(char_filter)
+    nops = list(nops-char_filter)
+
+    for i in range(0, count):
+        result += nops[randint(0, len(nops) - 1)]
+    return result
+
+
+def get_rnd_bytes(count=1, ignore=None):
+    """
+    Generates a specified number of random bytes while excluding unwanted bytes
+
+    :param count: Number of wanted bytes
+    :param ignore: The bytes, which should be ignored, as an array
+    :return: Random bytestring
+    """
+    if ignore is None:
+        ignore = []
+    result = b''
+    for i in range(0, count):
+        char = urandom(1)
+        while char in ignore:
+            char = urandom(1)
+        result += char
+    return result
+
+
+def get_bytes_from_file(filepath):
+    """
+    Converts the content of a file into its byte representation
+    The content of the file can either be a string or hexadecimal numbers/bytes (e.g. shellcode)
+    The file must have the keyword "str" or "hex" in its first line to specify the rest of the content
+    If the content is hex, whitespaces, backslashes, "x", quotation marks and "+" are removed
+    Example for a hexadecimal input file:
+
+        hex
+        "abcd ef \xff10\ff 'xaa' x \ ab"
+
+    Output: b'\xab\xcd\xef\xff\x10\xff\xaa\xab'
+
+    :param filepath: The path of the file from which to get the bytes
+    :return: The bytes of the file (either a byte representation of a string or the bytes contained in the file)
+    """
+    try:
+        file = open(filepath)
+        result_bytes = b''
+        header = file.readline().strip()
+        content = file.read()
+
+        if header == "hex":
+            content = content.replace(" ", "").replace("\n", "").replace("\\", "").replace("x", "").replace("\"", "")\
+                .replace("'", "").replace("+", "").replace("\r", "")
+            try:
+                result_bytes = bytes.fromhex(content)
+            except ValueError:
+                print("\nERROR: Content of file is not all hexadecimal.")
+                exit(1)
+        elif header == "str":
+            result_bytes = content.encode()
+        else:
+            print("\nERROR: Invalid header found: " + header + ". Try 'hex' or 'str' followed by endline instead.")
+            exit(1)
+
+        for forbidden_char in forbidden_chars:
+            if forbidden_char in result_bytes:
+                print("\nERROR: Forbidden character found in payload: ", forbidden_char)
+                exit(1)
+
+        file.close()
+        return result_bytes
+
+    except FileNotFoundError:
+        print("\nERROR: File not found: ", filepath)
+        exit(1)

+ 4 - 0
code_boost/src/CMakeLists.txt

@@ -77,6 +77,10 @@ ADD_LIBRARY(pcapreader SHARED ${SOURCE_FILES})
 # Libs pthread and dl are prerequisites of SQLiteCpp
 # Libs pthread and dl are prerequisites of SQLiteCpp
 TARGET_LINK_LIBRARIES(pcapreader ${Boost_LIBRARIES} "${TINS_LIBRARY}" ${PYTHON_LIBRARIES} SQLiteCpp sqlite3 pthread dl)
 TARGET_LINK_LIBRARIES(pcapreader ${Boost_LIBRARIES} "${TINS_LIBRARY}" ${PYTHON_LIBRARIES} SQLiteCpp sqlite3 pthread dl)
 
 
+IF (APPLE)
+  SET(CMAKE_SHARED_LIBRARY_SUFFIX ".so")
+ENDIF ()
+
 # comment this out to build executable (for development)
 # comment this out to build executable (for development)
 #ADD_EXECUTABLE(cpp-pcapreader ${SOURCE_FILES})
 #ADD_EXECUTABLE(cpp-pcapreader ${SOURCE_FILES})
 #TARGET_LINK_LIBRARIES(cpp-pcapreader ${Boost_LIBRARIES} "${TINS_LIBRARY}" SQLiteCpp sqlite3 pthread dl)
 #TARGET_LINK_LIBRARIES(cpp-pcapreader ${Boost_LIBRARIES} "${TINS_LIBRARY}" SQLiteCpp sqlite3 pthread dl)

+ 12 - 4
code_boost/src/cxx/pcap_processor.cpp

@@ -52,10 +52,18 @@ std::string pcap_processor::merge_pcaps(const std::string pcap_path) {
     std::string new_filepath = filePath;
     std::string new_filepath = filePath;
     const std::string &newExt = "_" + tstmp + ".pcap";
     const std::string &newExt = "_" + tstmp + ".pcap";
     std::string::size_type h = new_filepath.rfind('.', new_filepath.length());
     std::string::size_type h = new_filepath.rfind('.', new_filepath.length());
-    if (h != std::string::npos) {
-        new_filepath.replace(h, newExt.length(), newExt);
-    } else {
-        new_filepath.append(newExt);
+
+    if ((filePath.length() + newExt.length()) < 250) {
+
+        if (h != std::string::npos) {
+            new_filepath.replace(h, newExt.length(), newExt);
+        } else {
+            new_filepath.append(newExt);
+        }
+    }
+
+    else {
+        new_filepath = (new_filepath.substr(0, new_filepath.find('_'))).append(newExt);
     }
     }
 
 
     FileSniffer sniffer_base(filePath);
     FileSniffer sniffer_base(filePath);

+ 5 - 5
code_boost/src/cxx/statistics_db.cpp

@@ -27,13 +27,13 @@ void statistics_db::writeStatisticsIP(std::unordered_map<std::string, entry_ipSt
         SQLite::Transaction transaction(*db);
         SQLite::Transaction transaction(*db);
         const char *createTable = "CREATE TABLE ip_statistics ( "
         const char *createTable = "CREATE TABLE ip_statistics ( "
                 "ipAddress TEXT, "
                 "ipAddress TEXT, "
-                "pktsReceived INTEGtimestampER, "
+                "pktsReceived INTEGER, "
                 "pktsSent INTEGER, "
                 "pktsSent INTEGER, "
                 "kbytesReceived REAL, "
                 "kbytesReceived REAL, "
                 "kbytesSent REAL, "
                 "kbytesSent REAL, "
                 "maxPktRate REAL,"
                 "maxPktRate REAL,"
                 "minPktRate REAL,"
                 "minPktRate REAL,"
-                "ipClass TEXT, "
+                "ipClass TEXT COLLATE NOCASE, "
                 "PRIMARY KEY(ipAddress));";
                 "PRIMARY KEY(ipAddress));";
         db->exec(createTable);
         db->exec(createTable);
         SQLite::Statement query(*db, "INSERT INTO ip_statistics VALUES (?, ?, ?, ?, ?, ?, ?, ?)");
         SQLite::Statement query(*db, "INSERT INTO ip_statistics VALUES (?, ?, ?, ?, ?, ?, ?, ?)");
@@ -187,7 +187,7 @@ void statistics_db::writeStatisticsProtocols(std::unordered_map<ipAddress_protoc
         SQLite::Transaction transaction(*db);
         SQLite::Transaction transaction(*db);
         const char *createTable = "CREATE TABLE ip_protocols ("
         const char *createTable = "CREATE TABLE ip_protocols ("
                 "ipAddress TEXT,"
                 "ipAddress TEXT,"
-                "protocolName TEXT,"
+                "protocolName TEXT COLLATE NOCASE,"
                 "protocolCount INTEGER,"
                 "protocolCount INTEGER,"
                 "PRIMARY KEY(ipAddress,protocolName));";
                 "PRIMARY KEY(ipAddress,protocolName));";
         db->exec(createTable);
         db->exec(createTable);
@@ -217,7 +217,7 @@ void statistics_db::writeStatisticsPorts(std::unordered_map<ipAddress_inOut_port
         SQLite::Transaction transaction(*db);
         SQLite::Transaction transaction(*db);
         const char *createTable = "CREATE TABLE ip_ports ("
         const char *createTable = "CREATE TABLE ip_ports ("
                 "ipAddress TEXT,"
                 "ipAddress TEXT,"
-                "portDirection TEXT,"
+                "portDirection TEXT COLLATE NOCASE,"
                 "portNumber INTEGER,"
                 "portNumber INTEGER,"
                 "portCount INTEGER,"
                 "portCount INTEGER,"
                 "PRIMARY KEY(ipAddress,portDirection,portNumber));";
                 "PRIMARY KEY(ipAddress,portDirection,portNumber));";
@@ -249,7 +249,7 @@ void statistics_db::writeStatisticsIpMac(std::unordered_map<std::string, std::st
         SQLite::Transaction transaction(*db);
         SQLite::Transaction transaction(*db);
         const char *createTable = "CREATE TABLE ip_mac ("
         const char *createTable = "CREATE TABLE ip_mac ("
                 "ipAddress TEXT,"
                 "ipAddress TEXT,"
-                "macAddress TEXT,"
+                "macAddress TEXT COLLATE NOCASE,"
                 "PRIMARY KEY(ipAddress));";
                 "PRIMARY KEY(ipAddress));";
         db->exec(createTable);
         db->exec(createTable);
         SQLite::Statement query(*db, "INSERT INTO ip_mac VALUES (?, ?)");
         SQLite::Statement query(*db, "INSERT INTO ip_mac VALUES (?, ?)");

+ 122 - 0
resources/install_dependencies.sh

@@ -0,0 +1,122 @@
+#!/bin/bash
+
+install_pkg_arch()
+{
+    PACMAN_PKGS="boost boost-libs cmake python python-pip sqlite tcpdump"
+
+    # Check first to avoid unnecessary sudo
+    echo -e "Packages: Checking..."
+    pacman -Qi $PACMAN_PKGS >/dev/null
+    if [ $? != 0 ]; then
+        # Install all missing packages
+        echo -e "Packages: Installing..."
+        sudo pacman -S --needed $PACMAN_PKGS
+    else
+        echo -e "Packages: Found."
+    fi
+
+    # libtins is not provided by Arch repos, check seperately
+    echo -e "Additional Packages: Checking..."
+    pacman -Qi libtins >/dev/null
+    if [ $? != 0 ]; then
+        echo -e "Additional Packages: Installing..."
+
+        pushd /tmp
+
+        # Download fresh copy of libtins
+        wget "https://aur.archlinux.org/cgit/aur.git/snapshot/libtins.tar.gz"
+        tar -xzf libtins.tar.gz
+        rm libtins.tar.gz
+        rm -R libtins
+
+        pushd libtins
+
+        # Build and install
+        makepkg -si
+
+        popd
+        popd
+    else
+        echo -e "Additional Packages: Found."
+    fi
+}
+
+install_pkg_ubuntu()
+{
+    APT_PKGS="build-essential libboost-dev libboost-python-dev cmake python3-dev python3-pip sqlite tcpdump libtins-dev libpcap-dev"
+
+    # Check first to avoid unnecessary sudo
+    echo -e "Packages: Checking..."
+    dpkg -s $APT_PKGS &>/dev/null
+    if [ $? != 0 ]; then
+        # Install all missing packages
+        echo -e "Packages: Installing..."
+        sudo apt-get install $APT_PKGS
+    else
+        echo -e "Packages: Found."
+    fi
+}
+
+install_pkg_darwin()
+{
+    echo -e "Installing: Packages"
+    brew install cmake python coreutils libdnet libtins boost boost-python --with-python3
+}
+
+install_pip()
+{
+    PYTHON_MODULES="lea numpy matplotlib scapy-python3 scipy"
+    echo -e "Python modules: Checking..."
+
+    # Check first to avoid unnecessary sudo
+    echo $PYTHON_MODULES | xargs -n 1 pip3 show >/dev/null
+    if [ $? == 0 ]; then
+        echo -e "Python modules: Found."
+        return
+    fi
+
+    # Install all missing packages
+    echo -e "Python modules: Installing..."
+    if [ $KERNEL == 'Darwin' ]; then
+        pip3 install $PYTHON_MODULES
+    else
+        sudo pip3 install $PYTHON_MODULES
+    fi
+}
+
+# Make sure the SQLiteCpp submodule is there
+echo -e "Updating SQLiteCpp"
+git submodule update --init
+
+KERNEL=$(uname)
+
+if [ "$KERNEL" = 'Darwin' ]; then
+    echo -e "Detected OS:  macOS"
+
+    which brew
+    if [ $? != 0 ]; then
+        echo -e "Brew not found, please install it manually!"
+        exit 1
+    fi
+
+    install_pkg_darwin
+    install_pip
+    exit 0
+elif [ "$KERNEL" = 'Linux' ]; then
+    # Kernel is Linux, check for supported distributions
+    OS=$(awk '/DISTRIB_ID=/' /etc/*-release | sed 's/DISTRIB_ID=//' | tr '[:upper:]' '[:lower:]')
+
+    if [ "$OS" = 'arch' ]; then
+        echo -e "Detected OS: Arch Linux"
+        install_pkg_arch
+        install_pip
+        exit 0
+    elif [ "$OS" = 'ubuntu' ]; then
+        echo -e "Detected OS: Ubuntu"
+        install_pkg_ubuntu
+        install_pip
+        exit 0
+    fi
+fi
+echo -e "Your OS is not supported by this script, please make sure to install the dependencies manually"
+exit 0