TL;DR:

Only do this if you can't change your application/device in your network and you want to kill SSLv3 on network level.

Example for logging SSLv3 outbound connections on your host. Run:

iptables -I OUTPUT 1 \
  -p tcp \! -f --dport 443 \
  -m state --state ESTABLISHED -m u32 --u32 \
  "0>>22&0x3C@ 12>>26&0x3C@ 0 & 0xFFFFFF00=0x16030000 && \
   0>>22&0x3C@ 12>>26&0x3C@ 2 & 0xFF=0x01 && \
   0>>22&0x3C@ 12>>26&0x3C@ 7 & 0xFFFF=0x0300" \
  -j LOG --log-prefix "SSLv3 Client Hello detected: " # or -j DROP ...

The above will only log them and show up in your kernel messages like this:

[11318.883379] SSLv3 Client Hello detected: IN= OUT=eth0 SRC=192.168.31.10 DST=74.208.162.100 LEN=154 [...]
[11318.889486] SSLv3 Client Hello detected: IN= OUT=eth0 SRC=192.168.31.10 DST=74.208.162.100 LEN=154 [...]

Adjust this OUTPUT chain to INPUT for an SSL server and to the FORWARD chain on a gateway. And change -j LOG --log-prefix ... to -j DROP or -j REJECT to actually block the traffic.

Danger

Don't use this in production to mitigate POODLE now. That would be silly. I haven't tested this on an actual downgrade attack. But let me know what you think.

Do I need this?

No, you should be disabling SSLv3 properly on application level. However, there could be use cases for blocking a protocol on network level. For example:

  • An appliance or server application that does not offer a way to disable SSLv3 (or at least CBC ciphersuites in SSLv3).
  • You can't change all browser client configurations in your network, but you abolutely need to turn off SSLv3.

Then a firewall block could be your last resort.

iptables and SSL-level?

How can one determine the SSLv3 packets? iptables can't work at that level, right? Well, it can. I remembered from the Heartbleed attack, I saw some magic iptables commands mitigating Heartbleed. Will it work for killing SSLv3 too? Let's find out!

SSLv3 versus TLSv1+

First, let's take a look at how an SSLv3 handshake looks in Wireshark.

SSLv3 handshake in Wireshark

And below the handshake for TLSv1 (TLSv1.2 in this case).

TLSv1.2 handshake in Wireshark

Based on pure assumption I'm deciding that this selection based on those four conditions is quite reliable for machting a true SSLv3 Client Hello packet.

Selecting the right data in iptables

In order to quickly detect the packet based on the highlighted items, one can use the u32 iptables extension. It handles matches per 4 bytes (32 bits) and here's a quickly drawn scheme on the offsets and masks in order to match the right stuff in the payload.

Data and offsets for fields in SSLv3 Client Hello payload

The hard part was selecting the right offsets for the TCP payload. I've found this tutorial on the u32 iptables extension which explains how 0>>22&0x3C@ 12>>26&0x3C@ sets the offset right on the TCP payload: http://www.stearns.org/doc/iptables-u32.current.html. Nice!

Then it's just doing the work using the documentation, resulting in the following u32 'selector' for SSLv3 Client Hello.

0>>22&0x3C@ 12>>26&0x3C@ 0 & 0xFFFFFF00=0x16030000 && \
0>>22&0x3C@ 12>>26&0x3C@ 2 & 0xFF=0x01 && \
0>>22&0x3C@ 12>>26&0x3C@ 7 & 0xFFFF=0x0300

Inserting it in your iptables chain

If you want to protect your host running SSL clients (e.g. your workstation with a browser), you'll want to block SSLv3 Client Hello outbound packets (OUTPUT chain) and SSLv3 Server Hello inbound packets (INPUT chain). I haven't constructed nor tested any rule for Server Hello messages yet, but see below in 'Future work' for more on that.

You probably want to insert the rule above the regular rules.

$ sudo iptables -L -n -v
[...]
Chain OUTPUT (policy DROP 280 packets, 118K bytes)
 pkts bytes target     prot opt in     out     source               destination         
 2990  265K ACCEPT     all  --  *      lo      0.0.0.0/0            0.0.0.0/0            /* 001 accept all outbound to lo interface */
 841K  138M ACCEPT     all  --  *      *       0.0.0.0/0            0.0.0.0/0            /* 003 accept related outbound established rules */ ctstate RELATED,ESTABLISHED
 1449 93561 ACCEPT     udp  --  *      *       0.0.0.0/0            192.168.30.2         multiport dports 53 /* 100 accept outbound DNS to local recursor */
[...]

If the above is like what you have, then insert a rule on top like this:

$ sudo iptables -I OUTPUT 1 [...]

Before we actually construct the full example we'll have to look at performance.

Performance

Using solely the above u32 rule would be VERY slow as it parses all traffic on that chain. How can we optimize this? Be more specific!

Prepend the following extra selectors.

  • -p tcp \! -f --dport 443
    Selects only TCP with destination port 443 which are not fragments.
  • -m state --state ESTABLISHED
    Only look at packets which have obtained the ESTABLISHED state (TCP).

This then finally leads up to the example at the top of the page which should result in an output like this:

$ sudo iptables -L -n -v
[...]
Chain OUTPUT (policy DROP 280 packets, 118K bytes)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 LOG        tcp  !f  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:443 state ESTABLISHED u32 "0x0>>0x16&0x3c@0xc>>0x1a&0x3c@0x0&0xffffff00=0x16030000&&0x0>>0x16&0x3c@0xc>>0x1a&0x3c@0x2&0xff=0x1&&0x0>>0x16&0x3c@0xc>>0x1a&0x3c@0x7&0xffff=0x300" LOG flags 0 level 4 prefix "SSLv3 Client Hello detected: "
 2990  265K ACCEPT     all  --  *      lo      0.0.0.0/0            0.0.0.0/0            /* 001 accept all outbound to lo interface */
 841K  138M ACCEPT     all  --  *      *       0.0.0.0/0            0.0.0.0/0            /* 003 accept related outbound established rules */ ctstate RELATED,ESTABLISHED
 1449 93561 ACCEPT     udp  --  *      *       0.0.0.0/0            192.168.30.2         multiport dports 53 /* 100 accept outbound DNS to local recursor */
[...]

Testing

You can use the SSLv3 server from https://www.poodletest.com/ like this in an OpenSSL command line:

$ openssl s_client -connect sslv3.dshield.org:443
[...]
SSL-Session:
    Protocol  : SSLv3
[...]

Verify the session is established using SSLv3. Then watch your logs.

Tip

Use iptables -Z to clear the counters and check the iptables -L -n -v output repeatedly for increasing counters.

Further work, TODO

  • Improving the conditionals for starting on u32 matching to improve performance.
    Maybe using the -m connbytes --connbytes 0:<nbytes> to grab only a certain amount of data from a stream. See also this discussion.
  • Include blocking SSLv3 Sever Hello. A downgrade attack or even an alternative way to connect with SSLv3 may not always involve a Client Hello as pointed out in the above discussion.
  • Ensuring/testing on a gateway (FORWARD chain) and how to configure this on OpenWRT for example.

More ideas? Or suggestions? Let me know via Twitter or in the Disqus comments below!

Share on: TwitterHacker NewsFacebookLinkedInRedditEmail


Related Posts


Published

Category

Security

Tags

Connect with me on...