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