SMBLorisAttack.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  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.process_db_query("most_used(ipClass)"))
  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. pps = self.get_param_value(atkParam.Parameter.PACKETS_PER_SECOND)
  62. # Timestamp
  63. first_timestamp = self.get_param_value(atkParam.Parameter.INJECT_AT_TIMESTAMP)
  64. # store start time of attack
  65. self.attack_start_utime = first_timestamp
  66. # Initialize parameters
  67. self.packets = []
  68. ip_destination = self.get_param_value(atkParam.Parameter.IP_DESTINATION)
  69. mac_destination = self.get_param_value(atkParam.Parameter.MAC_DESTINATION)
  70. # Determine source IP and MAC address
  71. num_attackers = self.get_param_value(atkParam.Parameter.NUMBER_ATTACKERS)
  72. # user supplied atkParam.Parameter.NUMBER_ATTACKERS
  73. if (num_attackers is not None) and (num_attackers is not 0):
  74. # The most used IP class in background traffic
  75. most_used_ip_class = Util.handle_most_used_outputs(self.statistics.process_db_query("most_used(ipClass)"))
  76. # Create random attackers based on user input atkParam.Parameter.NUMBER_ATTACKERS
  77. ip_source = self.generate_random_ipv4_address(most_used_ip_class, num_attackers)
  78. mac_source = self.generate_random_mac_address(num_attackers)
  79. else: # user did not supply atkParam.Parameter.NUMBER_ATTACKS
  80. # use default values for IP_SOURCE/MAC_SOURCE or overwritten values
  81. # if user supplied any values for those params
  82. ip_source = self.get_param_value(atkParam.Parameter.IP_SOURCE)
  83. mac_source = self.get_param_value(atkParam.Parameter.MAC_SOURCE)
  84. ip_source_list = []
  85. mac_source_list = []
  86. if isinstance(ip_source, list):
  87. ip_source_list = ip_source
  88. else:
  89. ip_source_list.append(ip_source)
  90. if isinstance(mac_source, list):
  91. mac_source_list = mac_source
  92. else:
  93. mac_source_list.append(mac_source)
  94. if (num_attackers is None) or (num_attackers is 0):
  95. num_attackers = min(len(ip_source_list), len(mac_source_list))
  96. # Check ip.src == ip.dst
  97. self.ip_src_dst_equal_check(ip_source_list, ip_destination)
  98. # Get MSS, TTL and Window size value for destination IP
  99. destination_mss_value, destination_ttl_value, destination_win_value = self.get_ip_data(ip_destination)
  100. min_delay, max_delay = self.get_reply_delay(ip_destination)
  101. attack_duration = self.get_param_value(atkParam.Parameter.ATTACK_DURATION)
  102. attack_ends_time = first_timestamp + attack_duration
  103. victim_pps = pps * num_attackers
  104. for attacker in range(num_attackers):
  105. # Get MSS, TTL and Window size value for source IP(attacker)
  106. source_mss_value, source_ttl_value, source_win_value = self.get_ip_data(ip_source_list[attacker])
  107. attacker_seq = rnd.randint(1000, 50000)
  108. victim_seq = rnd.randint(1000, 50000)
  109. sport = 1025
  110. # Timestamps of first self.packets shouldn't be exactly the same to look more realistic
  111. timestamp_next_pkt = rnd.uniform(first_timestamp, Util.update_timestamp(first_timestamp, pps))
  112. while timestamp_next_pkt <= attack_ends_time:
  113. # Establish TCP connection
  114. if sport > 65535:
  115. sport = 1025
  116. # prepare reusable Ethernet- and IP-headers
  117. attacker_ether = inet.Ether(src=mac_source_list[attacker], dst=mac_destination)
  118. attacker_ip = inet.IP(src=ip_source_list[attacker], dst=ip_destination, ttl=source_ttl_value,
  119. flags='DF')
  120. victim_ether = inet.Ether(src=mac_destination, dst=mac_source_list[attacker])
  121. victim_ip = inet.IP(src=ip_destination, dst=ip_source_list[attacker], ttl=destination_ttl_value,
  122. flags='DF')
  123. # connection request from attacker (client)
  124. syn_tcp = inet.TCP(sport=sport, dport=SMBLib.smb_port, window=source_win_value, flags='S',
  125. seq=attacker_seq, options=[('MSS', source_mss_value)])
  126. attacker_seq += 1
  127. syn = (attacker_ether / attacker_ip / syn_tcp)
  128. syn.time = timestamp_next_pkt
  129. timestamp_next_pkt = Util.update_timestamp(timestamp_next_pkt, victim_pps, min_delay)
  130. self.packets.append(syn)
  131. # response from victim (server)
  132. synack_tcp = inet.TCP(sport=SMBLib.smb_port, dport=sport, seq=victim_seq, ack=attacker_seq, flags='SA',
  133. window=destination_win_value, options=[('MSS', destination_mss_value)])
  134. victim_seq += 1
  135. synack = (victim_ether / victim_ip / synack_tcp)
  136. synack.time = timestamp_next_pkt
  137. timestamp_next_pkt = Util.update_timestamp(timestamp_next_pkt, pps, min_delay)
  138. self.packets.append(synack)
  139. # acknowledgement from attacker (client)
  140. ack_tcp = inet.TCP(sport=sport, dport=SMBLib.smb_port, seq=attacker_seq, ack=victim_seq, flags='A',
  141. window=source_win_value, options=[('MSS', source_mss_value)])
  142. ack = (attacker_ether / attacker_ip / ack_tcp)
  143. ack.time = timestamp_next_pkt
  144. timestamp_next_pkt = Util.update_timestamp(timestamp_next_pkt, pps)
  145. self.packets.append(ack)
  146. # send NBT session header paket with maximum LENGTH-field
  147. req_tcp = inet.TCP(sport=sport, dport=SMBLib.smb_port, seq=attacker_seq, ack=victim_seq, flags='AP',
  148. window=source_win_value, options=[('MSS', source_mss_value)])
  149. req_payload = NBTSession(TYPE=0x00, LENGTH=0x1FFFF)
  150. attacker_seq += len(req_payload)
  151. req = (attacker_ether / attacker_ip / req_tcp / req_payload)
  152. req.time = timestamp_next_pkt
  153. timestamp_next_pkt = Util.update_timestamp(timestamp_next_pkt, victim_pps, min_delay)
  154. self.packets.append(req)
  155. # final ack from victim (server)
  156. last_ack_tcp = inet.TCP(sport=SMBLib.smb_port, dport=sport, seq=victim_seq, ack=attacker_seq, flags='A',
  157. window=destination_win_value, options=[('MSS', destination_mss_value)])
  158. last_ack = (victim_ether / victim_ip / last_ack_tcp)
  159. last_ack.time = timestamp_next_pkt
  160. timestamp_next_pkt = Util.update_timestamp(timestamp_next_pkt, pps, min_delay)
  161. self.packets.append(last_ack)
  162. sport += 1
  163. def generate_attack_pcap(self):
  164. # store end time of attack
  165. self.attack_end_utime = self.packets[-1].time
  166. # write attack self.packets to pcap
  167. pcap_path = self.write_attack_pcap(sorted(self.packets, key=lambda pkt: pkt.time))
  168. # return packets sorted by packet time_sec_start
  169. return len(self.packets), pcap_path