写这篇文章的时候,HGAME2025 马上就要结束了,还是比较有自信它能够平稳结束吧,就开始提前开香槟写总结文章了,你们看到这篇文章的时候估计已经结束了。

我所在的 Vidar-Team 算是办赛非常非常勤的一支队伍了,几乎覆盖了全年。我们一届运维,一路会从小规模长时间的 HGAME-Mini 开始办赛,到中上规模,较长时间的 HGAME 正式赛,再到线下赛 HGAME Final,最后还要办一个国际范围大强度标准时长的 D^3 CTF。

我先吹一句,高校战队中 No Body Has CTF Hosting Experience More Than Vidar-Team. 🙌

这届 HGAME 对我来说意义不同寻常,往年主要运维工作其实都由凌武科技承担,老学长连着干了不知道多少届运维,我们就混混经验看看操作。但是今年是完全由现役 Vidar-Team 成员去做的所有支撑工作,所以很多东西包括预算,选方案,开机子这些细节是完全从头来过的,也可以说这是我们这一届头一次独立办赛。

这篇文章我们主要还是谈一些运维上的方案,包括备选的技术方案,如果您是某个校队的队长或者运维,希望这些方案以及数据能够给你们提供一些小小的帮助。

关于平台与集群化

平台选择非常重要,下面的讨论是完全基于“回归终端”这一平台进行,你可以在 https://ctf.xidian.edu.cn/ 找到部署好的平台以及找到开发者联系方式。

这个平台目前并不开源,如果要办赛,要做私有化部署,需要事先获取作者rx授权,当然你可以有其他的选择,比如 GZCTF,也是一个非常现代化 CTF 平台,包括所有必须的功能。

HGAME 选取回归终端一部分原因是其还承担着一些关于回归终端的规模技术验证的任务,您自然可以做出你自己的选择。

但是一些旧平台可能会存在一些能力的缺失,导致无法实现下面我们提到的的一些方案。

打个比方说CTFd,他的原版是没有动态靶机能力的,虽然可以通过插件实现 Docker 容器分发,但实际上靶机调度能力比较受限,比如你想做多个节点的容器调度,他就是做不了。

不过我们也不是非要动态靶机不可,下面的丐版方案会提到,最低成本办赛。

一些假设

要出运维方案我们肯定得先确定一下规模和办赛方案,我们做了一些假设:

  1. 报名参赛的人数计作 1000
  2. 开赛当天有 30% 的人会蹲点开靶机,合计 300-400 靶机
  3. 假设平均一个靶机需要 512MB,CPU内存配比按 1:2 给
  4. 流量费用与计算资源费用 1:1
  5. 峰值过后靶机数量维持在 100 左右

有了这些个假设,我们就可以开始做预算了

HGAME 赛程相当长,平台开放时间从注册两周,到比赛两周,再到复现一周,合计会有5周时间,相同规模下预算会显著高于那些只办 48h 的赛事。

这里所有的预算仅为事先试算,数据均不可靠

多个方案

最优方案: ALL IN 阿里云 ACK

具体计算细节不提了,如果采用这个方案,预算会来到 2000-3000 这一个位置,最大的好处是他确实稳,同时也能省下很多很多的精力,往上面托管就好了。

其实这些个公有云厂商都是一样的,需要资源的时候随时可以狠狠扩容,网络呢一般大家国内对于办个 CTF 来说都过得去的都挺好,甚至如果搞个 serverless 集群吧,全都不用管了,主打一个钱到位了啥都省心。

这个方案的开销对 HGAME 来说其实是可接受的,但是会挤压周边制作预算,因此只能先作备选。

灵车幻想: 边缘混合云

早先我们没有得到学校的消息说可以提供一些帮助,我们设计了一个灵车方案:

graph TB
    subgraph DN11
    subgraph cloud
        Master
    end
    subgraph local1
        Node1 
    end
    subgraph local2
        Node2
    end
    subgraph local...
        Node...
    end
    end
    Master ==> Node1
    Master ==> Node2
    Master ==> Node...

乍一看这个架构图挺普通的,除了外面套了个名为DN11的壳

常看我的 Blog 的兄弟们会知道 DN11 为何物,他是一个中型的 BGP 实验性网络,里面的节点很多是一些 homelab 家庭节点一类的东西。

这个方案正是利用了这一点,以 DN11 代替单独拉隧道的工作,发动面子果实,将散落在各地的边缘计算资源给他们都聚集在一起,有公网的可以拿去当入口,有计算资源的可以拿来托管一个节点

比如我插满内存的 j4125 理论上跑几十个靶机是可以的,随后我可以提供一个 v6 入口,或者通过他人的 v4 入口转到我这里。

你还别说我甚至可以做地理位置上的靶机就近调度,由于一切都是废物利用,所以靶机成本为0,非常省钱。

