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