Get the latest updates on how F5 mitigates Heartbleed

For those of you tuning in to learn more about the OpenSSL Heartbleed vulnerability, here are more details about it and how F5 customers are protected. The iRule below mitigates the Heartbleed vulnerability for virtual servers that do not use SSL termination.

 

This iRule is very similar to the client iRule, except it watches the server responses searching for a heartbeat. If it sees one that is longer than 128 bytes, it rejects the connection.

As TCP segments arrive, we pick out the TLS records, which are rarely aligned with the containing TCP segment. The current segment may contain zero or more TLS records. All we know for sure is that the first 5 bytes of the first segment is a TLS record header. In the presentation language of the TLSv1.2 protocol specification (RFC5246), a TLS record is called TLSPlaintext. Here’s the relevant presentation:

struct {
    uint8 major;
    uint8 minor;
} ProtocolVersion;
enum {
    change_cipher_spec(20), alert(21), handshake(22),
    application_data(23), (255)
} ContentType;
struct {
    ContentType type;
    ProtocolVersion version;
    uint16 length;
    opaque fragment[TLSPlaintext.length];
} TLSPlaintext;

The code will parse the first five bytes of TLSPlaintext, which includes the fields type, version and length. Because these are always unencrypted, we use these bytes to determine if the server is sending an exceptionally long heartbeat response message. If we see the attack, we log and reject the connection.
If the attack is not seen, we must skip the fragment, then look for another record header.

This script is almost identical to the client-side script we posted yesterday. But because there’s so much more data in a typical web server stream, this one will affect performance a bit more than the previous. The advantage here is that by examining the length of the heartbeat response, we can more reliably detect the attack, allowing non-attack heartbeats through.

It was difficult to find an off-the-shelf client that would actually send benign heartbeat requests. We just scripted one up for testing purposes. Curl and other OpenSSL-based clients will typically run with the library’s default behavior, which is to advertise support for heartbeats, but never actually send them.
If that’s true on your network, then use the client-side script we posted yesterday. If not, and you have valid uses of the client-side heartbeats, then use this script.

 

##############################################
# Name: Server side block_heartbleed iRule.
# Description: This irule will detect a long TLS heartbeat response
#   and reject the TCP connection. It uses TCP::collect and TCP::release
#   more efficiently, which results in a much lower performance
#   penalty compared with the previous version.
# VERSION: 2 - 12.apr.14
##############################################
when SERVER_CONNECTED {
  set Debug 1
  set HB_Size_Max 64
  TCP::collect 5
}
when SERVER_DATA {
  set Buf_Len [TCP::offset]
  set Skip_Len 0
  set Collect_Len 0
 while { $Collect_Len == 0 && $Buf_Len > 0 } {
    set Skip_Len 0
    set Collect_Len 0
    # Start of new Rec(s)
    binary scan [TCP::payload] cSS Rec_Type Version Rec_Len
    if { ($Rec_Type == 24) } {
      if { $Rec_Len > $HB_Size_Max } {
        if { $Debug > 0 } {
          log local0. [format "BIG HEARTBEAT len %i; conn reset" $Rec_Len $Rec_Len]
        }
        reject
        return
      } elseif { $Debug > 1 } {
        log local0. [format "HEARTBEAT len %i (%#x)" $Rec_Len $Rec_Len]
      }
    }
    TCP::release 5
    incr Buf_Len -5
    # From current buffer, release as much data as possible.
    if { $Rec_Len > 0 } {
      # Partial data. Prepare to passthru remainder, then collect next header.
      if { $Buf_Len < $Rec_Len } {
        TCP::release $Buf_Len
        incr Rec_Len -$Buf_Len
        set Skip_Len $Rec_Len
        set Collect_Len 5
      } else {
        # Complete data.
        TCP::release $Rec_Len
        set Rec_Len 0
      }
    }
    set Buf_Len [TCP::offset]
    # If buffer does not contain full next header, prepare to collect.
    if { $Buf_Len < 5 } {
      set Collect_Len 5
      incr Collect_Len -$Buf_Len
    }
    if { $Collect_Len > 0 } {
      if { $Skip_Len > 0 } {
        TCP::collect $Collect_Len $Skip_Len
      } else {
        TCP::collect $Collect_Len
      }
    }
  }
  return
}

With this new iRule, you can be assured that your servers will not leak information.