SMBScanAttack.py 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522
  1. import logging
  2. from os import urandom
  3. from binascii import b2a_hex
  4. from random import shuffle, randint, choice, uniform
  5. from lea import Lea
  6. from Attack import BaseAttack
  7. from Attack.AttackParameters import Parameter as Param
  8. from Attack.AttackParameters import ParameterTypes
  9. from ID2TLib.SMB2 import *
  10. from ID2TLib.Utility import *
  11. logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
  12. # noinspection PyPep8
  13. from scapy.layers.inet import IP, Ether, TCP
  14. from scapy.layers.smb import *
  15. from scapy.layers.netbios import *
  16. class SMBScanAttack(BaseAttack.BaseAttack):
  17. # SMB port
  18. smb_port = 445
  19. # SMB versions
  20. smb_versions = {"1", "2.0", "2.1", "3.0", "3.0.2", "3.1.1"}
  21. smb_versions_per_win = {'win7': "2.1", 'win10': "3.1.1", 'winxp': "1", 'win8.1': "3.0.2", 'win8': "3.0",
  22. 'winvista': "2.0", 'winnt': "1", "win2000": "1"}
  23. smb_versions_per_samba = {'3.6': "2.0", '4.0': "2.1", '4.1': "3.0", '4.3': "3.1.1"}
  24. # SMB dialects
  25. smb_dialects = ["PC NETWORK PROGRAM 1.0", "LANMAN1.0", "Windows for Workgroups 3.1a", "LM1.2X002", "LANMAN2.1",
  26. "NT LM 0.12", "SMB 2.002", "SMB 2.???"]
  27. # SMB security blobs
  28. security_blob_windows = "\x60\x82\x01\x3c\x06\x06\x2b\x06\x01\x05\x05\x02\xa0\x82\x01\x30" \
  29. "\x30\x82\x01\x2c\xa0\x1a\x30\x18\x06\x0a\x2b\x06\x01\x04\x01\x82" \
  30. "\x37\x02\x02\x1e\x06\x0a\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a" \
  31. "\xa2\x82\x01\x0c\x04\x82\x01\x08\x4e\x45\x47\x4f\x45\x58\x54\x53" \
  32. "\x01\x00\x00\x00\x00\x00\x00\x00\x60\x00\x00\x00\x70\x00\x00\x00" \
  33. "\xbc\x84\x03\x97\x6f\x80\x3b\x81\xa6\x45\x1b\x05\x92\x39\xde\x3d" \
  34. "\xd6\x91\x85\x49\x8a\xd0\x3b\x58\x87\x99\xb4\x98\xdf\xa6\x1d\x73" \
  35. "\x3b\x57\xbf\x05\x63\x5e\x30\xea\xa8\xd8\xd8\x45\xba\x80\x52\xa5" \
  36. "\x00\x00\x00\x00\x00\x00\x00\x00\x60\x00\x00\x00\x01\x00\x00\x00" \
  37. "\x00\x00\x00\x00\x00\x00\x00\x00\x5c\x33\x53\x0d\xea\xf9\x0d\x4d" \
  38. "\xb2\xec\x4a\xe3\x78\x6e\xc3\x08\x4e\x45\x47\x4f\x45\x58\x54\x53" \
  39. "\x03\x00\x00\x00\x01\x00\x00\x00\x40\x00\x00\x00\x98\x00\x00\x00" \
  40. "\xbc\x84\x03\x97\x6f\x80\x3b\x81\xa6\x45\x1b\x05\x92\x39\xde\x3d" \
  41. "\x5c\x33\x53\x0d\xea\xf9\x0d\x4d\xb2\xec\x4a\xe3\x78\x6e\xc3\x08" \
  42. "\x40\x00\x00\x00\x58\x00\x00\x00\x30\x56\xa0\x54\x30\x52\x30\x27" \
  43. "\x80\x25\x30\x23\x31\x21\x30\x1f\x06\x03\x55\x04\x03\x13\x18\x54" \
  44. "\x6f\x6b\x65\x6e\x20\x53\x69\x67\x6e\x69\x6e\x67\x20\x50\x75\x62" \
  45. "\x6c\x69\x63\x20\x4b\x65\x79\x30\x27\x80\x25\x30\x23\x31\x21\x30" \
  46. "\x1f\x06\x03\x55\x04\x03\x13\x18\x54\x6f\x6b\x65\x6e\x20\x53\x69" \
  47. "\x67\x6e\x69\x6e\x67\x20\x50\x75\x62\x6c\x69\x63\x20\x4b\x65\x79"
  48. security_blob_ubuntu = "\x60\x48\x06\x06\x2b\x06\x01\x05\x05\x02\xa0\x3e\x30\x3c\xa0\x0e" \
  49. "\x30\x0c\x06\x0a\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a\xa3\x2a" \
  50. "\x30\x28\xa0\x26\x1b\x24\x6e\x6f\x74\x5f\x64\x65\x66\x69\x6e\x65" \
  51. "\x64\x5f\x69\x6e\x5f\x52\x46\x43\x34\x31\x37\x38\x40\x70\x6c\x65" \
  52. "\x61\x73\x65\x5f\x69\x67\x6e\x6f\x72\x65"
  53. security_blob_macos = "\x60\x7e\x06\x06\x2b\x06\x01\x05\x05\x02\xa0\x74\x30\x72\xa0\x44" \
  54. "\x30\x42\x06\x09\x2a\x86\x48\x82\xf7\x12\x01\x02\x02\x06\x09\x2a" \
  55. "\x86\x48\x86\xf7\x12\x01\x02\x02\x06\x06\x2a\x85\x70\x2b\x0e\x03" \
  56. "\x06\x06\x2b\x06\x01\x05\x05\x0e\x06\x0a\x2b\x06\x01\x04\x01\x82" \
  57. "\x37\x02\x02\x0a\x06\x06\x2b\x05\x01\x05\x02\x07\x06\x06\x2b\x06" \
  58. "\x01\x05\x02\x05\xa3\x2a\x30\x28\xa0\x26\x1b\x24\x6e\x6f\x74\x5f" \
  59. "\x64\x65\x66\x69\x6e\x65\x64\x5f\x69\x6e\x5f\x52\x46\x43\x34\x31" \
  60. "\x37\x38\x40\x70\x6c\x65\x61\x73\x65\x5f\x69\x67\x6e\x6f\x72\x65"
  61. def __init__(self):
  62. """
  63. Creates a new instance of the SMBScanAttack.
  64. """
  65. # Initialize attack
  66. super(SMBScanAttack, self).__init__("SmbScan Attack", "Injects an SMB scan",
  67. "Scanning/Probing")
  68. # Define allowed parameters and their type
  69. self.supported_params = {
  70. Param.IP_SOURCE: ParameterTypes.TYPE_IP_ADDRESS,
  71. Param.IP_DESTINATION: ParameterTypes.TYPE_IP_ADDRESS,
  72. Param.PORT_SOURCE: ParameterTypes.TYPE_PORT,
  73. Param.MAC_SOURCE: ParameterTypes.TYPE_MAC_ADDRESS,
  74. Param.MAC_DESTINATION: ParameterTypes.TYPE_MAC_ADDRESS,
  75. Param.INJECT_AT_TIMESTAMP: ParameterTypes.TYPE_FLOAT,
  76. Param.INJECT_AFTER_PACKET: ParameterTypes.TYPE_PACKET_POSITION,
  77. Param.IP_SOURCE_RANDOMIZE: ParameterTypes.TYPE_BOOLEAN,
  78. Param.PACKETS_PER_SECOND: ParameterTypes.TYPE_FLOAT,
  79. Param.PORT_SOURCE_RANDOMIZE: ParameterTypes.TYPE_BOOLEAN,
  80. Param.HOSTING_IP: ParameterTypes.TYPE_IP_ADDRESS,
  81. Param.HOSTING_VERSION: ParameterTypes.TYPE_STRING,
  82. Param.SOURCE_PLATFORM: ParameterTypes.TYPE_STRING,
  83. Param.PROTOCOL_VERSION: ParameterTypes.TYPE_STRING,
  84. Param.IP_DESTINATION_END: ParameterTypes.TYPE_IP_ADDRESS
  85. }
  86. def init_params(self):
  87. """
  88. Initialize the parameters of this attack using the user supplied command line parameters.
  89. Use the provided statistics to calculate default parameters and to process user
  90. supplied queries.
  91. :param statistics: Reference to a statistics object.
  92. """
  93. # PARAMETERS: initialize with default values
  94. # (values are overwritten if user specifies them)
  95. most_used_ip_address = self.statistics.get_most_used_ip_address()
  96. if isinstance(most_used_ip_address, list):
  97. most_used_ip_address = most_used_ip_address[0]
  98. self.add_param_value(Param.IP_SOURCE, most_used_ip_address)
  99. self.add_param_value(Param.IP_SOURCE_RANDOMIZE, 'False')
  100. self.add_param_value(Param.MAC_SOURCE, self.statistics.get_mac_address(most_used_ip_address))
  101. all_ips = self.statistics.get_ip_addresses()
  102. if not isinstance(all_ips, list):
  103. ip_destinations = []
  104. ip_destinations.append(all_ips)
  105. else:
  106. ip_destinations = all_ips
  107. self.add_param_value(Param.IP_DESTINATION, ip_destinations)
  108. # FIXME: MAYBE REMOVE/CHANGE THIS MAC STUFF
  109. destination_mac = []
  110. for ip in ip_destinations:
  111. destination_mac.append(self.statistics.get_mac_address(str(ip)))
  112. if isinstance(destination_mac, list) and len(destination_mac) == 0:
  113. destination_mac = self.generate_random_mac_address()
  114. self.add_param_value(Param.MAC_DESTINATION, destination_mac)
  115. self.add_param_value(Param.PORT_SOURCE, randint(1024, 65535))
  116. self.add_param_value(Param.PORT_SOURCE_RANDOMIZE, 'True')
  117. self.add_param_value(Param.PACKETS_PER_SECOND,
  118. (self.statistics.get_pps_sent(most_used_ip_address) +
  119. self.statistics.get_pps_received(most_used_ip_address)) / 2)
  120. self.add_param_value(Param.INJECT_AFTER_PACKET, randint(0, self.statistics.get_packet_count()))
  121. rnd_ip_count = self.statistics.get_ip_address_count()/2
  122. self.add_param_value(Param.HOSTING_IP, self.statistics.get_random_ip_address(rnd_ip_count))
  123. self.host_os = get_rnd_os()
  124. self.add_param_value(Param.HOSTING_VERSION, self.get_smb_version(self.host_os))
  125. self.add_param_value(Param.SOURCE_PLATFORM, get_rnd_os())
  126. self.add_param_value(Param.PROTOCOL_VERSION, "1")
  127. self.add_param_value(Param.IP_DESTINATION_END, "0.0.0.0")
  128. def get_smb_version(self, os: str):
  129. if os is "linux":
  130. return random.choice(list(self.smb_versions_per_samba.values()))
  131. elif os is "macos":
  132. return "2.1"
  133. else:
  134. return self.smb_versions_per_win[os]
  135. def get_rnd_smb_version(self):
  136. os = get_rnd_os()
  137. return self.get_smb_version(os)
  138. def generate_attack_pcap(self):
  139. def update_timestamp(timestamp, pps, delay=0):
  140. """
  141. Calculates the next timestamp to be used based on the packet per second rate (pps) and the maximum delay.
  142. :return: Timestamp to be used for the next packet.
  143. """
  144. if delay == 0:
  145. # Calculate request timestamp
  146. # To imitate the bursty behavior of traffic
  147. randomdelay = Lea.fromValFreqsDict({1 / pps: 70, 2 / pps: 20, 5 / pps: 7, 10 / pps: 3})
  148. return timestamp + uniform(1/pps , randomdelay.random())
  149. else:
  150. # Calculate reply timestamp
  151. randomdelay = Lea.fromValFreqsDict({2*delay: 70, 3*delay: 20, 5*delay: 7, 10*delay: 3})
  152. return timestamp + uniform(1 / pps + delay, 1 / pps + randomdelay.random())
  153. def getIntervalPPS(complement_interval_pps, timestamp):
  154. """
  155. Gets the packet rate (pps) for a specific time interval.
  156. :param complement_interval_pps: an array of tuples (the last timestamp in the interval, the packet rate in the crresponding interval).
  157. :param timestamp: the timestamp at which the packet rate is required.
  158. :return: the corresponding packet rate (pps) .
  159. """
  160. for row in complement_interval_pps:
  161. if timestamp<=row[0]:
  162. return row[1]
  163. return complement_interval_pps[-1][1] # in case the timstamp > capture max timestamp
  164. def get_ip_data(ip_address: str):
  165. """
  166. :param ip_address: the ip of which (packet-)data shall be returned
  167. :return: MSS, TTL and Window Size values of the given IP
  168. """
  169. # Set MSS (Maximum Segment Size) based on MSS distribution of IP address
  170. mss_dist = self.statistics.get_mss_distribution(ip_address)
  171. if len(mss_dist) > 0:
  172. mss_prob_dict = Lea.fromValFreqsDict(mss_dist)
  173. mss_value = mss_prob_dict.random()
  174. else:
  175. mss_value = self.statistics.process_db_query("most_used(mssValue)")
  176. # Set TTL based on TTL distribution of IP address
  177. ttl_dist = self.statistics.get_ttl_distribution(ip_address)
  178. if len(ttl_dist) > 0:
  179. ttl_prob_dict = Lea.fromValFreqsDict(ttl_dist)
  180. ttl_value = ttl_prob_dict.random()
  181. else:
  182. ttl_value = self.statistics.process_db_query("most_used(ttlValue)")
  183. # Set Window Size based on Window Size distribution of IP address
  184. win_dist = self.statistics.get_win_distribution(ip_address)
  185. if len(win_dist) > 0:
  186. win_prob_dict = Lea.fromValFreqsDict(win_dist)
  187. win_value = win_prob_dict.random()
  188. else:
  189. win_value = self.statistics.process_db_query("most_used(winSize)")
  190. return mss_value, ttl_value, win_value
  191. def get_smb_platform_data(platform: str, timestamp=time.time()):
  192. check_platform(platform)
  193. if platform == "linux":
  194. server_Guid = "ubuntu"
  195. security_blob = self.security_blob_ubuntu
  196. capabilities = 0x5
  197. data_size = 0x800000
  198. server_start_time = 0
  199. elif platform == "macos":
  200. server_Guid = b2a_hex(urandom(15)).decode()
  201. security_blob = self.security_blob_macos
  202. capabilities = 0x6
  203. data_size = 0x400000
  204. server_start_time = 0
  205. else:
  206. server_Guid = b2a_hex(urandom(15)).decode()
  207. security_blob = self.security_blob_windows
  208. capabilities = 0x7
  209. data_size = 0x100000
  210. server_start_time = get_rnd_boot_time(timestamp)
  211. return server_Guid, security_blob, capabilities, data_size, server_start_time
  212. pps = self.get_param_value(Param.PACKETS_PER_SECOND)
  213. # Calculate complement packet rates of the background traffic for each interval
  214. complement_interval_pps = self.statistics.calculate_complement_packet_rates(pps)
  215. # Timestamp
  216. timestamp_next_pkt = self.get_param_value(Param.INJECT_AT_TIMESTAMP)
  217. # store start time of attack
  218. self.attack_start_utime = timestamp_next_pkt
  219. timestamp_prv_reply, timestamp_confirm = 0,0
  220. # Initialize parameters
  221. ip_source = self.get_param_value(Param.IP_SOURCE)
  222. ip_destinations = self.get_param_value(Param.IP_DESTINATION)
  223. hosting_ip = self.get_param_value(Param.HOSTING_IP)
  224. ip_range_end = self.get_param_value(Param.IP_DESTINATION_END)
  225. mac_source = self.get_param_value(Param.MAC_SOURCE)
  226. mac_dest = self.get_param_value(Param.MAC_DESTINATION)
  227. # Check smb version
  228. def invalid_version(version: str):
  229. print("\nInvalid smb version: " + version +
  230. "\nPlease select one of the following versions: ", self.smb_versions)
  231. exit(1)
  232. smb_version = self.get_param_value(Param.PROTOCOL_VERSION)
  233. if smb_version not in self.smb_versions:
  234. invalid_version(smb_version)
  235. hosting_version = self.get_param_value(Param.HOSTING_VERSION)
  236. if hosting_version not in self.smb_versions:
  237. invalid_version(hosting_version)
  238. # Check source platform
  239. src_platform = self.get_param_value(Param.SOURCE_PLATFORM).lower()
  240. packets = []
  241. # randomize source ports according to platform, if specified
  242. if self.get_param_value(Param.PORT_SOURCE_RANDOMIZE):
  243. sport = generate_source_port_from_platform(src_platform)
  244. else:
  245. sport = self.get_param_value(Param.PORT_SOURCE)
  246. # No destination IP was specified, but a destination MAC was specified, generate IP that fits MAC
  247. if isinstance(ip_destinations, list) and isinstance(mac_dest, str):
  248. ip_destinations = self.statistics.get_ip_address_from_mac(mac_dest)
  249. if len(ip_destinations) == 0:
  250. ip_destinations = self.generate_random_ipv4_address("Unknown", 1)
  251. # Check ip.src == ip.dst
  252. self.ip_src_dst_equal_check(ip_source, ip_destinations)
  253. ip_dests = []
  254. if isinstance(ip_destinations, list):
  255. ip_dests = ip_destinations
  256. else:
  257. ip_dests.append(ip_destinations)
  258. # Generate IPs of destination IP range, if specified
  259. if ip_range_end != "0.0.0.0":
  260. ip_dests = get_ip_range(ip_dests[0], ip_range_end)
  261. shuffle(ip_dests)
  262. # Randomize source IP, if specified
  263. if self.get_param_value(Param.IP_SOURCE_RANDOMIZE):
  264. ip_source = self.generate_random_ipv4_address("Unknown", 1)
  265. while ip_source in ip_dests:
  266. ip_source = self.generate_random_ipv4_address("Unknown", 1)
  267. mac_source = self.statistics.get_mac_address(str(ip_source))
  268. if len(mac_source) == 0:
  269. mac_source = self.generate_random_mac_address()
  270. # Get MSS, TTL and Window size value for source IP
  271. source_mss_value, source_ttl_value, source_win_value = get_ip_data(ip_source)
  272. for ip in ip_dests:
  273. if ip != ip_source:
  274. # Get destination Mac Address
  275. mac_destination = self.statistics.get_mac_address(str(ip))
  276. if len(mac_destination) == 0:
  277. if isinstance(mac_dest, str):
  278. if len(self.statistics.get_ip_address_from_mac(mac_dest)) != 0:
  279. ip = self.statistics.get_ip_address_from_mac(mac_dest)
  280. self.ip_src_dst_equal_check(ip_source, ip)
  281. mac_destination = mac_dest
  282. else:
  283. mac_destination = self.generate_random_mac_address()
  284. # Get MSS, TTL and Window size value for destination IP
  285. destination_mss_value, destination_ttl_value, destination_win_value = get_ip_data(ip)
  286. minDelay, maxDelay = self.get_reply_delay(ip)
  287. # New connection, new random TCP sequence numbers
  288. attacker_seq = randint(1000, 50000)
  289. victim_seq = randint(1000, 50000)
  290. # Randomize source port for each connection if specified
  291. if self.get_param_value(Param.PORT_SOURCE_RANDOMIZE):
  292. sport = generate_source_port_from_platform(src_platform, sport)
  293. # 1) Build request package
  294. request_ether = Ether(src=mac_source, dst=mac_destination)
  295. request_ip = IP(src=ip_source, dst=ip, ttl=source_ttl_value, flags='DF')
  296. request_tcp = TCP(sport=sport, dport=self.smb_port, window=source_win_value, flags='S',
  297. seq=attacker_seq, options=[('MSS', source_mss_value)])
  298. attacker_seq += 1
  299. request = (request_ether / request_ip / request_tcp)
  300. request.time = timestamp_next_pkt
  301. # Append request
  302. packets.append(request)
  303. # Update timestamp for next package
  304. timestamp_reply = update_timestamp(timestamp_next_pkt, pps, minDelay)
  305. while (timestamp_reply <= timestamp_prv_reply):
  306. timestamp_reply = update_timestamp(timestamp_prv_reply, pps, minDelay)
  307. timestamp_prv_reply = timestamp_reply
  308. if ip in hosting_ip:
  309. # 2) Build TCP packages for ip that hosts SMB
  310. # destination sends SYN, ACK
  311. reply_ether = Ether(src=mac_destination, dst=mac_source)
  312. reply_ip = IP(src=ip, dst=ip_source, ttl=destination_ttl_value, flags='DF')
  313. reply_tcp = TCP(sport=self.smb_port, dport=sport, seq=victim_seq, ack=attacker_seq, flags='SA',
  314. window=destination_win_value, options=[('MSS', destination_mss_value)])
  315. victim_seq += 1
  316. reply = (reply_ether / reply_ip / reply_tcp)
  317. reply.time = timestamp_reply
  318. packets.append(reply)
  319. # requester confirms, ACK
  320. confirm_ether = request_ether
  321. confirm_ip = request_ip
  322. confirm_tcp = TCP(sport=sport, dport=self.smb_port, seq=attacker_seq, ack=victim_seq,
  323. window=source_win_value, flags='A')
  324. confirm = (confirm_ether / confirm_ip / confirm_tcp)
  325. timestamp_confirm = update_timestamp(timestamp_reply, pps, minDelay)
  326. confirm.time = timestamp_confirm
  327. packets.append(confirm)
  328. smb_MID = randint(1, 65535)
  329. smb_PID = randint(1, 65535)
  330. smb_req_tail_arr = []
  331. smb_req_tail_size = 0
  332. # select dialects based on smb version
  333. if smb_version is "1":
  334. smb_req_dialects = self.smb_dialects[0:6]
  335. else:
  336. smb_req_dialects = self.smb_dialects
  337. if len(smb_req_dialects) == 0:
  338. smb_req_tail_arr.append(SMBNegociate_Protocol_Request_Tail())
  339. smb_req_tail_size = len(SMBNegociate_Protocol_Request_Tail())
  340. else:
  341. for dia in smb_req_dialects:
  342. smb_req_tail_arr.append(SMBNegociate_Protocol_Request_Tail(BufferData = dia))
  343. smb_req_tail_size += len(SMBNegociate_Protocol_Request_Tail(BufferData = dia))
  344. smb_req_head = SMBNegociate_Protocol_Request_Header\
  345. (Flags2=0x2801, PID=smb_PID, MID=smb_MID, ByteCount=smb_req_tail_size)
  346. smb_req_length = len(smb_req_head) + smb_req_tail_size
  347. smb_req_net_bio = NBTSession(TYPE=0x00, LENGTH=smb_req_length)
  348. smb_req_tcp = TCP(sport=sport, dport=self.smb_port, flags='PA', seq=attacker_seq, ack=victim_seq)
  349. smb_req_ip = IP(src=ip_source, dst=ip, ttl=source_ttl_value)
  350. smb_req_ether = Ether(src=mac_source, dst=mac_destination)
  351. attacker_seq += len(smb_req_net_bio) + len(smb_req_head) + smb_req_tail_size
  352. smb_req_combined = (smb_req_ether / smb_req_ip / smb_req_tcp / smb_req_net_bio / smb_req_head)
  353. for i in range(0 , len(smb_req_tail_arr)):
  354. smb_req_combined = smb_req_combined / smb_req_tail_arr[i]
  355. timestamp_smb_req = update_timestamp(timestamp_confirm, pps, minDelay)
  356. smb_req_combined.time = timestamp_smb_req
  357. packets.append(smb_req_combined)
  358. # destination confirms SMB request package
  359. reply_tcp = TCP(sport=self.smb_port, dport=sport, seq=victim_seq, ack=attacker_seq,
  360. window=destination_win_value, flags='A')
  361. confirm_smb_req = (reply_ether / reply_ip / reply_tcp)
  362. timestamp_reply = update_timestamp(timestamp_smb_req, pps, minDelay)
  363. confirm_smb_req.time = timestamp_reply
  364. packets.append(confirm_smb_req)
  365. # smb response package
  366. first_timestamp = time.mktime(time.strptime(self.statistics.get_pcap_timestamp_start()[:19],
  367. "%Y-%m-%d %H:%M:%S"))
  368. server_Guid, security_blob, capabilities, data_size, server_start_time = get_smb_platform_data\
  369. (self.host_os, first_timestamp)
  370. timestamp_smb_rsp = update_timestamp(timestamp_reply, pps, minDelay)
  371. diff = timestamp_smb_rsp - timestamp_smb_req
  372. begin = get_filetime_format(timestamp_smb_req+diff*0.1)
  373. end = get_filetime_format(timestamp_smb_rsp-diff*0.1)
  374. system_time = randint(begin, end)
  375. if smb_version is not "1" and hosting_version is not "1":
  376. smb_rsp_paket = SMB2_SYNC_Header(Flags = 1)
  377. smb_rsp_negotiate_body = SMB2_Negotiate_Protocol_Response\
  378. (DialectRevision=0x02ff, SecurityBufferOffset=124, SecurityBufferLength=len(security_blob),
  379. SecurityBlob=security_blob, Capabilities=capabilities, MaxTransactSize=data_size,
  380. MaxReadSize=data_size, MaxWriteSize=data_size, SystemTime=system_time,
  381. ServerStartTime=server_start_time, ServerGuid=server_Guid)
  382. smb_rsp_length = len(smb_rsp_paket) + len(smb_rsp_negotiate_body)
  383. else:
  384. smb_rsp_paket = SMBNegociate_Protocol_Response_Advanced_Security\
  385. (Start="\xffSMB", PID=smb_PID, MID=smb_MID, DialectIndex=5, SecurityBlob=security_blob)
  386. smb_rsp_length = len(smb_rsp_paket)
  387. smb_rsp_net_bio = NBTSession(TYPE=0x00, LENGTH=smb_rsp_length)
  388. smb_rsp_tcp = TCP(sport=self.smb_port, dport=sport, flags='PA', seq=victim_seq, ack=attacker_seq)
  389. smb_rsp_ip = IP(src=ip, dst=ip_source, ttl=destination_ttl_value)
  390. smb_rsp_ether = Ether(src=mac_destination, dst=mac_source)
  391. victim_seq += len(smb_rsp_net_bio) + len(smb_rsp_paket)
  392. if smb_version is not "1"and hosting_version is not "1":
  393. victim_seq += len(smb_rsp_negotiate_body)
  394. smb_rsp_combined = (smb_rsp_ether / smb_rsp_ip / smb_rsp_tcp / smb_rsp_net_bio / smb_rsp_paket)
  395. if smb_version is not "1"and hosting_version is not "1":
  396. smb_rsp_combined = (smb_rsp_combined / smb_rsp_negotiate_body)
  397. smb_rsp_combined.time = timestamp_smb_rsp
  398. packets.append(smb_rsp_combined)
  399. # source confirms SMB response package
  400. confirm_tcp = TCP(sport=sport, dport=self.smb_port, seq=attacker_seq, ack=victim_seq,
  401. window=source_win_value, flags='A')
  402. confirm_smb_res = (confirm_ether / confirm_ip / confirm_tcp)
  403. timestamp_confirm = update_timestamp(timestamp_smb_rsp, pps, minDelay)
  404. confirm_smb_res.time = timestamp_confirm
  405. packets.append(confirm_smb_res)
  406. # attacker sends FIN ACK
  407. confirm_tcp = TCP(sport=sport, dport=self.smb_port, seq=attacker_seq, ack=victim_seq,
  408. window=source_win_value, flags='FA')
  409. source_fin_ack = (confirm_ether / confirm_ip / confirm_tcp)
  410. timestamp_src_fin_ack = update_timestamp(timestamp_confirm, pps, minDelay)
  411. source_fin_ack.time = timestamp_src_fin_ack
  412. attacker_seq += 1
  413. packets.append(source_fin_ack)
  414. # victim sends FIN ACK
  415. reply_tcp = TCP(sport=self.smb_port, dport=sport, seq=victim_seq, ack=attacker_seq,
  416. window=destination_win_value, flags='FA')
  417. destination_fin_ack = (reply_ether / reply_ip / reply_tcp)
  418. timestamp_dest_fin_ack = update_timestamp(timestamp_src_fin_ack, pps, minDelay)
  419. victim_seq += 1
  420. destination_fin_ack.time = timestamp_dest_fin_ack
  421. packets.append(destination_fin_ack)
  422. # source sends final ACK
  423. confirm_tcp = TCP(sport=sport, dport=self.smb_port, seq=attacker_seq, ack=victim_seq,
  424. window=source_win_value, flags='A')
  425. final_ack = (confirm_ether / confirm_ip / confirm_tcp)
  426. timestamp_final_ack = update_timestamp(timestamp_dest_fin_ack, pps, minDelay)
  427. final_ack.time = timestamp_final_ack
  428. packets.append(final_ack)
  429. else:
  430. # Build RST package
  431. reply_ether = Ether(src=mac_destination, dst=mac_source)
  432. reply_ip = IP(src=ip, dst=ip_source, ttl=destination_ttl_value, flags='DF')
  433. reply_tcp = TCP(sport=self.smb_port, dport=sport, seq=0, ack=attacker_seq, flags='RA',
  434. window=destination_win_value, options=[('MSS', destination_mss_value)])
  435. reply = (reply_ether / reply_ip / reply_tcp)
  436. reply.time = timestamp_reply
  437. packets.append(reply)
  438. pps = max(getIntervalPPS(complement_interval_pps, timestamp_next_pkt), 10)
  439. timestamp_next_pkt = update_timestamp(timestamp_next_pkt, pps)
  440. # store end time of attack
  441. self.attack_end_utime = packets[-1].time
  442. # write attack packets to pcap
  443. pcap_path = self.write_attack_pcap(sorted(packets, key=lambda pkt: pkt.time))
  444. # return packets sorted by packet time_sec_start
  445. return len(packets), pcap_path