|
@@ -9,6 +9,8 @@ import os
|
|
from Attack import BaseAttack
|
|
from Attack import BaseAttack
|
|
from Attack.AttackParameters import Parameter as Param
|
|
from Attack.AttackParameters import Parameter as Param
|
|
from Attack.AttackParameters import ParameterTypes
|
|
from Attack.AttackParameters import ParameterTypes
|
|
|
|
+# from ID2TLib import PcapFile
|
|
|
|
+# from ID2TLib.PcapFile import PcapFile
|
|
|
|
|
|
class MessageType(Enum):
|
|
class MessageType(Enum):
|
|
"""
|
|
"""
|
|
@@ -63,6 +65,8 @@ from ID2TLib import FileUtils, Generator
|
|
from ID2TLib.PcapAddressOperations import PcapAddressOperations
|
|
from ID2TLib.PcapAddressOperations import PcapAddressOperations
|
|
from ID2TLib.CommunicationProcessor import CommunicationProcessor
|
|
from ID2TLib.CommunicationProcessor import CommunicationProcessor
|
|
from ID2TLib.Botnet.MessageMapping import MessageMapping
|
|
from ID2TLib.Botnet.MessageMapping import MessageMapping
|
|
|
|
+from ID2TLib.PcapFile import PcapFile
|
|
|
|
+from ID2TLib.Statistics import Statistics
|
|
|
|
|
|
|
|
|
|
class MembersMgmtCommAttack(BaseAttack.BaseAttack):
|
|
class MembersMgmtCommAttack(BaseAttack.BaseAttack):
|
|
@@ -72,12 +76,12 @@ class MembersMgmtCommAttack(BaseAttack.BaseAttack):
|
|
|
|
|
|
"""
|
|
"""
|
|
# Initialize communication
|
|
# Initialize communication
|
|
- super(MembersMgmtCommAttack, self).__init__("Membership Management Communication Attack (MembersMgmtCommAttack)",
|
|
|
|
|
|
+ super(MembersMgmtCommAttack, self).__init__("Membership Management Communication Attack (MembersMgmtCommAttack)",
|
|
"Injects Membership Management Communication", "Botnet communication")
|
|
"Injects Membership Management Communication", "Botnet communication")
|
|
|
|
|
|
# Define allowed parameters and their type
|
|
# Define allowed parameters and their type
|
|
self.supported_params = {
|
|
self.supported_params = {
|
|
- # parameters regarding attack
|
|
|
|
|
|
+ # parameters regarding attack
|
|
Param.INJECT_AT_TIMESTAMP: ParameterTypes.TYPE_FLOAT,
|
|
Param.INJECT_AT_TIMESTAMP: ParameterTypes.TYPE_FLOAT,
|
|
Param.INJECT_AFTER_PACKET: ParameterTypes.TYPE_PACKET_POSITION,
|
|
Param.INJECT_AFTER_PACKET: ParameterTypes.TYPE_PACKET_POSITION,
|
|
Param.PACKETS_PER_SECOND: ParameterTypes.TYPE_FLOAT,
|
|
Param.PACKETS_PER_SECOND: ParameterTypes.TYPE_FLOAT,
|
|
@@ -111,7 +115,7 @@ class MembersMgmtCommAttack(BaseAttack.BaseAttack):
|
|
def init_params(self):
|
|
def init_params(self):
|
|
"""
|
|
"""
|
|
Initialize some parameters of this communication-attack using the user supplied command line parameters.
|
|
Initialize some parameters of this communication-attack using the user supplied command line parameters.
|
|
- The remaining parameters are implicitly set in the provided data file. Note: the timestamps in the file
|
|
|
|
|
|
+ The remaining parameters are implicitly set in the provided data file. Note: the timestamps in the file
|
|
have to be sorted in ascending order
|
|
have to be sorted in ascending order
|
|
|
|
|
|
:param statistics: Reference to a statistics object.
|
|
:param statistics: Reference to a statistics object.
|
|
@@ -146,7 +150,7 @@ class MembersMgmtCommAttack(BaseAttack.BaseAttack):
|
|
self.add_param_value(Param.PACKET_PADDING, 20)
|
|
self.add_param_value(Param.PACKET_PADDING, 20)
|
|
|
|
|
|
|
|
|
|
-
|
|
|
|
|
|
+
|
|
def generate_attack_pcap(self, context):
|
|
def generate_attack_pcap(self, context):
|
|
# create the final messages that have to be sent, including all bot configurations
|
|
# create the final messages that have to be sent, including all bot configurations
|
|
messages = self._create_messages(context)
|
|
messages = self._create_messages(context)
|
|
@@ -180,17 +184,17 @@ class MembersMgmtCommAttack(BaseAttack.BaseAttack):
|
|
duration = msg.time - messages[0].time
|
|
duration = msg.time - messages[0].time
|
|
|
|
|
|
# if total number of packets has been sent or the attack duration has been exceeded, stop
|
|
# if total number of packets has been sent or the attack duration has been exceeded, stop
|
|
- if ((limit_packetcount is not None and total_pkts >= limit_packetcount) or
|
|
|
|
|
|
+ if ((limit_packetcount is not None and total_pkts >= limit_packetcount) or
|
|
(limit_duration is not None and duration >= limit_duration)):
|
|
(limit_duration is not None and duration >= limit_duration)):
|
|
break
|
|
break
|
|
-
|
|
|
|
|
|
+
|
|
# if the type of the message is a NL reply, determine the number of entries
|
|
# if the type of the message is a NL reply, determine the number of entries
|
|
- nl_size = 0
|
|
|
|
|
|
+ nl_size = 0
|
|
if msg.type == MessageType.SALITY_NL_REPLY:
|
|
if msg.type == MessageType.SALITY_NL_REPLY:
|
|
- nl_size = randint(1, 25) # what is max NL entries?
|
|
|
|
|
|
+ nl_size = randint(1, 25) # what is max NL entries?
|
|
|
|
|
|
# create suitable IP/UDP packet and add to packets list
|
|
# create suitable IP/UDP packet and add to packets list
|
|
- packet = pkt_gen.generate_mmcom_packet(ip_src=ip_src, ip_dst=ip_dst, ttl=ttl, mac_src=mac_src, mac_dst=mac_dst,
|
|
|
|
|
|
+ packet = pkt_gen.generate_mmcom_packet(ip_src=ip_src, ip_dst=ip_dst, ttl=ttl, mac_src=mac_src, mac_dst=mac_dst,
|
|
port_src=port_src, port_dst=port_dst, message_type=msg.type, neighborlist_entries=nl_size)
|
|
port_src=port_src, port_dst=port_dst, message_type=msg.type, neighborlist_entries=nl_size)
|
|
Generator.add_padding(packet, padding,True, True)
|
|
Generator.add_padding(packet, padding,True, True)
|
|
|
|
|
|
@@ -236,7 +240,7 @@ class MembersMgmtCommAttack(BaseAttack.BaseAttack):
|
|
:param new_ips: the newly generated IPs that should be assigned to some, or all, IDs
|
|
:param new_ips: the newly generated IPs that should be assigned to some, or all, IDs
|
|
:param bot_configs: the existing configurations for the bots
|
|
:param bot_configs: the existing configurations for the bots
|
|
:param idtype: the locality type of the IDs
|
|
:param idtype: the locality type of the IDs
|
|
- :param router_mac: the MAC address of the router in the PCAP
|
|
|
|
|
|
+ :param router_mac: the MAC address of the router in the PCAP
|
|
"""
|
|
"""
|
|
|
|
|
|
ids = ids_to_add.copy()
|
|
ids = ids_to_add.copy()
|
|
@@ -292,6 +296,31 @@ class MembersMgmtCommAttack(BaseAttack.BaseAttack):
|
|
else:
|
|
else:
|
|
bot_configs[bot]["TTL"] = self.statistics.process_db_query("most_used(ttlValue)")
|
|
bot_configs[bot]["TTL"] = self.statistics.process_db_query("most_used(ttlValue)")
|
|
|
|
|
|
|
|
+ def assign_realworld_ttls(bot_configs):
|
|
|
|
+ '''
|
|
|
|
+ Assigns realistic ttl values to each bot from a realworld pcap file.
|
|
|
|
+ :param bot_configs: the existing configurations for the bots
|
|
|
|
+ '''
|
|
|
|
+
|
|
|
|
+ # create a PcapFile
|
|
|
|
+ pcap = PcapFile("resources/oc48-mfn.dirB.20030424-074500.UTC.anon.pcap")
|
|
|
|
+ # create new instance of an Statistics Object
|
|
|
|
+ stat = Statistics(pcap)
|
|
|
|
+ # recalculate the statistic, because there doesn't exist one
|
|
|
|
+ stat.load_pcap_statistics(False, True, False) # does not work! Why? Won't create DB
|
|
|
|
+ bot_ttl_dist = stat.get_ttl_distribution("*")
|
|
|
|
+ # assign local and external TTL randomly
|
|
|
|
+ for pos,bot in enumerate(sorted(bot_configs.keys())):
|
|
|
|
+ bot_type = bot_configs[bot]["Type"]
|
|
|
|
+ if bot_type == "local":
|
|
|
|
+ bot_configs[bot]["TTL"] = 128
|
|
|
|
+ else:
|
|
|
|
+ source_ttl_prob_dict = Lea.fromValFreqsDict(bot_ttl_dist)
|
|
|
|
+ bot_configs[bot]["TTL"] = source_ttl_prob_dict.random()
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
|
|
def add_delay(timestamp: float, minDelay: float, delay: float):
|
|
def add_delay(timestamp: float, minDelay: float, delay: float):
|
|
'''
|
|
'''
|
|
@@ -337,7 +366,7 @@ class MembersMgmtCommAttack(BaseAttack.BaseAttack):
|
|
|
|
|
|
# prefer XML input over CSV input (in case both are given)
|
|
# prefer XML input over CSV input (in case both are given)
|
|
if filepath_csv and filepath_xml == self.DEFAULT_XML_PATH:
|
|
if filepath_csv and filepath_xml == self.DEFAULT_XML_PATH:
|
|
- filepath_xml = FileUtils.parse_csv_to_xml(filepath_csv)
|
|
|
|
|
|
+ filepath_xml = FileUtils.parse_csv_to_xml(filepath_csv)
|
|
filepath_xml = move_xml_to_outdir(filepath_xml)
|
|
filepath_xml = move_xml_to_outdir(filepath_xml)
|
|
|
|
|
|
|
|
|
|
@@ -391,14 +420,14 @@ class MembersMgmtCommAttack(BaseAttack.BaseAttack):
|
|
number_local_ids, number_external_ids = len(local_ids), len(external_ids)
|
|
number_local_ids, number_external_ids = len(local_ids), len(external_ids)
|
|
# assign addresses for local IDs
|
|
# assign addresses for local IDs
|
|
if number_local_ids > 0:
|
|
if number_local_ids > 0:
|
|
- reuse_count_local = int(reuse_percent_total * reuse_percent_local * number_local_ids)
|
|
|
|
|
|
+ reuse_count_local = int(reuse_percent_total * reuse_percent_local * number_local_ids)
|
|
existing_local_ips = sorted(pcapops.get_existing_local_ips(reuse_count_local))
|
|
existing_local_ips = sorted(pcapops.get_existing_local_ips(reuse_count_local))
|
|
new_local_ips = sorted(pcapops.get_new_local_ips(number_local_ids - len(existing_local_ips)))
|
|
new_local_ips = sorted(pcapops.get_new_local_ips(number_local_ids - len(existing_local_ips)))
|
|
add_ids_to_config(sorted(local_ids), existing_local_ips, new_local_ips, bot_configs)
|
|
add_ids_to_config(sorted(local_ids), existing_local_ips, new_local_ips, bot_configs)
|
|
|
|
|
|
# assign addresses for external IDs
|
|
# assign addresses for external IDs
|
|
if number_external_ids > 0:
|
|
if number_external_ids > 0:
|
|
- reuse_count_external = int(reuse_percent_total * reuse_percent_external * number_external_ids)
|
|
|
|
|
|
+ reuse_count_external = int(reuse_percent_total * reuse_percent_external * number_external_ids)
|
|
existing_external_ips = sorted(pcapops.get_existing_external_ips(reuse_count_external))
|
|
existing_external_ips = sorted(pcapops.get_existing_external_ips(reuse_count_external))
|
|
remaining = len(external_ids) - len(existing_external_ips)
|
|
remaining = len(external_ids) - len(existing_external_ips)
|
|
new_external_ips = sorted([ipgen.random_ip() for _ in range(remaining)])
|
|
new_external_ips = sorted([ipgen.random_ip() for _ in range(remaining)])
|
|
@@ -435,8 +464,8 @@ class MembersMgmtCommAttack(BaseAttack.BaseAttack):
|
|
if int(req_msg.src) < int(req_msg.dst):
|
|
if int(req_msg.src) < int(req_msg.dst):
|
|
hello_time = hello_times[(req_msg.src, req_msg.dst)]
|
|
hello_time = hello_times[(req_msg.src, req_msg.dst)]
|
|
else:
|
|
else:
|
|
- hello_time = hello_times[(req_msg.dst, req_msg.src)]
|
|
|
|
-
|
|
|
|
|
|
+ hello_time = hello_times[(req_msg.dst, req_msg.src)]
|
|
|
|
+
|
|
if next_timestamp < hello_time:
|
|
if next_timestamp < hello_time:
|
|
# use the time of the hello_reply instead of next_timestamp to update this pair of messages
|
|
# use the time of the hello_reply instead of next_timestamp to update this pair of messages
|
|
post_hello = add_delay(hello_time, minDelay, equi_timeslice)
|
|
post_hello = add_delay(hello_time, minDelay, equi_timeslice)
|
|
@@ -461,7 +490,7 @@ class MembersMgmtCommAttack(BaseAttack.BaseAttack):
|
|
hello_times[(req_msg.src, req_msg.dst)] = respns_msg.time
|
|
hello_times[(req_msg.src, req_msg.dst)] = respns_msg.time
|
|
else:
|
|
else:
|
|
hello_times[(req_msg.dst, req_msg.src)] = respns_msg.time
|
|
hello_times[(req_msg.dst, req_msg.src)] = respns_msg.time
|
|
-
|
|
|
|
|
|
+
|
|
# create port configurations for the bots
|
|
# create port configurations for the bots
|
|
for bot in bot_configs:
|
|
for bot in bot_configs:
|
|
bot_configs[bot]["Port"] = Generator.gen_random_server_port()
|
|
bot_configs[bot]["Port"] = Generator.gen_random_server_port()
|
|
@@ -471,6 +500,8 @@ class MembersMgmtCommAttack(BaseAttack.BaseAttack):
|
|
|
|
|
|
# assign realistic TTL for every bot
|
|
# assign realistic TTL for every bot
|
|
assign_realistic_ttls(bot_configs)
|
|
assign_realistic_ttls(bot_configs)
|
|
|
|
+ # assign_realworld_ttls(bot_configs)
|
|
|
|
+
|
|
# put together the final messages including the full sender and receiver
|
|
# put together the final messages including the full sender and receiver
|
|
# configurations (i.e. IP, MAC, port, ...) for easier later use
|
|
# configurations (i.e. IP, MAC, port, ...) for easier later use
|
|
final_messages = []
|
|
final_messages = []
|
|
@@ -484,7 +515,7 @@ class MembersMgmtCommAttack(BaseAttack.BaseAttack):
|
|
# sort out messages that do not have a suitable locality setting
|
|
# sort out messages that do not have a suitable locality setting
|
|
if type_src == "external" and type_dst == "external":
|
|
if type_src == "external" and type_dst == "external":
|
|
continue
|
|
continue
|
|
-
|
|
|
|
|
|
+
|
|
msg.src, msg.dst = bot_configs[id_src], bot_configs[id_dst]
|
|
msg.src, msg.dst = bot_configs[id_src], bot_configs[id_dst]
|
|
msg.src["ID"], msg.dst["ID"] = id_src, id_dst
|
|
msg.src["ID"], msg.dst["ID"] = id_src, id_dst
|
|
msg.msg_id = new_id
|
|
msg.msg_id = new_id
|
|
@@ -504,4 +535,4 @@ class MembersMgmtCommAttack(BaseAttack.BaseAttack):
|
|
ts_last_date = datetime.strptime(self.statistics.get_pcap_timestamp_end(), ts_date_format)
|
|
ts_last_date = datetime.strptime(self.statistics.get_pcap_timestamp_end(), ts_date_format)
|
|
diff_date = ts_last_date - ts_first_date
|
|
diff_date = ts_last_date - ts_first_date
|
|
duration = "%d.%d" % (diff_date.total_seconds(), diff_date.microseconds)
|
|
duration = "%d.%d" % (diff_date.total_seconds(), diff_date.microseconds)
|
|
- return duration
|
|
|
|
|
|
+ return duration
|