"""
The attacker module is used for simualtion predefined attacks.
Messages between clients and servers are passed through the attacker and modified for attacks.
The attacker runs as a single process.
"""
import multiprocessing
import random
import time
import collections
import sys
import imp
from src import Msg
from src import Configuration
from src import SomeIPPacket
[docs]class Attacker(object):
"""
Initializes the Attacker.
:param config: Own config
:param clientConfigs: List of all available client configurations
:param clientQueues: List of all available Client queues to pass messages to the client
:param serverConfigs: List of all available server configurations
:param serverQueues: List of all available Client queues to pass messages to the client
:param writer: Writer queue to pass messages to that are send on the interface or written to the .pcap file
:param conter: Number of attacks to be executed, can be set to 0 to create dumps without attacks
:param attacks: List of attacks that can be executed during runtime, those values can be configured using the configuration file
:param attackerQueue: Own queue messages from all clients and servers are passed to
:param attackers: Other attackers whos messages can be ignored and are not attacked
:param verbose: can be set to True for additional output, default=False
:returns: configured Attacker Object
"""
def __init__(self, config, clientConfigs, clientQueues, serverConfigs, serverQueues, writer, counter, attacks, attackerQueue, attackers, verbose=False):
self.config = config
self.clientConfigs = clientConfigs
self.clientQueues = clientQueues
self.serverConfigs = serverConfigs
self.serverQueues = serverQueues
self.attackerQueue=attackerQueue
self.attackers = attackers
self.writerQueue = writer
self.counter = counter
self.attacks = attacks
self.verbose = verbose
[docs] def setIntervalMin(self, intervalMin):
""" Set the minimum Interval an attacker will respond. The interval is given as int im ms."""
self.intervalMin = intervalMin
[docs] def setIntervalMax(self, intervalMax):
""" Set the maximum Interval an attacker will respond. The interval is given as int im ms."""
self.intervalMax = intervalMax
[docs] def setName(self, name):
""" Set the internal Name of the attacker, useful in case more attackers in verbose mode are used. The name is given as string. """
self.name = name
[docs] def setOwnClientID(self, clientID):
""" Set the own client ID of the attacker as the attacker is a legitime part of the network. The client id is given as int. """
self.clientID = clientID
def getUsedMethod(methods, methodIdUsed):
for elem in methods:
if elem['id'] == methodIdUsed:
return elem
return None
def getUsedService(services, serviceIdUsed):
for elem in services:
if elem['id'] == serviceIdUsed:
return elem
return None
[docs]def randomErrorCode():
""" Attack that replaces a correct Error Code with an arbitrary one that might is not correct for the situation. """
errorCode = random.choice(list(SomeIPPacket.errorCodes.keys()))
return SomeIPPacket.errorCodes[errorCode]
def str2bool(s):
if s == 'True' or s == 'true':
return True
else:
return False
def setTimestamp(timestamp, intervalMin, intervalMax):
newTS = timestamp + random.uniform(intervalMin, intervalMax)
return newTS
[docs]def doAttack(curAttack, msgOrig, a, attacksSuc):
"""
Execute one of the predefined attacks that are configured to be executed.
:param curAttack: Choosen current attack.
:param msgOrig: Original message the attack is applied to.
:param a: Attacker Object containing all needed configurations and information.
:param attacksSuc: Counter for successfully executed attacks.
:returns: Triple(Boolean, Boolean, Int), First entry means that the original message is forwarded or not, The second part means attack was successfull, the last value indicates the number of successfully executed attacks.
"""
RetVal = curAttack.doAttack(curAttack, msgOrig, a, attacksSuc)
if RetVal['msg'] != None and RetVal['msg'] != 'Forward':
sendMsg(a, RetVal['msg'], msgOrig)
if RetVal['msg'] == 'Forward':
forward (a, msgOrig)
return (RetVal['attackOngoing'], RetVal['dropMsg'], RetVal['counter'])
[docs]def sendMsg(a, msg, msgOrig):
""" The Message Object is sent to the writer queue putting the Packet into the trace. """
msg.timestamp = setTimestamp(msgOrig.timestamp, a.intervalMin, a.intervalMax)
a.writerQueue.put(msg)
print (msg.receiver)
if msg.receiver in a.serverQueues:
a.serverQueues[msg.receiver].put(msg)
elif msg.receiver in a.clientQueues:
a.clientQueues[msg.receiver].put(msg)
else:
print ('Unkown Receiver.')
[docs]def forward (a, msg):
""" The message is going to be forwarded to its original receiver. """
print (msg.receiver)
if msg.receiver in a.clientQueues:
a.clientQueues[msg.receiver].put(msg)
elif msg.receiver in a.serverQueues:
a.serverQueues[msg.receiver].put(msg)
elif msg.receiver in a.attackers:
print (a.name, ' - Attack happend : ', msg.receiver)
else:
print ('Unkown Receiver.')
[docs]def loadAttacks(attacksToUse):
"""
Dynamically loads modules from attacks folder to perform configured attacks.
"""
modules = []
for attack in attacksToUse:
selectedModulePath = 'src/attacks/' + attack + '.py'
selectedModuleName = attack
my_module = imp.load_source(selectedModuleName, selectedModulePath)
modules.append(my_module)
return modules
[docs]def attacker (a):
"""
Main method of the module that is initializing needed data and executing the attacking loop.
The default value to set the minimum attacker response time is 0 ms.
The default value to set the maximum attacker response time is 10 ms.
Thoose values are used in case nothing is specified.
"""
name = multiprocessing.current_process().name
a.setName(name)
a.setOwnClientID(a.config['clientID'])
if a.attacks['min'] != None:
intervalMin = int(a.attacks['min'])
else:
intervalMin = 0
if a.attacks['max'] != None:
intervalMax = int(a.attacks['max'])
else:
intervalMax = 10
a.setIntervalMin(intervalMin)
a.setIntervalMax(intervalMax)
attacksToUse = [elem.strip() for elem in a.attacks['attacks'].split(',')]
if a.verbose:
print ('Configured Attacks: ', attacksToUse)
attacksConfigured = loadAttacks(attacksToUse)
if a.verbose:
print (a.name, ' - Attacker started - ')
print (a.name, ' - Client Configs: ', a.clientConfigs)
print (a.name, ' - Server Configs: ', a.serverConfigs)
print (a.name, ' - Attacks: ', a.attacks)
attackOngoing = False
dropMsg = False
attacksSuc = 0
while (True):
msg = a.attackerQueue.get()
dropMsg = False
# Writer is done, attacker can close
if (msg == 'Done'):
print (a.name, 'GOT DONE msg')
break
# ignore attacker messages
if (msg.receiver in a.attackers) or (msg.sender in a.attackers):
continue
if len(attacksConfigured) != 0:
if not attackOngoing:
attack = random.randint(1,a.counter)
if attack == 1:
if a.verbose:
print ('Do Attack now!')
curAttack = random.choice(attacksConfigured)
attackResult = doAttack(curAttack, msg, a, attacksSuc)
attackOngoing = attackResult[0]
dropMsg = attackResult[1]
attacksSuc = attackResult[2]
else:
attackResult = doAttack(curAttack, msg, a, attacksSuc)
attackOngoing = attackResult[0]
dropMsg = attackResult[1]
attacksSuc = attackResult[2]
if not dropMsg:
forward(a, msg)
a.writerQueue.put(msg)
print (a.name, ' - BREAK - with ', attacksSuc, ' successful attacks')
a.writerQueue.put('Done')