SQLiAttack.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. import logging
  2. from random import randint, uniform
  3. from lea import Lea
  4. from Attack import BaseAttack
  5. from Attack.AttackParameters import Parameter as Param
  6. from Attack.AttackParameters import ParameterTypes
  7. logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
  8. # noinspection PyPep8
  9. from scapy.utils import RawPcapReader
  10. from scapy.layers.inet import IP, Ether, TCP, RandShort
  11. from ID2TLib.Utility import *
  12. class SQLiAttack(BaseAttack.BaseAttack):
  13. template_attack_pcap_path = "resources/ATutorSQLi.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 SQLi Attack.
  22. """
  23. # Initialize attack
  24. super(SQLiAttack, self).__init__("SQLi Attack", "Injects a SQLi attack'",
  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. mac_destination = self.get_param_value(Param.MAC_DESTINATION)
  80. ip_destination = self.get_param_value(Param.IP_DESTINATION)
  81. port_destination = self.get_param_value(Param.PORT_DESTINATION)
  82. target_host = self.get_param_value(Param.TARGET_HOST)
  83. target_uri = "/" # self.get_param_value(Param.TARGET_URI)
  84. # Check ip.src == ip.dst
  85. self.ip_src_dst_equal_check(ip_source, ip_destination)
  86. path_attack_pcap = None
  87. # Set TTL based on TTL distribution of IP address
  88. source_ttl_dist = self.statistics.get_ttl_distribution(ip_source)
  89. if len(source_ttl_dist) > 0:
  90. source_ttl_prob_dict = Lea.fromValFreqsDict(source_ttl_dist)
  91. source_ttl_value = source_ttl_prob_dict.random()
  92. else:
  93. source_ttl_value = self.statistics.process_db_query("most_used(ttlValue)")
  94. destination_ttl_dist = self.statistics.get_ttl_distribution(ip_destination)
  95. if len(destination_ttl_dist) > 0:
  96. destination_ttl_prob_dict = Lea.fromValFreqsDict(destination_ttl_dist)
  97. destination_ttl_value = destination_ttl_prob_dict.random()
  98. else:
  99. destination_ttl_value = self.statistics.process_db_query("most_used(ttlValue)")
  100. # Inject SQLi Attack
  101. # Read SQLi Attack pcap file
  102. orig_ip_dst = None
  103. exploit_raw_packets = RawPcapReader(self.template_attack_pcap_path)
  104. inter_arrival_times, inter_arrival_time_dist = self.get_inter_arrival_time(exploit_raw_packets,True)
  105. timeSteps = Lea.fromValFreqsDict(inter_arrival_time_dist)
  106. exploit_raw_packets = RawPcapReader(self.template_attack_pcap_path)
  107. port_source = randint(self.minDefaultPort,self.maxDefaultPort) # experiments show this range of ports
  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. orig_ip_dst = ip_pkt.getfieldval("dst") # victim IP
  125. if tcp_pkt.getfieldval("dport") == 80 or tcp_pkt.getfieldval("sport") == 80:
  126. # Attacker --> vicitm
  127. if ip_pkt.getfieldval("dst") == orig_ip_dst: # victim IP
  128. # There are 363 TCP connections with different source ports, for each of them we generate random port
  129. if tcp_pkt.getfieldval("sport") != prev_orig_port_source and tcp_pkt.getfieldval("dport") != 4444:
  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, '/ATutor', 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(getIntervalPPS(complement_interval_pps, timestamp_next_pkt), 10)
  157. timestamp_next_pkt = update_timestamp(timestamp_next_pkt, pps) + float(timeSteps.random())
  158. # 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, '/ATutor', 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. timestamp_next_pkt = update_timestamp(timestamp_next_pkt, pps) + float(timeSteps.random())
  179. new_pkt.time = timestamp_next_pkt
  180. # The last connection
  181. else:
  182. # New connection, new random TCP sequence numbers
  183. attacker_seq = randint(1000, 50000)
  184. victim_seq = randint(1000, 50000)
  185. # First packet in a connection has ACK = 0
  186. tcp_pkt.setfieldval("ack", 0)
  187. #port_source = randint(self.minDefaultPort, self.maxDefaultPort)
  188. # Attacker --> vicitm
  189. if ip_pkt.getfieldval("dst") == orig_ip_dst: # victim IP
  190. # Ether
  191. eth_frame.setfieldval("src", mac_source)
  192. eth_frame.setfieldval("dst", mac_destination)
  193. # IP
  194. ip_pkt.setfieldval("src", ip_source)
  195. ip_pkt.setfieldval("dst", ip_destination)
  196. ip_pkt.setfieldval("ttl", source_ttl_value)
  197. # TCP
  198. #tcp_pkt.setfieldval("sport", port_source)
  199. str_tcp_seg = self.modify_http_header(str_tcp_seg, '/ATutor', target_uri, orig_ip_dst, target_host)
  200. # TCP Seq, Ack
  201. if tcp_pkt.getfieldval("ack") != 0:
  202. tcp_pkt.setfieldval("ack", victim_seq)
  203. tcp_pkt.setfieldval("seq", attacker_seq)
  204. if not (tcp_pkt.getfieldval("flags") == 16 and len(str_tcp_seg) == 0): # flags=A:
  205. attacker_seq += max(len(str_tcp_seg), 1)
  206. new_pkt = (eth_frame / ip_pkt / tcp_pkt / str_tcp_seg)
  207. new_pkt.time = timestamp_next_pkt
  208. pps = max(getIntervalPPS(complement_interval_pps, timestamp_next_pkt), 10)
  209. timestamp_next_pkt = update_timestamp(timestamp_next_pkt, pps) + float(timeSteps.random())
  210. # Victim --> attacker
  211. else:
  212. # Ether
  213. eth_frame.setfieldval("src", mac_destination)
  214. eth_frame.setfieldval("dst", mac_source)
  215. # IP
  216. ip_pkt.setfieldval("src", ip_destination)
  217. ip_pkt.setfieldval("dst", ip_source)
  218. ip_pkt.setfieldval("ttl", destination_ttl_value)
  219. # TCP
  220. #tcp_pkt.setfieldval("dport", port_source)
  221. str_tcp_seg = self.modify_http_header(str_tcp_seg, '/ATutor', target_uri, orig_ip_dst, target_host)
  222. # TCP Seq, ACK
  223. tcp_pkt.setfieldval("ack", attacker_seq)
  224. tcp_pkt.setfieldval("seq", victim_seq)
  225. strLen = len(str_tcp_seg)
  226. if not (tcp_pkt.getfieldval("flags") == 16 and strLen == 0): # flags=A:
  227. victim_seq += max(strLen, 1)
  228. new_pkt = (eth_frame / ip_pkt / tcp_pkt / str_tcp_seg)
  229. timestamp_next_pkt = update_timestamp(timestamp_next_pkt, pps) + float(timeSteps.random())
  230. new_pkt.time = timestamp_next_pkt
  231. packets.append(new_pkt)
  232. # Store timestamp of first packet (for attack label)
  233. self.attack_start_utime = packets[0].time
  234. self.attack_end_utime = packets[-1].time
  235. if len(packets) > 0:
  236. packets = sorted(packets, key=lambda pkt: pkt.time)
  237. path_attack_pcap = self.write_attack_pcap(packets, True, path_attack_pcap)
  238. # return packets sorted by packet time_sec_start
  239. # pkt_num+1: because pkt_num starts at 0
  240. return pkt_num + 1, path_attack_pcap