suricata
detect-engine-enip.c
Go to the documentation of this file.
1 /* Copyright (C) 2015-2022 Open Information Security Foundation
2  *
3  * You can copy, redistribute or modify this Program under the terms of
4  * the GNU General Public License version 2 as published by the Free
5  * Software Foundation.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * version 2 along with this program; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15  * 02110-1301, USA.
16  */
17 
18 /** \file
19  *
20  * \author Kevin Wong <kwong@solananetworks.com>
21  *
22  * Based on detect-engine-modbus.c
23  */
24 
25 #include "suricata-common.h"
26 
27 #include "app-layer.h"
28 #include "app-layer-enip-common.h"
29 
30 #include "detect.h"
31 #include "detect-cipservice.h"
32 #include "detect-engine-enip.h"
33 
34 #include "flow.h"
35 
36 #include "util-debug.h"
37 
38 #if 0
39 /**
40  * \brief Print fields from ENIP Packet
41  * @param enip_data
42  */
43 void PrintENIPAL(ENIPTransaction *enip_data)
44 {
45  SCLogDebug("============================================");
46  SCLogDebug("ENCAP HEADER cmd 0x%x, length %d, session 0x%x, status 0x%x",
47  enip_data->header.command, enip_data->header.length,
48  enip_data->header.session, enip_data->header.status);
49  //SCLogDebug("context 0x%x option 0x%x", enip_data->header.context, enip_data->header.option);
50  SCLogDebug("ENCAP DATA HEADER handle 0x%x, timeout %d, count %d",
52  enip_data->encap_data_header.timeout,
53  enip_data->encap_data_header.item_count);
54  SCLogDebug("ENCAP ADDR ITEM type 0x%x, length %d",
55  enip_data->encap_addr_item.type, enip_data->encap_addr_item.length);
56  SCLogDebug("ENCAP DATA ITEM type 0x%x, length %d sequence 0x%x",
57  enip_data->encap_data_item.type, enip_data->encap_data_item.length,
58  enip_data->encap_data_item.sequence_count);
59 
60  CIPServiceEntry *svc = NULL;
61 
62  int count = 0;
63  TAILQ_FOREACH(svc, &enip_data->service_list, next)
64  {
65  //SCLogDebug("CIP Service #%d : 0x%x", count, svc->service);
66  count++;
67  }
68 }
69 #endif
70 
71 /**
72  * \brief Matches the rule to the CIP segment in ENIP Packet
73  * @param svc - the CIP service entry
74  * * @param cipserviced - the CIP service rule
75  */
76 static int CIPPathMatch(CIPServiceEntry *svc, DetectCipServiceData *cipserviced)
77 {
78  uint16_t class = 0;
79  uint16_t attrib = 0;
80  int found_class = 0;
81 
82  SegmentEntry *seg = NULL;
83  TAILQ_FOREACH(seg, &svc->segment_list, next)
84  {
85  switch(seg->segment)
86  {
87  case PATH_CLASS_8BIT:
88  class = seg->value;
89  if (cipserviced->cipclass == class)
90  {
91  if (cipserviced->tokens == 2)
92  {// if rule only has class
93  return 1;
94  } else
95  {
96  found_class = 1;
97  }
98  }
99  break;
100  case PATH_INSTANCE_8BIT:
101  break;
102  case PATH_ATTR_8BIT: //single attribute
103  attrib = seg->value;
104  if ((cipserviced->tokens == 3) &&
105  (cipserviced->cipclass == class) &&
106  (cipserviced->cipattribute == attrib) &&
107  (cipserviced->matchattribute == 1))
108  { // if rule has class & attribute, matched all here
109  return 1;
110  }
111  if ((cipserviced->tokens == 3) &&
112  (cipserviced->cipclass == class) &&
113  (cipserviced->matchattribute == 0))
114  { // for negation rule on attribute
115  return 1;
116  }
117  break;
118  case PATH_CLASS_16BIT:
119  class = seg->value;
120  if (cipserviced->cipclass == class)
121  {
122  if (cipserviced->tokens == 2)
123  {// if rule only has class
124  return 1;
125  } else
126  {
127  found_class = 1;
128  }
129  }
130  break;
131  case PATH_INSTANCE_16BIT:
132  break;
133  default:
134  return 0;
135  }
136  }
137 
138  if (found_class == 0)
139  { // if haven't matched class yet, no need to check attribute
140  return 0;
141  }
142 
143  if ((svc->service == CIP_SET_ATTR_LIST) ||
144  (svc->service == CIP_GET_ATTR_LIST))
145  {
146  AttributeEntry *attr = NULL;
147  TAILQ_FOREACH (attr, &svc->attrib_list, next)
148  {
149  if (cipserviced->cipattribute == attr->attribute)
150  {
151  return 1;
152  }
153  }
154  }
155 
156  return 0;
157 }
158 
159 /**
160  * \brief Matches the rule to the ENIP Transaction
161  * @param enip_data - the ENIP transaction
162  * * @param cipserviced - the CIP service rule
163  */
164 
165 static int CIPServiceMatch(ENIPTransaction *enip_data,
166  DetectCipServiceData *cipserviced)
167 {
168 #ifdef DEBUG
169  int count = 1;
170 #endif
171  CIPServiceEntry *svc = NULL;
172  //SCLogDebug("CIPServiceMatchAL");
173  TAILQ_FOREACH(svc, &enip_data->service_list, next)
174  {
175  SCLogDebug("CIPServiceMatchAL service #%d : 0x%x dir %d",
176  count, svc->service, svc->direction);
177 
178  if (cipserviced->cipservice == svc->service)
179  { // compare service
180  //SCLogDebug("Rule Match for cip service %d",cipserviced->cipservice );
181 
182  if (cipserviced->tokens > 1)
183  { //if rule params have class and attribute
184 
185 
186  if ((svc->service == CIP_SET_ATTR_LIST) || (svc->service
187  == CIP_SET_ATTR_SINGLE) || (svc->service
188  == CIP_GET_ATTR_LIST) || (svc->service
190  { //decode path
191  if (CIPPathMatch(svc, cipserviced) == 1)
192  {
193  if (svc->direction == 1) return 0; //don't match responses
194 
195  return 1;
196  }
197  }
198  } else
199  {
200  if (svc->direction == 1) return 0; //don't match responses
201 
202  // SCLogDebug("CIPServiceMatchAL found");
203  return 1;
204  }
205  }
206 #ifdef DEBUG
207  count++;
208 #endif
209  }
210  return 0;
211 }
212 
213 /** \brief Do the content inspection & validation for a signature
214  *
215  * \param de_ctx Detection engine context
216  * \param det_ctx Detection engine thread context
217  * \param s Signature to inspect ( and sm: SigMatch to inspect)
218  * \param f Flow
219  * \param flags App layer flags
220  * \param alstate App layer state
221  * \param txv Pointer to ENIP Transaction structure
222  *
223  * \retval 0 no match or 1 match
224  */
226  const struct DetectEngineAppInspectionEngine_ *engine, const Signature *s, Flow *f,
227  uint8_t flags, void *alstate, void *txv, uint64_t tx_id)
228 {
229  SCEnter();
230 
231 
232  ENIPTransaction *tx = (ENIPTransaction *) txv;
233  DetectCipServiceData *cipserviced = (DetectCipServiceData *)engine->smd->ctx;
234 
235  if (cipserviced == NULL)
236  {
237  SCLogDebug("no cipservice state, no match");
238  SCReturnInt(0);
239  }
240  //SCLogDebug("DetectEngineInspectCIP %d", cipserviced->cipservice);
241 
242  if (CIPServiceMatch(tx, cipserviced) == 1)
243  {
244  //SCLogDebug("DetectCIPServiceMatchAL found");
245  SCReturnInt(1);
246  }
247 
248  SCReturnInt(0);
249 }
250 
251 /** \brief Do the content inspection & validation for a signature
252  *
253  * \param de_ctx Detection engine context
254  * \param det_ctx Detection engine thread context
255  * \param s Signature to inspect ( and sm: SigMatch to inspect)
256  * \param f Flow
257  * \param flags App layer flags
258  * \param alstate App layer state
259  * \param txv Pointer to ENIP Transaction structure
260  *
261  * \retval 0 no match or 1 match
262  */
263 
265  const struct DetectEngineAppInspectionEngine_ *engine, const Signature *s, Flow *f,
266  uint8_t flags, void *alstate, void *txv, uint64_t tx_id)
267 {
268  SCEnter();
269 
270  ENIPTransaction *tx = (ENIPTransaction *) txv;
271  DetectEnipCommandData *enipcmdd = (DetectEnipCommandData *)engine->smd->ctx;
272 
273  if (enipcmdd == NULL)
274  {
275  SCLogDebug("no enipcommand state, no match");
276  SCReturnInt(0);
277  }
278 
279  //SCLogDebug("DetectEngineInspectENIP %d, %d", enipcmdd->enipcommand, tx->header.command);
280 
281  if (enipcmdd->enipcommand == tx->header.command)
282  {
283  // SCLogDebug("DetectENIPCommandMatchAL found!");
284  SCReturnInt(1);
285  }
286 
287  SCReturnInt(0);
288 }
PATH_INSTANCE_16BIT
#define PATH_INSTANCE_16BIT
Definition: app-layer-enip-common.h:86
ENIPEncapAddressItem_::length
uint16_t length
Definition: app-layer-enip-common.h:118
DetectEngineAppInspectionEngine_
Definition: detect.h:427
ENIPTransaction_::encap_data_header
ENIPEncapDataHdr encap_data_header
Definition: app-layer-enip-common.h:199
CIP_SET_ATTR_SINGLE
#define CIP_SET_ATTR_SINGLE
Definition: app-layer-enip-common.h:76
DetectCipServiceData_::matchattribute
uint8_t matchattribute
Definition: detect-cipservice.h:35
SegmentEntry_
Definition: app-layer-enip-common.h:154
DetectCipServiceData_::tokens
uint8_t tokens
Definition: detect-cipservice.h:36
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:269
next
struct HtpBodyChunk_ * next
Definition: app-layer-htp.h:0
ENIPEncapHdr_::session
uint32_t session
Definition: app-layer-enip-common.h:96
SigMatchData_::ctx
SigMatchCtx * ctx
Definition: detect.h:362
ENIPEncapDataItem_::length
uint16_t length
Definition: app-layer-enip-common.h:129
Flow_
Flow data structure.
Definition: flow.h:351
DetectEngineCtx_
main detection engine ctx
Definition: detect.h:839
ENIPEncapDataItem_::sequence_count
uint16_t sequence_count
Definition: app-layer-enip-common.h:130
PATH_INSTANCE_8BIT
#define PATH_INSTANCE_8BIT
Definition: app-layer-enip-common.h:85
TAILQ_FOREACH
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:252
SegmentEntry_::segment
uint16_t segment
Definition: app-layer-enip-common.h:155
ENIPEncapDataHdr_::item_count
uint16_t item_count
Definition: app-layer-enip-common.h:110
ENIPEncapHdr_::command
uint16_t command
Definition: app-layer-enip-common.h:99
AttributeEntry_
Definition: app-layer-enip-common.h:162
CIPServiceEntry_
Definition: app-layer-enip-common.h:169
DetectCipServiceData_::cipservice
uint8_t cipservice
Definition: detect-cipservice.h:32
detect-engine-enip.h
DetectEnipCommandData_::enipcommand
uint16_t enipcommand
Definition: detect-cipservice.h:44
CIP_GET_ATTR_SINGLE
#define CIP_GET_ATTR_SINGLE
Definition: app-layer-enip-common.h:75
util-debug.h
de_ctx
DetectEngineCtx * de_ctx
Definition: fuzz_siginit.c:17
DetectEngineThreadCtx_
Definition: detect.h:1095
SCEnter
#define SCEnter(...)
Definition: util-debug.h:271
detect.h
CIPServiceEntry_::service
uint8_t service
Definition: app-layer-enip-common.h:170
ENIPTransaction_::encap_data_item
ENIPEncapDataItem encap_data_item
Definition: app-layer-enip-common.h:201
ENIPEncapAddressItem_::type
uint16_t type
Definition: app-layer-enip-common.h:117
PATH_CLASS_8BIT
#define PATH_CLASS_8BIT
Definition: app-layer-enip-common.h:83
DetectEnipCommandData_
Definition: detect-cipservice.h:43
DetectEngineAppInspectionEngine_::smd
SigMatchData * smd
Definition: detect.h:444
ENIPTransaction_
Definition: app-layer-enip-common.h:192
flags
uint8_t flags
Definition: decode-gre.h:0
suricata-common.h
ENIPEncapDataHdr_::interface_handle
uint32_t interface_handle
Definition: app-layer-enip-common.h:108
PATH_ATTR_8BIT
#define PATH_ATTR_8BIT
Definition: app-layer-enip-common.h:87
DetectEngineInspectCIP
uint8_t DetectEngineInspectCIP(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, const struct DetectEngineAppInspectionEngine_ *engine, const Signature *s, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id)
Do the content inspection & validation for a signature.
Definition: detect-engine-enip.c:225
ENIPEncapHdr_::status
uint32_t status
Definition: app-layer-enip-common.h:97
DetectEngineInspectENIP
uint8_t DetectEngineInspectENIP(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, const struct DetectEngineAppInspectionEngine_ *engine, const Signature *s, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id)
Do the content inspection & validation for a signature.
Definition: detect-engine-enip.c:264
ENIPEncapDataHdr_::timeout
uint16_t timeout
Definition: app-layer-enip-common.h:109
Signature_
Signature container.
Definition: detect.h:596
app-layer-enip-common.h
CIP_SET_ATTR_LIST
#define CIP_SET_ATTR_LIST
Definition: app-layer-enip-common.h:67
ENIPEncapDataItem_::type
uint16_t type
Definition: app-layer-enip-common.h:128
ENIPEncapHdr_::length
uint16_t length
Definition: app-layer-enip-common.h:100
CIP_GET_ATTR_LIST
#define CIP_GET_ATTR_LIST
Definition: app-layer-enip-common.h:66
DetectCipServiceData_::cipattribute
uint16_t cipattribute
Definition: detect-cipservice.h:34
DetectCipServiceData_::cipclass
uint16_t cipclass
Definition: detect-cipservice.h:33
DetectEngineContentInspectionCtx::count
uint32_t count
Definition: detect-engine-content-inspection.c:75
DetectCipServiceData_
Definition: detect-cipservice.h:31
flow.h
ENIPTransaction_::header
ENIPEncapHdr header
Definition: app-layer-enip-common.h:198
SCReturnInt
#define SCReturnInt(x)
Definition: util-debug.h:275
CIPServiceEntry_::direction
uint8_t direction
Definition: app-layer-enip-common.h:171
detect-cipservice.h
SegmentEntry_::value
uint16_t value
Definition: app-layer-enip-common.h:156
AttributeEntry_::attribute
uint16_t attribute
Definition: app-layer-enip-common.h:163
app-layer.h
PATH_CLASS_16BIT
#define PATH_CLASS_16BIT
Definition: app-layer-enip-common.h:84
ENIPTransaction_::encap_addr_item
ENIPEncapAddressItem encap_addr_item
Definition: app-layer-enip-common.h:200