[Snort-devel] Stream5: RST handling + 'STREAM5_BAD_RST' alert

Bram bram-fabeg at ...3414...
Wed Sep 18 15:33:08 EDT 2013


Was this message taken into consideration? (I received no reply)

Quoting Bram <bram-fabeg at ...3414...>:

> Hi,
>
>
> While looking at traffic which triggered the 'STREAM5_BAD_RST' alert  
>  I've found some (potential) issues..
>
>
> * snort_stream5_tcp.c: 'ValidRst' function:
>
> This issue is more of a configuration question/remark and not   
> necessarily a bug in the code:
>
> First the comments before the function:
>        // per rfc 793 a rst is valid if the seq number is in window
>        // for all states but syn-sent (handled above).  however, we
>        // validate here based on how various implementations actually
>        // handle a rst.
>
> The question however is how the stream5 streamprocessor should be configured?
> What if it's a connection between a Linux system and a Windows system?
> The code in 'ValidRST' appears to be stricter for Windows than for Linux?
> What if the OS of one of the peers is unknown?
> And by extension: what if the OS of both peers is unknown? (a DHCP   
> client connection to a server on internet for example)
>
> Looking at the code: this also means Windows (for example) does not   
> accept all (RFC) valid RSTs?
> Based on what was this code written? A windows document? Trial and  
> error? ...?
>
> Either way: the message of the alert 'Reset outside window' is at  
> the  very least confusing..
> When the sequence number is inside the window but if/when the host   
> ignores the RST then (IMO) a different alert should be generated.
> Right now it looks like an invalid RST packet is send/received which  
>  is not really the case..
>
>
> * snort_stream5_tcp.c: 'Stream5GetWindow' function:
>
> Second issue: this does look like a bug:
>
> Code:
>     if ( st->l_window )
>     {
>         // don't use the window if we may have missed scaling
>         if ( !(lwssn->session_state & STREAM5_STATE_MIDSTREAM) )
>             return st->l_window;
>     }
>     // one way zero window is unitialized
>     // two way zero window is actually closed (regardless of scaling)
>     else if ( TwoWayTraffic(lwssn) )
>         return st->l_window;
>
>     // ensure the data is in the window
>     window = tdb->end_seq - st->r_win_base;
>
>     if ( window <  0 )
>         window = 0;
>
>     return (uint32_t)window;
>
>
> The 'window scaling' option is part of the SYN and SYN+ACK packet.
> If I read the code in 'ProcessTcp' correctly then   
> 'STREAM5_STATE_MIDSTREAM' gets set when data is seen on the  
> connection  but the SYN or the SYN+ACK was not seen.
>
> I believe the intent of the code in 'Stream5GetWindow' is to only  
> use  'window scaling' when the SYN and SYN+ACK were seen.
> This is however not what the code appears to be doing.
>
> Code:
>         // don't use the window if we may have missed scaling
>         if ( !(lwssn->session_state & STREAM5_STATE_MIDSTREAM) )
>             return st->l_window;
>
>
> If I read the code correctly:
> - When the SYN or SYN+ACK is missing then 'lwssn->session_state &   
> STREAM5_STATE_MIDSTREAM' will return a value.
> - This value is then negated.
> - Which means: if the 'STREAM5_STATE_MIDSTREAM' flag is set then the  
>  code will continue (using scaling), when it's not set it will   
> immediately return 'st->l_window' (not using scaling)
>
> I believe the code should read:
>         // don't use the window if we may have missed scaling
>         if ( lwssn->session_state & STREAM5_STATE_MIDSTREAM )
>             return st->l_window;
>
>
> This can lead to false positives but no attempt has been made to   
> trigger this particular case.
>
>
> * false positive?
>
> Attached are two dumps of the same TCP stream: one taken on the  
> client  and one taken on the server.
> (TCP session recreated based on a SMTP session between two linux hosts.)
>
> Config:
>        config checksum_mode: all
>        dynamicpreprocessor directory /usr/lib/snort_dynamicpreprocessor/
>        preprocessor stream5_global: track_tcp yes, \
>           track_udp no, \
>           track_icmp no, \
>           max_tcp 262144, \
>           max_udp 131072
>        preprocessor stream5_tcp: policy linux, detect_anomalies
>
>        alert ( msg: "STREAM5_BAD_RST"; sid: 15; gid: 129; rev: 1;  
> metadata:  rule-type preproc ; )
>
>        output alert_fast: stdout
>
> Running it:
>        $ snort -v -l /var/log -c /etc/ips/snort.conf --daq-dir  
> /lib/daq/ -r  /tmp/client.cap 2>&1 | grep '129:'
>
>        $ snort -v -l /var/log -c /etc/ips/snort.conf --daq-dir  
> /lib/daq/ -r  /tmp/server.cap 2>&1 | grep '129:'
>        08/23-11:14:37.257018  [**] [129:15:1] Reset outside window  
> [**]  [Priority: 0] {TCP} 10.11.1.2:5556 -> 10.10.1.1:5555
>
> Looking with gdb with the 'server.cap' shows that the alert is   
> generated on the first RST packet (packet 9).
> Breaking in the 'ValidRST' function shows:
> - tdb->end_seq = 100010
> - st->r_win_base = 100020
>
> The first check in the code checks that 'tdb->end_seq' is greater   
> than/or equal to 'st->r_win_base'.
> This is not the case --> alert is generated.
>
> My guess is that this happens because the server already send an ACK  
>  for the data up to sequence '100020'.
> The client then sends a RST with sequence '100010' and a RST with   
> sequence '100020'.
>
> This appears to be standard Linux behaviour..
> When it sends a RST packet it appears to be using the 'ACK' number  
> of  the receiving packet as sequence number.
>
> I'm not sure if this can be considered a false positive or not..
>
> Looking at RFC 793 shows:
>   Reset Generation
>
>   As a general rule, reset (RST) must be sent whenever a segment arrives
>   which apparently is not intended for the current connection.  A reset
>   must not be sent if it is not clear that this is the case.
>
>   There are three groups of states:
>
>     1.  If the connection does not exist (CLOSED) then a reset is sent
>     in response to any incoming segment except another reset.  In
>     particular, SYNs addressed to a non-existent connection are rejected
>     by this means.
>
>     If the incoming segment has an ACK field, the reset takes its
>     sequence number from the ACK field of the segment, otherwise the
>     reset has sequence number zero and the ACK field is set to the sum
>     of the sequence number and segment length of the incoming segment.
>     The connection remains in the CLOSED state.
>
> This appears to be what linux is doing.
>
> The same RFC:
>   Reset Processing
>
>   In all states except SYN-SENT, all reset (RST) segments are validated
>   by checking their SEQ-fields.  A reset is valid if its sequence number
>   is in the window.  In the SYN-SENT state (a RST received in response
>   to an initial SYN), the RST is acceptable if the ACK field
>   acknowledges the SYN.
>
>
> It does not seem to specify how a RST packet with a sequence number   
> which is lower then the last acked segment should be handled...
>
>
>
> Best regards,
>
> Bram
>
>
>
> ----------------------------------------------------------------
> This message was sent using IMP, the Internet Messaging Program.
>
>



----------------------------------------------------------------
This message was sent using IMP, the Internet Messaging Program.





More information about the Snort-devel mailing list