1 /****************************************************************************
2  * Copyright (C) 2014-2021 Cisco and/or its affiliates. All rights reserved.
3  * Copyright (C) 2008-2013 Sourcefire, Inc.
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License Version 2 as
7  * published by the Free Software Foundation.  You may not use, modify or
8  * distribute this program under any other version of the GNU General
9  * Public License.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19  *
20  ****************************************************************************
21  * Handles processing of events generated by the preprocessor.
22  *
23  * 8/17/2008 - Initial implementation ... Todd Wease <twease@sourcefire.com>
24  *
25  ****************************************************************************/
26 
27 #ifdef HAVE_CONFIG_H
28 #include "config.h"
29 #endif
30 
31 #include "sf_types.h"
32 #include "dce2_event.h"
33 #include "dce2_memory.h"
34 #include "dce2_config.h"
35 #include "dce2_stats.h"
36 #include "smb.h"
37 #include "dcerpc.h"
38 #include "sf_dynamic_preprocessor.h"
39 #include <stdarg.h>
40 #include <string.h>
41 
42 /********************************************************************
43  * Global variables
44  ********************************************************************/
45 /* Used to print events and their arguments to.  Each event gets
46  * a buffer and 255 chars to print to.  The reason for the multiple
47  * buffers is that if multiple events fire, we don't want to overwrite
48  * one before it's been written via an output plugin.  Only one event
49  * type per session is ever logged. */
50 static char dce2_event_bufs[DCE2_EVENT__MAX][256];
51 /* Used to hold event information */
52 static DCE2_EventNode dce2_events[DCE2_EVENT__MAX];
53 /* Used for matching a pdu string to a pdu type */
54 char *dce2_pdu_types[DCERPC_PDU_TYPE__MAX];
55 
56 /******************************************************************
57  * Function: DCE2_EventsInit()
58  *
59  * Initializes global data.
60  *
61  * Arguments: None
62  *
63  * Returns: None
64  *
65  ******************************************************************/
DCE2_EventsInit(void)66 void DCE2_EventsInit(void)
67 {
68     DCE2_Event event;
69     char gname[100];
70     unsigned int i;
71     static const DCE2_EventNode events[DCE2_EVENT__MAX] =
72     {
73         {
74             DCE2_EVENT_FLAG__NONE,
75             DCE2_EVENT__NO_EVENT,
76             "Have to use this because can't have an event sid of zero"
77         },
78         {
79             DCE2_EVENT_FLAG__MEMCAP,
80             DCE2_EVENT__MEMCAP,
81             "Memory cap exceeded"
82         },
83         {
84             DCE2_EVENT_FLAG__SMB,
85             DCE2_EVENT__SMB_BAD_NBSS_TYPE,
86             "SMB - Bad NetBIOS Session Service session type"
87         },
88         {
89             DCE2_EVENT_FLAG__SMB,
90             DCE2_EVENT__SMB_BAD_TYPE,
91             "SMB - Bad SMB message type"
92         },
93         {
94             DCE2_EVENT_FLAG__SMB,
95             DCE2_EVENT__SMB_BAD_ID,
96             "SMB - Bad SMB Id (not \\xffSMB for SMB1 or not \\xfeSMB for SMB2)"
97         },
98         {
99             DCE2_EVENT_FLAG__SMB,
100             DCE2_EVENT__SMB_BAD_WCT,
101             "SMB - Bad word count or structure size: %u"
102         },
103         {
104             DCE2_EVENT_FLAG__SMB,
105             DCE2_EVENT__SMB_BAD_BCC,
106             "SMB - Bad byte count: %u"
107         },
108         {
109             DCE2_EVENT_FLAG__SMB,
110             DCE2_EVENT__SMB_BAD_FORMAT,
111             "SMB - Bad format type: %u"
112         },
113         {
114             DCE2_EVENT_FLAG__SMB,
115             DCE2_EVENT__SMB_BAD_OFF,
116             "SMB - Bad offset: %p not between %p and %p"
117         },
118         {
119             DCE2_EVENT_FLAG__SMB,
120             DCE2_EVENT__SMB_TDCNT_ZERO,
121             "SMB - Zero total data count"
122         },
123         {
124             DCE2_EVENT_FLAG__SMB,
125             DCE2_EVENT__SMB_NB_LT_SMBHDR,
126             "SMB - NetBIOS data length (%u) less than SMB header length (%u)"
127         },
128         {
129             DCE2_EVENT_FLAG__SMB,
130             DCE2_EVENT__SMB_NB_LT_COM,
131             "SMB - Remaining NetBIOS data length (%u) less than command length (%u)"
132         },
133         {
134             DCE2_EVENT_FLAG__SMB,
135             DCE2_EVENT__SMB_NB_LT_BCC,
136             "SMB - Remaining NetBIOS data length (%u) less than command byte count (%u)"
137         },
138         {
139             DCE2_EVENT_FLAG__SMB,
140             DCE2_EVENT__SMB_NB_LT_DSIZE,
141             "SMB - Remaining NetBIOS data length (%u) less than command data size (%u)"
142         },
143         {
144             DCE2_EVENT_FLAG__SMB,
145             DCE2_EVENT__SMB_TDCNT_LT_DSIZE,
146             "SMB - Remaining total data count (%u) less than this command data size (%u)"
147         },
148         {
149             DCE2_EVENT_FLAG__SMB,
150             DCE2_EVENT__SMB_DSENT_GT_TDCNT,
151             "SMB - Total data sent ("STDu64") greater than command total data expected (%u)"
152         },
153         {
154             DCE2_EVENT_FLAG__SMB,
155             DCE2_EVENT__SMB_BCC_LT_DSIZE,
156             "SMB - Byte count (%u) less than command data size ("STDu64")"
157         },
158         {
159             DCE2_EVENT_FLAG__SMB,
160             DCE2_EVENT__SMB_INVALID_DSIZE,
161             "SMB - Invalid command data size (%u) for byte count (%u)"
162         },
163         {
164             DCE2_EVENT_FLAG__SMB,
165             DCE2_EVENT__SMB_EXCESSIVE_TREE_CONNECTS,
166             "SMB - Excessive Tree Connect requests (>%u) with pending Tree Connect responses"
167         },
168         {
169             DCE2_EVENT_FLAG__SMB,
170             DCE2_EVENT__SMB_EXCESSIVE_READS,
171             "SMB - Excessive Read requests (>%u) with pending Read responses"
172         },
173         {
174             DCE2_EVENT_FLAG__SMB,
175             DCE2_EVENT__SMB_EXCESSIVE_CHAINING,
176             "SMB - Excessive command chaining (>%u)"
177         },
178         {
179             DCE2_EVENT_FLAG__SMB,
180             DCE2_EVENT__SMB_MULT_CHAIN_SS,
181             "SMB - Multiple chained login requests"
182         },
183         {
184             DCE2_EVENT_FLAG__SMB,
185             DCE2_EVENT__SMB_MULT_CHAIN_TC,
186             "SMB - Multiple chained tree connect requests"
187         },
188         {
189             DCE2_EVENT_FLAG__SMB,
190             DCE2_EVENT__SMB_CHAIN_SS_LOGOFF,
191             "SMB - Chained/Compounded login followed by logoff"
192         },
193         {
194             DCE2_EVENT_FLAG__SMB,
195             DCE2_EVENT__SMB_CHAIN_TC_TDIS,
196             "SMB - Chained/Compounded tree connect followed by tree disconnect"
197         },
198         {
199             DCE2_EVENT_FLAG__SMB,
200             DCE2_EVENT__SMB_CHAIN_OPEN_CLOSE,
201             "SMB - Chained/Compounded open pipe followed by close pipe"
202         },
203         {
204             DCE2_EVENT_FLAG__SMB,
205             DCE2_EVENT__SMB_INVALID_SHARE,
206             "SMB - Invalid share access: %s"
207         },
208         {
209             DCE2_EVENT_FLAG__CO,
210             DCE2_EVENT__CO_BAD_MAJ_VERSION,
211             "Connection-oriented DCE/RPC - Invalid major version: %u"
212         },
213         {
214             DCE2_EVENT_FLAG__CO,
215             DCE2_EVENT__CO_BAD_MIN_VERSION,
216             "Connection-oriented DCE/RPC - Invalid minor version: %u"
217         },
218         {
219             DCE2_EVENT_FLAG__CO,
220             DCE2_EVENT__CO_BAD_PDU_TYPE,
221             "Connection-oriented DCE/RPC - Invalid pdu type: 0x%02x"
222         },
223         {
224             DCE2_EVENT_FLAG__CO,
225             DCE2_EVENT__CO_FLEN_LT_HDR,
226             "Connection-oriented DCE/RPC - Fragment length (%u) less than header size (%u)"
227         },
228         {
229             DCE2_EVENT_FLAG__CO,
230             DCE2_EVENT__CO_FLEN_LT_SIZE,
231             "Connection-oriented DCE/RPC - %s: Remaining fragment length (%u) less than size needed (%u)"
232         },
233         {
234             DCE2_EVENT_FLAG__CO,
235             DCE2_EVENT__CO_ZERO_CTX_ITEMS,
236             "Connection-oriented DCE/RPC - %s: No context items specified"
237         },
238         {
239             DCE2_EVENT_FLAG__CO,
240             DCE2_EVENT__CO_ZERO_TSYNS,
241             "Connection-oriented DCE/RPC - %s: No transfer syntaxes specified"
242         },
243         {
244             DCE2_EVENT_FLAG__CO,
245             DCE2_EVENT__CO_FRAG_LT_MAX_XMIT_FRAG,
246             "Connection-oriented DCE/RPC - %s: Fragment length on non-last fragment (%u) less than "
247                 "maximum negotiated fragment transmit size for client (%u)"
248         },
249         {
250             DCE2_EVENT_FLAG__CO,
251             DCE2_EVENT__CO_FRAG_GT_MAX_XMIT_FRAG,
252             "Connection-oriented DCE/RPC - %s: Fragment length (%u) greater than "
253                 "maximum negotiated fragment transmit size (%u)"
254         },
255         {
256             DCE2_EVENT_FLAG__CO,
257             DCE2_EVENT__CO_ALTER_CHANGE_BYTE_ORDER,
258             "Connection-oriented DCE/RPC - Alter Context byte order different from Bind"
259         },
260         {
261             DCE2_EVENT_FLAG__CO,
262             DCE2_EVENT__CO_FRAG_DIFF_CALL_ID,
263             "Connection-oriented DCE/RPC - Call id (%u) of non first/last fragment different "
264                 "from call id established for fragmented request (%u)"
265         },
266         {
267             DCE2_EVENT_FLAG__CO,
268             DCE2_EVENT__CO_FRAG_DIFF_OPNUM,
269             "Connection-oriented DCE/RPC - Opnum (%u) of non first/last fragment different "
270                 "from opnum established for fragmented request (%u)"
271         },
272         {
273             DCE2_EVENT_FLAG__CO,
274             DCE2_EVENT__CO_FRAG_DIFF_CTX_ID,
275             "Connection-oriented DCE/RPC - Context id (%u) of non first/last fragment different "
276                 "from context id established for fragmented request (%u)"
277         },
278         {
279             DCE2_EVENT_FLAG__CL,
280             DCE2_EVENT__CL_BAD_MAJ_VERSION,
281             "Connection-less DCE/RPC - Invalid major version: %u"
282         },
283         {
284             DCE2_EVENT_FLAG__CL,
285             DCE2_EVENT__CL_BAD_PDU_TYPE,
286             "Connection-less DCE/RPC - Invalid pdu type: 0x%02x"
287         },
288         {
289             DCE2_EVENT_FLAG__CL,
290             DCE2_EVENT__CL_DATA_LT_HDR,
291             "Connection-less DCE/RPC - Data length (%u) less than header size (%u)"
292         },
293         {
294             DCE2_EVENT_FLAG__CL,
295             DCE2_EVENT__CL_BAD_SEQ_NUM,
296             "Connection-less DCE/RPC - %s: Bad sequence number"
297         },
298         {
299             DCE2_EVENT_FLAG__SMB,
300             DCE2_EVENT__SMB_V1,
301             "SMB - Invalid SMB version 1 seen"
302         },
303         {
304             DCE2_EVENT_FLAG__SMB,
305             DCE2_EVENT__SMB_V2,
306             "SMB - Invalid SMB version 2 seen"
307         },
308         {
309             DCE2_EVENT_FLAG__SMB,
310             DCE2_EVENT__SMB_INVALID_BINDING,
311             "SMB - Invalid user, tree connect, file binding"
312         },
313         {
314             DCE2_EVENT_FLAG__SMB,
315             DCE2_EVENT__SMB2_EXCESSIVE_COMPOUNDING,
316             "SMB - Excessive command compounding (>%u)"
317         },
318         {
319             DCE2_EVENT_FLAG__SMB,
320             DCE2_EVENT__SMB_DCNT_ZERO,
321             "SMB - Zero data count"
322         },
323         {
324             DCE2_EVENT_FLAG__SMB,
325             DCE2_EVENT__SMB_DCNT_MISMATCH,
326             "SMB - Data count mismatch %u in command / %u in format"
327         },
328         {
329             DCE2_EVENT_FLAG__SMB,
330             DCE2_EVENT__SMB_MAX_REQS_EXCEEDED,
331             "SMB - Maximum number of outstanding requests exceeded: %u"
332         },
333         {
334             DCE2_EVENT_FLAG__SMB,
335             DCE2_EVENT__SMB_REQS_SAME_MID,
336             "SMB - Outstanding requests with same MID",
337         },
338         {
339             DCE2_EVENT_FLAG__SMB,
340             DCE2_EVENT__SMB_DEPR_DIALECT_NEGOTIATED,
341             "SMB - Deprecated dialect negotiated"
342         },
343         {
344             DCE2_EVENT_FLAG__SMB,
345             DCE2_EVENT__SMB_DEPR_COMMAND_USED,
346             "SMB - Deprecated command used: %s"
347         },
348         {
349             DCE2_EVENT_FLAG__SMB,
350             DCE2_EVENT__SMB_UNUSUAL_COMMAND_USED,
351             "SMB - Unusual command used: %s"
352         },
353         {
354             DCE2_EVENT_FLAG__SMB,
355             DCE2_EVENT__SMB_INVALID_SETUP_COUNT,
356             "SMB - Invalid setup count for %s/%s command: %u"
357         },
358         {
359             DCE2_EVENT_FLAG__SMB,
360             DCE2_EVENT__SMB_MULTIPLE_NEGOTIATIONS,
361             "SMB - Client attempted multiple dialect negotiations on session"
362         },
363         {
364             DCE2_EVENT_FLAG__SMB,
365             DCE2_EVENT__SMB_EVASIVE_FILE_ATTRS,
366             "SMB - Client attempted to create or set a file's attributes to readonly/hidden/system"
367         },
368         {
369             DCE2_EVENT_FLAG__SMB,
370             DCE2_EVENT__SMB_INVALID_FILE_OFFSET,
371             "SMB - File offset provided is greater than file size specified"
372         },
373         {
374             DCE2_EVENT_FLAG__SMB,
375             DCE2_EVENT__SMB_BAD_NEXT_COMMAND_OFFSET,
376             "SMB - Nextcommand specified in SMB2 header is beyond payload boundary"
377         }
378     };
379 
380     snprintf(gname, sizeof(gname) - 1, "(%s) ", DCE2_GNAME);
381     gname[sizeof(gname) - 1] = '\0';
382 
383     for (event = DCE2_EVENT__NO_EVENT; event < DCE2_EVENT__MAX; event++)
384     {
385         int size = strlen(gname) + strlen(events[event].format) + 1;
386 
387         /* This is a check to make sure all of the events in the array are
388          * in the same order as the enum, so we index the right thing when
389          * alerting - DO NOT REMOVE THIS CHECK */
390         if (events[event].event != event)
391         {
392             DCE2_Die("%s(%d) Events are not in the right order.",
393                      __FILE__, __LINE__);
394         }
395 
396         dce2_events[event].format = (char *)DCE2_Alloc(size, DCE2_MEM_TYPE__INIT);
397         if (dce2_events[event].format == NULL)
398         {
399             DCE2_Die("%s(%d) Could not allocate memory for events array.",
400                      __FILE__, __LINE__);
401         }
402 
403         dce2_events[event].format[size - 1] = '\0';
404         snprintf(dce2_events[event].format, size, "%s%s", gname, events[event].format);
405         if (dce2_events[event].format[size - 1] != '\0')
406         {
407             DCE2_Die("%s(%d) Event string truncated.", __FILE__, __LINE__);
408         }
409 
410         dce2_events[event].eflag = events[event].eflag;
411         dce2_events[event].event = events[event].event;
412     }
413 
414     for (i = 0; i < (sizeof(dce2_pdu_types) / sizeof(char *)); i++)
415     {
416         char *type;
417 
418         switch (i)
419         {
420             case DCERPC_PDU_TYPE__REQUEST:
421                 type = "Request";
422                 break;
423             case DCERPC_PDU_TYPE__PING:
424                 type = "Ping";
425                 break;
426             case DCERPC_PDU_TYPE__RESPONSE:
427                 type = "Response";
428                 break;
429             case DCERPC_PDU_TYPE__FAULT:
430                 type = "Fault";
431                 break;
432             case DCERPC_PDU_TYPE__WORKING:
433                 type = "Working";
434                 break;
435             case DCERPC_PDU_TYPE__NOCALL:
436                 type = "NoCall";
437                 break;
438             case DCERPC_PDU_TYPE__REJECT:
439                 type = "Reject";
440                 break;
441             case DCERPC_PDU_TYPE__ACK:
442                 type = "Ack";
443                 break;
444             case DCERPC_PDU_TYPE__CL_CANCEL:
445                 type = "Cancel";
446                 break;
447             case DCERPC_PDU_TYPE__FACK:
448                 type = "Fack";
449                 break;
450             case DCERPC_PDU_TYPE__CANCEL_ACK:
451                 type = "Cancel Ack";
452                 break;
453             case DCERPC_PDU_TYPE__BIND:
454                 type = "Bind";
455                 break;
456             case DCERPC_PDU_TYPE__BIND_ACK:
457                 type = "Bind Ack";
458                 break;
459             case DCERPC_PDU_TYPE__BIND_NACK:
460                 type = "Bind Nack";
461                 break;
462             case DCERPC_PDU_TYPE__ALTER_CONTEXT:
463                 type = "Alter Context";
464                 break;
465             case DCERPC_PDU_TYPE__ALTER_CONTEXT_RESP:
466                 type = "Alter Context Response";
467                 break;
468             case DCERPC_PDU_TYPE__AUTH3:
469                 type = "Auth3";
470                 break;
471             case DCERPC_PDU_TYPE__SHUTDOWN:
472                 type = "Shutdown";
473                 break;
474             case DCERPC_PDU_TYPE__CO_CANCEL:
475                 type = "Cancel";
476                 break;
477             case DCERPC_PDU_TYPE__ORPHANED:
478                 type = "Orphaned";
479                 break;
480             case DCERPC_PDU_TYPE__MICROSOFT_PROPRIETARY_OUTLOOK2003_RPC_OVER_HTTP:
481                 type = "Microsoft Exchange/Outlook 2003";
482                 break;
483             default:
484                 type = "Unknown DCE/RPC type";
485                 break;
486         }
487 
488         dce2_pdu_types[i] = (char *)DCE2_Alloc(strlen(type) + 1, DCE2_MEM_TYPE__INIT);
489         strncpy(dce2_pdu_types[i], type, strlen(type));
490         dce2_pdu_types[i][strlen(type)] = '\0';
491 #ifdef DCE2_EVENT_PRINT_DEBUG
492         printf("%s\n", dce2_pdu_types[i]);
493 #endif
494     }
495 }
496 
497 /******************************************************************
498  * Function: DCE2_Alert()
499  *
500  * Potentially generates an alert if an event is triggered.
501  *
502  * Arguments:
503  *  DCE2_SsnData *
504  *      This is the current session data structure being used
505  *      when the event was triggered.  It is not a necessary
506  *      argument if no session data is currently available, for
507  *      example if the event is a memcap event - pass in NULL in
508  *      this case.
509  *  DCE2_Event
510  *      The event type that was triggered.
511  *  ...
512  *      The arguments to the format for the event.
513  *
514  * Returns: None
515  *
516  ******************************************************************/
DCE2_Alert(DCE2_SsnData * sd,DCE2_Event e,...)517 void DCE2_Alert(DCE2_SsnData *sd, DCE2_Event e, ...)
518 {
519     va_list ap;
520 
521 #ifdef DEBUG_MSGS
522     // When debugging want to see all of the alerts generated
523     va_start(ap, e);
524     vsnprintf(dce2_event_bufs[e], sizeof(dce2_event_bufs[e]) - 1, dce2_events[e].format, ap);
525     va_end(ap);
526 
527     dce2_event_bufs[e][sizeof(dce2_event_bufs[e]) - 1] = '\0';
528     DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__ALL, "DCE2 Alert => %s\n", dce2_event_bufs[e]));
529 #endif
530 
531     if (sd != NULL)
532     {
533         // NOTE This check needs to change if the number of preprocessor events
534         // should exceed 63
535 
536         /* Only log a specific alert once per session */
537         if (sd->alert_mask & ((uint64_t)1 << e))
538             return;
539 
540         /* set bit for this alert so we don't alert on again
541          * in this session */
542         sd->alert_mask |= ((uint64_t)1 << e);
543     }
544 
545     if (!DCE2_GcAlertOnEvent(dce2_events[e].eflag))
546         return;
547 
548     dce2_stats.events++;
549 
550 #ifndef DEBUG_MSGS
551     va_start(ap, e);
552     vsnprintf(dce2_event_bufs[e], sizeof(dce2_event_bufs[e]) - 1, dce2_events[e].format, ap);
553     va_end(ap);
554 
555     dce2_event_bufs[e][sizeof(dce2_event_bufs[e]) - 1] = '\0';
556     DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__ALL, "DCE2 Alert => %s\n", dce2_event_bufs[e]));
557 #endif
558 
559     _dpd.alertAdd(GENERATOR_DCE2, e, 1, 0, 3, dce2_event_bufs[e], 0);
560 }
561 
562 /******************************************************************
563  * Function: DCE2_EventsFree()
564  *
565  * Frees any global data that was dynamically allocated.
566  *
567  * Arguments: None
568  *
569  * Returns: None
570  *
571  ******************************************************************/
DCE2_EventsFree(void)572 void DCE2_EventsFree(void)
573 {
574     unsigned int i;
575 
576     for (i = 0; i < DCE2_EVENT__MAX; i++)
577     {
578         if (dce2_events[i].format != NULL)
579         {
580             DCE2_Free((void *)dce2_events[i].format, strlen(dce2_events[i].format) + 1, DCE2_MEM_TYPE__INIT);
581             dce2_events[i].format = NULL;
582         }
583     }
584 
585     for (i = 0; i < (sizeof(dce2_pdu_types) / sizeof(char *)); i++)
586     {
587         if (dce2_pdu_types[i] != NULL)
588         {
589             DCE2_Free((void *)dce2_pdu_types[i], strlen(dce2_pdu_types[i]) + 1, DCE2_MEM_TYPE__INIT);
590             dce2_pdu_types[i] = NULL;
591         }
592     }
593 }
594 
595