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

sp_byte_jump.c

Go to the documentation of this file.
00001 /* $Id$ */
00002 /* Copyright (C) 2002 Sourcefire Inc. */
00003 /* Author: Martin Roesch*/
00004 
00005 /* sp_byte_jump 
00006  * 
00007  * Purpose:
00008  *      Grab some number of bytes, convert them to their numeric 
00009  *      representation, jump the doe_ptr up that many bytes (for
00010  *      further pattern matching/byte_testing).
00011  *
00012  *
00013  * Arguments:
00014  *      Required:
00015  *      <bytes_to_grab>: number of bytes to pick up from the packet
00016  *      <offset>: number of bytes into the payload to grab the bytes
00017  *      Optional:
00018  *      ["relative"]: offset relative to last pattern match
00019  *      ["big"]: process data as big endian (default)
00020  *      ["little"]: process data as little endian
00021  *      ["string"]: converted bytes represented as a string needing conversion
00022  *      ["hex"]: converted string data is represented in hexidecimal
00023  *      ["dec"]: converted string data is represented in decimal
00024  *      ["oct"]: converted string data is represented in octal
00025  *      ["align"]: round the number of converted bytes up to the next 
00026  *                 32-bit boundry
00027  *   
00028  *   sample rules:
00029  *   alert udp any any -> any 32770:34000 (content: "|00 01 86 B8|"; \
00030  *       content: "|00 00 00 01|"; distance: 4; within: 4; \
00031  *       byte_jump: 4, 12, relative, align; \
00032  *       byte_test: 4, >, 900, 20, relative; \
00033  *       msg: "statd format string buffer overflow";)
00034  *
00035  * Effect:
00036  *
00037  *      Reads in the indicated bytes, converts them to an numeric 
00038  *      representation and then jumps the doe_ptr up
00039  *      that number of bytes.  Returns 1 if the jump is in range (within the
00040  *      packet) and 0 if it's not.
00041  *
00042  * Comments:
00043  *
00044  * Any comments?
00045  *
00046  */
00047 
00048 #ifdef HAVE_CONFIG_H
00049 #include "config.h"
00050 #endif
00051 
00052 #include <sys/types.h>
00053 #include <stdlib.h>
00054 #include <ctype.h>
00055 #ifdef HAVE_STRINGS_H
00056 #include <strings.h>
00057 #endif
00058 #include <errno.h>
00059 
00060 #include "bounds.h"
00061 #include "rules.h"
00062 #include "decode.h"
00063 #include "plugbase.h"
00064 #include "parser.h"
00065 #include "debug.h"
00066 #include "util.h"
00067 #include "plugin_enum.h"
00068 #include "mstring.h"
00069 #include "byte_extract.h"
00070 
00071 extern u_int8_t *doe_ptr;
00072 extern u_int8_t DecodeBuffer[DECODE_BLEN];
00073 
00074 typedef struct _ByteJumpData
00075 {
00076     u_int32_t bytes_to_grab; /* number of bytes to compare */
00077     int32_t offset;
00078     u_int8_t relative_flag;
00079     u_int8_t data_string_convert_flag;
00080     u_int8_t from_beginning_flag;
00081     u_int8_t align_flag;
00082     u_int8_t endianess;
00083     u_int32_t base;
00084     u_int32_t multiplier;
00085 
00086 } ByteJumpData;
00087 
00088 void ByteJumpInit(char *, OptTreeNode *, int);
00089 void ByteJumpParse(char *, ByteJumpData *, OptTreeNode *);
00090 int ByteJump(Packet *, struct _OptTreeNode *, OptFpList *);
00091 
00092 /****************************************************************************
00093  * 
00094  * Function: SetupByteJump()
00095  *
00096  * Purpose: Load 'er up
00097  *
00098  * Arguments: None.
00099  *
00100  * Returns: void function
00101  *
00102  ****************************************************************************/
00103 void SetupByteJump(void)
00104 {
00105     /* map the keyword to an initialization/processing function */
00106     RegisterPlugin("byte_jump", ByteJumpInit);
00107 
00108     DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN,"Plugin: ByteJump Setup\n"););
00109 }
00110 
00111 
00112 /****************************************************************************
00113  * 
00114  * Function: ByteJumpInit(char *, OptTreeNode *)
00115  *
00116  * Purpose: Generic rule configuration function.  Handles parsing the rule 
00117  *          information and attaching the associated detection function to
00118  *          the OTN.
00119  *
00120  * Arguments: data => rule arguments/data
00121  *            otn => pointer to the current rule option list node
00122  *            protocol => protocol the rule is on (we don't care in this case)
00123  *
00124  * Returns: void function
00125  *
00126  ****************************************************************************/
00127 void ByteJumpInit(char *data, OptTreeNode *otn, int protocol)
00128 {
00129     ByteJumpData *idx;
00130     OptFpList *fpl;
00131 
00132     /* allocate the data structure and attach it to the
00133        rule's data struct list */
00134     idx = (ByteJumpData *) calloc(sizeof(ByteJumpData), sizeof(char));
00135 
00136     if(idx == NULL)
00137     {
00138         FatalError("%s(%d): Unable to allocate byte_jump data node\n", 
00139                    file_name, file_line);
00140     }
00141 
00142     /* this is where the keyword arguments are processed and placed into the 
00143        rule option's data structure */
00144     ByteJumpParse(data, idx, otn);
00145 
00146     fpl = AddOptFuncToList(ByteJump, otn);
00147 
00148     /* attach it to the context node so that we can call each instance
00149      * individually
00150      */
00151     fpl->context = (void *) idx;
00152 }
00153 
00154 
00155 
00156 /****************************************************************************
00157  * 
00158  * Function: ByteJumpParse(char *, ByteJumpData *, OptTreeNode *)
00159  *
00160  * Purpose: This is the function that is used to process the option keyword's
00161  *          arguments and attach them to the rule's data structures.
00162  *
00163  * Arguments: data => argument data
00164  *            idx => pointer to the processed argument storage
00165  *            otn => pointer to the current rule's OTN
00166  *
00167  * Returns: void function
00168  *
00169  ****************************************************************************/
00170 void ByteJumpParse(char *data, ByteJumpData *idx, OptTreeNode *otn)
00171 {
00172     char **toks;
00173     char *endp;
00174     int num_toks;
00175     char *cptr;
00176     int i =0;
00177 
00178     idx->multiplier = 1;
00179 
00180     toks = mSplit(data, ",", 12, &num_toks, 0);
00181 
00182     if(num_toks < 2)
00183         FatalError("ERROR %s (%d): Bad arguments to byte_jump: %s\n", file_name,
00184                 file_line, data);
00185 
00186     /* set how many bytes to process from the packet */
00187     idx->bytes_to_grab = strtoul(toks[0], &endp, 10);
00188 
00189     if(endp==toks[0])
00190     {
00191         FatalError("%s(%d): Unable to parse as byte value %s\n",
00192                    file_name, file_line, toks[0]);
00193     }
00194 
00195     if(idx->bytes_to_grab > PARSELEN || idx->bytes_to_grab == 0)
00196     {
00197         FatalError("%s(%d): byte_jump can't process more than "
00198                 "%d bytes!\n", file_name, file_line, PARSELEN);
00199     }
00200 
00201     /* set offset */
00202     idx->offset = strtol(toks[1], &endp, 10);
00203 
00204     if(endp==toks[1])
00205     {
00206         FatalError("%s(%d): Unable to parse as offset %s\n",
00207                    file_name, file_line, toks[1]);
00208     }
00209 
00210     i = 2;
00211 
00212     /* is it a relative offset? */
00213     if(num_toks > 2)
00214     {
00215         while(i < num_toks)
00216         {
00217             cptr = toks[i];
00218 
00219             while(isspace((int)*cptr)) {cptr++;}
00220 
00221             if(!strcasecmp(cptr, "relative"))
00222             {
00223                 /* the offset is relative to the last pattern match */
00224                 idx->relative_flag = 1;
00225             }
00226             else if(!strcasecmp(cptr, "from_beginning"))
00227             {
00228                 idx->from_beginning_flag = 1;
00229             }
00230             else if(!strcasecmp(cptr, "string"))
00231             {
00232                 /* the data will be represented as a string that needs 
00233                  * to be converted to an int, binary is assumed otherwise
00234                  */
00235                 idx->data_string_convert_flag = 1;
00236             }
00237             else if(!strcasecmp(cptr, "little"))
00238             {
00239                 idx->endianess = LITTLE;
00240             }
00241             else if(!strcasecmp(cptr, "big"))
00242             {
00243                 /* this is the default */
00244                 idx->endianess = BIG;
00245             }
00246             else if(!strcasecmp(cptr, "hex"))
00247             {
00248                 idx->base = 16;
00249             }
00250             else if(!strcasecmp(cptr, "dec"))
00251             {
00252                 idx->base = 10;
00253             }
00254             else if(!strcasecmp(cptr, "oct"))
00255             {
00256                 idx->base = 8;
00257             }
00258             else if(!strcasecmp(cptr, "align"))
00259             {
00260                 idx->align_flag = 1;
00261             }
00262             else if(!strncasecmp(cptr, "multiplier ", 11))
00263             {
00264                 /* Format of this option is multiplier xx.
00265                  * xx is a positive base 10 number.
00266                  */
00267                 char *mval = &cptr[11];
00268                 long factor = 0;
00269                 int multiplier_len = strlen(cptr);
00270                 if (multiplier_len > 11)
00271                 {
00272                     factor = strtol(mval, &endp, 10);
00273                 }
00274                 if ((factor <= 0) || (endp != cptr + multiplier_len))
00275                 {
00276                     FatalError("%s(%d): invalid length multiplier \"%s\"\n", 
00277                             file_name, file_line, cptr);
00278                 }
00279                 idx->multiplier = factor;
00280             }
00281             else
00282             {
00283                 FatalError("%s(%d): unknown modifier \"%s\"\n", 
00284                         file_name, file_line, cptr);
00285             }
00286 
00287             i++;
00288         }
00289     }
00290 
00291     /* idx->base is only set if the parameter is specified */
00292     if(!idx->data_string_convert_flag && idx->base)
00293     {
00294         FatalError("%s(%d): hex, dec and oct modifiers must be used in conjunction \n"
00295                    "        with the 'string' modifier\n", file_name, file_line);
00296     }
00297 
00298     mSplitFree(&toks, num_toks);
00299 }
00300 
00301 
00302 /****************************************************************************
00303  * 
00304  * Function: ByteJump(char *, OptTreeNode *, OptFpList *)
00305  *
00306  * Purpose: Use this function to perform the particular detection routine
00307  *          that this rule keyword is supposed to encompass.
00308  *
00309  * Arguments: p => pointer to the decoded packet
00310  *            otn => pointer to the current rule's OTN
00311  *            fp_list => pointer to the function pointer list
00312  *
00313  * Returns: If the detection test fails, this function *must* return a zero!
00314  *          On success, it calls the next function in the detection list 
00315  *
00316  ****************************************************************************/
00317 int ByteJump(Packet *p, struct _OptTreeNode *otn, OptFpList *fp_list)
00318 {
00319     ByteJumpData *bjd;
00320     u_int32_t value = 0;
00321     u_int32_t jump_value = 0;
00322     int dsize;
00323     int use_alt_buffer = p->packet_flags & PKT_ALT_DECODE;
00324     char *base_ptr, *end_ptr, *start_ptr;
00325 
00326     bjd = (ByteJumpData *) fp_list->context;
00327 
00328     if(use_alt_buffer)
00329     {
00330         dsize = p->alt_dsize;
00331         start_ptr = (char *) DecodeBuffer;        
00332         DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, 
00333                     "Using Alternative Decode buffer!\n"););
00334 
00335     }
00336     else
00337     {
00338         start_ptr = p->data;
00339         dsize = p->dsize;
00340     }
00341 
00342     DEBUG_WRAP(
00343             DebugMessage(DEBUG_PATTERN_MATCH,"[*] byte jump firing...\n");
00344             DebugMessage(DEBUG_PATTERN_MATCH,"payload starts at %p\n", start_ptr);
00345             );  /* END DEBUG_WRAP */
00346 
00347     /* save off whatever our ending pointer is */
00348     end_ptr = start_ptr + dsize;
00349     base_ptr = start_ptr;
00350 
00351     if(doe_ptr)
00352     {
00353         /* @todo: possibly degrade to use the other buffer, seems non-intuitive*/        
00354         if(!inBounds(start_ptr, end_ptr, doe_ptr))
00355         {
00356             DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
00357                                     "[*] byte jump bounds check failed..\n"););
00358             return 0;
00359         }
00360     }
00361 
00362     if(bjd->relative_flag && doe_ptr)
00363     {
00364         DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
00365                                 "Checking relative offset!\n"););
00366         base_ptr = doe_ptr + bjd->offset;
00367     }
00368     else
00369     {
00370         DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
00371                                 "checking absolute offset %d\n", bjd->offset););
00372         base_ptr = start_ptr + bjd->offset;
00373     }
00374 
00375     /* Both of the extraction functions contain checks to insure the data
00376      * is always inbounds */
00377     
00378     if(!bjd->data_string_convert_flag)
00379     {
00380         if(byte_extract(bjd->endianess, bjd->bytes_to_grab,
00381                         base_ptr, start_ptr, end_ptr, &value))
00382         {
00383             DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
00384                                     "Byte Extraction Failed\n"););
00385 
00386             return 0;
00387         }
00388     }
00389     else
00390     {
00391         if(string_extract(bjd->bytes_to_grab, bjd->base,
00392                           base_ptr, start_ptr, end_ptr, &value))
00393         {
00394             DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
00395                                     "Byte Extraction Failed\n"););
00396 
00397             return 0;
00398         }
00399 
00400     }
00401 
00402     DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
00403                 "grabbed %d bytes, value = %08X\n", 
00404                 bjd->bytes_to_grab, value););
00405 
00406     /* Adjust the jump_value (# bytes to jump forward) with
00407      * the multiplier.
00408      */
00409     jump_value = value * bjd->multiplier;
00410 
00411     DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
00412                 "grabbed %d bytes, after multiplier value = %08X\n", 
00413                 bjd->bytes_to_grab, jump_value););
00414 
00415 
00416     /* if we need to align on 32-bit boundries, round up to the next
00417      * 32-bit value
00418      */
00419     if(bjd->align_flag)
00420     {
00421         DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, 
00422                     "offset currently at %d\n", jump_value););
00423         if ((jump_value % 4) != 0)
00424         {
00425             jump_value += (4 - (jump_value % 4));
00426         }
00427         DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
00428                     "offset aligned to %d\n", jump_value););
00429     }
00430 
00431     DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
00432                 "Grabbed %d bytes at offset %d, value = 0x%08X\n",
00433                 bjd->bytes_to_grab, bjd->offset, jump_value););
00434 
00435     if(bjd->from_beginning_flag)
00436     {
00437         /* Reset base_ptr if from_beginning */
00438         DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
00439                                 "jumping from beginning %d bytes\n", jump_value););
00440         base_ptr = start_ptr;
00441 
00442         /* from base, push doe_ptr ahead "value" number of bytes */
00443         doe_ptr = base_ptr + jump_value;
00444     }
00445     else
00446     {
00447         doe_ptr = base_ptr + bjd->bytes_to_grab + jump_value;
00448     }
00449    
00450     if(!inBounds(start_ptr, end_ptr, doe_ptr))
00451     {
00452         DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
00453                                 "tmp ptr is not in bounds %p\n", doe_ptr););
00454         return 0;
00455     }
00456     else
00457     {        
00458         return fp_list->next->OptTestFunc(p, otn, fp_list->next);
00459     }
00460 
00461     /* Never reached */
00462     return 0;
00463 }

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