使用 nftables 创建动态黑名单

使用 nftables 创建动态黑名单

我想用 nftables 创建一个动态黑名单。在嵌入式设备上的 0.8.3 版本下,我使用 nft list 规则集创建一个如下所示的规则集:

table inet filter {
set blackhole {
    type ipv4_addr
    size 65536
    flags timeout
}

chain input {
    type filter hook input priority 0; policy drop;
    ct state invalid drop
    ct state established,related accept
    iif "lo" accept
    ip6 nexthdr 58 icmpv6 type { destination-unreachable, packet-too-big, time-exceeded, parameter-problem, echo-request, echo-reply, mld-listener-query, mld-listener-report, mld-listener-done, nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, ind-neighbor-solicit, ind-neighbor-advert, mld2-listener-report } accept
    ip protocol icmp icmp type { echo-reply, destination-unreachable, echo-request, router-advertisement, router-solicitation, time-exceeded, parameter-problem } accept
    ip saddr @blackhole counter packets 0 bytes 0 drop
    tcp flags syn tcp dport ssh meter flood { ip saddr timeout 1m limit rate over 10/second burst 5 packets}  set add ip saddr timeout 1m @blackhole drop
    tcp dport ssh accept
}

chain forward {
    type filter hook forward priority 0; policy drop;
}

chain output {
    type filter hook output priority 0; policy accept;
}
}

对我来说这只是一个临时解决方案。我想用官方的例子联机帮助页用于动态黑名单。如果我使用联机帮助页中的官方示例,我的 nftables 文件如下所示:

table inet filter {
set blackhole{
        type ipv4_addr
        flags timeout
        size 65536
}
chain input {
        type filter hook input priority 0; policy drop;

        # drop invalid connections
        ct state invalid drop

        # accept traffic originating from us
        ct state established,related accept

        # accept any localhost traffic
        iif lo accept

        # accept ICMP
        ip6 nexthdr 58 icmpv6 type { destination-unreachable, packet-too-big, time-exceeded, parameter-problem, echo-request, echo-reply, mld-listener-query, mld-listener-report, mld-listener-done, nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, ind-neighbor-solicit, ind-neighbor-advert, mld2-listener-report } accept
        ip protocol icmp icmp type { destination-unreachable, router-solicitation, router-advertisement, time-exceeded, parameter-problem, echo-request, echo-reply } accept

        # accept SSH (port 22)
        ip saddr @blackhole counter drop
        tcp flags syn tcp dport ssh meter flood { ip saddr timeout 10s limit rate over 10/second} add @blackhole { ip saddr timeout 1m } drop
        tcp dport 22 accept

}


chain forward {
        type filter hook forward priority 0; policy drop;
}

chain output {
        type filter hook output priority 0; policy accept;
}

}

但是当我使用 nft -f myfile 在 0.8.3 版本上加载此 nftables 文件时,出现此错误:

Error: syntax error, unexpected add, expecting newline or semicolon
    tcp flags syn tcp dport ssh meter flood { ip saddr timeout 10s limit rate over 10/second} add @blackhole { ip saddr timeout 1m } drop

我不知道为什么会这样,但根据维基百科它应该可以从版本 0.8.1 和内核 4.3 开始工作。

我的版本是0.8.3,内核是4.19.94。

我已经在 Debian Buster 下测试了 0.9.0 版官方手册页中的规则集。手册页中的规则集在 Debian 上运行良好,但 IP 仅被阻止一次。

在这个例子中,我想创建一个防火墙规则,如果对我的设备发起暴力攻击,该规则会阻止 ssh 端口上的 IP 地址。但我想封锁IP,例如5分钟。在此之后,应该可以从攻击者的 IP 再次连接到设备。如果他再次进行暴力破解,则应再次封锁 ip 5 分钟,依此类推。如果 nftables 可以的话,我想避免为我的嵌入式设备使用其他软件,例如 sshguard 或fail2ban。

我希望任何人都可以帮助我。谢谢!

答案1

hydra工具同时多次连接到 SSH 服务器。在OP的情况下(评论:)hydra -l <username> -P </path/to/passwordlist.txt> -I -t 6 ssh://<ip-address>它将使用 6 个并发线程连接。

根据服务器设置,一个连接通常可以尝试 5 或 6 个密码,并且需要大约 10 秒的时间才会被 SSH 服务器拒绝,因此我无法看出 10 的速率如何联系每秒的尝试次数可能会被超出(但事实就是如此)。这可能意味着触发的是在不到 1/2 秒内完成了 5 次以上的连接尝试。我不太相信 的准确性10/s,但可以假设它发生在这里。

版本和语法问题

不适用于版本 0.8.1 或 0.8.3 的语法是出现在的较新语法这次提交

