/* detection functions */ int rule17741eval(void *p) { const uint8_t *cursor_normal = 0, *end_of_payload; SFSnortPacket *sp = (SFSnortPacket *) p; BER_ELEMENT ber_element; BER_ELEMENT req_body; BER_ELEMENT req_body_SEQUENCE; int ret; DEBUG_SO(printf("rule17741eval enter\n")); if(sp == NULL) return RULE_NOMATCH; // flow:to_server; if(checkFlow(p, rule17741options[0]->option_u.flowFlags) <= 0 ) return RULE_NOMATCH; if (getBuffer(sp, CONTENT_BUF_NORMALIZED, &cursor_normal, &end_of_payload) <= 0) return RULE_NOMATCH; ret = ber_get_element(sp, cursor_normal, &ber_element); DEBUG_SO(printf("First element type 0x%02x\n", ber_element.type)); if(ret < 0 || ((ber_element.type != 0x6a) && (ber_element.type != 0x6c))) return RULE_NOMATCH; // We want to delve into this element cursor_normal = ber_element.data.data_ptr; BER_DATA(0x30); // SEQUENCE BER_SKIP(0xA1); // pvno [1] INTEGER (5) BER_SKIP(0xA2); // msg-type [2] INTEGER (10 -- AS -- | 12 -- TGS --) // if optional PA-DATA exists, skip it // 10 1 00011 (context-specific, structured, tag number 3) if (cursor_normal < end_of_payload && *cursor_normal == 0xA3) BER_SKIP(0xA3); // padata [3] SEQUENCE OF PA-DATA OPTIONAL // req-body [4] KDC-REQ-BODY // req-body is defined as SEQUENCE and if req-body's data size is not equal to // the total size of SEQUENCE, it is malicious ret = ber_get_element(sp, cursor_normal, &req_body); if (ret < 0) return RULE_NOMATCH; BER_DATA(0xA4); ret = ber_get_element(sp, cursor_normal, &req_body_SEQUENCE); if (ret < 0) return RULE_NOMATCH; DEBUG_SO(printf("req_body.data_len = 0x%08x, req_body_SEQUENCE.specified_total_len = 0x%08x\n", req_body.data_len, req_body_SEQUENCE.specified_total_len);) if (req_body.data_len != req_body_SEQUENCE.specified_total_len)
// #if 0 // Don't compile the detection functions if they're not used int rule18101eval(void *p) { const uint8_t *cursor_normal = 0; SFSnortPacket *sp = (SFSnortPacket *) p; const uint8_t *end_of_payload; BER_ELEMENT ber_element; if(sp == NULL) return RULE_NOMATCH; // flow:established, to_server; if(checkFlow(p, rule18101options[0]->option_u.flowFlags) <= 0 ) return RULE_NOMATCH; if(getBuffer(sp, CONTENT_BUF_NORMALIZED, &cursor_normal, &end_of_payload) <= 0) return RULE_NOMATCH; BER_DATA(0x30); BER_SKIP(0x02); if(ber_get_element(sp, cursor_normal, &ber_element) < 0) return RULE_NOMATCH; // Exploit condition is SearchRequest (0x63) or ModifyDNRequest (0x6c) with // large size. We're going with 1000 as a max size, apparently. if(ber_element.data_len > 1000 && (ber_element.type == 0x63 || ber_element.type == 0x6c)) return RULE_MATCH; 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; }
/* detection functions */ int rule27906eval(void *p) { const u_int8_t *cursor_normal = 0, *end_of_payload; SFSnortPacket *sp = (SFSnortPacket *) p; BER_ELEMENT kerberos_string; int i; if(sp == NULL) return RULE_NOMATCH; if(sp->payload == NULL) return RULE_NOMATCH; // flow:to_server; if(checkFlow(p, rule27906options[0]->option_u.flowFlags) <= 0) return RULE_NOMATCH; if(getBuffer(sp, CONTENT_BUF_NORMALIZED, &cursor_normal, &end_of_payload) <= 0) return RULE_NOMATCH; BER_DATA(0x6c); // KDC-REQ [12] BER_DATA(0x30); // SEQUENCE [16] BER_SKIP(0xA1); // pvno [1] BER_SKIP(0xA2); // msg-type [2] // if optional PA-DATA exists, skip it // 10 1 00011 (context-specific, structured, tag number 3) if(cursor_normal+1 > end_of_payload) return RULE_NOMATCH; if(*cursor_normal == 0xA3) BER_SKIP(0xA3); // KDC-REQ-BODY [4] ::= SEQUENCE [16] // kdc-options [0] // realm [2] server's realm // sname [3] PrincipalName BER_DATA(0xA4); // KDC-REQ-BODY BER_DATA(0x30); // SEQUENCE BER_SKIP(0xA0); // kdc-options BER_SKIP(0xA2); // realm // PrincipalName [3] ::= SEQUENCE [16] // name-type [0] Int32 // name-string [1] SEQUENCE [16] of KerberosString BER_DATA(0xA3); BER_DATA(0x30); BER_SKIP(0xA0); BER_DATA(0xA1); BER_DATA(0x30); // check up to 20 strings for the vulnerable condition for(i=0; (ber_get_element(sp, cursor_normal, &kerberos_string) >= 0) && (i < 20); i++) { // verify we are looking at a string element if(kerberos_string.type != 0x1b) return RULE_NOMATCH; DEBUG_SO(fprintf(stderr,"kerberos_string:\n data_len = 0x%02x\n",kerberos_string.data_len);) // vulnerable condition is kerberos_string.data_len == 0 if(kerberos_string.data_len == 0) return RULE_MATCH; // Move to the end of the current element. Guaranteed to move us forward in the packet. cursor_normal += kerberos_string.total_len; }
/* detection functions */ int rule36153eval(void *p) { const uint8_t *cursor_normal = 0, *end_of_buffer, *next_mod_item, *next_msg; SFSnortPacket *sp = (SFSnortPacket *) p; BER_ELEMENT msg, req, mod, attribute; int i,j, bytes_available, stop; unsigned int subtag_len; if(sp == NULL) return RULE_NOMATCH; if(sp->payload == NULL) return RULE_NOMATCH; // flow:established, to_server; if(checkFlow(p, rule36153options[0]->option_u.flowFlags) <= 0) return RULE_NOMATCH; if(getBuffer(sp, CONTENT_BUF_NORMALIZED, &cursor_normal, &end_of_buffer) <= 0) return RULE_NOMATCH; // LDAPMessage ::= SEQUENCE [16] if(ber_get_element(sp, cursor_normal, &msg) < 0) return RULE_NOMATCH; if(msg.type != 0x30) return RULE_NOMATCH; // calculate position of next msg next_msg = cursor_normal + msg.total_len; // integer overflow check if(next_msg < cursor_normal) return RULE_NOMATCH; // move cursor to messageID cursor_normal = msg.data.data_ptr; // messageID [2] BER_SKIP(0x02); // Request ::= APPLICATION [6] if(ber_get_element(sp, cursor_normal, &req) < 0) return RULE_NOMATCH; // move cursor to LDAPDN cursor_normal = req.data.data_ptr; if(req.type != 0x66) { // check second msg for modifyRequest cursor_normal = next_msg; BER_DATA(0x30); // LDAPMessage BER_SKIP(0x02); // messageID BER_DATA(0x66); // Request } BER_SKIP(0x04); // LDAPDN [4] BER_DATA(0x30); // modification items ::= SEQUENCE [16] // check up to 5 modification items for(i=0; i<5; i++, cursor_normal = next_mod_item) { // modification item ::= SEQUENCE [16] if(ber_get_element(sp, cursor_normal, &mod) < 0) return RULE_NOMATCH; if(mod.type != 0x30) return RULE_NOMATCH; DEBUG_SO(fprintf(stderr,"mod item [0x%04X]\n", mod.data_len);) // calculate position of next mod item next_mod_item = cursor_normal + mod.total_len; // integer overflow check if(next_mod_item < cursor_normal) return RULE_NOMATCH; // if modification item data_len < 256 skip if(mod.data_len < 256) continue; // move cursor to operation cursor_normal = mod.data.data_ptr; BER_SKIP(0x0A); // operation [10] BER_DATA(0x30); // modification ::= SEQUENCE [16] // attribute [4] bytes_available = ber_get_element(sp, cursor_normal, &attribute); if(bytes_available <= 0) return RULE_NOMATCH; if(attribute.type != 0x04) return RULE_NOMATCH; DEBUG_SO(fprintf(stderr," attribute [0x%04X]\n", attribute.data_len);) // if the attribute len is < 256 // it cannot possibly contain the vuln, skip if(attribute.data_len < 256)