PortscanAttack.py 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  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_ipAddress = self.statistics.process_db_query("most_used(ipAddress)")
  38. self.add_param_value(Param.IP_SOURCE, most_used_ipAddress)
  39. self.add_param_value(Param.IP_SOURCE_RANDOMIZE, 'False')
  40. self.add_param_value(Param.IP_DESTINATION, '192.168.178.13')
  41. self.add_param_value(Param.PORT_DESTINATION, '0-1023,1720,1900,8080')
  42. self.add_param_value(Param.PORT_SOURCE, '8542')
  43. self.add_param_value(Param.PORT_OPEN, '8080,9232,9233')
  44. self.add_param_value(Param.PORT_SOURCE_RANDOM, 'False')
  45. self.add_param_value(Param.PORT_DEST_SHUFFLE, 'False')
  46. self.add_param_value(Param.PORT_ORDER_DESC, 'False')
  47. self.add_param_value(Param.MAC_SOURCE, 'macAddress(ipAddress=' + most_used_ipAddress + ')')
  48. self.add_param_value(Param.MAC_DESTINATION, 'A0:1A:28:0B:62:F4')
  49. self.add_param_value(Param.PACKETS_PER_SECOND, self.statistics.get_pps_sent(most_used_ipAddress))
  50. self.add_param_value(Param.INJECT_AT_TIMESTAMP, '1410733342') # Sun, 14 Sep 2014 22:22:22 GMT
  51. def get_packets(self):
  52. def get_timestamp():
  53. """
  54. Calculates the next timestamp and returns the timestamp to be used for the current packet.
  55. :return: Timestamp to be used for the current packet.
  56. """
  57. nonlocal timestamp_next_pkt, pps, maxdelay
  58. timestamp_current_packet = timestamp_next_pkt # current timestamp
  59. #TODO Derive timestamps based on pps rate given
  60. timestamp_next_pkt = timestamp_next_pkt + uniform(0.1 / pps, maxdelay) # timestamp for next pkt
  61. return timestamp_current_packet
  62. # Determine ports
  63. dest_ports = self.get_param_value(Param.PORT_DESTINATION)
  64. if self.get_param_value(Param.PORT_ORDER_DESC):
  65. dest_ports.reverse()
  66. elif self.get_param_value(Param.PORT_DEST_SHUFFLE):
  67. shuffle(dest_ports)
  68. if self.get_param_value(Param.PORT_SOURCE_RANDOM):
  69. sport = randint(0, 65535)
  70. else:
  71. sport = self.get_param_value(Param.PORT_SOURCE)
  72. # Get TTL distribution
  73. # keys = list(self.statistics.get_ttl_distribution().vals()
  74. # values = list(self.statistics.get_ttl_distribution().pmf())
  75. # TTL_samples = numpy.random.choice(keys, size=len(dest_ports), replace=True, dport=values)
  76. ttl_value = self.statistics.process_db_query("most_used(ttlValue)")
  77. # MSS (Maximum Segment Size) for Ethernet. Allowed values [536,1500]
  78. mss = ('MSS', int(self.statistics.process_db_query('avg(mss)')))
  79. # Timestamp
  80. timestamp_next_pkt = self.get_param_value(Param.INJECT_AT_TIMESTAMP)
  81. self.attack_start_utime = timestamp_next_pkt # store start time of attack
  82. pps = self.get_param_value(Param.PACKETS_PER_SECOND)
  83. randomdelay = Lea.fromValFreqsDict({1 / pps: 70, 2 / pps: 30, 5 / pps: 15, 10 / pps: 3})
  84. maxdelay = randomdelay.random()
  85. # Initialize parameters
  86. packets = []
  87. ip_source = self.get_param_value(Param.IP_SOURCE)
  88. ip_destination = self.get_param_value(Param.IP_DESTINATION)
  89. mac_source = self.get_param_value(Param.MAC_SOURCE)
  90. mac_destination = self.get_param_value(Param.MAC_DESTINATION)
  91. for dport in dest_ports:
  92. # Parameters changing each iteration
  93. if self.get_param_value(Param.IP_SOURCE_RANDOMIZE) and isinstance(ip_source, list):
  94. ip_source = choice(ip_source)
  95. # 1) Build request package
  96. request_ether = Ether(src=mac_source, dst=mac_destination)
  97. request_ip = IP(src=ip_source, dst=ip_destination, ttl=ttl_value)
  98. request_tcp = TCP(sport=sport, dport=dport)
  99. request = (request_ether / request_ip / request_tcp)
  100. request.time = get_timestamp()
  101. packets.append(request)
  102. # 2) Build reply package
  103. reply_ether = Ether(src=mac_destination, dst=mac_source)
  104. reply_ip = IP(src=ip_destination, dst=ip_source, flags='DF')
  105. if str(dport) in self.get_param_value(Param.PORT_OPEN): # destination port is OPEN
  106. # target answers
  107. reply_tcp = TCP(sport=dport, dport=sport, seq=0, ack=1, flags='SA', window=29200,
  108. options=[mss])
  109. # reply_tcp.time = time_sec_start + random.uniform(0.00005, 0.00013)
  110. reply = (reply_ether / reply_ip / reply_tcp)
  111. reply.time = get_timestamp()
  112. packets.append(reply)
  113. # requester confirms
  114. confirm_ether = request_ether
  115. confirm_ip = request_ip
  116. confirm_tcp = TCP(sport=sport, dport=dport, seq=1, window=0, flags='R')
  117. reply = (confirm_ether / confirm_ip / confirm_tcp)
  118. reply.time = get_timestamp()
  119. packets.append(reply)
  120. else: # destination port is NOT OPEN
  121. reply_tcp = TCP(sport=dport, dport=sport, flags='RA', seq=1, ack=1, window=0)
  122. # reply_tcp.time = time_sec_start + random.uniform(0.00005, 0.00013)
  123. reply = (reply_ether / reply_ip / reply_tcp)
  124. reply.time = get_timestamp()
  125. packets.append(reply)
  126. # store end time of attack
  127. self.attack_end_utime = reply.time
  128. # return packets sorted by packet time_sec_start
  129. return sorted(packets, key=lambda pkt: pkt.time)