但是,节点是不可靠的,入口是不可靠的,DN11 这个网络本身也没多高可用,这对选手做题体验会造成很大负面影响。

这个方案的预算大概会在在四五百左右,我们只需要一个配置足够的云上 master。

这个方案看上去真的非常酷,非常吸引人,但是我们确实要认识到他背后的风险,这不是 HGAME 能承受的。

丐版方案:静态

我们上面其实一直在解决动态靶机的问题,但是动态靶机这事情其实也没有那么多年,在静态靶机时代大家也各有办法:

  1. 对题目做限制,尽量不让选手RCE,即使R了也得尽量控制权限
  2. 如果非得有破坏性操作,那就开多个静态靶机,定时重置

所以以前的 CTF 赛事有两种富有时代特征的说法:

  1. 搅屎
  2. 蹭车

现在随着现代化 CTF 平台的逐渐普及,尤其是动态靶机的出现和普及,这种现象其实已经越来越少了,但如果预算实在有限的话也可以采用这些老方案。

另一个好处是靶机运维可以全部交给对应的出题人,主办这边只需考虑报销,或者反正高校战队大家都熟,除非学校报销,反正迟早会转嫁回去的,也可以干脆不给出题人报销。

这个方案的预算会更低一些,因为不用起集群,可能还能砍一半,全程两三百左右。

我们可以再省一点,选购最近新上线的 200Mbps 轻量云,规格稍微高一点,再直接塞一个 CTFd 上去,这下网费也省了,成本能下到100以内。

折中方案: 混合云

比较有幸的是我们这次能够和学校网络中心合作,可以拿一批计算资源,虽然是淘汰下来的,但是其实我们作靶机也不需要怎么怎么高的性能,都可以接受。

如果您也有办赛的想法可以先看看所在学校的网络中心能不能提供一些力所能及的支持。

在介绍这个方案前,讲一个大前提:我们学校的网络真不行。

这是经过反复验证的事实,西电的学校网络就很稳,虽然他们只能七层 web 反代,但是他们确实稳,他们可以做全云下,我们不行,我们连接一上去甚至会带着整个学校网络一起暴毙,具体受什么影响尚且不明。

所以,我们没法做全云下的方案,我们的底线是平台,平台起码得放在云上。

graph TB
    subgraph cloud
        Master
        Node3
    end
    subgraph local
        Node1 
        Node2
    end
    Master === Node1
    Master === Node2

在这个方案里,我们给云下的多个 Node 分别拉了一个隧道到云上,组了一个云上云下异地集群,在这个集群里,平台本体位于云上的,靶机都部署在云下的节点里

Node3 默认不启用,当云下饱和或故障时,可以启用 Node3 将靶机调度到云上以维持可用。

这个时候成本就剩下了 Master 以及偶尔启用的 Node3,整个成本就一台足够配置的Master,打个比方4c8g,就算我们无视任何优惠硬买机子,再算上流量就那么四五百块钱,还有突发的 Node3 偶尔吃一点,总的来说是可以接受的。

实际上回归终端平台性能非常好,全程仅在开赛高峰期观察到最差1%平均响应延时有小幅度增加,平均响应延时几乎没动,与此同时资源占用仅为零头,这不仅得益于 Rust,也与开发者的功底息息相关。

这就是我们最终定下的方案。

赛中:办赛不得不品的紧急运维工作

我们需不需要CDN?

简单算一笔账,CDN流量0.2元/GB,云服务器按量0.8元/GB。

这么一看如果是过CDN回源 api 路由的话,流量会涨到 1元/GB,静态资源倒是可以省一点。

可以计算得到只有当静态资源流量占比超过25%的时候,这笔账是合算的。我们平台要加载前端,加载题目描述的一些图片,最重要的是要下载附件,所以一般都是值得的。

但是好像不能省很多,并不是必须的?附件还可以百度网盘。

我给出的答案是除非你的参赛选手只面向校内或者一个小范围都必须上,为什么,怕被打。

HGAME 今年开赛十分钟被海外拉了 100G 流量,要是没 CDN 扛了一遍,我们口子并不大的服务器可能得出点事情,还好全打 CDN 上了。

又有谁闲的没事打一个新生赛呢,完全没头绪。

我们用到Node3了吗?

用到了,甚至还追加了Node4、Node5、Node6,因为学校的两个节点在开赛的同时精准地失联了,太蠢了直接无节点可用了。

但是由于平台的一些配置出了点小问题,导致我们没能及时上线追加的Node4、5、6,一连调整了几个问题,直到 20 分钟时才开始恢复,到 30 分钟时才完全恢复运行。

顺便一提峰值靶机数量为 342,与预计的 333 非常接近,猜的太准了。

