DEFCON 23 CTF参赛记

8月4日

从北京出发,起飞前两小时发现机票没有买成功,立即买了一张,感谢诸位队友。到达San Francisco后与昨日航班延迟一天的队友会合,21:00多飞往Las Vegas。今年DEFCON会场从Rio迁到了Paris & Bally’s。我们提前到达的在这里订了几间房间。

场外选手所在的套房

8月5日

在LINQ吃了一顿Hash a Go Go,一顿管一天,吃完就难受了,疼了一天,这一天什么都没做就过去了……

Hash a Go Go

8月6日

准备了一天binary hardening。

8月7日

比赛分三天进行,前两天从11:00到20:00,第三天从11:00到14:00。

10:00入场,CTF比赛和其他一些活动共用一个分会场,找到会场就花了不少工夫。参赛队伍的桌上有LED灯,每轮开始会闪烁一下,似乎还能表示攻击和被打,具体规则不明。大屏幕可视化各战队攻击情况。

可视化攻防状态的屏幕

比赛为攻防形式(attack and defense),每5分钟为一轮,每轮主办方更新各个服务的flag文件,分析题目程序、挖掘漏洞、编写exploit攻破其他队伍的服务,获取权限访问flag以得分。主办方有service level agreement,会检测各服务的可用性,如果判断为down也会扣分。具体分数计算规则不明。

10:40左右通网,我们可以访问gamebox了,ctf@10.5.8.4,~/README提供了一些说明。开赛前必须修改初始密码后,否则会扣分。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
- Important IP addresses
10.3.1.7 scorebot
10.5.8.6 capture
#### team vulnerable boxes
10.5.1.4 team1 ppp
10.5.2.4 team2 bushwhackers
10.5.3.4 team3 samurai
10.5.4.4 team4 hitcon
10.5.5.4 team5 defkor
10.5.6.4 team6 team9447
10.5.7.4 team7 gallopsled
10.5.8.4 team8 bluelotus
10.5.9.4 team9 spamandhex
10.5.10.4 team10 corndump
10.5.11.4 team11 0ops
10.5.12.4 team12 0daysober
10.5.13.4 team13 dragonsector
10.5.14.4 team14 shellphish
10.5.15.4 team15 lcbc

队伍编号是根据决赛晋级顺序得到的。

前两年的决赛平台都是armv7,大家都觉得今年仍是ARM的可能性很大,结果是个x86-64的机器,CPU是AMD Opteron(tm) Processor 6128 HE,Ubuntu 14.04,uname信息是Linux version 3.16.7-ckt13 (root@lxc1)。可能所有队伍共享一个机器,用lxc隔离,每支队伍分到20GB磁盘空间。

11:00比赛开始,每5分钟为一轮,每轮主办方会更新各个服务的flag文件,分析题目程序、挖掘漏洞、编写exploit攻破其他队伍的服务,获取权限访问flag以得分。主办方有service level agreement,会检测各服务的可用性,如果判断为down也会扣分。具体分数计算规则不明。

首先开放的服务是rxc,程序在/home/rxc/rxc,所有者是ctf;flag文件在/home/flags/rxc,rxc用户可以读取。我们用Dropbox把文件分享给场外套房选手。

10.5.8.6开放了sftp服务提供PCAPNG格式的流量文件,数据包文件会延迟一段时间提供。今年流量文件被处理过了,所有IP都被改成了1.1.1.1,无法判断连接发起的来源。这可能有几方面原因,如更好地隐藏service level agreement检查流量、让选手难以根据连接发起源做检查。

服务都是使用标准输入输出进行交互的,使用xinetd监听端口,xinetd运行服务时会把权限drop至服务名对应的用户比如rxc,配置文件/etc/xinetd.d/rxc如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
service bluelotus-service
{
disable = no
type = UNLISTED
socket_type = stream
protocol = tcp
user = rxc
group = rxc
wait = no
server = /home/rxc/rxc
port = 799
per_source = 2
log_on_failure = HOST
banner_fail = /etc/DoS-msg
nice = 10
killafter = 25
seccomp_whitelist = 0 1 2 3 5 9 10 11 12 13 14 16 21 23 35 56 59 97 158 202 218 231 273
}

