使用单包授权保护 SSH 服务器

作者:Michael Rash

上个月,在一个分为两部分的系列文章的第一部分中,我描述了下一代被动身份验证技术——单包授权(SPA)背后的理论。本文将抛开理论,专注于 SPA 的实际应用,使用 fwknop 和 iptables 来保护 SSHD 免受侦察和攻击。通过在 Linux 系统上进行此设置,任何人都无法通过 nmap 扫描来判断 SSHD 是否正在监听,只有经过身份验证和授权的客户端才能与 SSHD 通信。

首先,我们需要一些关于配置和网络架构的信息。本文假设您已在运行 SSHD 和 iptables 的同一系统上安装了最新版本的 fwknop(在撰写本文时为 1.0.1)。您可以从 www.cipherdyne.org/fwknop 下载 fwknop,并通过运行 install.pl 脚本从源代码 tar 存档安装,或者通过 RPM 为基于 RPM 的 Linux 发行版安装。

网络架构

图 1 中描述的基本网络说明了我们的设置。fwknop 客户端在标记为 spa_client (15.1.1.1) 的主机上执行,而 fwknop 服务器(以及 iptables)在标记为 spa_server (16.2.2.2) 的系统上运行。恶意系统标记为 attacker (18.3.3.3),它可以嗅探 spa_client 和 spa_server 系统之间的所有流量。

Protecting SSH Servers with Single Packet Authorization

图 1. 使用 SPA 保护 SSH 通信的示例场景

默认丢弃 iptables 策略

spa_client 系统的 IP 地址为 15.1.1.1,spa_server 系统的 IP 地址为 16.2.2.2。在 spa_server 系统上,iptables 配置为为内部网络 (192.168.10.0/24) 提供基本连接服务,并记录和丢弃来自外部网络连接到防火墙本身任何服务的所有尝试(通过 iptables LOG 和 DROP 目标)。此策略非常简单,仅旨在表明防火墙在 nmap 扫描下不通告任何服务(包括 SSHD)。对于真实网络的任何严肃的 iptables 部署都将更加复杂。但是,需要注意的一个重要功能是,Netfilter 提供的连接跟踪功能用于在 iptables 策略中保持状态。最终结果是,通过防火墙(通过 FORWARD 链)和到防火墙(通过 INPUT 链)发起的连接保持打开状态,而无需额外的 ACCEPT 规则来允许保持连接建立所需的数据包(例如 TCP 确认等)。iptables 策略是使用以下基本 firewall.sh 脚本构建的

