/* detection functions */ int rule13308eval(void *p) { const u_int8_t *cursor_normal = 0; const u_int8_t *beg_of_buffer, *end_of_buffer; SFSnortPacket *sp = (SFSnortPacket *) p; // Base64 stuff u_int8_t base64buf[256], decodedbuf[256]; u_int32_t inputchars, base64bytes, decodedbytes; int i; if(sp == NULL) return RULE_NOMATCH; // flow:established, to_server; if (checkFlow(p, rule13308options[0]->option_u.flowFlags) <= 0) return RULE_NOMATCH; // Doing this content match is pretty useless because it's duplicated in our PCRE. // But we want to keep the structure for the pattern matcher. // // content:"Authorization|3A|", depth 0, nocase, fast_pattern; // if (contentMatch(p, rule13308options[1]->option_u.content, &cursor_normal) <= 0) // return RULE_NOMATCH; // pcre:"^Authorization\x3A\s*Basic[ \t]+", dotall, multiline, nocase; if (pcreMatch(p, rule13308options[2]->option_u.pcre, &cursor_normal) <= 0) return RULE_NOMATCH; if(getBuffer(sp, CONTENT_BUF_NORMALIZED, &beg_of_buffer, &end_of_buffer) != CURSOR_IN_BOUNDS) return RULE_NOMATCH; // At this point, cursor should point to the start of the auth data inputchars = (end_of_buffer > cursor_normal + sizeof(base64buf)) ? sizeof(base64buf) : end_of_buffer - cursor_normal; DEBUG_SO(printf("%d input chars: %*s\n", inputchars, inputchars, cursor_normal)); if(unfold_header(cursor_normal, inputchars, base64buf, sizeof(base64buf), &base64bytes) != 0) return RULE_NOMATCH; DEBUG_SO(printf("Successfully unfolded header (%s)(%d)\n", base64buf, base64bytes)); if(base64decode(base64buf, base64bytes, decodedbuf, sizeof(decodedbuf), &decodedbytes) < 0) return RULE_NOMATCH; DEBUG_SO(printf("Successfully base64 decoded (%s)(%d)\n", decodedbuf, decodedbytes)); for(i=0; i<decodedbytes; i++) { DEBUG_SO(printf("checking byte: %c\n", decodedbuf[i])); if(decodedbuf[i] == '%') { return RULE_MATCH; } else if(decodedbuf[i] == ':') { // Separator between username:password return RULE_NOMATCH; } } return RULE_NOMATCH; }
int encode_rfc2047(const char *name, char **value, int encoding, const char *charset) { int i, asciicount = 0, eightbitcount = 0, qpspecialcount = 0; char *p; /* * First, check to see if we even need to encode the header */ for (p = *value; *p != '\0'; p++) { if (isascii((unsigned char) *p)) { asciicount++; if (qpspecial((unsigned char) *p)) qpspecialcount++; } else eightbitcount++; } if (eightbitcount == 0) return 0; /* * Some rules from RFC 2047: * * - Encoded words cannot be more than 75 characters long * - Multiple "long" encoded words must be on new lines. * * Also, we're not permitted to encode email addresses, so * we need to actually _parse_ email addresses and only encode * the right bits. */ /* * If charset was NULL, then get the value from the locale. But * we reject it if it returns US-ASCII */ if (charset == NULL) charset = write_charset_8bit(); if (strcasecmp(charset, "US-ASCII") == 0) { advise(NULL, "Cannot use US-ASCII with 8 bit characters in header"); return 1; } /* * If we have an address header, then we need to parse the addresses * and only encode the names or comments. Otherwise, handle it normally. */ for (i = 0; address_headers[i]; i++) { if (strcasecmp(name, address_headers[i]) == 0) return field_encode_address(name, value, encoding, charset); } /* * On the encoding we choose, and the specifics of encoding: * * - If a specified encoding is passed in, we use that. * - Otherwise, pick which encoding is shorter. * * We don't quite handle continuation right here, but it should be * pretty close. */ if (encoding == CE_UNKNOWN) encoding = pref_encoding(asciicount, qpspecialcount, eightbitcount); unfold_header(value, asciicount + eightbitcount); switch (encoding) { case CE_BASE64: return field_encode_base64(name, value, charset); case CE_QUOTED: return field_encode_quoted(name, value, charset, asciicount, eightbitcount + qpspecialcount, 0); default: advise(NULL, "Internal error: unknown RFC-2047 encoding type"); return 1; } }