Protecting SSH Servers with Single Packet Authorization
Last month, in the first of a two-part series, I described the theory behind the next generation in passive authentication technologies called Single Packet Authorization (SPA). This article gets away from theory and concentrates on the practical application of SPA with fwknop and iptables to protect SSHD from reconnaissance and attack. With this setup on a Linux system, no one will be able to tell that SSHD is even listening under an nmap scan, and only authenticated and authorized clients will be able to communicate with SSHD.
To begin, we require some information about configuration and network architecture. This article assumes you have installed the latest version of fwknop (1.0.1 at the time of this writing) on the same system where SSHD and iptables are running. You can download fwknop from www.cipherdyne.org/fwknop and install either from the source tar archive by running the install.pl script or via the RPM for RPM-based Linux distributions.
The basic network depicted in Figure 1 illustrates our setup. The fwknop client is executed on the host labeled spa_client (126.96.36.199), and the fwknop server (along with iptables) runs on the system labeled spa_server (188.8.131.52). A malicious system is labeled attacker (184.108.40.206), which is able to sniff all traffic between the spa_client and spa_server systems.
The spa_client system has the IP address 220.127.116.11, and the spa_server system has the IP address 18.104.22.168. On the spa_server system, iptables is configured to provide basic connectivity services for the internal network (192.168.10.0/24) and to log and drop all attempts (via the iptables LOG and DROP targets) from the external network to connect to any service on the firewall itself. This policy is quite simplistic, and it is meant to show only that the firewall does not advertise any services (including SSHD) under an nmap scan. Any serious deployment of iptables for a real network would be significantly more complicated. One important feature to note, however, is that the connection tracking facilities provided by Netfilter are used to keep state in the iptables policy. The end result is that connections initiated through the firewall (via the FORWARD chain) and to the firewall (via the INPUT chain) remain open without additional ACCEPT rules to allow packets required to keep the connections established (such as TCP acknowledgements and the like). The iptables policy is built with the following basic firewall.sh script:
[spa_server]# cat firewall.sh #!/bin/sh IPTABLES=/sbin/iptables $IPTABLES -F $IPTABLES -F -t nat $IPTABLES -X $IPTABLES -A INPUT -m state --state ↪ESTABLISHED,RELATED -j ACCEPT $IPTABLES -A FORWARD -m state --state ↪ESTABLISHED,RELATED -j ACCEPT $IPTABLES -t nat -A POSTROUTING -s ↪192.168.10.0/24 -o eth0 -j MASQUERADE $IPTABLES -A INPUT -i ! lo -j LOG --log-prefix ↪"DROP " $IPTABLES -A INPUT -i ! lo -j DROP $IPTABLES -A FORWARD -i ! lo -j LOG --log-prefix ↪"DROP " $IPTABLES -A FORWARD -i ! lo -j DROP echo 1 > /proc/sys/net/ipv4/ip_forward echo "[+] iptables policy activated" exit [spa_server]# ./firewall.sh [+] iptables policy activated
With iptables active, it is time to see what remote access we might have. From the spa_client system, we use nmap to see if SSHD is accessible on the spa_server system:
[spa_client]$ nmap -P0 -sT -p 22 22.214.171.124 Starting Nmap 4.01 ( http://www.insecure.org/nmap/ ) at 2007-02-09 23:55 EST Interesting ports on 126.96.36.199: PORT STATE SERVICE 22/tcp filtered ssh Nmap finished: 1 IP address (1 host up) scanned in 12.009 seconds
As expected, iptables is blocking all attempts to communicate with SSHD, and the remaining ports (both TCP and UDP) are similarly protected by the iptables policy. It does not matter if an attacker has a zero-day exploit for the particular version of OpenSSH that is deployed on the spa_server system; all attempts to communicate up the stack are being blocked by iptables.
Confident that iptables is protecting the local network with a Draconian stance, it is time to configure the fwknop server dæmon (fwknopd) on the spa_server system. The file /etc/fwknop/fwknop.conf controls important configuration parameters, such as the interface on which fwknopd sniffs traffic via libpcap, the e-mail address(es) to which fwknopd sends informational alerts and the pcap filter statement designed to sniff SPA packets off the wire. By default, fwknop sends SPA packets over UDP port 62201, so the pcap filter statement in /etc/fwknop/fwknop.conf is set to udp port 62201 by default. However, SPA packets can be sent over any port and protocol (even over ICMP), but the filter statement would need to be updated to handle SPA communications over other port/protocols. More information can be found in the fwknop man page. Although the defaults in this file usually make sense for most deployments, you may need to tweak the PCAP_INTF and EMAIL_ADDRESSES variables for your particular setup.
The /etc/fwknop/access.conf file is the most important fwknopd configuration file—it manages the encryption keys and access control rights used to validate SPA packets from fwknop clients. The following access.conf file is used for the remainder of this article:
[spa_server]# cat /etc/fwknop/access.conf SOURCE: ANY; OPEN_PORTS: tcp/22; FW_ACCESS_TIMEOUT: 30; KEY: LJ07p2rbga; GPG_DECRYPT_ID: ABCD1234; GPG_DECRYPT_PW: p2atc1l30p; GPG_REMOTE_ID: 5678DEFG; GPG_HOME_DIR: /root/.gnupg;
The SOURCE variable defines the IP addresses from which fwknopd accepts SPA packets. The value ANY shown above is a wild card to examine SPA packets from any IP address, but it can be restricted to specific IP addresses or subnets, and comma-separated lists are supported (for example, 192.168.10.0/24, 188.8.131.52). The OPEN_PORTS variable informs fwknopd about the set of ports that should be opened upon receiving a valid SPA packet; in this case, fwknopd will open TCP port 22.
Although not shown above, fwknopd can be configured to allow the fwknop client to dictate the set of ports to open by including the PERMIT_CLIENT_PORTS variable and setting it to Y. FW_ACCESS_TIMEOUT specifies the length of time that an ACCEPT rule is added to the iptables policy to allow the traffic defined by the OPEN_PORTS variable. Because the iptables policy in the firewall.sh script above makes use of the connection tracking capabilities provided by Netfilter, an SSH connection will remain established after the initial ACCEPT rule is deleted by fwknopd.
The remaining variables define parameters for the encryption and decryption of SPA packets. This article illustrates the usage of both symmetric and asymmetric ciphers, but only one encryption style is required by fwknop.
All of the GPG_* variables can be omitted if there is a KEY variable and vice versa. The KEY variable defines a shared key between the fwknop client and fwknopd server. This key is used to encrypt/decrypt the SPA packet with the Rijndael symmetric block cipher (see Resources). For asymmetric encryption, GPG_DECRYPT_ID defines the local fwknopd server GnuPG key ID. This key is used by the fwknop client to encrypt SPA packets via an encryption algorithm supported by GnuPG (such as the ElGamal cipher).
GPG_DECRYPT_PW is the decryption password associated with the fwknopd server key. Because this password is placed within the access.conf file in clear text, it is not recommended to use a valuable GnuPG key for the server; a dedicated key should be generated for the purpose of decrypting SPA packets. The fwknop clients sign SPA packets with a GnuPG key on the local key ring, and the password is supplied by the user from the command line and never stored within a file (as we will see below). Hence, any GnuPG key can be used by the fwknop client; even a valuable key used for encrypting sensitive e-mail communications, for example.
The GPG_REMOTE_ID variable defines a list of key IDs that the fwknopd server will accept. Any SPA packet encrypted with the fwknopd server public key must be signed with a private key specified by the GPG_REMOTE_ID variable. This allows fwknopd to restrict the set of people who can gain access to a protected service (SSHD in our case) via a cryptographically strong mechanism. Instructions for creating GnuPG keys for use with fwknop can be found at www.cipherdyne.org/fwknop/docs/gpghowto.html.
With the /etc/fwknop/access.conf file built, it is time to start fwknopd on the spa_server system and put fwknop to work for us:
[spa_server]# /etc/init.d/fwknop start * Starting fwknop ... [ ok ]