Skip to content

Latest commit

 

History

History
195 lines (87 loc) · 7.85 KB

TOA绕过ACL问题研究.md

File metadata and controls

195 lines (87 loc) · 7.85 KB

前言

很久没有写文章了,面试的时候遇到一个哥们,问他最近印象特别深刻的漏洞是什么,他说是TOA伪造,其实我当时挺尴尬的,因为这个东西我是真没研究过,所以赶紧补一下知识

TOA全称Tcp Option Address,这不是什么Tcp协议规范的字段,而是一种方案名称,相关的方案介绍可以查看RFC7974,大概的意思就是提出了在Tcp option中增加主机信息的方案,用于解决在某些场景下传递主机信息的问题,不过这个方案被明确拒绝了进入Tcp主线代码里,因此后面的大多数功能实现都是基于模块来支持。

好,接下来就是关注如下三个问题:

  1. 什么是Tcp Option
  2. TOA该怎么使用?
  3. 风险是什么?

什么是Tcp Option

TCP Header

如上是一个tcp header的结构图,最大长度为60 bytes,而其中前20 bytes是固定长度,其中包含了端口信息,序号,窗口等信息,而第六层的区域就是tcp option区域,是一个最长是40 bytes长度的可变区域。

这块区域是干嘛用的呢?我们回顾一下RFC793也就是正式定义了tcp的那一份文档,可以看到当时已经有了tcp option的概念

https://datatracker.ietf.org/doc/html/rfc793#section-3.1
TCP Header Format






    0                   1                   2                   3


    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1


   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+


   |          Source Port          |       Destination Port        |


   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+


   |                        Sequence Number                        |


   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+


   |                    Acknowledgment Number                      |


   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+


   |  Data |           |U|A|P|R|S|F|                               |


   | Offset| Reserved  |R|C|S|S|Y|I|            Window             |


   |       |           |G|K|H|T|N|N|                               |


   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+


   |           Checksum            |         Urgent Pointer        |


   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+


   |                    Options                    |    Padding    |


   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+


   |                             data                              |


   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+




                            TCP Header Format




          Note that one tick mark represents one bit position.




                               Figure 3.

不仅是如此,还明确规定了options的数据格式,以及明确了TCP必须实现所有的options,当时定义好的options仅有3个:

      Kind     Length    Meaning


      ----     ------    -------


       0         -       End of option list.


       1         -       No-Operation.


       2         4       Maximum Segment Size.

但是当我们回顾历史,翻阅最早的tcp的文献《A Protocol for Packet Network Intercommunication》,可以发现在当时的设想中并没有看到有关options这样自定义的部分存在

走马观花,完全没有生啃下来,所以如果有的话,当我没说

中间发生了什么并不是很清楚,只能是通过继续阅读大致猜测出来:

在早期,即协议规范确定以前,首部定义的数据就足以支撑计算节点之间的通信了,但是随着技术的发展,首部的基础信息就开始变得不够用了,但是这时候协议本身已经在世界上流行起来,通过更改预先定义的首部字段的方案基本不可能,所以规范上正式提出来将一个可选的字段定义在了当时首部的下面,然后通过选项字段来优化能力

目前来说已经被纳入规范并要求主线代码实现的options有如下: 00519ccc-6ff9-4c33-8cbe-813b72c0f962.png

TOA该怎么使用

介绍完Tcp Options,那么就该回归到主题了 -- TOA,之前说过这是一个被拒绝的方案,也就是没有被当做是标准来实现。想知道怎么用,自然就要先知道这个方案到底是来解决什么问题的。 在之前的rfc7974中说明了该方案是用来尝试解决信息传递的问题,那么在实际场景中,会是什么样的情况我们会有这样的需求呢?

就以LB来说,当客户端发起请求的时候,目的地址是LB的ip,然后经过了Full NAT最终由Rs(Real Server)收到了来自LBtcp报文

d37ec695-e7e4-4296-a867-75bc4fc49da6.jpg

那么这样就有一个很明确的问题出来了,就是如果Rs想要知道客户端的真实ip怎么办?在并不修改上面的通信链路的情况下,最好的办法就是将Clinet IP塞到报文里,Tcp Options就正好能满足这个需求,只要LB在进行Full NAT时候将Clinet IPClient Port放到Tcp Options中,当传递到Rs时候,再由Rs从报文中读取这一段信息,就能获取到客户端的真实地址信息,而这样的一套数据流转方案就被叫做TOA

可以明显看出来,这种方案对网络架构要求很低,但是缺点也就很明显了:

  1. 中间层得支持TOA的实现
  2. 因为TOA是一个非标方案,所以需要修改tcp逻辑来实现真实ip地址的提取

第一点在现在诸多云厂商上都是支持的,而第二点各家云厂商都各自实现了自己的TOA模块

但是这儿需要注意一点,我们先前说过在Tcp Options中的数据是需要满足一定的数据结构的

   +--------+--------+--------+--------+


   |  Kind  | Length |      data       |


   +--------+--------+--------+--------+

那么LB上设置的Kind自然需要和Rs上解析的Kind保持一致才行

风险点

从上面的流程里可以看出来,最大的问题就是RcTcp Options中获取到这个客户端地址是否完全可信呢?

路人甲:啊!这个客户端地址是LB获取后写入的,怎么会不可信呢?

这么说没有错,但是如果在LB收到的TCP报文的时候,Tcp Options中就已经存在了客户端地址,会如何处理呢?

这就要看各家云厂商的中间件是怎么处理的了,如果是取了client ip以后直接塞到tcp options里面,无视已经被写入的toa还好说,但是如果当检测到有对应的toa以后就直接透传的话,就会导致toa外部可控,从而使得RC拿到的是外部指定的地址,从而 绕过某些ACL

参考