JoomlaRegPrivExploit.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. import logging
  2. from random import randint
  3. from lea import Lea
  4. from scapy.utils import RawPcapReader
  5. from scapy.layers.inet import Ether
  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, get_interval_pps
  10. logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
  11. # noinspection PyPep8
  12. class JoomlaRegPrivExploit(BaseAttack.BaseAttack):
  13. template_attack_pcap_path = "resources/joomla_registration_privesc.pcap"
  14. # HTTP port
  15. http_port = 80
  16. # Metasploit experiments show this range of ports
  17. minDefaultPort = 30000
  18. maxDefaultPort = 50000
  19. def __init__(self):
  20. """
  21. Creates a new instance of the Joomla Registeration Privileges Escalation Exploit.
  22. """
  23. # Initialize attack
  24. super(JoomlaRegPrivExploit, self).__init__("JoomlaRegPrivesc Exploit", "Injects an JoomlaRegPrivesc exploit'",
  25. "Privilege elevation")
  26. # Define allowed parameters and their type
  27. self.supported_params = {
  28. Param.MAC_SOURCE: ParameterTypes.TYPE_MAC_ADDRESS,
  29. Param.IP_SOURCE: ParameterTypes.TYPE_IP_ADDRESS,
  30. Param.MAC_DESTINATION: ParameterTypes.TYPE_MAC_ADDRESS,
  31. Param.IP_DESTINATION: ParameterTypes.TYPE_IP_ADDRESS,
  32. Param.PORT_DESTINATION: ParameterTypes.TYPE_PORT,
  33. Param.TARGET_HOST: ParameterTypes.TYPE_DOMAIN,
  34. #Param.TARGET_URI: ParameterTypes.TYPE_URI,
  35. Param.INJECT_AT_TIMESTAMP: ParameterTypes.TYPE_FLOAT,
  36. Param.INJECT_AFTER_PACKET: ParameterTypes.TYPE_PACKET_POSITION,
  37. Param.PACKETS_PER_SECOND: ParameterTypes.TYPE_FLOAT
  38. }
  39. def init_params(self):
  40. """
  41. Initialize the parameters of this attack using the user supplied command line parameters.
  42. Use the provided statistics to calculate default parameters and to process user
  43. supplied queries.
  44. :param statistics: Reference to a statistics object.
  45. """
  46. # PARAMETERS: initialize with default utilsvalues
  47. # (values are overwritten if user specifies them)
  48. # Attacker configuration
  49. most_used_ip_address = self.statistics.get_most_used_ip_address()
  50. if isinstance(most_used_ip_address, list):
  51. most_used_ip_address = most_used_ip_address[0]
  52. self.add_param_value(Param.IP_SOURCE, most_used_ip_address)
  53. self.add_param_value(Param.MAC_SOURCE, self.statistics.get_mac_address(most_used_ip_address))
  54. # Victim configuration
  55. random_ip_address = self.statistics.get_random_ip_address()
  56. self.add_param_value(Param.IP_DESTINATION, random_ip_address)
  57. destination_mac = self.statistics.get_mac_address(random_ip_address)
  58. if isinstance(destination_mac, list) and len(destination_mac) == 0:
  59. destination_mac = self.generate_random_mac_address()
  60. self.add_param_value(Param.MAC_DESTINATION, destination_mac)
  61. self.add_param_value(Param.PORT_DESTINATION, self.http_port)
  62. # self.add_param_value(Param.TARGET_URI, '/')
  63. self.add_param_value(Param.TARGET_HOST, "www.hackme.com")
  64. # Attack configuration
  65. self.add_param_value(Param.INJECT_AFTER_PACKET, randint(0, self.statistics.get_packet_count()))
  66. self.add_param_value(Param.PACKETS_PER_SECOND,
  67. (self.statistics.get_pps_sent(most_used_ip_address) +
  68. self.statistics.get_pps_received(most_used_ip_address)) / 2)
  69. def generate_attack_pcap(self):
  70. # Timestamp
  71. timestamp_next_pkt = self.get_param_value(Param.INJECT_AT_TIMESTAMP)
  72. pps = self.get_param_value(Param.PACKETS_PER_SECOND)
  73. # Calculate complement packet rates of BG traffic per interval
  74. complement_interval_pps = self.statistics.calculate_complement_packet_rates(pps)
  75. # Initialize parameters
  76. packets = []
  77. mac_source = self.get_param_value(Param.MAC_SOURCE)
  78. ip_source = self.get_param_value(Param.IP_SOURCE)
  79. port_source = randint(self.minDefaultPort, self.maxDefaultPort)
  80. mac_destination = self.get_param_value(Param.MAC_DESTINATION)
  81. ip_destination = self.get_param_value(Param.IP_DESTINATION)
  82. port_destination = self.get_param_value(Param.PORT_DESTINATION)
  83. target_host = self.get_param_value(Param.TARGET_HOST)
  84. target_uri = "/" #self.get_param_value(Param.TARGET_URI)
  85. # Check ip.src == ip.dst
  86. self.ip_src_dst_equal_check(ip_source, ip_destination)
  87. path_attack_pcap = None
  88. # Set TTL based on TTL distribution of IP address
  89. source_ttl_dist = self.statistics.get_ttl_distribution(ip_source)
  90. if len(source_ttl_dist) > 0:
  91. source_ttl_prob_dict = Lea.fromValFreqsDict(source_ttl_dist)
  92. source_ttl_value = source_ttl_prob_dict.random()
  93. else:
  94. source_ttl_value = self.statistics.process_db_query("most_used(ttlValue)")
  95. destination_ttl_dist = self.statistics.get_ttl_distribution(ip_destination)
  96. if len(destination_ttl_dist) > 0:
  97. destination_ttl_prob_dict = Lea.fromValFreqsDict(destination_ttl_dist)
  98. destination_ttl_value = destination_ttl_prob_dict.random()
  99. else:
  100. destination_ttl_value = self.statistics.process_db_query("most_used(ttlValue)")
  101. # Inject Joomla_registration_privesc
  102. # Read joomla_registration_privesc pcap file
  103. orig_ip_dst = None
  104. exploit_raw_packets = RawPcapReader(self.template_attack_pcap_path)
  105. inter_arrival_times, inter_arrival_time_dist = self.get_inter_arrival_time(exploit_raw_packets,True)
  106. timeSteps = Lea.fromValFreqsDict(inter_arrival_time_dist)
  107. exploit_raw_packets = RawPcapReader(self.template_attack_pcap_path)
  108. # Random TCP sequence numbers
  109. global attacker_seq
  110. attacker_seq = randint(1000,50000)
  111. global victim_seq
  112. victim_seq = randint(1000,50000)
  113. for pkt_num, pkt in enumerate(exploit_raw_packets):
  114. eth_frame = Ether(pkt[0])
  115. ip_pkt = eth_frame.payload
  116. tcp_pkt = ip_pkt.payload
  117. str_tcp_seg = str(tcp_pkt.payload)
  118. # Clean payloads
  119. eth_frame.payload = b''
  120. ip_pkt.payload = b''
  121. tcp_pkt.payload = b''
  122. if pkt_num == 0:
  123. prev_orig_port_source = tcp_pkt.getfieldval("sport")
  124. if tcp_pkt.getfieldval("dport") == self.http_port:
  125. orig_ip_dst = ip_pkt.getfieldval("dst") # victim IP
  126. # Request: Attacker --> vicitm
  127. if ip_pkt.getfieldval("dst") == orig_ip_dst: # victim IP
  128. # There are 7 TCP connections with different source ports, for each of them we generate random port
  129. if tcp_pkt.getfieldval("sport") != prev_orig_port_source:
  130. port_source = randint(self.minDefaultPort, self.maxDefaultPort)
  131. prev_orig_port_source = tcp_pkt.getfieldval("sport")
  132. # New connection, new random TCP sequence numbers
  133. attacker_seq = randint(1000, 50000)
  134. victim_seq = randint(1000, 50000)
  135. # First packet in a connection has ACK = 0
  136. tcp_pkt.setfieldval("ack", 0)
  137. # Ether
  138. eth_frame.setfieldval("src", mac_source)
  139. eth_frame.setfieldval("dst", mac_destination)
  140. # IP
  141. ip_pkt.setfieldval("src", ip_source)
  142. ip_pkt.setfieldval("dst", ip_destination)
  143. ip_pkt.setfieldval("ttl", source_ttl_value)
  144. # TCP
  145. tcp_pkt.setfieldval("sport",port_source)
  146. tcp_pkt.setfieldval("dport", port_destination)
  147. str_tcp_seg = self.modify_http_header(str_tcp_seg, '/joomla360', target_uri, orig_ip_dst, target_host)
  148. # TCP Seq, Ack
  149. if tcp_pkt.getfieldval("ack") != 0:
  150. tcp_pkt.setfieldval("ack", victim_seq)
  151. tcp_pkt.setfieldval("seq", attacker_seq)
  152. if not(tcp_pkt.getfieldval("flags") == 16 and len(str_tcp_seg) == 0): # flags=A:
  153. attacker_seq += max(len(str_tcp_seg),1)
  154. new_pkt = (eth_frame / ip_pkt/ tcp_pkt / str_tcp_seg)
  155. new_pkt.time = timestamp_next_pkt
  156. pps = max(get_interval_pps(complement_interval_pps, timestamp_next_pkt), 10)
  157. timestamp_next_pkt = update_timestamp(timestamp_next_pkt, pps) + float(timeSteps.random())
  158. # Reply: Victim --> attacker
  159. else:
  160. # Ether
  161. eth_frame.setfieldval("src", mac_destination)
  162. eth_frame.setfieldval("dst", mac_source)
  163. # IP
  164. ip_pkt.setfieldval("src", ip_destination)
  165. ip_pkt.setfieldval("dst", ip_source)
  166. ip_pkt.setfieldval("ttl", destination_ttl_value)
  167. # TCP
  168. tcp_pkt.setfieldval("dport", port_source)
  169. tcp_pkt.setfieldval("sport", port_destination)
  170. str_tcp_seg = self.modify_http_header(str_tcp_seg, '/joomla360', target_uri, orig_ip_dst, target_host)
  171. # TCP Seq, ACK
  172. tcp_pkt.setfieldval("ack", attacker_seq)
  173. tcp_pkt.setfieldval("seq", victim_seq)
  174. strLen = len(str_tcp_seg)
  175. if not(tcp_pkt.getfieldval("flags") == 16 and strLen == 0): # flags=A:
  176. victim_seq += max(strLen, 1)
  177. new_pkt = (eth_frame / ip_pkt / tcp_pkt / str_tcp_seg)
  178. pps = max(get_interval_pps(complement_interval_pps, timestamp_next_pkt), 10)
  179. timestamp_next_pkt = update_timestamp(timestamp_next_pkt, pps) + float(timeSteps.random())
  180. new_pkt.time = timestamp_next_pkt
  181. packets.append(new_pkt)
  182. # Store timestamp of first packet (for attack label)
  183. self.attack_start_utime = packets[0].time
  184. self.attack_end_utime = packets[-1].time
  185. if len(packets) > 0:
  186. packets = sorted(packets, key=lambda pkt: pkt.time)
  187. path_attack_pcap = self.write_attack_pcap(packets, True, path_attack_pcap)
  188. # return packets sorted by packet time_sec_start
  189. # pkt_num+1: because pkt_num starts at 0
  190. return pkt_num + 1, path_attack_pcap