[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

激活 iptables 后,是时候看看我们可能有什么远程访问权限了。从 spa_client 系统,我们使用 nmap 来查看是否可以访问 spa_server 系统上的 SSHD

[spa_client]$  nmap -P0 -sT -p 22 16.2.2.2

Starting Nmap 4.01 ( http://www.insecure.org/nmap/ )
at 2007-02-09 23:55 EST
Interesting ports on 16.2.2.2:
PORT   STATE    SERVICE
22/tcp filtered ssh

Nmap finished: 1 IP address (1 host up) scanned in
12.009 seconds

正如预期的那样,iptables 阻止了所有与 SSHD 通信的尝试,其余端口(TCP 和 UDP)也受到 iptables 策略的类似保护。攻击者是否拥有部署在 spa_server 系统上的特定版本的 OpenSSH 的零日漏洞并不重要;所有尝试向上层堆栈通信的尝试都被 iptables 阻止了。

fwknop SPA 配置

确信 iptables 正在以严厉的姿态保护本地网络后,是时候在 spa_server 系统上配置 fwknop 服务器守护程序 (fwknopd) 了。文件 /etc/fwknop/fwknop.conf 控制重要的配置参数,例如 fwknopd 通过 libpcap 嗅探流量的接口、fwknopd 发送信息警报的电子邮件地址以及旨在嗅探线路上的 SPA 数据包的 pcap 过滤器语句。默认情况下,fwknop 通过 UDP 端口 62201 发送 SPA 数据包,因此 /etc/fwknop/fwknop.conf 中的 pcap 过滤器语句设置为udp 端口 62201默认情况下。但是,SPA 数据包可以通过任何端口和协议(甚至通过 ICMP)发送,但过滤器语句需要更新以处理通过其他端口/协议的 SPA 通信。更多信息可以在 fwknop 手册页中找到。虽然此文件中的默认值通常对于大多数部署都有意义,但您可能需要针对您的特定设置调整 PCAP_INTF 和 EMAIL_ADDRESSES 变量。

/etc/fwknop/access.conf 文件是最重要的 fwknopd 配置文件——它管理用于验证来自 fwknop 客户端的 SPA 数据包的加密密钥和访问控制权限。以下 access.conf 文件用于本文的其余部分

[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;

SOURCE 变量定义 fwknopd 接受 SPA 数据包的 IP 地址。上面显示的 ANY 值是检查来自任何 IP 地址的 SPA 数据包的通配符,但它可以限制为特定的 IP 地址或子网,并且支持逗号分隔的列表(例如,192.168.10.0/24, 15.1.1.1)。OPEN_PORTS 变量告知 fwknopd 关于在收到有效的 SPA 数据包后应打开的端口集;在本例中,fwknopd 将打开 TCP 端口 22。

尽管上面未显示,但可以将 fwknopd 配置为允许 fwknop 客户端通过包含 PERMIT_CLIENT_PORTS 变量并将其设置为 Y 来指示要打开的端口集。FW_ACCESS_TIMEOUT 指定将 ACCEPT 规则添加到 iptables 策略以允许 OPEN_PORTS 变量定义的流量的时间长度。由于上面的 firewall.sh 脚本中的 iptables 策略利用了 Netfilter 提供的连接跟踪功能,因此在 fwknopd 删除初始 ACCEPT 规则后,SSH 连接将保持建立状态。

其余变量定义了 SPA 数据包的加密和解密参数。本文说明了对称和非对称密码的使用,但 fwknop 仅需要一种加密样式。

如果存在 KEY 变量,则所有 GPG_* 变量都可以省略,反之亦然。KEY 变量定义了 fwknop 客户端和 fwknopd 服务器之间的共享密钥。此密钥用于使用 Rijndael 对称分组密码加密/解密 SPA 数据包(请参阅资源)。对于非对称加密,GPG_DECRYPT_ID 定义了本地 fwknopd 服务器 GnuPG 密钥 ID。此密钥由 fwknop 客户端用于通过 GnuPG 支持的加密算法(例如 ElGamal 密码)加密 SPA 数据包。

GPG_DECRYPT_PW 是与 fwknopd 服务器密钥关联的解密密码。由于此密码以明文形式放置在 access.conf 文件中,因此不建议将有价值的 GnuPG 密钥用于服务器;应生成专用密钥以用于解密 SPA 数据包。fwknop 客户端使用本地密钥环上的 GnuPG 密钥对 SPA 数据包进行签名,密码由用户从命令行提供,并且永远不会存储在文件中(我们将在下面看到)。因此,任何 GnuPG 密钥都可以被 fwknop 客户端使用;甚至可以用于加密敏感电子邮件通信的有价值的密钥。

GPG_REMOTE_ID 变量定义了 fwknopd 服务器将接受的密钥 ID 列表。使用 fwknopd 服务器公钥加密的任何 SPA 数据包都必须使用 GPG_REMOTE_ID 变量指定的私钥进行签名。这允许 fwknopd 通过密码学上强大的机制限制可以访问受保护服务(在本例中为 SSHD)的人员范围。有关创建用于 fwknop 的 GnuPG 密钥的说明,请访问 www.cipherdyne.org/fwknop/docs/gpghowto.html

构建 /etc/fwknop/access.conf 文件后,是时候在 spa_server 系统上启动 fwknopd 并让 fwknop 为我们工作了

[spa_server]# /etc/init.d/fwknop start
 * Starting fwknop ...                      [ ok ]
通过对称加密的 SPA

在 spa_client 系统上,我们使用 fwknop 构建通过 Rijndael 加密的 SPA 数据包,并将其发送到 spa_server 系统。我们想要访问 SSHD,下面的 -A 参数在 SPA 数据包中编码了所需的访问权限。-w 参数通过查询 http://www.whatismyip.com 解析客户端系统的 IP 地址(如果 fwknop 客户端位于 NAT 设备后面,则此参数很有用),-k 参数是目标 SPA 服务器的 IP 地址,-v 在详细模式下运行,以便我们可以查看原始数据包数据

[spa_client]$ fwknop -A tcp/22 -w -k 16.2.2.2 -v
[+] Starting fwknop in client mode.
    Resolving external IP via: http://www.whatismyip.com/
    Got external address: 15.1.1.1

[+] Enter an encryption key. This key must match a key
    in the file /etc/fwknop/access.conf on the remote system.

Encryption Key:

[+] Building encrypted single-packet authorization
    (SPA) message...
[+] Packet fields:

        Random data: 7764880827899123
        Username:    mbr
        Timestamp:   1171133745
        Version:     1.0.1
        Action:      1 (access mode)
        Access:      15.1.1.1,tcp/22
        MD5 sum:     yzxKgnAxwUA5M2YhI8NTFQ

[+] Packet data:

U2FsdGVkX1+BvzxXj5Zv6gvfCFXwJ+iJGKPqe2whdYzyigkerSp \
2WtvON/xTd8t6V6saxbg1v4zsK+YNt53BE8EInxVCgpD7y/gEBI \
g8sd+AvU1ekQh9vwJJduseVxDxjmAHx3oNnClo2wckBqd8zA

[+] Sending 150 byte message to 16.2.2.2 over udp/62201...

从上面的“数据包数据”部分可以看出,SPA 数据包是完全难以理解的加密数据块。在 spa_server 系统上,生成以下 syslog 消息,指示已为生成 SPA 数据包的源 IP (15.1.1.1) 添加了 ACCEPT 规则。请注意,源 IP 由 fwknop 客户端放置在 SPA 数据包中。在本例中,SPA 数据包未被欺骗,因此真实源地址和嵌入在 SPA 数据包中的源地址匹配。可以使用以下命令通过 fwknop 欺骗 SPA 数据包--Spoof-src命令行参数(需要 root 权限)

Feb 10 13:55:44 spa_server fwknopd: received valid Rijndael \
encrypted packet from: 15.1.1.1, remote user: mbr
Feb 10 13:55:44 spa_server fwknopd: adding FWKNOP_INPUT ACCEPT \
rule for 15.1.1.1 -> tcp/22 (30 seconds)

因此,在发送 SPA 数据包后的 30 秒内,spa_server 上的 iptables 策略允许 spa_client 系统建立 SSH 会话

[spa_client]$ ssh -l mbr 16.2.2.2
mbr@spa_server's password:

30 秒到期后,knoptm(负责删除 fwknopd 添加到 iptables 策略的 iptables 规则的守护程序)删除 ACCEPT 规则,并将以下消息写入 syslog

Feb 10 13:52:17 spa_server knoptm: removed iptables \
FWKNOP_INPUT ACCEPT rule for 15.1.1.1 -> tcp/22, \
30 second timeout exceeded

由于 iptables 策略中的状态跟踪规则(请参阅上面的 firewall.sh 脚本),我们的 SSH 会话在删除 ACCEPT 规则后仍然保持建立状态。这些规则允许属于已建立 TCP 连接的数据包畅通无阻地通过。

通过非对称加密的 SPA

要使用 GnuPG 加密和签名 SPA 数据包,您可以执行以下 fwknop 命令。在本例中,fwknopd 服务器的密钥 ID 在命令行中使用 --gpg-recipient 参数指定,用于签名 SPA 数据包的密钥 ID 使用 --gpg-signing-key 参数给出(以下输出已缩写)

[spa_client]$ fwknop -A tcp/22 --gpg-recipient ABCD1234 \
--gpg-signing-key 5678DEFG -w -k 16.2.2.2

[+] Sending 1010 byte message to 16.2.2.2 over udp/62201

如您所见,SPA 数据包的应用程序部分长度已增加到 1,000 多个字节,而 Rijndael 示例中仅为 150 字节。这是因为 GnuPG 密钥的密钥长度(在本例中为 2,048 位)和非对称密码的特性往往会在加密后膨胀小块数据的大小。明文数据和密文数据的大小之间没有像 Rijndael 等分组密码那样的严格对应关系。

同样,在 spa_server 系统上,fwknop 为我们添加了 ACCEPT 规则。这次 fwknopd 报告说 SPA 数据包已使用 GnuPG 加密,并且找到了所需密钥 ID 5678DEFG 的有效签名

Feb 10 14:38:26 spa_server fwknopd: received valid GnuPG
encrypted packet (signed with required key ID: "5678DEFG")
from: 15.1.1.1, remote user: mbr
Feb 10 14:38:26 spa_server fwknopd: adding
FWKNOP_INPUT ACCEPT rule for 15.1.1.1 -> tcp/22 (30 seconds)
阻止重放攻击

假设第一个示例中的 SPA 数据包在途中被网络图 1 中标记为 attacker 的系统上的狡猾人员嗅探到。SPA 数据包始终可以放回线路中,以努力获得与原始数据包相同的访问权限——这被称为重放攻击。有几种方法可以获取数据包数据并重放它。最常见的方法之一是使用 tcpdump 写入 pcap 文件(在本例中tcpdump -i eth0 -l -nn -s 0 -w SPA.pcap 端口 62201将起作用),然后使用 tcpreplay(请参阅 tcpreplay.synfin.net/trac)将 SPA 数据包复制回线路。另一种方法是在捕获数据包后,将 echo 命令与 netcat 结合使用

[attacker]$ echo "U2FsdGVkX1+BvzxXj5Zv6gvfCFXwJ+iJGKP \
qe2whdYzyigkerSp2WtvON/xTd8t6V6saxbg1v4zsK+YNt53BE8EI \
nxVCgpD7y/gEBIg8sd+AvU1ekQh9vwJJduseVx \
DxjmAHx3oNnClo2wckBqd8zA" |nc -u 16.2.2.2 62201

在 fwknopd 服务器上,监视重复的 SPA 数据包,但由于 MD5 校验和与原始 SPA 数据包的校验和匹配,因此未授予访问权限,并且以下消息写入 spa_server 系统上的 syslog

Feb 10 14:14:24 spa_server fwknopd: attempted \
message replay from: 18.3.3.3
结论

单包授权为 SSHD 等服务提供了额外的安全层,这一层打击了攻击者在尝试入侵系统时必须完成的第一步:侦察。通过在默认丢弃姿态中使用 iptables 和 fwknop 来嗅探线路中专门构造的(即,加密且未重放的)数据包,甚至很难判断服务是否正在监听,更不用说与之通信了。最终结果是,利用受保护服务可能存在的任何漏洞变得更加困难。

资源

fwknop: www.cipherdyne.org/fwknop

关于端口敲门和单包授权的更多理论信息的极佳来源可以在 Sebastien Jeanquier 在伦敦大学皇家霍洛威学院的硕士论文中找到。该论文可以从 web.mac.com/s.j 下载,其中包含一个很好的论点,解释了为什么 SPA 不是“通过混淆实现安全”。

Rijndael 密码在 2001 年被选为高级加密标准 (AES),作为老化数据加密标准 (DES) 的继任者。可以在 en.wikipedia.org/wiki/Advanced_Encryption_Standard 找到一篇很好的文章。

GnuPG 是 GNU Privacy Guard,是 OpenPGP 标准的开源实现。更多信息可以在 www.gnupg.org 找到。

Michael Rash 拥有马里兰大学应用数学硕士学位,专注于计算机安全。Michael 是 cipherdyne.org 的创始人,这是一个致力于 Linux 系统的开源安全软件的网站,他还在 Enterasys Networks 的 Dragon 入侵检测系统中担任安全架构师。他是即将出版的书籍 Linux 防火墙:攻击检测与响应 的作者,该书由 No Starch Press 出版。

加载 Disqus 评论