1 //--------------------------------------------------------------------------
2 // Copyright (C) 2016-2021 Cisco and/or its affiliates. All rights reserved.
3 //
4 // This program is free software; you can redistribute it and/or modify it
5 // under the terms of the GNU General Public License Version 2 as published
6 // by the Free Software Foundation. You may not use, modify or distribute
7 // this program under any other version of the GNU General Public License.
8 //
9 // This program is distributed in the hope that it will be useful, but
10 // WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 // General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License along
15 // with this program; if not, write to the Free Software Foundation, Inc.,
16 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 //--------------------------------------------------------------------------
18
19 // dce_common.cc author Rashmi Pitre <rrp@cisco.com>
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include "dce_common.h"
26
27 #include "detection/detection_engine.h"
28 #include "ips_options/extract.h"
29 #include "log/messages.h"
30 #include "utils/safec.h"
31
32 #include "dce_context_data.h"
33 #include "dce_http_proxy_module.h"
34 #include "dce_http_server_module.h"
35 #include "dce_smb1.h"
36 #include "dce_smb_common.h"
37 #include "dce_smb_utils.h"
38 #include "dce_tcp.h"
39 #include "dce_udp.h"
40
41 using namespace snort;
42
43 THREAD_LOCAL int dce2_detected = 0;
44 static THREAD_LOCAL bool using_rpkt = false;
45
dce2_get_policy_name(DCE2_Policy policy)46 static const char* dce2_get_policy_name(DCE2_Policy policy)
47 {
48 const char* policyStr = nullptr;
49 switch (policy)
50 {
51 case DCE2_POLICY__WIN2000:
52 policyStr = DCE2_SARG__POLICY_WIN2000;
53 break;
54 case DCE2_POLICY__WINXP:
55 policyStr = DCE2_SARG__POLICY_WINXP;
56 break;
57 case DCE2_POLICY__WINVISTA:
58 policyStr = DCE2_SARG__POLICY_WINVISTA;
59 break;
60 case DCE2_POLICY__WIN2003:
61 policyStr = DCE2_SARG__POLICY_WIN2003;
62 break;
63 case DCE2_POLICY__WIN2008:
64 policyStr = DCE2_SARG__POLICY_WIN2008;
65 break;
66 case DCE2_POLICY__WIN7:
67 policyStr = DCE2_SARG__POLICY_WIN7;
68 break;
69 case DCE2_POLICY__SAMBA:
70 policyStr = DCE2_SARG__POLICY_SAMBA;
71 break;
72 case DCE2_POLICY__SAMBA_3_0_37:
73 policyStr = DCE2_SARG__POLICY_SAMBA_3_0_37;
74 break;
75 case DCE2_POLICY__SAMBA_3_0_22:
76 policyStr = DCE2_SARG__POLICY_SAMBA_3_0_22;
77 break;
78 case DCE2_POLICY__SAMBA_3_0_20:
79 policyStr = DCE2_SARG__POLICY_SAMBA_3_0_20;
80 break;
81 default:
82 policyStr = "Unknown";
83 }
84 return policyStr;
85 }
86
dce2_set_common_config(const Value & v,dce2CommonProtoConf & common)87 bool dce2_set_common_config(const Value& v, dce2CommonProtoConf& common)
88 {
89 if ( v.is("limit_alerts") )
90 common.limit_alerts = v.get_bool();
91
92 else if ( v.is("disable_defrag") )
93 common.disable_defrag = v.get_bool();
94
95 else if ( v.is("max_frag_len") )
96 common.max_frag_len = v.get_uint16();
97
98 else
99 return false;
100
101 return true;
102 }
103
dce2_set_co_config(const Value & v,dce2CoProtoConf & co)104 bool dce2_set_co_config(const Value& v, dce2CoProtoConf& co)
105 {
106 if (dce2_set_common_config(v, co.common))
107 return true;
108
109 else if ( v.is("policy") )
110 co.policy = (DCE2_Policy)v.get_uint8();
111
112 else if ( v.is("reassemble_threshold") )
113 co.co_reassemble_threshold = v.get_uint16();
114
115 else
116 return false;
117
118 return true;
119 }
120
print_dce2_common_config(const dce2CommonProtoConf & common)121 void print_dce2_common_config(const dce2CommonProtoConf& common)
122 {
123 ConfigLogger::log_flag("limit_alerts", common.limit_alerts);
124 ConfigLogger::log_flag("disable_defrag", common.disable_defrag);
125 ConfigLogger::log_value("max_frag_len", common.max_frag_len);
126 }
127
print_dce2_co_config(const dce2CoProtoConf & co)128 void print_dce2_co_config(const dce2CoProtoConf& co)
129 {
130 print_dce2_common_config(co.common);
131
132 ConfigLogger::log_value("policy", dce2_get_policy_name(co.policy));
133 ConfigLogger::log_value("reassemble_threshold", co.co_reassemble_threshold);
134 }
135
dce2_paf_abort(DCE2_SsnData * sd)136 bool dce2_paf_abort(DCE2_SsnData* sd)
137 {
138 if ((sd != nullptr) && DCE2_SsnNoInspect(sd))
139 return true;
140
141 return false;
142 }
143
DCE2_Detect(DCE2_SsnData * sd)144 void DCE2_Detect(DCE2_SsnData* sd)
145 {
146 if (!sd) return ;
147 DceContextData::set_current_ropts(sd);
148 if ( using_rpkt )
149 {
150 using_rpkt = false;
151 DetectionEngine de;
152 DCE2_Detect(sd);
153 return;
154 }
155 Packet* top_pkt = DetectionEngine::get_current_packet();
156 DetectionEngine::detect(top_pkt);
157 dce2_detected = 1;
158 /* Always reset rule option data after detecting */
159 DCE2_ResetRopts(sd, top_pkt);
160 }
161
get_dce2_trans_type(const Packet * p)162 DCE2_TransType get_dce2_trans_type(const Packet* p)
163 {
164 DCE2_SsnData* sd = get_dce2_session_data(p->flow);
165 if ((sd != nullptr) && (sd->trans == DCE2_TRANS_TYPE__SMB))
166 {
167 return DCE2_TRANS_TYPE__SMB;
168 }
169
170 DCE2_TcpSsnData* tcp_data = get_dce2_tcp_session_data(p->flow);
171 sd = (tcp_data != nullptr) ? &(tcp_data->sd) : nullptr;
172 if ((sd != nullptr) && (sd->trans == DCE2_TRANS_TYPE__TCP))
173 {
174 return DCE2_TRANS_TYPE__TCP;
175 }
176
177 DCE2_UdpSsnData* udp_data = get_dce2_udp_session_data(p->flow);
178 sd = (udp_data != nullptr) ? &(udp_data->sd) : nullptr;
179 if ((sd != nullptr) && (sd->trans == DCE2_TRANS_TYPE__UDP))
180 {
181 return DCE2_TRANS_TYPE__UDP;
182 }
183
184 return DCE2_TRANS_TYPE__NONE;
185 }
186
DceEndianness()187 DceEndianness::DceEndianness()
188 {
189 hdr_byte_order = DCE2_SENTINEL;
190 data_byte_order = DCE2_SENTINEL;
191 stub_data_offset = DCE2_SENTINEL;
192 }
193
reset()194 void DceEndianness::reset()
195 {
196 hdr_byte_order = DCE2_SENTINEL;
197 data_byte_order = DCE2_SENTINEL;
198 stub_data_offset = DCE2_SENTINEL;
199 }
200
get_offset_endianness(int32_t offset,uint8_t & endian)201 bool DceEndianness::get_offset_endianness(int32_t offset, uint8_t& endian)
202 {
203 int byte_order;
204
205 if ((data_byte_order == DCE2_SENTINEL) ||
206 (hdr_byte_order == DCE2_SENTINEL))
207 return false;
208
209 if (stub_data_offset == DCE2_SENTINEL)
210 {
211 byte_order = (DceRpcBoFlag)hdr_byte_order;
212 }
213 else if (offset < stub_data_offset)
214 {
215 byte_order = (DceRpcBoFlag)hdr_byte_order;
216 }
217 else
218 {
219 byte_order = (DceRpcBoFlag)data_byte_order;
220 }
221
222 endian = (byte_order == DCERPC_BO_FLAG__BIG_ENDIAN) ? ENDIAN_BIG : ENDIAN_LITTLE;
223
224 return true;
225 }
226
DCE2_GetRpktMaxData(DCE2_RpktType rtype)227 uint16_t DCE2_GetRpktMaxData(DCE2_RpktType rtype)
228 {
229 Packet* p = DetectionEngine::get_current_packet();
230 uint16_t overhead = 0;
231
232 switch (rtype)
233 {
234 case DCE2_RPKT_TYPE__SMB_SEG:
235 case DCE2_RPKT_TYPE__SMB_TRANS:
236 break;
237
238 case DCE2_RPKT_TYPE__SMB_CO_SEG:
239 if (p->is_from_client())
240 overhead += DCE2_MOCK_HDR_LEN__SMB_CLI;
241 else
242 overhead += DCE2_MOCK_HDR_LEN__SMB_SRV;
243 break;
244
245 case DCE2_RPKT_TYPE__SMB_CO_FRAG:
246 if (p->is_from_client())
247 overhead += DCE2_MOCK_HDR_LEN__SMB_CLI + DCE2_MOCK_HDR_LEN__CO_CLI;
248 else
249 overhead += DCE2_MOCK_HDR_LEN__SMB_SRV + DCE2_MOCK_HDR_LEN__CO_SRV;
250 break;
251
252 case DCE2_RPKT_TYPE__TCP_CO_SEG:
253 break;
254 case DCE2_RPKT_TYPE__TCP_CO_FRAG:
255 if (p->is_from_client())
256 overhead += DCE2_MOCK_HDR_LEN__CO_CLI;
257 else
258 overhead += DCE2_MOCK_HDR_LEN__CO_SRV;
259 break;
260
261 default:
262 assert(false);
263 return 0;
264 }
265 return (Packet::max_dsize - overhead);
266 }
267
dce2_fill_rpkt_info(Packet * rpkt,Packet * p)268 static void dce2_fill_rpkt_info(Packet* rpkt, Packet* p)
269 {
270 rpkt->endianness = new DceEndianness();
271 rpkt->pkth = p->pkth;
272 rpkt->ptrs = p->ptrs;
273 rpkt->flow = p->flow;
274 rpkt->proto_bits = p->proto_bits;
275 rpkt->packet_flags = p->packet_flags;
276 rpkt->packet_flags |= PKT_PSEUDO;
277 rpkt->user_inspection_policy_id = p->user_inspection_policy_id;
278 rpkt->user_ips_policy_id = p->user_ips_policy_id;
279 rpkt->user_network_policy_id = p->user_network_policy_id;
280 }
281
DCE2_GetRpkt(Packet * p,DCE2_RpktType rpkt_type,const uint8_t * data,uint32_t data_len)282 Packet* DCE2_GetRpkt(Packet* p,DCE2_RpktType rpkt_type,
283 const uint8_t* data, uint32_t data_len)
284 {
285 Packet* rpkt = DetectionEngine::set_next_packet(p);
286 uint8_t* wrdata = const_cast<uint8_t*>(rpkt->data);
287 dce2_fill_rpkt_info(rpkt, p);
288 uint16_t data_overhead = 0;
289
290 switch (rpkt_type)
291 {
292 case DCE2_RPKT_TYPE__SMB_SEG:
293 rpkt->pseudo_type = PSEUDO_PKT_SMB_SEG;
294 break;
295
296 case DCE2_RPKT_TYPE__SMB_TRANS:
297 rpkt->pseudo_type = PSEUDO_PKT_SMB_TRANS;
298 if (p->is_from_client())
299 {
300 data_overhead = DCE2_MOCK_HDR_LEN__SMB_CLI;
301 memset(wrdata, 0, data_overhead);
302 DCE2_SmbInitRdata(wrdata, PKT_FROM_CLIENT);
303 }
304 else
305 {
306 data_overhead = DCE2_MOCK_HDR_LEN__SMB_SRV;
307 memset(wrdata, 0, data_overhead);
308 DCE2_SmbInitRdata(wrdata, PKT_FROM_SERVER);
309 }
310 break;
311
312 case DCE2_RPKT_TYPE__SMB_CO_SEG:
313 rpkt->pseudo_type = PSEUDO_PKT_DCE_SEG;
314 if (p->is_from_client())
315 {
316 data_overhead = DCE2_MOCK_HDR_LEN__SMB_CLI;
317 memset(wrdata, 0, data_overhead);
318 DCE2_SmbInitRdata(wrdata, PKT_FROM_CLIENT);
319 }
320 else
321 {
322 data_overhead = DCE2_MOCK_HDR_LEN__SMB_SRV;
323 memset(wrdata, 0, data_overhead);
324 DCE2_SmbInitRdata(wrdata, PKT_FROM_SERVER);
325 }
326 break;
327
328 case DCE2_RPKT_TYPE__SMB_CO_FRAG:
329 rpkt->pseudo_type = PSEUDO_PKT_DCE_FRAG;
330 if (p->is_from_client())
331 {
332 data_overhead = DCE2_MOCK_HDR_LEN__SMB_CLI + DCE2_MOCK_HDR_LEN__CO_CLI;
333 memset(wrdata, 0, data_overhead);
334 DCE2_SmbInitRdata(wrdata, PKT_FROM_CLIENT);
335 DCE2_CoInitRdata(wrdata +
336 DCE2_MOCK_HDR_LEN__SMB_CLI, PKT_FROM_CLIENT);
337 }
338 else
339 {
340 data_overhead = DCE2_MOCK_HDR_LEN__SMB_SRV + DCE2_MOCK_HDR_LEN__CO_SRV;
341 memset(wrdata, 0, data_overhead);
342 DCE2_SmbInitRdata(wrdata, PKT_FROM_SERVER);
343 DCE2_CoInitRdata(wrdata +
344 DCE2_MOCK_HDR_LEN__SMB_SRV, PKT_FROM_SERVER);
345 }
346 break;
347
348 case DCE2_RPKT_TYPE__UDP_CL_FRAG:
349 rpkt->pseudo_type = PSEUDO_PKT_DCE_FRAG;
350 data_overhead = DCE2_MOCK_HDR_LEN__CL;
351 memset(wrdata, 0, data_overhead);
352 DCE2_ClInitRdata(wrdata);
353 break;
354
355 case DCE2_RPKT_TYPE__TCP_CO_SEG:
356 case DCE2_RPKT_TYPE__TCP_CO_FRAG:
357 if (rpkt_type == DCE2_RPKT_TYPE__TCP_CO_FRAG)
358 {
359 rpkt->pseudo_type = PSEUDO_PKT_DCE_FRAG;
360 if (p->is_from_client())
361 {
362 data_overhead = DCE2_MOCK_HDR_LEN__CO_CLI;
363 memset(wrdata, 0, data_overhead);
364 DCE2_CoInitRdata(wrdata, PKT_FROM_CLIENT);
365 }
366 else
367 {
368 data_overhead = DCE2_MOCK_HDR_LEN__CO_SRV;
369 memset(wrdata, 0, data_overhead);
370 DCE2_CoInitRdata(wrdata, PKT_FROM_SERVER);
371 }
372 }
373 else
374 {
375 rpkt->pseudo_type = PSEUDO_PKT_DCE_SEG;
376 }
377 break;
378
379 default:
380 assert(false);
381 return nullptr;
382 }
383
384 if ((data_overhead + data_len) > Packet::max_dsize)
385 data_len -= (data_overhead + data_len) - Packet::max_dsize;
386
387 if (data_len > Packet::max_dsize - data_overhead)
388 {
389 delete rpkt->endianness;
390 rpkt->endianness = nullptr;
391 return nullptr;
392 }
393
394 memcpy_s((void*)(rpkt->data + data_overhead),
395 Packet::max_dsize - data_overhead, data, data_len);
396
397 rpkt->dsize = data_len + data_overhead;
398 using_rpkt = true;
399 return rpkt;
400 }
401
DCE2_AddDataToRpkt(Packet * rpkt,const uint8_t * data,uint32_t data_len)402 DCE2_Ret DCE2_AddDataToRpkt(Packet* rpkt, const uint8_t* data, uint32_t data_len)
403 {
404 if ((rpkt == nullptr) || (data == nullptr) || (data_len == 0))
405 return DCE2_RET__ERROR;
406
407 if (rpkt->data == nullptr)
408 return DCE2_RET__ERROR;
409
410 // FIXIT-L PORT_IF_NEEDED packet size and hdr check
411 const uint8_t* pkt_data_end = rpkt->data + Packet::max_dsize;
412 const uint8_t* payload_end = rpkt->data + rpkt->dsize;
413
414 if ((payload_end + data_len) > pkt_data_end)
415 data_len = pkt_data_end - payload_end;
416
417 if (data_len > Packet::max_dsize - rpkt->dsize)
418 return DCE2_RET__ERROR;
419
420 memcpy_s((void*)(payload_end), Packet::max_dsize - rpkt->dsize,
421 data, data_len);
422
423 rpkt->dsize += (uint16_t)data_len;
424 return DCE2_RET__SUCCESS;
425 }
426
427 extern const BaseApi* ips_dce_iface;
428 extern const BaseApi* ips_dce_opnum;
429 extern const BaseApi* ips_dce_stub_data;
430
431 #ifdef BUILDING_SO
432 SO_PUBLIC const BaseApi* snort_plugins[] =
433 #else
434 const BaseApi* sin_dce[] =
435 #endif
436 {
437 &dce2_tcp_api.base,
438 &dce2_smb_api.base,
439 &dce2_udp_api.base,
440 &dce_http_proxy_api.base,
441 &dce_http_server_api.base,
442 ips_dce_iface,
443 ips_dce_opnum,
444 ips_dce_stub_data,
445 nullptr
446 };
447