/* The second example for Sourcefire VRT Intro to SO Rules blog post.

This is modified autogeneration from the example rule to show how one would modify
the output to provide advanced detection.  The "vulnerability" we are detecting is
one where the size of the DATA section does not take us to the end of the payload,
causing a buffer overflow in our fictitious server.

Example by Patrick Mullen <pmullen@sourcefire.com>


Base rule for autogeneration:

alert tcp $EXTERNAL_NET any -> $HOME_NET 4444 (msg:"MISC Intro to SO Rules Generator Example 1"; flow:to_server,established; content:"MESG"; content:"NAME"; content:"DATA"; classtype:misc-activity; sid:64501;)


  MODIFIED generator output from http://labs.snort.org/cgi-bin/sorules.cgi follows:
*/
/*
 * Use at your own risk.
 *
 * Copyright (C) 2005-2008 Sourcefire, Inc.
 * 
 * This file is autogenerated via rules2c, by Brian Caswell <bmc@sourcefire.com>
 */


#include "sf_snort_plugin_api.h"
#include "sf_snort_packet.h"


/* declare detection functions */
int rule64501eval(void *p);

/* declare rule data structures */
/* flow:established, to_server; */
static FlowFlags rule64501flow0 = 
{
    FLOW_ESTABLISHED|FLOW_TO_SERVER
};

static RuleOption rule64501option0 =
{
    OPTION_TYPE_FLOWFLAGS,
    {
        &rule64501flow0
    }
};
#ifndef CONTENT_FAST_PATTERN
#define CONTENT_FAST_PATTERN 0
#endif
// content:"MESG", payload raw, depth 0, fast_pattern; 
static ContentInfo rule64501content1 = 
{
    (u_int8_t *) "MESG", /* pattern (now in snort content format) */
    0, /* depth */
    0, /* offset */
    CONTENT_FAST_PATTERN|CONTENT_BUF_RAW, /* flags */
    NULL, /* holder for boyer/moore PTR */
    NULL, /* more holder info - byteform */
    0, /* byteform length */
    0 /* increment length*/
};

static RuleOption rule64501option1 = 
{
    OPTION_TYPE_CONTENT,
    {
        &rule64501content1
    }
};
// content:"NAME", payload raw, depth 0; 
static ContentInfo rule64501content2 = 
{
    (u_int8_t *) "NAME", /* pattern (now in snort content format) */
    0, /* depth */
    0, /* offset */
    CONTENT_BUF_RAW, /* flags */
    NULL, /* holder for boyer/moore PTR */
    NULL, /* more holder info - byteform */
    0, /* byteform length */
    0 /* increment length*/
};

static RuleOption rule64501option2 = 
{
    OPTION_TYPE_CONTENT,
    {
        &rule64501content2
    }
};
// content:"DATA", payload raw, depth 0; 
static ContentInfo rule64501content3 = 
{
    (u_int8_t *) "DATA", /* pattern (now in snort content format) */
    0, /* depth */
    0, /* offset */
    CONTENT_BUF_RAW, /* flags */
    NULL, /* holder for boyer/moore PTR */
    NULL, /* more holder info - byteform */
    0, /* byteform length */
    0 /* increment length*/
};

static RuleOption rule64501option3 = 
{
    OPTION_TYPE_CONTENT,
    {
        &rule64501content3
    }
};

/* references for sid 64501 */
static RuleReference *rule64501refs[] =
{
    NULL
};
#ifdef HAS_METADATA
/* metadata for sid 64501 */
/* metadata:; */


static RuleMetaData *rule64501metadata[] =
{
    NULL
};
#endif

RuleOption *rule64501options[] =
{
    &rule64501option0,
    &rule64501option1,
    &rule64501option2,
    &rule64501option3,
    NULL
};

Rule rule64501 = {
   /* rule header, akin to => tcp any any -> any any */
   {
       IPPROTO_TCP, /* proto */
       "$EXTERNAL_NET", /* SRCIP     */
       "any", /* SRCPORT   */
   
       0, /* DIRECTION */
       "$HOME_NET", /* DSTIP     */
   
       "4444", /* DSTPORT   */
   },
   /* metadata */
   { 
       3,  /* genid */
       64501, /* sigid */
       1, /* revision */
       "misc-activity", /* classification */
       0,  /* hardcoded priority XXX NOT PROVIDED BY GRAMMAR YET! */
       "MISC Intro to SO Rules Generator Example 2 -- size field check",     /* message */
       rule64501refs /* ptr to references */
   #ifdef HAS_METADATA
       ,rule64501metadata
   #endif
   },
   rule64501options, /* ptr to rule options */
   &rule64501eval, /* replace with NULL to use the built in detection function */
   0 /* am I initialized yet? */
};


/* detection functions */
int rule64501eval(void *p) {
    const u_int8_t *cursor_raw = 0;
    SFSnortPacket *sp = (SFSnortPacket *) p;

    // New variables for our detection
    const u_int8_t *end_of_payload;
    u_int32_t data_size;

    if(sp == NULL)
        return RULE_NOMATCH;

    if(sp->payload == NULL)
        return RULE_NOMATCH;
    
    // flow:established, to_server;
    if (checkFlow(p, rule64501options[0]->option_u.flowFlags) > 0 ) {
        // content:"MESG", payload raw, depth 0, fast_pattern;
        if (contentMatch(p, rule64501options[1]->option_u.content, &cursor_raw) > 0) {
            // content:"NAME", payload raw, depth 0;
            if (contentMatch(p, rule64501options[2]->option_u.content, &cursor_raw) > 0) {
                // content:"DATA", payload raw, depth 0;
                if (contentMatch(p, rule64501options[3]->option_u.content, &cursor_raw) > 0) {
                   
                   // Calculate the end of the payload
                   end_of_payload = sp->payload + sp->payload_size;

                   // Verify we have enough space to read the DATA size
                   if(cursor_raw + 4 > end_of_payload)
                      return RULE_NOMATCH;

                   // Read the size, big endian.  We can't just typecast the pointer
                   // because we don't know what endianess our device uses
                   data_size = *cursor_raw++ << 24;
                   data_size |= *cursor_raw++ << 16;
                   data_size |= *cursor_raw++ << 8;
                   data_size |= *cursor_raw++;

                   // Alert if our data_size doesn't take us to the end of the payload
                   if(cursor_raw + data_size < end_of_payload)
                      return RULE_MATCH;
                }
            }
        }
    }
    return RULE_NOMATCH;
}

/*
Rule *rules[] = {
    &rule64501,
    NULL
};
*/


