网吧网管如何在 DEF COOON CTF 中存活
全文都是流水帐,和writeup没什么关系。
俗话说的好,别人的作业交的越晚,能抄的样本就越多(并不)。
因为个人参与度的问题,就不多讨论Quals了,只谈四年里参与过的Final。
Oh, Take Me Back, My Timemachine
在大学是跟着big1ce和wilson师傅通过CTF接触了安全领域,打了一些比赛,虽然成绩不太好,但自我感觉还不错。
工作之后,因为一些机缘巧合的因素,开始参与 DEF CON CTF。DC CTF的题比较难,起初做逆向,他们往往让我的F5没什么用,机器码也看不得;后来看看Pwn和流量,各家神仙的payload也看的紧,抄exp也很为难。所以过了几天,又觉得自己干不了这事。幸亏荐头的情面大,辞退不得,便改为专管网络的一种 无聊(并不) 职务了,或许这就是网吧网管的宿命罢。(neta结束)
The Order of Overflow自2018起开始作为出题人,直到2021年结束。我则从2018 Final起,逐渐参与到这一局游戏中。2018年的事情几乎没有留下太多印记,只记得几个同事在Flamingo的房间里逆向,以及同事D在赛前帮我回酒店拿了一份快递。记忆消失了一块,有点可惜。直到长大后才会明白,有些东西如果不记下来,就会随风飘逝。
Summer Night Wind
实际2019年本来是会在国内参与后勤做题的。只是没想到,有同学的签证没有过,原本在做运维的Azure需要被解放去做题。想当年我还在做某方向的商业测试项目,唉,人呐,就都不知道,自己不可以预料。一个人的命运啊,当然要靠自我奋斗,但是也要考虑到历史的行程,我绝对不知道我作为一个包邮区的测试工程师,怎么就把我当作主力运维选到Las Vegas去了。所以Azure同志跟我讲话,说,「中央已经研究决定了」,后来我就念了……
不,和你们想的不太一样。后来我就因为担心协作平台R不够稳定,跟他在会议室拍桌子吵了两个小时(此处音量-20dBm
事情是这样的,在DC 26中,我们引入了一个新的协作平台R。这是一个非常富有远见的做法,试图解决在CTF这个特殊场景下多人协作的问题。实际上,后来我们也发现,在其他队伍(示例1、示例2、示例3)中也引入了类似的实践,侧面说明Azure还是很牛逼的。而也是因为大家对平台的期望很高,导致DC26中出现了一些影响访问的问题,打击了大家对协作平台的信心。不过还好,在赛前,Azure和Mr. Robot完成了部分后端代码的强化工作,并在比赛之前完成了核心模块的测试工作。我则从公司出发,带着:
- 一台用作路由器的BPI-R2,以及作为备份的树莓派;
- 一台支持VLAN的交换机,防止OOO的网络配置和DC26不一样,当然事后证明多虑了;
- 一块将近160Wh的蓄电池,足以支撑上述设备在没有电源供应的情况下满负载工作几个小时,航空公司竟然真的让我把电池带上去了;
- 以及一些笔记本和摄像头,用来协助做现场监视。
在提议将热点名称改成Tea Receivers后,就收拾东西准备迎接正式比赛了。DC 27是分布式布局,CTF场地是在Planet Hollywood的Mezzanine。不过和其他国内队伍差不多,我们的人员也是分在三个点:现场,酒店套房和国内支援,三点之间靠OpenVPN
组成了一个大内网,内网和主办方的内网互通。此外,为了保证协作平台R
正常运行,需要维护用来执行攻击任务的脚本Ra
和用来解析主办方题目状态的脚本Rp
。那么作为运维的常规工作就很清楚了:维护好内网,维护好bot,应对一些奇妙的新网络需求,顺便水个签到题。
第一天过去布好网络后最大的感受就是,这空调开的真足,加上楼下人不多,没人帮我挡风,感觉腿好冷,不知道是不是酒店要照顾楼下在赌博的大爷大妈们……网络方面除了因为Google(一如既往的)对酒店网络访问Google DNS做了干扰,其他一切正常,所以作为国内队伍自然祭出了114.114.114.114
用。除了一些服务被d、服务下线、服务被d后下线之外的小插曲外,第一天的比赛就结束了。
第二天的比赛,主办方一大早就给每个队伍发了一个xbox 360
,说要把这个连到主办方的网络上,来完成题目dooom
。接上显示器后发现,显示器应该会走DHCP拉一个IP地址,于是重新配置了下交换机,将网线分出来一条接到了xbox上,同时把xbox的包抓出来分析了下。但不巧的是,因为自己手滑把路由器的一些配置写错了,再加上主办方似乎应用了DHCP限制,导致我们大概有半个小时左右的时间,没法从DHCP拉到IP。后来分析,这个DHCP限制应该一部分原因是由于,xbox本身是通过DHCP拿到IP后,去找网关启动的,可能他们认为网络上过多的DHCP请求会间接加重服务器负担,所以就做了一些限制。有趣的是,此时也似乎恰好赶上了主办方自己的网络出现问题,从中午11点多开始scoreboard的可用性开始下降,一段时间后完全不可用。
网络恢复后,开始和来楼下的同学一起看这个题,分析流量后认为应该是可以通过我们自己的DHCP服务器,给xbox的bootloader下发一个新的固件,达到patch。于是飞速重新划了个vlan,启动dhcp服务器,跑起来队友的脚本,之后就是常规的逆向、patch、打人的操作了,可以把KoH当作Pwn来做了。不过Zach大师的writeup也介绍了他们的方法,只能说毕竟是老牌队伍,这都能干这么多分,自叹不如……
美好的做题时光总是短暂的,jackyx开心的游戏时间(虽然没有很nb的枪)也走到了尾声,dooom
在被HITCON拿了一堆分数后,很快就离开了我们(rip),而我的网管任务也在第三天来到了尾声。第三天和前两天一样,没有什么变化。只是在实践中发现,攻击脚本Ra的运行不仅不够平稳,规则也不太灵活,因此后面的一两个题现场好像还是依赖人工打出去的。
我是在酒店看最后的颁奖典礼的,结果算是差强人意,但在比赛结束时也多多少少有预计到会是这样的结果。因为准备和朋友们去黄石玩,所以跳过了一些有趣的party和自助餐环节,直奔机场了。事后想了下:
- 从来没有预计到DHCP竟然会成为卡点;
- 酒店网络实在是糟糕,也不知道明年会在哪个酒店,头大;
- 今年攻击脚本没有发挥出最大的效用,表面原因还是大家的习惯问题,但深层原因是协作本身的成本就很高;
- 类似的,和我们一样,Tea Deliverers的writeup中也有提到,idarling也需要改进。在赛前我们实际花了很多时间和精力处理idarling相关的问题,相信TD也有,但看来无论是我们还是TD,都没有达到符合预期的成果。深入思考后我觉得,核心问题在于IDA的重交互,让实现“协同逆向”这个目标的难度过高了。
Baba O'Riley
实际去年在去DEF CON之前,感觉或许DC27是我为数不多的几次DEF CON了,因为周围的环境已经和之前不一样了。然而万万没想到,环境不仅变了,变的还很剧烈。以至于干爽的夏夜晚风,变得燥热和阴湿。
在这次Cancelled DEF CON前,国内的疫情基本上得到了有效控制,所以最后决定在公司的会议层把线下参与的所有同学召集起来(羡慕麦香的大别野)。因为今年整个DEF CON都是线上版本,所以CTF的时间也被划分成了四个赛段,基本上几个主要大陆的白天和晚上都包含进来了。对运维的好处就是,因为不需要考虑套房网络这个最不稳定的因素,所有基础设施都可以放在云上了。此外,按照去年的经验,以及我们观察到的OOO出题特征,感觉攻击脚本Ra和状态解析器Rp所带来的成本会大于收益,因此决定在比赛中仅使用协作平台的基本功能。
纯远程的比赛,大概需要考虑的就是这么几个部分:
- 和比赛方网络的连接。按照OOO给出的指南,我们会通过一个带有
wireguard
的jumpbox
接入比赛内网。考虑到美国云市场的情况,估计他们用的就是aws,所以在云上提前买了美国的机器,用来写入wireguard
配置。 - 选手接入网络。由于大多数选手都在国内,因此需要准备好国内的VPN服务器,并提前分发配置信息。此外,因为在美国也有同学参与比赛,也需要准备给他们的VPN服务。不过需要在服务器上屏蔽掉对方的IP地址,防止国内同学误接到国外VPN(或者反过来),导致被GFW封锁。
- 我们自己的服务设施。根据业务特性的不同,服务器可能需要在不同的地点。比如,协作平台的主要用户在国内,因此相关服务要部署在国内的服务器上。而有些exp对延迟要求比较高(比如涉及到侧信道的攻击方法),因此需要在国外也准备服务器。
- 中美服务器网络的Peer。因为所有的服务都部署在上,考虑到中美之间的网络本身就不够稳定,我们果断决定借用〇〇〇提供的专线,将国内和国外的两个云内网接在一起。
大致决定好了基础网络架构后,用一个下午的时间设置起了整套系统,以及重启后的恢复措施,保证不会因为一些奇怪的母鸡问题导致VM重启后长时间中断业务,顺便加了一些安全策略,并将所有服务器加入了Netdata,然后就静待OOO的配置了。整体的网络架构大体是这样了:
+---------------------------------------------------------------------------+
| |
| >Other players in our team< |
| |
+-----------------+----------------------------------+----------------------+
| |
| |
| OpenVPN | OpenVPN
| | The `dc28-redir-controller`
+--------+------+ +------+--------+ is deployed here
| | | |
| VPN Endpoint | | VPN Endpoint | |
| for CHN users | | for USA users | |
| | | | v
+-------+-------+ +-------+-------+
| | +---------------------------+ +--------------------+
| bandwidth and ACL limited! | | | | |
| save some money ;) | | Jumpbox, config copied +-----+ OOO's WG endpoint |
| | | +-----+ from OOO's machine | | |
| | | | | | | |
+---------------------------------+ | v | | +---------------------------+ +--------------------+
| | +-----+-----+ +-----+-----+ |
| CPU-intensive applications | | | QoS Promised | | |
| since EPYC servers are only +------+ Gateway +------------------------+ Gateway +------+ +------------------------------------+
| available in CHN available zone | | China | MPLS VPN? not sure. | U.S West | | |
| | | | 110-130ms, <0.1% loss | +------------+ Latency-aware programs |
+---------------------------------+ +-----------+ +-----------+ | & |
| Traffic-heavy programs (like pcap) |
| Reduce costs under the ocean |
| |
+------------------------------------+
- All connections are using WireGuard unless specified.
- Netdata is installed on all machines so we can do remote telemetry
and receive alarms.
在比赛前,突然想起来OOO有提到过,这次比赛会有Normal和Stealth两种端口方式,因此和space、dadong临时赶工,做了一个转发控制器,保证不会因为手滑打错端口。上线后大家的反响还不错,而且从赛后听到的一些情况看,的确有的队伍出现过打流量打错的情况(第一轮打Normal,之后就开始打Stealth),侧面证明这个工作还是有意义的。
OOO方面,因为这次是一次“云原生”(请允许我滥用下这个概念)的CTF,因此他们也引入了一些措施,包括:
- 私有题目实例,导致就算你能D别人,其他队伍也不会被影响,而且OOO原本就会手动检查patch。这无疑进一步加重了运维同学的工作量,也带来了一些问题,但可能更多的是他们的经验不够丰富,因为在〇〇〇和〇〇〇〇等公司的CTF平台中,为了阻止一些老搅〇棍(以及我这种乐于看戏的)获得乐趣,就引入了这种方式;
- 打到600个flag就下线服务,结合之前的分段下线。这个很好,很活跃气氛,而且实际上给了队伍更多动力:能否找到更奇妙的利用方式?能否找到更奇妙的洞?
云原生的好处就是OOO的资源几乎是无限的(depends on your credit card),但坏处就是往往让人对架构过于自信,以至于忽视了一些原生运维中遇到的带宽等问题,结合他们之前的一些Devops问题,总的一算确实给这次比赛的体验带来了一些影响。实际和他们一样,我也犯了一些不大不小的错误,不过好在没有影响最终结果。对大盘有比较严重影响的就是在比赛中间,预设的网络报警弹了下。起初以为是偶发抖动,后来发现专线丢包率可以达到10%,以至于影响到了队友打exp。登录监控系统发现,为了把流量发回另一个分析系统进行分析和重放,20M的专线带宽被占满了,因此临时把专线带宽限制提升到了100Mbps,不过还好比赛后就没有发生类似的情况。至于服务器爆内存等,基本都通过云上的快速资源扩容解决了,没有收到太多的影响。甚至还充当人肉打字员,帮做crypto的同学打了几圈,直到题目下线。此外,赛中做KoH的同学提议,是不是有个面板能看到得分历史比较好一些。想了想也有道理,但即便写了解析脚本Rp也不太好实现这个功能,索性用一些现成工具快速搓了一个,上线效果还不错,感觉自己也算是DevSecOps一把了(你说看不到Sec在哪里?我不是有配iptables
?)。
因为赛中大家基本都在会议室,感觉会议室会变的很热(虽然有空调),所以大部分运维工作都是在工位通过线上会议完成的。虽然在最后的十几个小时到会议室跟着看了几个题,但基本上已经错过了整场比赛最有意思的部分:Manchester Dataflow Architecture。数据驱动的思想虽然让我有点不怀好意的想起了某理论,但仔细想了下,这个思路其实和六七十年代的模拟计算机有一点关系,把Compiler理解成电路图后,也大概能了解一些题目的意图了,感觉如果用电容和电感搭一台这样的计算机,应该是一个很有趣的挑战(笑)。途中还去围观了下pinboool
的题,感觉可以通过scoreboard上的那个长的很像CFG的动画,映射到真正的程序执行流上,然后就有队友做出来了(md好强),虽然两者有一定差别,不过还是对这个题起到了一些帮助。一边看题一边想,这个东西对思维模式的冲击还是很大的,出题好用,所以明年估计还是会用(没想到一语成谶……)。
最后投入时间比较长的是gameboooy
这道题,也恰好因为自己对gameboy比较感兴趣(指在工位抽屉里有一台山寨的gameboy),就跟着过去逆了一下,把涉及到VRAM和ROM的一些东西逆了一圈,确认了GPU的工作过程和原生的ROM没有太多差别,但没找到任何有帮助的东西,百思不得其解。最后搞得会议室里众人十分萎靡,dmxcsnsbh说这应该是一个不知道为什么被出错了的条件竞争,而我不信。最后证明他的想法是对的,的确是一个条件竞争,但似乎是因为编译器优化的原因被吃掉了。
比赛结束后会议室里的气氛并不算特别好,因为结果实在不好确定,直到成绩最后公布的那一刻。看Zardus宣布成绩的gif其实还没反应过来,直到听到第二名是PPP才意识到是自己第一,听到自己被宣布是第一名时就激动了,甚至把旁边几个会议室开会的人都吓了一跳(抱歉)……
总之开心是很开心,赛后想了下:
- 疫情控制得当,在这次比赛中显然演变成了主场优势,但人多带来的沟通问题和人力浪费问题也超过了预期;
- KoH的确很有意思,虽然被打的有点惨,但真的有意思,比攻防有意思(虽然会被人吐槽不纯粹);
- 传数据包这种典型的大流量业务应该走公网的,不应该出问题后才扩容,浪费了一些预算而且影响了业务;
- 监控指标应该再精细一些,且占用带宽长期高于一定程度的话,就应该先扩容了,不应该等到丢包的地步;
- 缺少更精细的流量调度能力,不过说是这么说,到底要怎么调度,也没有想好……;
- 协作方面,协作工具实际上并没有太大变化,而且甚至都使用起了微信群,个人觉得这个东西是真的不堪用,不仅沟通效率低,新来的人也不知道上下文,而且这个小而美的应用可真的是……;
- 不过语音会议真的是个好东西,以至于在DC结束之后,如果需要远程工作的场合,都喜欢挂一个会议软件在线上,这样别人要叫我的话只要加入会议就可以了。
一边开心,一边在想,明年的CTF要怎么办呢?也算是比较深刻的领会到了美国的联邦制特色,不同州的控制力度截然不同,在当时也完全看不出两国边境重开的迹象。总之一边怀着对边境重开的美好期盼,一边沟通badge的邮寄事项,一边思考明年的CTF有什么可以做。
所以最后请吃饭了嘛?
I Don't Wanna Leave Tonight
到了今年,事情变得更糟了,有关部门甚至暂停了护照签发。两国关系也每况愈下,和朋友之间的正常邮路被干扰,邮局的朋友也说从美国的退包变多了,以至于直到今年的Quals之前还没收到奖牌,索性不想这些,安心准备比赛。
新的网络
相比于前几年赛前组织的几次专门比赛,今年Quals前大家基本以其他CTF作为练习和娱乐的方式,仅在Final前一周举办了一次测试赛,以便新同学习惯环境。今年的比赛采用Hybrid模式,线上和线下同时进行。根据主办方提前发过来的邮件,接入比赛网络的方式似乎和去年一样,是通过jumpbox里的一个wireguard配置文件,设置好路由表,所以今年在云端的框架也基本和去年类似。不同的是,经过之前在其他业务上的一些测试,我对云服务上的VPC能力更有信心了,因此决定今年在云端除了必要的peering(比如和主办方peer)外,其他流量都通过云上的虚拟网络来解决,这也算是“云原生”的CTF了。 ;-)
此外,由于在Quals中,不常驻在公司的同学反馈链接公司网络过于麻烦(需要绕来绕去,而且带宽也有限),因此在Final前我决定除了保留原有的VPN接入方式作为备份外,还是给大家部署一个专用的无线网络比较好,这也是今年的网络部署和去年最大的不同。整体拓扑就变成了这样:
+---------------------------------------------------------------------------+
| |
| >Other players in our team< |
| |
+----------+------------------------------------------------+---------------+
| |
| |
| OpenVPN | OpenVPN
+-----------------+ +------------------------+ +---------------------------------------------------------------------------------------+
| | | +---------------+ | | +---------------+ |
| | | | | | | | | |
| Meeting Rooms +---------+ VPN Endpoint | | | | VPN Endpoint | |
| | | | for CHN users | | | | for USA users | |
| | | | | | | | | The `dc28+redir+controller` |
| | | +-------+-------+ | | +-------+-------+ is deployed here |
+-----------------+ | | | | | |
| | | QoS Promised | | + |
| | <<-------------------------->> | | |
| | | MPLS VPN? not sure. | | v |
| | | 110+130ms, <0.1% loss | | |
| | | | | +---------------------------+ +--------------------+ |
| +-----+-----+ | bandwidth and ACL limited! | +-----+-----+ | | | | |
| | | | save some money ;) | | | | Jumpbox, config copied +-----+ OOO's WG endpoint | |
| | Other | | | | Other +---------+ from OOO's machine | | | |
| | Servers | | | | Servers | | | | | |
| | | | | | | +---------------------------+ +--------------------+ |
| +-----------+ | | +-----------+ |
| | | |
| Cloud VPC - CN | | Cloud VPC - US |
+---------------+--------+ +--------------------------------------+------------------------------------------------+
+ All connections are using WireGuard unless specified.
+ Netdata is installed on all machines so we can do remote telemetry
and receive alarms.
从mamamiya10那里打听到,和去年差不多,本次比赛会用到会议楼层的5间会议室,每间会议室大概是6mx8m的样子。外网方面,不巧的是,由于一些大人的原因,每条外网链路的带宽只有40Mbps,而且需要为每条外网链路单独引一根网线(不是光纤),在这根网线上只能有一个mac地址。但幸运的是,这些链路的数量是基本不受限制的。此外,在用户接入方面,最好能让用户直接接入到比赛内网中。
赛前整理了下手中的材料,似乎有:
- 比赛前从淘宝买到了一台6端口的杂牌软路由;
- 在仓库中挖掘出若干态TP-Link入门型家用无线路由器;
- 一台由Azure留下的无线路由器,装好了openwrt。在往年的比赛中,这台路由器是放在酒店房间的;
- 原本被用来
拆解测试的,一台H3C S51xx的三层交换机,有24个千兆电口,4个光口;
除此之外在京东上买了一些网线、地毯胶带之类的耗材。
网络部署方案,则相对从简:
- 从各个地方接出10条公网网线,接入交换机上;
- 软路由作为网关,使用全部网口,和交换机做
bonding
连接(lacp,L2+L3 hash),并透传所有VLAN; - 在交换机上划分出四类VLAN,分别用于:
- 用户接入(1000);
- 流量路由(1500);
- 网管(500);
- 与公网上游互连(1200-1300);
- 每个房间各部署1个无线路由器,当作接入点使用,链接到用户接入VLAN上,并通过调整接入点信号强度,保证终端尽量落到最合适的接入点上;
- 用交换机承载接入业务(DHCP和DNS转发、三层路由到网关)并实现部分ACL;
- 刚好剩下两个网口,在路由设备所在的会议室,用有线预留几根网线,供紧急情况下接入网管段,或进行流量镜像使用。
因为所有VLAN都被透传到了网关,所以和公网互连的工作也要由网关负责。通过ECMP,可以保证不同的会话被分配到不同的外网链路上,从而让接入到网络中的用户能够分担不同链路。除此之外就是一些常规的SNAT、防火墙配置等工作。
但仅通过ECMP并不能实现带宽的有效利用,因为在比赛中需要优先保障的是会议层用户和云上服务器之间的高带宽,而OpenVPN只会有一条TCP链路。因此,经过比较了一些方案的性能后,我决定使用MPTCP作为会议室网关和云上互联的三层协议。由于我们需要通过OpenVPN实现对接,因此除了更新到较新版本的内核外,还需要将已有的OpenVPN程序适配到MPTCP下。由于时间比较紧张,在不熟悉程序的情况下,重新编译程序比较麻烦。因此我决定使用systemtap修改系统调用的参数(也可以使用LD_PRELOAD
实现此目的),从抓包中便可以看到,服务器和客户端之间已经带着MPTCP相关的协议头在公网链路上进行三次握手了:
理论上,只要给服务器再增加一些公网IP,就可以让mptcp在多条链路上建立通信,从而发挥ECMP的负载均衡作用,实现VPN内的高带宽和强可靠性了。但在我们的场景中,仅是这样,还不足以让mptcp发挥作用。因为在我们的云服务器中,由于采用了私有网络,因此服务器上网卡的IP地址都是某个子网的私有地址,而非这个网卡对应的公网IP。为了在不做重度修改的情况下,让通信双方发现服务器所具备的公网IP,还需要使用ip mptcp endpoint
命令进行一些修改,这样就可以了。我们选择了两条链路作为测试,如图:
除此之外,吸取了去年的教训,对传数据包这种重要性一般、但代价极大的业务用公网定期rsync,对其他一些反馈过的问题也做的调整。此外,除了将所有服务器加入netdata外,本次也在netdata上配置了更多的监控告警规则,防止发生网没了但自己不知道的尴尬情况。
在决赛前一周的练习赛前,上述网络就已经准备好了。但在练习赛中,有同学反应自己上网非常困难。经过检查,感觉是交换机的DNS转发服务如果直接使用公网的DNS服务器会有问题,因此我决定在网关上加布一个SmartDNS作为缓存服务器,将查询转发到这台缓存服务器上(flag1)。调整后,仅有零星几个请求出现了问题,我感觉应该是偶发问题,可能和对端有关,因此没有深入看(flag2)。不过当时也没想这么多,训练赛结束后,将所有用到的命令、脚本等整理到一个在线文档后,就开始等待决赛。现在回头看,没处理好这两个flag,给比赛中的基础设施带来了不少麻烦,幸亏有这个在线文档,救了一命。
A-roll
决赛那周的周一晚上,因为一些其他事情,我不得不临时离开比赛地。直到比赛开始的六小时前,我还被堵在首都机场高速上。在此期间,在现场的rambou、digle等大佬们,已经从我零散的文档中推断出了一些网络规划,并已经帮忙大致铺设好了遍布五个会议室的所有网线,总长度约300米。比赛前一小时,我终于回到了比赛现场,马上打开电脑开始部署,借助之前整理好的在线文档完成了启动,顺便帮忙整理了剩下的一些网线,总算是没有耽误比赛,但原本在比赛之前预留的一小时网络测试时间就不见了。
因为今年是线上、线下混合模式的比赛,所以和往年的线下比赛一样,分三轮进行,setup时间是每天凌晨0点。为了保证线上队伍和线下队伍有尽量公平的环境,OOO要求所有队伍都使用jumpbox接入比赛网络,他们的服务也都部署在云上。按照往年的经验,DEF CON现场的网络不是很稳定,偶尔会有奇怪的断网行为,但估计是因为疫情影响,没有太多队伍在Discord频道里反馈有断网的问题。
周六凌晨一点,比赛开始,但随后大家就反馈访问网络断断续续的,从抓包结果看似乎依然是DNS问题,登上交换机一看,原来是训练赛时候设置的DNS没有保存,还在往外网的DNS服务器发送请求。因为DNS是工作在转发模式,所以修改配置后可以立刻生效。但似乎依然不能访问team interface,不久Zardus在公屏通知大家,比赛因为网络问题延迟一小时开始,并顺手发送了第一道题目。PPP的Writeup里大概介绍了这个题目,很有趣,赛后我也玩了一会,不过在比赛时,完全没有时间顾及这道题目,因为要在服务器上跑起来各种脚本。
在若干脚本中,其中一个脚本是负责获取当前比赛信息的。在OOO的比赛中,所有数据会通过一个game_state.json
提供出来,我们则用一个非常简单的while true; do ... done
每隔一段时间抓取这个json,并将解析后的结果输出给其他服务。按照正常的放题规律,在比赛初期这个文件应该只有几k大小,因为放出的题目不多。不过出人意料的是,第一次运行脚本,就拉下了一个1MB的文件。还没等开始分析这个文件,就看到Zardus在公告频道说,PPP已经发现了这个问题并通知了主办方。文件泄漏是他们不小心将测试文件放到了生产环境中,因此为了公平起见,他们决定公布这个泄露的json文件。不久后的captain meeting上,Zardus也说原本600个Flag即下线服务的机制,可能会暂时取消了。
不久后比赛开始,但又有人反应访问外网出现问题,查了半天发现是那台Netgear路由器不知道怎么回事,二层表现很奇怪,用户间不能互相访问,而且在网络上乱发一些二层报文。感觉可能是要寿终正寝了,加上感觉来的人也不多,甚至有一个会议室是空的,索性把空会议室的路由器挪用过去,就解决问题了。回到椅子上感叹,可能网管就是这样吧,用最简单的思路解决最低级的问题……
没等感叹完,又有人报警了,而且是连同自己的监控脚本一起报警的,是访问外网偶有超时、链接不上等等,不过对到比赛网络的VPN链接没有影响。看了半天流量和抓包结果,没有头绪,感觉是偶发问题,但在部分同学的机器上甚至无法访问网络,像极了在测试赛中的那个没有回收的flag。因为流量比较大,大家也都在比赛,找用户抓包显然是一个不太讲道理的选择。考虑到只影响一部分用户,且不影响比赛流量,感觉还是等这一轮比赛结束后再处理比较好,索性让有问题的用户先用VPN连,自己也不准备再看题了,还是看网络情况,保证大家能做题比较要紧,直到第一轮比赛结束,没有太严重的问题。
第一轮比赛结束后,趁着大多数人都去睡觉,用户不多,开始修网。此前提过,为了实现对多条外网带宽的负载均衡,我们使用了ECMP,同时也使用了MPTCP。一般来说,在这种情况下,要使用策略路由,然后设置好这样的路由表:
# route table eth1, gateway 192.168.1.254/24
default via 192.168.1.254 dev eth1 src 192.168.1.1 table eth1table
192.168.1.0/24 on link table eth1table ...
# route table eth2, gateway 192.168.2.254/24
default via 192.168.2.254 dev eth2 src 192.168.2.1 table eth2table
192.168.2.0/24 on link table eth2table ...
并添加这样的策略:
3000: from 192.168.1.1 lookup table eth1table
3000: from 192.168.2.1 lookup table eth2table
这样的目的,是保证流量被正确的发送到对应的网卡上。这样,理论上,我们可以用这样的一条命令,来测试eth1
这条链路的状况:
ping -c 1 --interface 192.168.1.1 192.168.1.254 # test link
ping -c 1 --interface 192.168.1.1 1.1.1.1 # test network
这样,在默认路由表中,加入一条:
default
nexthop via 192.168.1.254 dev eth1 src 192.168.1.1 weight 1
nexthop via 192.168.2.254 dev eth2 src 192.168.2.1 weight 1
来方便的控制路由。此外,通过使用上面的命令检查链路状态,可以在检测到某条链路出现问题时,用ip link set dev eth1 down
关掉,从而保证默认路由不受影响。然而在抓包过程中,意外发现,上面两条用来测试eth1网卡的ping命令,会在eth2网卡上发出ICMP包,源地址却还是eth1网卡的源地址。由于上游链路的限制比较多,这个包显然会被上游直接丢掉。使用iptables
的trace
后,发现并不是netfilter导致的问题。此外,前面提到过的systemtap程序仅对openvpn起作用,按理讲不会影响ping才对。看来是路由层面出现的问题,百思不得其解之时,查看了下路由表的内容:
# ip route show table eth1table
default via 192.168.2.254 dev eth2 src 192.168.2.1 table eth2table
192.168.2.0/24 on link table eth2table ...
很灵异。为什么查看的是eth1table
,返回的却是eth2table
?突然想起来,内核实际并不用名字来区分路由表,而是用一个编号。名字和编号的对应关系,定义在rt_tables
中。打开一看,果然不出所料:
30 eth1table
30 eth2table
40 eth3table
40 eth4table
不同的编号被赋予了相同的名字……想来是配置的时候太困导致打错字。而和云端互联的VPN通道之所以没有受影响,是因为我们给云端的VPN通道分配了4个IP,加上MPTCP的保证,只要有一个IP恰好被分配到正确的路由表项上,就不会出问题。总之,这是一个非常低级的错误。
修好后,感觉没什么事做,被bigtang师傅叫去看broadcooom
,帮忙分析了一部分交互逻辑。这个题实际上是泄漏出题目的一部分,归属于ooows
系列。从名字也能看出来,是做了一套虚拟化的体系,而这个题自然是neta了broadcom
,写了一张虚拟网卡,可以放在不同的主机上,通过mosquitto
(MQTT)实现通信。MQTT本质上是基于pub/sub的,客户端连上服务器后,可以对某个topic发消息,也可以收某个topic的消息。在这个题中,MQTT大概是被当成一个二层的集线器(hub)来用,是真的hub,发消息后所有人都会收到,然后根据发送的id和vpcid来决定是否要把数据交给网卡的firmware。网卡的firmware比较有意思,听其他同学介绍是自定义了一个cpu,这个cpu有4个虚拟的核,执行方式有点像node
的事件循环机制,在A核上会一直处理,直到阻塞在队列上,然后去B核处理事件循环……大概是这个样子,不过我并没看这部分。除了让我想起了node.js
外,不由得想起了去年决赛和今年预选赛,让我受益匪浅的曼彻斯特机……
B-roll
解决了各种混乱的事情后,已经离下一轮比赛开始没多久了。第二轮比赛开始后,见网络没有大问题,就去睡觉了。没想到睡了三个小时不到,被space从梦中叫醒,说网络又出问题了。从气垫床上爬起来,登上网关一看,外网链路有一大半处于不可用的状态,二层的广播包尚且有反应,但三层到网关完全不通。想了想,应该是坑爹的上游链路问题,难道是一段时间没有发DHCP包就会被踢下线?于是手动renew下,一切正常了,继续回去试图睡觉,幸好不影响VPN链路……
睡自然是睡不了多久的。醒来回到座位呆了一会,就听到www
题目被放出来了。此时已经完全不清楚大家都在干什么(因为睡觉的时间点不是很对),于是跟着看了看。应space的需求,写了个脚本,循环检测跳板机上的密钥是否存在,如果不存在的话重置密钥和rsync,然后拉回流量,顺便把网络内到这个题目的网段13.37.0.0/16
和192.168.0.0/16
,经过redsocks
处理后,通过跳板机发走。不过工作量实际不多,主要的经历都分配在如何在碰路由表的时候防止服务中断,以及如何配置redsocks
,顺便将这个题目的分数单独爬出来,灌到数据库里,以便可视化使用。
想来也是有趣,我的网络知识大多拜GFW所赐,但基本都在CTF中派上过用场。
此外因为KoH的一些脚本耗费资源过大,导致内存爆炸,因此将脚本单独放到了一台服务器上跑,再次证明了预先做准备的重要性……这个题给我的感觉是,所有人乘着时光机回到了2003年:
你手里有一个0day,有一个ISDN Modem,有一堆没有打补丁的机器,你要做什么?
主办方后来还说他们还在网内放了几台Windows 2000的机器,不过我们似乎因为扫描流量太多,所以没发现。题目页面也冒着一股西部牛仔的风格,总之这个题也的确是很有意思。
第二天结束后,为了保证第三天的比赛不受影响,我临时将专线级别从铁牌改到了银牌。此外,比赛方面,主办方循例放了几道题,说大家可以在晚上看看,但不确保一定会放题,其中一道是ows系列题目的最后一体题hyper-o。比赛结束不久后,dmxcsnsbh在大群里说这个题有点意思,于是我也被吸引过去看了起来。
题目本身是一个带有符号的kernel module,拖进去一看遍地的VMREAD
,再结合hyper-o
这个neta,就知道这应该是个VMM。队友拉出了好用的插件,我不懂挖洞,也不懂linux kernel,闲着的话也显得格格不入,于是索性开始从Intel SDM的22章开始读起,学习一点虚拟化技术,写一点读书笔记。从代码来看,出题形式应该也不会很复杂,将shellcode喂进去就好了。但因为题目的init
还没有给出,而整个ows
系列也还没出过race,于是我在想,会不会有那么一种可能,一个连接就在VMM里起一台新的虚拟机……以至于最后困的不得了,被dmxcsnsbh拉着一起一个个bit的看虚拟机的启动逻辑,自然也都是一无所获。
为了保证第三阶段我的脑子还在线,索性去睡觉。醒来后才知道大佬们已经在页表中发现了问题,但没来得及写出exploit。其他同学从流量中发现了exploit,通过写寄存器的方法传输flag,虽然只读了一半,不过汇编很容易读,简单修改后我们就抄好了作业。因为这一题的题目始终不太稳定,因此决定将受害者分成几组,分别打。
令人伤心的是,作业还抄的不够开心,这一题就被升级到了第二阶段。这一阶段就和其他题目一样,我们需要上传一个完整的磁盘镜像,虚拟机会从这个磁盘镜像启动,然后运行我们的exp。洞虽然修了,但exp不是很好写。jackyx试图写显存,但似乎因为一些奇怪的原因没有生效。我则从流量中看到了一些可疑的痕迹,但要么重放后没有效果,要么是因为服务问题无法上传到服务器上。OOO中途也重置了几次环境,这样不仅负责patch的xhj需要重传patch,我也要测试下之前传过的镜像是不是可以用……在最后几十分钟,由于一些奇妙的原因,我们和其他队伍都不能访问自己的实例,但可以被打,不由得让我想起了去年的bdooos
。无论如何,比赛按照预定的时间结束了。在最后几分钟,我终于完成了本次CTF里,个人影响最大的一件事:公放《The Final Countdown》
赛后大家拍合照的时候,才意识到今年的人的确比去年多。虽然从WLAN的接入数量上没看出来,但网络流量基本是和去年持平的,可能是因为大家感觉现场公网比较卡,都自己找其他热点了……“网卡”甚至延续到了公布比赛成绩的时候,此时现场临时搭建的网络已经撤除,我在用会议室的Wifi,给大家直播DEF CON TV。奇妙的是,在公布第四名的时候,twitch开始转起了菊花……坏运气真的是能维持到最后一刻。最后大家围成一圈,在space的手机屏幕前,看完了整个闭幕式,也算是一种别样的体验了。
比赛后整理了下服务器上的数据,感觉从流量规模上和去年差不多,没有什么值得一提的。今年由于用了新的网络,也带来了一些问题和反思:
- 多备份,多测试,早上线,早测试,真的很重要。虽然是有一些不可抗力的因素在,但一些低级错误(比如写错路由表名字)还是不该发生的;
- 复杂度太高不好,容易扯〇,但多尝试总是好事(只要不要太影响大家的信心……;
- 赛中为了应付
ogx
这个题,一度找不到服务器,看来只靠云也不太行; - 今年比赛临时写的三四个脚本里,其实去年都写过,所以资料保存很重要,但复用也很重要。不过这个意义不大了,毕竟明年要换主办方……;
- 流量调度完全没做,也没有准备,这可能也是www题里大家互相干扰的一个原因,侧面说明协作的重要性;
- 服务器之间数据共享也有问题,一份流量传N次,不过还好都是在同地域,没有花流量费……。
除了网络有点抖动外,还为OOO感到可惜的一点是,题目泄漏实在是太出人意料了。按照这个题目难度,遵循600个flag即下线题目的规则,如果不出意外,这些题甚至很可能是大家都做不完的。然而木已成舟,事情已经发生了,也没有别的办法能够补救。
在多人协作方面,实际很容易观察到,人越多,维持协作的成本是几何级上涨的,而idarling
等工具在此时带来的麻烦甚至会远多于能解决的问题。我们在多人协作的方式、方法和工具上作出了一些努力,但这还不够,可能还需要更长远的设计,以及更多的资源投入。
Komm, süsser Tod
流水帐很长,也不知道有没有人看。总之最后,姑且作为运维,在OOO的比赛中存活下来了,特此留念,希望老了也不会忘掉。从网管视角里看到的就是这么多了,年纪大了,只能看别人做题。选手视角的有队友写了一份,其他人或许也会写。
赛后看到了OOO原始的proposal,反复读了两三遍。Zardus、adam和OOO的所有成员,必然是配的上inspiration这几个字的。Legitbs时代是在探索pwn的可能性,而OOO时代则是在探索Attack/Defense外的可能性,虽然并不总是能像legitbs一样硬核,但拥有了更宽广的想象空间。在这样糟糕而充满遗憾的、被地缘因素和”大人们”隔离的20年代,能参与这样的ctf比赛,无疑是OOO对CTF社区的馈赠。
很幸运能和这样的一群人打ctf。感谢几年中为比赛提供支持的mamamiya10等同学,能和你们坐在同一块地毯上让我感到很开心。感谢space对本文进行的fact check。
没有人知道下一届defcon ctf会是什么样的,我只希望在逆全球化的浪潮中,还能有这样一个有趣的游戏可以玩。
不过对我自己来说,可能还会夹杂一点额外的私货。最近一年,自己已经离“纯粹的”安全研究远了很多,我熟悉的CTF也不是五年前的CTF了。这并不是坏事,反而让CTF对我来说更有意义,即是认识新朋友的方式,也是和旧识们见面的机会。引用宋教授的一句话:
每年八月,放下手頭的工作,在Las Vegas見故交新知,並肩作戰,折騰平時不想折騰的軟件,速成平時用不到的技能,繼續發光發熱(與其讓生命生鏽),享受這段時光。
(顺便求奖品,啥时候能发货)
Rainy Days and Mondays
这几周,屋外的雨格外的勤。开始写blog的时候是周日,写完的时候已经是下一个周日了,也意识到自己也很久没更新博客了。
这可能也是把爱好当成工作的一个坏处,虽然还能有余力在工作之外抽出时间做点自己感兴趣的事情,但毕竟要考虑到避嫌的因素,不能把工作上的事情带到非工作的场合中,所以姑且写了点东西但也没发出来。
另一方面也发现,爱好当成工作,对爱好多少还是有一些影响的。前段时间和同学一起(冒着行程信息被公开分享的风险)吃了顿饭,等位的时候同学讨论的一些互联网产品自己甚至都没听说过。上班几年,感觉对新事情的嗅觉显著变淡了,不知道是因为和身边的人一样患上了「互联网公司流行性感冒」,闻不出有趣的产品,还是说这更多是自己的问题,只是假托工作的名义罢了。虽然也还年轻,但偶尔也会感叹自己老了……毕竟接受新事物的能力真的不如年轻人了。看看周围还在努力的同学和同事们,不由生出一丝愧意,鄙人何德何能……
总之过段时间重写下blog,现在这样markdown的编写和存储方式,也不太容易和自己的其他资料存储在一起。最近在学Rust,感觉很有意思,清风拂面。