流量日志

出于平台安全性以及视奸选手做题进度考虑,我们还做了流量日志,这事其实不在原规划中,只是我一是想加上去的。

我们选用的是 kubeshark,我想狠狠吐槽一下这玩意有多难用。

你看他的UI确实很漂亮一切都很美丽,但是他的录制功能简直是灾难。

起初看到他提供了 aws s3 的上传,就给他配了 aksk ,然后我们挂个录制就让他传吧,这一传发现他这个其实更像是一种备份,而不是保存记录。

他自动每小时上传一次,每次传的都是全量的,这事情占用了我巨大存储空间,他上传上去的东西吧,很多 pcap 很多 json,我都不知道到时候怎么把他拿出来分析。

这其实还能接受,但是他会爆炸,比如他的临时 empty-dir 满了,爆了这个录制任务就会消失,但是其他节点的还在,那我如何二次启用呢?不知道

我个人感受就是他总是会断在一些很奇怪的地方,我遇到的先是录制爆了,再是上传爆了,很难留下一个长期而完整的流量日志,而且备份文件没有可靠的本地分析手段。

总的来说上传爆的概率比录制爆的概率高一点,所以最终是划了块 pvc 让他存去得了。

kubeshark worker 似乎会时不时问 hub 要 pods/all 这就导致了 hub 往 worker 方向的流量非常大,如果按量计费容易超预算,需要注意。

失误的预算

这段时间看下来,我们严重高估了动态靶机的资源需求。

Week1 的日常靶机数量远高于 Week2,但是 Week1 的靶机都很轻,以至于占用其实低于 Week2。

我有时候想想如果拿 Week1 的靶机数量需求去开 Week2 的靶机,那其实就可以达到预估的资源占用了,问题出在 Week2 是 2。

那这事情真的是这样子的吗?我觉得有点关系,但是可能根本问题不在这里。

首先考虑一个问题,日常靶机数量是否和难度成反比?

如果题目难度上升,有头绪的人会变少,做的人也会变少,对 24h 赛不合理,但是对于一个持续一周的赛事来说应该是合理的。

再考虑一个问题,难度高的题目,其靶机是不是往往会占用较高的资源?

至少简单题不可能有太复杂的结构,在一定范围内我觉得这是完全合理的,HGAME 毕竟是新生赛,对比实际两周的题,这句话在 HGAME 是合理的。

所以,随着难度上升,靶机变少但是单个靶机占用变高,那么对于 HGAME 是否存在一个资源占用奇点,无论题目难易,总的资源占用都会在这个点附近?

对比了两周的占用,居然真的差不多,但还得考虑热度流失,上班开学等问题,我没法这样就结论说存在这个奇点。

但是对于 HGAME 我可以说:一般来说,靶机总资源占用受题目本身内容影响没有那么大。

让我们回到预算的事情上,由于难度对靶机数量的负反馈调节存在,下次做资源预算的时候可以再压低一下单一 pod 的资源占用值。

Addons

反作弊

首先我直接告诉你,回归终端可能不是反作弊最强的,但他一定是反作弊上限最高的 CTF 平台。

这也和现在的大环境有关系吧,什么比赛都能上上闲鱼。

有时候您能想象吗?HGAME 只是一个高校新生赛,虽然 HGAME 确实是比较热门的新生赛,但这都能催生出铺天盖地的 flag 买卖,换作其他政府赛事或者奖金丰厚的,感觉已经完蛋了。这是一切是什么时候开始的呢?

当您看到这篇文章的时候,HGAME2025 应该已经结束了,具体反作弊多强这里先按下不表,过段时间公布最终排名的时候应该就可以从中略知一二了。

反作弊这个真的是现在办 CTF 必须要过的一关。

关于办赛的意义

我们真的出了不少题目,可能您打过的某一次比赛就是我们出的。

但给别人出题和给自己出题区别在于,前者你要满足对方需求即可,题出的再好你也不会拿到什么反馈,他只是买断了,给自己出题你会精益求精。

对的,独立办赛确实有这个好处,大家都知道出出去的题是代表自己战队的,都会谋求高质量、有意思的新题,基本当你出过某一个类型的题,那你这块已经很通了。

我听一些小登讲过这个事情,他们都说出题比做题学到的更多。

我想这也是交流学习的一种重要方式,我有一个好的想法,我通过赛题将这个想法分享出去,通过 WriteUp 将这个想法交流出去。

我今天参加了一个战队的 CTF,其实就是听他们开分享会,听不懂的还有 WP 教你,这样子循环下去整个圈子才会好起来。

我认为应该把现在的 CTF 划为两类,一类是交流型的一类是决胜型的,毕竟办赛初衷有所不同,总的来说还是希望看到更多战队主办的交流型 CTF。