TCP/IP Stack Hardening
Tuning the Kernel
If you run a UNIX-like operating system, you can make it more secure by slightly modifying the behavior of its TCP/IP implementation. This page describes how to modify the kernel of the running operating system, and thereby modify and harden the various TCP/IP protocols. So, this topic will not make much sense unless you understand the protocols! Read Doug Comer's Internetworking with TCP/IP: Volume One. He did a great job of making a dry topic easy to read and understand.
The current edition is rather expensive, but look for used or remaindered older editions. Those editions will have what you need for this.
Do be careful — he wrote a three-volume series. You probably want Volume 1, which describes the protocols. Volumes 2 and 3 show how to implement a protocol stack in an operating system and how to write applications based on that platform, respectively.
For the most part, the following are commands
that would go into a boot script such as
/etc/rc.sysinit
or
/etc/rc.local
.
Linux uses the files /etc/sysctl.conf
and /etc/sysctl.d/*.conf
.
As described in my detailed description of how
Linux has evolved,
you want to leave the file /etc/sysctl.conf
alone and add your customizations in a new file named
something like /etc/sysctl.d/99-hardening.conf
.
Changes in the distributions *.conf
files
can be lost or, more likely, lead to headaches every time
you update packages.
The tables only list the possible commands — some tuning steps are not possible (at least as far as I know) on certain UNIX implementations.
If there is a dangerous type of packet that might be allowed under a strict interpretation of the protocols, but which is currently considered to be risky, the listed commands frequently list how to both ignore inbound packets and refuse to send outbound packets. This prevents your host from being victimized and prevents it from being used to launch attacks.
This page only describes how to harden the TCP/IP stack on UNIX-like operating systems. It is based on the recommendations found in the following pages, plus my commentary and explanation.
Ipsysctltutorial
On a Linux system, see the file
/usr/src/linux/Documentation/filesystems/proc.txt
.
Also see Oskar Andreasson's great
Ipsysctl tutorial.
Sun had a BigAdmin Resource on tuning the Solaris TCP/IP stack. That page has long since disappeared from the Internet, although The Internet Archive has a copy. However, that simply pointed to this excellent page.
ARP
Decrease the ARP cache cleanup interval.
AIX |
no -o arpt_killc=20
|
FreeBSD |
sysctl -w net.link.ether.inet.max_age=1200
|
Linux |
sysctl -w net.ipv4.neigh.default.gc_interval=30
|
Solaris |
ndd -set /dev/arp arp_cleanup_interval 60000
|
For Linux, per the
arp(7)
manual page,
gc_interval
value specifies how frequently
the garbage collector for neighbor entries should run,
in seconds.
It should already be defaulting to 30 seconds,
so the above shouldn't change anything.
The directory /proc/sys/net/ipv4/neigh
contains a subdirectory neigh
whose values
apply to all interfaces, plus one subdirectory specific
to each detected interface.
Note that /proc/sys/net/ipv[46]/neigh
contains subdirectories named default
plus one for each detected interface.
The variables in default
apply to all,
they are overridden by variables in the interface-specific
collections.
The directory /proc/sys/net/ipv[46]/conf
has that plus a subdirectory all
.
Variables in all
apply immediately,
variables in default
apply to interfaces
not yet detected.
Consider static ARP (but also consider the maintenance problems!). This does not scale well to routine use on typical LANs, especially if the hardware changes often, but it might be worth its trouble on a small sensitive LAN — a DMZ LAN in your network perimeter, or a small LAN populated by a few sensitive servers and a router port. Remember that if you change the Ethernet card in one machine, you must then modify and re-run the static ARP script boot script on every host on that LAN!
If you want to do this, you will need a script like the following, with IP and MAC addresses changed as needed. For thorough paranoia, define a MAC address for all possible IP addresses on the LAN, even ones not in use. For the unused IP addresses, use a MAC address that you know will not exist on that LAN (maybe that of an Ethernet card on another LAN).
arp -s 10.1.1.1 00:02:E3:05:9F:A3 ... and so on ...
|
ICMP
Disable ICMP broadcast echo activity. Otherwise, your system could be used as part of a Smurf attack:
AIX |
no -o directed_broadcast=0
|
FreeBSD |
sysctl -w net.inet.icmp.bmcastecho=0
|
HP-UX |
ndd -set /dev/ip ip_respond_to_echo_broadcast 0
|
IRIX |
systune allow_brdaddr_srcaddr 0
|
Linux |
sysctl -w net.ipv4.icmp_echo_ignore_broadcasts=1
|
OpenBSD | Already ignores these by default |
Solaris |
ndd -set /dev/ip ip_respond_to_echo_broadcast 0 |
Disable ICMP routing redirects. Otherwise, an attacker could corrupt your system's routing table.
AIX |
no -o ipignoreredirects=1 |
FreeBSD |
sysctl -w net.inet.ip.redirect=0 |
HP-UX |
ndd -set /dev/ip ip_send_redirects 0
|
IRIX |
systune icmp_dropredirects 1
|
Linux |
sysctl -w net.ipv4.conf.all.accept_redirects=0 |
OpenBSD |
sysctl -w net.inet.icmp.rediraccept=0 Those two disable the acceptance of ICMP Redirect. To disable sending ICMP Redirect messages: sysctl -w net.inet.ip.redirect=0
|
Solaris |
ndd -set /dev/ip ip_ignore_redirect 1 |
On Linux, setting secure_redirects
to 1 (on)
as shown above means that the kernel will not
accept ICMP redirects from any host, but only from a
default gateway.
The shared_media
variable overrides this,
so also turn it on.
Disable IPv4 ICMP router solicitations and advertisements, and ICMP subnet mask requests and replies. And of course do not disable this on IPv6. An attacker might be able to use unsolicited advertisements and replies to corrupt host routing tables. An attack also might be able to use solicitations and requests to reverse engineer some details of your network infrastructure. It appears that you will have to do this with packet-filtering rules on the host.
Disable ICMP broadcast probes. Otherwise, an attacker might be able to reverse engineer some details of your network infrastructure.
AIX |
no -o icmpaddressmask=0
|
FreeBSD |
sysctl -w net.inet.icmp.maskrepl=0
|
HP-UX |
ndd -set /dev/ip ip_respond_to_address_mask_broadcast 0 |
IRIX | You will have to block these with
a packet filter like
ipfilterd |
Linux | You will have to block these with
a packet filter like
iptables |
OpenBSD | Already ignores these by default |
Solaris |
ndd -set /dev/ip ip_respond_to_address_mask_broadcast 0 |
IP
Disable IP source routing. The only use of IP source routing these days is by attackers trying to spoof IP addresses that you would trust as internal hosts.
AIX |
no -o ipsrcroutesend=0 |
FreeBSD |
sysctl -w net.inet.ip.sourceroute=0 |
HP-UX |
ndd -set /dev/ip ip_src_route_forward 0
|
IRIX |
systune ipforward 2
(by Irix 5.6.22, this was ipforwarding ) |
OpenBSD | Already ignores these by default |
Solaris |
ndd -set /dev/ip ip_forward_src_routed 0 |
It seems that Linux no longer supports source routing.
That's good, as it wasn't useful for much of anything
besides causing trouble.
But if you're stuck running rather old Linux kernels,
such as what you find with Red Hat Enterprise Linux 6,
set net.ipv4.conf.all.accept_source_route
to 0
.
Enforce sanity checking, also called ingress filtering or egress filtering. The point is to drop a packet if the source and destination IP addresses in the IP header do not make sense when considered in light of the physical interface on which it arrived.
Linux |
sysctl -w net.ipv4.conf.all.rp_filter=1
|
Log and drop "Martian" packets. A "Martian" packet is one for which the host does not have a route back to the source IP address (it apparently dropped in from Mars). These days most hosts have a default route, meaning that there would be no such thing as a Martian packet, but to be safe and complete...
Linux |
sysctl -w net.ipv4.conf.all.log_martians=1
|
Enforce strict multi-homing for non-forwarding multi-homed systems. If a host is connected to more than one LAN, but it should not act as an IP router, make certain that it does not forward IP datagrams between networks. Maybe it is a firewall, or maybe it is just a multi-homed host.
Solaris |
ndd -set /dev/ip ip_strict_dst_multihoming 1 |
TCP
Increase resiliance under heavy TCP load (which makes the system more resistant to SYN Flood attacks). There are five major steps to making a system more resiliant under heavy, possibly malicious, TCP load:
1: Buy more RAM. Each inbound SYN packet is intended to establish a TCP circuit, which requires resources on the server. The TCP buffers require memory to be allocated.
2: Use TCP SYN Cookies (Linux and BSD only). With TCP Syn Cookies, the kernel does not really allocate the TCP buffers unless the server's ACK/SYN packet gets an ACK back, meaning that it was a legitimate request.
3: Reduce the allowed number of HALF_OPEN TCP connections. Further requests are refused, a denial of service, but at least the server hasn't run out of memory. This chooses one problem over another.
4: Reduce the amount of time an opening TCP circuit can stay in the HALF_OPEN state. The server is made less patient — if the TCP circuit is not fully established quickly, it is dropped. The client, if legitimate but very slow, must start again. Default timeouts tend to be based on recommendations from when IP and TCP were being developed in the late 1970s and very early 1980s. 60 second timeouts make no sense when round-trip time to the other side of the world is under a second.
5: Reduce the amount of time a closing TCP circuit can stay in the TIME_WAIT state. Some clients are very rude, Microsoft Explorer used to be particularly bad. They establish a connection, get their data, but then refuse to participate in cleanly shutting down the TCP circuit. At least for busy web servers, make them very impatient with such nonsense, dropping these no longer active connections and freeing resources.
The following show the vendor recommendations for tuning the TCP queue length and circuit establishment timers, and how to reduce TCP TIME_WAIT to 3 seconds.
AIX |
no -o clean_partial_conns=1
|
FreeBSD |
sysctl -w kern.ipc.maxsockbuf=2097152 |
HP-UX |
ndd -set /dev/tcp tcp_syn_rcvd_max 1024 |
IRIX |
systune tcp_2msl 3 The kernel automatically limits the queue of pending connections. |
Linux |
sysctl -w net.ipv4.tcp_max_syn_backlog=1280
|
OpenBSD | Already has a resilient TCP implementation by default |
Solaris |
ndd -set /dev/tcp tcp_conn_req_max_q 1024 |
For FreeBSD, see the /etc/sysctl.conf
discussion
here.
The value of 2097152 (2 MB) for maxsockbuf
is good for 1 Gbps Ethernet,
use 16777216 (16 MB) for 10 Gbps.
Setting rexmtlimit
means it will not
retransmit ACK/SYN to clients that do not complete
the TCP 3-way handshake.
Variables finwait2_timeout
and
msl
are the TCP FIN_WAIT_2 timeout
(which defaults to 60 seconds)
and the Maximum Segment Lifetime or time the
connection may stay in TIME_WAIT state
(default is 30,000 milliseconds),
respectively.
Defend against TCP connection hijacking by following the recommendations of RFC 1948. Most UNIX implementations use RFC 1948 recommendations to generate initial sequence numbers, but Solaris (at least up through Solaris 8) needs a little help.
Solaris |
ndd -set /dev/tcp tcp_strong_iss 2 To configure this behavior to be the default after future reboots, put the line TCP_STRONG_ISS=2
in the file
/etc/default/inetinit
|
Increase TCP send and receive window sizes to at least
32 kbytes.
But do not increase these above 64 kbytes unless
you fully understand and support both
RFC 1323
and
RFC 2018.
For FreeBSD, see the /etc/sysctl.conf
discussion
here.
AIX |
no -o tcp_sendspace=32768 |
FreeBSD |
sysctl -w net.inet.tcp.sendspace=32768 |
HP-UX | The TCP send and receive spaces are 32 kbytes by default. |
IRIX | The TCP send and receive spaces are 64 kbytes by default. |
Linux | The kernel supports RFC 1323 and RFC 2018 and dynamically adjusts the TCP send and receive space by default |
OpenBSD | The kernel supports RFC 1323 and RFC 2018 and dynamically adjusts the TCP send and receive space by default |
Solaris |
ndd -set /dev/tcp tcp_xmit_hwat 32768 |