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