Main Page | Modules | Class List | Directories | File List | Class Members | File Members | Related Pages

spp_bo.c

Go to the documentation of this file.
00001 /*
00002 ** Copyright (C) 1998-2005 Martin Roesch <roesch@sourcefire.com>
00003 **
00004 ** This program is free software; you can redistribute it and/or modify
00005 ** it under the terms of the GNU General Public License as published by
00006 ** the Free Software Foundation; either version 2 of the License, or
00007 ** (at your option) any later version.
00008 **
00009 ** This program is distributed in the hope that it will be useful,
00010 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 ** GNU General Public License for more details.
00013 **
00014 ** You should have received a copy of the GNU General Public License
00015 ** along with this program; if not, write to the Free Software
00016 ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00017 */
00018 
00019 /* $Id$ */
00020 /* Snort Preprocessor Plugin Source File Bo */
00021 
00022 /* spp_bo 
00023  * 
00024  * Purpose: Detects Back Orifice traffic by brute forcing the weak encryption
00025  *          of the program's network protocol and detects the magic cookie
00026  *          that it's servers and clients require to communicate with each 
00027  *          other.
00028  *
00029  * Arguments: none
00030  *   
00031  * Effect: Analyzes UDP traffic for the BO magic cookie, reports if it finds
00032  *         traffic matching the profile.
00033  *
00034  * Comments:
00035  *
00036  */
00037 
00038 /*
00039  * The following text describes a couple of ways in which the Back Orifice
00040  * signature is calculated.  The snort runtime generated an array of 65K
00041  * possible signatures, of which two are described here.  Refer back to
00042  * this simplified algorithm when evaluating the snort code below.
00043  *
00044  * Back Orifice magic cookie is "*!*QWTY?", which is located in the first
00045  * eight bytes of the packet.  But it is encrypted using an XOR.  Here we'll
00046  * generate a sequence of eight bytes which will decrypt (XOR) into the
00047  * magic cookie.  This test uses the NON-DEFAULT KEY to initialize (seed) the
00048  * "random" number generator.  The default seed results in the following
00049  * sequence of bytes:  E4 42 FB 83 41 B3 4A F0.  When XOR'd against the
00050  * magic cookie, we have our packet data which looks like a Back Orifice
00051  * signature:
00052  *
00053  *   Cookie:  2A 21 2A 51 57 54 59 3F
00054  *   Random:  E4 42 FB 83 41 B3 4A F0
00055  *   -------  -- -- -- -- -- -- -- --
00056  *   Result:  CE 63 D1 D2 16 E7 13 CF  (XOR'd result)
00057  * 
00058  * For demonstration purposes:
00059  *
00060  *   static long holdrand = 1L;
00061  *   static int LocalBoRand()
00062  *   {
00063  *       return(((holdrand = holdrand * 214013L + 2531011L) >> 16) & 0x7fff);
00064  *   }
00065  *   ...
00066  *
00067  *   int BoRandValues_NonDefaultKey[8];
00068  *   holdrand = BACKORIFICE_DEFAULT_KEY;    (seed value)
00069  *   BoRandValues_NonDefaultKey[0] = LocalBoRand() % 256;  --> 228 (0xe4)
00070  *   BoRandValues_NonDefaultKey[1] = LocalBoRand() % 256;  -->  66 (0x42)
00071  *   BoRandValues_NonDefaultKey[2] = LocalBoRand() % 256;  --> 251 (0xfb)
00072  *   BoRandValues_NonDefaultKey[3] = LocalBoRand() % 256;  --> 131 (0x83)
00073  *   BoRandValues_NonDefaultKey[4] = LocalBoRand() % 256;  -->  65 (0x41)
00074  *   BoRandValues_NonDefaultKey[5] = LocalBoRand() % 256;  --> 179 (0xb3)
00075  *   BoRandValues_NonDefaultKey[6] = LocalBoRand() % 256;  -->  74 (0x4a)
00076  *   BoRandValues_NonDefaultKey[7] = LocalBoRand() % 256;  --> 240 (0xf0)
00077  *
00078  *
00079  * The following test uses the DEFAULT KEY to initialize (seed) the
00080  * "random" number generator.  The default seed results in the following
00081  * sequence of bytes:  26 27 F6 85 97 15 AD 1D.  When XOR'd against the
00082  * magic cookie, we have our packet data which looks like a Back Orifice
00083  * signature:
00084  *
00085  *   Cookie:  2A 21 2A 51 57 54 59 3F
00086  *   Random:  26 27 F6 85 97 15 AD 1D
00087  *   -------  -- -- -- -- -- -- -- --
00088  *   Result:  0C 06 DC D4 C0 41 F4 22  (XOR'd result)
00089  * 
00090  * For demonstration purposes:
00091  *
00092  *   int BoRandValues_DefaultKey[8];
00093  *   holdrand = 0;    (seed value)
00094  *   BoRandValues_DefaultKey[0] = LocalBoRand() % 256;  -->  38 (0x26)
00095  *   BoRandValues_DefaultKey[1] = LocalBoRand() % 256;  -->  39 (0x27)
00096  *   BoRandValues_DefaultKey[2] = LocalBoRand() % 256;  --> 246 (0xf6)
00097  *   BoRandValues_DefaultKey[3] = LocalBoRand() % 256;  --> 133 (0x85)
00098  *   BoRandValues_DefaultKey[4] = LocalBoRand() % 256;  --> 151 (0x97)
00099  *   BoRandValues_DefaultKey[5] = LocalBoRand() % 256;  -->  21 (0x15)
00100  *   BoRandValues_DefaultKey[6] = LocalBoRand() % 256;  --> 173 (0xad)
00101  *   BoRandValues_DefaultKey[7] = LocalBoRand() % 256;  -->  29 (0x1d)
00102  * 
00103  * Notes:
00104  * 
00105  *   10/13/2005 marc norton - This has a lot of changes  to the runtime 
00106  *   decoding and testing.  The '% 256' op was removed, 
00107  *   the xor op is bit wise so modulo is not needed, 
00108  *   the char casting truncates to one byte,
00109  *   and len testing has been modified as was the xor decode copy and 
00110  *   final PONG test.
00111  */
00112 
00113 #include <sys/types.h>
00114 #include <stdlib.h>
00115 #include <ctype.h>
00116 
00117 #include "generators.h"
00118 #include "log.h"
00119 #include "detect.h"
00120 #include "decode.h"
00121 #include "event.h"
00122 #include "plugbase.h"
00123 #include "parser.h"
00124 #include "debug.h"
00125 #include "mstring.h"
00126 #include "util.h"
00127 #include "event_queue.h"
00128 /* In case we need to drop this packet */
00129 #include "inline.h"
00130 
00131 #include "snort.h"
00132 
00133 #define BACKORIFICE_DEFAULT_KEY   31337
00134 #define BACKORIFICE_MAGIC_SIZE    8
00135 #define BACKORIFICE_MIN_SIZE      18
00136 #define BACKORIFICE_DEFAULT_PORT  31337
00137 #define BO_TYPE_PING              1
00138 #define BO_FROM_UNKNOWN           0
00139 #define BO_FROM_CLIENT            1
00140 #define BO_FROM_SERVER            2
00141 
00142 #define BO_BUF_SIZE         8
00143 #define BO_BUF_ATTACK_SIZE  1024
00144 
00145 /* Configuration defines */
00146 #define START_LIST      "{"
00147 #define END_LIST        "}"
00148 #define CONF_SEPARATORS         " \t\n\r"
00149 #define BO_ALERT_GENERAL        0x0001
00150 #define BO_ALERT_CLIENT         0x0002
00151 #define BO_ALERT_SERVER         0x0004
00152 #define BO_ALERT_SNORT_ATTACK   0x0008
00153 
00154 
00155 /* list of function prototypes for this preprocessor */
00156 void BoInit(u_char *);
00157 void BoProcess(Packet *);
00158 void BoFind(Packet *, void *);
00159 
00160 /* list of private functions */
00161 static int  BoGetDirection(Packet *p, char *pkt_data);
00162 static void PrecalcPrefix();
00163 static char BoRand();
00164 static void ProcessArgs(u_char *args);
00165 static int  ProcessOptionList(void);
00166 static void PrintConfig(void);
00167 
00168 #define MODNAME "spp_bo"
00169 
00170 
00171 /* global keyvalue for the BoRand() function */
00172 static long holdrand = 1L;
00173 
00174 /* brute forcing is on by default */
00175 int brute_force_enable = 1;
00176 int default_key;
00177 
00178 static u_int16_t noalert_flags = 0;
00179 static u_int16_t drop_flags = 0;
00180 
00181 
00182 u_int16_t lookup1[65536][3];
00183 u_int16_t lookup2[65536];
00184 
00185 /*
00186  * Function: SetupBo()
00187  *
00188  * Purpose: Registers the preprocessor keyword and initialization 
00189  *          function into the preprocessor list.  
00190  *
00191  * Arguments: None.
00192  *
00193  * Returns: void function
00194  *
00195  */
00196 void SetupBo()
00197 {
00198     /* link the preprocessor keyword to the init function in 
00199        the preproc list */
00200     RegisterPreprocessor("bo", BoInit);
00201     DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, 
00202                 "Preprocessor: Back Orifice is setup...\n"););
00203 }
00204 
00205 
00206 /*
00207  * Function: BoInit(u_char *)
00208  *
00209  * Purpose: Link the BO preprocessor to the preperocessor call chain.
00210  *
00211  * Arguments: args => ptr to argument string (spp_bo takes no args)
00212  *
00213  * Returns: void function
00214  *
00215  */
00216 void BoInit(u_char *args)
00217 {
00218     static int bIsInitialized = 0;
00219 
00220     /* BoInit is re-entrant */
00221     if ( !bIsInitialized )
00222     {
00223         DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN,"Preprocessor: Bo Initialized\n"););
00224 
00225         /* we no longer need to take args */
00226         PrecalcPrefix();
00227 
00228         /* Set the preprocessor function into the function list */
00229         AddFuncToPreprocList(BoFind);
00230 
00231         bIsInitialized = 1;
00232     }
00233 
00234     /* Process argument list */
00235     ProcessArgs(args);
00236 }
00237 
00238 
00239 /*
00240  * Function: ProcessArgs(u_char *)
00241  *
00242  * Purpose: Parse additional config items.
00243  *
00244  * Arguments: args => ptr to argument string
00245  *   syntax:
00246  *     preprocessor bo: noalert { client | server | general | snort_attack } \
00247  *                      drop    { client | server | general | snort_attack }
00248  *
00249  *   example:
00250  *     preprocessor bo: noalert { general server } drop { snort_attack }
00251  *
00252  * Returns: void function
00253  *
00254  */
00255 static void ProcessArgs(u_char *args)
00256 {
00257     char *arg;
00258    
00259     if ( args == NULL )
00260         return;
00261 
00262     arg = strtok(args, CONF_SEPARATORS);
00263     
00264     while ( arg != NULL )
00265     {
00266         if ( !strcasecmp("noalert", arg) )
00267         {
00268             noalert_flags = ProcessOptionList();
00269         }
00270         else if ( !strcasecmp("drop", arg) )
00271         {
00272             drop_flags = ProcessOptionList();
00273         }
00274         else
00275         {
00276             FatalError("%s(%d) => Unknown bo option %s.\n", 
00277                         file_name, file_line, arg);
00278         }
00279 
00280         arg = strtok(NULL, CONF_SEPARATORS);
00281     }
00282 
00283     PrintConfig();
00284 
00285     return;
00286 }
00287 
00288 
00289 /*
00290  * Function: ProcessOptionList(u_char *)
00291  *
00292  * Purpose: Parse config list, either "noalert" or "drop".
00293  *
00294  * Arguments: none, use string from strtok in ProcessArgs
00295  *
00296  * Returns: AND'ed list of flags based on option list
00297  *
00298  */
00299 static int ProcessOptionList(void)
00300 {
00301     char *arg;
00302     int   retFlags = 0;
00303     int   endList = 0;
00304 
00305     arg = strtok(NULL, CONF_SEPARATORS);
00306 
00307     if ( arg == NULL || strcmp(START_LIST, arg) )
00308     {
00309         FatalError("%s(%d) => Invalid bo option.\n", 
00310                         file_name, file_line);        
00311         return 0;
00312     }
00313     
00314     while ( (arg = strtok(NULL, CONF_SEPARATORS)) )
00315     {
00316         if ( !strcmp(END_LIST, arg) )
00317         {
00318             endList = 1;
00319             break;
00320         }
00321 
00322         if ( !strcasecmp("general", arg) )
00323         {
00324             retFlags |= BO_ALERT_GENERAL;
00325         }
00326         else if ( !strcasecmp("client", arg) )
00327         {
00328             retFlags |= BO_ALERT_CLIENT;
00329         }
00330         else if ( !strcasecmp("server", arg) )
00331         {
00332             retFlags |= BO_ALERT_SERVER;
00333         }
00334         else if ( !strcasecmp("snort_attack", arg) )
00335         {
00336             retFlags |= BO_ALERT_SNORT_ATTACK;
00337         }
00338         else
00339         {
00340             FatalError("%s(%d) => Invalid bo option argument %s.\n", 
00341                         file_name, file_line, arg);        
00342         }
00343     }
00344 
00345     if ( !endList )
00346     {
00347         FatalError("%s(%d) => Must end configuration list with %s.\n", 
00348                         file_name, file_line, END_LIST);      
00349         return 0;
00350     }
00351 
00352     return retFlags;
00353 }
00354 
00355 /*
00356  * Function: PrintConfig(u_char *)
00357  *
00358  * Purpose: Print configuration
00359  *
00360  * Arguments: none
00361  *
00362  * Returns: none
00363  *
00364  */
00365 static void PrintConfig(void)
00366 {
00367     if ( noalert_flags != 0 || drop_flags != 0 )
00368         LogMessage("Back Orifice Config:\n");
00369     
00370     if ( noalert_flags != 0 )
00371     {
00372         LogMessage("    Disable alerts:");
00373         if ( noalert_flags & BO_ALERT_CLIENT )
00374             LogMessage(" client");
00375         if ( noalert_flags & BO_ALERT_SERVER )
00376             LogMessage(" server");
00377         if ( noalert_flags & BO_ALERT_GENERAL )
00378             LogMessage(" general");
00379         if ( noalert_flags & BO_ALERT_SNORT_ATTACK )
00380             LogMessage(" snort_attack");
00381         LogMessage("\n");
00382     }
00383     if ( drop_flags != 0 )
00384     {
00385         LogMessage("    Drop packets (inline only) on alerts:");
00386         if ( drop_flags & BO_ALERT_CLIENT )
00387             LogMessage(" client");
00388         if ( drop_flags & BO_ALERT_SERVER )
00389             LogMessage(" server");
00390         if ( drop_flags & BO_ALERT_GENERAL )
00391             LogMessage(" general");
00392         if ( drop_flags & BO_ALERT_SNORT_ATTACK )
00393             LogMessage(" snort_attack");
00394         LogMessage("\n");
00395     }
00396 }
00397 
00398 /*
00399  * Function: BoRand()
00400  *
00401  * Purpose: Back Orifice "encryption" algorithm
00402  *
00403  * Arguments: None.
00404  *
00405  * Returns: key to XOR with current char to be "encrypted"
00406  */
00407 static char BoRand()
00408 {
00409     holdrand = holdrand * 214013L + 2531011L;
00410     return (char) (((holdrand  >> 16) & 0x7fff) & 0xFF);
00411 }
00412 
00413 
00414 /*
00415  * Precalculate the known cyphertext into a prefix and suffix lookup table 
00416  * to recover the key.  Using this in the BoFind() function below is much
00417  * faster than the old brute force method
00418  */
00419 static void PrecalcPrefix()
00420 {
00421     u_int8_t cookie_cyphertext[BACKORIFICE_MAGIC_SIZE];
00422     char *cookie_plaintext = "*!*QWTY?";
00423     int key;
00424     int cookie_index;
00425     char *cp_ptr;       /* cookie plaintext indexing pointer */
00426     u_int16_t cyphertext_referent;
00427     
00428     for(key=0;key<65536;key++)
00429     {
00430         /* setup to generate cyphertext for this key */
00431         holdrand = key;
00432         cp_ptr = cookie_plaintext;
00433 
00434         /* convert the plaintext cookie to cyphertext for this key */
00435         for(cookie_index=0;cookie_index<BACKORIFICE_MAGIC_SIZE;cookie_index++)
00436         {
00437             cookie_cyphertext[cookie_index] =(u_int8_t)(*cp_ptr^(BoRand()));
00438             cp_ptr++;
00439         }
00440 
00441         /* 
00442          * generate the key lookup mechanism from the first 2 characters of
00443          * the cyphertext
00444          */
00445         cyphertext_referent = (u_int16_t) (cookie_cyphertext[0] << 8) & 0xFF00;
00446         cyphertext_referent |= (u_int16_t) (cookie_cyphertext[1]) & 0x00FF;
00447 
00448         /* if there are any keyspace collisions that's going to suck */
00449         if(lookup1[cyphertext_referent][0] != 0)
00450         {
00451             if(lookup1[cyphertext_referent][1] != 0)
00452             {
00453                 lookup1[cyphertext_referent][2] = key;
00454             }
00455             else
00456             {
00457                 lookup1[cyphertext_referent][1] = key;
00458             }
00459         }
00460         else
00461         {
00462             lookup1[cyphertext_referent][0] = key;
00463         }
00464 
00465         /* 
00466          * generate the second lookup from the last two characters of 
00467          * the cyphertext
00468          */
00469         cyphertext_referent = (u_int16_t) (cookie_cyphertext[6] << 8) & 0xFF00;
00470         cyphertext_referent |= (u_int16_t) (cookie_cyphertext[7]) & 0x00FF;
00471 
00472         /*
00473          * set the second lookup with the current key
00474          */
00475         lookup2[key] = cyphertext_referent;
00476     }
00477 }
00478 
00479 
00480 /*
00481  * Function: BoFind(Packet *)
00482  *
00483  * Purpose: Look for the magic cookie, squawk if you find it.
00484  *
00485  * Arguments: p => pointer to the current packet data struct 
00486  *
00487  * Returns: void function
00488  *
00489  *
00490  */
00491 void BoFind(Packet *p, void *context)
00492 {
00493     u_int16_t cyphertext_referent;
00494     u_int16_t cyphertext_suffix;
00495     u_int16_t key;
00496     char *magic_cookie = "*!*QWTY?";
00497     char *pkt_data;
00498     char *magic_data;
00499     char *end;
00500     char plaintext;
00501     int i;
00502     int bo_direction = 0;
00503 
00504 
00505     if(!(p->preprocessors & PP_BO))
00506     {
00507         return;
00508     }
00509     
00510     /* make sure it's UDP and that it's at least 19 bytes long */
00511     if(!PacketIsUDP(p))
00512     {
00513         DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, 
00514                     "   -> spp_bo: Not UDP\n"););
00515         return;
00516     }
00517 
00518     if(p->dsize < BACKORIFICE_MIN_SIZE)
00519     {
00520         return;
00521     }
00522 
00523     /*
00524      * take the first two characters of the packet and generate the 
00525      * first reference that gives us a reference key
00526      */
00527     cyphertext_referent = (u_int16_t) (p->data[0] << 8) & 0xFF00;
00528     cyphertext_referent |= (u_int16_t) (p->data[1]) & 0x00FF;
00529 
00530     /* 
00531      * generate the second referent from the last two characters
00532      * of the cyphertext
00533      */
00534     cyphertext_suffix = (u_int16_t) (p->data[6] << 8) & 0xFF00;
00535     cyphertext_suffix |= (u_int16_t) (p->data[7]) & 0x00FF;
00536 
00537     for(i=0;i<3;i++)
00538     {
00539         /* get the key from the cyphertext */
00540         key = lookup1[cyphertext_referent][i];
00541 
00542         /* 
00543          * if the lookup from the proposed key matches the cyphertext reference
00544          * then we've probably go the right key and can proceed to full 
00545          * decryption using the key
00546          *
00547          * moral of the story: don't use a lame keyspace 
00548          */
00549         if(lookup2[key] == cyphertext_suffix)
00550         {
00551             holdrand = key;
00552             pkt_data = (char*)p->data;
00553             end = (char*)p->data + BACKORIFICE_MAGIC_SIZE;
00554             magic_data = magic_cookie;
00555 
00556             while(pkt_data<end)
00557             {
00558                 plaintext = (char) (*pkt_data ^ BoRand());
00559 
00560                 if(*magic_data != plaintext)
00561                 {
00562                     DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, 
00563                             "Failed check one on 0x%X : 0x%X\n", 
00564                             *magic_data, plaintext););
00565                     return;
00566                 }
00567 
00568                 magic_data++;
00569                 pkt_data++;
00570             }
00571             
00572             /* if we fall thru there's a detect */
00573             DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, 
00574                         "Detected Back Orifice Data!\n");
00575             DebugMessage(DEBUG_PLUGIN, "hash value: %d\n", key););
00576             
00577             bo_direction = BoGetDirection(p, pkt_data);
00578 
00579             if ( bo_direction == BO_FROM_CLIENT )
00580             {
00581                 if ( !(noalert_flags & BO_ALERT_CLIENT) )
00582                 {
00583                     SnortEventqAdd(GENERATOR_SPP_BO, BO_CLIENT_TRAFFIC_DETECT, 1, 0, 0,
00584                                             BO_CLIENT_TRAFFIC_DETECT_STR, 0);
00585                 }
00586                 if ( (drop_flags & BO_ALERT_CLIENT) && InlineMode() )
00587                 {
00588                     p->packet_flags |= PKT_INLINE_DROP; 
00589                     InlineDrop();
00590                 }
00591                 DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, "Client packet\n"););
00592             }
00593             else if ( bo_direction == BO_FROM_SERVER )
00594             {
00595                 if ( !(noalert_flags & BO_ALERT_SERVER) )
00596                 {
00597                     SnortEventqAdd(GENERATOR_SPP_BO, BO_SERVER_TRAFFIC_DETECT, 1, 0, 0,
00598                                             BO_SERVER_TRAFFIC_DETECT_STR, 0);
00599                 }
00600                 if ( (drop_flags & BO_ALERT_SERVER) && InlineMode() )
00601                 {
00602                     p->packet_flags |= PKT_INLINE_DROP; 
00603                     InlineDrop();
00604                 }
00605                 DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, "Server packet\n"););
00606             }
00607             else
00608             {
00609                 if ( !(noalert_flags & BO_ALERT_GENERAL) )
00610                 {
00611                     SnortEventqAdd(GENERATOR_SPP_BO, BO_TRAFFIC_DETECT, 1, 0, 0,
00612                                             BO_TRAFFIC_DETECT_STR, 0);
00613                 }
00614                 if ( (drop_flags & BO_ALERT_GENERAL) && InlineMode() )
00615                 {
00616                     p->packet_flags |= PKT_INLINE_DROP; 
00617                     InlineDrop();
00618                 }
00619             }           
00620         }
00621     }
00622 
00623     return;
00624 }
00625 
00626 
00627 /*
00628  * Function: BoGetDirection(Packet *)
00629  *
00630  * Purpose: Attempt to guess the direction this packet is going in.
00631  *
00632  * Arguments: p        => pointer to the current packet data struct
00633  *            pkt_data => pointer to data after magic cookie
00634  *
00635  * Returns: BO_FROM_UNKNOWN  if direction unknown
00636  *          BO_FROM_CLIENT   if direction from client to server
00637  *          BO_FROM_SERVER   if direction from server to client
00638  *
00639  * Reference: http://www.magnux.org/~flaviovs/boproto.html
00640  *    BO header structure:
00641  *      Mnemonic    Size in bytes
00642  *      -------------------------
00643  *      MAGIC       8
00644  *      LEN         4
00645  *      ID          4
00646  *      T           1
00647  *      DATA        variable
00648  *      CRC         1
00649  *
00650  */
00651 static int BoGetDirection(Packet *p, char *pkt_data)
00652 {
00653     u_int32_t len = 0;
00654     u_int32_t id = 0;
00655     u_int32_t l, i;
00656     char type;
00657     static char buf1[BO_BUF_SIZE];
00658     char plaintext;
00659     
00660     /* Check for the default port on either side */
00661     if ( p->dp == BACKORIFICE_DEFAULT_PORT )
00662     {
00663         return BO_FROM_CLIENT;
00664     }
00665     else if ( p->sp == BACKORIFICE_DEFAULT_PORT )
00666     {
00667         return BO_FROM_SERVER;
00668     }
00669     
00670     /* Didn't find default port, so look for ping packet */  
00671     
00672     /* Get length from BO header - 32 bit int */
00673     for ( i = 0; i < 4; i++ )
00674     {
00675         plaintext = (char) (*pkt_data ^ BoRand());
00676         l = (u_int32_t) plaintext;
00677         len += l << (8*i);
00678         pkt_data++;
00679     }
00680 
00681     /* Get ID from BO header - 32 bit int */
00682     for ( i = 0; i < 4; i++ )
00683     {
00684         plaintext = (char) (*pkt_data ^ BoRand() );
00685         l = ((u_int32_t) plaintext) & 0x000000FF;
00686         id += l << (8*i);
00687         pkt_data++;
00688     }
00689     
00690     DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, "Data length = %lu\n", len););
00691     DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, "ID = %lu\n", id););
00692 
00693     /* Do more len checking */
00694     
00695     if ( len >= BO_BUF_ATTACK_SIZE )
00696     {
00697         if ( !(noalert_flags & BO_ALERT_SNORT_ATTACK) )
00698         {
00699             SnortEventqAdd(GENERATOR_SPP_BO, BO_SNORT_BUFFER_ATTACK, 1, 0, 0,
00700                                             BO_SNORT_BUFFER_ATTACK_STR, 0);
00701         }
00702         if ( (drop_flags & BO_ALERT_SNORT_ATTACK) && InlineMode() )
00703         {
00704             p->packet_flags |= PKT_INLINE_DROP; 
00705             InlineDrop();
00706         }
00707 
00708         return BO_FROM_UNKNOWN;
00709     }
00710 
00711     /* Adjust for BO packet header length */
00712     len -= BACKORIFICE_MIN_SIZE;
00713 
00714     if( len == 0 )
00715     {
00716         /* Need some data, or we can't figure out client or server */
00717         return BO_FROM_UNKNOWN; 
00718     }
00719     
00720     if( len > 7 )
00721     {
00722         len = 7; /* we need no more than  7 variable chars */
00723     }
00724 
00725     /* length must be 7 OR LESS due to above logic  */
00726   
00727     if( p->dsize < len )
00728     {
00729         /* We don't have enough data to inspect */
00730         return BO_FROM_UNKNOWN;
00731     }
00732     
00733     /* Continue parsing BO header */
00734     type = (char) (*pkt_data ^ BoRand());
00735     pkt_data++;
00736         
00737     if ( type & 0x80 )
00738     {
00739         DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, "Partial packet\n"););
00740     }
00741     if ( type & 0x40 )
00742     {
00743         DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, "Continued packet\n"););
00744     }
00745 
00746     /* Extract type of BO packet */
00747     type = type & 0x3F;
00748 
00749     DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, "Type = 0x%x\n", type););
00750 
00751     /* Only examine data if this is a ping request or response */
00752     if ( type == BO_TYPE_PING )
00753     {
00754         if ( len < 7 )
00755         {
00756             return BO_FROM_CLIENT;
00757         }
00758 
00759         for(i=0;i<len;i++ ) /* start at 0 to advance the BoRand() function properly */
00760         {
00761             buf1[i] = (char) (pkt_data[i] ^ BoRand());
00762             if ( buf1[i] == 0 )
00763             {
00764                 return BO_FROM_UNKNOWN; 
00765             }
00766         }
00767 
00768         if( ( buf1[3] == 'P' || buf1[3] == 'p' ) &&
00769             ( buf1[4] == 'O' || buf1[4] == 'o' ) && 
00770             ( buf1[5] == 'N' || buf1[5] == 'n' ) && 
00771             ( buf1[6] == 'G' || buf1[6] == 'g' ) )
00772         {
00773             return BO_FROM_SERVER;
00774         }
00775         else
00776         {
00777             return BO_FROM_CLIENT;
00778         }
00779     } 
00780    
00781     return BO_FROM_UNKNOWN;
00782 }

Generated on Sun May 14 14:51:16 2006 by  doxygen 1.4.2