COMMAND
kernel (IP Masquerading)
SYSTEMS AFFECTED
Linux 2.2.x
PROBLEM
H D Moore found following. Due to lax checking in the
masquerading kernel code, an attacker is able to rewrite a linux
masq gateway's UDP masquerading entries so that the remote host
and port are whatever they choose. This creates a tunnel between
whatever host and port they want and a UDP port on an inside
machine. The attacker is unable to tell what local inside ports
and addresses are being used, but they can determine the number
of currently masqueraded connections and the number of different
hosts using those connections behind the firewall. Any network
where UDP traffic is masqueraded to the outside is vulnerable to
this, including DNS, TFTP, NetBIOS, and a multitude of other
applications which rely on UDP transport. Since UDP is a
connectionless protocol, the only way to determine that a
masqueraded connection is no longer being used is by timing it
out due to lack of activity or receiving ICMP messages indication
the port is closed. The result is that there is a 5 minute
time-out by default for all masqueraded UDP sessions, allowing an
attacker enough time to find and exploit the connection with some
of the methods outlined in the Examples section below.
For those familiar with the linux masquerading system, please
jump to the next paragraph. IP masquerading is an implementation
of NAT (Network Address Translation) for the linux OS. It allows
you to connect an internal network using private addresses to an
external network (internet) in a fairly secure manner. All
packets coming from the internal network and destined for the
external network are rewritten so the source of those packets is
the masquerading gateway's external address and the source port
is the gateway's source port. This only requires one external IP
address to enable internet access for hundreds/thousands of
internal machines and is therefore a popular method for many
businesses and home users with broadband connections. The TCP
and UDP protocols require both source and destination ports as
well as source and destination addresses to work. The source
port for outgoing UDP/TCP connections is usually picked from the
first available port between 1024 and 65535 on the originating
host, so how does the masq gateway relay these connections AND be
able to use these protocols for its own networking? The kernel
sets aside the ports 61000 to 65096 by default for handling the
masqueaded connection entries, allowing for a theoretical maximum
of 4096 of both UDP and TCP connections at a time. These values
can be changed in the code or through the /proc file system. Now
when connection request from internal host A comes in from local
port 1035 and its destination is the external DNS server Host Z
on port 53, the masquerading machine adds a new entry to the
masquerading table that looks like this:
Host A:1035 (651001) -> Host Z:53
The port in paranthesis is the local port the gateway uses to
send the forwarded UDP datagrams from and the port it uses to
receive responses back from Host Z. The next paragraph describes
how the vulnerability found allows an attacker to modify the
right side of the above connection to allow traffic to come from
thier host back into the internal network to the local port on
the inside host.
The UDP masquerading code only checks the DESTINATION PORT to
determine if a packet coming from the external network is to be
forwarded inside. It then sets the remote HOST and PORT to the
source address and source port of the incoming packet. This is
due to a number of hosts/services returning UDP from an IP other
than that which the original UDP packet went to - for example it
is frequently the case that NFS servers just use the interface ip
address "closest" to that which the NFS op came from.
An attacker only needs to determine the local port on the masq
gateway to be able to rewrite the masq table with thier own
address and port, which is trivial considering the relatively
small port range set by default for use by masqueraded conenctions
(65100 - 65096). Now how do you determine which one of these
ports is the local port on the gateway for the masq connection?
Easy, we send a probe packet to each of these hosts and watch the
IP ID field in the responses. The IP ID field is sequentially
incremented on each host's TCP/IP stack for each packet they send
out, so the masq'd port ICMP response will have the IP ID of the
INTERNAL host, which is almost always at least 1000 away from the
current IP ID of the gateway machine. See the Examples section
below for packet traces of a complete scan/attack.
Examples. We know that example.com has a linux masquerading
gateway and that thier DNS server is outside of this firewall. We
can come to the conclusion that internal machines must be able to
contact the external DNS server to be able to access the
internet. We start sending our probe packets:
Host A is our internal workstation (192.168.1.100)
Host B is our masq gateway (192.168.1.1 / 10.0.0.1)
Host C is the DNS server (10.0.0.25)
Host X is the attacker (10.10.187.13)
ipchains -L -M -n on the masq gateway BEFORE the probes
> UDP 03:39.21 192.168.1.100 10.0.0.25 1035 (63767) -> 53
[ tcpdump from attacker's machine ]
( we picked source port 12345 for our packets just so the trace
would be easier to follow)
[ snip -- this starts at port 61000 ]
10.0.0.1 > 10.10.187.13: icmp: 10.0.0.1 udp port 63762 unreachable [tos
0xd8] (ttl 245, id 13135)
10.10.187.13.12345 > 10.0.0.1.63763: udp 0 (DF) [tos 0x18] (ttl 254, id
23069)
10.0.0.1 > 10.10.187.13: icmp: 10.0.0.1 udp port 63763 unreachable [tos
0xd8] (ttl 245, id 13136)
10.10.187.13.12345 > 10.0.0.1.63764: udp 0 (DF) [tos 0x18] (ttl 254, id
23070)
10.0.0.1 > 10.10.187.13: icmp: 10.0.0.1 udp port 63764 unreachable [tos
0xd8] (ttl 245, id 13137)
10.10.187.13.12345 > 10.0.0.1.63765: udp 0 (DF) [tos 0x18] (ttl 254, id
23071)
10.0.0.1 > 10.10.187.13: icmp: 10.0.0.1 udp port 63765 unreachable [tos
0xd8] (ttl 245, id 13138)
10.10.187.13.12345 > 10.0.0.1.63766: udp 0 (DF) [tos 0x18] (ttl 254, id
23074)
10.0.0.1 > 10.10.187.13: icmp: 10.0.0.1 udp port 63766 unreachable [tos
0xd8] (ttl 245, id 13139)
10.10.187.13.12345 > 10.0.0.1.63767: udp 0 (DF) [tos 0x18] (ttl 254, id
23083)
10.0.0.1 > 10.10.187.13: icmp: 10.0.0.1 udp port 63767 unreachable [tos
0xd8] (ttl 244, id 17205)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The above packet's ID is substantially different, we may have
found a masq'd connection !!!
10.10.187.13.12345 > 10.0.0.1.63768: udp 0 (DF) [tos 0x18] (ttl 254, id
23084)
10.0.0.1 > 10.10.187.13: icmp: 10.0.0.1 udp port 63768 unreachable [tos
0xd8] (ttl 245, id 13140)
10.10.187.13.12345 > 10.0.0.1.63769: udp 0 (DF) [tos 0x18] (ttl 254, id
23088)
10.0.0.1 > 10.10.187.13: icmp: 10.0.0.1 udp port 63769 unreachable [tos
0xd8] (ttl 245, id 13141)
10.10.187.13.12345 > 10.0.0.1.63770: udp 0 (DF) [tos 0x18] (ttl 254, id
23090)
10.0.0.1 > 10.10.187.13: icmp: 10.0.0.1 udp port 63770 unreachable [tos
0xd8] (ttl 245, id 13142)
10.10.187.13.12345 > 10.0.0.1.63771: udp 0 (DF) [tos 0x18] (ttl 254, id
23091)
10.0.0.1 > 10.10.187.13: icmp: 10.0.0.1 udp port 63771 unreachable [tos
0xd8] (ttl 245, id 13143)
10.10.187.13.12345 > 10.0.0.1.63771: udp 0 (DF) [tos 0x18] (ttl 254, id
23092)
10.0.0.1 > 10.10.187.13: icmp: 10.0.0.1 udp port 63772 unreachable [tos
0xd8] (ttl 245, id 13144)
[ snip -- all the way to the upper end of our masq ports ]
ipchains -L -M -n on the masq gateway AFTER the probes
> UDP 04:35.12 192.168.1.100 10.10.187.13 1035 (63767) -> 12345
^-------[ expiration of the udp tunnel has been updated ;)
We now have a working tunnel from our host to port 1035 on the
inside machine!
We have demonstrated that it is possible for us to 'hijack' the
enternal side of a masqueraded connection, so now what? There is
not a whole lot we can do to the closed local udp port on the
inside machine, so its time to examine other
applications/protocols that use UDP for transport and what
security risks there are in allowing unrestricted external access
to thier source ports. We leave this as an excercise to the
reader...
Following the "NetBIOS Info" thread on Incidents mailing list at
SF, Robert Graham mentioned a utility he wrote to automatically
respond to netbios port 137 name probes with a netbios name
lookup back to the originating host. He mentioned that it seems
to cut right through state-based firewalls and NAT systems
because the response probe looks like a response to the outgoing
probe. Assuming that a host on an inside network is sending out
these netbios name queries, an attacker could exploit the linux
2.2.x vulnerability and be able to query the netbios names of
internal machines. More info:
http://www.robertgraham.com/pubs/firewall-seen.html#netbios
SOLUTION
In general it is not advisable the use of UDP masq for a
firewalling gateway - since the only thing that people are
normally putting through the UDP side is DNS, you are much better
advised to put a decent caching name server on the gateway box
and block UDP through completely.
The core problem is precisely not being able to actually _know_
when internal box has closed the port. You can easily revert to
good"old" way (1 tunnel/pair) by commenting out
#define CONFIG_IP_MASQ_LOOSE_DEFAULT 1
at ip_masq.c:418 (stupid patch attached). This should drop
hijack'ing... Of course, if we change the default, some way to
enable it back perhaps on a per-application basis (ip_masq
module) MUST be done.
--- net/ipv4/ip_masq.c.dloose Thu Mar 30 14:51:06 2000
+++ net/ipv4/ip_masq.c Thu Mar 30 14:57:24 2000
@@ -415,7 +415,7 @@
/*
* By default enable dest loose semantics
*/
-#define CONFIG_IP_MASQ_LOOSE_DEFAULT 1
+/* #define CONFIG_IP_MASQ_LOOSE_DEFAULT 1 */
/*
The issues causing this DoS are apparently more complex than it
may appear according to the discussion in the Linux kernel mailing
list. There is a patch for the exploit in 2.2.15pre-16 and it is
a noteworthy amount of code.
If you downloaded pre-patch-2.2.15pre-16 you'll see following:
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla
/net/unix/af_unix.c linux.15pre16/net/unix/af_unix.c
--- linux.vanilla/net/unix/af_unix.c Sat Aug 14 02:27:46 1999
+++ linux.15pre16/net/unix/af_unix.c Tue Mar 28 17:27:52 2000
@@ -969,6 +969,10 @@
return -ENOTCONN;
}
+ err = -EMSGSIZE;
+ if (len > sk->sndbuf)
+ goto out;
+
if (sock->passcred && !sk->protinfo.af_unix.addr)
unix_autobind(sock);
This isn't so different from above (except the fact that the one
above checks len > sk->sndbuff - 16, thus limiting the sending
buffer).
Solution for SuSE Linux (they provide a patched 2.2.14 kernel to
ensure stability and not the 2.2.15 kernel):
ftp://ftp.suse.com/pub/suse/i386/update/6.4/kernel/k_deflt.rpm
ftp://ftp.suse.com/pub/suse/i386/update/6.4/kernel/k_eide.rpm
ftp://ftp.suse.com/pub/suse/i386/update/6.4/kernel/k_i386.rpm
ftp://ftp.suse.com/pub/suse/i386/update/6.4/d1/lx_suse-2.2.14.SuSE-24.i386.rpm