SMBLorisAttack.py 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. import logging
  2. from random import randint, uniform
  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 = {
  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. :param statistics: Reference to a statistics object.
  39. """
  40. # PARAMETERS: initialize with default values
  41. # (values are overwritten if user specifies them)
  42. most_used_ip_address = self.statistics.get_most_used_ip_address()
  43. # The most used IP class in background traffic
  44. most_used_ip_class = handle_most_used_outputs(self.statistics.process_db_query("most_used(ipClass)"))
  45. num_attackers = randint(1, 16)
  46. source_ip = self.generate_random_ipv4_address(most_used_ip_class, num_attackers)
  47. self.add_param_value(Param.IP_SOURCE, source_ip)
  48. self.add_param_value(Param.MAC_SOURCE, self.generate_random_mac_address(num_attackers))
  49. random_ip_address = self.statistics.get_random_ip_address()
  50. # ip-dst should be valid and not equal to ip.src
  51. while not self.is_valid_ip_address(random_ip_address) or random_ip_address == source_ip:
  52. random_ip_address = self.statistics.get_random_ip_address()
  53. self.add_param_value(Param.IP_DESTINATION, random_ip_address)
  54. destination_mac = self.statistics.get_mac_address(random_ip_address)
  55. if isinstance(destination_mac, list) and len(destination_mac) == 0:
  56. destination_mac = self.generate_random_mac_address()
  57. self.add_param_value(Param.MAC_DESTINATION, destination_mac)
  58. self.add_param_value(Param.PACKETS_PER_SECOND,
  59. (self.statistics.get_pps_sent(most_used_ip_address) +
  60. self.statistics.get_pps_received(most_used_ip_address)) / 2)
  61. self.add_param_value(Param.INJECT_AFTER_PACKET, randint(0, self.statistics.get_packet_count()))
  62. self.add_param_value(Param.ATTACK_DURATION, 30)
  63. def generate_attack_pcap(self):
  64. pps = self.get_param_value(Param.PACKETS_PER_SECOND)
  65. # Timestamp
  66. first_timestamp = self.get_param_value(Param.INJECT_AT_TIMESTAMP)
  67. # store start time of attack
  68. self.attack_start_utime = first_timestamp
  69. # Initialize parameters
  70. packets = []
  71. ip_destination = self.get_param_value(Param.IP_DESTINATION)
  72. mac_destination = self.get_param_value(Param.MAC_DESTINATION)
  73. # Determine source IP and MAC address
  74. num_attackers = self.get_param_value(Param.NUMBER_ATTACKERS)
  75. if (num_attackers is not None) and (num_attackers is not 0): # user supplied Param.NUMBER_ATTACKERS
  76. # The most used IP class in background traffic
  77. most_used_ip_class = handle_most_used_outputs(self.statistics.process_db_query("most_used(ipClass)"))
  78. # Create random attackers based on user input Param.NUMBER_ATTACKERS
  79. ip_source = self.generate_random_ipv4_address(most_used_ip_class, num_attackers)
  80. mac_source = self.generate_random_mac_address(num_attackers)
  81. else: # user did not supply Param.NUMBER_ATTACKS
  82. # use default values for IP_SOURCE/MAC_SOURCE or overwritten values
  83. # if user supplied any values for those params
  84. ip_source = self.get_param_value(Param.IP_SOURCE)
  85. mac_source = self.get_param_value(Param.MAC_SOURCE)
  86. ip_source_list = []
  87. mac_source_list = []
  88. if isinstance(ip_source, list):
  89. ip_source_list = ip_source
  90. else:
  91. ip_source_list.append(ip_source)
  92. if isinstance(mac_source, list):
  93. mac_source_list = mac_source
  94. else:
  95. mac_source_list.append(mac_source)
  96. if (num_attackers is None) or (num_attackers is 0):
  97. num_attackers = min(len(ip_source_list), len(mac_source_list))
  98. # Check ip.src == ip.dst
  99. self.ip_src_dst_equal_check(ip_source_list, ip_destination)
  100. # Get MSS, TTL and Window size value for destination IP
  101. destination_mss_value, destination_ttl_value, destination_win_value = self.get_ip_data(ip_destination)
  102. minDelay,maxDelay = self.get_reply_delay(ip_destination)
  103. attack_duration = self.get_param_value(Param.ATTACK_DURATION)
  104. attack_ends_time = first_timestamp + attack_duration
  105. victim_pps = pps*num_attackers
  106. for attacker in range(num_attackers):
  107. # Get MSS, TTL and Window size value for source IP(attacker)
  108. source_mss_value, source_ttl_value, source_win_value = self.get_ip_data(ip_source_list[attacker])
  109. attacker_seq = randint(1000, 50000)
  110. victim_seq = randint(1000, 50000)
  111. sport = 1025
  112. # Timestamps of first packets shouldn't be exactly the same to look more realistic
  113. timestamp_next_pkt = uniform(first_timestamp, update_timestamp(first_timestamp, pps))
  114. while timestamp_next_pkt <= attack_ends_time:
  115. # Establish TCP connection
  116. if sport > 65535:
  117. sport = 1025
  118. # prepare reusable Ethernet- and IP-headers
  119. attacker_ether = Ether(src=mac_source_list[attacker], dst=mac_destination)
  120. attacker_ip = IP(src=ip_source_list[attacker], dst=ip_destination, ttl=source_ttl_value, flags='DF')
  121. victim_ether = Ether(src=mac_destination, dst=mac_source_list[attacker])
  122. victim_ip = IP(src=ip_destination, dst=ip_source_list[attacker], ttl=destination_ttl_value, flags='DF')
  123. # connection request from attacker (client)
  124. syn_tcp = TCP(sport=sport, dport=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 = update_timestamp(timestamp_next_pkt, victim_pps, minDelay)
  130. packets.append(syn)
  131. # response from victim (server)
  132. synack_tcp = TCP(sport=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 = update_timestamp(timestamp_next_pkt, pps, minDelay)
  138. packets.append(synack)
  139. # acknowledgement from attacker (client)
  140. ack_tcp = TCP(sport=sport, dport=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 = update_timestamp(timestamp_next_pkt, pps)
  145. packets.append(ack)
  146. # send NBT session header paket with maximum LENGTH-field
  147. req_tcp = TCP(sport=sport, dport=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 = update_timestamp(timestamp_next_pkt, victim_pps, minDelay)
  154. packets.append(req)
  155. # final ack from victim (server)
  156. last_ack_tcp = TCP(sport=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 = update_timestamp(timestamp_next_pkt, pps, minDelay)
  161. packets.append(last_ack)
  162. sport += 1
  163. # store end time of attack
  164. self.attack_end_utime = packets[-1].time
  165. # write attack packets to pcap
  166. pcap_path = self.write_attack_pcap(sorted(packets, key=lambda pkt: pkt.time))
  167. # return packets sorted by packet time_sec_start
  168. return len(packets), pcap_path