SMBLorisAttack.py 10 KB

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