后两个选项是主办方修改的xinetd特有的,其中killaftersetitimer设置了连接的超时时间,杀死卡死的进程。比如去年决赛的eliza用qemu-i386-aslr执行,CPU占用很大,经常有长时间不退出的连接,造成DoS攻击。seccomp_whitelist结合NO_NEW_PRIVSSECCOMP_MODE_FILTER等,设置了进程及子进程允许使用的系统调用。

主办方在gamebox安全上花了很大工夫,做的防护还有:

  • /home/ctf的权限会被定期改成0700,大概是怕选手不慎把重要资料泄漏出去。
  • /proc/net/tcp等无法读取,netstatss等工具无法看到TCP连接。
  • 进程自身的/proc/self/{personality,stack,syscall}无法读取。
  • 无法读取相同用户其他进程的/proc/$pid/{auxv,environ,maps,mountstats}等。

近15:00主办方宣布DEFKOR获得rxc的first blood,DEFKOR against PPP。实际发生的first blood应该还在这之前,开始吊打全场,比分逐步拉开。其他队伍分数相差不大,Shellphish、0daysober不久即相继防御成功,分数比余下队伍稍高些。

16:00多发现了新题ombdsu,在另外一个gamebox 10.5.8.2上,似乎是MIPS Creator Ci20,CPU是Ingenic JZRISC V4.15 FPU V0.0。

发现新题hearye.zip,ARM64的,做题得一次性分。我们没有在意,回去后才做,第二天准备提交时发现主办方关闭了题目,第一天做出来的才有分。

第一天流量混淆已经非常严重了。

HITCON似乎重放rxc成功,名次逐步上升。

19:00改了改之前ISC’14时的监控,写了一个积分榜。
自制积分榜

第一天结束时DEFKOR领先第二名7334分。
第一天结束时积分榜

晚上回去换了一种思路写binary hardening工具,稍晚研究MIPS的方案,希望第二天能用上。我们写出了rxc的exploit,ombdsu也有replay和exploit。

8月8日

可能大学都觉得现场嘈杂不适于解体,都不愿意来现场。10:00多来到现场,仍旧是先搭建环境。

10:40+允许访问外网,可以连接两个gamebox了,看到i386的新题hackermud,这是一个MUD游戏的客户端,程序启动时会连接主办方控制的10.5.17.4的5050/tcp。10.5.17.4:5050只允许gamebox连接,因此要让场外选手连接的话,得用SSH port forwarding等方式以gamebox为跳板连接。今天https://10.3.1.7/scoreboard不再显示积分,只能看到排名。

HITCON开赛即发动第一波攻击取得tachikoma first blood。

tachikoma似乎被主办方更新了,因此没有立即换上我们的patch。换了多个修补版本,改缓冲区大小,关闭NX等,但服务持续down,不知道主办方怎么检查的。折腾了好久,13:20服务状态终于up了,再改了一会儿终于不丢flag了。

12:31给rxc换上patch似乎不再掉分。

近15:00主办方宣布有新题。发现说明文件~/readme-rpi,是Raspberry Pi 2上的ARM Windows 10。参赛选手无法直接管理题目所在的平台10.5.8.3,只能通过主办方提供的简易FTP更新程序,以及通过PowerShell编写的、8989/tcp上的管理服务停止、启动服务。

16:00多放出mipsel新题irkd。以/home/irkd/irkd -i 10.5.17.4 -p 666 -n /home/flags/irk_nick的方式执行,需要连接服务端10.5.17.4,是个类似IRC的服务。

19:00多有队员失误踢掉电源线,服务器关机,几乎所有攻击都无法打出,图为这段持续20分钟的艰难时刻:

