[Snort-devel] ASN.1 Preprocessor for Snort 2.0rc1

Andrew R. Baker andrewb at ...835...
Sat Mar 29 09:16:18 EST 2003


Attached is a patch that will add back the ASN.1 preprocessor that was 
removed with the rc1 release of Snort 2.0.  The ASN.1 preprocessor 
validates the length encodings within packets destined to UDP/161 and 
UDP/162.  This particular version should correct the following issues 
that were present in the versions available in earlier versions of Snort:

     * incorrect reporting of some error conditions
     * possible memory access fault processing some length encodings
     * continued processing of a packet after generating an event
         causing excessive recursion in the decoder.


If you use this and like it, let me know.

-A
-------------- next part --------------
diff -durN snort-CVS/etc/snort.conf snort-2.0-arb/etc/snort.conf
--- snort-CVS/etc/snort.conf	2003-03-29 11:52:45.000000000 -0500
+++ snort-2.0-arb/etc/snort.conf	2003-03-29 12:02:36.000000000 -0500
@@ -397,6 +397,13 @@
 # preprocessor portscan2-ignorehosts: 10.0.0.0/8 192.168.24.0/24
 #
 
+# Experimental ASN.1 Decoder
+#------------------------------------
+# asn1_decode validates the ASN.1 length encoding on UDP packets destined to 
+# ports 161 and 162.  
+#
+preprocessor asn1_decode
+
 # Experimental Perf stats
 # -----------------------
 # No docs. Highly subject to change.
diff -durN snort-CVS/src/plugbase.c snort-2.0-arb/src/plugbase.c
--- snort-CVS/src/plugbase.c	2003-03-29 11:52:49.000000000 -0500
+++ snort-2.0-arb/src/plugbase.c	2003-03-29 11:58:48.000000000 -0500
@@ -59,6 +59,7 @@
 #include "preprocessors/spp_portscan2.h"
 #include "preprocessors/spp_httpflow.h"
 #include "preprocessors/spp_perfmonitor.h"
+#include "preprocessors/spp_asn1.h"
 
 /* built-in detection plugins */
 #include "detection-plugins/sp_pattern_match.h"
@@ -396,6 +397,7 @@
     SetupScan2();
     SetupHttpFlow();
     SetupPerfMonitor();