src:重新访问语法以更新数据包路径中的集和映射

对于集合,我们允许这样:

  nft add rule x y ip protocol tcp update @y { ip saddr}

[...]

它已被承诺版本 0.8.3 仅适用于 nftables >= 0.8.4

当前的 wiki 修订版为从数据包路径更新集,在同一页面中,仍然显示以前语法的命令

 % nft add rule filter input set add ip saddr @myset

[...]

并使用新语法显示结果:

[...]

                add @myset { ip saddr }

[...]

某些 wiki 页面或最新的联机帮助页可能不适用于较旧的 nftables 版本。

无论如何,如果使用内核 4.19 运行,nftables>= 0.9.0 应该是首选以获得附加功能。例如,它可以在Debian 10或在Debian 9 向后移植

黑名单应该在状态接受规则之前完成

一旦 IP 被添加到黑名单中,这并不会阻止已建立的连接继续、不受阻碍且不被考虑,直到它们被 SSH 服务器本身断开。那是因为之前有通常存在的短路规则:

        # accept traffic originating from us
        ct state established,related accept

此评论具有误导性:事实并非如此接受来自我们的流量任何已经在进行的交通。这是短路规则。它的作用是通过仅解析新连接的所有规则来处理有状态连接:此规则之后的任何规则都适用于新连接。一旦连接被接受,它们的各个数据包将保持被接受状态,直到连接结束。

对于具体的黑名单处理情况,需要将具体的黑名单规则或者其中的一部分放置在该短路规则之前,以便能够立即生效。在OP的情况下是:

        ip saddr @blackhole counter drop

应将其移至ct state established,related accept规则之前。

现在,一旦攻击者被添加到黑名单中,其他正在进行的连接将无法获得一些剩余的免费尝试来猜测密码:它们将立即挂起。

如果有黑名单,请考虑白名单

附带说明一下,便宜的iif lo accept规则本身可以作为优化和被列入白名单之前移动:所有(甚至是长期存在的)本地建立的连接现在也将在滥用情况下被列入黑名单(例如:来自 127.0.0.1) 。考虑在规则之前添加各种白名单规则@blackhole

可选择更快地警告应用程序

为了防止来自服务器的持续回复到达黑名单 IP(特别是对于 UDP 流量,对于 TCP 没有多大用处,包括 SSH),daddr还可以在inet filter output链中添加使用的等效规则,并使用拒绝更快地通知试图回复的本地进程。发出他们应该中止的信号:

    ip daddr @blackhole counter reject

集合之间的区别addupdate应用于集合上的区别

现在有了这样的设置,即使正在进行的连接立即停止,攻击者也能够继续尝试并在 100 万年后获得一个新的短窗口,这不是最佳的。

条目必须是更新输入@blackhole ... drop规则中的d。update如果条目已经存在,则会刷新计时器,而add不会执行任何操作。这将继续阻止任何进一步(不成功)连接到 SSH 服务器的尝试,直到攻击者放弃,打开的窗口为零。 (我上面添加的输出规则不应该改变,这不是攻击者的行为):

代替:

ip saddr @blackhole counter drop

与(仍然保留旧语法):

ip saddr @blackhole counter set update ip saddr timeout 1m @blackhole drop

它甚至应该移到ct state invalid规则之前,否则如果攻击者尝试无效的数据包(例如,TCP 数据包不是已知连接的一部分,例如来自已忘记的连接的迟到的 RST),则该集将不会更新,而它本可以更新。

限制最大建立连接数

需要内核 >= 4.18 且 nftables >= 0.9.0,因此无法使用 OP 的当前配置来完成。

攻击者可能会发现它不能一次连接太多次,但仍然可以无限制地不断添加新连接,只要连接速度不要太快。

A并发连接数限制(与 iptables 一样可用connlimit) 还可以添加其他计量规则:

tcp flags syn tcp dport 22 meter toomanyestablished { ip saddr ct count over 3 } reject with tcp reset

将允许任何给定的 IP 地址仅建立 3 个 SSH 连接。

或者,同时也触发 @blackhole 集(这次使用更新的语法):

tcp flags syn tcp dport 22 meter toomanyestablished { ip saddr ct count over 3 } add @blackhole { ip saddr timeout 1m } drop

在 OP 的情况下,这甚至应该在之前的计量规则之前触发。请谨慎使用,避免合法用户受到影响(但请参阅 openssh 的ControlMaster选项)。

IPv4 和 IPv6

由于没有通用的 IPv4+IPv6 集地址类型,因此处理 IPv4 的所有规则(只要有 2 个字母的单词ip)可能应该复制到ip6其中包含并在 IPv6 集上工作的镜像规则中。

相关内容