Skip to content

Commit 0e90113

Browse files
committed
hotfix into the simple_dos_attack
1 parent 71a4ab8 commit 0e90113

File tree

3 files changed

+104
-64
lines changed

3 files changed

+104
-64
lines changed

dhalsim/network_attacks/concealment_netfilter_queue.py

Lines changed: 83 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ class ConcealmentMiTMNetfilterQueue(PacketQueue):
2222

2323
def __init__(self, intermediate_yaml_path: Path, yaml_index: int, queue_number: int ):
2424
super().__init__(intermediate_yaml_path, yaml_index, queue_number)
25-
self.attacked_tag = self.intermediate_attack['tag']
25+
self.attacked_tags = self.intermediate_attack['tags']
26+
self.logger.debug('Attacked tags:' + str(self.attacked_tags))
2627
self.scada_session_ids = []
2728
self.attack_session_ids = []
2829
self.concealment_type = None
@@ -38,6 +39,70 @@ def __init__(self, intermediate_yaml_path: Path, yaml_index: int, queue_number:
3839

3940
self.logger.debug('Concealment type is: ' + str(self.concealment_type))
4041

42+
def get_attack_tag(self, a_tag_name):
43+
for tag in self.attacked_tags:
44+
if tag['tag'] == a_tag_name:
45+
return tag
46+
47+
def handle_enip_response(self, ip_payload):
48+
this_session = int.from_bytes(p[Raw].load[4:8], sys.byteorder)
49+
this_context = int.from_bytes(ip_payload[Raw].load[12:20], sys.byteorder)
50+
this_session_dict = None
51+
52+
# Attack values to PLCs
53+
for session in self.attack_session_ids:
54+
# We support multi tag sending, using the same session. Context varies among tags
55+
if session['session'] == this_session and session['context'] == this_context:
56+
this_session_dict = session
57+
for tag in self.intermediate_attack['tags']:
58+
if this_session_dict['tag'] == tag['tag']:
59+
if 'value' in tag['tag'].keys():
60+
return translate_float_to_payload(tag['value'], ip_payload[Raw].load)
61+
62+
elif 'offset' in tag['tag'].keys():
63+
return translate_float_to_payload(translate_payload_to_float(p[Raw].load) + tag['value'],
64+
ip_payload[Raw].load)
65+
66+
# Concealment values to SCADA
67+
for session in self.scada_session_ids:
68+
if session['session'] == this_session and session['context'] == this_context:
69+
this_session_dict = session
70+
for tag in self.intermediate_attack['tags']:
71+
if this_session_dict['tag'] == tag['tag']:
72+
self.logger.debug('Concealing to SCADA: ' + str(this_session))
73+
if self.concealment_type == 'path':
74+
exp = (self.concealment_data_pd['iteration'] == self.get_master_clock())
75+
concealment_value = float(self.concealment_data_pd.loc[exp][self.attacked_tags].values[-1])
76+
self.logger.debug('Concealing with value: ' + str(concealment_value))
77+
return translate_float_to_payload(concealment_value, ip_payload[Raw].load)
78+
elif self.concealment_type == 'value':
79+
concealment_value = self.intermediate_attack['concealment_data']['concealment_value']
80+
self.logger.debug('Concealment value is: ' + str(concealment_value))
81+
return translate_float_to_payload(concealment_value, ip_payload[Raw].load)
82+
83+
84+
def handle_enip_request(self, ip_payload, offset):
85+
86+
this_session = int.from_bytes(ip_payload[Raw].load[4:8], sys.byteorder)
87+
tag_name = ip_payload[Raw].load.decode(encoding='latin-1')[54:offset]
88+
context = int.from_bytes(ip_payload[Raw].load[12:20], sys.byteorder)
89+
90+
self.logger.debug('this tag is: ' + str(tag_name))
91+
this_tag = self.get_attack_tag(tag_name)
92+
93+
self.logger.debug('Tag name: ' + str(tag_name))
94+
self.logger.debug('Attack tag: ' + str(this_tag['tag']))
95+
session_dict = {'session': this_session, 'tag': this_tag['tag'], 'context': context}
96+
97+
if ip_payload[IP].src == self.intermediate_yaml['scada']['public_ip']:
98+
self.logger.debug('SCADA Req session')
99+
self.scada_session_ids.append(session_dict)
100+
101+
else:
102+
self.logger.debug('PLC Req session')
103+
self.attack_session_ids.append(session_dict)
104+
105+
41106
def capture(self, packet):
42107
"""
43108
This function is the function that will run in the thread started in the setup function.
@@ -47,65 +112,29 @@ def capture(self, packet):
47112
packet and delete the original checksum.
48113
:param packet: The captured packet.
49114
"""
115+
50116
try:
51117
p = IP(packet.get_payload())
52118
if 'TCP' in p:
53-
self.logger.debug('TCP packet')
54-
if len(p) == 118:
55-
this_session = int.from_bytes(p[Raw].load[4:8], sys.byteorder)
56-
tag_name = p[Raw].load.decode(encoding='latin-1')[54:57]
57-
self.logger.debug('Tag name: ' + str(tag_name))
58-
self.logger.debug('Attack tag: ' + self.attacked_tag)
59-
if self.attacked_tag == tag_name:
60-
# This is a packet being sent to SCADA server, conceal the manipulation
61-
if p[IP].src == self.intermediate_yaml['scada']['public_ip']:
62-
self.logger.debug('SCADA Req session')
63-
self.scada_session_ids.append(this_session)
64-
else:
65-
self.logger.debug('PLC Req session')
66-
self.attack_session_ids.append(this_session)
67-
68119
if len(p) == 102:
69-
this_session = int.from_bytes(p[Raw].load[4:8], sys.byteorder)
70-
71-
if this_session in self.attack_session_ids:
72-
#value = translate_payload_to_float(p[Raw].load)
73-
74-
if 'value' in self.intermediate_attack.keys():
75-
p[Raw].load = translate_float_to_payload(
76-
self.intermediate_attack['value'], p[Raw].load)
77-
elif 'offset' in self.intermediate_attack.keys():
78-
p[Raw].load = translate_float_to_payload(
79-
translate_payload_to_float(p[Raw].load) + self.intermediate_attack[
80-
'offset'], p[Raw].load)
81-
82-
del p[IP].chksum
83-
del p[TCP].chksum
84-
85-
packet.set_payload(bytes(p))
86-
self.logger.debug(f"Value of network packet for {p[IP].dst} overwritten.")
87-
88-
89-
elif this_session in self.scada_session_ids:
90-
self.logger.debug('Concealing to SCADA: ' + str(this_session))
91-
92-
if self.concealment_type == 'path':
93-
exp = (self.concealment_data_pd['iteration'] == self.get_master_clock())
94-
concealment_value = float(self.concealment_data_pd.loc[exp][self.attacked_tag].values[-1])
95-
self.logger.debug('Concealing with value: ' + str(concealment_value))
96-
p[Raw].load = translate_float_to_payload(concealment_value, p[Raw].load)
97-
elif self.concealment_type == 'value':
98-
concealment_value = self.intermediate_attack['concealment_data']['concealment_value']
99-
self.logger.debug('Concealment value is: ' + str(concealment_value))
100-
p[Raw].load = translate_float_to_payload(concealment_value, p[Raw].load)
101-
102-
del p[IP].chksum
103-
del p[TCP].chksum
104-
105-
packet.set_payload(bytes(p))
106-
self.logger.debug(f"Value of network packet for {p[IP].dst} overwritten.")
120+
p[Raw].load = self.handle_enip_response(p)
121+
del p[IP].chksum
122+
del p[TCP].chksum
123+
packet.set_payload(bytes(p))
124+
self.logger.debug(f"Value of network packet for {p[IP].dst} overwritten.")
125+
packet.accept()
126+
127+
else:
128+
if len(p) == 118:
129+
self.handle_enip_request(p, 57)
130+
elif len(p) == 116:
131+
self.handle_enip_request(p, 56)
132+
else:
133+
packet.accept()
134+
return
107135

108136
packet.accept()
137+
109138
except Exception as exc:
110139
print(exc)
111140
if self.nfqueue:

dhalsim/network_attacks/simple_dos_attack.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,8 @@ def teardown(self):
131131
os.system('iptables -D INPUT -p icmp -j DROP')
132132
os.system('iptables -D OUTPUT -p icmp -j DROP')
133133

134+
self.run_thread = False
135+
134136
nfqueue.unbind()
135137
self.logger.debug("[*] Stopping water level spoofing")
136138

dhalsim/parser/config_parser.py

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -92,9 +92,14 @@ class SchemaParser:
9292
Use(str.lower),
9393
'value'
9494
),
95-
'concealment_value': And(
96-
Or(float, And(int, Use(float))),
97-
)
95+
'concealment_value': [{
96+
'tag': And(
97+
str,
98+
string_pattern,
99+
),
100+
Or('value', 'offset', only_one=True,
101+
error="'tags' should have either a 'value' or 'offset' attribute."): Or(float, And(int, Use(float))),
102+
}],
98103
},
99104
{
100105
'type': And(
@@ -310,13 +315,14 @@ class SchemaParser:
310315
str,
311316
string_pattern
312317
),
313-
'tag': And(
314-
str,
315-
string_pattern,
316-
),
317-
'value': And(
318-
Or(float, And(int, Use(float)))
319-
),
318+
'tags': [{
319+
'tag': And(
320+
str,
321+
string_pattern,
322+
),
323+
Or('value', 'offset', only_one=True,
324+
error="'tags' should have either a 'value' or 'offset' attribute."): Or(float, And(int, Use(float))),
325+
}],
320326
'concealment_data': concealment_data
321327
},
322328
{
@@ -737,6 +743,9 @@ def generate_network_attacks(self):
737743
raise NoSuchTag(
738744
f"PLC {target_plc['name']} does not have all the tags specified.")
739745

746+
#todo: Checks for concealment_mitm
747+
748+
740749
return network_attacks
741750
return []
742751

0 commit comments

Comments
 (0)