第二天结束时名次依次为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
DEFKOR
0daysober
Plaid Parliament of Pwning
HITCON
Dragon Sector
blue-lotus
0ops
Samurai
Shellphish
LC↯BC
!SpamAndHex
9447
Gallopsled
Bushwhackers
CORNDUMP

8月9日

为了悬念,今天不再显示排名。每轮时间从300秒缩短到150秒,今天三小时大概有72轮。

开场就看到DEFKOR的badlogger first blood。

badlogger的PowerShell管理界面更新了,可以一次性kill所有进程。我们上传了修补后的badlogger,但写好的exploit打不了。之后一直在修改badlogger的exploit,比赛快结束时才弄好,提交了十几个flag。

比赛前几分钟LED狂闪,循环播放The Final Countdown,震耳欲聋,14:00比赛结束。队员们这几天睡眠缺乏,大多去睡觉了。

闭幕式

16:00闭幕式。

闭幕式

DEFCON一共有8个urban gaming,Capture the Flag是压轴项目。第一名是韩国DEFKOR,成员大多来自首尔大学,似乎都是Best of the Best项目的成员,这是一个培养网络安全人才的计划。第二名是两届DEFCON CTF决赛冠军PPP (Plaid Parliament of Pwning)。第三名是0daysober,欧洲多国联队,成员主要来自瑞士法语地区和法国。

结束后送出了一些吉祥物……但镇宅之宝我们队员都没拿到……

准备

参加完ISC’15 Student Cluster Competition回来已经被剥夺学校寝室居住资格了,这段故事也许之后应该再写篇文章记录。飘零,搬到了一个赛前备战的地方,做了一些东西:

系统管理脚本

下载流量文件自动切分、杀死后门进程等。今年主办方在封杀后门,营造一个纯粹的逆向、漏洞利用的比赛环境上作出的努力不可谓不大。杀死后门我着实思考了很多,不过在这次比赛上都没用上。

系统管理脚本

左上读取积分,右上下载流量,左下更新badlogger,右下用coproc实现semaphore,并行化PCAP/PCAPNG的预处理供索引工具使用。

GitHub项目:https://github.com/MaskRay/DEFCONCTFFinalsGameboxAdmin

搜索flag

在流量文件中找到flag定位攻击流量是流量分析的关键。以往使用wireshark的display filter搜索flag,性能很差。因此我写了一个多串匹配工具搜索flag,定位后解析PCAP/PCAPNG,按frame拆分后把偏移量转换成frame.number==1337式样的filter,方便深入检查。多串匹配采用Multi Backward DAWG Matching算法,网上没有找到字串长短不一时的构造算法,自己揣摩并实现了一个。大意是取最短的模式串为窗口大小,初始时窗口左端与文本对齐,检查所有与窗口右端对齐的模式串能否匹配文本。若找不到则对于所有模式串的所有前缀,找到其中最长的落在窗口右端的前缀,滑动窗口使之与该前缀对齐。

该算法需要实现多串suffix automaton/suffix oracle。General Suffix Automaton Construction Algorithm and Space Bounds提到了一种多串构建方法,但只对suffix-unique的字串集有效。研究后发现常规的单串构造算法稍加修改即可用于多串。

PCAP搜索引擎

流量分析时经幢需要搜索字串。Wireshark display filter中的contains很慢,因此打算自行实现。全文搜索有inverted index和stringology算法两套思路,调研后决定使用stringology流派的FM index。FM-index以Burrows-Wheeler Transform为核心,集成了Wavelet Matrix、succinct bit sequence等,趁着这次要写全文搜索引擎的机会实现了各种succinct data structure:RRR、Elias-Fano encoding、Wavelet Matrix等。

fqj1994编写了预处理PCAP/PCAPNG,以stream为单元重组PCAP;我在对预处理后的文件建立索引FM-index;pandada8用riot.js写了前端。

