// #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) {
/* 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 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
/* 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 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; }
// #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 rule16343eval(void *p) { const u_int8_t *cursor_normal = 0; const u_int8_t *end_of_payload = 0; int ascii_flag; int hex_flag; unsigned long escape_char; char escape_buf[3]; SFSnortPacket *sp = (SFSnortPacket *) p; if(sp == NULL) return RULE_NOMATCH; if(sp->payload == NULL) return RULE_NOMATCH; // flow:established, to_client; if (checkFlow(p, rule16343options[0]->option_u.flowFlags) > 0 ) { // flowbits:isset "http.pdf"; || content:"|25|PDF-"; if ( processFlowbits(p, rule16343options[1]->option_u.flowBit) > 0 || contentMatch(p, rule16343options[5]->option_u.content, &cursor_normal) > 0) { // If we're in a Partial Content packet, get out to avoid false positives. // There are some really stupid packets / multiparts out there and I can't // think of a good way to avoid false negatives while avoiding the false // positives, so may as well go for broke. // content:"HTTP/1.1 206", depth 12, offset 0; if(contentMatch(p, rule16343options[4]->option_u.content, &cursor_normal) > 0) return RULE_NOMATCH; if(getBuffer(sp, CONTENT_BUF_NORMALIZED, &cursor_normal, &end_of_payload) <= 0) return RULE_NOMATCH; escape_buf[2] = 0x00; // No need to set this every time as long as it's preset // content:"obj", depth 0, nocase, fast_pattern; while (contentMatch(p, rule16343options[2]->option_u.content, &cursor_normal) > 0) { if (contentMatch(p, rule16343options[3]->option_u.content, &cursor_normal) <= 0) { continue; } hex_flag = 0; ascii_flag = 0; while (cursor_normal < end_of_payload) { // Check for end of object header. If found, search for new "obj<<" tag if ((*cursor_normal == '>') && ((cursor_normal + 1 < end_of_payload) && (*(cursor_normal + 1) == '>'))) { break; } if (*cursor_normal == '#') { cursor_normal++; // Skip the # // Make sure we've got the bytes to read if ((cursor_normal + 2 > end_of_payload)) { return RULE_NOMATCH; } escape_buf[0] = *cursor_normal++; escape_buf[1] = *cursor_normal; // The pointer increment is below //escape_buf[2] = 0x00; No need to set this every time as long as it's preset escape_char = strtoul(escape_buf, NULL, 16); // We only care if the resultant value is alphanumeric if(!isalnum(escape_char)) continue; if (ascii_flag == 1) return RULE_MATCH; hex_flag = 1; } else if (*cursor_normal == '(') { // binary data in object tag cursor_normal++; // Run through to the end of the binary data while(cursor_normal < end_of_payload) { // If we come across a close parens, see if it's escaped. // If not, we're at the end of the binary data. if(*cursor_normal != ')') cursor_normal++; else if(*(cursor_normal - 1) == '\\') cursor_normal++; else break; } // We'll step over the ')' at the end of the while() loop } else { if (isalnum(*cursor_normal)) { if (hex_flag == 1) return RULE_MATCH; ascii_flag = 1; } // Fall through advances the pointer } cursor_normal++; // Ensure we will always advance the pointer } } } } return RULE_NOMATCH; }
/* detection functions */ int rule16370eval(void *p) { const uint8_t *cursor_normal = 0; SFSnortPacket *sp = (SFSnortPacket *) p; const uint8_t *beg_of_payload, *end_of_payload; uint16_t Csiz; uint16_t atomlen; uint16_t Crgn; if(sp == NULL) return RULE_NOMATCH; if(sp->payload == NULL) return RULE_NOMATCH; // flow:established, to_client; if (checkFlow(p, rule16370options[0]->option_u.flowFlags) > 0 ) { // flowbits:isset "file.pdf"; if (processFlowbits(p, rule16370options[1]->option_u.flowBit) > 0) { // content:"jP ", depth 0, fast_pattern; if (contentMatch(p, rule16370options[2]->option_u.content, &cursor_normal) > 0) { // content:"|FF|O|FF|Q", depth 0; if (contentMatch(p, rule16370options[3]->option_u.content, &cursor_normal) > 0) { if(getBuffer(sp, CONTENT_BUF_NORMALIZED, &beg_of_payload, &end_of_payload) <= 0) return RULE_NOMATCH; //Make sure at least the entire atom is present, as well as //the atom signature and length of the following atom if(cursor_normal + 47 + 4 > end_of_payload) return RULE_NOMATCH; // Now make sure this atomlen is 47 if(*cursor_normal != 0 || *(cursor_normal + 1) != 47) return RULE_NOMATCH; //Extract the value of Csiz Csiz = read_big_16(cursor_normal + 36); //Jump to the next atom, just before the signature cursor_normal += 47; //atomlen; //Check to see if the following byte is FF (eg:the first byte of a signature) //and that we haven't ended up in no man's land while((cursor_normal + 4 < end_of_payload) && (*cursor_normal == 255)) { //Extract the length of next atom atomlen = read_big_16(cursor_normal+2); //Make sure the whole atom is present. Atom length is atomlen + file signature (2 bytes) if ((cursor_normal + atomlen + 2) > end_of_payload) return RULE_NOMATCH; //Check second byte of atom signature //A FF5E is the Region-of-interest atom if (*(cursor_normal+1) == '\x5e') { //This atom can only be either 5 or 6 bytes long, but no other value. //Crgn will be either 1 or 2 bytes depending on this length. //Exit if you some unexpected value. if (atomlen == 5) Crgn = *(cursor_normal+4); else if (atomlen == 6) { Crgn = read_big_16(cursor_normal+4); } else return RULE_NOMATCH; //Fire if Crgn >= Csiz if (Crgn >= Csiz) return RULE_MATCH; } //Skip to next atom cursor_normal += atomlen + 2; } } } } } return RULE_NOMATCH; }
/* * ruleMatch * * p: packet data structure, same as the one found in snort. * options: NULL terminated list of rule options * * Returns: * > 0 : match found * = 0 : no match found * * Predefined constants: * (see sf_snort_plugin_api.h for more values) * RULE_MATCH - if asn1 specifier is found within buffer * RULE_NOMATCH - if asn1 specifier is not found within buffer * */ int ruleMatchInternal(SFSnortPacket *p, Rule* rule, u_int32_t optIndex, u_int8_t **cursor) { u_int8_t *thisCursor = NULL, *startCursor = NULL; u_int8_t *tmpCursor = NULL; int retVal = RULE_NOMATCH; u_int32_t notFlag = 0; int thisType; ContentInfo *thisContentInfo = NULL; int startAdjust = 0; u_int32_t origFlags = 0; int32_t origOffset = 0; u_int32_t origDepth = 0; int continueLoop = 1; PCREInfo *thisPCREInfo = NULL; if (cursor) startCursor = thisCursor = *cursor; if (optIndex >= rule->numOptions || !rule->options[optIndex] ) return RULE_NOMATCH; thisType = rule->options[optIndex]->optionType; /* Do some saving off of some info for recursion purposes */ switch (thisType) { case OPTION_TYPE_CONTENT: thisContentInfo = rule->options[optIndex]->option_u.content; origFlags = thisContentInfo->flags; origDepth = thisContentInfo->depth; origOffset = thisContentInfo->offset; break; case OPTION_TYPE_PCRE: thisPCREInfo = rule->options[optIndex]->option_u.pcre; origFlags = thisPCREInfo->flags; break; default: /* Other checks should not need to check again like * PCRE & Content do. */ break; } do { switch (thisType) { case OPTION_TYPE_CONTENT: retVal = contentMatch(p, rule->options[optIndex]->option_u.content, &thisCursor); notFlag = rule->options[optIndex]->option_u.content->flags & NOT_FLAG; break; case OPTION_TYPE_PCRE: retVal = pcreMatch(p, rule->options[optIndex]->option_u.pcre, &thisCursor); notFlag = rule->options[optIndex]->option_u.pcre->flags & NOT_FLAG; break; case OPTION_TYPE_FLOWBIT: retVal = processFlowbits(p, rule->options[optIndex]->option_u.flowBit); notFlag = rule->options[optIndex]->option_u.flowBit->flags & NOT_FLAG; break; case OPTION_TYPE_BYTE_TEST: retVal = byteTest(p, rule->options[optIndex]->option_u.byte, thisCursor); notFlag = rule->options[optIndex]->option_u.byte->flags & NOT_FLAG; break; case OPTION_TYPE_BYTE_JUMP: retVal = byteJump(p, rule->options[optIndex]->option_u.byte, &thisCursor); notFlag = rule->options[optIndex]->option_u.byte->flags & NOT_FLAG; break; case OPTION_TYPE_FLOWFLAGS: retVal = checkFlow(p, rule->options[optIndex]->option_u.flowFlags); notFlag = rule->options[optIndex]->option_u.flowFlags->flags & NOT_FLAG; break; case OPTION_TYPE_ASN1: retVal = detectAsn1(p, rule->options[optIndex]->option_u.asn1, thisCursor); notFlag = rule->options[optIndex]->option_u.asn1->flags & NOT_FLAG; break; case OPTION_TYPE_CURSOR: retVal = checkCursor(p, rule->options[optIndex]->option_u.cursor, thisCursor); notFlag = rule->options[optIndex]->option_u.cursor->flags & NOT_FLAG; break; case OPTION_TYPE_SET_CURSOR: retVal = setCursor(p, rule->options[optIndex]->option_u.cursor, &thisCursor); notFlag = rule->options[optIndex]->option_u.cursor->flags & NOT_FLAG; break; case OPTION_TYPE_HDR_CHECK: retVal = checkHdrOpt(p, rule->options[optIndex]->option_u.hdrData); notFlag = rule->options[optIndex]->option_u.hdrData->flags & NOT_FLAG; break; case OPTION_TYPE_BYTE_EXTRACT: retVal = extractValue(p, rule->options[optIndex]->option_u.byteExtract, thisCursor); notFlag = rule->options[optIndex]->option_u.byteExtract->flags & NOT_FLAG; break; case OPTION_TYPE_LOOP: retVal = loopEval(p, rule->options[optIndex]->option_u.loop, &thisCursor); notFlag = rule->options[optIndex]->option_u.loop->flags & NOT_FLAG; break; case OPTION_TYPE_PREPROCESSOR: retVal = preprocOptionEval(p, rule->options[optIndex]->option_u.preprocOpt, &thisCursor); notFlag = rule->options[optIndex]->option_u.preprocOpt->flags & NOT_FLAG; break; } if ( notFlag ) { if ((retVal <= RULE_NOMATCH)) { /* Set this as a positive match -- a ! was specified. */ retVal = RULE_MATCH; } else /* Match */ { retVal = RULE_NOMATCH; } } if (retVal > RULE_NOMATCH) { /* This one matched. Depending on type, check the next one * either in a loop, or not, saving cursor temporarily. */ if (optIndex < rule->numOptions -1) /* hehe, optIndex is 0 based */ { int nestedRetVal; /* Here's where it gets tricky... */ if (thisType == OPTION_TYPE_CONTENT) { /* If this is a content option, we've found a match. * Save off the end-point of the current match. * Less the length of current match plus 1. * * This gives us the starting point to check for this * content again if subsequent options fail. That starting * point is the byte AFTER the beginning of the current * match. */ if ((origFlags & CONTENT_RELATIVE) && startCursor) { /* relative content. * need to adjust offset/depth as well */ tmpCursor = thisCursor - thisContentInfo->patternByteFormLength + thisContentInfo->incrementLength; /* Start Adjust is the difference between the old * starting point and the 'next' starting point. */ startAdjust = tmpCursor - startCursor; } else { /* non-relative content */ tmpCursor = thisCursor - thisContentInfo->patternByteFormLength + thisContentInfo->incrementLength; } } else if (thisType == OPTION_TYPE_PCRE) { /* Start next search at end of current pattern */ /* XXX: Could miss something here if part of pattern * repeats but not easy to tell with PCRE. */ tmpCursor = thisCursor; } nestedRetVal = ruleMatchInternal(p, rule, optIndex+1, &thisCursor); if (nestedRetVal == RULE_MATCH) { /* Cool, everyone after us matched, we're done with a match */ if (cursor) *cursor = thisCursor; break; } /* If Content or PCRE, look farther into the packet * for another match. */ if (((thisType == OPTION_TYPE_CONTENT) || (thisType == OPTION_TYPE_PCRE)) && !notFlag) { /* Only try to find this content again if it is a * positive match. */ /* And only if the next option is relative */ if (!isRelativeOption(rule->options[optIndex+1])) { /* Match failed, next option is not relative. * We're done. */ retVal = nestedRetVal; break; } switch (thisType) { case OPTION_TYPE_CONTENT: if (origFlags & CONTENT_RELATIVE) { if ((int32_t)(origDepth - startAdjust) < (int32_t)thisContentInfo->patternByteFormLength) { /* Adjusted depth would be less than the content we're searching for? * we're done. */ retVal = nestedRetVal; continueLoop = 0; } else { /* For contents that were already relative, adjust the offset & depth fields * from their original values. Makes it easy to determine when we'll be out * of the original bounds, relative to the original cursor. */ thisContentInfo->offset = origOffset + startAdjust; thisContentInfo->depth = origDepth - startAdjust; /* And use the original cursor that was passed in */ thisCursor = startCursor; } } else { thisContentInfo->flags |= CONTENT_RELATIVE; /* For contents that were not already relative, we simply use the adjusted * cursor. Set thisCursor to tmpCursor as calculated above */ thisCursor = tmpCursor; } break; case OPTION_TYPE_PCRE: /* Doesn't matter if it was already relative, * just make it relative anyway. */ thisPCREInfo->flags |= CONTENT_RELATIVE; /* For PCREs that were not already relative, we use the cursor * that was returned at the end of the pattern to start searching * again. */ thisCursor = tmpCursor; break; } continue; } /* Only need to search again when this is a * content option. If its not, we're done. */ if (nestedRetVal <= RULE_NOMATCH) { /* Handle the case when an error is propigated * via nestedRetVal. */ retVal = RULE_NOMATCH; } break; } else { /* Cool, nobody after us, we're done with a match */ if (cursor) *cursor = thisCursor; break; } } else { /* No match, get outta dodge */ break; } } while (continueLoop); /* Keep looping until we break or serialized content checks returns no match. */ /* Reset the flags for this content in case we added the * relative flag above. */ if (thisContentInfo) { thisContentInfo->flags = origFlags; thisContentInfo->offset = origOffset; thisContentInfo->depth = origDepth; } if (thisPCREInfo) { thisPCREInfo->flags = origFlags; } return retVal; }
/* detection functions */ int rule13969eval(void *p) { const uint8_t *cursor_normal = 0; SFSnortPacket *sp = (SFSnortPacket *) p; const uint8_t *end_of_payload, *beg_of_payload; uint8_t value=0, rec_instance; uint16_t word=0, pid, fcomplex; uint32_t op, rec_len; int i; if(sp == NULL) return RULE_NOMATCH; if(sp->payload == NULL) return RULE_NOMATCH; // flow:established, to_client; if (checkFlow(p, rule13969options[0]->option_u.flowFlags) > 0 ) { // flowbits:isset "file.ppt"; if (processFlowbits(p, rule13969options[1]->option_u.flowBit) > 0) { // content:"|0B F0|"; if(getBuffer(sp, CONTENT_BUF_NORMALIZED, &beg_of_payload, &end_of_payload) <= 0) return RULE_NOMATCH; cursor_normal = beg_of_payload; while (contentMatch(p, rule13969options[2]->option_u.content, &cursor_normal) > 0) { if((cursor_normal + 4 >= end_of_payload) || (cursor_normal - 2 < beg_of_payload)) return RULE_NOMATCH; rec_len = *cursor_normal++; rec_len |= (*cursor_normal++) << 8; rec_len |= (*cursor_normal++) << 16; rec_len |= (*cursor_normal++) << 24; if( (cursor_normal + rec_len - 4 >= end_of_payload) || (cursor_normal + rec_len < cursor_normal)) return RULE_NOMATCH; // MSO Drawing Property Table Property Table Record Instance // cursor_normal = cursor_normal -8; value = *(cursor_normal-8); DEBUG_WRAP(printf("WORD: %d\n", value)); rec_instance=(value>>4) & 0x0f; DEBUG_WRAP(printf("RECORD INSTANCE: %d\n", rec_instance)); // Loop through all FOPTE objects for(i=0; i < rec_instance; i++) { if(cursor_normal + 6 >= end_of_payload) return RULE_NOMATCH; word = *cursor_normal++; word |= *cursor_normal++ << 8; pid = word & 0x3fff; fcomplex = word & 0x8000; op = *cursor_normal++; op |= *cursor_normal++ << 8; op |= *cursor_normal++ << 16; op |= *cursor_normal++ << 24; DEBUG_WRAP(printf("PID: %d\n", pid)); DEBUG_WRAP(printf("FCOMPLEX: %d\n", fcomplex)); if ((fcomplex || pid==272) && (op >= 0xFFFFFFFC)) { return RULE_MATCH; } } } } } return RULE_NOMATCH; }