SalityBotnet.py 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. import logging
  2. from random import randint, uniform
  3. from random import randint
  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. from scapy.utils import RawPcapReader
  13. from scapy.layers.inet import IP, Ether, TCP, RandShort
  14. class SalityBotnet(BaseAttack.BaseAttack):
  15. template_attack_pcap_path = "resources/sality_botnet.pcap"
  16. def __init__(self):
  17. """
  18. Creates a new instance of the Sality botnet.
  19. """
  20. # Initialize attack
  21. super(SalityBotnet, self).__init__("Sality Botnet", "Injects an Sality botnet'",
  22. "Botnet")
  23. # Define allowed parameters and their type
  24. self.supported_params = {
  25. Param.MAC_SOURCE: ParameterTypes.TYPE_MAC_ADDRESS,
  26. Param.IP_SOURCE: ParameterTypes.TYPE_IP_ADDRESS,
  27. Param.INJECT_AT_TIMESTAMP: ParameterTypes.TYPE_FLOAT,
  28. Param.INJECT_AFTER_PACKET: ParameterTypes.TYPE_PACKET_POSITION,
  29. Param.PACKETS_PER_SECOND: ParameterTypes.TYPE_FLOAT
  30. }
  31. def init_params(self):
  32. """
  33. Initialize the parameters of this attack using the user supplied command line parameters.
  34. Use the provided statistics to calculate default parameters and to process user
  35. supplied queries.
  36. :param statistics: Reference to a statistics object.
  37. """
  38. # PARAMETERS: initialize with default utilsvalues
  39. # (values are overwritten if user specifies them)
  40. most_used_ip_address = self.statistics.get_most_used_ip_address()
  41. if isinstance(most_used_ip_address, list):
  42. most_used_ip_address = most_used_ip_address[0]
  43. self.add_param_value(Param.IP_SOURCE, most_used_ip_address)
  44. self.add_param_value(Param.MAC_SOURCE, self.statistics.get_mac_address(most_used_ip_address))
  45. # Attack configuration
  46. self.add_param_value(Param.INJECT_AFTER_PACKET, randint(0, self.statistics.get_packet_count()))
  47. self.add_param_value(Param.PACKETS_PER_SECOND,
  48. (self.statistics.get_pps_sent(most_used_ip_address) +
  49. self.statistics.get_pps_received(most_used_ip_address)) / 2)
  50. def generate_attack_pcap(self, context):
  51. def update_timestamp(timestamp, pps):
  52. """
  53. Calculates the next timestamp to be used based on the packet per second rate (pps) and the maximum delay.
  54. :return: Timestamp to be used for the next packet.
  55. """
  56. # Calculate the request timestamp
  57. # A distribution to imitate the bursty behavior of traffic
  58. randomdelay = Lea.fromValFreqsDict({1 / pps: 70, 2 / pps: 20, 5 / pps: 7, 10 / pps: 3})
  59. return timestamp + uniform(1 / pps, randomdelay.random())
  60. def getIntervalPPS(complement_interval_pps, timestamp):
  61. """
  62. Gets the packet rate (pps) in specific time interval.
  63. :return: the corresponding packet rate for packet rate (pps) .
  64. """
  65. for row in complement_interval_pps:
  66. if timestamp <= row[0]:
  67. return row[1]
  68. return complement_interval_pps[-1][1] # in case the timstamp > capture max timestamp
  69. # Timestamp
  70. timestamp_next_pkt = self.get_param_value(Param.INJECT_AT_TIMESTAMP)
  71. pps = self.get_param_value(Param.PACKETS_PER_SECOND)
  72. # Calculate complement packet rates of BG traffic per interval
  73. complement_interval_pps = self.statistics.calculate_complement_packet_rates(pps)
  74. # Initialize parameters
  75. packets = []
  76. mac_source = self.get_param_value(Param.MAC_SOURCE)
  77. ip_source = self.get_param_value(Param.IP_SOURCE)
  78. # Pick a DNS server from the background traffic
  79. ip_dns_server = self.statistics.process_db_query("SELECT ipAddress FROM ip_protocols WHERE protocolName='DNS' ORDER BY protocolCount DESC LIMIT 1;")
  80. if not ip_dns_server or ip_source == ip_dns_server:
  81. ip_dns_server = self.statistics.get_random_ip_address()
  82. mac_dns_server = self.statistics.get_mac_address(ip_dns_server)
  83. # Bot original config in the template PCAP
  84. origin_mac_src = "08:00:27:e5:d7:b0"
  85. origin_ip_src = "10.0.2.15"
  86. origin_mac_dns_server = "52:54:00:12:35:02"
  87. origin_ip_dns_server = "10.0.2.2"
  88. ttl_map = {}
  89. ip_map = {origin_ip_src : ip_source, origin_ip_dns_server: ip_dns_server}
  90. mac_map = {origin_mac_src : mac_source, origin_mac_dns_server: mac_dns_server}
  91. path_attack_pcap = None
  92. # Inject Sality botnet
  93. # Read sality_botnet pcap file
  94. exploit_raw_packets = RawPcapReader(self.template_attack_pcap_path)
  95. for pkt_num, pkt in enumerate(exploit_raw_packets):
  96. eth_frame = Ether(pkt[0])
  97. ip_pkt = eth_frame.payload
  98. # Ether
  99. if eth_frame.getfieldval("src") in mac_map:
  100. eth_frame.setfieldval("src", mac_map[eth_frame.getfieldval("src")])
  101. if eth_frame.getfieldval("dst") in mac_map:
  102. eth_frame.setfieldval("dst", mac_map[eth_frame.getfieldval("dst")])
  103. # IP
  104. if ip_pkt.getfieldval("src") in ip_map:
  105. ip_pkt.setfieldval("src", ip_map[ip_pkt.getfieldval("src")])
  106. if ip_pkt.getfieldval("dst") in ip_map:
  107. ip_pkt.setfieldval("dst", ip_map[ip_pkt.getfieldval("dst")])
  108. ## TTL
  109. if ip_pkt.getfieldval("ttl") not in ttl_map:
  110. source_ttl = self.statistics.get_most_used_ttl(ip_pkt.getfieldval("src"))
  111. if not source_ttl:
  112. source_ttl = self.statistics.process_db_query("SELECT ttlValue FROM ip_ttl ORDER BY RANDOM() LIMIT 1;")
  113. ttl_map[ip_pkt.getfieldval("ttl")] = source_ttl
  114. ip_pkt.setfieldval("ttl", ttl_map[ip_pkt.getfieldval("ttl")])
  115. new_pkt = (eth_frame / ip_pkt)
  116. new_pkt.time = timestamp_next_pkt
  117. pps = max(getIntervalPPS(complement_interval_pps, timestamp_next_pkt), 10)
  118. timestamp_next_pkt = update_timestamp(timestamp_next_pkt, pps)
  119. packets.append(new_pkt)
  120. # Store timestamp of first packet (for attack label)
  121. self.attack_start_utime = packets[0].time
  122. self.attack_end_utime = packets[-1].time
  123. if len(packets) > 0:
  124. packets = sorted(packets, key=lambda pkt: pkt.time)
  125. path_attack_pcap = self.write_attack_pcap(packets, True, path_attack_pcap)
  126. # return packets sorted by packet time_sec_start
  127. # pkt_num+1: because pkt_num starts at 0
  128. return pkt_num + 1, path_attack_pcap