计分方式和成绩

关于我们的名次。可能得再过一阵子才能知晓。如果现在要做个预测的话,我觉得第6、7名是我们较为可能的名次。最终名次是第5名,参见http://blog.legitbs.net/2015/08/2015-def-con-ctf-final-scores.html

15支队伍和主办方Legitimate Business Syndicate的虚拟队伍参与计分。x86-64和mipsel两个gamebox上最终开放的服务计有6个:rxc,irkd,tachikoma,ombdsu,hackermud,badlogger。每支队伍的每个服务初始被分配1337个flag。每一轮若service level agreement不通过则丢失14个flag,平均分配给其余14支参赛队伍;若token被其他队伍提交,则丢失14个flag,平均分给攻击者,余数给legitbs,legitbs趱到的flag会参与以后的分配。不清楚SLA不通过且被攻击会如何计分。最终得分是所有服务flag数和+4011。

ARM64题hearye.zip即为livectf_quals,只有第一天解出的队伍才有分,前三名分别得到600、300、200个flag,其他得到100个。第二天被允许参加livectf_finals的队伍中第一个解出的PPP得到1000个flag。这些flag参与到计分,一个即为一分。

我希望flag数用浮点数表示。

TeamScorerxcirkdtachikomaombdsuhackermudbadloggerlivectf_qualslivectf_finals
legitbs415242001001845519055
defkor239496746135926243731136835106000
ppp198963488117938592528136822632001000
0daysober179432095128416056216133812941000
hitcon13560230413293871313386041000
blue-lotus124428761299146520781323139000
0ops1130621701389110311383124900
dragonsector11288219013891220461132369400
samurai10742012541129802127821681000
shellphish1059112814193792057133811591000
lcbc994101359160039135312793000
spamandhex9461013442861578136887400
team-944784105514043871138310691000
gallopsled860801359527559135379900
corndump75081129900133885900
bushwhackers74470138900120384400

评论和爆料

今年不限制决赛参赛人数,得以成行。每年都希望多做一些,今年又朝这个目标多努力了一些。遗憾:尽管参加了三年DEFCON,但一直都没机会参加Capture the Flag以外的其他活动。

今年DEFCON CTF决赛的特点是可执行文件变得很大,梳理脉络变得尤为困难(这点向PPP讨教过,他们也这么认为),我们可以从中看到题目向实际应用靠拢的趋势。

三年参赛,我们也是一支经验较充足的队伍了,但也能看到名次进一步提升的天花板。对于很多成员不是安全专业从业者的我们来说,取得这个名次已属不易,算是发挥出了正常水平,在协作和准备上做出的准备也看到了成果。CTF竞赛和安全有很大关联,但水平到一定程度后还需要大量训练才能继续提高。对于大多数人而言,把精力投资在这方面价值远不如花在其他领域大。赛棍也许是存在的,但和算法竞赛相比仍差得很多。

提升竞争力的核心是逆向工程和漏洞利用能力。这方面我们与顶级强队仍有巨大差距,在其他方面如流量分析还有一定增长空间。Day 1四个小时后DEFKOR rxc first blood吊打全场,各队分数都差不多,随后HITCON成功重放,升到第二。善于防御的Shellphish很快修补服务。即使如此,各队分数差不了太多,攻击速度至关重要。小道消息:Day 1 geohot没来助力PPP,但晚上就到了,莫非是第一天状态太差就立马赶来救援?geohot震惊自己一晚上才解出来的题竟然被那个韩国人(lokihardt)用4个小时做出来了……最后PPP应该解出了所有的题目。但是主办方没通知irkd服务从监听0.0.0.0改为监听127.0.0.1,让ricky以为此题一直在维护状态而少拿了好多分。颁奖时韩国领队(?)说lokihardt “solved all the challenges”。关于我们,引用一句话:以其努力程度之低,还不到拼天赋的程度。