severity 381726 normal
thanks

Demarc reported a security vulnerability to Snort through Bugtraq, this
"security" issue is actually a problem with the HTTP inspector module in
Snort which prevents it from detecting an attack against *Apache* web servers
(not others) because it doesn't take into account that a carriage return
might be included in the request and accepted (even if its not RFC). More
info in the attached text file.

FWI the 2.4.5 changelog of Snort says:
2006-06-05 - Snort 2.4.5 Released
    * Fixed potential evasion in URI content buffers
    * Fixed potential evasion in Stream4

So, actually, to evasion bugs were fixed in this engine.

I have backported both fixes to the 2.3.3-8 packages and have uploaded
a new snort package. However, I don't think that the 'grave' severity of this
bug stands and I'm downgrading it.

Notice that:

a) it is an evasion issue, not a security vulnerability. That is, it only
affects the ability of Snort to detect attacks (but much in the same way that
an *outdated* ruleset [1] could be considered a security issue)

b) it only affects attacks to Apache web servers

For reference, attached is the 2.4.4 vs.  2.4.5 patch (stripping other info)
which fixes the bug, it is easily backported to the 2.3.3 (there is only one
rejection, easy to solve). [2]

Regards

Javier

[1]  Like the one we are providing due to the license change in Snort, post
2.3, with the appearance of the VRT rules

[2] Even if asked to (in #320920) I'm not sure it is reasonable to do
an upgrade to 2.6.0 and provide a Snort package with *no* ruleset (which
means that the Snort service could not be started by default). Since people
now have to download it manually from snort.org as it is not provided
in the GPL package.
diff -Nru snort-2.4.4/doc/README.http_inspect 
snort-2.4.5/doc/README.http_inspect
--- snort-2.4.4/doc/README.http_inspect 2005-05-19 17:05:07.000000000 +0200
+++ snort-2.4.5/doc/README.http_inspect 2006-06-02 21:41:41.000000000 +0200
@@ -249,7 +249,7 @@
 since some web sites refer to files using directory traversals.
 
 * apache_whitespace [yes/no] *
-This option deals with non-RFC standard of tab for a space delimiter.  Apache
+This option deals with non-RFC standard of tab or carriage return for a space 
delimiter.  Apache
 uses this, so if the emulated web server is Apache you need to enable this
 option.  Alerts on this option may be interesting, but may also be false
 positive prone.
diff -Nru snort-2.4.4/src/generators.h snort-2.4.5/src/generators.h
--- snort-2.4.4/src/generators.h        2005-10-16 20:55:29.000000000 +0200
+++ snort-2.4.5/src/generators.h        2006-05-24 18:14:33.000000000 +0200
@@ -98,6 +98,7 @@
 #define     STREAM4_ZERO_TIMESTAMP              21
 #define     STREAM4_OVERLAP_LIMIT               22
 #define     STREAM4_TCP_NO_ACK                  23
+#define     STREAM4_EVASIVE_FIN                 24
 
 #define GENERATOR_SPP_ARPSPOOF      112
 #define     ARPSPOOF_UNICAST_ARP_REQUEST         1
@@ -335,6 +336,7 @@
 #define STREAM4_ZERO_TIMESTAMP_STR "(spp_stream4) TCP Option Timestamp value 
of 0"
 #define STREAM4_OVERLAP_LIMIT_STR "(spp_stream4) TCP stream too many 
overlapping packets"
 #define STREAM4_TCP_NO_ACK_STR "(spp_stream4) Packet in Established TCP stream 
missing ACK"
+#define STREAM4_EVASIVE_FIN_STR "(spp_stream4) possible EVASIVE FIN detection"
 
 /*   FRAG3 strings */
 #define FRAG3_IPOPTIONS_STR "(spp_frag3) Inconsistent IP Options on Fragmented 
Packets"
diff -Nru snort-2.4.4/src/preprocessors/HttpInspect/client/hi_client.c 
snort-2.4.5/src/preprocessors/HttpInspect/client/hi_client.c
--- snort-2.4.4/src/preprocessors/HttpInspect/client/hi_client.c        
2005-03-16 22:52:18.000000000 +0100
+++ snort-2.4.5/src/preprocessors/HttpInspect/client/hi_client.c        
2006-06-02 21:41:41.000000000 +0200
@@ -85,6 +85,8 @@
 */
 static LOOKUP_FCN lookup_table[256];
 static int hex_lookup[256];
+static int NextNonWhiteSpace(HI_SESSION *Session, u_char *start,
+        u_char *end, u_char **ptr, URI_PTR *uri_ptr);
 
 /*
 **  NAME
@@ -455,7 +457,7 @@
         return URI_END;
     }
 
-    return NO_URI;
+    return NextNonWhiteSpace(Session, start, end, ptr, uri_ptr);
 }
 
 /*
@@ -677,7 +679,7 @@
             (*ptr)++;
             continue;
         }
-        else if((**ptr == '\t'))
+        else if((**ptr == '\t') || (**ptr == '\r'))
         {
             if(ServerConf->apache_whitespace.on)
             {
diff -Nru snort-2.4.4/src/preprocessors/spp_stream4.c 
snort-2.4.5/src/preprocessors/spp_stream4.c
--- snort-2.4.4/src/preprocessors/spp_stream4.c 2006-01-09 21:38:30.000000000 
+0100
+++ snort-2.4.5/src/preprocessors/spp_stream4.c 2006-05-24 18:14:33.000000000 
+0200
@@ -412,7 +412,7 @@
 void PreprocCleanExitFunction(int);
 static INLINE int isBetween(u_int32_t low, u_int32_t high, u_int32_t cur);
 static INLINE int NotForStream4(Packet *p);
-static INLINE int SetFinSent(Packet *p, Session *ssn, int direction);
+static INLINE int SetFinSent(Session *ssn, int direction, u_int32_t pkt_seq, 
Packet *p);
 static INLINE int WithinSessionLimits(Packet *p, Stream *stream);
 
  /* helpers for dealing with session byte_counters */
@@ -1777,32 +1777,115 @@
     return;
 }
 
