EternalBlueExploit.py 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399
  1. import logging
  2. from random import randint, uniform
  3. from lea import Lea
  4. from scapy.utils import RawPcapReader
  5. from scapy.layers.inet import Ether
  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, get_interval_pps
  10. logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
  11. # noinspection PyPep8
  12. class EternalBlueExploit(BaseAttack.BaseAttack):
  13. template_scan_pcap_path = "resources/Win7_eternalblue_scan.pcap"
  14. template_attack_pcap_path = "resources/Win7_eternalblue_exploit.pcap"
  15. # SMB port
  16. smb_port = 445
  17. # Empirical values from Metasploit experiments
  18. minDefaultPort = 30000
  19. maxDefaultPort = 50000
  20. last_conn_dst_port = 4444
  21. def __init__(self):
  22. """
  23. Creates a new instance of the EternalBlue Exploit.
  24. """
  25. # Initialize attack
  26. super(EternalBlueExploit, self).__init__("EternalBlue Exploit", "Injects an EternalBlue exploit'",
  27. "Privilege elevation")
  28. # Define allowed parameters and their type
  29. self.supported_params = {
  30. Param.MAC_SOURCE: ParameterTypes.TYPE_MAC_ADDRESS,
  31. Param.IP_SOURCE: ParameterTypes.TYPE_IP_ADDRESS,
  32. Param.PORT_SOURCE: ParameterTypes.TYPE_PORT,
  33. Param.MAC_DESTINATION: ParameterTypes.TYPE_MAC_ADDRESS,
  34. Param.IP_DESTINATION: ParameterTypes.TYPE_IP_ADDRESS,
  35. Param.PORT_DESTINATION: ParameterTypes.TYPE_PORT,
  36. Param.INJECT_AT_TIMESTAMP: ParameterTypes.TYPE_FLOAT,
  37. Param.INJECT_AFTER_PACKET: ParameterTypes.TYPE_PACKET_POSITION,
  38. Param.PACKETS_PER_SECOND: ParameterTypes.TYPE_FLOAT
  39. }
  40. def init_params(self):
  41. """
  42. Initialize the parameters of this attack using the user supplied command line parameters.
  43. Use the provided statistics to calculate default parameters and to process user
  44. supplied queries.
  45. :param statistics: Reference to a statistics object.
  46. """
  47. # PARAMETERS: initialize with default utilsvalues
  48. # (values are overwritten if user specifies them)
  49. # Attacker configuration
  50. most_used_ip_address = self.statistics.get_most_used_ip_address()
  51. if isinstance(most_used_ip_address, list):
  52. most_used_ip_address = most_used_ip_address[0]
  53. random_ip_address = self.statistics.get_random_ip_address()
  54. self.add_param_value(Param.IP_SOURCE, random_ip_address)
  55. self.add_param_value(Param.MAC_SOURCE, self.statistics.get_mac_address(random_ip_address))
  56. self.add_param_value(Param.PORT_SOURCE, randint(self.minDefaultPort, self.maxDefaultPort))
  57. # Victim configuration
  58. self.add_param_value(Param.IP_DESTINATION, most_used_ip_address)
  59. destination_mac = self.statistics.get_mac_address(most_used_ip_address)
  60. if isinstance(destination_mac, list) and len(destination_mac) == 0:
  61. destination_mac = self.generate_random_mac_address()
  62. self.add_param_value(Param.MAC_DESTINATION, destination_mac)
  63. self.add_param_value(Param.PORT_DESTINATION, self.smb_port)
  64. # Attack configuration
  65. self.add_param_value(Param.PACKETS_PER_SECOND,
  66. (self.statistics.get_pps_sent(most_used_ip_address) +
  67. self.statistics.get_pps_received(most_used_ip_address)) / 2)
  68. self.add_param_value(Param.INJECT_AFTER_PACKET, randint(0, self.statistics.get_packet_count()))
  69. def generate_attack_pcap(self):
  70. # Timestamp
  71. timestamp_next_pkt = self.get_param_value(Param.INJECT_AT_TIMESTAMP)
  72. pps = self.get_param_value(Param.PACKETS_PER_SECOND)
  73. # calculate complement packet rates of BG traffic per interval
  74. complement_interval_pps = self.statistics.calculate_complement_packet_rates(pps)
  75. # Initialize parameters
  76. packets = []
  77. mac_source = self.get_param_value(Param.MAC_SOURCE)
  78. ip_source = self.get_param_value(Param.IP_SOURCE)
  79. port_source = self.get_param_value(Param.PORT_SOURCE)
  80. mac_destination = self.get_param_value(Param.MAC_DESTINATION)
  81. ip_destination = self.get_param_value(Param.IP_DESTINATION)
  82. port_destination = self.get_param_value(Param.PORT_DESTINATION)
  83. # Check ip.src == ip.dst
  84. self.ip_src_dst_equal_check(ip_source, ip_destination)
  85. path_attack_pcap = None
  86. # Set TTL based on TTL distribution of IP address
  87. source_ttl_dist = self.statistics.get_ttl_distribution(ip_source)
  88. if len(source_ttl_dist) > 0:
  89. source_ttl_prob_dict = Lea.fromValFreqsDict(source_ttl_dist)
  90. source_ttl_value = source_ttl_prob_dict.random()
  91. else:
  92. source_ttl_value = self.statistics.process_db_query("most_used(ttlValue)")
  93. destination_ttl_dist = self.statistics.get_ttl_distribution(ip_destination)
  94. if len(destination_ttl_dist) > 0:
  95. destination_ttl_prob_dict = Lea.fromValFreqsDict(destination_ttl_dist)
  96. destination_ttl_value = destination_ttl_prob_dict.random()
  97. else:
  98. destination_ttl_value = self.statistics.process_db_query("most_used(ttlValue)")
  99. # Set Window Size based on Window Size distribution of IP address
  100. source_win_dist = self.statistics.get_win_distribution(ip_source)
  101. if len(source_win_dist) > 0:
  102. source_win_prob_dict = Lea.fromValFreqsDict(source_win_dist)
  103. else:
  104. source_win_dist = self.statistics.get_win_distribution(self.statistics.get_most_used_ip_address())
  105. source_win_prob_dict = Lea.fromValFreqsDict(source_win_dist)
  106. destination_win_dist = self.statistics.get_win_distribution(ip_destination)
  107. if len(destination_win_dist) > 0:
  108. destination_win_prob_dict = Lea.fromValFreqsDict(destination_win_dist)
  109. else:
  110. destination_win_dist = self.statistics.get_win_distribution(self.statistics.get_most_used_ip_address())
  111. destination_win_prob_dict = Lea.fromValFreqsDict(destination_win_dist)
  112. # Set MSS (Maximum Segment Size) based on MSS distribution of IP address
  113. mss_value = self.statistics.process_db_query("most_used(mssValue)")
  114. if not mss_value:
  115. mss_value = 1465
  116. # Scan (MS17) for EternalBlue
  117. # Read Win7_eternalblue_scan pcap file
  118. orig_ip_dst = None
  119. exploit_raw_packets = RawPcapReader(self.template_scan_pcap_path)
  120. inter_arrival_times = self.get_inter_arrival_time(exploit_raw_packets)
  121. exploit_raw_packets = RawPcapReader(self.template_scan_pcap_path)
  122. source_origin_wins, destination_origin_wins = {}, {}
  123. for pkt_num, pkt in enumerate(exploit_raw_packets):
  124. eth_frame = Ether(pkt[0])
  125. ip_pkt = eth_frame.payload
  126. tcp_pkt = ip_pkt.payload
  127. if pkt_num == 0:
  128. if tcp_pkt.getfieldval("dport") == self.smb_port:
  129. orig_ip_dst = ip_pkt.getfieldval("dst") # victim IP
  130. # Request
  131. if ip_pkt.getfieldval("dst") == orig_ip_dst: # victim IP
  132. # Ether
  133. eth_frame.setfieldval("src", mac_source)
  134. eth_frame.setfieldval("dst", mac_destination)
  135. # IP
  136. ip_pkt.setfieldval("src", ip_source)
  137. ip_pkt.setfieldval("dst", ip_destination)
  138. ip_pkt.setfieldval("ttl", source_ttl_value)
  139. # TCP
  140. tcp_pkt.setfieldval("sport",port_source)
  141. tcp_pkt.setfieldval("dport",port_destination)
  142. ## Window Size (mapping)
  143. source_origin_win = tcp_pkt.getfieldval("window")
  144. if source_origin_win not in source_origin_wins:
  145. source_origin_wins[source_origin_win] = source_win_prob_dict.random()
  146. new_win = source_origin_wins[source_origin_win]
  147. tcp_pkt.setfieldval("window", new_win)
  148. ## MSS
  149. tcp_options = tcp_pkt.getfieldval("options")
  150. if tcp_options:
  151. if tcp_options[0][0] == "MSS":
  152. tcp_options [0] = ("MSS",mss_value)
  153. tcp_pkt.setfieldval("options", tcp_options)
  154. new_pkt = (eth_frame / ip_pkt / tcp_pkt)
  155. new_pkt.time = timestamp_next_pkt
  156. pps = max(get_interval_pps(complement_interval_pps, timestamp_next_pkt), 10)
  157. timestamp_next_pkt = update_timestamp(timestamp_next_pkt, pps) + inter_arrival_times[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 = update_timestamp(timestamp_next_pkt, pps) + inter_arrival_times[pkt_num]#+ float(timeSteps.random())
  184. new_pkt.time = timestamp_next_pkt
  185. packets.append(new_pkt)
  186. # Inject EternalBlue exploit packets
  187. # Read Win7_eternalblue_exploit pcap file
  188. exploit_raw_packets = RawPcapReader(self.template_attack_pcap_path)
  189. port_source = randint(self.minDefaultPort,self.maxDefaultPort) # experiments show this range of ports
  190. # conversations = {(ip.src, ip.dst, port.src, port.dst): packets}
  191. conversations, orderList_conversations = self.packetsToConvs(exploit_raw_packets)
  192. conv_start_timesamp = timestamp_next_pkt
  193. for conv_index, conv in enumerate(orderList_conversations):
  194. conv_start_timesamp = conv_start_timesamp + uniform(0.001,0.01) # the distance between the starts of the converstaions
  195. timestamp_next_pkt = conv_start_timesamp
  196. conv_pkts = conversations[conv]
  197. inter_arrival_times = self.get_inter_arrival_time(conv_pkts)
  198. if conv_index == len(orderList_conversations) - 2: # Not the last conversation
  199. timestamp_next_pkt = packets[-1].time + uniform(0.001,0.01)
  200. if conv_index != len(orderList_conversations)-1: # Not the last conversation
  201. port_source += 2
  202. for pkt_num, pkt in enumerate(conv_pkts):
  203. eth_frame = Ether(pkt[0])
  204. ip_pkt = eth_frame.payload
  205. tcp_pkt = ip_pkt.payload
  206. if pkt_num == 0:
  207. if tcp_pkt.getfieldval("dport") == self.smb_port:
  208. orig_ip_dst = ip_pkt.getfieldval("dst")
  209. # Request
  210. if ip_pkt.getfieldval("dst") == orig_ip_dst: # victim IP
  211. # Ether
  212. eth_frame.setfieldval("src", mac_source)
  213. eth_frame.setfieldval("dst", mac_destination)
  214. # IP
  215. ip_pkt.setfieldval("src", ip_source)
  216. ip_pkt.setfieldval("dst", ip_destination)
  217. ip_pkt.setfieldval("ttl", source_ttl_value)
  218. # TCP
  219. tcp_pkt.setfieldval("sport", port_source)
  220. tcp_pkt.setfieldval("dport", port_destination)
  221. ## Window Size
  222. source_origin_win = tcp_pkt.getfieldval("window")
  223. if source_origin_win not in source_origin_wins:
  224. source_origin_wins[source_origin_win] = source_win_prob_dict.random()
  225. new_win = source_origin_wins[source_origin_win]
  226. tcp_pkt.setfieldval("window", new_win)
  227. ## MSS
  228. tcp_options = tcp_pkt.getfieldval("options")
  229. if tcp_options:
  230. if tcp_options[0][0] == "MSS":
  231. tcp_options[0] = ("MSS", mss_value)
  232. tcp_pkt.setfieldval("options", tcp_options)
  233. new_pkt = (eth_frame / ip_pkt / tcp_pkt)
  234. new_pkt.time = timestamp_next_pkt
  235. pps = max(get_interval_pps(complement_interval_pps, timestamp_next_pkt), 10)
  236. timestamp_next_pkt = update_timestamp(timestamp_next_pkt, pps) + inter_arrival_times[pkt_num] #float(timeSteps.random())
  237. # Reply
  238. else:
  239. # Ether
  240. eth_frame.setfieldval("src", mac_destination)
  241. eth_frame.setfieldval("dst", mac_source)
  242. # IP
  243. ip_pkt.setfieldval("src", ip_destination)
  244. ip_pkt.setfieldval("dst", ip_source)
  245. ip_pkt.setfieldval("ttl", destination_ttl_value)
  246. # TCP
  247. tcp_pkt.setfieldval("dport", port_source)
  248. tcp_pkt.setfieldval("sport", port_destination)
  249. ## Window Size
  250. destination_origin_win = tcp_pkt.getfieldval("window")
  251. if destination_origin_win not in destination_origin_wins:
  252. destination_origin_wins[destination_origin_win] = destination_win_prob_dict.random()
  253. new_win = destination_origin_wins[destination_origin_win]
  254. tcp_pkt.setfieldval("window", new_win)
  255. ## MSS
  256. tcp_options = tcp_pkt.getfieldval("options")
  257. if tcp_options:
  258. if tcp_options[0][0] == "MSS":
  259. tcp_options[0] = ("MSS", mss_value)
  260. tcp_pkt.setfieldval("options", tcp_options)
  261. new_pkt = (eth_frame / ip_pkt / tcp_pkt)
  262. pps = max(get_interval_pps(complement_interval_pps, timestamp_next_pkt), 10)
  263. timestamp_next_pkt = update_timestamp(timestamp_next_pkt, pps) + inter_arrival_times[pkt_num]#float(timeSteps.random())
  264. new_pkt.time = timestamp_next_pkt
  265. packets.append(new_pkt)
  266. else: # Last conversation where the victim start a connection with the attacker
  267. timestamp_next_pkt = packets[-1].time + uniform(0.001, 0.01)
  268. port_source = randint(self.minDefaultPort,self.maxDefaultPort)
  269. for pkt_num, pkt in enumerate(conv_pkts):
  270. eth_frame = Ether(pkt[0])
  271. ip_pkt = eth_frame.payload
  272. tcp_pkt = ip_pkt.payload
  273. # Request
  274. if tcp_pkt.getfieldval("dport") == self.last_conn_dst_port:
  275. # Ether
  276. eth_frame.setfieldval("src", mac_destination)
  277. eth_frame.setfieldval("dst", mac_source)
  278. # IP
  279. ip_pkt.setfieldval("src", ip_destination)
  280. ip_pkt.setfieldval("dst", ip_source)
  281. ip_pkt.setfieldval("ttl", destination_ttl_value)
  282. # TCP
  283. tcp_pkt.setfieldval("sport", port_source)
  284. # destination port is fixed 4444
  285. ## Window Size
  286. destination_origin_win = tcp_pkt.getfieldval("window")
  287. if destination_origin_win not in destination_origin_wins:
  288. destination_origin_wins[destination_origin_win] = destination_win_prob_dict.random()
  289. new_win = destination_origin_wins[destination_origin_win]
  290. tcp_pkt.setfieldval("window", new_win)
  291. ## MSS
  292. tcp_options = tcp_pkt.getfieldval("options")
  293. if tcp_options:
  294. if tcp_options[0][0] == "MSS":
  295. tcp_options[0] = ("MSS", mss_value)
  296. tcp_pkt.setfieldval("options", tcp_options)
  297. new_pkt = (eth_frame / ip_pkt / tcp_pkt)
  298. new_pkt.time = timestamp_next_pkt
  299. pps = max(get_interval_pps(complement_interval_pps, timestamp_next_pkt), 10)
  300. timestamp_next_pkt = update_timestamp(timestamp_next_pkt, pps) + inter_arrival_times[pkt_num]# float(timeSteps.random())
  301. # Reply
  302. else:
  303. # Ether
  304. eth_frame.setfieldval("src", mac_source)
  305. eth_frame.setfieldval("dst", mac_destination)
  306. # IP
  307. ip_pkt.setfieldval("src", ip_source)
  308. ip_pkt.setfieldval("dst", ip_destination)
  309. ip_pkt.setfieldval("ttl", source_ttl_value)
  310. # TCP
  311. tcp_pkt.setfieldval("dport", port_source)
  312. # source port is fixed 4444
  313. ## Window Size
  314. source_origin_win = tcp_pkt.getfieldval("window")
  315. if source_origin_win not in source_origin_wins:
  316. source_origin_wins[source_origin_win] = source_win_prob_dict.random()
  317. new_win = source_origin_wins[source_origin_win]
  318. tcp_pkt.setfieldval("window", new_win)
  319. ## MSS
  320. tcp_options = tcp_pkt.getfieldval("options")
  321. if tcp_options:
  322. if tcp_options[0][0] == "MSS":
  323. tcp_options[0] = ("MSS", mss_value)
  324. tcp_pkt.setfieldval("options", tcp_options)
  325. new_pkt = (eth_frame / ip_pkt / tcp_pkt)
  326. pps = max(get_interval_pps(complement_interval_pps, timestamp_next_pkt), 10)
  327. timestamp_next_pkt = update_timestamp(timestamp_next_pkt, pps) + inter_arrival_times[pkt_num]# float(timeSteps.random())
  328. new_pkt.time = timestamp_next_pkt
  329. packets.append(new_pkt)
  330. # Store timestamp of first packet (for attack label)
  331. self.attack_start_utime = packets[0].time
  332. self.attack_end_utime = packets[-1].time
  333. if len(packets) > 0:
  334. packets = sorted(packets, key=lambda pkt: pkt.time)
  335. path_attack_pcap = self.write_attack_pcap(packets, True, path_attack_pcap)
  336. # return packets sorted by packet time_sec_start
  337. # pkt_num+1: because pkt_num starts at 0
  338. return pkt_num + 1, path_attack_pcap