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=220.127.116.11 LEN=154 [...] [11318.889486] SSLv3 Client Hello detected: IN= OUT=eth0 SRC=192.168.31.10 DST=18.104.22.168 LEN=154 [...]
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.
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.
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.
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!
First, let's take a look at how an SSLv3 handshake looks in Wireshark.
And below the handshake for TLSv1 (TLSv1.2 in this case).
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.
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.
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.
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
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 (
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.
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 */ [...]
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.
iptables -Z to clear the counters and check the
iptables -L -n -v output repeatedly for increasing counters.
- 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 (
FORWARDchain) and how to configure this on OpenWRT for example.
More ideas? Or suggestions? Let me know via Twitter or in the Disqus comments below!