[<prev] [next>] [day] [month] [year] [list]
Message-ID: <CAKvVidR8TSopa=4Kvs4nKVLRGJf9hnkqFeAKkv-9o129p051qw@mail.gmail.com>
Date: Thu, 21 Mar 2019 11:32:12 +0100
From: Luca Moro <luca.moro@...acktiv.com>
To: netdev@...r.kernel.org
Cc: Nicolas Collignon <nicolas.collignon@...acktiv.com>,
Eloi Vanderbeken <eloi.benoist-vanderbeken@...acktiv.com>,
Corentin Bayet <corentin.bayet@...acktiv.com>
Subject: netfilter: missing correlation checks on icmp[v6] errors before
applying IP_CT_RELATED
Hello,
During a review of OpenBSD Packet Filter, we discovered a minor
security issue that also impacts netfilter.
When handling ICMP[v6] errors that encapsulate the original IP
datagram, there is no correlation check between the inner and outer IP
layers.
So one can encapsulate an error with an inner layer matching a known
connection, while its outer layer is directed to a filtered host.
In this case the whole packet will be tagged with the IP_CT_RELATED flag.
This has various implications from a rule bypass (if a rule allows
related trafic), to a known state oracle.
Unfortunately, we could not find a real statement in a RFC on how this
case should be filtered.
The closest we found is RFC5927 (Section 4.3) but it is not very clear.
A possible fix would be to check that the inner IP source is the same
than the outer destination.
For information here is what OpenBSD applied:
http://cvsweb.openbsd.org/cgi-bin/cvsweb/src/sys/net/pf.c?rev=1.1081&content-type=text/x-cvsweb-markup
http://cvsweb.openbsd.org/cgi-bin/cvsweb/src/sys/net/pf.c.diff?r1=1.1080&r2=1.1081&f=h
We are totally disposed to discuss the vulnerability and help in the fix.
If possible, we would also appreciate a citation for the discovery.
Here is the relevant code:
// /net/netfilter/nf_conntrack_proto_icmp.c
> icmp_error_message(struct nf_conn *tmpl, struct sk_buff *skb,
> const struct nf_hook_state *state)
> {
> // ...
>
> /* Are they talking about one of our connections? */
> if (!nf_ct_get_tuplepr(skb,
> skb_network_offset(skb) + ip_hdrlen(skb)
> + sizeof(struct icmphdr),
> PF_INET, state->net, &origtuple)) {
> pr_debug("icmp_error_message: failed to get tuple\n");
> return -NF_ACCEPT;
> }
>
> /* rcu_read_lock()ed by nf_hook_thresh */
> innerproto = __nf_ct_l4proto_find(origtuple.dst.protonum);
>
> /* Ordinarily, we'd expect the inverted tupleproto, but it's
> been preserved inside the ICMP. */
> if (!nf_ct_invert_tuple(&innertuple, &origtuple, innerproto)) {
> pr_debug("icmp_error_message: no match\n");
> return -NF_ACCEPT;
> }
>
> ctinfo = IP_CT_RELATED;
>
> h = nf_conntrack_find_get(state->net, zone, &innertuple);
> if (!h) {
> pr_debug("icmp_error_message: no match\n");
> return -NF_ACCEPT;
> }
>
> if (NF_CT_DIRECTION(h) == IP_CT_DIR_REPLY)
> ctinfo += IP_CT_IS_REPLY;
>
> /* Update skb to refer to this connection */
> nf_ct_set(skb, nf_ct_tuplehash_to_ctrack(h), ctinfo);
> return NF_ACCEPT;
> }
Best Regards.
Luca Moro
Synacktiv
Powered by blists - more mailing lists