SmbScanAttack.py 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484
  1. import logging
  2. from random import shuffle, randint, choice, uniform
  3. from lea import Lea
  4. from Attack import BaseAttack
  5. from Attack.AttackParameters import Parameter as Param
  6. from Attack.AttackParameters import ParameterTypes
  7. from ID2TLib.smb2 import *
  8. logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
  9. # noinspection PyPep8
  10. from scapy.layers.inet import IP, Ether, TCP
  11. from scapy.layers.smb import *
  12. from scapy.layers.netbios import *
  13. class SmbScanAttack(BaseAttack.BaseAttack):
  14. platforms = {"win7", "win10", "winxp", "win8.1", "macos", "linux", "win8", "winvista", "winnt", "win2000"}
  15. # SMB port
  16. smb_port = 445
  17. # SMB versions
  18. smb_versions = {"1", "2.0", "2.1", "3.0", "3.0.2", "3.1.1"}
  19. smb_versions_per_win = {'win7': "2.1", 'win10': "3.1.1", 'winxp': "1", 'win8.1': "3.0.2", 'win8': "3.0",
  20. 'winvista': "2.0", 'winnt': "1", "win2000": "1"}
  21. smb_versions_per_samba = {'3.6': "2.0", '4.0': "2.1", '4.1': "3.0", '4.3': "3.1.1"}
  22. # SMB dialects
  23. smb_dialects = ["PC NETWORK PROGRAM 1.0", "LANMAN1.0", "Windows for Workgroups 3.1a", "LM1.2X002", "LANMAN2.1",
  24. "NT LM 0.12", "SMB 2.002", "SMB 2.???"]
  25. def __init__(self):
  26. """
  27. Creates a new instance of the SmbScanAttack.
  28. """
  29. # Initialize attack
  30. super(SmbScanAttack, self).__init__("SmbScan Attack", "Injects an SMB scan",
  31. "Scanning/Probing")
  32. # Define allowed parameters and their type
  33. self.supported_params = {
  34. Param.IP_SOURCE: ParameterTypes.TYPE_IP_ADDRESS,
  35. Param.IP_DESTINATION: ParameterTypes.TYPE_IP_ADDRESS,
  36. Param.PORT_SOURCE: ParameterTypes.TYPE_PORT,
  37. Param.MAC_SOURCE: ParameterTypes.TYPE_MAC_ADDRESS,
  38. Param.MAC_DESTINATION: ParameterTypes.TYPE_MAC_ADDRESS,
  39. Param.INJECT_AT_TIMESTAMP: ParameterTypes.TYPE_FLOAT,
  40. Param.INJECT_AFTER_PACKET: ParameterTypes.TYPE_PACKET_POSITION,
  41. Param.IP_SOURCE_RANDOMIZE: ParameterTypes.TYPE_BOOLEAN,
  42. Param.PACKETS_PER_SECOND: ParameterTypes.TYPE_FLOAT,
  43. Param.PORT_SOURCE_RANDOMIZE: ParameterTypes.TYPE_BOOLEAN,
  44. Param.HOSTING_IP: ParameterTypes.TYPE_IP_ADDRESS,
  45. Param.HOSTING_VERSION: ParameterTypes.TYPE_STRING,
  46. Param.SOURCE_PLATFORM: ParameterTypes.TYPE_STRING,
  47. Param.PROTOCOL_VERSION: ParameterTypes.TYPE_STRING,
  48. Param.IP_DESTINATION_END: ParameterTypes.TYPE_IP_ADDRESS
  49. }
  50. def init_params(self):
  51. """
  52. Initialize the parameters of this attack using the user supplied command line parameters.
  53. Use the provided statistics to calculate default parameters and to process user
  54. supplied queries.
  55. :param statistics: Reference to a statistics object.
  56. """
  57. # PARAMETERS: initialize with default values
  58. # (values are overwritten if user specifies them)
  59. most_used_ip_address = self.statistics.get_most_used_ip_address()
  60. if isinstance(most_used_ip_address, list):
  61. most_used_ip_address = most_used_ip_address[0]
  62. self.add_param_value(Param.IP_SOURCE, most_used_ip_address)
  63. self.add_param_value(Param.IP_SOURCE_RANDOMIZE, 'False')
  64. self.add_param_value(Param.MAC_SOURCE, self.statistics.get_mac_address(most_used_ip_address))
  65. all_ips = self.statistics.get_ip_addresses()
  66. if not isinstance(all_ips, list):
  67. ip_destinations = []
  68. ip_destinations.append(all_ips)
  69. else:
  70. ip_destinations = all_ips
  71. self.add_param_value(Param.IP_DESTINATION, ip_destinations)
  72. # FIXME: MAYBE REMOVE/CHANGE THIS MAC STUFF
  73. destination_mac = []
  74. for ip in ip_destinations:
  75. destination_mac.append(self.statistics.get_mac_address(str(ip)))
  76. if isinstance(destination_mac, list) and len(destination_mac) == 0:
  77. destination_mac = self.generate_random_mac_address()
  78. self.add_param_value(Param.MAC_DESTINATION, destination_mac)
  79. self.add_param_value(Param.PORT_SOURCE, randint(1024, 65535))
  80. self.add_param_value(Param.PORT_SOURCE_RANDOMIZE, 'True')
  81. self.add_param_value(Param.PACKETS_PER_SECOND,
  82. (self.statistics.get_pps_sent(most_used_ip_address) +
  83. self.statistics.get_pps_received(most_used_ip_address)) / 2)
  84. self.add_param_value(Param.INJECT_AFTER_PACKET, randint(0, self.statistics.get_packet_count()))
  85. rnd_ip_count = self.statistics.get_ip_address_count()/2
  86. self.add_param_value(Param.HOSTING_IP, self.statistics.get_random_ip_address(rnd_ip_count))
  87. self.add_param_value(Param.HOSTING_VERSION, self.get_rnd_smb_version())
  88. self.add_param_value(Param.SOURCE_PLATFORM, self.get_rnd_os())
  89. self.add_param_value(Param.PROTOCOL_VERSION, "1")
  90. self.add_param_value(Param.IP_DESTINATION_END, "0.0.0.0")
  91. def get_rnd_os(self):
  92. os_dist = Lea.fromValFreqsDict({"win7": 48.43, "win10": 27.99, "winxp": 6.07, "win8.1": 6.07, "macos": 5.94,
  93. "linux": 3.38, "win8": 1.35, "winvista": 0.46, "winnt": 0.31})
  94. return os_dist.random()
  95. def get_rnd_smb_version(self):
  96. os = self.get_rnd_os()
  97. if os is "linux":
  98. return random.choice(list(self.smb_versions_per_samba.values()))
  99. elif os is "macos":
  100. # TODO: figure out macOS smb version(s)
  101. return random.choice(list(self.smb_versions))
  102. else:
  103. return self.smb_versions_per_win[os]
  104. @property
  105. def generate_attack_pcap(self):
  106. def update_timestamp(timestamp, pps, delay=0):
  107. """
  108. Calculates the next timestamp to be used based on the packet per second rate (pps) and the maximum delay.
  109. :return: Timestamp to be used for the next packet.
  110. """
  111. if delay == 0:
  112. # Calculate request timestamp
  113. # To imitate the bursty behavior of traffic
  114. randomdelay = Lea.fromValFreqsDict({1 / pps: 70, 2 / pps: 20, 5 / pps: 7, 10 / pps: 3})
  115. return timestamp + uniform(1/pps , randomdelay.random())
  116. else:
  117. # Calculate reply timestamp
  118. randomdelay = Lea.fromValFreqsDict({2*delay: 70, 3*delay: 20, 5*delay: 7, 10*delay: 3})
  119. return timestamp + uniform(1 / pps + delay, 1 / pps + randomdelay.random())
  120. def getIntervalPPS(complement_interval_pps, timestamp):
  121. """
  122. Gets the packet rate (pps) for a specific time interval.
  123. :param complement_interval_pps: an array of tuples (the last timestamp in the interval, the packet rate in the crresponding interval).
  124. :param timestamp: the timestamp at which the packet rate is required.
  125. :return: the corresponding packet rate (pps) .
  126. """
  127. for row in complement_interval_pps:
  128. if timestamp<=row[0]:
  129. return row[1]
  130. return complement_interval_pps[-1][1] # in case the timstamp > capture max timestamp
  131. def getIpData(ip_address: str):
  132. """
  133. :param ip_address: the ip of which (packet-)data shall be returned
  134. :return: MSS, TTL and Window Size values of the given IP
  135. """
  136. # Set MSS (Maximum Segment Size) based on MSS distribution of IP address
  137. mss_dist = self.statistics.get_mss_distribution(ip_address)
  138. if len(mss_dist) > 0:
  139. mss_prob_dict = Lea.fromValFreqsDict(mss_dist)
  140. mss_value = mss_prob_dict.random()
  141. else:
  142. mss_value = self.statistics.process_db_query("most_used(mssValue)")
  143. # Set TTL based on TTL distribution of IP address
  144. ttl_dist = self.statistics.get_ttl_distribution(ip_address)
  145. if len(ttl_dist) > 0:
  146. ttl_prob_dict = Lea.fromValFreqsDict(ttl_dist)
  147. ttl_value = ttl_prob_dict.random()
  148. else:
  149. ttl_value = self.statistics.process_db_query("most_used(ttlValue)")
  150. # Set Window Size based on Window Size distribution of IP address
  151. win_dist = self.statistics.get_win_distribution(ip_address)
  152. if len(win_dist) > 0:
  153. win_prob_dict = Lea.fromValFreqsDict(win_dist)
  154. win_value = win_prob_dict.random()
  155. else:
  156. win_value = self.statistics.process_db_query("most_used(winSize)")
  157. return mss_value, ttl_value, win_value
  158. def getIpRange(start_ip: str, end_ip: str):
  159. start = ipaddress.ip_address(start_ip)
  160. end = ipaddress.ip_address(end_ip)
  161. ips = []
  162. if start < end:
  163. while start <= end:
  164. ips.append(start.exploded)
  165. start = start+1
  166. elif start > end:
  167. while start >= end:
  168. ips.append(start.exploded)
  169. start = start-1
  170. else:
  171. ips.append(start_ip)
  172. return ips
  173. pps = self.get_param_value(Param.PACKETS_PER_SECOND)
  174. # Calculate complement packet rates of the background traffic for each interval
  175. complement_interval_pps = self.statistics.calculate_complement_packet_rates(pps)
  176. # Timestamp
  177. timestamp_next_pkt = self.get_param_value(Param.INJECT_AT_TIMESTAMP)
  178. # store start time of attack
  179. self.attack_start_utime = timestamp_next_pkt
  180. timestamp_prv_reply, timestamp_confirm = 0,0
  181. # Initialize parameters
  182. ip_source = self.get_param_value(Param.IP_SOURCE)
  183. ip_destinations = self.get_param_value(Param.IP_DESTINATION)
  184. hosting_ip = self.get_param_value(Param.HOSTING_IP)
  185. ip_range_end = self.get_param_value(Param.IP_DESTINATION_END)
  186. mac_source = self.get_param_value(Param.MAC_SOURCE)
  187. mac_dest = self.get_param_value(Param.MAC_DESTINATION)
  188. # Check smb version
  189. def invalid_verison(version: str):
  190. print("\nInvalid smb version: " + version +
  191. "\nPlease select one of the following versions: 1, 2.0, 2.1, 3.0, 3.0.2, 3.1.1")
  192. # FIXME: useful error code
  193. exit(-1)
  194. smb_version = self.get_param_value(Param.PROTOCOL_VERSION)
  195. if smb_version not in self.smb_versions:
  196. invalid_verison(smb_version)
  197. hosting_version = self.get_param_value(Param.HOSTING_VERSION)
  198. if hosting_version not in self.smb_versions:
  199. invalid_verison(hosting_version)
  200. # Check source platform
  201. src_platform = self.get_param_value(Param.SOURCE_PLATFORM).lower()
  202. if src_platform not in self.platforms:
  203. print("\nInvalid source platform: " + src_platform + ". Selecting random platform as source platform.")
  204. src_platform = self.get_rnd_os()
  205. packets = []
  206. # randomize source ports according to platform, if specified
  207. if self.get_param_value(Param.PORT_SOURCE_RANDOMIZE):
  208. if src_platform in {"winnt", "winxp", "win2000"}:
  209. sport = randint(1024, 5000)
  210. elif src_platform == "linux":
  211. sport = randint(32768, 61000)
  212. else:
  213. sport = randint(49152, 65535)
  214. else:
  215. sport = self.get_param_value(Param.PORT_SOURCE)
  216. # No destination IP was specified, but a destination MAC was specified, generate IP that fits MAC
  217. if isinstance(ip_destinations, list) and isinstance(mac_dest, str):
  218. ip_destinations = self.statistics.get_ip_address_from_mac(mac_dest)
  219. if len(ip_destinations) == 0:
  220. ip_destinations = self.generate_random_ipv4_address("Unknown", 1)
  221. # Check ip.src == ip.dst
  222. self.ip_src_dst_equal_check(ip_source, ip_destinations)
  223. ip_dests = []
  224. if isinstance(ip_destinations, list):
  225. ip_dests = ip_destinations
  226. else:
  227. ip_dests.append(ip_destinations)
  228. # Generate IPs of destination IP range, if specified
  229. if ip_range_end != "0.0.0.0":
  230. ip_dests = getIpRange(ip_dests[0], ip_range_end)
  231. shuffle(ip_dests)
  232. # Randomize source IP, if specified
  233. if self.get_param_value(Param.IP_SOURCE_RANDOMIZE):
  234. ip_source = self.generate_random_ipv4_address("Unknown", 1)
  235. while ip_source in ip_dests:
  236. ip_source = self.generate_random_ipv4_address("Unknown", 1)
  237. mac_source = self.statistics.get_mac_address(str(ip_source))
  238. if len(mac_source) == 0:
  239. mac_source = self.generate_random_mac_address()
  240. # Get MSS, TTL and Window size value for source IP
  241. source_mss_value, source_ttl_value, source_win_value = getIpData(ip_source)
  242. for ip in ip_dests:
  243. if ip != ip_source:
  244. # Get destination Mac Address
  245. mac_destination = self.statistics.get_mac_address(str(ip))
  246. if len(mac_destination) == 0:
  247. if isinstance(mac_dest, str):
  248. if len(self.statistics.get_ip_address_from_mac(mac_dest)) != 0:
  249. ip = self.statistics.get_ip_address_from_mac(mac_dest)
  250. self.ip_src_dst_equal_check(ip_source, ip)
  251. mac_destination = mac_dest
  252. else:
  253. mac_destination = self.generate_random_mac_address()
  254. # Get MSS, TTL and Window size value for destination IP
  255. destination_mss_value, destination_ttl_value, destination_win_value = getIpData(ip)
  256. minDelay, maxDelay = self.get_reply_delay(ip)
  257. # New connection, new random TCP sequence numbers
  258. attacker_seq = randint(1000, 50000)
  259. victim_seq = randint(1000, 50000)
  260. # Randomize source port for each connection if specified
  261. if self.get_param_value(Param.PORT_SOURCE_RANDOMIZE):
  262. if src_platform == "linux":
  263. sport = randint(32768, 61000)
  264. else:
  265. sport = sport+1
  266. # 1) Build request package
  267. request_ether = Ether(src=mac_source, dst=mac_destination)
  268. request_ip = IP(src=ip_source, dst=ip, ttl=source_ttl_value, flags='DF')
  269. request_tcp = TCP(sport=sport, dport=self.smb_port, window=source_win_value, flags='S',
  270. seq=attacker_seq, options=[('MSS', source_mss_value)])
  271. attacker_seq += 1
  272. request = (request_ether / request_ip / request_tcp)
  273. request.time = timestamp_next_pkt
  274. # Append request
  275. packets.append(request)
  276. # Update timestamp for next package
  277. timestamp_reply = update_timestamp(timestamp_next_pkt, pps, minDelay)
  278. while (timestamp_reply <= timestamp_prv_reply):
  279. timestamp_reply = update_timestamp(timestamp_prv_reply, pps, minDelay)
  280. timestamp_prv_reply = timestamp_reply
  281. if ip in hosting_ip:
  282. # 2) Build TCP packages for ip that hosts SMB
  283. # destination sends SYN, ACK
  284. reply_ether = Ether(src=mac_destination, dst=mac_source)
  285. reply_ip = IP(src=ip, dst=ip_source, ttl=destination_ttl_value, flags='DF')
  286. reply_tcp = TCP(sport=self.smb_port, dport=sport, seq=victim_seq, ack=attacker_seq, flags='SA',
  287. window=destination_win_value,
  288. options=[('MSS', destination_mss_value)])
  289. victim_seq += 1
  290. reply = (reply_ether / reply_ip / reply_tcp)
  291. reply.time = timestamp_reply
  292. packets.append(reply)
  293. # requester confirms, ACK
  294. confirm_ether = request_ether
  295. confirm_ip = request_ip
  296. confirm_tcp = TCP(sport=sport, dport=self.smb_port, seq=attacker_seq, ack=victim_seq,
  297. window=source_win_value, flags='A')
  298. confirm = (confirm_ether / confirm_ip / confirm_tcp)
  299. timestamp_confirm = update_timestamp(timestamp_reply, pps, minDelay)
  300. confirm.time = timestamp_confirm
  301. packets.append(confirm)
  302. # INSERT SMB-REQUEST PACKAGE HERE
  303. # FIXME: CHECK FOR PROTOCOL VERSION?
  304. smb_MID = randint(1, 65535)
  305. smb_PID = randint(1, 65535)
  306. smb_req_tail_arr = []
  307. smb_req_tail_size = 0
  308. # select dialects based on smb version
  309. if smb_version is "1":
  310. smb_req_dialects = self.smb_dialects[0:6]
  311. else:
  312. smb_req_dialects = self.smb_dialects
  313. if len(smb_req_dialects) == 0:
  314. smb_req_tail_arr.append(SMBNegociate_Protocol_Request_Tail())
  315. smb_req_tail_size = len(SMBNegociate_Protocol_Request_Tail())
  316. else:
  317. for dia in smb_req_dialects:
  318. smb_req_tail_arr.append(SMBNegociate_Protocol_Request_Tail(BufferData = dia))
  319. smb_req_tail_size += len(SMBNegociate_Protocol_Request_Tail(BufferData = dia))
  320. smb_req_head = SMBNegociate_Protocol_Request_Header(Flags2=0x2801, PID=smb_PID, MID=smb_MID,
  321. ByteCount=smb_req_tail_size)
  322. smb_req_length = len(smb_req_head) + smb_req_tail_size
  323. smb_req_net_bio = NBTSession(TYPE=0x00, LENGTH=smb_req_length)
  324. smb_req_tcp = TCP(sport=sport, dport=self.smb_port, flags='PA', seq=attacker_seq, ack=victim_seq)
  325. smb_req_ip = IP(src=ip_source, dst=ip, ttl=source_ttl_value)
  326. smb_req_ether = Ether(src=mac_source, dst=mac_destination)
  327. attacker_seq += len(smb_req_net_bio) + len(smb_req_head) + smb_req_tail_size
  328. smb_req_combined = (smb_req_ether / smb_req_ip / smb_req_tcp / smb_req_net_bio / smb_req_head)
  329. for i in range(0 , len(smb_req_tail_arr)):
  330. smb_req_combined = smb_req_combined / smb_req_tail_arr[i]
  331. timestamp_smb_req = update_timestamp(timestamp_confirm, pps, minDelay)
  332. smb_req_combined.time = timestamp_smb_req
  333. packets.append(smb_req_combined)
  334. # destination confirms SMB request package
  335. reply_tcp = TCP(sport=self.smb_port, dport=sport, seq=victim_seq, ack=attacker_seq,
  336. window=destination_win_value, flags='A')
  337. confirm_smb_req = (reply_ether / reply_ip / reply_tcp)
  338. timestamp_reply = update_timestamp(timestamp_smb_req, pps, minDelay)
  339. confirm_smb_req.time = timestamp_reply
  340. packets.append(confirm_smb_req)
  341. # smb response package
  342. if smb_version is not "1" and hosting_version is not "1":
  343. smb_rsp_paket = SMB2_SYNC_Header(Flags = 1)
  344. smb_rsp_negotiate_body = SMB2_Negotiate_Protocol_Response(DialectRevision=0x02ff)
  345. smb_rsp_length = len(smb_rsp_paket) + len(smb_rsp_negotiate_body)
  346. else:
  347. smb_rsp_paket = SMBNegociate_Protocol_Response_No_Security_No_Key(Start="\xffSMB" , PID=smb_PID,
  348. MID=smb_MID, DialectIndex=5)
  349. smb_rsp_length = len(smb_rsp_paket)
  350. smb_rsp_net_bio = NBTSession(TYPE=0x00, LENGTH=smb_rsp_length)
  351. smb_rsp_tcp = TCP(sport=self.smb_port, dport=sport, flags='PA', seq=victim_seq, ack=attacker_seq)
  352. smb_rsp_ip = IP(src=ip, dst=ip_source, ttl=destination_ttl_value)
  353. smb_rsp_ether = Ether(src=mac_destination, dst=mac_source)
  354. victim_seq += len(smb_rsp_net_bio) + len(smb_rsp_paket)
  355. if smb_version is not "1"and hosting_version is not "1":
  356. victim_seq += len(smb_rsp_negotiate_body)
  357. smb_rsp_combined = (smb_rsp_ether / smb_rsp_ip / smb_rsp_tcp / smb_rsp_net_bio / smb_rsp_paket)
  358. if smb_version is not "1"and hosting_version is not "1":
  359. smb_rsp_combined = (smb_rsp_combined / smb_rsp_negotiate_body)
  360. timestamp_smb_rsp = update_timestamp(timestamp_reply, pps, minDelay)
  361. smb_rsp_combined.time = timestamp_smb_rsp
  362. packets.append(smb_rsp_combined)
  363. # source confirms SMB response package
  364. confirm_tcp = TCP(sport=sport, dport=self.smb_port, seq=attacker_seq, ack=victim_seq,
  365. window=source_win_value, flags='A')
  366. confirm_smb_res = (confirm_ether / confirm_ip / confirm_tcp)
  367. timestamp_confirm = update_timestamp(timestamp_smb_rsp, pps, minDelay)
  368. confirm_smb_res.time = timestamp_confirm
  369. packets.append(confirm_smb_res)
  370. # attacker sends FIN ACK
  371. confirm_tcp = TCP(sport=sport, dport=self.smb_port, seq=attacker_seq, ack=victim_seq,
  372. window=source_win_value, flags='FA')
  373. source_fin_ack = (confirm_ether / confirm_ip / confirm_tcp)
  374. timestamp_src_fin_ack = update_timestamp(timestamp_confirm, pps, minDelay)
  375. source_fin_ack.time = timestamp_src_fin_ack
  376. attacker_seq += 1
  377. packets.append(source_fin_ack)
  378. # victim sends FIN ACK
  379. reply_tcp = TCP(sport=self.smb_port, dport=sport, seq=victim_seq, ack=attacker_seq,
  380. window=destination_win_value, flags='FA')
  381. destination_fin_ack = (reply_ether / reply_ip / reply_tcp)
  382. timestamp_dest_fin_ack = update_timestamp(timestamp_src_fin_ack, pps, minDelay)
  383. victim_seq += 1
  384. destination_fin_ack.time = timestamp_dest_fin_ack
  385. packets.append(destination_fin_ack)
  386. # source sends final ACK
  387. confirm_tcp = TCP(sport=sport, dport=self.smb_port, seq=attacker_seq, ack=victim_seq,
  388. window=source_win_value, flags='A')
  389. final_ack = (confirm_ether / confirm_ip / confirm_tcp)
  390. timestamp_final_ack = update_timestamp(timestamp_dest_fin_ack, pps, minDelay)
  391. final_ack.time = timestamp_final_ack
  392. packets.append(final_ack)
  393. else:
  394. # Build RST package
  395. reply_ether = Ether(src=mac_destination, dst=mac_source)
  396. reply_ip = IP(src=ip, dst=ip_source, ttl=destination_ttl_value, flags='DF')
  397. reply_tcp = TCP(sport=self.smb_port, dport=sport, seq=0, ack=attacker_seq, flags='RA',
  398. window=destination_win_value, options=[('MSS', destination_mss_value)])
  399. reply = (reply_ether / reply_ip / reply_tcp)
  400. reply.time = timestamp_reply
  401. packets.append(reply)
  402. pps = max(getIntervalPPS(complement_interval_pps, timestamp_next_pkt), 10)
  403. timestamp_next_pkt = update_timestamp(timestamp_next_pkt, pps)
  404. # store end time of attack
  405. self.attack_end_utime = packets[-1].time
  406. # write attack packets to pcap
  407. pcap_path = self.write_attack_pcap(sorted(packets, key=lambda pkt: pkt.time))
  408. # return packets sorted by packet time_sec_start
  409. return len(packets), pcap_path