+/**
+ * Check a FIN is valid within the window
+ *
+ * @param s stream to set the next_seq on 
+ * @param direction direction of the packet
+ * @param pkt_seq sequence number for the packet
+ * @param p packet to grab the session from
+ * 
+ * @return 0 if everything went ok
+ */
+static INLINE int CheckFin(Stream *s, int direction, u_int32_t pkt_seq, Packet 
*p)
+{
+    DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "CheckFin() called for %s\n",
+                            direction ? "FROM_CLIENT":"FROM_SERVER"););
+
+    /* If not tracking state ignore it */
+    if( !s4data.stateful_inspection_flag )
+        return 0;
+
+    /*
+     *  We want to make sure the FIN has the next valid sequence that 
+     *  this side should be sending 
+     *  If the pkt_seq < next_seq it's essentially a duplicate 
+     *  sequence, and is probably going to be discarded, it certainly 
+     *  should be. Also, the base sequence includes the SYN sequence count.
+     *  If the packet seq is after the next seq than we should queue the 
+     *  packet for later, in case an out of order packet arrives. We 
+     *  should also honor the FIN-ACK requirements.
+     *
+     *  Ignoring a FIN implies we won't shutdown this session due to it.
+     *  
+     *  This is a standard TCP/IP stack 'in the window' check, but it's 
+     *  not always the way stacks handle FIN's:
+     *  
+     *  if(SEQ_LT(pkt_seq,s->base_seq+s->bytes_tracked) || 
+     *     SEQ_GEQ(pkt_seq,(s->last_ack+s->win_size))) 
+     *  
+     */
+    if(SEQ_LT(pkt_seq,s->base_seq+s->bytes_tracked) || 
+       SEQ_GEQ(pkt_seq,(s->last_ack+s->win_size))) 
+    {
+        DEBUG_WRAP(DebugMessage(DEBUG_STREAM, 
+                    "Bad FIN packet, bad sequence!\n"
+                    "pkt seq: 0x%X   last_ack: 0x%X  win: 0x%X\n",
+                    pkt_seq, s->last_ack, s->win_size););
+
+        /* we should probably alert here */
+        if(s4data.evasion_alerts)
+        {
+            SnortEventqAdd(GENERATOR_SPP_STREAM4, /* GID */
+                    STREAM4_EVASIVE_FIN, /* SID */
+                    1,                      /* Rev */
+                    0,                      /* classification */
+                    3,                      /* priority (low) */
+                    STREAM4_EVASIVE_FIN_STR, /* msg string */
+                    0);
+        }
+        return 1;
+    }
+    return 0;
+}
+
+
 /** 
  * Set that this side of the session has sent a fin.
  *
  * This overloads the next_seq variable to also be used to tell how
  * far forward we can acknowledge data.
  * 
- * @param p packet to grab the session from
  * @param s stream to set the next_seq on 
+ * @param direction direction of the packet
+ * @param pkt_seq sequence number for the packet
+ * @param p packet to grab the session from
  * 
  * @return 0 if everything went ok
  */
-static INLINE int SetFinSent(Packet *p, Session *ssn, int direction)
+static INLINE int SetFinSent(Session *ssn, int direction, u_int32_t pkt_seq, 
Packet *p)
 {
     Stream *stream;
 
     DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "SetFinSet() called for %s\n",
                             direction ? "FROM_CLIENT":"FROM_SERVER"););
 
+    /* If not tracking state ignore it */
+    if( !s4data.stateful_inspection_flag )
+        return 0;
+
     if(direction == FROM_SERVER)
