AttackController.py 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. import importlib
  2. import sys
  3. import difflib
  4. import Attack.AttackParameters as atkParam
  5. import Core.LabelManager as LabelManager
  6. import Core.Statistics as Statistics
  7. import ID2TLib.Label as Label
  8. import ID2TLib.PcapFile as PcapFile
  9. class AttackController:
  10. def __init__(self, pcap_file: PcapFile.PcapFile, statistics_class: Statistics, label_manager: LabelManager):
  11. """
  12. Creates a new AttackController. The controller manages the attack injection, including the PCAP writing.
  13. :param pcap_file: The source .pcap file to run the attack on.
  14. :param statistics_class: A Statistics Object.
  15. :param label_manager: A LabelManager Object.
  16. """
  17. self.statistics = statistics_class
  18. self.pcap_file = pcap_file
  19. self.label_mgr = label_manager
  20. self.current_attack = None
  21. self.added_attacks = []
  22. self.seed = None
  23. self.total_packets = 0
  24. def set_seed(self, seed: int):
  25. """
  26. Sets global seed.
  27. :param seed: random seed
  28. """
  29. self.seed = seed
  30. def create_attack(self, attack_name: str, seed=None):
  31. """
  32. Creates dynamically a new class instance based on the given attack_name.
  33. :param attack_name: The name of the attack, must correspond to the attack's class name.
  34. :param seed: random seed for param generation
  35. :return: None
  36. """
  37. def choose_attack(input_name):
  38. # TODO: get list dynamically from module names
  39. list_of_attacks = ('DDoSAttack', 'EternalBlueExploit', 'FTPWinaXeExploit', 'JoomlaRegPrivExploit',
  40. 'MS17ScanAttack', 'PortscanAttack', 'SalityBotnet', 'SMBLorisAttack', 'SMBScanAttack',
  41. 'SQLiAttack')
  42. input_name = input_name.lower()
  43. highest_sim = 0
  44. highest_sim_attack = ''
  45. for attack in list_of_attacks:
  46. similarity = difflib.SequenceMatcher(None, input_name, attack.lower()).ratio()
  47. # Exact match, return appropriate attack name
  48. if similarity == 1.0:
  49. return attack
  50. # Found more likely match
  51. if similarity > highest_sim:
  52. highest_sim = similarity
  53. highest_sim_attack = attack
  54. # Found no exactly matching attack name, print highest match
  55. if highest_sim >= 0.6:
  56. print('Found no attack of name ' + input_name + '. The closest match was ' + highest_sim_attack +
  57. '. Use ./id2t -l for a list of available attacks.')
  58. exit(1)
  59. # Found no reasonably matching attack name
  60. else:
  61. print('Found no attack of name ' + input_name + ' or one similar to it .'
  62. 'Use ./id2t -l for a list of available attacks.')
  63. exit(1)
  64. attack_name = choose_attack(attack_name)
  65. print("\nCreating attack instance of \033[1m" + attack_name + "\033[0m")
  66. # Load attack class
  67. attack_module = importlib.import_module("Attack." + attack_name)
  68. attack_class = getattr(attack_module, attack_name)
  69. # Instantiate the desired attack
  70. self.current_attack = attack_class()
  71. # Initialize the parameters of the attack with defaults or user supplied values.
  72. self.current_attack.set_statistics(self.statistics)
  73. if seed is not None:
  74. self.current_attack.set_seed(seed=seed)
  75. self.current_attack.init_params()
  76. # Record the attack
  77. self.added_attacks.append(self.current_attack)
  78. def process_attack(self, attack: str, params: str, time=False):
  79. """
  80. Takes as input the name of an attack (classname) and the attack parameters as string. Parses the string of
  81. attack parameters, creates the attack by writing the attack packets and returns the path of the written pcap.
  82. :param attack: The classname of the attack to injecect.
  83. :param params: The parameters for attack customization, see attack class for supported params.
  84. :param time: Measure packet generation time or not.
  85. :return: The file path to the created pcap file.
  86. """
  87. self.create_attack(attack, self.seed)
  88. print("Validating and adding attack parameters.")
  89. # Add attack parameters if provided
  90. params_dict = []
  91. if isinstance(params, list) and params:
  92. # Convert attack param list into dictionary
  93. for entry in params:
  94. params_dict.append(entry.split('='))
  95. params_dict = dict(params_dict)
  96. # Check if Parameter.INJECT_AT_TIMESTAMP and Parameter.INJECT_AFTER_PACKET are provided at the same time
  97. # if TRUE: delete Paramter.INJECT_AT_TIMESTAMP (lower priority) and use Parameter.INJECT_AFTER_PACKET
  98. if (atkParam.Parameter.INJECT_AFTER_PACKET.value in params_dict) and (
  99. atkParam.Parameter.INJECT_AT_TIMESTAMP.value in params_dict):
  100. print("CONFLICT: Parameters", atkParam.Parameter.INJECT_AT_TIMESTAMP.value, "and",
  101. atkParam.Parameter.INJECT_AFTER_PACKET.value,
  102. "given at the same time. Ignoring", atkParam.Parameter.INJECT_AT_TIMESTAMP.value, "and using",
  103. atkParam.Parameter.INJECT_AFTER_PACKET.value, "instead to derive the timestamp.")
  104. del params_dict[atkParam.Parameter.INJECT_AT_TIMESTAMP.value]
  105. # Extract attack_note parameter, if not provided returns an empty string
  106. key_attack_note = "attack.note"
  107. attack_note = params_dict.get(key_attack_note, "")
  108. params_dict.pop(key_attack_note, None) # delete entry if found, otherwise return an empty string
  109. # Pass paramters to attack controller
  110. self.set_params(params_dict)
  111. else:
  112. attack_note = "This attack used only (random) default parameters."
  113. # Write attack into pcap file
  114. print("Generating attack packets...", end=" ")
  115. sys.stdout.flush() # force python to print text immediately
  116. if time:
  117. self.current_attack.set_start_time()
  118. self.current_attack.generate_attack_packets()
  119. if time:
  120. self.current_attack.set_finish_time()
  121. duration = self.current_attack.get_packet_generation_time()
  122. self.total_packets, temp_attack_pcap_path = self.current_attack.generate_attack_pcap()
  123. print("done. (total: " + str(self.total_packets) + " pkts", end="")
  124. if time:
  125. print(" in ", duration, " seconds", end="")
  126. print(".)")
  127. # Store label into LabelManager
  128. label = Label.Label(attack, self.get_attack_start_utime(),
  129. self.get_attack_end_utime(), attack_note)
  130. self.label_mgr.add_labels(label)
  131. return temp_attack_pcap_path, duration
  132. def get_attack_start_utime(self):
  133. """
  134. :return: The start time (timestamp of first packet) of the attack as unix timestamp.
  135. """
  136. return self.current_attack.attack_start_utime
  137. def get_attack_end_utime(self):
  138. """
  139. :return: The end time (timestamp of last packet) of the attack as unix timestamp.
  140. """
  141. return self.current_attack.attack_end_utime
  142. def set_params(self, params: dict):
  143. """
  144. Sets the attack's parameters.
  145. :param params: The parameters in a dictionary: {parameter_name: parameter_value}
  146. :return: None
  147. """
  148. for param_key, param_value in params.items():
  149. self.current_attack.add_param_value(param_key, param_value)