白皮书笔记三6.9.3及以上

由格式错误的 TCP AO 选项引起的 TCP 紧急指针状态混淆 (CVE-2019-12260)

虽然自 VxWorks 版本 6.9.3 以来,上面的 Urgent Pointer = 0 错误已修复,但 iptcp.c 模块同时经历了一些其他重构。 添加了一些新功能,例如新添加了一个对新添加的 AO TCP 选项的处理,而这为代码引入了更深层次的错误。
在高于 6.9.3 的 VxWorks 版本中,添加了对 TCP AO 选项(身份验证选项,RFC-5925)的支持。这似乎是默认包含的,并且确实得到了我们检查过的产品的 VxWorks 映像的支持。下面介绍的漏洞不依赖于实际启用或使用的TCP AO,因为它总是由 TCP 模块解析。
对于来自正在请求建立新连接的客户端传入的 SYN 数据包,将在模块 iptcp_input 内发生以下流程:
在这里插入图片描述
对 TCP AO 选项的支持已经添加到我们熟悉的魔模块 iptcp_input 中,从而导致该模块功能有一些改变。函数 iptcp_handle_passive_open 将在 SYN 到达监听套接字时被调用,并且为将传入的连接创建一个新的套接字对象。这个套接字随后将被添加到目标缓存中,以便它匹配来自同一 TCP 连接4元组(IP src/dst 和端口 src/dst)的任何新 TCP 报文段。此后,代码将立即在 TCP 选项报头中查找 AO 选项 (TCP_OPTION_AO),并在找到时尝试对其进行解析。

