/*
 *  Content Option processing function
 *
 *       p: packet data structure, same as the one found in snort.
 * content: data defined in the detection plugin for this rule content option
 *  cursor: updated to point the 1st byte after the match
 *
 * Returns:
 *    > 0 : match found
 *    = 0 : no match found
 *    < 0 : error
 *
 * Predefined constants:
 *    (see sf_snort_plugin_api.h for more values)
 *    CONTENT_MATCH   -  if content specifier is found within buffer
 *    CONTENT_NOMATCH -  if content specifier is not found within buffer
 *
 * Notes:
 *   For multiple URI buffers, we scan each buffer, if any one of them
 *   contains the content we return a match. This is essentially an OR
 *   operation.
 *
 *   Currently support:
 *    options:
 *      nocase
 *      offset
 *      depth
 *    buffers:
 *      normalized(alt-decode)
 *      raw
 *      uri
 *      post
 *
 */
static int contentMatchInternal(void *p, ContentInfo* content, const uint8_t **cursor)
{
    const uint8_t *start_ptr;
    const uint8_t *end_ptr;
    SFSnortPacket *sp = (SFSnortPacket *)p;
    unsigned hb_type;

    /* This content is only used for fast pattern matching and
     * should not be evaluated */
    if (content->flags & CONTENT_FAST_PATTERN_ONLY)
        return CONTENT_MATCH;

    /* Check for byte_extract variables and use them if present. */
    if (content->offset_location)
        content->offset = *content->offset_location;
    if (content->depth_location)
        content->depth = *content->depth_location;

    if ( (hb_type = HTTP_CONTENT(content->flags)) )
    {
        unsigned len;
        const uint8_t* buf = _ded.getHttpBuffer(hb_type, &len);

        if ( buf )
        {
            if (contentMatchCommon(content, buf, len, cursor) == CONTENT_MATCH)
                return CONTENT_MATCH;
        }
        return CONTENT_NOMATCH;
    }

    if ((content->flags & CONTENT_BUF_NORMALIZED) && _ded.Is_DetectFlag(SF_FLAG_DETECT_ALL))
    {
        if (_ded.Is_DetectFlag(SF_FLAG_ALT_DETECT))
        {
            start_ptr = _ded.altDetect->data;

            if (_alt_detect_end)
                end_ptr = _alt_detect_end;
            else
                end_ptr = _ded.altDetect->data + _ded.altDetect->len;
        }
        else if (_ded.Is_DetectFlag(SF_FLAG_ALT_DECODE))
        {
            start_ptr = _ded.altBuffer->data;

            if (_alt_buffer_end)
                end_ptr = _alt_buffer_end;
            else
                end_ptr = _ded.altBuffer->data + _ded.altBuffer->len;
        }
        else
        {
            return CONTENT_CURSOR_ERROR;
        }
    }
    else
    {
        start_ptr = sp->payload;

        if (sp->normalized_payload_size)
            end_ptr = sp->payload + sp->normalized_payload_size;
        else if (_buffer_end)
            end_ptr = _buffer_end;
        else
            end_ptr = sp->payload + sp->payload_size;
    }

    return contentMatchCommon(content, start_ptr, end_ptr - start_ptr, cursor);
}
static int contentMatchCommon(ContentInfo* content,
        const uint8_t *start_ptr, int dlen, const uint8_t **cursor)
{
    const uint8_t *q;
    const uint8_t *base_ptr;
    const uint8_t *end_ptr = start_ptr + dlen;
    int depth;
    char relative = (content->flags & CONTENT_RELATIVE) ? 1 : 0;

    if (relative)
    {
        // Sanity check to make sure the cursor isn't NULL and is within the
        // buffer we're searching.  It could be at the very end of the buffer
        // due to a previous match, but may have a negative offset here.
        if ((cursor == NULL) || (*cursor == NULL)
                || (*cursor < start_ptr) || (*cursor > end_ptr))
            return CONTENT_CURSOR_ERROR;

        base_ptr = *cursor;
        depth = dlen - (*cursor - start_ptr);
    }
    else
    {
        base_ptr = start_ptr;
        depth = dlen;
    }

    // Adjust base_ptr and depth based on offset/depth parameters.
    if (relative && ((content->offset != 0) || (content->depth != 0)))
    {
        if (content->offset != 0)
        {
            base_ptr += content->offset;
            depth -= content->offset;
        }

        // If the offset is negative and puts us before start_ptr
        // set base_ptr to start_ptr and adjust depth based on depth.
        if (base_ptr < start_ptr)
        {
            int delta = (int)content->depth - (start_ptr - base_ptr);
            base_ptr = start_ptr;
            depth = ((content->depth == 0) || (delta > dlen)) ? dlen : delta;
        }
        else if ((content->depth != 0) && ((int)content->depth < depth))
        {
            depth = (int)content->depth;
        }
    }
    else if ((content->offset != 0) || (content->depth != 0))
    {
        if (content->offset != 0)
        {
            base_ptr += content->offset;
            depth -= content->offset;
        }

        if ((content->depth != 0) && ((int)content->depth < depth))
            depth = content->depth;
    }

    // If the pattern size is greater than the amount of data we have to
    // search, there's no way we can match, so return error, however, return
    // CONTENT_NOMATCH here for the case where the match is inverted and there
    // is at least some data.
    if ((int)content->patternByteFormLength > depth)
    {
        if ((content->flags & NOT_FLAG) && (depth > 0))
            return CONTENT_NOMATCH;  // This will get inverted on return
        return CONTENT_CURSOR_ERROR;
    }

    q = hbm_match((HBM_STRUCT*)content->boyer_ptr, base_ptr, depth);

    if (q)
    {
        if (content->flags & CONTENT_END_BUFFER)
        {
            if ( HTTP_CONTENT(content->flags) )
                _uri_buffer_end = q;
            else if ((content->flags & CONTENT_BUF_NORMALIZED)
                    && _ded.Is_DetectFlag(SF_FLAG_ALT_DETECT) )
                _alt_detect_end = q;
            else if ((content->flags & CONTENT_BUF_NORMALIZED)
                    && _ded.Is_DetectFlag(SF_FLAG_ALT_DECODE) )
                _alt_buffer_end = q;
            else
                _buffer_end = q;
        }

        if (cursor)
            *cursor = q + content->patternByteFormLength;

        return CONTENT_MATCH;
    }

    return CONTENT_NOMATCH;
}
예제 #3
0
static int protectedContentMatchCommon(ProtectedContentInfo* content,
        const uint8_t *start_ptr, int dlen, const uint8_t **cursor)
{
    const uint8_t *base_ptr;
    const uint8_t *end_ptr = start_ptr + dlen;
    int depth, ret;
    char relative = (content->flags & CONTENT_RELATIVE) ? 1 : 0;

    if (relative)
    {
        // Sanity check to make sure the cursor isn't NULL and is within the
        // buffer we're searching.  It could be at the very end of the buffer
        // due to a previous match, but may have a negative offset here.
        if ((cursor == NULL) || (*cursor == NULL)
                || (*cursor < start_ptr) || (*cursor > end_ptr))
            return CONTENT_CURSOR_ERROR;

        base_ptr = *cursor;
        depth = dlen - (*cursor - start_ptr);
    }
    else
    {
        base_ptr = start_ptr;
        depth = dlen;
    }

    // Adjust base_ptr and depth based on offset/depth parameters.
    if (relative && ((content->offset != 0)))
    {
        base_ptr += content->offset;
        depth -= content->offset;

        // If the offset is negative and puts us before start_ptr
        // set base_ptr to start_ptr and adjust depth based on depth.
        if (base_ptr < start_ptr)
            return CONTENT_NOMATCH;
        else if((int)content->protected_length < depth)
            depth = (int)content->protected_length;
    }
    else if (content->offset != 0)
    {
        base_ptr += content->offset;
        depth -= content->offset;
    }

    // If the pattern size is greater than the amount of data we have to
    // search, there's no way we can match, so return error, however, return
    // CONTENT_NOMATCH here for the case where the match is inverted and there
    // is at least some data.
    if ((int)content->protected_length > depth)
    {
        if ((content->flags & NOT_FLAG) && (depth > 0))
            return CONTENT_NOMATCH;  // This will get inverted on return
        return CONTENT_CURSOR_ERROR;
    }

    switch( content->hash_type )
    {
        case PROTECTED_CONTENT_HASH_MD5:
        {
            ret = memcmp(MD5DIGEST(base_ptr, content->protected_length, NULL),
                         content->patternByteForm, MD5_HASH_SIZE);
            break;
        }
        case PROTECTED_CONTENT_HASH_SHA256:
        {
            ret = memcmp(SHA256DIGEST(base_ptr, content->protected_length, NULL),
                         content->patternByteForm, SHA256_HASH_SIZE);
            break;
        }
        case PROTECTED_CONTENT_HASH_SHA512:
        {
            ret = memcmp(SHA512DIGEST(base_ptr, content->protected_length, NULL),
                         content->patternByteForm, SHA512_HASH_SIZE);
            break;
        }
        default:
            return( CONTENT_HASH_ERROR );
    }

    if( ret == 0 )
    {
        if (content->flags & CONTENT_END_BUFFER)
        {
            if ( HTTP_CONTENT(content->flags) )
                _uri_buffer_end = base_ptr;
            else if ((content->flags & CONTENT_BUF_NORMALIZED)
                    && _ded.Is_DetectFlag(SF_FLAG_ALT_DETECT) )
                _alt_detect_end = base_ptr;
            else if ((content->flags & CONTENT_BUF_NORMALIZED)
                    && _ded.Is_DetectFlag(SF_FLAG_ALT_DECODE) )
                _alt_buffer_end = base_ptr;
            else
                _buffer_end = base_ptr;
        }

        if (cursor)
            *cursor = base_ptr + content->protected_length;

        return CONTENT_MATCH;
    }

    return CONTENT_NOMATCH;
}