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 transation
162  * * @param cipserviced - the CIP service rule
163  */
164 
165 static int CIPServiceMatch(ENIPTransaction *enip_data,
166  DetectCipServiceData *cipserviced)
167 {
168  int count = 1;
169  CIPServiceEntry *svc = NULL;
170  //SCLogDebug("CIPServiceMatchAL");
171  TAILQ_FOREACH(svc, &enip_data->service_list, next)
172  {
173  SCLogDebug("CIPServiceMatchAL service #%d : 0x%x dir %d",
174  count, svc->service, svc->direction);
175 
176  if (cipserviced->cipservice == svc->service)
177  { // compare service
178  //SCLogDebug("Rule Match for cip service %d",cipserviced->cipservice );
179 
180  if (cipserviced->tokens > 1)
181  { //if rule params have class and attribute
182 
183 
184  if ((svc->service == CIP_SET_ATTR_LIST) || (svc->service
185  == CIP_SET_ATTR_SINGLE) || (svc->service
186  == CIP_GET_ATTR_LIST) || (svc->service
188  { //decode path
189  if (CIPPathMatch(svc, cipserviced) == 1)
190  {
191  if (svc->direction == 1) return 0; //don't match responses
192 
193  return 1;
194  }
195  }
196  } else
197  {
198  if (svc->direction == 1) return 0; //don't match responses
199 
200  // SCLogDebug("CIPServiceMatchAL found");
201  return 1;
202  }
203  }
204  count++;
205  }
206  return 0;
207 }
208 
209 /** \brief Do the content inspection & validation for a signature
210  *
211  * \param de_ctx Detection engine context
212  * \param det_ctx Detection engine thread context
213  * \param s Signature to inspect ( and sm: SigMatch to inspect)
214  * \param f Flow
215  * \param flags App layer flags
216  * \param alstate App layer state
217  * \param txv Pointer to ENIP Transaction structure
218  *
219  * \retval 0 no match or 1 match
220  */
222  const struct DetectEngineAppInspectionEngine_ *engine, const Signature *s, Flow *f,
223  uint8_t flags, void *alstate, void *txv, uint64_t tx_id)
224 {
225  SCEnter();
226 
227 
228  ENIPTransaction *tx = (ENIPTransaction *) txv;
229  DetectCipServiceData *cipserviced = (DetectCipServiceData *)engine->smd->ctx;
230 
231  if (cipserviced == NULL)
232  {
233  SCLogDebug("no cipservice state, no match");
234  SCReturnInt(0);
235  }
236  //SCLogDebug("DetectEngineInspectCIP %d", cipserviced->cipservice);
237 
238  if (CIPServiceMatch(tx, cipserviced) == 1)
239  {
240  //SCLogDebug("DetectCIPServiceMatchAL found");
241  SCReturnInt(1);
242  }
243 
244  SCReturnInt(0);
245 }
246 
247 /** \brief Do the content inspection & validation for a signature
248  *
249  * \param de_ctx Detection engine context
250  * \param det_ctx Detection engine thread context
251  * \param s Signature to inspect ( and sm: SigMatch to inspect)
252  * \param f Flow
253  * \param flags App layer flags
254  * \param alstate App layer state
255  * \param txv Pointer to ENIP Transaction structure
256  *
257  * \retval 0 no match or 1 match
258  */
259 
261  const struct DetectEngineAppInspectionEngine_ *engine, const Signature *s, Flow *f,
262  uint8_t flags, void *alstate, void *txv, uint64_t tx_id)
263 {
264  SCEnter();
265 
266  ENIPTransaction *tx = (ENIPTransaction *) txv;
267  DetectEnipCommandData *enipcmdd = (DetectEnipCommandData *)engine->smd->ctx;
268 
269  if (enipcmdd == NULL)
270  {
271  SCLogDebug("no enipcommand state, no match");
272  SCReturnInt(0);
273  }
274 
275  //SCLogDebug("DetectEngineInspectENIP %d, %d", enipcmdd->enipcommand, tx->header.command);
276 
277  if (enipcmdd->enipcommand == tx->header.command)
278  {
279  // SCLogDebug("DetectENIPCommandMatchAL found!");
280  SCReturnInt(1);
281  }
282 
283  SCReturnInt(0);
284 }
PATH_INSTANCE_16BIT
#define PATH_INSTANCE_16BIT
Definition: app-layer-enip-common.h:86
DetectEngineAppInspectionEngine_
Definition: detect.h:390
ENIPTransaction_::encap_data_header
ENIPEncapDataHdr encap_data_header
Definition: app-layer-enip-common.h:200
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:155
DetectCipServiceData_::tokens
uint8_t tokens
Definition: detect-cipservice.h:36
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:296
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:326
ENIPEncapDataItem_::length
uint16_t length
Definition: app-layer-enip-common.h:130
Flow_
Flow data structure.
Definition: flow.h:353
DetectEngineCtx_
main detection engine ctx
Definition: detect.h:785
ENIPEncapDataItem_::sequence_count
uint16_t sequence_count
Definition: app-layer-enip-common.h:131
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
ENIPTransaction_::encap_addr_item
ENIPEncapAddresItem encap_addr_item
Definition: app-layer-enip-common.h:201
SegmentEntry_::segment
uint16_t segment
Definition: app-layer-enip-common.h:156
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:163
CIPServiceEntry_
Definition: app-layer-enip-common.h:170
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
ENIPEncapAddresItem_::length
uint16_t length
Definition: app-layer-enip-common.h:119
de_ctx
DetectEngineCtx * de_ctx
Definition: fuzz_siginit.c:17
DetectEngineThreadCtx_
Definition: detect.h:1034
SCEnter
#define SCEnter(...)
Definition: util-debug.h:298
detect.h
CIPServiceEntry_::service
uint8_t service
Definition: app-layer-enip-common.h:171
ENIPTransaction_::encap_data_item
ENIPEncapDataItem encap_data_item
Definition: app-layer-enip-common.h:202
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:407
ENIPTransaction_
Definition: app-layer-enip-common.h:193
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:221
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:260
ENIPEncapDataHdr_::timeout
uint16_t timeout
Definition: app-layer-enip-common.h:109
Signature_
Signature container.
Definition: detect.h:540
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:129
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
DetectCipServiceData_
Definition: detect-cipservice.h:31
flow.h
ENIPTransaction_::header
ENIPEncapHdr header
Definition: app-layer-enip-common.h:199
ENIPEncapAddresItem_::type
uint16_t type
Definition: app-layer-enip-common.h:118
SCReturnInt
#define SCReturnInt(x)
Definition: util-debug.h:302
CIPServiceEntry_::direction
uint8_t direction
Definition: app-layer-enip-common.h:172
detect-cipservice.h
SegmentEntry_::value
uint16_t value
Definition: app-layer-enip-common.h:157
AttributeEntry_::attribute
uint16_t attribute
Definition: app-layer-enip-common.h:164
app-layer.h
PATH_CLASS_16BIT
#define PATH_CLASS_16BIT
Definition: app-layer-enip-common.h:84