现在,假设攻击者在第一个 SYN 数据包中添加了格式错误的 TCP_OPTION_AO 选项,例如为该选项指定了 1 个字节的值 - 而根据 opt_len <= 3 条件,该值太短了。检查将失败,iptcp_input 将简单地丢弃掉数据包并返回。 但是,由 iptcp_handle_passive_open 创建的新套接字不会被破坏或取消。此时,与建立连接的 4 元组上任意传入的 TCP 报文段相匹配的新套接字对象仍然存在,但是,由于 SYN 数据包未完全被处理,新套接字将保持默认的 LISTEN_STATE 状态。现在攻击者可以发送一个新的(#2)SYN 数据包,它不会被函数 iptcp_handle_passive_open 处理,因为它到达了一个已经存在的客户端套接字(而不是监听套接字)。由于函数 iptcp_handle_passive_open 不处理这个新的 SYN(#2)数据包,因此这个函数不执行以下验证:
在这里插入图片描述
现在假设攻击者在这个新的 SYN(#2) 数据包中设置了 URG 和 FIN 以及 SYN 标志。这个新数据包(#2)将绕过上述检查而作为有效数据包,继续流程并到达函数 iptcp_deliver 。 在这里它将根据 tcb 状态被处理:
在这里插入图片描述
然后,函数iptcp_deliver_state_listen 将调用函数iptcp_process_syn,执行以下操作:
在这里插入图片描述
套接字的 recv.seq_next 现在将被设置为攻击者在数据包(#2)中选择的初始序列号。让该数值表示为 sequence_a
流程在函数 iptcp_deliver 中继续,并立即进入这个(熟悉的)流程:
在这里插入图片描述
因此,我们现在假设 tcp_hdr->urgent_pointer = 1(一个有效的非零值),变量 tcb->recv.urg_ptr 被赋值为 p->seg.seq_start + 1 = sequence_a + 1。
流程在函数 iptcp_deliver 中继续,但会立即遇到以下检查:
在这里插入图片描述
由于套接字的状态仍处于监听状态,这对于要接收的 FIN 无效,因此此检查失败,并且会从itpcp_deliver 返回一个错误到iptcp_input。而套接字的状态(tcb->state)不会再次更改,并且仍然保持在 LISTEN_STATE, 至于 iptcp_input ,它现在只是因为错误丢弃了这个数据包,套接字本身仍保持活动状态。值得注意的是,TCB_STATE_URG_RECEIVED 保留在套接字上,并且 recv.urg_ptr 仍然保留值 sequence_a + 1。
最后,此时,一个完全有效的(#3)SYN 数据包被发送到建立在 同一 4 元组上的套接字,且初始序列号值为 sequence_b 。假设 sequence_b = sequence_a + 1000000。 这是一个完全有效的 SYN 数据包,它将由代码按预期处理。SYN/ACK 将被发送回攻击者,然后攻击者将用 ACK 响应以完成握手。此外,攻击者可能会在此 ACK 段中包含多达 64K 字节的数据,这些数据将被添加到套接字的 TCP 接收窗口中。
直到现在,套接字的状态才会变为 ESTABLISHED_STATE ,并且一个等待 accept() 调用的用户将被交给客户端套接字。然后用户可能会在套接字上调用 recv()。此时,将执行在 iptcp_usr_get_from_recv_queue 中我们所熟悉的代码:
在这里插入图片描述
此时如前文所述 TCB_STATE_URG_RECEIVED 仍为设置着的状态,recv.urg_ptr 也仍然保留着其值。 因此,会进入检查 else-if 条件,所以现在可以用其匹配值进行替换:
在这里插入图片描述
在这里插入图片描述
因此else - if 条件检查通过,len 将由紧急数据偏移计算然后设置,如下所示:
在这里插入图片描述
因此,len 现在将等于 -1000000,并且由于 len 是一个无符号 32 位整数,它现在将等于一个非常大的正整数,从而使用户定义的任何限制无效。 与前面描述的紧急指针漏洞类似,这将导致在此 TCP 套接字上执行 recv() 的任何代码中发生轻微溢出。

五次握手
以下 wireshark 捕获显示了上述 TCP-AO 状态混淆攻击。 目标设备 (192.168.108.10) 有一个服务器正在侦听 TCP 端口 59747:
在这里插入图片描述
如您所见,从攻击者到目标设备的前 3 个数据包都设置了 SYN 标志:

  1. 第一个数据包具有格式错误的 TCP-AO 选项(显示在第二个捕获中);
  2. 第二个数据包的 Seq = 0 (即seq_a)并且设置了 URG、FIN 标志。 紧急指针也设置为 10(任意非零值);
  3. 第三个数据包的 Seq = 1000000(即seq_b),否则有效。

一个非易受攻击的 TCP 堆栈应该为前 2 个数据包中的每一个都返回一个 RST 数据包。但是,对于易受攻击的 IPnet 堆栈,这些数据包的处理方式不正确,从而导致一个状态混乱问题。最终结果是一个打开的(建立连接的)套接字,它的 tcb->recv.urg_ptr 设置为 10,tcb->recv.seq_next 设置为 1000000。如上文所述,这将导致在 recv() 调用期间紧急数据偏移计算下溢。在前 3 个数据包之后,目标设备以 SYN/ACK 响应,表明接收到第 3 个 SYN 数据包。第 5 个数据包是攻击者发送的用于完成握手的 ACK 包。 此 ACK 数据包附加了一个有效负载,长度为 1024。此时,目标设备对套接字的任何后续 recv()调用都将导致 1024 字节写入用户缓冲区,而不管用户传递的 len 是多少。
如果目标设备端口 59747 上的 TCP 服务器后续执行一个长度较短的 recv()调用,则会发生内存损坏。此外,攻击者可以控制溢出数据,因为它是在 ACK 数据包中发送的数据。
在这里插入图片描述
上面的屏幕截图来自运行 v6.9.3 的 VxWorks BSP VM。这里,fd = 5 是之前打开的服务器的监听套接字。执行攻击后,服务器接受攻击者的连接,导致一个打开的客户端套接字 (fd = 6)。然后执行一个长度为 10 的 recv() 调用。但是,如 recv() 的返回值所示,写入了 1024 个字节,这表明在这种情况下出现了堆溢出。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Pekingkenny

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值