+    SetupASN1Decode();
 }
 
 /****************************************************************************
diff -durN snort-CVS/src/preprocessors/Makefile.am snort-2.0-arb/src/preprocessors/Makefile.am
--- snort-CVS/src/preprocessors/Makefile.am	2003-03-29 11:52:53.000000000 -0500
+++ snort-2.0-arb/src/preprocessors/Makefile.am	2003-03-29 11:56:02.000000000 -0500
@@ -16,6 +16,7 @@
 perf-flow.c perf-flow.h \
 perf-event.c perf-event.h \
 http-resp.c http-resp.h \
+spp_asn1.c spp_asn1.h \
 sfprocpidstats.c sfprocpidstats.h
 
 INCLUDES = @INCLUDES@
diff -durN snort-CVS/src/preprocessors/spp_asn1.c snort-2.0-arb/src/preprocessors/spp_asn1.c
--- snort-CVS/src/preprocessors/spp_asn1.c	1969-12-31 19:00:00.000000000 -0500
+++ snort-2.0-arb/src/preprocessors/spp_asn1.c	2003-03-29 11:59:29.000000000 -0500
@@ -0,0 +1,337 @@
+/*
+** Copyright (C) 2002-2003 Andrew R. Baker <andrewb at ...835...>
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+/* $Id$ */
+/* spp_asn1
+ * 
+ * Purpose:
+ *
+ * Arguments:
+ *   
+ * Effect:
+ *
+ * Comments:
+ *
+ */
+
+/**************************************************************************
+ * ASN.1 - Abstract Syntax Notation number One 
+ *
+ * * * * * * *
+ *
+ * An interesting site about ASN.1 (and its primary author Professor John
+ * Larmouth) can be found here:  http://www.oss.com/asn1/larmouth.html
+ * including an electronic copy of Professor Larmouth's book titled
+ * "ASN.1 Complete".
+ *
+ * * * * * * *
+ *
+ * The following descriptions are copied from the website:
+ * "http://asn1.elibel.tm.fr/".  I have no affiliation with this website,
+ * but reference it here because they provide a large amount of useful
+ * information about ASN.1.
+ *
+ * "Abstract Syntax Notation number One (ASN.1) is an international standard
+ *  that aims at specifying data used in communication protocols. It is a
+ *  powerful and complex language: its features are designed to describe
+ *  accurately and efficiently communications between homogeneous or
+ *  heterogeneous systems."
+ *
+ *
+ *
+ * "ASN.1 is a formal notation used for describing data transmitted by
+ *  telecommunications protocols, regardless of language implementation and
+ *  physical representation of these data, whatever the application, whether
+ *  complex or very simple.
+ *  
+ *     "-------------------------------------------
+ *      Abstract Syntax Notation number One
+ *      is a standard that defines a formalism
+ *      for the specification of abstract data types. 
+ *      -------------------------------------------
+ *
+ * "The notation provides a certain number of pre-defined basic types such as:
+ *  -  integers (INTEGER), 
+ *  -  booleans (BOOLEAN), 
+ *  -  character strings (IA5String, UniversalString...), 
+ *  -  bit strings (BIT STRING), 
+ *  -  etc., 
+ *
+ * "and makes it possible to define constructed types such as:  
+ *  -  structures (SEQUENCE), 
+ *  -  lists (SEQUENCE OF), 
+ *  -  choice between types (CHOICE), 
+ *  -  etc. "
+ *
+ * * * * * * *
+ *
+ * My own notes about ASN.1, as understood from skimming through Section 3
+ * ("Encodings") of the book "ASN.1 Complete"...
+ *
+ *  - Data in ASN.1 is represented by groupings composed of T-L-V (Type,
+ *    Length, and Value)
+ *
+ *  - Datatypes are identified by the bottom six bits of a single byte.
+ *    Datatypes values 0 through 30 are represented in a single byte.
+ *    Value "31" (0x1f) is an escape marker to indicate the datatype
+ *    value continues in the following bytes -- as long as successive
+ *    bytes have the high bit set.
+ *
+ *  - The length of a given datatype can be represented in any of three
+ *    ways:  Short Length, Long Length, and Indefinite Length.
+ *
+ *  - Short Lengths are stored in one byte, and can indicate data lengths
+ *    of up to 127 bytes.  Note that Short Lengths are identified by an
+ *    upper bit of zero.
+ *
+ *  - Long Lengths are stored in multiple bytes.  The first byte indicates
+ *    how many bytes are required to contain the Long Length, and the
+ *    successive bytes contain the value of the Long Length.  Note that
+ *    the first byte of Long Lengths are identified by an upper bit of one,
+ *    and that only the bottom seven bits of the first byte are used to
+ *    represent how many bytes are required to contain the Long Length.
+ *    Also, note that the maximum allowed value of the bottom seven bits
+ *    is 126 (0x7e), and that 127 (0x7f) is reserved for future use.
+ *
+ *  - Indefinite Lengths are conceptually like BLOB data.  The upper bit of
+ *    the first byte is set to one, and the bottom seven bits are zero.  The
+ *    data value follows immediately, and continues until two zero-bytes
+ *    are encountered.
+ * 
+ **************************************************************************/
+
+#include "spp_asn1.h"
+#include "generators.h"
+#include "plugbase.h"
+#include "parser.h"
+#include "util.h"
+#include "detect.h"
+#include "log.h"
+#include "debug.h"
+#include <ctype.h>
+
+#define MODNAME "spp_asn1"
+
+int ASN1Decode(Packet *, u_int8_t *data, u_int16_t size);
+
+/* Instantiate the list of ports we're going to watch */
+
+/*
+ * Function: SetupASN1Decode()
+ *
+ * Purpose: Registers the preprocessor keyword and initialization 
+ *          function into the preprocessor list.
+ *
+ * Arguments: None.
+ *
+ * Returns: void function
+ *
+ */
+void SetupASN1Decode()
+{
+    /* link the preprocessor keyword to the init function in 
+       the preproc list */
+    RegisterPreprocessor("asn1_decode", ASN1DecodeInit);
+}
+
+
+/*
+ * Function: ASN1DecodeInit(u_char *)
+ *
+ * Purpose: Processes the args sent to the preprocessor, sets up the
+ *          port list, links the processing function into the preproc
+ *          function list
+ *
+ * Arguments: args => ptr to argument string
+ *
+ * Returns: void function
+ *
+ */
+void ASN1DecodeInit(u_char *args)
+{
+    /* Set the preprocessor function into the function list */
+    AddFuncToPreprocList(PreprocASN1Decode);
+}
+
+/*
+ * Function: PreprocASN1Decode(Packet *)
+ *
+ * Arguments: p => pointer to the current packet data struct 
+ *
+ * Returns: void function
+ *
+ */
+void PreprocASN1Decode(Packet *p)
+{
+    /* check to make sure we're talking TCP and that the TWH has already
+       completed before processing anything */
+    
+    if(!(p->preprocessors & PP_ASN1DECODE) || p->frag_flag)
+    {
+        return;
+    }
+    
+    if(!PacketIsUDP(p))
+    {
+        DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, "It isn't UDP traffic\n"););
+        return;
+    }
+
+    if(p->dp == 161 || p->dp == 162)
+    {
+        ASN1Decode(p, p->data, p->dsize);    
+    }
+}
+
+int ASN1Decode(Packet *p, u_int8_t *data, u_int16_t size)
+{
+    int i;
+    int id;
+    int length;
+    Event event;
+
+    for(i = 0; i < size; )
+    {
+        /* decode the identifier */
+        if((data[i] & 0x1f) == 0x1f)
+        {
+            if(pv.verbose_flag)
+            {
+                ErrorMessage("Multibyte ASN.1 identifier, bailing out");
+            }
+
+            return 0;
+        }
+
+        id = data[i];
+        ++i;
+
+        /* decode the length */
+        if(data[i] == 0x80)
+        {
+            /* indefinite length encoding, alert */
+            SetEvent(&event, GENERATOR_SPP_ASN1, ASN1_INDEFINITE_LENGTH, 
+                    1, 0, 5, 0);
+
+            CallAlertFuncs(p, ASN1_INDEFINITE_LENGTH_STR, 
+                    NULL, &event);
+
+            CallLogFuncs(p, ASN1_INDEFINITE_LENGTH_STR,
+                    NULL, &event);
+
+            return 1;
+        }
+        else if(data[i] == 0xff)
+        {
+            /* Invalid length encoding, alert */
+            SetEvent(&event, GENERATOR_SPP_ASN1, ASN1_INVALID_LENGTH, 
+                    1, 0, 5, 0);
+
+            CallAlertFuncs(p, ASN1_INVALID_LENGTH_STR, NULL, &event);
+
+            CallLogFuncs(p,ASN1_INVALID_LENGTH_STR,
+                    NULL, &event);
+
+            return 1;
+        }
+        else if(data[i] > 0x80)
+        {
+            /* multibyte length encoding */
+            int len_octets = data[i] & 0x7f;
+            ++i;
+            /* verify there is enough data available for the length
+             * specification
+             */
+            if(len_octets + i > size)
+            {
+                /* truncated packet, alert */
+                SetEvent(&event, GENERATOR_SPP_ASN1, ASN1_DATUM_BAD_LENGTH, 
+                        1, 0, 5, 0);
+
+                CallAlertFuncs(p,ASN1_DATUM_BAD_LENGTH_STR, NULL, &event);
+
+                CallLogFuncs(p,  ASN1_DATUM_BAD_LENGTH_STR, NULL, &event);
+                return 1;
+            }
+            /* decode the length */
+            while(len_octets > 2)
+            {
+                if(data[i] != 0x00)
+                {
+                    /* length specified is greater than maximum 
+                     * packet size, alert */
+                    SetEvent(&event, GENERATOR_SPP_ASN1, 
+                            ASN1_OVERSIZED_ITEM, 
+                            1, 0, 5, 0);
+
+                    CallAlertFuncs(p, ASN1_OVERSIZED_ITEM_STR,
+                            NULL, &event);
+
+                    CallLogFuncs(p, ASN1_OVERSIZED_ITEM_STR,
+                            NULL, &event);
+
+                    return 1;
+                }
+                len_octets--;
+                i++;
+            }
+
+            if(len_octets == 2)
+            {
+                length = (data[i] << 8 | data[i + 1]);
+                i += 2;
+
+            }
+            else /* len_octets == 1 */
+            {
+                length = data[i];
+                i++;
+            }
+        }
+        else
+        { 
+            /* simple length encoding */
+            length = data[i];
+            ++i;
+        } 
+
+        /* are there enough bytes for the length specified? */
+        if((length + i) > size)
+        {
+            SetEvent(&event, GENERATOR_SPP_ASN1, ASN1_DATUM_BAD_LENGTH, 
+                    1, 0, 5, 0);
+
+            CallAlertFuncs(p,ASN1_DATUM_BAD_LENGTH_STR, NULL, &event);
+
+            CallLogFuncs(p,  ASN1_DATUM_BAD_LENGTH_STR, NULL, &event);
+            return 1;
+        }
+
+        /* recursively parse constructed types */
+        if((id & 0x20) == 0x20)
+        {
+            if(ASN1Decode(p, data + i, length))
+                return 1;
+        }
+
+        /* skip length bytes */
+        i += length;
+    }
+
+    return 0;
+}
diff -durN snort-CVS/src/preprocessors/spp_asn1.h snort-2.0-arb/src/preprocessors/spp_asn1.h
--- snort-CVS/src/preprocessors/spp_asn1.h	1969-12-31 19:00:00.000000000 -0500
+++ snort-2.0-arb/src/preprocessors/spp_asn1.h	2003-03-29 11:58:45.000000000 -0500
@@ -0,0 +1,26 @@
+/*
+** Copyright (C) 2002-2003 Andrew R. Baker <andrewb at ...835...>
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#ifndef __SPP_ASN1_DECODE_H__
+#define __SPP_ASN1_DECODE_H__
+
+#include "snort.h"
+
+void SetupASN1Decode();
+
+#endif  /* __SPP_ASN1_DECODE_H__ */


More information about the Snort-devel mailing list