PortscanAttack.py 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. import logging
  2. from random import shuffle, randint, choice, 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.layers.inet import IP, Ether, TCP
  10. class PortscanAttack(BaseAttack.BaseAttack):
  11. def __init__(self, statistics, pcap_file_path):
  12. """
  13. Creates a new instance of the PortscanAttack.
  14. :param statistics: A reference to the statistics class.
  15. """
  16. # Initialize attack
  17. super(PortscanAttack, self).__init__(statistics, "Portscan Attack", "Injects a nmap 'regular scan'",
  18. "Scanning/Probing")
  19. # Define allowed parameters and their type
  20. self.supported_params = {
  21. Param.IP_SOURCE: ParameterTypes.TYPE_IP_ADDRESS,
  22. Param.IP_DESTINATION: ParameterTypes.TYPE_IP_ADDRESS,
  23. Param.PORT_SOURCE: ParameterTypes.TYPE_PORT,
  24. Param.PORT_DESTINATION: ParameterTypes.TYPE_PORT,
  25. Param.PORT_OPEN: ParameterTypes.TYPE_PORT,
  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.PORT_DEST_SHUFFLE: ParameterTypes.TYPE_BOOLEAN,
  31. Param.PORT_DEST_ORDER_DESC: ParameterTypes.TYPE_BOOLEAN,
  32. Param.IP_SOURCE_RANDOMIZE: ParameterTypes.TYPE_BOOLEAN,
  33. Param.PACKETS_PER_SECOND: ParameterTypes.TYPE_FLOAT,
  34. Param.PORT_SOURCE_RANDOMIZE: ParameterTypes.TYPE_BOOLEAN
  35. }
  36. # PARAMETERS: initialize with default values
  37. # (values are overwritten if user specifies them)
  38. most_used_ip_address = self.statistics.get_most_used_ip_address()
  39. if isinstance(most_used_ip_address, list):
  40. most_used_ip_address = most_used_ip_address[0]
  41. self.add_param_value(Param.IP_SOURCE, most_used_ip_address)
  42. self.add_param_value(Param.IP_SOURCE_RANDOMIZE, 'False')
  43. self.add_param_value(Param.MAC_SOURCE, self.statistics.get_mac_address(most_used_ip_address))
  44. random_ip_address = self.statistics.get_random_ip_address()
  45. self.add_param_value(Param.IP_DESTINATION, random_ip_address)
  46. self.add_param_value(Param.MAC_DESTINATION, self.statistics.get_mac_address(random_ip_address))
  47. self.add_param_value(Param.PORT_DESTINATION, '1-1023,1720,1900,8080')
  48. self.add_param_value(Param.PORT_OPEN, '8080,9232,9233')
  49. self.add_param_value(Param.PORT_DEST_SHUFFLE, 'False')
  50. self.add_param_value(Param.PORT_DEST_ORDER_DESC, 'False')
  51. self.add_param_value(Param.PORT_SOURCE, randint(1024, 65535))
  52. self.add_param_value(Param.PORT_SOURCE_RANDOMIZE, 'False')
  53. self.add_param_value(Param.PACKETS_PER_SECOND,
  54. (self.statistics.get_pps_sent(most_used_ip_address) +
  55. self.statistics.get_pps_received(most_used_ip_address)) / 2)
  56. self.add_param_value(Param.INJECT_AFTER_PACKET, randint(0, self.statistics.get_packet_count()))
  57. def generate_attack_pcap(self):
  58. def update_timestamp(timestamp, pps, maxdelay):
  59. """
  60. Calculates the next timestamp to be used based on the packet per second rate (pps) and the maximum delay.
  61. :return: Timestamp to be used for the next packet.
  62. """
  63. return timestamp + uniform(0.1 / pps, maxdelay)
  64. # Determine ports
  65. dest_ports = self.get_param_value(Param.PORT_DESTINATION)
  66. if self.get_param_value(Param.PORT_DEST_ORDER_DESC):
  67. dest_ports.reverse()
  68. elif self.get_param_value(Param.PORT_DEST_SHUFFLE):
  69. shuffle(dest_ports)
  70. if self.get_param_value(Param.PORT_SOURCE_RANDOMIZE):
  71. sport = randint(0, 65535)
  72. else:
  73. sport = self.get_param_value(Param.PORT_SOURCE)
  74. # Timestamp
  75. timestamp_next_pkt = self.get_param_value(Param.INJECT_AT_TIMESTAMP)
  76. # store start time of attack
  77. self.attack_start_utime = timestamp_next_pkt
  78. # Initialize parameters
  79. packets = []
  80. ip_source = self.get_param_value(Param.IP_SOURCE)
  81. ip_destination = self.get_param_value(Param.IP_DESTINATION)
  82. mac_source = self.get_param_value(Param.MAC_SOURCE)
  83. mac_destination = self.get_param_value(Param.MAC_DESTINATION)
  84. pps = self.get_param_value(Param.PACKETS_PER_SECOND)
  85. randomdelay = Lea.fromValFreqsDict({1 / pps: 70, 2 / pps: 30, 5 / pps: 15, 10 / pps: 3})
  86. maxdelay = randomdelay.random()
  87. # MSS (Maximum Segment Size) for Ethernet. Allowed values [536,1500]
  88. mss = self.statistics.get_mss(ip_destination)
  89. # Set TTL based on TTL distribution of IP address
  90. ttl_dist = self.statistics.get_ttl_distribution(ip_source)
  91. if len(ttl_dist) > 0:
  92. ttl_prob_dict = Lea.fromValFreqsDict(ttl_dist)
  93. ttl_value = ttl_prob_dict.random()
  94. else:
  95. ttl_value = self.statistics.process_db_query("most_used(ttlValue)")
  96. for dport in dest_ports:
  97. # Parameters changing each iteration
  98. if self.get_param_value(Param.IP_SOURCE_RANDOMIZE) and isinstance(ip_source, list):
  99. ip_source = choice(ip_source)
  100. # 1) Build request package
  101. request_ether = Ether(src=mac_source, dst=mac_destination)
  102. request_ip = IP(src=ip_source, dst=ip_destination, ttl=ttl_value)
  103. request_tcp = TCP(sport=sport, dport=dport, flags='S')
  104. request = (request_ether / request_ip / request_tcp)
  105. # first packet uses timestamp provided by attack parameter Param.INJECT_AT_TIMESTAMP
  106. if len(packets) > 0:
  107. timestamp_next_pkt = update_timestamp(timestamp_next_pkt, pps, maxdelay)
  108. request.time = timestamp_next_pkt
  109. packets.append(request)
  110. # 2) Build reply package
  111. if dport in self.get_param_value(Param.PORT_OPEN): # destination port is OPEN
  112. reply_ether = Ether(src=mac_destination, dst=mac_source)
  113. reply_ip = IP(src=ip_destination, dst=ip_source, flags='DF')
  114. if mss is None:
  115. reply_tcp = TCP(sport=dport, dport=sport, seq=0, ack=1, flags='SA', window=29200)
  116. else:
  117. reply_tcp = TCP(sport=dport, dport=sport, seq=0, ack=1, flags='SA', window=29200,
  118. options=[('MSS', mss)])
  119. reply = (reply_ether / reply_ip / reply_tcp)
  120. timestamp_next_pkt = update_timestamp(timestamp_next_pkt, pps, maxdelay)
  121. reply.time = timestamp_next_pkt
  122. packets.append(reply)
  123. # requester confirms
  124. confirm_ether = request_ether
  125. confirm_ip = request_ip
  126. confirm_tcp = TCP(sport=sport, dport=dport, seq=1, window=0, flags='R')
  127. reply = (confirm_ether / confirm_ip / confirm_tcp)
  128. timestamp_next_pkt = update_timestamp(timestamp_next_pkt, pps, maxdelay)
  129. reply.time = timestamp_next_pkt
  130. packets.append(reply)
  131. # else: destination port is NOT OPEN -> no reply is sent by target
  132. # store end time of attack
  133. self.attack_end_utime = packets[-1].time
  134. print("Packets created: " + str(len(packets)))
  135. # write packets to disk
  136. path_attack_pcap = self.write_attack_pcap(sorted(packets, key=lambda pkt: pkt.time))
  137. # return destination path
  138. return path_attack_pcap