SMBLorisAttack.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. import logging
  2. import random as rnd
  3. import scapy.layers.inet as inet
  4. from scapy.layers.netbios import NBTSession
  5. import Attack.AttackParameters as atkParam
  6. import Attack.BaseAttack as BaseAttack
  7. import ID2TLib.SMBLib as SMBLib
  8. import ID2TLib.Utility as Util
  9. logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
  10. # noinspection PyPep8
  11. class SMBLorisAttack(BaseAttack.BaseAttack):
  12. def __init__(self):
  13. """
  14. Creates a new instance of the SMBLorisAttack.
  15. """
  16. # Initialize attack
  17. super(SMBLorisAttack, self).__init__("SMBLoris Attack", "Injects an SMBLoris (D)DoS Attack",
  18. "Resource Exhaustion")
  19. # Define allowed parameters and their type
  20. self.supported_params.update({
  21. atkParam.Parameter.IP_SOURCE: atkParam.ParameterTypes.TYPE_IP_ADDRESS,
  22. atkParam.Parameter.IP_DESTINATION: atkParam.ParameterTypes.TYPE_IP_ADDRESS,
  23. atkParam.Parameter.MAC_SOURCE: atkParam.ParameterTypes.TYPE_MAC_ADDRESS,
  24. atkParam.Parameter.MAC_DESTINATION: atkParam.ParameterTypes.TYPE_MAC_ADDRESS,
  25. atkParam.Parameter.INJECT_AT_TIMESTAMP: atkParam.ParameterTypes.TYPE_FLOAT,
  26. atkParam.Parameter.INJECT_AFTER_PACKET: atkParam.ParameterTypes.TYPE_PACKET_POSITION,
  27. atkParam.Parameter.PACKETS_PER_SECOND: atkParam.ParameterTypes.TYPE_FLOAT,
  28. atkParam.Parameter.ATTACK_DURATION: atkParam.ParameterTypes.TYPE_INTEGER_POSITIVE,
  29. atkParam.Parameter.NUMBER_ATTACKERS: atkParam.ParameterTypes.TYPE_INTEGER_POSITIVE
  30. })
  31. def init_params(self):
  32. """
  33. Initialize the parameters of this attack using the user supplied command line parameters.
  34. Use the provided statistics to calculate default parameters and to process user
  35. supplied queries.
  36. """
  37. # PARAMETERS: initialize with default values
  38. # (values are overwritten if user specifies them)
  39. most_used_ip_address = self.statistics.get_most_used_ip_address()
  40. # The most used IP class in background traffic
  41. most_used_ip_class = Util.handle_most_used_outputs(self.statistics.get_most_used_ip_class())
  42. num_attackers = rnd.randint(1, 16)
  43. source_ip = self.generate_random_ipv4_address(most_used_ip_class, num_attackers)
  44. self.add_param_value(atkParam.Parameter.IP_SOURCE, source_ip)
  45. self.add_param_value(atkParam.Parameter.MAC_SOURCE, self.generate_random_mac_address(num_attackers))
  46. random_ip_address = self.statistics.get_random_ip_address()
  47. # ip-dst should be valid and not equal to ip.src
  48. while not self.is_valid_ip_address(random_ip_address) or random_ip_address == source_ip:
  49. random_ip_address = self.statistics.get_random_ip_address()
  50. self.add_param_value(atkParam.Parameter.IP_DESTINATION, random_ip_address)
  51. destination_mac = self.statistics.get_mac_address(random_ip_address)
  52. if isinstance(destination_mac, list) and len(destination_mac) == 0:
  53. destination_mac = self.generate_random_mac_address()
  54. self.add_param_value(atkParam.Parameter.MAC_DESTINATION, destination_mac)
  55. self.add_param_value(atkParam.Parameter.PACKETS_PER_SECOND,
  56. (self.statistics.get_pps_sent(most_used_ip_address) +
  57. self.statistics.get_pps_received(most_used_ip_address)) / 2)
  58. self.add_param_value(atkParam.Parameter.INJECT_AFTER_PACKET, rnd.randint(0, self.statistics.get_packet_count()))
  59. self.add_param_value(atkParam.Parameter.ATTACK_DURATION, 30)
  60. def generate_attack_packets(self):
  61. """
  62. Creates the attack packets.
  63. """
  64. pps = self.get_param_value(atkParam.Parameter.PACKETS_PER_SECOND)
  65. # Timestamp
  66. first_timestamp = self.get_param_value(atkParam.Parameter.INJECT_AT_TIMESTAMP)
  67. # store start time of attack
  68. self.attack_start_utime = first_timestamp
  69. # Initialize parameters
  70. self.packets = []
  71. ip_destination = self.get_param_value(atkParam.Parameter.IP_DESTINATION)
  72. mac_destination = self.get_param_value(atkParam.Parameter.MAC_DESTINATION)
  73. # Determine source IP and MAC address
  74. num_attackers = self.get_param_value(atkParam.Parameter.NUMBER_ATTACKERS)
  75. # user supplied atkParam.Parameter.NUMBER_ATTACKERS
  76. if (num_attackers is not None) and (num_attackers is not 0):
  77. # The most used IP class in background traffic
  78. most_used_ip_class = Util.handle_most_used_outputs(self.statistics.get_most_used_ip_class())
  79. # Create random attackers based on user input atkParam.Parameter.NUMBER_ATTACKERS
  80. ip_source = self.generate_random_ipv4_address(most_used_ip_class, num_attackers)
  81. mac_source = self.generate_random_mac_address(num_attackers)
  82. else: # user did not supply atkParam.Parameter.NUMBER_ATTACKS
  83. # use default values for IP_SOURCE/MAC_SOURCE or overwritten values
  84. # if user supplied any values for those params
  85. ip_source = self.get_param_value(atkParam.Parameter.IP_SOURCE)
  86. mac_source = self.get_param_value(atkParam.Parameter.MAC_SOURCE)
  87. ip_source_list = []
  88. mac_source_list = []
  89. if isinstance(ip_source, list):
  90. ip_source_list = ip_source
  91. else:
  92. ip_source_list.append(ip_source)
  93. if isinstance(mac_source, list):
  94. mac_source_list = mac_source
  95. else:
  96. mac_source_list.append(mac_source)
  97. if (num_attackers is None) or (num_attackers is 0):
  98. num_attackers = min(len(ip_source_list), len(mac_source_list))
  99. # Check ip.src == ip.dst
  100. self.ip_src_dst_equal_check(ip_source_list, ip_destination)
  101. # Get MSS, TTL and Window size value for destination IP
  102. destination_mss_value, destination_ttl_value, destination_win_value = self.get_ip_data(ip_destination)
  103. min_delay, max_delay = self.get_reply_delay(ip_destination)
  104. attack_duration = self.get_param_value(atkParam.Parameter.ATTACK_DURATION)
  105. attack_ends_time = first_timestamp + attack_duration
  106. victim_pps = pps * num_attackers
  107. for attacker in range(num_attackers):
  108. # Get MSS, TTL and Window size value for source IP(attacker)
  109. source_mss_value, source_ttl_value, source_win_value = self.get_ip_data(ip_source_list[attacker])
  110. attacker_seq = rnd.randint(1000, 50000)
  111. victim_seq = rnd.randint(1000, 50000)
  112. sport = 1025
  113. # Timestamps of first self.packets shouldn't be exactly the same to look more realistic
  114. timestamp_next_pkt = rnd.uniform(first_timestamp, Util.update_timestamp(first_timestamp, pps))
  115. while timestamp_next_pkt <= attack_ends_time:
  116. # Establish TCP connection
  117. if sport > 65535:
  118. sport = 1025
  119. # prepare reusable Ethernet- and IP-headers
  120. attacker_ether = inet.Ether(src=mac_source_list[attacker], dst=mac_destination)
  121. attacker_ip = inet.IP(src=ip_source_list[attacker], dst=ip_destination, ttl=source_ttl_value,
  122. flags='DF')
  123. victim_ether = inet.Ether(src=mac_destination, dst=mac_source_list[attacker])
  124. victim_ip = inet.IP(src=ip_destination, dst=ip_source_list[attacker], ttl=destination_ttl_value,
  125. flags='DF')
  126. # connection request from attacker (client)
  127. syn_tcp = inet.TCP(sport=sport, dport=SMBLib.smb_port, window=source_win_value, flags='S',
  128. seq=attacker_seq, options=[('MSS', source_mss_value)])
  129. attacker_seq += 1
  130. syn = (attacker_ether / attacker_ip / syn_tcp)
  131. syn.time = timestamp_next_pkt
  132. timestamp_next_pkt = Util.update_timestamp(timestamp_next_pkt, victim_pps, min_delay)
  133. self.packets.append(syn)
  134. # response from victim (server)
  135. synack_tcp = inet.TCP(sport=SMBLib.smb_port, dport=sport, seq=victim_seq, ack=attacker_seq, flags='SA',
  136. window=destination_win_value, options=[('MSS', destination_mss_value)])
  137. victim_seq += 1
  138. synack = (victim_ether / victim_ip / synack_tcp)
  139. synack.time = timestamp_next_pkt
  140. timestamp_next_pkt = Util.update_timestamp(timestamp_next_pkt, pps, min_delay)
  141. self.packets.append(synack)
  142. # acknowledgement from attacker (client)
  143. ack_tcp = inet.TCP(sport=sport, dport=SMBLib.smb_port, seq=attacker_seq, ack=victim_seq, flags='A',
  144. window=source_win_value, options=[('MSS', source_mss_value)])
  145. ack = (attacker_ether / attacker_ip / ack_tcp)
  146. ack.time = timestamp_next_pkt
  147. timestamp_next_pkt = Util.update_timestamp(timestamp_next_pkt, pps)
  148. self.packets.append(ack)
  149. # send NBT session header paket with maximum LENGTH-field
  150. req_tcp = inet.TCP(sport=sport, dport=SMBLib.smb_port, seq=attacker_seq, ack=victim_seq, flags='AP',
  151. window=source_win_value, options=[('MSS', source_mss_value)])
  152. req_payload = NBTSession(TYPE=0x00, LENGTH=0x1FFFF)
  153. attacker_seq += len(req_payload)
  154. req = (attacker_ether / attacker_ip / req_tcp / req_payload)
  155. req.time = timestamp_next_pkt
  156. timestamp_next_pkt = Util.update_timestamp(timestamp_next_pkt, victim_pps, min_delay)
  157. self.packets.append(req)
  158. # final ack from victim (server)
  159. last_ack_tcp = inet.TCP(sport=SMBLib.smb_port, dport=sport, seq=victim_seq, ack=attacker_seq, flags='A',
  160. window=destination_win_value, options=[('MSS', destination_mss_value)])
  161. last_ack = (victim_ether / victim_ip / last_ack_tcp)
  162. last_ack.time = timestamp_next_pkt
  163. timestamp_next_pkt = Util.update_timestamp(timestamp_next_pkt, pps, min_delay)
  164. self.packets.append(last_ack)
  165. sport += 1
  166. def generate_attack_pcap(self):
  167. """
  168. Creates a pcap containing the attack packets.
  169. :return: The location of the generated pcap file.
  170. """
  171. # store end time of attack
  172. self.attack_end_utime = self.packets[-1].time
  173. # write attack self.packets to pcap
  174. pcap_path = self.write_attack_pcap(sorted(self.packets, key=lambda pkt: pkt.time))
  175. # return packets sorted by packet time_sec_start
  176. return len(self.packets), pcap_path