WebSocketReflectorX 开发小记

警告
本文最后更新于 2022-11-12,文中内容可能已过时。

需求

  在 CTF 比赛中经常会有动态类型的题目,每个选手都拥有自己的题目容器,与其他选手的环境相互隔离,不同容器中的 flag 值也各不相同。这样能够显著提升作弊成本进而减少作弊行为,对于一些简陋的作弊行为也可以直接查处;同时也能够避免选手在做题过程中对题目环境造成不可逆的破坏,从而耽误其他选手的解题过程;当选手无意对自己的环境造成破坏后,也可以自助重启容器来恢复做题环境。

  对于动态题目而言,目前已经有一些比较成熟的解决方案了,例如 frankli0324/CTFd-Whale 等等,但是总有一些不妙的地方,使得这些解决方案在某些场景下会受到各种各样的限制。

  如何让选手舒适的访问到容器一直是比赛平台开发中一件难以解决的需求,对于某些限制颇多的场景下越是如此。我们就遇到了这样的一个场景:

学校服务器仅拥有一个单域名解析,不支持泛域名,不支持自行签发证书,所有流量需要通过 CDN 转发,再通过堡垒机审计之后解密成明文HTTP流量,再转发给我们的服务器。我们对 CDN、堡垒机、域名均没有控制权,堡垒机安全组也仅开放 堡垒机443端口 -> 服务器80端口 这一条通道,服务器的其他端口均无法从外部进行访问,用 IP 地址直连都不行。

  在服务器场景如此受限的情况下,我们应当怎么把动态题目容器映射出去?

现有反向代理方案

  上文提到的解决方案中或多或少的都考虑到了这个问题。例如 CTFd-Whale 的解决方案就是利用 frp 进行内网穿透,然后将题目流量反向代理到一台我们拥有控制权的服务器上,然后用我们自己的域名进行泛域名分发和端口分发。这样的好处是选手的解题体验会很好,和直接对着原始题目端口打没有区别。但是缺点很明显:一旦中转服务器出现一点问题,那么所有的动态题目容器会同时挂掉。由于密码和 pwn 题目本身的交互特殊性,不能使用基于 HTTPS 的 L7 流量转发,只能通过分配不同端口的形式做 L4 分流。这样就要求我们必须要将中转服务器直接暴露在公网上,这样一旦遭遇 DDoS 攻击,救都没法救。

注:L4 、L7 指的是计算机网络中的第四层传输层与第七层应用层,以下简写。

在某些场景下基于SNI的方案

  后来学长 zkongeFrank 提出了一种新的方法:利用 服务器名称指示(SNI) 机制进行 L4 流量转发。由于 TLS 流量是完全加密的,对于某些需要承载多个网站的单一服务器来说就没办法使用单一证书进行解密。于是, SNI 在 2003 年 6 月的 RFC 3546 标准提出的《传输层安全(TLS)扩展》中加入到 IETFInternet RFCs 内。目前所有主流 TLS 客户端均已支持 TLS 的 SNI 扩展协议。

  这种方案虽然解决了多端口、无加密的问题,但无法进行 CDN 保护的问题仍然存在。又由于这套方案依赖于多域名,我们需要一个泛域名证书与一个 我们拥有完全控制权的域名,显然也是不适用学校服务器这一诸多限制场景的。

WebSocket 中转方案

  在此基础上,我考虑出一种新的方法:利用 WebSocket 进行 TCP 流量转发,也就是在 L7 上再搭一层 L4。

  其中转发器是跑在选手本地的,服务器接收器是跑在服务器端的。转发器在启动的时候需要传入一个服务器地址与一个特定的 URI,然后转发器便会作为一个本地的 TCP 服务器开启一个端口。服务器接收器会监听某个路由下的请求,接收请求之后根据请求的地址是否有对应的题目容器,与转发器建立起一条 WebSocket 连接,然后将连接中的所有数据原样转发到对应容器服务的端口上。当选手对本地转发器开放的 TCP 端口建立 TCP 连接时,转发器便会立即向服务器发起一次 WebSocket 连接请求,然后将原始流量尽数转发。

  由于 WebSocket 建立连接需要客户端先发送一个 HTTP Upgrade 请求,服务器才会响应并将其升级为 WebSocket 连接,所以我们可以给服务器套上 CDN 或者防火墙之类的东西,只要 CDN 和防火墙均支持转发 WebSocket 请求即可,所幸学校的堡垒机和 CDN 服务都支持 WebSocket。同时,我们可以通过修改 nginx 配置,将接收器配置在某个子路径之下,这样其他路径还可以部署其他的服务,例如比赛平台之类的,问题就解决了。

  虽然看起来很美好,但这个方案实际上是不完美的。有一个很明显的问题就是选手的环境各不相同,所以转发器必须要“全平台”。这个全平台不仅仅只是 Windows,Linux,MacOS 三端,还要包括这些系统的历史版本。因为 CTF 题目类型多样,经常会有一些题目要求一些特定的题目环境才能够打通,那么连接器也需要能够在这种环境下无压力运行,才能够用起来比较舒适。

  还有一个问题是连接器可能会降低选手的做题体验。毕竟又是要下载又是要启动,还要对着本地端口打,让选手操作的步骤越多,比赛体验就越低。对于连接器的设计,可能还需要再多考虑考虑。

0%