Forum Discussion

aplovich_252762's avatar
aplovich_252762
Icon for Nimbostratus rankNimbostratus
Aug 19, 2016

Question on using STREAM to detect login failures

We use our F5 to load-balance exchange (IMAP, POP3, SMTP, ActiveSync), however since we're using SNAT, our exchange servers report login failures that associate the F5's SNAT IPs with the failing user (not helpful). We'd like to know the which user is failing logins, and from what IP.

 

The easiest solution seems to be switching to a 2-armed network, with the F5s as the gateway. However the current design is entrenched, so we can't make this change.

 

After some searching I found out about the STREAM:: irule expression, and figured I could use this to log when an email client fails authentication.

 

Thinking the workflow would work like so:

 

  1. CLIENT_CONNECTED, start STREAM and search for a specific login string (IE imap "a1 LOGIN USERNAME").
  2. once found, stash the USERNAME in a variable.
  3. SERVER_CONNECTED, stream is already enabled? so search for a specific deny message from the server.
  4. if the deny message is found, log the client::IP, USERNAME, and protocol (smtp, imap, ect) to syslog.
  5. disable the stream to ensure it stops using resources.

Questions:

 

  1. Once enabled, does STREAM search both sides (client/server) of the TCP connection?
  2. Do I need to make two STREAM::expression statements? one in CLIENT_CONNECTED and another in SERVER_CONNECTED, or should I just specify one statement with both the LOGIN and auth failure strings?
  3. Does anybody have any thoughts on doing it this way?

1 Reply

  • Hi Aplovich,

    using

    [STREAM]
    (or a manual
    [TCP::payload]
    or even
    [SSL::payload]
    parsing) as a basic IDS to detect and report login failurs should be possible and I really love this creative idea 🙂

    To shed some lights on your questions:

    1. Once enabled it will

      STREAM
      your request and responses packet wise.

    2. You could use a single expression for both sides. Using two independent expressions would require you to trigger the

      CLIENT_DATA
      and
      SERVER_DATA
      events to flip the search patterns, since a flip would be required for each single inbound/outbound TCP packet and not just for the initial connection establishment.

    3. I have a lots of additional thoughts for you...

    a.) Active Sync is HTTP and supports

    X-Forwarded-For
    headers. There is no need for
    [STREAM]
    .

    b.) SMTP uses HELO/EHLO commands to exchange freetext at the beginning of the conversation. You could embeded the orig_ip into this packet exchange and use your SMTP logfiles to identify the source IP.

    c.) IMAP and POP3 will most likely use a transport layer security. You have to deploy SSL Profiles to be able to MitM the conversation.

    d.) Fragmentation of the protocol conversation will bypass your

    [STREAM::expression]
    . (e.g. TCP-Nagle will fragment (TCP-PUSH) a conversation if a delay of >250ms between independent chars is detected.) To make the detection more robust, you will need to buffer and defragment the user input on each of its
    CRLF
    sequences using the
    CLIENT_DATA
    event (e.g.
    [TCP::collect]
    /
    [SSL::collect]
    with conditional
    [TCP::release]
    /
    [SSL::release]
    ).

    e.) If d.) is going to be implemented. Then it will be more effective to skip the

    [STREAM]
    approach and just use
    [string]
    ,
    [getfield]
    ,
    [findstr]
    and
    [substr]
    commands to parse the usernames.

    Hope this helps 🙂

    Cheers, Kai