TCP off-path exploits(又一个弄巧成拙的例子)

承接前面几篇文章的观点,本文用一个安全攻击的例子说明为了解决一个伤害很低的低概率问题,会引入多么大的麻烦,这次是可怕的被攻击 (⊙o⊙)。

TCP 端口号只有 16bit,序列号只有 32bit,这意味着在强大攻击算力面前,它很容易会被 Blind In-Window Attacks 伤害。比如,如果一个针对知名服务器 80 端口的攻击者恰好猜对了 sport,并且使用 in_window 的序列号伪造了 SYN 报文(or RST,Data...)发给服务端,服务器将重置正常的连接,这种攻击随着主机内存的增加从而 window 的增加而更加容易。

为了让这种 Blind In-Window Attacks 更难以实施,RFC5961 引入了 Challenge ACK 的概念,如果收到莫名其妙的异常报文(比如异常 SYN,RST),将重置的责任推给发送方:

  • 向发送方发一个 Challenge ACK,如果果真是发送方发生了异常,收到 Challenge ACK 后自然会自行 RST 连接,否则就是遭受了 Blind In-Window Attack。

多么好的创意,却弄巧成拙。

设计者意识到 Blind In-Window Attacks 可能会带来海量的 Challenge ACK 报文注入网络占用带宽资源,从而导致另一类 DDoS Attack,于是提出 ACK Throttling 方案:在固定时间段(比如 1 分钟)只发送固定数量(比如 100)个 Challenge ACK。

是不是很完美?是也不是,说 "是" 因为想到的问题都解决了,说 "不是" 因为总有想不到的。下面是一个闭环:

  • 为解决 Blind In-Win Attacks => 引入 Challenge ACK => 造成潜在 DDoS => 引入 ACK Throttling => 为 Blind In-Win Attack 提供了有效信息 => Blind In-Win Attack 实施更容易,不再 Blind!

下面是一个攻击图示:

如 Linux 常规配置的 Throttling thresh 是 1 分钟 100 次,攻击者只需要与熟知端口服务器创建正常连接,然后发送一个猜测的 sport,seq 携带 SYN 的报文,紧接着在 1 分钟内在合法连接 conn-2 中发送 100 个 In-Win 的 RST,如果攻击者收到了 100 个 Challenge ACK,说明猜错了,继续改变 sport,seq,如果它收到了 99 个 Challenge ACK,说明猜对了,因为有一个 Challenge ACK 发给了被攻击者 A,是不是很有趣?

紧接着,知道了 sport,攻击者便可以用同样的方法猜测 seq 和 ack 来注入数据了。是不是机关算计太聪明,反误了卿卿性命?

针对这(又一个,yet another)个问题,我曾经本想着提交一个派池,不再用固定的 threshold,而是用随机数,一会儿换一个,当我查代码时,发现在 4.7 版本已经更正了:

c 复制代码
/* RFC 5961 7 [ACK Throttling] */
static void tcp_send_challenge_ack(struct sock *sk, const struct sk_buff *skb)
{
        ...
        /* Then check host-wide RFC 5961 rate limit. */
        now = jiffies / HZ;
        if (now != challenge_timestamp) {
                u32 half = (sysctl_tcp_challenge_ack_limit + 1) >> 1;

                challenge_timestamp = now;
                WRITE_ONCE(challenge_count, half +
                           prandom_u32_max(sysctl_tcp_challenge_ack_limit));
        }
        count = READ_ONCE(challenge_count);
        if (count > 0) {
                WRITE_ONCE(challenge_count, count - 1);
                NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPCHALLENGEACK);
                tcp_send_ack(sk);
        }
}

而在此之前,它长这样:

c 复制代码
/* RFC 5961 7 [ACK Throttling] */
static void tcp_send_challenge_ack(struct sock *sk, const struct sk_buff *skb)
{
        ...
        /* Then check the check host-wide RFC 5961 rate limit. */
        now = jiffies / HZ;
        if (now != challenge_timestamp) {
                challenge_timestamp = now;
                challenge_count = 0;
        }
        if (++challenge_count <= sysctl_tcp_challenge_ack_limit) {
                NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPCHALLENGEACK);
                tcp_send_ack(sk);
        }
}

但天知道会不会有引入另一个问题,一定会。

讲这个故事的技术细节不是本意,我想表达的是,不要为解决一件小事而引入复杂的机制。回到 RFC5961 之前,SYN,RST 的 Blind In-Win Attack 发生多吗?成功概率大吗?不是因为它有可能发生就一定要去解决它。此外,针对安全问题,我一向的观点是 "不与陌生人说话",你说的每句话都在透露信息,如果非要说,那么 "说谎,并且每次说不同的谎",真相不重要,重要的是指纹,不要让人猜到你的特征。

浙江温州皮鞋湿,下雨进水不会胖。

相关推荐
利刃大大28 分钟前
【网络编程】四、守护进程实现 && 前后台作业 && 会话与进程组
linux·网络·c++·网络编程·守护进程
qq_260241231 小时前
SSL泄露源IP怎么办?(教学与防护)
网络协议·tcp/ip·ssl
pp-周子晗(努力赶上课程进度版)1 小时前
【计算机网络-数据链路层】以太网、MAC地址、MTU与ARP协议
服务器·网络·计算机网络
asdfg12589632 小时前
在linux系统中,没有网络如何生成流量以使得wireshark能捕获到流量
linux·网络·wireshark
嵌入式在学无敌大神2 小时前
TCP 与 UDP报文
网络协议·tcp/ip·udp
IP管家2 小时前
多级路由器如何避免IP冲突
网络·网络协议·tcp/ip·游戏·智能路由器·ip
久绊A4 小时前
双ISP(双互联网服务提供商)
网络
SZ1701102314 小时前
介质访问控制(MAC)
网络·macos
Xena_Networks4 小时前
屎上雕花系列-2nd
网络
Dream Algorithm4 小时前
路由器WAN口和LAN口
网络·智能路由器