123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221 |
- import logging
- import random as rnd
- import scapy.layers.inet as inet
- from scapy.layers.netbios import NBTSession
- import Attack.AttackParameters as atkParam
- import Attack.BaseAttack as BaseAttack
- import ID2TLib.SMBLib as SMBLib
- import ID2TLib.Utility as Util
- logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
- # noinspection PyPep8
- class SMBLorisAttack(BaseAttack.BaseAttack):
- def __init__(self):
- """
- Creates a new instance of the SMBLorisAttack.
- This attack injects special SMB-packets, which exploit the SMBLoris DoS vulnerability, into the output pcap
- file.
- """
- # Initialize attack
- super(SMBLorisAttack, self).__init__("SMBLoris Attack", "Injects an SMBLoris (D)DoS Attack",
- "Resource Exhaustion")
- # Define allowed parameters and their type
- self.supported_params.update({
- atkParam.Parameter.IP_SOURCE: atkParam.ParameterTypes.TYPE_IP_ADDRESS,
- atkParam.Parameter.IP_DESTINATION: atkParam.ParameterTypes.TYPE_IP_ADDRESS,
- atkParam.Parameter.MAC_SOURCE: atkParam.ParameterTypes.TYPE_MAC_ADDRESS,
- atkParam.Parameter.MAC_DESTINATION: atkParam.ParameterTypes.TYPE_MAC_ADDRESS,
- atkParam.Parameter.INJECT_AT_TIMESTAMP: atkParam.ParameterTypes.TYPE_FLOAT,
- atkParam.Parameter.INJECT_AFTER_PACKET: atkParam.ParameterTypes.TYPE_PACKET_POSITION,
- atkParam.Parameter.PACKETS_PER_SECOND: atkParam.ParameterTypes.TYPE_FLOAT,
- atkParam.Parameter.ATTACK_DURATION: atkParam.ParameterTypes.TYPE_INTEGER_POSITIVE,
- atkParam.Parameter.NUMBER_ATTACKERS: atkParam.ParameterTypes.TYPE_INTEGER_POSITIVE
- })
- def init_params(self):
- """
- Initialize the parameters of this attack using the user supplied command line parameters.
- Use the provided statistics to calculate default parameters and to process user
- supplied queries.
- """
- # PARAMETERS: initialize with default values
- # (values are overwritten if user specifies them)
- most_used_ip_address = self.statistics.get_most_used_ip_address()
- # The most used IP class in background traffic
- most_used_ip_class = Util.handle_most_used_outputs(self.statistics.get_most_used_ip_class())
- num_attackers = rnd.randint(1, 16)
- source_ip = self.generate_random_ipv4_address(most_used_ip_class, num_attackers)
- self.add_param_value(atkParam.Parameter.IP_SOURCE, source_ip)
- self.add_param_value(atkParam.Parameter.MAC_SOURCE, self.generate_random_mac_address(num_attackers))
- random_ip_address = self.statistics.get_random_ip_address()
- # ip-dst should be valid and not equal to ip.src
- while not self.is_valid_ip_address(random_ip_address) or random_ip_address == source_ip:
- random_ip_address = self.statistics.get_random_ip_address()
- self.add_param_value(atkParam.Parameter.IP_DESTINATION, random_ip_address)
- destination_mac = self.statistics.get_mac_address(random_ip_address)
- if isinstance(destination_mac, list) and len(destination_mac) == 0:
- destination_mac = self.generate_random_mac_address()
- self.add_param_value(atkParam.Parameter.MAC_DESTINATION, destination_mac)
- self.add_param_value(atkParam.Parameter.PACKETS_PER_SECOND,
- (self.statistics.get_pps_sent(most_used_ip_address) +
- self.statistics.get_pps_received(most_used_ip_address)) / 2)
- self.add_param_value(atkParam.Parameter.INJECT_AFTER_PACKET, rnd.randint(0, self.statistics.get_packet_count()))
- self.add_param_value(atkParam.Parameter.ATTACK_DURATION, 30)
- def generate_attack_packets(self):
- """
- Creates the attack packets.
- """
- pps = self.get_param_value(atkParam.Parameter.PACKETS_PER_SECOND)
- # Timestamp
- first_timestamp = self.get_param_value(atkParam.Parameter.INJECT_AT_TIMESTAMP)
- # store start time of attack
- self.attack_start_utime = first_timestamp
- # Initialize parameters
- self.packets = []
- ip_destination = self.get_param_value(atkParam.Parameter.IP_DESTINATION)
- mac_destination = self.get_param_value(atkParam.Parameter.MAC_DESTINATION)
- # Determine source IP and MAC address
- num_attackers = self.get_param_value(atkParam.Parameter.NUMBER_ATTACKERS)
- # user supplied atkParam.Parameter.NUMBER_ATTACKERS
- if (num_attackers is not None) and (num_attackers is not 0):
- # The most used IP class in background traffic
- most_used_ip_class = Util.handle_most_used_outputs(self.statistics.get_most_used_ip_class())
- # Create random attackers based on user input atkParam.Parameter.NUMBER_ATTACKERS
- ip_source = self.generate_random_ipv4_address(most_used_ip_class, num_attackers)
- mac_source = self.generate_random_mac_address(num_attackers)
- else: # user did not supply atkParam.Parameter.NUMBER_ATTACKS
- # use default values for IP_SOURCE/MAC_SOURCE or overwritten values
- # if user supplied any values for those params
- ip_source = self.get_param_value(atkParam.Parameter.IP_SOURCE)
- mac_source = self.get_param_value(atkParam.Parameter.MAC_SOURCE)
- ip_source_list = []
- mac_source_list = []
- if isinstance(ip_source, list):
- ip_source_list = ip_source
- else:
- ip_source_list.append(ip_source)
- if isinstance(mac_source, list):
- mac_source_list = mac_source
- else:
- mac_source_list.append(mac_source)
- if (num_attackers is None) or (num_attackers is 0):
- num_attackers = min(len(ip_source_list), len(mac_source_list))
- # Check ip.src == ip.dst
- self.ip_src_dst_equal_check(ip_source_list, ip_destination)
- # Get MSS, TTL and Window size value for destination IP
- destination_mss_value, destination_ttl_value, destination_win_value = self.get_ip_data(ip_destination)
- min_delay, max_delay = self.get_reply_delay(ip_destination)
- attack_duration = self.get_param_value(atkParam.Parameter.ATTACK_DURATION)
- attack_ends_time = first_timestamp + attack_duration
- victim_pps = pps * num_attackers
- for attacker in range(num_attackers):
- # Get MSS, TTL and Window size value for source IP(attacker)
- source_mss_value, source_ttl_value, source_win_value = self.get_ip_data(ip_source_list[attacker])
- attacker_seq = rnd.randint(1000, 50000)
- victim_seq = rnd.randint(1000, 50000)
- sport = 1025
- # Timestamps of first self.packets shouldn't be exactly the same to look more realistic
- timestamp_next_pkt = rnd.uniform(first_timestamp, Util.update_timestamp(first_timestamp, pps))
- while timestamp_next_pkt <= attack_ends_time:
- # Establish TCP connection
- if sport > 65535:
- sport = 1025
- # prepare reusable Ethernet- and IP-headers
- attacker_ether = inet.Ether(src=mac_source_list[attacker], dst=mac_destination)
- attacker_ip = inet.IP(src=ip_source_list[attacker], dst=ip_destination, ttl=source_ttl_value,
- flags='DF')
- victim_ether = inet.Ether(src=mac_destination, dst=mac_source_list[attacker])
- victim_ip = inet.IP(src=ip_destination, dst=ip_source_list[attacker], ttl=destination_ttl_value,
- flags='DF')
- # connection request from attacker (client)
- syn_tcp = inet.TCP(sport=sport, dport=SMBLib.smb_port, window=source_win_value, flags='S',
- seq=attacker_seq, options=[('MSS', source_mss_value)])
- attacker_seq += 1
- syn = (attacker_ether / attacker_ip / syn_tcp)
- syn.time = timestamp_next_pkt
- timestamp_next_pkt = Util.update_timestamp(timestamp_next_pkt, victim_pps, min_delay)
- self.packets.append(syn)
- # response from victim (server)
- synack_tcp = inet.TCP(sport=SMBLib.smb_port, dport=sport, seq=victim_seq, ack=attacker_seq, flags='SA',
- window=destination_win_value, options=[('MSS', destination_mss_value)])
- victim_seq += 1
- synack = (victim_ether / victim_ip / synack_tcp)
- synack.time = timestamp_next_pkt
- timestamp_next_pkt = Util.update_timestamp(timestamp_next_pkt, pps, min_delay)
- self.packets.append(synack)
- # acknowledgement from attacker (client)
- ack_tcp = inet.TCP(sport=sport, dport=SMBLib.smb_port, seq=attacker_seq, ack=victim_seq, flags='A',
- window=source_win_value, options=[('MSS', source_mss_value)])
- ack = (attacker_ether / attacker_ip / ack_tcp)
- ack.time = timestamp_next_pkt
- timestamp_next_pkt = Util.update_timestamp(timestamp_next_pkt, pps)
- self.packets.append(ack)
- # send NBT session header packet with maximum LENGTH-field
- req_tcp = inet.TCP(sport=sport, dport=SMBLib.smb_port, seq=attacker_seq, ack=victim_seq, flags='AP',
- window=source_win_value, options=[('MSS', source_mss_value)])
- req_payload = NBTSession(TYPE=0x00, LENGTH=0x1FFFF)
- attacker_seq += len(req_payload)
- req = (attacker_ether / attacker_ip / req_tcp / req_payload)
- req.time = timestamp_next_pkt
- timestamp_next_pkt = Util.update_timestamp(timestamp_next_pkt, victim_pps, min_delay)
- self.packets.append(req)
- # final ack from victim (server)
- last_ack_tcp = inet.TCP(sport=SMBLib.smb_port, dport=sport, seq=victim_seq, ack=attacker_seq, flags='A',
- window=destination_win_value, options=[('MSS', destination_mss_value)])
- last_ack = (victim_ether / victim_ip / last_ack_tcp)
- last_ack.time = timestamp_next_pkt
- timestamp_next_pkt = Util.update_timestamp(timestamp_next_pkt, pps, min_delay)
- self.packets.append(last_ack)
- sport += 1
- def generate_attack_pcap(self):
- """
- Creates a pcap containing the attack packets.
- :return: The location of the generated pcap file.
- """
- # store end time of attack
- self.attack_end_utime = self.packets[-1].time
- # write attack self.packets to pcap
- pcap_path = self.write_attack_pcap(sorted(self.packets, key=lambda pkt: pkt.time))
- # return packets sorted by packet time_sec_start
- return len(self.packets), pcap_path
|