1 /*
2 ** Copyright (C) 2014-2021 Cisco and/or its affiliates. All rights reserved.
3 ** Copyright (C) 2005-2013 Sourcefire, Inc.
4 ** Copyright (C) 1998-2005 Martin Roesch <roesch@sourcefire.com>
5 **
6 ** This program is free software; you can redistribute it and/or modify
7 ** it under the terms of the GNU General Public License Version 2 as
8 ** published by the Free Software Foundation. You may not use, modify or
9 ** distribute this program under any other version of the GNU General
10 ** Public License.
11 **
12 ** This program is distributed in the hope that it will be useful,
13 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
14 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 ** GNU General Public License for more details.
16 **
17 ** You should have received a copy of the GNU General Public License
18 ** along with this program; if not, write to the Free Software
19 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 */
21
22 /* $Id$ */
23 /* Snort Preprocessor Plugin Source File Bo */
24
25 /* spp_bo
26 *
27 * Purpose: Detects Back Orifice traffic by brute forcing the weak encryption
28 * of the program's network protocol and detects the magic cookie
29 * that it's servers and clients require to communicate with each
30 * other.
31 *
32 * Arguments: none
33 *
34 * Effect: Analyzes UDP traffic for the BO magic cookie, reports if it finds
35 * traffic matching the profile.
36 *
37 * Comments:
38 *
39 */
40
41 /*
42 * The following text describes a couple of ways in which the Back Orifice
43 * signature is calculated. The snort runtime generated an array of 65K
44 * possible signatures, of which two are described here. Refer back to
45 * this simplified algorithm when evaluating the snort code below.
46 *
47 * Back Orifice magic cookie is "*!*QWTY?", which is located in the first
48 * eight bytes of the packet. But it is encrypted using an XOR. Here we'll
49 * generate a sequence of eight bytes which will decrypt (XOR) into the
50 * magic cookie. This test uses the NON-DEFAULT KEY to initialize (seed) the
51 * "random" number generator. The default seed results in the following
52 * sequence of bytes: E4 42 FB 83 41 B3 4A F0. When XOR'd against the
53 * magic cookie, we have our packet data which looks like a Back Orifice
54 * signature:
55 *
56 * Cookie: 2A 21 2A 51 57 54 59 3F
57 * Random: E4 42 FB 83 41 B3 4A F0
58 * ------- -- -- -- -- -- -- -- --
59 * Result: CE 63 D1 D2 16 E7 13 CF (XOR'd result)
60 *
61 * For demonstration purposes:
62 *
63 * static long holdrand = 1L;
64 * static int LocalBoRand()
65 * {
66 * return(((holdrand = holdrand * 214013L + 2531011L) >> 16) & 0x7fff);
67 * }
68 * ...
69 *
70 * int BoRandValues_NonDefaultKey[8];
71 * holdrand = BACKORIFICE_DEFAULT_KEY; (seed value)
72 * BoRandValues_NonDefaultKey[0] = LocalBoRand() % 256; --> 228 (0xe4)
73 * BoRandValues_NonDefaultKey[1] = LocalBoRand() % 256; --> 66 (0x42)
74 * BoRandValues_NonDefaultKey[2] = LocalBoRand() % 256; --> 251 (0xfb)
75 * BoRandValues_NonDefaultKey[3] = LocalBoRand() % 256; --> 131 (0x83)
76 * BoRandValues_NonDefaultKey[4] = LocalBoRand() % 256; --> 65 (0x41)
77 * BoRandValues_NonDefaultKey[5] = LocalBoRand() % 256; --> 179 (0xb3)
78 * BoRandValues_NonDefaultKey[6] = LocalBoRand() % 256; --> 74 (0x4a)
79 * BoRandValues_NonDefaultKey[7] = LocalBoRand() % 256; --> 240 (0xf0)
80 *
81 *
82 * The following test uses the DEFAULT KEY to initialize (seed) the
83 * "random" number generator. The default seed results in the following
84 * sequence of bytes: 26 27 F6 85 97 15 AD 1D. When XOR'd against the
85 * magic cookie, we have our packet data which looks like a Back Orifice
86 * signature:
87 *
88 * Cookie: 2A 21 2A 51 57 54 59 3F
89 * Random: 26 27 F6 85 97 15 AD 1D
90 * ------- -- -- -- -- -- -- -- --
91 * Result: 0C 06 DC D4 C0 41 F4 22 (XOR'd result)
92 *
93 * For demonstration purposes:
94 *
95 * int BoRandValues_DefaultKey[8];
96 * holdrand = 0; (seed value)
97 * BoRandValues_DefaultKey[0] = LocalBoRand() % 256; --> 38 (0x26)
98 * BoRandValues_DefaultKey[1] = LocalBoRand() % 256; --> 39 (0x27)
99 * BoRandValues_DefaultKey[2] = LocalBoRand() % 256; --> 246 (0xf6)
100 * BoRandValues_DefaultKey[3] = LocalBoRand() % 256; --> 133 (0x85)
101 * BoRandValues_DefaultKey[4] = LocalBoRand() % 256; --> 151 (0x97)
102 * BoRandValues_DefaultKey[5] = LocalBoRand() % 256; --> 21 (0x15)
103 * BoRandValues_DefaultKey[6] = LocalBoRand() % 256; --> 173 (0xad)
104 * BoRandValues_DefaultKey[7] = LocalBoRand() % 256; --> 29 (0x1d)
105 *
106 * Notes:
107 *
108 * 10/13/2005 marc norton - This has a lot of changes to the runtime
109 * decoding and testing. The '% 256' op was removed,
110 * the xor op is bit wise so modulo is not needed,
111 * the char casting truncates to one byte,
112 * and len testing has been modified as was the xor decode copy and
113 * final PONG test.
114 */
115
116 #include <assert.h>
117 #include <sys/types.h>
118 #include <stdlib.h>
119 #include <ctype.h>
120 #include <string.h>
121
122 #ifdef HAVE_CONFIG_H
123 #include "config.h"
124 #endif
125
126 #include "sf_types.h"
127 #include "generators.h"
128 #include "log.h"
129 #include "detect.h"
130 #include "decode.h"
131 #include "event.h"
132 #include "plugbase.h"
133 #include "parser.h"
134 #include "snort_debug.h"
135 #include "mstring.h"
136 #include "util.h"
137 #include "event_queue.h"
138 /* In case we need to drop this packet */
139 #include "active.h"
140 #include "snort.h"
141 #include "profiler.h"
142 #include "sf_types.h"
143 #include "sfPolicy.h"
144 #include "sfPolicyUserData.h"
145 #include "session_api.h"
146
147 #define BACKORIFICE_DEFAULT_KEY 31337
148 #define BACKORIFICE_MAGIC_SIZE 8
149 #define BACKORIFICE_MIN_SIZE 18
150 #define BACKORIFICE_DEFAULT_PORT 31337
151 #define BO_TYPE_PING 1
152 #define BO_FROM_UNKNOWN 0
153 #define BO_FROM_CLIENT 1
154 #define BO_FROM_SERVER 2
155
156 #define BO_BUF_SIZE 8
157 #define BO_BUF_ATTACK_SIZE 1024
158
159 /* Configuration defines */
160 #define MODNAME "spp_bo"
161 #define START_LIST "{"
162 #define END_LIST "}"
163 #define CONF_SEPARATORS " \t\n\r"
164 #define BO_ALERT_GENERAL 0x0001
165 #define BO_ALERT_CLIENT 0x0002
166 #define BO_ALERT_SERVER 0x0004
167 #define BO_ALERT_SNORT_ATTACK 0x0008
168
169 typedef struct _BoConfig
170 {
171 int noalert_flags;
172 int drop_flags;
173
174 } BoConfig;
175
176
177 /* global keyvalue for the BoRand() function */
178 static long holdrand = 1L;
179 static uint16_t lookup1[65536][3];
180 static uint16_t lookup2[65536];
181
182 #ifdef PERF_PROFILING
183 PreprocStats boPerfStats;
184 #endif
185
186 static tSfPolicyUserContextId bo_config = NULL;
187
188 /* list of function prototypes for this preprocessor */
189 static void BoInit(struct _SnortConfig *, char *);
190 static void BoFind(Packet *, void *);
191
192 /* list of private functions */
193 static int BoGetDirection(BoConfig *bo, Packet *p, char *pkt_data);
194 static void PrecalcPrefix(void);
195 static char BoRand(void);
196 static void ProcessArgs(BoConfig *, char *args);
197 static int ProcessOptionList(void);
198 static void PrintConfig(BoConfig *);
199 static void BoFreeConfig(tSfPolicyUserContextId bo);
200 static void BoCleanExit(int, void *);
201
202 #ifdef SNORT_RELOAD
203 static void BoReload(struct _SnortConfig *, char *, void **);
204 static void * BoReloadSwap(struct _SnortConfig *, void *);
205 static void BoReloadSwapFree(void *);
206 #endif
207
208 /*
209 * Function: SetupBo()
210 *
211 * Purpose: Registers the preprocessor keyword and initialization
212 * function into the preprocessor list.
213 *
214 * Arguments: None.
215 *
216 * Returns: void function
217 *
218 */
SetupBo(void)219 void SetupBo(void)
220 {
221 /* link the preprocessor keyword to the init function in
222 the preproc list */
223 #ifndef SNORT_RELOAD
224 RegisterPreprocessor("bo", BoInit);
225 #else
226 RegisterPreprocessor("bo", BoInit, BoReload, NULL, BoReloadSwap, BoReloadSwapFree);
227 #endif
228
229 DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN,
230 "Preprocessor: Back Orifice is setup...\n"););
231 }
232
233
234 /*
235 * Function: BoInit(char *)
236 *
237 * Purpose: Link the BO preprocessor to the preperocessor call chain.
238 *
239 * Arguments: args => ptr to argument string (spp_bo takes no args)
240 *
241 * Returns: void function
242 *
243 */
BoInit(struct _SnortConfig * sc,char * args)244 static void BoInit(struct _SnortConfig *sc, char *args)
245 {
246 int policy_id = (int)getParserPolicy(sc);
247 BoConfig *pPolicyConfig = NULL;
248
249 if (bo_config == NULL)
250 {
251 //create a context
252 bo_config = sfPolicyConfigCreate();
253
254 DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN,"Preprocessor: Bo Initialized\n"););
255
256 /* we no longer need to take args */
257 PrecalcPrefix();
258
259 AddFuncToPreprocCleanExitList(BoCleanExit, NULL, PRIORITY_LAST, PP_BO);
260
261 #ifdef PERF_PROFILING
262 RegisterPreprocessorProfile("backorifice", &boPerfStats, 0, &totalPerfStats, NULL);
263 #endif
264 }
265
266 sfPolicyUserPolicySet (bo_config, policy_id);
267 pPolicyConfig = (BoConfig *)sfPolicyUserDataGetCurrent(bo_config);
268 if (pPolicyConfig)
269 {
270 ParseError("BO preprocessor can only be configured once.\n");
271 }
272
273 pPolicyConfig = (BoConfig *)SnortAlloc(sizeof(BoConfig));
274 if (!pPolicyConfig)
275 {
276 ParseError("BO preprocessor: memory allocate failed.\n");
277 }
278
279 sfPolicyUserDataSetCurrent(bo_config, pPolicyConfig);
280
281 /* Process argument list */
282 ProcessArgs(pPolicyConfig, args);
283
284 /* Set the preprocessor function into the function list */
285 AddFuncToPreprocList(sc, BoFind, PRIORITY_APPLICATION, PP_BO, PROTO_BIT__UDP);
286 session_api->enable_preproc_all_ports( sc, PP_BO, PROTO_BIT__UDP );
287 }
288
289
290 /*
291 * Function: ProcessArgs(char *)
292 *
293 * Purpose: Parse additional config items.
294 *
295 * Arguments: args => ptr to argument string
296 * syntax:
297 * preprocessor bo: noalert { client | server | general | snort_attack } \
298 * drop { client | server | general | snort_attack }
299 *
300 * example:
301 * preprocessor bo: noalert { general server } drop { snort_attack }
302 *
303 * Returns: void function
304 *
305 */
ProcessArgs(BoConfig * bo,char * args)306 static void ProcessArgs(BoConfig *bo, char *args)
307 {
308 char *arg;
309
310 if ((args == NULL) || (bo == NULL))
311 return;
312
313 arg = strtok(args, CONF_SEPARATORS);
314
315 while ( arg != NULL )
316 {
317 if ( !strcasecmp("noalert", arg) )
318 {
319 bo->noalert_flags = (uint16_t)ProcessOptionList();
320 }
321 else if ( !strcasecmp("drop", arg) )
322 {
323 bo->drop_flags = (uint16_t)ProcessOptionList();
324 }
325 else
326 {
327 FatalError("%s(%d) => Unknown bo option %s.\n",
328 file_name, file_line, arg);
329 }
330
331 arg = strtok(NULL, CONF_SEPARATORS);
332 }
333
334 PrintConfig(bo);
335 }
336
337
338 /*
339 * Function: ProcessOptionList(u_char *)
340 *
341 * Purpose: Parse config list, either "noalert" or "drop".
342 *
343 * Arguments: none, use string from strtok in ProcessArgs
344 *
345 * Returns: AND'ed list of flags based on option list
346 *
347 */
ProcessOptionList(void)348 static int ProcessOptionList(void)
349 {
350 char *arg;
351 int retFlags = 0;
352 int endList = 0;
353
354 arg = strtok(NULL, CONF_SEPARATORS);
355
356 if ( arg == NULL || strcmp(START_LIST, arg) )
357 {
358 FatalError("%s(%d) => Invalid bo option.\n", file_name, file_line);
359 //return 0;
360 }
361
362 while ((arg = strtok(NULL, CONF_SEPARATORS)) != NULL)
363 {
364 if ( !strcmp(END_LIST, arg) )
365 {
366 endList = 1;
367 break;
368 }
369
370 if ( !strcasecmp("general", arg) )
371 {
372 retFlags |= BO_ALERT_GENERAL;
373 }
374 else if ( !strcasecmp("client", arg) )
375 {
376 retFlags |= BO_ALERT_CLIENT;
377 }
378 else if ( !strcasecmp("server", arg) )
379 {
380 retFlags |= BO_ALERT_SERVER;
381 }
382 else if ( !strcasecmp("snort_attack", arg) )
383 {
384 retFlags |= BO_ALERT_SNORT_ATTACK;
385 }
386 else
387 {
388 FatalError("%s(%d) => Invalid bo option argument %s.\n",
389 file_name, file_line, arg);
390 }
391 }
392
393 if ( !endList )
394 {
395 FatalError("%s(%d) => Must end configuration list with %s.\n",
396 file_name, file_line, END_LIST);
397 //return 0;
398 }
399
400 return retFlags;
401 }
402
403 /*
404 * Function: PrintConfig()
405 *
406 * Purpose: Print configuration
407 *
408 * Arguments: none
409 *
410 * Returns: none
411 *
412 */
PrintConfig(BoConfig * bo)413 static void PrintConfig(BoConfig *bo)
414 {
415 if (bo == NULL)
416 return;
417
418 if ( bo->noalert_flags != 0 || bo->drop_flags != 0 )
419 LogMessage("Back Orifice Config:\n");
420
421 if ( bo->noalert_flags != 0 )
422 {
423 LogMessage(" Disable alerts:");
424 if ( bo->noalert_flags & BO_ALERT_CLIENT )
425 LogMessage(" client");
426 if ( bo->noalert_flags & BO_ALERT_SERVER )
427 LogMessage(" server");
428 if ( bo->noalert_flags & BO_ALERT_GENERAL )
429 LogMessage(" general");
430 if ( bo->noalert_flags & BO_ALERT_SNORT_ATTACK )
431 LogMessage(" snort_attack");
432 LogMessage("\n");
433 }
434 if ( bo->drop_flags != 0 )
435 {
436 LogMessage(" Drop packets (inline only) on alerts:");
437 if ( bo->drop_flags & BO_ALERT_CLIENT )
438 LogMessage(" client");
439 if ( bo->drop_flags & BO_ALERT_SERVER )
440 LogMessage(" server");
441 if ( bo->drop_flags & BO_ALERT_GENERAL )
442 LogMessage(" general");
443 if ( bo->drop_flags & BO_ALERT_SNORT_ATTACK )
444 LogMessage(" snort_attack");
445 LogMessage("\n");
446 }
447 }
448
449 /*
450 * Function: BoRand()
451 *
452 * Purpose: Back Orifice "encryption" algorithm
453 *
454 * Arguments: None.
455 *
456 * Returns: key to XOR with current char to be "encrypted"
457 */
BoRand(void)458 static char BoRand(void)
459 {
460 holdrand = holdrand * 214013L + 2531011L;
461 return (char) (((holdrand >> 16) & 0x7fff) & 0xFF);
462 }
463
464
465 /*
466 * Precalculate the known cyphertext into a prefix and suffix lookup table
467 * to recover the key. Using this in the BoFind() function below is much
468 * faster than the old brute force method
469 */
PrecalcPrefix(void)470 static void PrecalcPrefix(void)
471 {
472 uint8_t cookie_cyphertext[BACKORIFICE_MAGIC_SIZE];
473 char *cookie_plaintext = "*!*QWTY?";
474 int key;
475 int cookie_index;
476 char *cp_ptr; /* cookie plaintext indexing pointer */
477 uint16_t cyphertext_referent;
478
479 memset(lookup1, 0, sizeof(lookup1));
480 memset(lookup2, 0, sizeof(lookup2));
481
482 for(key=0;key<65536;key++)
483 {
484 /* setup to generate cyphertext for this key */
485 holdrand = key;
486 cp_ptr = cookie_plaintext;
487
488 /* convert the plaintext cookie to cyphertext for this key */
489 for(cookie_index=0;cookie_index<BACKORIFICE_MAGIC_SIZE;cookie_index++)
490 {
491 cookie_cyphertext[cookie_index] =(uint8_t)(*cp_ptr^(BoRand()));
492 cp_ptr++;
493 }
494
495 /*
496 * generate the key lookup mechanism from the first 2 characters of
497 * the cyphertext
498 */
499 cyphertext_referent = (uint16_t) (cookie_cyphertext[0] << 8) & 0xFF00;
500 cyphertext_referent |= (uint16_t) (cookie_cyphertext[1]) & 0x00FF;
501
502 /* if there are any keyspace collisions that's going to suck */
503 if(lookup1[cyphertext_referent][0] != 0)
504 {
505 if(lookup1[cyphertext_referent][1] != 0)
506 {
507 lookup1[cyphertext_referent][2] = (uint16_t)key;
508 }
509 else
510 {
511 lookup1[cyphertext_referent][1] = (uint16_t)key;
512 }
513 }
514 else
515 {
516 lookup1[cyphertext_referent][0] = (uint16_t)key;
517 }
518
519 /*
520 * generate the second lookup from the last two characters of
521 * the cyphertext
522 */
523 cyphertext_referent = (uint16_t) (cookie_cyphertext[6] << 8) & 0xFF00;
524 cyphertext_referent |= (uint16_t) (cookie_cyphertext[7]) & 0x00FF;
525
526 /*
527 * set the second lookup with the current key
528 */
529 lookup2[key] = cyphertext_referent;
530 }
531 }
532
533
534 /*
535 * Function: BoFind(Packet *)
536 *
537 * Purpose: Look for the magic cookie, squawk if you find it.
538 *
539 * Arguments: p => pointer to the current packet data struct
540 *
541 * Returns: void function
542 *
543 *
544 */
BoFind(Packet * p,void * context)545 static void BoFind(Packet *p, void *context)
546 {
547 uint16_t cyphertext_referent;
548 uint16_t cyphertext_suffix;
549 uint16_t key;
550 char *magic_cookie = "*!*QWTY?";
551 char *pkt_data;
552 char *magic_data;
553 char *end;
554 char plaintext;
555 int i;
556 int bo_direction = 0;
557 uint32_t sid = 0;
558 BoConfig *bo = NULL;
559 PROFILE_VARS;
560
561 sfPolicyUserPolicySet (bo_config, getNapRuntimePolicy());
562 bo = (BoConfig *)sfPolicyUserDataGetCurrent(bo_config);
563
564 /* Not configured in this policy */
565 if (bo == NULL)
566 return;
567
568 // preconditions - what we registered for
569 assert(IsUDP(p));
570
571 /* make sure it's at least 19 bytes long */
572 if(p->dsize < BACKORIFICE_MIN_SIZE)
573 {
574 return;
575 }
576
577 PREPROC_PROFILE_START(boPerfStats);
578
579 /*
580 * take the first two characters of the packet and generate the
581 * first reference that gives us a reference key
582 */
583 cyphertext_referent = (uint16_t) (p->data[0] << 8) & 0xFF00;
584 cyphertext_referent |= (uint16_t) (p->data[1]) & 0x00FF;
585
586 /*
587 * generate the second referent from the last two characters
588 * of the cyphertext
589 */
590 cyphertext_suffix = (uint16_t) (p->data[6] << 8) & 0xFF00;
591 cyphertext_suffix |= (uint16_t) (p->data[7]) & 0x00FF;
592
593 for(i=0;i<3;i++)
594 {
595 /* get the key from the cyphertext */
596 key = lookup1[cyphertext_referent][i];
597
598 /*
599 * if the lookup from the proposed key matches the cyphertext reference
600 * then we've probably go the right key and can proceed to full
601 * decryption using the key
602 *
603 * moral of the story: don't use a lame keyspace
604 */
605 if(lookup2[key] == cyphertext_suffix)
606 {
607 holdrand = key;
608 pkt_data = (char*)p->data;
609 end = (char*)p->data + BACKORIFICE_MAGIC_SIZE;
610 magic_data = magic_cookie;
611
612 while(pkt_data<end)
613 {
614 plaintext = (char) (*pkt_data ^ BoRand());
615
616 if(*magic_data != plaintext)
617 {
618 DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN,
619 "Failed check one on 0x%X : 0x%X\n",
620 *magic_data, plaintext););
621 PREPROC_PROFILE_END(boPerfStats);
622 return;
623 }
624
625 magic_data++;
626 pkt_data++;
627 }
628
629 /* if we fall thru there's a detect */
630 DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN,
631 "Detected Back Orifice Data!\n");
632 DebugMessage(DEBUG_PLUGIN, "hash value: %d\n", key););
633
634 bo_direction = BoGetDirection(bo, p, pkt_data);
635
636 if ( bo_direction == BO_FROM_CLIENT )
637 {
638 if ( !(bo->noalert_flags & BO_ALERT_CLIENT) )
639 {
640 SnortEventqAdd(GENERATOR_SPP_BO, BO_CLIENT_TRAFFIC_DETECT, 1, 0, 0,
641 BO_CLIENT_TRAFFIC_DETECT_STR, 0);
642 }
643 if ( (bo->drop_flags & BO_ALERT_CLIENT) )
644 {
645 Active_DropSession(p);
646 sid = BO_CLIENT_TRAFFIC_DETECT;
647 }
648 DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, "Client packet\n"););
649 }
650 else if ( bo_direction == BO_FROM_SERVER )
651 {
652 if ( !(bo->noalert_flags & BO_ALERT_SERVER) )
653 {
654 SnortEventqAdd(GENERATOR_SPP_BO, BO_SERVER_TRAFFIC_DETECT, 1, 0, 0,
655 BO_SERVER_TRAFFIC_DETECT_STR, 0);
656 }
657 if ( (bo->drop_flags & BO_ALERT_SERVER) )
658 {
659 Active_DropSession(p);
660 sid = BO_SERVER_TRAFFIC_DETECT;
661 }
662 DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, "Server packet\n"););
663 }
664 else
665 {
666 if ( !(bo->noalert_flags & BO_ALERT_GENERAL) )
667 {
668 SnortEventqAdd(GENERATOR_SPP_BO, BO_TRAFFIC_DETECT, 1, 0, 0,
669 BO_TRAFFIC_DETECT_STR, 0);
670 }
671 if ( (bo->drop_flags & BO_ALERT_GENERAL) )
672 {
673 Active_DropSession(p);
674 sid = BO_TRAFFIC_DETECT;
675 }
676 }
677 }
678 }
679 if (Active_PacketWasDropped() || Active_PacketWouldBeDropped())
680 {
681 if (pkt_trace_enabled)
682 addPktTraceData(VERDICT_REASON_BO, snprintf(trace_line, MAX_TRACE_LINE,
683 "Back Orifice: gid %u, sid %u, %s\n", GENERATOR_SPP_BO, sid, getPktTraceActMsg()));
684 else addPktTraceData(VERDICT_REASON_BO, 0);
685 }
686
687 PREPROC_PROFILE_END(boPerfStats);
688
689 return;
690 }
691
692
693 /*
694 * Function: BoGetDirection(Packet *)
695 *
696 * Purpose: Attempt to guess the direction this packet is going in.
697 *
698 * Arguments: p => pointer to the current packet data struct
699 * pkt_data => pointer to data after magic cookie
700 *
701 * Returns: BO_FROM_UNKNOWN if direction unknown
702 * BO_FROM_CLIENT if direction from client to server
703 * BO_FROM_SERVER if direction from server to client
704 *
705 * Reference: http://www.magnux.org/~flaviovs/boproto.html
706 * BO header structure:
707 * Mnemonic Size in bytes
708 * -------------------------
709 * MAGIC 8
710 * LEN 4
711 * ID 4
712 * T 1
713 * DATA variable
714 * CRC 1
715 *
716 */
BoGetDirection(BoConfig * bo,Packet * p,char * pkt_data)717 static int BoGetDirection(BoConfig *bo, Packet *p, char *pkt_data)
718 {
719 uint32_t len = 0;
720 uint32_t id = 0;
721 uint32_t l, i;
722 char type;
723 static char buf1[BO_BUF_SIZE];
724 char plaintext;
725
726 /* Check for the default port on either side */
727 if ( p->dp == BACKORIFICE_DEFAULT_PORT )
728 {
729 return BO_FROM_CLIENT;
730 }
731 else if ( p->sp == BACKORIFICE_DEFAULT_PORT )
732 {
733 return BO_FROM_SERVER;
734 }
735
736 /* Didn't find default port, so look for ping packet */
737
738 /* Get length from BO header - 32 bit int */
739 for ( i = 0; i < 4; i++ )
740 {
741 plaintext = (char) (*pkt_data ^ BoRand());
742 l = (uint32_t) plaintext;
743 len += l << (8*i);
744 pkt_data++;
745 }
746
747 /* Get ID from BO header - 32 bit int */
748 for ( i = 0; i < 4; i++ )
749 {
750 plaintext = (char) (*pkt_data ^ BoRand() );
751 l = ((uint32_t) plaintext) & 0x000000FF;
752 id += l << (8*i);
753 pkt_data++;
754 }
755
756 DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, "Data length = %lu\n", len););
757 DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, "ID = %lu\n", id););
758
759 /* Do more len checking */
760
761 if ( len >= BO_BUF_ATTACK_SIZE )
762 {
763 if ( !(bo->noalert_flags & BO_ALERT_SNORT_ATTACK) )
764 {
765 SnortEventqAdd(GENERATOR_SPP_BO, BO_SNORT_BUFFER_ATTACK, 1, 0, 0,
766 BO_SNORT_BUFFER_ATTACK_STR, 0);
767 }
768 if ( (bo->drop_flags & BO_ALERT_SNORT_ATTACK) )
769 {
770 Active_DropSession(p);
771 }
772
773 return BO_FROM_UNKNOWN;
774 }
775
776 /* Adjust for BO packet header length */
777 if (len <= BACKORIFICE_MIN_SIZE)
778 {
779 /* Need some data, or we can't figure out client or server */
780 return BO_FROM_UNKNOWN;
781 }
782 else
783 {
784 len -= BACKORIFICE_MIN_SIZE;
785 }
786
787 if( len > 7 )
788 {
789 len = 7; /* we need no more than 7 variable chars */
790 }
791
792 /* Continue parsing BO header */
793 type = (char) (*pkt_data ^ BoRand());
794 pkt_data++;
795
796 /* check to make sure we don't run off end of packet */
797 if ((uint32_t)(p->dsize - ((uint8_t *)pkt_data - p->data)) < len)
798 {
799 /* We don't have enough data to inspect */
800 return BO_FROM_UNKNOWN;
801 }
802
803 if ( type & 0x80 )
804 {
805 DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, "Partial packet\n"););
806 }
807 if ( type & 0x40 )
808 {
809 DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, "Continued packet\n"););
810 }
811
812 /* Extract type of BO packet */
813 type = type & 0x3F;
814
815 DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, "Type = 0x%x\n", type););
816
817 /* Only examine data if this is a ping request or response */
818 if ( type == BO_TYPE_PING )
819 {
820 if ( len < 7 )
821 {
822 return BO_FROM_CLIENT;
823 }
824
825 for(i=0;i<len;i++ ) /* start at 0 to advance the BoRand() function properly */
826 {
827 buf1[i] = (char) (pkt_data[i] ^ BoRand());
828 if ( buf1[i] == 0 )
829 {
830 return BO_FROM_UNKNOWN;
831 }
832 }
833
834 if( ( buf1[3] == 'P' || buf1[3] == 'p' ) &&
835 ( buf1[4] == 'O' || buf1[4] == 'o' ) &&
836 ( buf1[5] == 'N' || buf1[5] == 'n' ) &&
837 ( buf1[6] == 'G' || buf1[6] == 'g' ) )
838 {
839 return BO_FROM_SERVER;
840 }
841 else
842 {
843 return BO_FROM_CLIENT;
844 }
845 }
846
847 return BO_FROM_UNKNOWN;
848 }
849
850
BoFreeConfigPolicy(tSfPolicyUserContextId bo,tSfPolicyId policyId,void * pData)851 static int BoFreeConfigPolicy(
852 tSfPolicyUserContextId bo,
853 tSfPolicyId policyId,
854 void* pData
855 )
856 {
857 BoConfig *pPolicyConfig = (BoConfig *)pData;
858
859 //do any housekeeping before freeing BoConfig
860
861 sfPolicyUserDataClear (bo, policyId);
862 free(pPolicyConfig);
863 return 0;
864 }
865
BoFreeConfig(tSfPolicyUserContextId bo)866 static void BoFreeConfig(tSfPolicyUserContextId bo)
867 {
868 if (bo == NULL)
869 return;
870
871 sfPolicyUserDataFreeIterate (bo, BoFreeConfigPolicy);
872
873 sfPolicyConfigDelete(bo);
874 }
875
BoCleanExit(int signal,void * unused)876 static void BoCleanExit(int signal, void *unused)
877 {
878 BoFreeConfig(bo_config);
879 bo_config = NULL;
880 }
881
882 #ifdef SNORT_RELOAD
BoReload(struct _SnortConfig * sc,char * args,void ** new_config)883 static void BoReload(struct _SnortConfig *sc, char *args, void **new_config)
884 {
885 tSfPolicyUserContextId bo_swap_config = (tSfPolicyUserContextId)*new_config;
886 int policy_id = (int)getParserPolicy(sc);
887 BoConfig *pPolicyConfig = NULL;
888
889 if (!bo_swap_config)
890 {
891 bo_swap_config = sfPolicyConfigCreate();
892 *new_config = (void *)bo_swap_config;
893 }
894
895 sfPolicyUserPolicySet (bo_swap_config, policy_id);
896
897 pPolicyConfig = (BoConfig *)sfPolicyUserDataGetCurrent(bo_swap_config);
898 if (pPolicyConfig)
899 {
900 ParseError("BO preprocessor can only be configured once.\n");
901 }
902
903 pPolicyConfig = (BoConfig *)SnortAlloc(sizeof(BoConfig));
904 if (!pPolicyConfig)
905 {
906 ParseError("BO preprocessor: memory allocate failed.\n");
907 }
908
909 sfPolicyUserDataSetCurrent(bo_swap_config, pPolicyConfig);
910
911 ProcessArgs(pPolicyConfig, args);
912
913 AddFuncToPreprocList(sc, BoFind, PRIORITY_LAST, PP_BO, PROTO_BIT__UDP);
914 session_api->enable_preproc_all_ports( sc, PP_BO, PROTO_BIT__UDP );
915 }
916
BoReloadSwap(struct _SnortConfig * sc,void * swap_config)917 static void * BoReloadSwap(struct _SnortConfig *sc, void *swap_config)
918 {
919 tSfPolicyUserContextId bo_swap_config = (tSfPolicyUserContextId)swap_config;
920 tSfPolicyUserContextId old_config = bo_config;
921
922 if (bo_swap_config == NULL)
923 return NULL;
924
925 bo_config = bo_swap_config;
926 bo_swap_config = NULL;
927
928 return (void *)old_config;
929 }
930
BoReloadSwapFree(void * data)931 static void BoReloadSwapFree(void *data)
932 {
933 if (data == NULL)
934 return;
935
936 BoFreeConfig((tSfPolicyUserContextId )data);
937 }
938 #endif
939