int rule35943eval(void *p) {
   const uint8_t *cursor_normal = 0, *end_of_buffer;
   SFSnortPacket *sp = (SFSnortPacket *) p;

   if(sp == NULL)
      return RULE_NOMATCH;

   if(sp->payload == NULL)
      return RULE_NOMATCH;
   
   // flow:established, to_server;
   if(checkFlow(p, rule35943options[0]->option_u.flowFlags) <= 0)
      return RULE_NOMATCH;
   
   // content:"|00 01|", offset 6, depth 2;
   if(contentMatch(p, rule35943options[2]->option_u.content, &cursor_normal) <= 0)
      return RULE_NOMATCH;
   
   // content:"|00 00 00|", offset 2, depth 3, relative;
   if(contentMatch(p, rule35943options[3]->option_u.content, &cursor_normal) <= 0)
      return RULE_NOMATCH;

   if(getBuffer(sp, CONTENT_BUF_NORMALIZED, &cursor_normal, &end_of_buffer) <= 0)
      return RULE_NOMATCH;

   // move cursor to flags
   // in the TCP case, flags are at offset 4
   cursor_normal += 4;

   return DetectBindTkeyDos(cursor_normal, end_of_buffer);
}
/* detection functions */
int rule15968eval(void *p) {
    const uint8_t *cursor_normal = 0, *beg_of_payload, *end_of_payload;
    SFSnortPacket *sp = (SFSnortPacket *) p;

    uint32_t MsgLen, stringOffset;

    if(sp == NULL)
        return RULE_NOMATCH;

    if(sp->payload == NULL)
        return RULE_NOMATCH;
    
    // flow:established, to_server;
    if (checkFlow(p, rule15968options[0]->option_u.flowFlags) > 0 ) {
        // content:"heal", offset 14, depth 4, fast_pattern;
        if (contentMatch(p, rule15968options[1]->option_u.content, &cursor_normal) > 0) {
            // content:"sdfx", depth 4;
            if (contentMatch(p, rule15968options[2]->option_u.content, &cursor_normal) > 0) {

                // This protocol is goofy.  stringOffset, in the payload, is little endian.
                // MsgLen, in the header, is big endian.
                // Vulnerable condition is if stringOffset is less than 0x24 or greater
                // than MsgLen.
                if(getBuffer(sp, CONTENT_BUF_NORMALIZED, &beg_of_payload, &end_of_payload) <= 0)
                   return RULE_NOMATCH;
 
                if(end_of_payload - beg_of_payload < 38)
                   return RULE_NOMATCH;

                cursor_normal = beg_of_payload + 34;
                stringOffset = *cursor_normal++;
                stringOffset |= *cursor_normal++ << 8;
                stringOffset |= *cursor_normal++ << 16;
                stringOffset |= *cursor_normal << 24;

                //printf("stringOffset = %d (0x%08x)\n", stringOffset, stringOffset);

                if(stringOffset < 0x24)
                    return RULE_MATCH;

                cursor_normal = beg_of_payload + 4;
                MsgLen = *cursor_normal++ << 24;
                MsgLen |= *cursor_normal++ << 16;
                MsgLen |= *cursor_normal++ << 8;
                MsgLen |= *cursor_normal;

                //printf("MsgLen = %d (0x%08x)\n", MsgLen, MsgLen);

                if(stringOffset > MsgLen)
                    return RULE_MATCH;

                // Note there is also a two-byte big endian value PayloadLen at offset 12
                // and a four-byte little endian dataLen at offset 18.
                // We ignore them, because they do not seem relevant to detection.
            }
        }
    }
    return RULE_NOMATCH;
}
/* detection functions */
int rule16180eval(void *p) {
    const u_int8_t *cursor_normal = 0;
    SFSnortPacket *sp = (SFSnortPacket *) p;
    const u_int8_t *beg_of_payload, *end_of_payload;
    const u_int8_t *end_of_CommonName;

    if(sp == NULL)
        return RULE_NOMATCH;

    if(sp->payload == NULL)
        return RULE_NOMATCH;
    
    // flow:established, to_client;
    if (checkFlow(p, rule16180options[0]->option_u.flowFlags) > 0 ) {

        // content:"|16 03|", depth 0;
        if (contentMatch(p, rule16180options[1]->option_u.content, &cursor_normal) > 0) {

            // content:"U|04 03|", depth 0, relative, fast_pattern;
            if (contentMatch(p, rule16180options[2]->option_u.content, &cursor_normal) > 0) {

                if(getBuffer(sp, CONTENT_BUF_NORMALIZED, &beg_of_payload, &end_of_payload) <= 0)
                  return RULE_NOMATCH;

                // Skip single byte type value, we're not checking it
                cursor_normal++;

                if(cursor_normal + 1 > end_of_payload)
                   return RULE_NOMATCH;

                // Extract one-byte length value and use it to set end_of_CommonName
                end_of_CommonName = cursor_normal + *cursor_normal + 1;

                // Skip length value
                cursor_normal++;

                // Ensure we don't go past the end of the payload
                if (end_of_payload < end_of_CommonName) {
                    end_of_CommonName = end_of_payload;
                }

                // Zip through the field, stop at end or NULL
                while ((cursor_normal < end_of_CommonName) && (*cursor_normal++)) {
                   // empty loop
                }

                // If we stop before the end, there was a NULL so alert
                if (cursor_normal < end_of_CommonName) {
                    return RULE_MATCH;
                }
            }
        }
    }
    return RULE_NOMATCH;
}
int rule37676eval(void *p) {
   const uint8_t *cursor_normal = 0, *end_of_buffer;
   SFSnortPacket *sp = (SFSnortPacket *) p;

   if(sp == NULL)
      return RULE_NOMATCH;

   if(sp->payload == NULL)
      return RULE_NOMATCH;

   // flow:to_server
   if(checkFlow(p, rule37676options[0]->option_u.flowFlags) <= 0)
      return RULE_NOMATCH;

   // content:"|84|", fast_pattern:only;
   // if(contentMatch(p, rule37676options[1]->option_u.content, &cursor_normal) <= 0)
   //    return RULE_NOMATCH;
  
   // content:"|20|", offset 17, depth 1;
   if(contentMatch(p, rule37676options[2]->option_u.content, &cursor_normal) <= 0)
      return RULE_NOMATCH;

   if(getBuffer(sp, CONTENT_BUF_NORMALIZED, &cursor_normal, &end_of_buffer) <= 0)
      return RULE_NOMATCH;

   return DetectCiscoIkeBof(sp, cursor_normal, end_of_buffer);
}
// #if 0 // Don't compile the detection functions if they're not used
int rule18063eval(void *p) {
    const uint8_t *cursor_normal = 0, *OfficeArtSPContainer = 0, *OfficeArtSpgrContainer = 0, *OfficeArtFSP = 0, *OfficeArtFSPGR = 0;
    const uint8_t *beg_of_payload = 0, *end_of_payload = 0, *tmp_payload = 0;
    uint32_t OfficeArtSpgrContainer_size = 0, OfficeArtSPContainer_size = 0;
    SFSnortPacket *sp = (SFSnortPacket *) p;

    if(sp == NULL)
        return RULE_NOMATCH;

    if(sp->payload == NULL)
        return RULE_NOMATCH;
    
    // flow:established, to_client;
    if (checkFlow(p, rule18063options[0]->option_u.flowFlags) <= 0 ) {
       return RULE_NOMATCH;
    }
    // flowbits:isset "file.doc";
    if (processFlowbits(p, rule18063options[1]->option_u.flowBit) <= 0) {
       return RULE_NOMATCH;
    }
    if(getBuffer(sp, CONTENT_BUF_NORMALIZED, &beg_of_payload, &end_of_payload) <= 0) {
      return RULE_NOMATCH;
    }

    // Start by finding inner container
    // content:"|0F 00 04 F0|", depth 0, fast_pattern;
    if (contentMatch(p, rule18063options[3]->option_u.content, &OfficeArtSPContainer) <= 0) {
       return RULE_NOMATCH;
    }

    DEBUG_SO(fprintf(stderr, "OfficeArtSPContainer found: %p\n", OfficeArtSPContainer);)
    
    // Find the outer container - This may or may not exist
    // content:"|0F 00 03 F0|", depth 0; 
    if(contentMatch(p, rule18063options[2]->option_u.content, &OfficeArtSpgrContainer) <= 0) {
// #if 0 // Don't compile the detection functions if they're not used
int rule23039eval(void *p) {
    const u_int8_t  *cursor_normal  = 0;
    SFSnortPacket *sp = (SFSnortPacket *) p;

    if(sp == NULL)
        return RULE_NOMATCH;

    if(sp->payload == NULL)
        return RULE_NOMATCH;

    // flow:to_server;
    if(checkFlow(p, rule23039options[0]->option_u.flowFlags) <= 0 )
        return RULE_NOMATCH;
   
    // content:"|00 01 00 00 00 00|", offset 4, depth 8, fast_pattern;
    if(contentMatch( p, rule23039options[1]->option_u.content, &cursor_normal ) <= 0)
        return RULE_NOMATCH;

    // The last |00| in the match above drops the cursor at the beginning of the first query,
    //      12 bytes from the beginning of the payload.  If the first 2 bits are set on this byte,
    //      it means we're looking at a pointer.  In that event, we'll go ahead and flag it, because
    //      we've already verified that there is only one query.

    return detectDNSloop(sp, cursor_normal );
}
/* detection functions */
int rule23847eval(void *p) {
    const u_int8_t *cursor_normal = 0;
    SFSnortPacket *sp = (SFSnortPacket *) p;
    const u_int8_t *end_of_payload = 0;
    const u_int8_t *beg_of_payload = 0;
    const u_int8_t *beg_of_servers = 0;
    const u_int8_t *start_of_smb = 0;

    int16_t converter = 0;
    int16_t server_comment = 0;
    int16_t server_comment_position = 0;

    u_int32_t entries = 0;
    u_int32_t netbios_message_length = 0; 

    int i;

    if(sp == NULL)
        return RULE_NOMATCH;

    if(sp->payload == NULL)
        return RULE_NOMATCH;
    
    // flow:established, to_client;
    if (checkFlow(p, rule23847options[0]->option_u.flowFlags) <= 0 )
      return RULE_NOMATCH;

    // Verify we are looking at an SMB Trans (0x25) response.
    // Verify the SMB Request was STATUS_SUCCESS (0x00000000)
    // content:"|FF|SMB|25 00 00 00 00|", depth 0, fast_pattern;
    if (contentMatch(p, rule23847options[1]->option_u.content, &cursor_normal) <= 0)
      return RULE_NOMATCH;

    // Verify LANMAN protocol is reporting additional data available.
    // content:"|EA 00|", offset 47, depth 2, relative;
    if(contentMatch(p, rule23847options[2]->option_u.content, &cursor_normal) <= 0)
      return RULE_NOMATCH;

    // Get the beginning of payload and end of payload positions.
    if(getBuffer(sp, CONTENT_BUF_NORMALIZED, &beg_of_payload, &end_of_payload) <= 0)
      return RULE_NOMATCH;

    start_of_smb = beg_of_payload + 4;  // Beginning of 9-byte content match

    netbios_message_length = READ_BIG_16(beg_of_payload + 2); // 2 byte size field
    DEBUG_SO(fprintf(stderr,"\nnetbios_message_length: %d\n", netbios_message_length);)
/* detection functions */
int rule15329eval(void *p) {
    const u_int8_t *cursor_normal = 0;
    SFSnortPacket *sp = (SFSnortPacket *) p;
    u_int8_t countOne = 0;
    u_int8_t countTwo = 0;
    const u_int8_t *beg_of_payload, *end_of_payload;

    if(sp == NULL)
        return RULE_NOMATCH;

    if(sp->payload == NULL)
        return RULE_NOMATCH;


    // flow:established, to_server;
    if (checkFlow(p, rule15329options[0]->option_u.flowFlags) > 0 ) {
        // content:"MODPROPS"; nocase; 
        if (contentMatch(p, rule15329options[1]->option_u.content, &cursor_normal) > 0) {

            if(getBuffer(sp, CONTENT_BUF_NORMALIZED, &beg_of_payload, &end_of_payload) <= 0)
                return RULE_NOMATCH;

            while ((cursor_normal < end_of_payload) && (*cursor_normal != '\r') && (*cursor_normal != '\n')) {
                if (*cursor_normal == ',') {
                    countOne++;
                }
                cursor_normal++;
            }
            if (contentMatch(p, rule15329options[2]->option_u.content, &cursor_normal) > 0) {
                while ((cursor_normal < end_of_payload) && (*cursor_normal != '\r') && (*cursor_normal != '\n')) {
                    if (*cursor_normal == ',') {
                        countTwo++;
                    }
                    cursor_normal++;
                }
            }
            // Yes, technically these are both off-by-one on the count...but why waste the CPU
            // necessary to increment them both when leaving them as-is yields the same result?
            if (countTwo > countOne) {
                return RULE_MATCH;
            }
        }
    }
    return RULE_NOMATCH;
}
/* detection functions */
int rule16396eval(void *p) {
    const uint8_t *cursor_normal = 0;
    SFSnortPacket *sp = (SFSnortPacket *) p;

    const uint8_t *beg_of_payload, *end_of_payload;
    uint32_t length = 0;
    uint16_t WCT;
    uint16_t BCC;

    if(sp == NULL)
        return RULE_NOMATCH;

    if(sp->payload == NULL)
        return RULE_NOMATCH;
    
    // flow:established, to_server;
    if (checkFlow(p, rule16396options[0]->option_u.flowFlags) > 0 ) {
        // content:"|FF|SMBr", offset 4, depth 5, fast_pattern;
        if (contentMatch(p, rule16396options[1]->option_u.content, &cursor_normal) > 0) {

            if(getBuffer(sp, CONTENT_BUF_NORMALIZED, &beg_of_payload, &end_of_payload) <= 0)
                     return RULE_NOMATCH;

            // isdataat:offset 30, relative;
            if (cursor_normal + 30 <= end_of_payload) {

                //Extract length from Netbios session header
                //Previous content match assures us no buffer underread
                length = *(cursor_normal-8) << 16;
                length |= *(cursor_normal-7) << 8;
                length |= *(cursor_normal-6);

                //Extract WCT Word Count
                //Word Count should be usually be zero in negotiate requests
                //But we need to be able to handle the case where there is 
                //some value in there.
                cursor_normal += 27;
                WCT =  2 * *cursor_normal++;
                cursor_normal += WCT;                

                //Make sure there is enough room to extract BCC
                if (cursor_normal + 2 > end_of_payload)
                    return RULE_NOMATCH;

                //Extract BCC Byte Count
                BCC = read_little_16_inc(cursor_normal);

                //Alert if your netbios session size is bigger than
                //Byte count + number of words * 2 + 32-byte SMB header
                //+ 3 bytes (1 for the WCT field, and 2 for the BCC field)
                if (length > (BCC + WCT + 35))
                    return RULE_MATCH;
            }
        }
    }
    return RULE_NOMATCH;
}
/* detection functions */
int rule19187eval(void *p) {
   const u_int8_t *cursor_normal = 0;
   SFSnortPacket *sp = (SFSnortPacket *) p;

   u_int16_t flags, num_of_answers, data_len;
   const u_int8_t *beg_of_payload, *end_of_payload;
   const u_int8_t *start_hostent, *end_hostent;

   int i;

   if(sp == NULL)
       return RULE_NOMATCH;

   if(sp->payload == NULL)
       return RULE_NOMATCH;

   // flow:to_client;
   if (checkFlow(p, rule19187options[0]->option_u.flowFlags) > 0 ) {

      if(getBuffer(sp, CONTENT_BUF_NORMALIZED, &beg_of_payload, &end_of_payload) <= 0)
         return RULE_NOMATCH;

      // Ensure we have enough data
      // txid, flags, num records * 4, query response (unk), at least 256 bytes of hostent
      // So, at least 300 bytes, I guess.
      DEBUG_SO(printf("Payload size = %d\n", (int)(end_of_payload - beg_of_payload));)
      if(end_of_payload - beg_of_payload < 300)
         return RULE_NOMATCH;

      // Forcing to be only one response entry
      // content:"|00 01|", offset 4, depth 2, fast_pattern;
      if (contentMatch(p, rule19187options[1]->option_u.content, &cursor_normal) <= 0) {
          return RULE_NOMATCH;
      }

      // Now, let's make sure this is actually a standard query response.
      // Our content match above ensures we have requisite data.

      flags = *(cursor_normal - 4) << 8;
      flags |= *(cursor_normal - 3);

      if((flags & 0xFA0F) != 0x8000) {
         // 1 bit - response (1 = response)
         // 4 bits - opcode (0000 = standard query)
         // 1 bit - authoritative (don't care)
         // 1 bit - truncated (0 = not truncated)
         // 5 bits - recursion and other don't cares
         // 4 bits - reply code (0000 = no error)
         return RULE_NOMATCH;
      }

      // Get number of answers
      num_of_answers = *cursor_normal++ << 8;
      num_of_answers |= *cursor_normal;
      DEBUG_SO(printf("We have %d answers\n", num_of_answers);)
/* detection functions */
int rule15700eval(void *p) {
   const u_int8_t *cursor_normal = 0, *beg_of_payload, *end_of_payload;
   SFSnortPacket *sp = (SFSnortPacket *) p;

   if(sp == NULL)
      return RULE_NOMATCH;

   if(sp->payload == NULL)
      return RULE_NOMATCH;
    
   // content:"|02|", depth 1;
   if(contentMatch(p, rule15700options[0]->option_u.content, &cursor_normal) <= 0)
      return RULE_NOMATCH;

   // content:"c|82|Sc", offset 236, depth 4, fast_pattern;
   if(contentMatch(p, rule15700options[1]->option_u.content, &cursor_normal) <= 0)
      return RULE_NOMATCH;

   if(getBuffer(sp, CONTENT_BUF_NORMALIZED, &beg_of_payload, &end_of_payload) <= 0)
      return RULE_NOMATCH;

   // "c|82|Sc" puts us at the beginning of the dhcp options
   // 0xFF is the end of DHCP options
   while((cursor_normal + 1 < end_of_payload) && (*cursor_normal != 0xFF)) {

      if(*cursor_normal == 0x01) { // subnet mask option

         // Alert if the subnet mask is more than four bytes long
         if(*(cursor_normal + 1) > 4)
            return RULE_MATCH;

         // Do not return RULE_NOMATCH in the negative case in case it's
         // possible to specify this option more than once and still hit
         // the vulnerable code
           
      }

      cursor_normal += *(cursor_normal + 1) + 2; // + option size + option type and size bytes
   }

   return RULE_NOMATCH;
}
int ruleMYSQL_COM_TABLE_DUMPeval(void *p) {
   const uint8_t *cursor_normal = 0, *beg_of_payload = 0, *end_of_payload = 0;
   uint32_t packet_length;
   uint8_t db_name_length, table_name_length;

   SFSnortPacket *sp = (SFSnortPacket *) p; 

   // flow:established, to_server;
   if(checkFlow(p, ruleMYSQL_COM_TABLE_DUMPoptions[0]->option_u.flowFlags) > 0 ) {

      /* Make sure the packet is long enough */
      if(getBuffer(sp, CONTENT_BUF_NORMALIZED, &beg_of_payload, &end_of_payload) <= 0)
         return RULE_NOMATCH;

      if((end_of_payload - beg_of_payload) < 6)
         return RULE_NOMATCH;


      // content:"|13|", depth 1; offset 4;
      if(contentMatch(p, ruleMYSQL_COM_TABLE_DUMPoptions[1]->option_u.content, &cursor_normal) > 0) {

         // Grab the size of the "packet" -- this is the size (in bytes) of
         // data after the message number byte, including the command byte
         // Packet size is 3 bytes, little endian
         packet_length = beg_of_payload[0];
         packet_length += beg_of_payload[1] << 8;
         packet_length += beg_of_payload[2] << 16;

         // Grab the length of the DB Name
         db_name_length = beg_of_payload[5];

         // if db name length > packet length (+2 for length and command
         // bytes), flag
         if((db_name_length + 2) > packet_length) {
            return RULE_MATCH;
         }  else {
            // else grab table name length
            // table_name_length is at offset of db_name + db_name_length 
            // + size byte
            if((end_of_payload - beg_of_payload) < 5 + db_name_length + 2) 
               return RULE_NOMATCH;

            table_name_length = beg_of_payload[5 + db_name_length + 1]; 

            // if table name length + db name length + size bytes
            // + command byte > packet length, flag
            if((db_name_length + table_name_length + 3) > packet_length)
               return RULE_MATCH;
         }
      }  
   }  

   return RULE_NOMATCH;
}
/* detection functions */
int rule13897eval(void *p) {
   const u_int8_t *cursor_normal = 0;
   SFSnortPacket *sp = (SFSnortPacket *) p;

   const u_int8_t *beg_of_payload, *end_of_payload;
   u_int32_t atom_size;
   u_int16_t region_size;
      
   if(sp == NULL)
      return RULE_NOMATCH;

   if(sp->payload == NULL)
      return RULE_NOMATCH;
    
   // flow:established, to_client;
   if(checkFlow(p, rule13897options[0]->option_u.flowFlags) > 0 ) {
      // flowbits:isset "file.quicktime";
      if(processFlowbits(p, rule13897options[1]->option_u.flowBit) > 0) {
        // content:"crgn";
        if(contentMatch(p, rule13897options[2]->option_u.content, &cursor_normal) > 0) {
           if(getBuffer(sp, CONTENT_BUF_NORMALIZED, &beg_of_payload, &end_of_payload) <= 0)
              return RULE_NOMATCH;
                
           if(cursor_normal + 2 >= end_of_payload)
              return RULE_NOMATCH;
   
           region_size = (*cursor_normal++) << 8;
           region_size |= *cursor_normal++;
   
           DEBUG_WRAP(printf("REGION SIZE: %d\n", region_size));
      
           cursor_normal = cursor_normal - 10;

           if(cursor_normal < beg_of_payload)
              return RULE_NOMATCH;
      
           atom_size = (*cursor_normal++) << 24;   
           atom_size |= (*cursor_normal++) << 16;
           atom_size |= (*cursor_normal++) << 8;
           atom_size |= *cursor_normal++;
   
           DEBUG_WRAP(printf("ATOM SIZE: %d\n", atom_size));
  
           // Changed from region_size > (atom_size - 8) to avoid
           // integer underflow from (atom_size - 8)
           if(((u_int32_t)region_size + 8) > atom_size) 
              return RULE_MATCH;
         }
      }
   }

   return RULE_NOMATCH;
}
/* detection functions */
int rule13469eval(void *p) {
    const uint8_t *cursor_normal = 0;
    const uint8_t *beg_of_payload, *end_of_payload;
    uint32_t length;

    SFSnortPacket *sp = (SFSnortPacket *) p;

    // flow:established, to_client;
    if (checkFlow(p, rule13469options[0]->option_u.flowFlags) > 0 ) {
        // flowbits:isset "file.doc";
        if (processFlowbits(p, rule13469options[1]->option_u.flowBit) > 0) {

            // content:"bjbj";
            if (contentMatch(p, rule13469options[2]->option_u.content, &cursor_normal) > 0) {
                // content:"|00 00 00 00|", offset 62, depth 4, relative;
                if (!(contentMatch(p, rule13469options[3]->option_u.content, &cursor_normal) > 0)) {

                if(getBuffer(sp, CONTENT_BUF_NORMALIZED, &beg_of_payload, &end_of_payload) <= 0)
                    return RULE_NOMATCH;

                // At this point, cursor_normal is still right after bjbj because negative
                // content matches do not move the pointer
                // Start custom detection here
                if((cursor_normal + 572) > end_of_payload)
                   return RULE_NOMATCH;

                cursor_normal += 568;
                length = *cursor_normal++;
                length |= *cursor_normal++ << 8;
                length |= *cursor_normal++ << 16;
                length |= *cursor_normal++ << 24;

                if((length - 4) % 0x1a)
                   return RULE_MATCH;
                }
            }
        }
    }
    return RULE_NOMATCH;
}
/* detection functions */
int ruleCITRIX_METAFRAME_BOeval(void *p) {
    const uint8_t *cursor_normal = 0, *beg_of_payload, *end_of_payload;

    const uint8_t *cursor_extract = 0;
    uint32_t event_data_length, description_length, encr_data_length;

    SFSnortPacket *sp = (SFSnortPacket *) p;

    // flow:established, to_server;
    if (checkFlow(p, ruleCITRIX_METAFRAME_BOoptions[0]->option_u.flowFlags) > 0 ) {

        // content:"A|80 00 00 02|", offset 28, depth 5;
        if (contentMatch(p, ruleCITRIX_METAFRAME_BOoptions[1]->option_u.content, &cursor_normal) > 0) {

            // byte_test:size 4, value 16, operator <, offset 4, endian little;
            if (byteTest(p, ruleCITRIX_METAFRAME_BOoptions[2]->option_u.byte, cursor_normal) > 0) {

                if(getBuffer(sp, CONTENT_BUF_NORMALIZED, &beg_of_payload, &end_of_payload) <= 0)
                     return RULE_NOMATCH;

                if((end_of_payload - beg_of_payload) < 0x28)
                   return RULE_NOMATCH;


                // Extract Event Data Length ( 4 bytes little endian )
                cursor_extract = &(beg_of_payload[0x0008]);
                event_data_length  = (*cursor_extract++) & 0xFF;
                event_data_length |= ((*cursor_extract++) & 0xFF) << 8;
                event_data_length |= ((*cursor_extract++) & 0xFF) << 16;
                event_data_length |= ((*cursor_extract++) & 0xFF) << 24;

                // Extract Description Length ( 2 bytes little endian )
                cursor_extract = &(beg_of_payload[0x0022]);
                description_length  = (*cursor_extract++) & 0xFF;
                description_length |= ((*cursor_extract++) & 0xFF) << 8;

		// extract Encrypted Data Length ( 4 bytes little endian )
                cursor_extract = &(beg_of_payload[0x00024]);
                encr_data_length  = (*cursor_extract++) & 0xFF;
                encr_data_length |= ((*cursor_extract++) & 0xFF) << 8;
                encr_data_length |= ((*cursor_extract++) & 0xFF) << 16;
                encr_data_length |= ((*cursor_extract++) & 0xFF) << 24;

                if(description_length + encr_data_length > event_data_length)
                   return RULE_MATCH;
            }
        }
    }
    return RULE_NOMATCH;
}
/* detection functions */
int rule15148eval(void *p) {
    const u_int8_t *cursor_normal = 0, *beg_of_payload, *end_of_payload;
    SFSnortPacket *sp = (SFSnortPacket *) p;
    u_int16_t data_len;

    if(sp == NULL)
        return RULE_NOMATCH;

    if(sp->payload == NULL)
        return RULE_NOMATCH;
    
    // flow:established, to_server;
    if (checkFlow(p, rule15148options[0]->option_u.flowFlags) > 0 ) {
        // content:"RCH0", depth 4, nocase;
        if (contentMatch(p, rule15148options[1]->option_u.content, &cursor_normal) > 0) {
            // content:"RCHE", offset 4, depth 4, nocase, relative;
            if (contentMatch(p, rule15148options[2]->option_u.content, &cursor_normal) > 0) {
                cursor_normal = cursor_normal - 8;
                data_len = *cursor_normal++;
                data_len |= (*cursor_normal++) << 8;

                if(data_len >= 130)
                   return RULE_MATCH;

                if(getBuffer(sp, CONTENT_BUF_NORMALIZED, &beg_of_payload, &end_of_payload) <= 0)
                   return RULE_NOMATCH;

                // Normally, we'd be nervous about this check with TCP, but given the
                // packet sizes involved, we'll take the false positives from segmentation
                // on such a small packet.
                if(cursor_normal + 6 + data_len != end_of_payload)
                   return RULE_MATCH;
            }
        }
    }
    return RULE_NOMATCH;
}
int rule23040eval(void *p) {
    const u_int8_t *cursor_normal = 0;
    SFSnortPacket *sp = (SFSnortPacket *) p;

    if(sp == NULL)
        return RULE_NOMATCH;

    if(sp->payload == NULL)
        return RULE_NOMATCH;
    
    // flow:established, to_server;
    if(checkFlow(p, rule23040options[0]->option_u.flowFlags) <= 0 ) 
        return RULE_NOMATCH;

    // content:"|00 01 00 00 00 00 00 00|", offset 6, depth 8, fast_pattern;
    if(contentMatch(p, rule23040options[1]->option_u.content, &cursor_normal) <= 0)  
        return RULE_NOMATCH;

    return detectDNSloop( sp, cursor_normal );
}
Ejemplo n.º 18
0
/* detection functions */
int ruleDHCPCATeval(void *p) {
    const u_int8_t *end;
    const u_int8_t *ptr;
    unsigned short type;
    unsigned short size;
    unsigned short sizes[256];
    SFSnortPacket *sp = (SFSnortPacket *) p;
    const u_int8_t *cursor_normal = 0, *beg_of_payload;


    if (NULL == sp)
        return RULE_NOMATCH;

    if (NULL == sp->payload)
        return RULE_NOMATCH;

    if (contentMatch(p, ruleDHCPCAToptions[0]->option_u.content, &cursor_normal)) {
        if(getBuffer(sp, CONTENT_BUF_NORMALIZED, &beg_of_payload, &end) <= 0)
           return RULE_NOMATCH;

        /* offset for cookie + 2 options of size 500 */
        if (740 > (end - beg_of_payload))
        return RULE_NOMATCH;

        ptr = beg_of_payload + 240;
      
        memset(sizes, 0, sizeof(sizes));

        while (ptr + 2 < end)
        {
            type = (((u_int8_t) *(ptr))&0xFF);
            size = (((u_int8_t) *(ptr+1))&0xFF);
            if ((sizes[type] += size) > 500) {
                return RULE_MATCH;
            }
            ptr += 2 + size;
        }
    }

    return RULE_NOMATCH;
}
Ejemplo n.º 19
0
/* detection functions */
int ruleIGMPIPOPTDOSeval(void *p) {
    int i = 0;
    u_int8_t alert = 0;
    const u_int8_t *cursor_normal = 0;
    SFSnortPacket *sp = (SFSnortPacket *) p;
    u_int8_t *ip_options_data;

    if (checkHdrOpt(p, ruleIGMPIPOPTDOSoptions[0]->option_u.hdrData)) {
        if (contentMatch(p, ruleIGMPIPOPTDOSoptions[1]->option_u.content, &cursor_normal) > 0) {
            if (sp->ip4_options_data != NULL) {
                ip_options_data = (u_int8_t *) sp->ip4_options_data;

                if (sp->ip4_options_length >= 2) {
                    if (*ip_options_data == 0 &&
                        *(ip_options_data+1) == 0) {
                        return RULE_MATCH;
                    }
                }
            }

            for(i=0; i< (int) sp->num_ip_options; i++) {
                if (sp->ip_options[i].option_code == 148) {
                    return RULE_NOMATCH;
                }

                if (sp->ip_options[i].length == 1) {
                    alert++;
                }
            }
            if (alert > 0) {
                return RULE_MATCH;
            }
        }
    }
    return RULE_NOMATCH;
}
/* detection functions */
int rule15117eval(void *p) {
   const uint8_t *cursor_normal = 0;
   SFSnortPacket *sp = (SFSnortPacket *) p;
   const uint8_t *end_of_payload, *end_of_record;
   const uint8_t *cursor_nextloop;

   uint16_t obj_record_len;
   uint16_t ft;
   uint16_t cb;

   if(sp == NULL)
      return RULE_NOMATCH;

   if(sp->payload == NULL)
      return RULE_NOMATCH;
    
   // flow:established, to_client;
   if(checkFlow(p, rule15117options[0]->option_u.flowFlags) <= 0 )
      return RULE_NOMATCH;

   // flowbits:isset "file.xls";
   if(processFlowbits(p, rule15117options[1]->option_u.flowBit) <= 0)
      return RULE_NOMATCH;

   if(getBuffer(sp, CONTENT_BUF_NORMALIZED, &cursor_normal, &end_of_payload) <= 0)
      return RULE_NOMATCH;

   // content:"|5D 00|";
   while(contentMatch(p, rule15117options[2]->option_u.content, &cursor_normal) > 0) {
      // If we need to search again, we want to start here in case we matched on data
      cursor_nextloop = cursor_normal; 

      // The first sub-record is 22 bytes plus the 2-byte obj_record_len
      if(cursor_normal + 24 >= end_of_payload)
         return RULE_NOMATCH;

      // Verify the first sub-record is type 0x0015 to reduce false positives.
      // This also adds false negatives, but otherwise the FP rate will be
      // astronomical.
      if((*(cursor_normal + 2) != 0x15) || (*(cursor_normal + 3) != 0x00))
         continue;

      // Verify the second sub-record is type 0x0012 to reduce false positives.
      if((*(cursor_normal + 4) != 0x12) || (*(cursor_normal + 5) != 0x00))
         continue;

      // Verify the last 3 bytes in the sub-record are null
      if(*(cursor_normal + 12) != 0)
         continue;
      if(*((uint16_t*)(cursor_normal + 13)) !=0)  // byte order doesn't matter here
         continue;

      obj_record_len = *cursor_normal++;
      obj_record_len |= *cursor_normal++ << 8;

      DEBUG_WRAP(printf("obj_record_len=0x%04x\n", obj_record_len));

      if(obj_record_len == 0) // if 0, not a valid record
         return RULE_NOMATCH;

      obj_record_len -= 4; // minus 2 for tag and 2 for size to properly find end_of_record

      //the record with no variable length data will not exceed 160 ish bytes. Use this check to eliminate FPs
      if(obj_record_len > 1000)
         continue;

      // Stop at the end of the record or when we run out of data
      end_of_record = (cursor_normal + obj_record_len >= end_of_payload) ? end_of_payload : cursor_normal + obj_record_len;

      // Skip the first sub-record, it's always 22 bytes. Bounds check was prior to this
      cursor_normal += 22;

      while(cursor_normal + 2 < end_of_record) {

         ft = *cursor_normal++;
         ft |= *cursor_normal++ << 8;
                 
         DEBUG_WRAP(printf("FT: 0x%02x\n", ft));
                    
         if(ft > 0x15)
            return RULE_MATCH;

         if(cursor_normal + 2 > end_of_record)
            break; // Get out of the loop, look for another OBJ record

         cb = *cursor_normal++;
         cb |= *cursor_normal++ << 8;

         DEBUG_WRAP(printf("  cb: 0x%02x\n", cb));

         cursor_normal += cb;
      }

      DEBUG_WRAP(printf("Searching for new OBJ record (|5D 00|)\n"));

      // Start our next search immediately after the last "|5D 00|"
      cursor_normal = cursor_nextloop;
   }

   return RULE_NOMATCH;
}
/* detection functions */
int rule17697eval(void *p) {
    const uint8_t *cursor_normal = 0;
    const uint8_t *beg_of_buffer, *end_of_buffer;

    uint8_t decodedbuf[MAX_BASE64_BUFFER_SIZE], *decodedbuf_ptr;
    uint32_t inputchars, decodedbytes;
    SFSnortPacket *sp = (SFSnortPacket *) p;

    uint32_t tmpval = 0;

    if(sp == NULL)
        return RULE_NOMATCH;

    if(sp->payload == NULL)
        return RULE_NOMATCH;
    
    // flow:established, to_server;
    if (checkFlow(p, rule17697options[0]->option_u.flowFlags) > 0 ) {
        // content:"-----BEGIN PGP MESSAGE-----", depth 0, nocase, fast_pattern;
        if (contentMatch(p, rule17697options[1]->option_u.content, &cursor_normal) > 0) {
            DEBUG_SO(printf("Matched the PGP header\n"));

            // content:"Version|3A|", offset 2, depth 8, nocase, relative;
            if (contentMatch(p, rule17697options[2]->option_u.content, &cursor_normal) > 0) {
                DEBUG_SO(printf("Matched the version\n"));

                // content:"|0D 0A 0D 0A|", depth 0, relative;
                if (contentMatch(p, rule17697options[3]->option_u.content, &cursor_normal) > 0) {
                    DEBUG_SO(printf("Matched the newline\n"));

                    if(getBuffer(sp, CONTENT_BUF_NORMALIZED, &beg_of_buffer, &end_of_buffer) != CURSOR_IN_BOUNDS)
                        return RULE_NOMATCH;
               
                    // We should now be at the beginning of the PGP data
                    // Four base64 input chars become three output chars
                    inputchars = (end_of_buffer > cursor_normal + (sizeof(decodedbuf) * 4 / 3)) ? (sizeof(decodedbuf) * 4 / 3) : end_of_buffer - cursor_normal;
                    DEBUG_SO(printf("Decoding %d bytes\n", inputchars));

                    // Only need 6 output bytes, plus 1 byte for the NULL added by base64decode()
                    if(base64decode(cursor_normal, inputchars, decodedbuf, 7, &decodedbytes) < 0) {
                        DEBUG_SO(printf("Failed to decode any data to work with\n"));
                        return RULE_NOMATCH;
                    }
                    
                    DEBUG_SO(printf("Decoded %d bytes\n", decodedbytes));

                    // Make sure we have enough data to work with
                    if(decodedbytes >= 6) {
                        decodedbuf_ptr = decodedbuf;

                        // New format with content tag of 16 or 61 (both in the first byte)
                        DEBUG_SO(printf("Packet format: %01x\n", decodedbuf[0]));

                        // The top two bits are set, the lower six we want to be either 16 or 61.
                        // 0xC0 + 16 = 0xD0,  0xC0 + 61 = 0xFD
                        if((decodedbuf[0] == (uint8_t)0xD0) || (decodedbuf[0] == (uint8_t)0xFD)) {

                            if(decodedbuf[1] == 0xFF) {
                               decodedbuf_ptr = decodedbuf + 2;

                               tmpval =  *decodedbuf_ptr++;
                               tmpval |= *decodedbuf_ptr++ << 8;
                               tmpval |= *decodedbuf_ptr++ << 16;
                               tmpval |= *decodedbuf_ptr++ << 24;

                               DEBUG_SO(printf("Packet Size: 0x%08x\n", tmpval));

                               if((tmpval >= 0xF9FFFFFF) && (tmpval <= 0xFEFFFFFF)) {
                                  return RULE_MATCH;
                               }
                            }
                        }       
                    }
                }
            }
        }
    }
    return RULE_NOMATCH;
}
/* detection functions */
int rule33053eval(void *p) {
   const uint8_t *check, *end_of_buffer, *cursor_normal = 0;
   SFSnortPacket *sp = (SFSnortPacket *) p;

   int i, j;
   uint8_t atype, alength;

   if(sp == NULL)
      return RULE_NOMATCH;

   if(sp->payload == NULL)
      return RULE_NOMATCH;
   
   // content:"|01|", depth 1;
   if(contentMatch(p, rule33053options[0]->option_u.content, &cursor_normal) <= 0)
      return RULE_NOMATCH;
   
   // content:"|1F 13|", depth 0, fast_pattern;
   if(contentMatch(p, rule33053options[1]->option_u.content, &cursor_normal) <= 0)
      return RULE_NOMATCH;
   
   // content:"|2D|", offset 2, depth 1, relative;
   if(contentMatch(p, rule33053options[2]->option_u.content, &cursor_normal) <= 0)
      return RULE_NOMATCH;
   
   // content:"|2D|", offset 2, depth 1, relative;
   if(contentMatch(p, rule33053options[3]->option_u.content, &cursor_normal) <= 0)
      return RULE_NOMATCH;

   if(getBuffer(p, CONTENT_BUF_NORMALIZED, &cursor_normal, &end_of_buffer) <= 0)
      return RULE_NOMATCH;

   // following RFC 2865 Page 17
   // skip code (1 byte), pkt identifier (1 byte),
   // length (2 bytes), authenticator (16 bytes)
   cursor_normal += 20;

   // parse up to 10 attributes (TLV)
   for(i = 0; i < 10; i++)
   {
      // make sure we can read type and length (1 byte each)
      if(cursor_normal + 2 > end_of_buffer)
         return RULE_NOMATCH;

      atype = *cursor_normal;
      alength = *(cursor_normal+1);

      DEBUG_SO(fprintf(stderr,"radius attribute type:0x%02X len:0x%02X\n",atype,alength);)

      // make sure we can read value 
      check = cursor_normal + alength;

      // overflow check
      if(check <= cursor_normal)
         return RULE_NOMATCH;

      // overread check
      if(check > end_of_buffer)
         return RULE_NOMATCH;

      if(atype == 0x01)
      {
         // restrict how many bytes we will check
         // in the User-Name Attribute Value
         if(alength > 25)
            alength = 25;

         // User-Name Attribute, check for '(' or ')', if present, alert.
         // we start at index 2 because alength includes the Type and Length
         for(j = 2; j < alength; j++)
         {
            if(cursor_normal[j] == '(' || cursor_normal[j] == ')')
               return RULE_MATCH;
         }

         // only check one User-Name attribute
         return RULE_NOMATCH;
      }

      cursor_normal = check;      
   }
int rule13773eval(void *p) {
    const u_int8_t *cursor_normal = 0;
    SFSnortPacket *sp = (SFSnortPacket *) p;

    /*const u_int8_t *end_of_payload; */

    int retval;
    u_int32_t snmp_ver;
    u_int32_t size_len, size;
    BER_ELEMENT element;

    DEBUG_WRAP(printf("rule13773eval: (linux netfilter snmp nat) begin\n"));

    if(sp == NULL)
        return RULE_NOMATCH;

    if(sp->payload == NULL)
        return RULE_NOMATCH;

    // flow:to_server; XXX bleh flow with UDP
//   if(checkFlow(p, rule13773options[0]->option_u.flowFlags) <= 0 )
//      return RULE_NOMATCH;

    // content:"0", depth 1;
    if(contentMatch(p, rule13773options[1]->option_u.content, &cursor_normal) <= 0)
        return RULE_NOMATCH;

    // Custom detection -- step through the structure to find the SNMP Trap and any anomalies
    // The content match puts us just past the universal sequence; we'll start from there --

    DEBUG_WRAP(printf("rule13773eval: start custom detection\n"));

    // Jump over the size of the message
    retval = ber_get_size(p, cursor_normal, &size_len, &size);

    if(retval < 0)
        return(RULE_NOMATCH);

    cursor_normal += size_len;

    DEBUG_WRAP(printf("rule13773eval: checking SNMP version\n"));

    // SNMP version. Because we're going to check the version, we need to make sure
    // the full data is present
    retval = ber_get_element(p, cursor_normal, &element);

    if((retval < 0) || (element.type != 0x02) || (retval != element.data_len))
        return RULE_NOMATCH;

    // Get the value of the SNMP version
    retval = ber_extract_int_val(&element);
    if(retval < 0)
        return RULE_NOMATCH;

    snmp_ver = element.data.int_val;
    DEBUG_WRAP(printf("rule13773eval: snmp_ver=%d\n", snmp_ver));

    cursor_normal += element.total_len;

    DEBUG_WRAP(printf("rule13773eval: checking community string\n"));

    // Community string
    retval = ber_get_element(p, cursor_normal, &element);

    if((retval < 0) || (element.type != 0x04))
        return RULE_NOMATCH;

    cursor_normal += element.total_len;

    DEBUG_WRAP(printf("rule13773eval: processing trap-pdu, snmp_ver=%d\n", snmp_ver));

    // Here's where the trap information is located
    if(snmp_ver <= 1) {  // PROTOS only does SNMPv1, but some other samples are using SNMPv2
        retval = ber_get_element(p, cursor_normal, &element);

        if(retval < 0) {
            DEBUG_WRAP(printf("rule13773eval: failed to read element\n"));
            return RULE_NOMATCH;
        }

        DEBUG_WRAP(printf("rule13773eval: element.type=%#x (want 0xA4)\n", element.type));
        cursor_normal = element.data.data_ptr;

        // Apparently, you can use V1 traps with SNMPv2.
        if(element.type == 0xA4) {
            if(process_v1_trap(sp, cursor_normal, element.data_len) > 0)
                return RULE_MATCH;
//      } else if(element.type == 0xA7) { // Schema for V2 trap in bug 42464 / RFC1905 if needed
//         if(process_v2_trap(sp, cursor_normal, element.data_len) > 0)
//            return RULE_MATCH;
        } else {
            return RULE_NOMATCH;
        }
    }

    return RULE_NOMATCH;
}
/* detection functions */
int rule13666eval(void *p) {
    const uint8_t *cursor_normal = 0, *cursor_offBmi;
    SFSnortPacket *sp = (SFSnortPacket *) p;

    const uint8_t *record_size_ptr, *beg_of_payload, *end_of_payload;

    uint32_t recordType, offBmi, bcSize;
    uint16_t bcWidth,bcHeight,bcPlanes,bcBitCount;
    uint64_t Value;  // For storing exploit calculations

    if(sp == NULL)
        return RULE_NOMATCH;

    if(sp->payload == NULL)
        return RULE_NOMATCH;
    
    // flow:established, to_client;
    if (checkFlow(p, rule13666options[0]->option_u.flowFlags) <= 0 )
        return RULE_NOMATCH;
    
    // flowbits:isset "file.emf";
    if (processFlowbits(p, rule13666options[1]->option_u.flowBit) <= 0)
        return RULE_NOMATCH;
    
    // content:" EMF|00 00 01 00|";
    if (contentMatch(p, rule13666options[2]->option_u.content, &cursor_normal) > 0) {
        // content:"|01 00 00 00|", offset -48, depth 4, relative;
        if (contentMatch(p, rule13666options[3]->option_u.content, &cursor_normal) > 0) {
            // byte_jump:size 4, relative, endian little;
            if (byteJump(p, rule13666options[4]->option_u.byte, &cursor_normal) > 0) {
                
                if(getBuffer(sp, CONTENT_BUF_NORMALIZED, &beg_of_payload, &end_of_payload) <= 0)
                    return RULE_NOMATCH;

                // Now we're at the start of records.  Find the interesting ones.
                while(cursor_normal < end_of_payload) {
                     
                    // We point to record size so we're at the right state for the relative jump
                    // if it turns out the record doesn't have a BITMAPCOREHEADER. 
                    record_size_ptr = cursor_normal - 4;                    

                    // content:"|5E 00 00 00|", offset -8, depth 4, relative;  XXX /* EMR_CREATEDIBPATTERNBRUSHPT */
                    if (contentMatch(p, rule13666options[5]->option_u.content, &cursor_normal) > 0
                        // content:"|51 00 00 00|", offset -8, depth 4, relative; XXX /* EMR_STRETCHDIBITS */
                        || (contentMatch(p, rule13666options[6]->option_u.content, &cursor_normal) > 0))
                    {
                        recordType = *(cursor_normal - 4);
                        switch(recordType)
                        {
                            case EMR_CREATEDIBPATTERNBRUSHPT:
                                DEBUG_SO(printf("matched EMR_CREATEDIBPATTERNBRUSHPT\n");)
                                    
                                if (cursor_normal + 28 > end_of_payload) // Make sure there's enough room
                                    return RULE_NOMATCH;

                                // extract offset to BITMAPCOREHEADER.  can't use byte_jump because it could put us
                                // past end of packet since the "jump" actually starts from an earlier offset
                                cursor_offBmi = cursor_normal + 12;
                                offBmi = read_little_32(cursor_offBmi);
                                break;
                                    
                            case EMR_STRETCHDIBITS: 
                                DEBUG_SO(printf("matched EMR_STRETCHDIBITS\n");)

                                if (cursor_normal + 60 > end_of_payload) 
                                    return RULE_NOMATCH;
                        
                                // read offBmiSrc field 
                                cursor_offBmi = cursor_normal + 44;
                                offBmi = read_little_32(cursor_offBmi);
                                break;
                                
                            default:
                                DEBUG_SO(printf("This case must not happen\n");)
                                return RULE_NOMATCH;                                    
                        }
                                    
                        if (offBmi + cursor_normal - 4 < cursor_normal)  // check integer overflow
                            return RULE_NOMATCH;

                        // move cursor to the beginning of a device independent bitmap (DIB)
                        DEBUG_SO(printf("offBmi=0x%08x\n", offBmi);)  
                        cursor_normal += offBmi - 4; 
                                  
                        if(cursor_normal + 12 > end_of_payload)
                           return RULE_NOMATCH;
                                  
                        // match size of BITMAPCOREHEADER to determine if it's the proper structure
                        bcSize = read_little_32(cursor_normal);
                        cursor_normal += 4;
                        DEBUG_SO(printf("bcSize=0x%08x\n", bcSize);)
        
                        if (bcSize == 12) // checks BITMAPCOREHEADER
// #if 0 // Don't compile the detection functions if they're not used
int rule24666eval(void *p) {
   const u_int8_t *cursor_normal = 0;
   const u_int8_t *beg_of_payload = 0;
   const u_int8_t *end_of_payload = 0;
   const u_int8_t *cursor_detect = 0;
   const u_int8_t *cursor_tmp = 0;

   u_int16_t cref = 0; // number of 8 byte refs
   u_int16_t rgbNameL = 0; // length of rgbName field
   u_int16_t cFieldData = 0; // number of Feat11FieldDataItems
   u_int16_t entryIDL = 0; // length of entryID field
   u_int16_t strFieldNameL = 0; // length of strFieldName
   u_int16_t strCaptionL = 0; // length of strCaption
   u_int32_t cbdxfHdrDiskL = 0; // length of cbdxfHdrDisk field
   u_int32_t cbFmtInsertRowL = 0; // length of cbFmtInsertRowL
   int i = 0; // iterator for for() loop
   SFSnortPacket *sp = (SFSnortPacket *) p;

   if(sp == NULL)
      return RULE_NOMATCH;

   if(sp->payload == NULL)
      return RULE_NOMATCH;

   // flow:established, to_client;
   if (checkFlow(p, rule24666options[0]->option_u.flowFlags) <= 0 )
   return RULE_NOMATCH;

   // flowbits:isset "file.xls";
   if (processFlowbits(p, rule24666options[1]->option_u.flowBit) <= 0)
   return RULE_NOMATCH;

   if(getBuffer(sp, CONTENT_BUF_NORMALIZED, &beg_of_payload, &end_of_payload) <= 0)
   return RULE_NOMATCH;

   cursor_normal = beg_of_payload;

   // content:"x|08|", depth 0; // this is 0x7808, header for feature12
   while(contentMatch(p, rule24666options[2]->option_u.content, &cursor_normal) > 0) {
   
      cursor_detect = cursor_normal;
   
      // jump to "x|08|" offset 2, depth 2
      // there is a two byte length field and the 0x7808 header again
      cursor_detect += 2;
   
         // check if we can read two bytes
      if((cursor_detect + 2) > end_of_payload)
         return RULE_NOMATCH;
   
      // are those bytes 0x0878 (little endian)
      if((*cursor_detect != 0x78) || (*(cursor_detect+1) != 0x08))
         continue;
   
      // jump to reserved fields
      cursor_detect += 14;
   
      // Two fields labeled reserved1 and reserved2
      // total of 5 null bytes, plus 2 bytes for cref
      if((cursor_detect + 8) > end_of_payload)
         return RULE_NOMATCH;
   
      // make sure reserved fields are null
      // Normally we can't just typecase our cursor, but because we
      // are checking for NULL here, we can
      if(*((u_int32_t*)cursor_detect) != 0)
         continue;
   
      // jump to cref, after reserved fields
      cursor_detect += 5;
   
      // read the cref value, we checked for 7 bytes before reserved fields
      // so we don't need to check again here
      cref = READ_LITTLE_16(cursor_detect);
   
      // jump cref*8+8, this jumps over all the ref structures
      // must check for integer overflows
      cursor_tmp = cursor_detect + 16 + (cref * 8);
         
      if(cursor_tmp < cursor_detect)
            return RULE_NOMATCH;
   
      cursor_detect = cursor_tmp;
   
   
      // this jump puts us at the beginning of the rgbFeatData
      // make sure we can read crwHeader
      if((cursor_detect + 4) >= end_of_payload)
         return RULE_NOMATCH;
   
      // make sure crwHeader==0
      if(*((u_int32_t*)cursor_detect) != 0)
         continue;
   
      // jump to rgbName, it is an XLUnicodeString, the first 2-bytes = length
      cursor_detect += 56;
   
      // make sure we can read rgbNameL
      if((cursor_detect + 2) > end_of_payload)
         return RULE_NOMATCH;
   
      // store rgbNameL
      rgbNameL = READ_LITTLE_16(cursor_detect);
   
      // jump over rgbName
      cursor_detect += rgbNameL + 3;
   
      // make sure we can read cFieldData and entryID
      if((cursor_detect + 4) > end_of_payload)
         return RULE_NOMATCH;
   
      // store cFieldData
      cFieldData = READ_LITTLE_16(cursor_detect);
   
      // jump over cFieldData
      cursor_detect += 2;
   
      // read entryIDL
      entryIDL = READ_LITTLE_16(cursor_detect);
   
      // jump over entryID
      cursor_detect += 3 + entryIDL;
      
      // max 10 iterations through Feat11FieldDataItem structures
      if(cFieldData > 10) cFieldData = 10;
      
      // loop through the Feat11FieldDataItem fields
      for(i = 0; i < cFieldData; i++) {
   
         // jump to cbFmtInsertRowL
         cursor_detect += 28;
   
         // make sure we can read length of cbFmtInsertRowL and strFieldNameL
         if((cursor_detect + 16) > end_of_payload)
            return RULE_NOMATCH;
   
         // read the cbFmtInsertRowL
         cbFmtInsertRowL =  READ_LITTLE_32(cursor_detect);
   
         // jump to strFieldName
         cursor_detect += 8;
   
         // read stFieldNameL
         strFieldNameL = READ_LITTLE_32(cursor_detect);
   
         // jump over strFieldName, with overflow check
         cursor_tmp = cursor_detect + strFieldNameL + 3;
   
         if(cursor_tmp < cursor_detect)
            return RULE_NOMATCH;
   
         cursor_detect = cursor_tmp;
   
         // make sure we can read strCaptionL
         if((cursor_detect + 2) > end_of_payload)
            return RULE_NOMATCH;
   
         // read strCaptionL
         strCaptionL = READ_LITTLE_16(cursor_detect);
   
         // jump over strCaptionL and dxFmtInsertRow
         cursor_tmp = cursor_detect + strCaptionL + cbFmtInsertRowL + 3;
   
         if(cursor_tmp < cursor_detect) 
            return RULE_NOMATCH;
   
         cursor_detect = cursor_tmp;
   
         // make sure we can read cbdxfHdrDiskL
         if((cursor_detect + 4) >  end_of_payload)
            return RULE_NOMATCH;
   
         // read the cbdxfHdrDiskL
         cbdxfHdrDiskL = READ_LITTLE_32(cursor_detect);
   
         //DEBUG_SO(fprintf(stderr, "cbdxfHdrDiskL: %d\n", cbdxfHdrDiskL);)
         if(cbdxfHdrDiskL > 0x2020)
            return RULE_MATCH; // cbdxfHdrDiskL > 0x2020 is the vulnerable condition
   
         // if cbdxfHdrDiskL is <= 0x2020 than it's the length
         // used for the last field and we jump
         cursor_tmp = cursor_detect + cbdxfHdrDiskL + 4;
         if(cursor_tmp < cursor_detect)
            return RULE_NOMATCH;
   
         cursor_detect = cursor_tmp;
      }
      
      return RULE_NOMATCH;
   }
   return RULE_NOMATCH;
}
/* detection functions */
int rule16394eval(void *p) {
   const uint8_t *cursor_normal = 0;
   SFSnortPacket *sp = (SFSnortPacket *) p;

   const uint8_t *cursor_padata;

   BER_ELEMENT ber_element;
   int retval;

   uint32_t renew_realm_len;
   const uint8_t *renew_realm_str;

   uint32_t ticket_realm_len;
   const uint8_t *ticket_realm_str;

   DEBUG_SO(int i);

   DEBUG_SO(printf("rule16394eval enter\n"));

   if(sp == NULL)
      return RULE_NOMATCH;

   if(sp->payload == NULL)
      return RULE_NOMATCH;
   
   // flow:established, to_server;
   if(checkFlow(p, rule16394options[0]->option_u.flowFlags) <= 0)
      return RULE_NOMATCH;

   // For speed and for ease of programming, we take advantage of some content matches
   // here in some places at the expense of false negatives.
   // But they do also to give us a nice content match.

   // This content match skips over a few items then matches on Kerberos protocol
   // version (pvno) 5 and mesg type TGS-REQ (12)
   // content:"|A1 03 02 01 05 A2 03 02 01 0C|", payload raw, depth 22, fast_pattern;
   if(contentMatch(p, rule16394options[1]->option_u.content, &cursor_normal) <= 0)
      return RULE_NOMATCH;

   // Save the pointer so we can come back here, and we're going to jump ahead to make
   // sure this is a renew packet as well as store the pointer to and size of the
   // renewal realm
   cursor_padata = cursor_normal;

   BER_SKIP(0xa3); // This is a wrapper to ber_skip_element() that NOMATCH's on failure

   // We should now be at the start of the KDC_REQ_BODY

   BER_DATA(0xa4); // This is a wrapper to ber_point_to_data() that NOMATCH's on failure
   BER_DATA(0x30); 

   // We're going to cheat again here and do a quick content match.
   // Plus, this is our fast pattern match.
   // content:"|A0 07 03 05 00 00 00 00 02|", payload raw, depth 9, relative, fast_pattern;
   if(contentMatch(p, rule16394options[2]->option_u.content, &cursor_normal) <= 0)
      return RULE_NOMATCH;

   BER_DATA(0xa2);
 
   // Grab the piece of data we've been looking for
   retval = ber_get_element(sp, cursor_normal, &ber_element);

   // Type 0x1b is essentially a string.  Don't know why it's not type 0x04. 
   // Negative return value means error.  0 means 0 data bytes and therefore useless.
   // Also make sure there is the full amount of data present.
   if((retval <= 0) || (ber_element.type != 0x1b) || (retval < ber_element.data_len))
      return RULE_NOMATCH;

   renew_realm_len = ber_element.data_len;
   renew_realm_str = ber_element.data.data_ptr;

   DEBUG_SO(for(i=0; i<renew_realm_len; i++) printf("%c", renew_realm_str[i]); printf("\n"));

   // Now that we have our renew_realm info and we've verified the data is complete,
   // Let's go back to the beginning and get our ticket_realm information
   cursor_normal = cursor_padata;

   // This is a very long list.  Glad we made sure we were in a renewal packet and
   // had all of the data we need before we bother with this.  :)
   BER_DATA(0xa3);
   BER_DATA(0x30);
   BER_DATA(0x30); 
   BER_SKIP(0xa1);
   BER_DATA(0xa2);
   BER_DATA(0x04);
   BER_DATA(0x6e);
   BER_DATA(0x30);
   BER_SKIP(0xa0);
   BER_SKIP(0xa1);
   BER_SKIP(0xa2);
   BER_DATA(0xa3);
   BER_DATA(0x61);
   BER_DATA(0x30);
   BER_SKIP(0xa0);
   BER_DATA(0xa1);

   // Same code and checks as above for our ticket/home realm
   retval = ber_get_element(sp, cursor_normal, &ber_element);
   if((retval <= 0) || (ber_element.type != 0x1b) || (retval < ber_element.data_len))
      return RULE_NOMATCH;

   ticket_realm_len = ber_element.data_len;
   ticket_realm_str = ber_element.data.data_ptr;

   DEBUG_SO(for(i=0; i<ticket_realm_len; i++) printf("%c", ticket_realm_str[i]); printf("\n"));

   // Match if the realm names are different (either lens are diff or value is diff)
   if(ticket_realm_len != renew_realm_len || memcmp(ticket_realm_str, renew_realm_str, ticket_realm_len))
      return RULE_MATCH;

   return RULE_NOMATCH;
}
Ejemplo n.º 27
0
/* detection functions */
int rule15734eval(void *p) {
   const u_int8_t *cursor_raw = 0, *end_of_payload;
   SFSnortPacket *sp = (SFSnortPacket *) p;

   const u_int8_t *junkptr; // for getBuffer()

   u_int16_t num_updates;
   u_int16_t num_addtl_rrs;
   u_int16_t data_len;
   u_int16_t record_type;

   // cruft
   int i;

   if(sp == NULL)
      return RULE_NOMATCH;

   if(sp->payload == NULL)
      return RULE_NOMATCH;
    
   // flow:established, to_server;
//   if(checkFlow(p, rule15734options[0]->option_u.flowFlags) <= 0 )
//      return RULE_NOMATCH;

   // content:"|28 00 00 01 00 01|", offset 2, depth 6, fast_pattern;
   if(contentMatch(p, rule15734options[1]->option_u.content, &cursor_raw) <= 0)
      return RULE_NOMATCH;

   DEBUG_WRAP(printf("passed content\n"));

   if(getBuffer(p, CONTENT_BUF_NORMALIZED, &junkptr, &end_of_payload) <= 0)
      return RULE_NOMATCH;

   if(cursor_raw + 25 >= end_of_payload)
      return RULE_NOMATCH;

   num_updates = *cursor_raw++ << 8;
   num_updates |= *cursor_raw++;

   DEBUG_WRAP(printf("num_updates=%d\n", num_updates));

   if(num_updates == 0)
      return RULE_NOMATCH;

   num_addtl_rrs = *cursor_raw++ << 8;
   num_addtl_rrs |= *cursor_raw++;

   DEBUG_WRAP(printf("num_addtl_rrs=%d\n", num_addtl_rrs));

   // Zone section (we force this to be one entry by content match)
   if(dns_skip_name(&cursor_raw, end_of_payload) <= 0)
      return RULE_NOMATCH;

   if(cursor_raw + 18 >= end_of_payload)
      return RULE_NOMATCH;

   DEBUG_WRAP(printf("SOA: 0x%02x%02x Class: 0x%02x%02x\n", cursor_raw[0], cursor_raw[1],cursor_raw[2],cursor_raw[3]));

   // Verify Type: SOA and Class: IN
   if(memcmp(cursor_raw, "\x00\x06\x00\x01", 4))
      return RULE_NOMATCH;

   cursor_raw += 4;

   // Prerequisites section (we force this to be one entry by content match)
   if(dns_skip_name(&cursor_raw, end_of_payload) <= 0)
      return RULE_NOMATCH;

   if(cursor_raw + 14 >= end_of_payload)
      return RULE_NOMATCH;

   // FP reduction.  Microsoft clients do ANY-ANY
   // Better solution is to make sure EXTERNAL_NET is set correctly
   // Verify Type: ANY Class: IN
   if(memcmp(cursor_raw, "\x00\xff\x00\x01", 4))
      return RULE_NOMATCH;

   cursor_raw += 8; // Skip over class and type and Skip TTL

   data_len = *cursor_raw++ << 8;
   data_len |= *cursor_raw++;     
   cursor_raw += data_len;   

   // Updates (YAY!!)
   DEBUG_WRAP(printf("Checking updates\n"));
   for(i = 0; i < num_updates; i++) {
      DEBUG_WRAP(printf("Checking update %d...", i));

      if(dns_skip_name(&cursor_raw, end_of_payload) <= 0)
         return RULE_NOMATCH;

      if(cursor_raw + 2 >= end_of_payload)
         return RULE_NOMATCH;
   
      record_type = *cursor_raw++ << 8;
      record_type |= *cursor_raw++;

      DEBUG_WRAP(printf("record_type 0x%04x\n", record_type));  
      // Alert if we see an update of type ANY (0x00FF) 
      if(record_type == 0x00FF)
         return RULE_MATCH;

      if(cursor_raw + 8 >= end_of_payload)
         return RULE_NOMATCH;

      cursor_raw += 6;

      data_len = *cursor_raw++ << 8;
      data_len |= *cursor_raw++;   
      cursor_raw += data_len;
   }

   // Currently, we don't care about the Additional RRs section, but if it turns
   // out we get false positives, we can add the requirement that there be no
   // TSIG (0x00fa) records aka unauthenticated update requests

   return RULE_NOMATCH;
}
Ejemplo n.º 28
0
int ruleIMAIL_LDAPeval(void *p) {
   u_int32_t current_byte = 0;
   u_int32_t width, value, lengthwidth;
   int retval;

   u_int32_t payload_len;

   const u_int8_t *cursor_normal, *beg_of_payload, *end_of_payload;

   SFSnortPacket *sp = (SFSnortPacket *) p;

   if(sp == NULL)
      return RULE_NOMATCH;

   if(sp->payload == NULL)
      return RULE_NOMATCH;

   /* call flow match */
   if (checkFlow(sp, ruleIMAIL_LDAPoptions[0]->option_u.flowFlags) <= 0 )
      return RULE_NOMATCH;

   /* call content match */
   if (contentMatch(sp, ruleIMAIL_LDAPoptions[1]->option_u.content, &cursor_normal) <= 0) {
      return RULE_NOMATCH;
   }

   if(getBuffer(sp, CONTENT_BUF_NORMALIZED, &beg_of_payload, &end_of_payload) <= 0)
      return RULE_NOMATCH;

   payload_len = end_of_payload - beg_of_payload;

   if(payload_len < 10)   /* Minimum bind request length */
      return RULE_NOMATCH;

   /* our contentMatch already assures us the first byte is \x30, so just jump over it */
   current_byte++;

   /* Begin packet structure processing */
   /* Packet length (only care about width of the specifier) */
   if(beg_of_payload[current_byte] & 0x80) {
      current_byte += beg_of_payload[current_byte] & 0x0F;  /* Does imail do this properly? */
   }
   current_byte++;

   /* Message number (only care about width of the specifier) */
   if(payload_len < current_byte + 8) 
      return RULE_NOMATCH;

   if(beg_of_payload[current_byte] != 0x02) /* Int data type */
      return RULE_NOMATCH;
   current_byte++;

   /* int width specifier */
   if(beg_of_payload[current_byte] & 0x80) {
      width = beg_of_payload[current_byte] & 0x0F;
      current_byte++;

      if(payload_len < current_byte + width) 
         return RULE_NOMATCH;

      retval = process_val(&(beg_of_payload[current_byte]), width, &value);
      if(retval < 0) 
         return RULE_NOMATCH;  /* width is either 0 or > 4 */
      current_byte += width;   /* width of data width specifier */
      current_byte += value;   /* width of data itself */
   }  else {
      current_byte += beg_of_payload[current_byte] + 1;
   }

   /* Bind request */
   if(payload_len < current_byte + 5) 
      return RULE_NOMATCH;

   if(beg_of_payload[current_byte] != 0x60) 
      return RULE_NOMATCH;

   current_byte++;

   /* Message length  (only care about width of the specifier) */
   if(beg_of_payload[current_byte] & 0x80) {
      current_byte += beg_of_payload[current_byte] & 0x0F; 
   }
   current_byte++;

   /* ldap version */
   if(payload_len < current_byte + 3) 
      return RULE_NOMATCH;

   /* ldap version */
   if(beg_of_payload[current_byte] != 0x02) /* Int data type */
      return RULE_NOMATCH;
   current_byte++;

   /* Now check for funkiness with the version field */
   /* Get width of version number */
   if(beg_of_payload[current_byte] & 0x80) {

      /* Excess bits in the high nibble */
      if(beg_of_payload[current_byte] & 0x70)
         return RULE_MATCH;

      lengthwidth = beg_of_payload[current_byte] & 0x0F;
      current_byte++;
  
      if(payload_len < current_byte + lengthwidth) 
         return RULE_NOMATCH;

      retval = process_val(&(beg_of_payload[current_byte]), lengthwidth, &value);
      if(retval < 0)
          return RULE_MATCH; /* Something screwy's going on around here */
      width = value;
      current_byte += lengthwidth;
   }  else {
      width = beg_of_payload[current_byte];
      current_byte++;
   }

   if(payload_len < current_byte + width)
      return RULE_NOMATCH;

   /* In this case, if the version value is this fubar, trigger */
   retval = process_val(&(beg_of_payload[current_byte]), width, &value);
   if(retval < 0)
         return RULE_MATCH;

   /* LDAP version > 9 (currently, should be 1-3) */
   if(value > 9)
      return RULE_MATCH;

   return RULE_NOMATCH;
}
static int rule13921eval(void *p) {
   SFSnortPacket *sp = (SFSnortPacket *)p;

   const u_int8_t *cursor, *beg_of_payload, *end_of_payload;

   int16_t lm_x;  

   int n;  /* cruft */

   /* Data for holding our base64 data */
   u_int8_t decoded_data[16];
   u_int32_t num_bytes_extracted;


   /* General sanity checking */
  if(sp == NULL)
      return RULE_NOMATCH;

   if(sp->payload == NULL)
      return RULE_NOMATCH;

   if(getBuffer(sp, CONTENT_BUF_NORMALIZED, &beg_of_payload, &end_of_payload) <= 0)
      return RULE_NOMATCH;

   if((end_of_payload - beg_of_payload) < 32)
      return RULE_NOMATCH;

   /* call flow match */
   if (checkFlow(sp, rule13921options[0]->option_u.flowFlags) <= 0 )
      return RULE_NOMATCH;

   /* call first content match */
   if (contentMatch(sp, rule13921options[1]->option_u.content, &cursor) <= 0) {
      return RULE_NOMATCH;
   }

   /* call second content match */
   if (contentMatch(sp, rule13921options[2]->option_u.content, &cursor) <= 0) {
      return RULE_NOMATCH;
   }

   /* Decode the part containing "/P.\x03/" to ensure the proper header and message type */
   n = base64decode(&(beg_of_payload[8]), 4, decoded_data, sizeof(decoded_data), &num_bytes_extracted);

   if((n < 0) || (num_bytes_extracted < 3))
      return RULE_NOMATCH;

   /* verify contents */
   if((decoded_data[0] != 'P') || (decoded_data[2] != 0x03))
      return RULE_NOMATCH;

   /* Now decode the part containing LM_X */
   n = base64decode(&(beg_of_payload[24]), 8, decoded_data, sizeof(decoded_data), &num_bytes_extracted);

   if((n < 0) || (num_bytes_extracted < 6))
      return RULE_NOMATCH;

   /* Extract LM_X, a signed 16-bit entity in little-endian format */
   lm_x = decoded_data[2];
   lm_x += decoded_data[3] << 8; 

   if((lm_x < 0) || (lm_x > 56))
      return RULE_MATCH;

   return RULE_NOMATCH;
}
/* detection functions */
int rule17700eval(void *p) {
    const u_int8_t *cursor_normal = 0, *beg_of_payload, *end_of_payload;
    SFSnortPacket *sp = (SFSnortPacket *) p;

    const u_int8_t *cursor_detect;

    u_int32_t fourCC;
    u_int32_t listsize;
    u_int32_t chunksize;
    u_int32_t stringsize;

    if(sp == NULL)
        return RULE_NOMATCH;

    if(sp->payload == NULL)
        return RULE_NOMATCH;

    // flow:established, to_client;
    if (checkFlow(p, rule17700options[0]->option_u.flowFlags) > 0 ) {
        // flowbits:isset "wav_file.request";
        if (processFlowbits(p, rule17700options[1]->option_u.flowBit) > 0) {
            // content:"LIST", payload raw, depth 0, fast_pattern;
            if (contentMatch(p, rule17700options[2]->option_u.content, &cursor_normal) > 0) {
                // content:"INFO", payload raw, offset 4, depth 4, relative;
                if (contentMatch(p, rule17700options[3]->option_u.content, &cursor_normal) > 0) {
                    
                    if (getBuffer(sp, CONTENT_BUF_NORMALIZED, &beg_of_payload, &end_of_payload) <= 0)
                        return RULE_NOMATCH;

                    //Extract size of list chunk size
                    listsize = *(cursor_normal-8);
                    listsize |= *(cursor_normal-7) << 8;
                    listsize |= *(cursor_normal-6) << 16;
                    listsize |= *(cursor_normal-5) << 24;

                    //Make sure we have 8 bytes to extact 4CC and chunk size
                    while(cursor_normal + 8 < end_of_payload) {
                        //Extract chunk size
                        chunksize = *(cursor_normal+4);
                        chunksize |= *(cursor_normal+5) << 8;
                        chunksize |= *(cursor_normal+6) << 16;
                        chunksize |= *(cursor_normal+7) << 24;

                        //In a loop, check the 4CC tag to see if it's any of the vulnerable tags
                        fourCC = *cursor_normal << 24;
                        fourCC |= *(cursor_normal + 1) << 16;
                        fourCC |= *(cursor_normal + 2) << 8;
                        fourCC |= *(cursor_normal + 3);

                        if((fourCC == 0x49415254) || // IART
                           (fourCC == 0x494e414d) || // INAM
                           (fourCC == 0x49434f50)) { // ICOP

                            //If it is one of the vulnerable tags, jump to the subchunk data
                            //and treat it as a string. Count the actual size of the string
                            //in another loop.
                            stringsize = 0;
    
                            cursor_detect = cursor_normal + 8;
    
                            //Match if stringsize > either chunksize or listsize
                            //otherwise keep counting characters or break if we
                            //encounter a null character or end_of_payload
                            while(cursor_detect < end_of_payload) {
                               if(!*cursor_detect++)
                                  break;  // stop when we find a null
                            }

                            stringsize = cursor_detect - cursor_normal - 8;

                            //printf("stringsize=%d, chunksize=%d, listsize=%d\n");
                            if (stringsize > chunksize || stringsize > listsize)
                                return RULE_MATCH;
                        }
                        
                        //We need to do a check before skipping to the next chunk to make sure that
                        //addition won't cause an integer overflow on cursor_normal
                        if (cursor_normal + chunksize + 8 <= cursor_normal) // <= to also avoid infinite loops
                            return RULE_NOMATCH;

                        // Jump to the start of the next chunk
                        cursor_normal += chunksize + 8; // fourCC, 4 bytes size, chunk size
                    } 
                }
            }
        }
    }
    return RULE_NOMATCH;
}