MS17ScanAttack.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. import logging
  2. from random import randint, uniform
  3. from lea import Lea
  4. from scapy.layers.inet import Ether
  5. from scapy.utils import RawPcapReader
  6. from Attack import BaseAttack
  7. from Attack.AttackParameters import Parameter as Param
  8. from Attack.AttackParameters import ParameterTypes
  9. from ID2TLib.SMBLib import smb_port
  10. import ID2TLib.Utility as Util
  11. logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
  12. # noinspection PyPep8
  13. class MS17ScanAttack(BaseAttack.BaseAttack):
  14. template_scan_pcap_path = Util.RESOURCE_DIR + "Win7_eternalblue_scan.pcap"
  15. # Empirical values from Metasploit experiments
  16. minDefaultPort = 30000
  17. maxDefaultPort = 50000
  18. last_conn_dst_port = 4444
  19. def __init__(self):
  20. """
  21. Creates a new instance of the EternalBlue Exploit.
  22. """
  23. # Initialize attack
  24. super(MS17ScanAttack, self).__init__("MS17ScanAttack", "Injects a MS17 scan'",
  25. "Scanning/Probing")
  26. # Define allowed parameters and their type
  27. self.supported_params.update({
  28. Param.MAC_SOURCE: ParameterTypes.TYPE_MAC_ADDRESS,
  29. Param.IP_SOURCE: ParameterTypes.TYPE_IP_ADDRESS,
  30. Param.PORT_SOURCE: ParameterTypes.TYPE_PORT,
  31. Param.MAC_DESTINATION: ParameterTypes.TYPE_MAC_ADDRESS,
  32. Param.IP_DESTINATION: ParameterTypes.TYPE_IP_ADDRESS,
  33. Param.PORT_DESTINATION: ParameterTypes.TYPE_PORT,
  34. Param.INJECT_AT_TIMESTAMP: ParameterTypes.TYPE_FLOAT,
  35. Param.INJECT_AFTER_PACKET: ParameterTypes.TYPE_PACKET_POSITION,
  36. Param.PACKETS_PER_SECOND: ParameterTypes.TYPE_FLOAT
  37. })
  38. def init_params(self):
  39. """
  40. Initialize the parameters of this attack using the user supplied command line parameters.
  41. Use the provided statistics to calculate default parameters and to process user
  42. supplied queries.
  43. """
  44. # PARAMETERS: initialize with default utilsvalues
  45. # (values are overwritten if user specifies them)
  46. # Attacker configuration
  47. most_used_ip_address = self.statistics.get_most_used_ip_address()
  48. random_ip_address = self.statistics.get_random_ip_address()
  49. while random_ip_address == most_used_ip_address:
  50. random_ip_address = self.statistics.get_random_ip_address()
  51. self.add_param_value(Param.IP_SOURCE, random_ip_address)
  52. self.add_param_value(Param.MAC_SOURCE, self.statistics.get_mac_address(random_ip_address))
  53. self.add_param_value(Param.PORT_SOURCE, randint(self.minDefaultPort, self.maxDefaultPort))
  54. # Victim configuration
  55. self.add_param_value(Param.IP_DESTINATION, most_used_ip_address)
  56. destination_mac = self.statistics.get_mac_address(most_used_ip_address)
  57. if isinstance(destination_mac, list) and len(destination_mac) == 0:
  58. destination_mac = self.generate_random_mac_address()
  59. self.add_param_value(Param.MAC_DESTINATION, destination_mac)
  60. self.add_param_value(Param.PORT_DESTINATION, smb_port)
  61. # Attack configuration
  62. self.add_param_value(Param.PACKETS_PER_SECOND,
  63. (self.statistics.get_pps_sent(most_used_ip_address) +
  64. self.statistics.get_pps_received(most_used_ip_address)) / 2)
  65. self.add_param_value(Param.INJECT_AFTER_PACKET, randint(0, self.statistics.get_packet_count()))
  66. def generate_attack_packets(self):
  67. # Timestamp
  68. timestamp_next_pkt = self.get_param_value(Param.INJECT_AT_TIMESTAMP)
  69. pps = self.get_param_value(Param.PACKETS_PER_SECOND)
  70. # calculate complement packet rates of BG traffic per interval
  71. complement_interval_pps = self.statistics.calculate_complement_packet_rates(pps)
  72. # Initialize parameters
  73. self.packets = []
  74. mac_source = self.get_param_value(Param.MAC_SOURCE)
  75. ip_source = self.get_param_value(Param.IP_SOURCE)
  76. port_source = self.get_param_value(Param.PORT_SOURCE)
  77. mac_destination = self.get_param_value(Param.MAC_DESTINATION)
  78. ip_destination = self.get_param_value(Param.IP_DESTINATION)
  79. port_destination = self.get_param_value(Param.PORT_DESTINATION)
  80. # Check ip.src == ip.dst
  81. self.ip_src_dst_equal_check(ip_source, ip_destination)
  82. self.path_attack_pcap = None
  83. # Set TTL based on TTL distribution of IP address
  84. source_ttl_dist = self.statistics.get_ttl_distribution(ip_source)
  85. if len(source_ttl_dist) > 0:
  86. source_ttl_prob_dict = Lea.fromValFreqsDict(source_ttl_dist)
  87. source_ttl_value = source_ttl_prob_dict.random()
  88. else:
  89. source_ttl_value = Util.handle_most_used_outputs(self.statistics.process_db_query("most_used(ttlValue)"))
  90. destination_ttl_dist = self.statistics.get_ttl_distribution(ip_destination)
  91. if len(destination_ttl_dist) > 0:
  92. destination_ttl_prob_dict = Lea.fromValFreqsDict(destination_ttl_dist)
  93. destination_ttl_value = destination_ttl_prob_dict.random()
  94. else:
  95. destination_ttl_value = Util.handle_most_used_outputs(
  96. self.statistics.process_db_query("most_used(ttlValue)"))
  97. # Set Window Size based on Window Size distribution of IP address
  98. source_win_dist = self.statistics.get_win_distribution(ip_source)
  99. if len(source_win_dist) > 0:
  100. source_win_prob_dict = Lea.fromValFreqsDict(source_win_dist)
  101. else:
  102. source_win_dist = self.statistics.get_win_distribution(self.statistics.get_most_used_ip_address())
  103. source_win_prob_dict = Lea.fromValFreqsDict(source_win_dist)
  104. destination_win_dist = self.statistics.get_win_distribution(ip_destination)
  105. if len(destination_win_dist) > 0:
  106. destination_win_prob_dict = Lea.fromValFreqsDict(destination_win_dist)
  107. else:
  108. destination_win_dist = self.statistics.get_win_distribution(self.statistics.get_most_used_ip_address())
  109. destination_win_prob_dict = Lea.fromValFreqsDict(destination_win_dist)
  110. # Set MSS (Maximum Segment Size) based on MSS distribution of IP address
  111. mss_value = Util.handle_most_used_outputs(self.statistics.process_db_query("most_used(mssValue)"))
  112. if not mss_value:
  113. mss_value = 1465
  114. # Scan (MS17)
  115. # Read Win7_eternalblue_scan pcap file
  116. orig_ip_dst = None
  117. exploit_raw_packets = RawPcapReader(self.template_scan_pcap_path)
  118. inter_arrival_times = self.get_inter_arrival_time(exploit_raw_packets)
  119. exploit_raw_packets.close()
  120. exploit_raw_packets = RawPcapReader(self.template_scan_pcap_path)
  121. source_origin_wins, destination_origin_wins = {}, {}
  122. for self.pkt_num, pkt in enumerate(exploit_raw_packets):
  123. eth_frame = Ether(pkt[0])
  124. ip_pkt = eth_frame.payload
  125. tcp_pkt = ip_pkt.payload
  126. if self.pkt_num == 0:
  127. if tcp_pkt.getfieldval("dport") == smb_port:
  128. orig_ip_dst = ip_pkt.getfieldval("dst") # victim IP
  129. # Request
  130. if ip_pkt.getfieldval("dst") == orig_ip_dst: # victim IP
  131. # Ether
  132. eth_frame.setfieldval("src", mac_source)
  133. eth_frame.setfieldval("dst", mac_destination)
  134. # IP
  135. ip_pkt.setfieldval("src", ip_source)
  136. ip_pkt.setfieldval("dst", ip_destination)
  137. ip_pkt.setfieldval("ttl", source_ttl_value)
  138. # TCP
  139. tcp_pkt.setfieldval("sport", port_source)
  140. tcp_pkt.setfieldval("dport", port_destination)
  141. ## Window Size (mapping)
  142. source_origin_win = tcp_pkt.getfieldval("window")
  143. if source_origin_win not in source_origin_wins:
  144. source_origin_wins[source_origin_win] = source_win_prob_dict.random()
  145. new_win = source_origin_wins[source_origin_win]
  146. tcp_pkt.setfieldval("window", new_win)
  147. ## MSS
  148. tcp_options = tcp_pkt.getfieldval("options")
  149. if tcp_options:
  150. if tcp_options[0][0] == "MSS":
  151. tcp_options[0] = ("MSS", mss_value)
  152. tcp_pkt.setfieldval("options", tcp_options)
  153. new_pkt = (eth_frame / ip_pkt / tcp_pkt)
  154. new_pkt.time = timestamp_next_pkt
  155. pps = max(Util.get_interval_pps(complement_interval_pps, timestamp_next_pkt), 10)
  156. timestamp_next_pkt = Util.update_timestamp(timestamp_next_pkt, pps) + inter_arrival_times[
  157. self.pkt_num] # float(timeSteps.random())
  158. # Reply
  159. else:
  160. # Ether
  161. eth_frame.setfieldval("src", mac_destination)
  162. eth_frame.setfieldval("dst", mac_source)
  163. # IP
  164. ip_pkt.setfieldval("src", ip_destination)
  165. ip_pkt.setfieldval("dst", ip_source)
  166. ip_pkt.setfieldval("ttl", destination_ttl_value)
  167. # TCP
  168. tcp_pkt.setfieldval("dport", port_source)
  169. tcp_pkt.setfieldval("sport", port_destination)
  170. ## Window Size
  171. destination_origin_win = tcp_pkt.getfieldval("window")
  172. if destination_origin_win not in destination_origin_wins:
  173. destination_origin_wins[destination_origin_win] = destination_win_prob_dict.random()
  174. new_win = destination_origin_wins[destination_origin_win]
  175. tcp_pkt.setfieldval("window", new_win)
  176. ## MSS
  177. tcp_options = tcp_pkt.getfieldval("options")
  178. if tcp_options:
  179. if tcp_options[0][0] == "MSS":
  180. tcp_options[0] = ("MSS", mss_value)
  181. tcp_pkt.setfieldval("options", tcp_options)
  182. new_pkt = (eth_frame / ip_pkt / tcp_pkt)
  183. timestamp_next_pkt = Util.update_timestamp(timestamp_next_pkt, pps) + inter_arrival_times[
  184. self.pkt_num] # + float(timeSteps.random())
  185. new_pkt.time = timestamp_next_pkt
  186. self.packets.append(new_pkt)
  187. exploit_raw_packets.close()
  188. def generate_attack_pcap(self):
  189. # Store timestamp of first packet (for attack label)
  190. self.attack_start_utime = self.packets[0].time
  191. self.attack_end_utime = self.packets[-1].time
  192. if len(self.packets) > 0:
  193. self.packets = sorted(self.packets, key=lambda pkt: pkt.time)
  194. self.path_attack_pcap = self.write_attack_pcap(self.packets, True, self.path_attack_pcap)
  195. # return packets sorted by packet time_sec_start
  196. # pkt_num+1: because pkt_num starts at 0
  197. return self.pkt_num + 1, self.path_attack_pcap