PortscanAttack.py 8.0 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_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_RANDOM: ParameterTypes.TYPE_BOOLEAN}
  35. # PARAMETERS: initialize with default values
  36. # (values are overwritten if user specifies them)
  37. most_used_ip_address = self.statistics.get_most_used_ip_address()
  38. if isinstance(most_used_ip_address, list):
  39. most_used_ip_address = most_used_ip_address[0]
  40. self.add_param_value(Param.IP_SOURCE, most_used_ip_address)
  41. self.add_param_value(Param.IP_SOURCE_RANDOMIZE, 'False')
  42. self.add_param_value(Param.MAC_SOURCE, self.statistics.get_mac_address(most_used_ip_address))
  43. random_ip_address = self.statistics.get_random_ip_address()
  44. self.add_param_value(Param.IP_DESTINATION, random_ip_address)
  45. self.add_param_value(Param.MAC_DESTINATION, self.statistics.get_mac_address(random_ip_address))
  46. self.add_param_value(Param.PORT_DESTINATION, '0-1023,1720,1900,8080')
  47. self.add_param_value(Param.PORT_OPEN, '8080,9232,9233')
  48. self.add_param_value(Param.PORT_DEST_SHUFFLE, 'False')
  49. self.add_param_value(Param.PORT_ORDER_DESC, 'False')
  50. self.add_param_value(Param.PORT_SOURCE, '8542')
  51. self.add_param_value(Param.PORT_SOURCE_RANDOM, 'False')
  52. self.add_param_value(Param.PACKETS_PER_SECOND,
  53. (self.statistics.get_pps_sent(most_used_ip_address) +
  54. self.statistics.get_pps_received(most_used_ip_address)) / 2)
  55. self.add_param_value(Param.INJECT_AFTER_PACKET, randint(0, self.statistics.get_packet_count()))
  56. def get_packets(self):
  57. def update_timestamp(timestamp, pps, maxdelay):
  58. """
  59. Calculates the next timestamp to be used based on the packet per second rate (pps) and the maximum delay.
  60. :return: Timestamp to be used for the next packet.
  61. """
  62. return timestamp + uniform(0.1 / pps, maxdelay)
  63. # Determine ports
  64. dest_ports = self.get_param_value(Param.PORT_DESTINATION)
  65. if self.get_param_value(Param.PORT_ORDER_DESC):
  66. dest_ports.reverse()
  67. elif self.get_param_value(Param.PORT_DEST_SHUFFLE):
  68. shuffle(dest_ports)
  69. if self.get_param_value(Param.PORT_SOURCE_RANDOM):
  70. sport = randint(0, 65535)
  71. else:
  72. sport = self.get_param_value(Param.PORT_SOURCE)
  73. # Get TTL distribution
  74. # keys = list(self.statistics.get_ttl_distribution().vals()
  75. # values = list(self.statistics.get_ttl_distribution().pmf())
  76. # TTL_samples = numpy.random.choice(keys, size=len(dest_ports), replace=True, dport=values)
  77. ttl_value = self.statistics.process_db_query("most_used(ttlValue)")
  78. # Timestamp
  79. timestamp_next_pkt = self.get_param_value(Param.INJECT_AT_TIMESTAMP)
  80. self.attack_start_utime = timestamp_next_pkt # store start time of attack
  81. pps = self.get_param_value(Param.PACKETS_PER_SECOND)
  82. randomdelay = Lea.fromValFreqsDict({1 / pps: 70, 2 / pps: 30, 5 / pps: 15, 10 / pps: 3})
  83. maxdelay = randomdelay.random()
  84. # Initialize parameters
  85. packets = []
  86. ip_source = self.get_param_value(Param.IP_SOURCE)
  87. ip_destination = self.get_param_value(Param.IP_DESTINATION)
  88. mac_source = self.get_param_value(Param.MAC_SOURCE)
  89. mac_destination = self.get_param_value(Param.MAC_DESTINATION)
  90. # MSS (Maximum Segment Size) for Ethernet. Allowed values [536,1500]
  91. mss = self.statistics.get_mss(ip_destination)
  92. for dport in dest_ports:
  93. # Parameters changing each iteration
  94. if self.get_param_value(Param.IP_SOURCE_RANDOMIZE) and isinstance(ip_source, list):
  95. ip_source = choice(ip_source)
  96. # 1) Build request package
  97. request_ether = Ether(src=mac_source, dst=mac_destination)
  98. request_ip = IP(src=ip_source, dst=ip_destination, ttl=ttl_value)
  99. request_tcp = TCP(sport=sport, dport=dport)
  100. request = (request_ether / request_ip / request_tcp)
  101. # first packet uses timestamp provided by attack parameter Param.INJECT_AT_TIMESTAMP
  102. if len(packets) > 0:
  103. timestamp_next_pkt = update_timestamp(timestamp_next_pkt, pps, maxdelay)
  104. request.time = timestamp_next_pkt
  105. packets.append(request)
  106. # 2) Build reply package
  107. reply_ether = Ether(src=mac_destination, dst=mac_source)
  108. reply_ip = IP(src=ip_destination, dst=ip_source, flags='DF')
  109. if dport in self.get_param_value(Param.PORT_OPEN): # destination port is OPEN
  110. # target answers
  111. if mss is None:
  112. reply_tcp = TCP(sport=dport, dport=sport, seq=0, ack=1, flags='SA', window=29200)
  113. else:
  114. reply_tcp = TCP(sport=dport, dport=sport, seq=0, ack=1, flags='SA', window=29200,
  115. options=[('MSS', mss)])
  116. # reply_tcp.time = time_sec_start + random.uniform(0.00005, 0.00013)
  117. reply = (reply_ether / reply_ip / reply_tcp)
  118. timestamp_next_pkt = update_timestamp(timestamp_next_pkt, pps, maxdelay)
  119. reply.time = timestamp_next_pkt
  120. packets.append(reply)
  121. # requester confirms
  122. confirm_ether = request_ether
  123. confirm_ip = request_ip
  124. confirm_tcp = TCP(sport=sport, dport=dport, seq=1, window=0, flags='R')
  125. reply = (confirm_ether / confirm_ip / confirm_tcp)
  126. timestamp_next_pkt = update_timestamp(timestamp_next_pkt, pps, maxdelay)
  127. reply.time = timestamp_next_pkt
  128. packets.append(reply)
  129. # else: # destination port is NOT OPEN -> no reply is sent by target
  130. # reply_tcp = TCP(sport=dport, dport=sport, flags='RA', seq=1, ack=1, window=0)
  131. # # reply_tcp.time = time_sec_start + random.uniform(0.00005, 0.00013)
  132. # reply = (reply_ether / reply_ip / reply_tcp)
  133. # timestamp_next_pkt = update_timestamp(timestamp_next_pkt, pps, maxdelay)
  134. # reply.time = timestamp_next_pkt
  135. # packets.append(reply)
  136. # store end time of attack
  137. self.attack_end_utime = reply.time
  138. # return packets sorted by packet time_sec_start
  139. return sorted(packets, key=lambda pkt: pkt.time)