-    {
+    {        
         stream = &ssn->server;
+        DEBUG_WRAP(DebugMessage(DEBUG_STREAM,"--RST From Server!\n"););
+    }
+    else
+    {        
+        stream = &ssn->client;
+        DEBUG_WRAP(DebugMessage(DEBUG_STREAM,"--RST From Client!\n"););
+    }
+
+    if (CheckFin(stream, direction, pkt_seq, p))
+    {
+        return 0;
+    }
+
+    if(direction == FROM_SERVER)
+    {
         ssn->session_flags |= SSNFLAG_SERVER_FIN;
     }
     else
     {
-        stream = &ssn->client;
         ssn->session_flags |= SSNFLAG_CLIENT_FIN;
     }
     
@@ -2596,14 +2679,6 @@
 
     direction = GetDirection(ssn, p);
 
-    if(p->tcph->th_flags & TH_FIN)
-    {
-        DEBUG_WRAP(DebugMessage(DEBUG_STREAM, 
-                    "Marking that a fin was was sent %s\n",
-                    (direction ? "FROM_CLIENT" : "FROM_SERVER")););
-        SetFinSent(p, ssn, direction);
-    }
-
     if(direction == FROM_SERVER)
     {
         ssn->session_flags |= SSNFLAG_SEEN_SERVER;
@@ -2638,6 +2713,15 @@
                     "   %s state: %s\n", l, state_names[listener->state]););
     }
 
+    if(p->tcph->th_flags & TH_FIN)
+    {
+        DEBUG_WRAP(DebugMessage(DEBUG_STREAM, 
+                    "Marking that a fin was was sent %s\n",
+                    (direction ? "FROM_CLIENT" : "FROM_SERVER")););
+
+        SetFinSent(ssn, direction, pkt_seq, p);
+    }
+
     StreamSegmentAdd(talker, p->dsize); 
 
     if(talker->state == ESTABLISHED)
@@ -2754,10 +2838,13 @@
 
             if((p->tcph->th_flags & TH_FIN) == TH_FIN)
             {
-                talker->state = FIN_WAIT_1;
-                DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,  
-                            "   %s Transition: FIN_WAIT_1\n", t););
-                QueueState(CLOSE_WAIT, listener, TH_ACK, pkt_seq, CHK_SEQ);
+                if (!CheckFin(talker, direction, pkt_seq, p))
+                {
+                    talker->state = FIN_WAIT_1;
+                    DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,  
+                                "   %s Transition: FIN_WAIT_1\n", t););
+                    QueueState(CLOSE_WAIT, listener, TH_ACK, pkt_seq, CHK_SEQ);
+                }
             }
 
             break;
diff -Nru snort-2.4.4/src/preprocessors/xlink2state.c 
snort-2.4.5/src/preprocessors/xlink2state.c
--- snort-2.4.4/src/preprocessors/xlink2state.c 2005-08-23 17:52:20.000000000 
+0200
+++ snort-2.4.5/src/preprocessors/xlink2state.c 2006-06-02 21:00:10.000000000 
+0200
@@ -38,7 +38,7 @@
 
 /* Pointer to current session data */
 XLINK2STATE *_xlink;
-static u_int       _xlink2state_ports[65535];
+static u_int       _xlink2state_ports[65536];
 static u_int       _xlink2state_disabled = 0;
 static u_int       _xlink2state_drop = 0;
 static Packet      *_xlink2state_pkt = NULL;
@@ -67,9 +67,6 @@
     /*  Set up commands we will watch for */
     SearchInit(1);
     
-    /*  Set up commands we will watch for */
-    SearchInit(1);
-    
     SearchAdd(0, "X-LINK2STATE", 0);
     
     SearchPrepPatterns(0);
Possible Evasion in http_inspect        Jennifer Steffens (Sourcefire) @ May 
31, 2006 18:32:28
Sourcefire is aware of a possible Snort evasion that exists in the http_inspect 
preprocessor. This evasion case only applies to protected Apache web servers. 
We have prepared fixes for both the 2.4 and 2.6 branches and will have fully 
tested releases, including binaries, available for both on Monday, June 5th.


Evasion Details:

The Apache web server supports special characters in HTTP requests that do not 
affect the processing of the particular request. The current target-based 
profiles for Apache in the http_inspect preprocessor do not properly handle 
these requests, resulting in the possibility that an attacker can bypass 
detection of rules that use the "uricontent" keyword by embedding special 
characters in a HTTP request.


Background Information:

It is important to note that this is an evasion and not a vulnerability. This 
means that while it is possible for an attacker to bypass detection, Snort 
sensors and the networks they protect are not at a heightened risk of other 
attacks.


Timeline:

Sourcefire has prepared fixes and is currently finalizing a complete round of 
testing to ensure that the fixes not only solve the issue at hand but do not 
create new bugs as well. The following releases, including binaries for Linux 
and Windows deployments, will be available on Monday, June 5th:

* Snort v2.4.5
* Snort v2.6.0 final


Questions:

Any questions regarding these releases can be sent to [EMAIL PROTECTED]

Attachment: signature.asc
Description: Digital signature

Reply via email to