TUCoPS :: Linux :: Apps N-Z :: lnx5165.htm

shell code detection for snort
5th Mar 2002 [SBWID-5165]
COMMAND

	shell code detection for snort

SYSTEMS AFFECTED

	snort

PROBLEM

	 Editor\'s note

	 =============

	

	This is not a bug, but a feature you may add to snort.  Cool  enough  to
	pass it around. Good reading !
	

	Dragos Ruiu [http://dragos.com/dr-dursec.asc] says :
	

	** Shell code detector **
	

	This has proven to be substantially better than the  snort  experimental
	NOP signatures with fewer  falses,  and  consumes  very  little  CPU  in
	testing on a loaded DS3. Beta testing has caught some new attacks  using
	this detector and shown that turned up to  high  sensitivity  levels  it
	functions as a good lycos cookie, nntp,  and  streaming  media  detector
	too :-).
	

	It should detect any ordinary shellcode that has NOP sleds  even  it  it
	is not polymorphically mutated, as well  as  codes  mutated  with  K2\'s
	ADMmutate.
	

	The options on the preprocessor definitions  can  override  the  default
	sensitivity on a per port basis. (shorter = more sensitive)
	

	A sorted list of NOP codes can be found at
	

	 http://cansecwest.com/noplist-v1-1.txt  

	

	

	Please mail additions/edits to this list to dr@kyx.net.
	

	This preprocessor can be found at http://cansecwest.com/spp_fnord.c  and
	will shortly be integrated into the snort 1.9  source  tree.  It  should
	work  with  any  version  of  snort  1.7  or  later  by  following   the
	integration instructions below.
	

	As usual send the inevitable bug reports to dr@kyx.net :-). Seems to  be
	relatively stable in testing so far.
	

	/*****************************/
	

	 /* spp_fnord:  snort preprocessor - Multi-architecture mutated NOP sled detector - copyright 2002 Dragos Ruiu (dr@kyx.net) 

	info on this at CanSecWest and at SANS Real World IDS Workshop. (a.k.a. Martycon :)

	

	Version 2.1 2002 February 26

	*/

	

	/*  LESS code == BETTER ! :-)  */

	/*

	

	USAGE:

	

	use this line in your snort.conf file to activate it

	

	preproc fnord: 80:768; 110:768;

	

	The format for the options is port:length;  

	Lengths are rounded to modulo 8. Maximum is 2048 currently.

	Length 0 will disable checking on that port.

	Default length is 384 (MAXNOP) except for port 80 which is 768 (MAXNOPMORE). 

	

	to use this module make sure you add spp_fnord.c and spp_fnord.o to the makefile objects

	and these lines in generators.h (maybe incrementing 114 to the next available highest number) 

	

	#define GENERATOR_SPP_FNORD         114

	#define     FNORD_NOPSLED                         1

	

	and add the line below in plugbase.c in the routine InitPreprocessors()

	

	(void) SetupFnord();

	

	

	*/

	#include \"decode.h\"

	#include <string.h>

	#include <stdlib.h>

	#include <limits.h>

	

	

	#define MAXNOP         384 /* NOTE this must be a multiple of 4!!!*/

	#define MAXNOPMORE     768 /* This is the lower sensitivity level (also must be amultiple of 4!!!) */

	#define MAXFUZZ          3

	#define SKIP             0

	#define BACKTRACK        1

	#define SKIPIA32	11

	#define SKIPHPPA	12

	#define SKIPSPARC       13

	#define WALK            20

	#define WALKIA32	21

	#define WALKHPPA	22

	#define WALKSPARC       23

	

	

	#define VAL              (*pointer)

	#define CMP(x)		 (*pointer == x)

	#define CMPL(l,x)	 (*(pointer+l) == x)

	#define CMP2(x,y)	 ((*pointer == x) && (*(pointer+1) == y))

	#define CMPL2(l,x,y)	 ((*(pointer+l) == x) && (*(pointer+l+1) == y))

	#define CMP3(x,y,z)	 ((*pointer == x) && (*(pointer+1) == y) && (*(pointer+2) == z))

	#define CMPL3(l,x,y,z)	 ((*(pointer+l) == x) && (*(pointer+l+1) == y) && (*(pointer+l+2) == z)) 

	#define CMP4(x,y,z,q)	 ((*pointer == x) && (*(pointer+1) == y) && (*(pointer+2) == z) && (*(pointer+3) == q))

	#define CMPL4(l,x,y,z,q) ((*(pointer+l) == x) && (*(pointer+l+1) == y) && (*(pointer+l+2) == z) && (*(pointer+l+3) == q)) 

	

	

	#define INC(val)       ((pointer < (max - val)) ? (pointer += val) : (pointer = max)) 

	

	

	u_int8_t ports[65536];

	

	void PreprocFnord(Packet *p);

	void FnordInit();

	

	/*************Parsing Routines*************/

	

	

	inline char *strquotchr(char *str, char c)

	{

	    if(!str)

	        return NULL;

	again:

	    if(strchr(str,(int)\'\\\"\') && strchr(str,(int)\'\\\"\') < strchr(str,(int)c))

	    {

	        str = strchr(str,(int)\'\\\"\');

	        if(*(str-1) == \'\\\\\')

	        {

	            str++;

	            goto again;

	        }

	        if(!str || !*str)

	            return NULL;

	        while((*str != \'\\\"\' || (*str == \'\\\"\' && *((char*)str-1) != \'\\\\\')) && *str != c)

	        {

	            str++;

	            if(!str || !*str)

	                return NULL;

	        }

	        if(*str == c)

	            return str;

	        return(strquotchr(str,c));

	    }

	    else return(strchr(str,(int)c));

	}

	

	

	

	inline void splitstr(char *main[], char **split)

	{

	    if(*split)

	    {

	        *((*split)++) = \'\\0\';

	        while(isspace(**split))

	            (*split)++;

	    }

	    if(*main)

	        while(isspace((*main)[strlen(*main)-1]))

	            (*main)[strlen(*main)-1] = \'\\0\';

	}

	

	

	

	inline void trim(char *str[])

	{

	    if(*str)

	    {

	        while(isspace(**str))

	            (*str)++;

	        while(isspace((*str)[strlen(*str)-1]))

	            (*str)[strlen(*str)-1] = \'\\0\';

	    }

	}

	

	

	

	void parseopts(char *opts)

	{

	    char *x, *y, *tmp, *tmporg;

	    int tmplen = 0;

	

	    tmporg = NULL;

	    if(opts && *opts)

	    {

	        tmplen = strlen(opts);

	        tmp = calloc(tmplen+1, sizeof(char));

	        bcopy((void *) opts, (void *) tmp, tmplen);

	        tmp[tmplen+1] = \'\\0\';

	        tmporg = tmp;

	        trim(&tmp);

	        while(*tmp == \';\')

	        {

	             *tmp++ = NULL;

	             trim(&tmp);

	        }

	

	    }

	    while(tmp && *tmp)

	    {

	        x = strquotchr(tmp,\';\');

	        splitstr(&tmp, &x);

	        if(tmp && !*tmp)

	             ErrorMessage(\"fnord init: Empty parameter before \\\';\\\', ignoring.\\n\");

	        else

	        {

	            if((y = strquotchr(tmp,\':\')))

	            {

	                splitstr(&tmp, &y);

	                if(tmp && !*tmp)

	                    ErrorMessage(\"fnord init: Empty port number before \\\':\\\', ignoring. \\n\");

	                else

	                {

	                    if(y && !*y)

	                        ErrorMessage(\"fnord init: Empty parameter after \\\':\\\'.\\n\");

	                    else

	                    {

	#ifdef DEBUG

			fprintf(stdout,\"init: %d:%d\\n\", (int)(strtol(tmp,0,0)&0xffff), (int)(strtol(y,0,0)&0x7ff));

			fflush(stdout);

	#endif /* DEBUG */

				ports[strtol(tmp,0,0)&0xffff] = (u_int8_t) ((strtol(y,0,0)&0x7ff)>>3);

	                    }

	                } // end if

	            } // end if

	            else

	                ErrorMessage(\"fnord init: Expecting port:length after ; , ignoring.\\n\");

	        } // end if

	        tmp = x;

	    } // end while

	    if(tmporg)

	    {

	        free(tmporg);

	    }

	

	} // end parseopt

	

	

	/**************Snort Stupf****************/

	

	/*

	 * Function: SetupFnord()

	 * Purpose:

	 * Registers the preprocessor keyword and initialization function

	 * into the preprocessor list.  This is the function that gets called from

	 * InitPreprocessors() in plugbase.c.

	 * Arguments: None.

	 * Returns: void function

	 */

	void SetupFnord()

	{

	    RegisterPreprocessor(\"fnord\", FnordInit);

	

	    DebugMessage(DEBUG_STREAM,  \"Preprocessor: fnord is setup...\\n\");

	

	}

	

	void FnordInit(u_char *opts)

	{

	int i;

	

	    AddFuncToPreprocList(PreprocFnord);

	

	// default port sensitivity

	    for(i = 0; i < 65536; i++)

		ports[i] = MAXNOP >> 3;

	

	// default lower port sensitivity

	    ports[80] = MAXNOPMORE >> 3;

	

	// user overrides defaults

	    parseopts(opts);

	}

	

	/******************* Main Logic *********************/

	/* When adding codes please pay attention to        */

	/* overlaps and side effects in logic flow          */

	/****************************************************/

	

	void PreprocFnord(Packet *p)

	{

	u_int8_t * pstart;

	register u_int8_t * pointer;

	u_int8_t * max;

	int fuzz, len, mode, plen, maxnop;

	Event event;

	

	    if(!p || !p->pkth || !p->pkt)

	    {

	        if(pv.verbose_flag)

	        {

	            ErrorMessage(\"%s\\n\",\"Garbage Packet with Null Pointer discarded!\");

	        }

	

	        return;

	    }

	

	    /* check to make sure the IP header exists and that

	     * there isn\'t a bad IP checksum

	     */

	    if(!p->iph || (p->csum_flags & CSE_IP))

	    {

	        return;

	    }

	

	/* OK here we go, let\'s git us some mutants  */

	

		pstart = ((u_int8_t *)p->data);

		plen = p->dsize; 

		pointer = pstart;

		max = pstart + plen - 4;

		mode = SKIP;

		fuzz = 0;

		len = 0;

	/* port based desensitizer */

		maxnop = (ports[p->dp] > ports[p->sp] ? ports[p->dp] : ports[p->sp]) << 3;

		if(maxnop == 0)

			return;

	

	

		while(pointer < max)

		{

	

	#ifdef DEBUG

			fprintf(stdout,\"pointer: %08X max: %08X count: %d val: %02X %02X %02X %02X len: %d mode: %d fuzz: %d\\n\", pointer, max, (plen - (max - pointer)), VAL, *(pointer+1), *(pointer+2), *(pointer+3), len, mode, fuzz);

			fflush(stdout);

	#endif /* DEBUG */

	

			/* SPARC 4 byte nop detector */

			/* note it is important to check these before intel because 0x96 and 0x98 overlap */

			if(

			       CMP3(0x20,0xBF,0xBF) ||              /* bn -random        */

			       CMP3(0x81,0xD0,0x20) ||              /* tn random         */

			       CMP4(0x89,0xA5,0x08,0x22) ||         /* fadds %f20,%f2,%f4*/

			       (CMP(0x96) &&

	                         ( CMPL2(1,0x23,0x60) ||            /* sub %o5,0x42,%o3  */

			           CMPL3(1,0x24,0x80,0x12))) ||     /* sub %l2,%l2,%o3   */

			       CMP4(0x98,0x3E,0x80,0x12) ||         /* xnor %i2,%l2,%o4  */

			       CMP3(0xA0,0x26,0xE0) ||              /* sub %i3,0x42,%l0  */

			       (CMP(0xA2) &&

				 ( CMPL3(1,0x03,0x40,0x12) ||       /* add %o5,%l2,%l1   */

				   CMPL3(1,0x0E,0x80,0x13) ||       /* and %i2,%l3,%l1   */

				   CMPL3(1,0x1A,0x40,0x0A) ||       /* xor %o1,%o2,%l1   */

				   CMPL3(1,0x1C,0x80,0x12))) ||     /* xor %l2,%l2,%l1   */

			       (CMP(0xA4) &&

				 ( CMPL2(1,0x04,0xE0) ||            /* add %l3,0x42,%l2  */

				   CMPL3(1,0x27,0x40,0x12) ||       /* sub %i5,%l2,%l2   */

				   CMPL2(1,0x32,0xA0))) ||          /* orn %o2,0x42,%l2  */

			       (CMP(0xB2) &&

				 ( CMPL2(1,0x03,0x60) ||            /* add %o5,0x42,%i1  */

				   CMPL3(1,0x26,0x80,0x19))) ||     /* sub %i2,%i1,%i1   */

			       (CMP(0xB6) &&

				 ( CMPL3(1,0x06,0x40,0x1A) ||       /* add %i1,%i2,%i3   */

				   CMPL3(1,0x16,0x40,0x1A) ||       /* or  %i1,%i2,%i3   */

				   CMPL3(1,0x04,0x80,0x12) ||       /* add %l2,%l2,%i3   */

				   CMPL2(1,0x03,0x60))) ||          /* add %o5,0x42,%i3  */

			       CMP3(0xBA,0x56,0xA0)                 /* umul %i2,0x42,%i5 */

			    )

			{

				if(mode == SKIP)

				{

					mode = BACKTRACK;

					INC(0 - (fuzz + maxnop));

				}

				else if(mode == WALKSPARC)

				{

					len += 4;

					INC(4);

				}

				else if(mode == SKIPSPARC)

				{

					mode = WALKSPARC;

					INC( - maxnop);

				}

				else

				{

					mode = SKIPSPARC;

					len = 0;

					fuzz = 0;

					INC(maxnop);

				}

			}

	

			/* HPPA nop detector */

			else if(

				(CMP(0x08) &&

				  ( CMPL3(1,0x21,0x02,0x9A) ||      /* xor %r1,%r1,%r26        */

				    CMPL3(1,0x41,0x02,0x83) ||      /* xor %r1,%r2,%r3         */

				    CMPL3(1,0xA4,0x02,0x46))) ||    /* or  %r4,%r5,%r6         */

				(CMP(0x09) &&

				  ( CMPL3(1,0x04,0x06,0x8F) ||      /* shladd %r4,2,%r8,%r15   */

				    CMPL3(1,0x09,0x04,0x07) ||      /* sub %r9,%r8,%r7         */

				    CMPL3(1,0x6A,0x02,0x8C) ||      /* xor %r10,%r11,%12       */

				    CMPL3(1,0xCD,0x06,0x0F))) ||    /* add %r13,%r14,%r15      */

				CMP4(0x94,0x6C,0xE0,0x84) ||        /* subi,OD 0x42,%r3,%r12   */

				CMP4(0xD0,0xE8,0x0A,0xE9) ||        /* shrpw %r8,%r7,8,%r9     */

				(CMP(0xB5) &&

				  ( CMPL2(1,0x03,0xE0) ||           /* addi,OD 0x42,%r8,%r3    */

				    CMPL2(1,0x4B,0xE0)))            /* addi,OD 0x42,%r10,%r11  */

			   )

			{

				if(mode == SKIP)

				{

					mode = BACKTRACK;

					INC(0 - (fuzz + maxnop));

				}

				else if(mode == WALKHPPA)

				{

					len += 4;

					INC(4);

				}

				else if(mode == SKIPHPPA)

				{

					mode = WALKHPPA;

					INC( - maxnop);

				}

				else

				{

					mode = SKIPHPPA;

					len = 0;

					fuzz = 0;

					INC(maxnop);

				}

			}

	

	

			/* intel 3 byte with wildcard nop codes */

			else if(

			       CMP2(0x6B,0xC0) ||                   /* imul N,%eax    */

			       (CMP(0x83) &&

				 ( CMPL(1,0xE0) ||                  /* and N,%eax     */

				   CMPL(1,0xC8) ||                  /* or  N,%eax     */

				   CMPL(1,0xE8) ||                  /* sub N,%eax     */

				   CMPL(1,0xF0) ||                  /* xor N,%eax     */

				   CMPL(1,0xF8) ||                  /* cmp N,%eax     */

				   CMPL(1,0xF9) ||                  /* cmp N,%ecx     */

				   CMPL(1,0xFA) ||                  /* cmp N,%edx     */

				   CMPL(1,0xFB) ||                  /* cmp N,%ebx     */

				   CMPL(1,0xC0))) ||                /* add N,%eax, N  */

			       (CMP(0xC1) &&

				 ( CMPL(1,0xC0) ||                  /* rol N,%eax     */

				   CMPL(1,0xC8) ||                  /* ror N,%eax     */

				   CMPL(1,0xE8)))                   /* shr N,%eax     */

			    )

			{

				if(mode == SKIP)

				{

					mode = BACKTRACK;

					INC(0 - (fuzz + maxnop));

				}

				else if(mode == WALKIA32)

				{

					len += 3;

					INC(3);

				}

				else if(mode == SKIPIA32)

				{

					mode = WALKIA32;

					INC(0 - (fuzz + maxnop));

				}

				else

				{

					mode = SKIPIA32;

					len = 0;

					fuzz = 0;

					INC(maxnop);

				}

			}

	

	

			/* intel 2 byte nop codes */

			else if(

			       CMP2(0x33,0xC0) ||                   /* xor %eax,%eax  */

			       CMP2(0x85,0xC0) ||                   /* test %eax,%eax */

			       (CMP(0x87) &&

				 ( CMPL(1,0xD2) ||                  /* xchg %edx,%edx */

				   CMPL(1,0xDB) ||                  /* xchg %ebx,%ebx */

				   CMPL(1,0xC9))) ||                /* xchg %ecx,%ecx */

			       (CMP(0x8C) &&

				 ( CMPL(1,0xC0) ||                  /* mov %es,%eax   */

				   CMPL(1,0xE0) ||                  /* mov %fs,%eax   */

				   CMPL(1,0xE8))) ||                /* mov %gs,%eax   */

			       CMP(0xB0) ||                         /* mov N,%eax     */

			       CMP2(0xF7,0xD0)                      /* not %eax       */

			    )

			{

				if(mode == SKIP)

				{

					mode = BACKTRACK;

					INC(0 - (fuzz + maxnop));

				}

				else if(mode == WALKIA32)

				{

					len += 2;

					INC(2);

				}

				else if(mode == SKIPIA32)

				{

					mode = WALKIA32;

					INC(0 - (fuzz + maxnop));

				}

				else

				{

					mode = SKIPIA32;

					len = 0;

					fuzz = 0;

					INC(maxnop);

				}

			}

	

	

	

			/* one byte intel nop detector */

	

			else if(

			    ((VAL >= 0x3f) && (VAL <=0x60)) ||      /* inc, dec, push, pop */ 

			    ((VAL >= 0x90) && (VAL <=0x9F)) ||      /* nop, xchg, cwtl, fwait, pushf safh, lahf */

			    CMP(0x27) ||                            /* daa        \"\'\" */

			    CMP(0x2F) ||                            /* das        \"/\" */

			    CMP(0x37) ||                            /* aaa        \"7\" */

			    CMP(0x60) ||                            /* pusha      \"`\" */

			    CMP(0xF5) ||                            /* cmc            */

			    CMP(0xF8) ||                            /* clc            */

			    CMP(0xF9) ||                            /* stc            */

			    CMP(0xFC) 	                            /* cld            */

			   )

			{

				if(mode == SKIP)

				{

					mode = BACKTRACK;

					INC(0 - (fuzz + maxnop));

				}

				else if(mode == WALKIA32)

				{

					len += 1;

					INC(1);

				}

				else if(mode == SKIPIA32)

				{

					mode = WALKIA32;

					INC(0 - (fuzz + maxnop));

				}

				else

				{

					mode = SKIPIA32;

					len = 0;

					fuzz = 0;

					INC(maxnop);

				}

			}

			else

			{				/* NO NOP CODE */

				if(mode == BACKTRACK)

				{

					INC(1);

				}

				else if(mode >= WALK)

				{

					mode = SKIP;

					INC(maxnop);

					fuzz = 0;

				}

				else

				{

					if(fuzz > MAXFUZZ || mode == SKIPHPPA || mode == SKIPSPARC)

					{

						mode = SKIP;

						INC(maxnop - fuzz);

						fuzz = 0;

					}

					else

					{		/* only fuzz for SKIP and SKIPIA32 */

						fuzz++;

						INC(1);

					}

				}

			}

	

	#define ALERT(msg) (CallAlertPlugins(p,msg,NULL,&event), CallLogPlugins(p,msg,NULL,&event))

	

			if( len >= maxnop )

			{

			        SetEvent(&event, GENERATOR_SPP_FNORD, FNORD_NOPSLED, 1, 0, 0, 0);

	

				if(mode == WALKIA32)

			                ALERT(\"spp_fnord: Possible Mutated IA32 NOP sled detected.\");

				if(mode == WALKHPPA)

	                                ALERT(\"spp_fnord: Possible Mutated HPPA NOP sled detected.\");

				if(mode == WALKSPARC)

	                                ALERT(\"spp_fnord: Possible Mutated SPARC NOP sled detected.\");

				pointer = max; /* no real point in checking more now is there :-) */

			}

		}

						

	}

				

				

	/***** end of spp_fnord.c *****/

SOLUTION

	

TUCoPS is optimized to look best in Firefox® on a widescreen monitor (1440x900 or better).
Site design & layout copyright © 1986-2024 AOH