#2026 年 Defcon 34 参赛游记
qwq 先放结果

#Day-2
一开始以为比赛是晚上周五晚上九点开始,所以为了给队长省点机票钱,买了最便宜的周四晚上那一班飞机去北京。。飞机一路都有点颠簸,没睡着,想看个电视剧什么的发现没提前下,嗯睡睡到落地。
12 点刚过半个小时落地,很爽的是在大兴机场外面那个出租车平台有拒载的神人,理由是我去的地方太近了。。有点不爽 hia hia 直接举报了(
#Day -1
第二天早早到酒店,我和 stackc00kie 师傅一间,我一个人在房间玩到他来,和他聊天才发现“我靠原来比赛是早上五点开始”,原来是 UTC+0 啊,哈哈那无敌了(
然后等人来的差不多,队长和 tplus 拉着我们一起去酒店旁边找了个饭店吃饭,听说前几年也是在这边吃的,还不赖(
stackc00kie 师傅拍了点照片:


谔谔... stackc00kie 师傅晚上 11 点早早就睡了,而我的作息根本睡不着,依旧 1 点睡 4 点起.. 阎王夸我好身体
#Day 0
ok 早上五点也是早早起来把电脑搬到 tplus 房间准备开打了,,然后遇到了很经典的

很难绷...
第一天第一波放的 Pwn 题是一个 lua vm,输入 lua 字节码,然后解释运行。
一开始注意到🕳其实是在 ipairs 里存在对 shared_prt 生命周期的错误管理,可以实现 UAF 一个 0x20 的 chunk,而且后续研究通过堆喷也可以实现踩到这个 chunk
中间还闹了个乌龙,题目的 docker 的 glibc 版本是 2.39,chroot 的是 2.43,一开始堆喷拿 2.39 打的,后面发现其实得按 2.43 打。。。但这都不是大问题
问题是没有 leak... 在这个地方一直卡着,事已至此 先想想吃什么,tplus 师傅点了 kfc,吃东西的时候挂着 agent 再让 ai 看看有没有办法 leak,0 进展。。
这个时候上了一道 kernel pwn,出于好奇打开附件看了眼:

我靠怎么是 Ubuntu 2404,那岂不是可以打这个 https://kqx.io/post/qemu-nday/,进 docker 确认了下 qemu 版本,果然是 v8.2,看了眼 run.sh,是 TCG。。那感觉可以打啊。。

思索...然后

是的我已经一分钟没有跟人提起过 Defcon 34 内核题 1 血了,虽然这没什么好炫耀的,但是正如我所说这没什么好炫耀的 OvO
其实想不通这题为什么没人打,因为其实一开始在看这题的师傅在看预期解,后面想了想可能这个点外国人还在歇(
然后三点钟上了另一道 gitvfs,也是同样的环境,如法炮制两道一血到手了(
不过没敢交 gitvfs 的 flag2,因为怕交太快又上新题,我们前面的题还没怎么做(tplus 的策略),感觉是对的
然后上了 shelldiet 这道 KoH,具体就是实现一个读 flag 的 shellcode,要求 shellcode 的所有字节和相加尽可能小。没开任何沙箱限制。
先插一个回旋镖 
先当 speedrun 打,第一反应:
- 肯定直接拿 shell 优于 orw
- double read 应该是最好的方向
然后一开始写了个 260 字节的先交上去,顺带提一嘴,这场比赛的 PoW 计算量都好大,每次都能给我电脑 cpu 卡住...可能该换电脑了,后续这题都是用 tplus 借我的服务器打的
double read 的思路一开始就是最常规的 pop rdx; xchg eax, esi; syscall,然后通过 add byte ptr [rax], al 这种低 cost 汇编实现自修改。这种一直卷到 24.. 歇了一会让 ai 继续研究,去看上午没看完的 stork,这个时候这个题已经有很多解了。感觉就是 ai 做的,另外 cscat 师傅实现了一个 gc 的 poc。。
daimi 把 poc 给 ai,leak 尝试爆破,然后就出了(
给 ai 大人👻了
#livectf
这个时候 pwn 基本上做的差不多了,开始帮 tplus 看 livectf,此时 livectf 刚进行到 phase2
livectf 很有意思,题目有点像坦克大战,每个队伍可以维护一个 bot,bot 根据队伍自定义的策略在地图上战斗,击杀越多得分越多。题目下发了一个 vm 程序,bot 需要实现为一个 bin,vm 负责解析 bot,每个 tick 可以执行一个 syscall,每个 syscall 之间允许执行 10000 条指令
场上一共 1000 个 bot,70 个队伍,剩下全是 npc
一个大轮 4 h,一个小轮 3 min,一共 6 个大轮
具体信息(例如武器池、武器信息、行动冷什么的)得靠每轮逆向那个 vm 程序。然后得实现一个编译 bot 的编译器(
我上手的时候 phase1 已经 gg 了,40 多名,一开始理想的策略是先本地 agent 养蛐蛐,然后拿出最优化的交到平台上,解析一下这类 bot 发现 ai 喜欢行动之前先用 scan map 的 syscall 拿敌人站位,但是这个动作是需要花费 tick 的,也就是开局大概率站着不动,死亡率很高,所以分数很低。。
最粗暴的策略反而是最有效的,开局先随机动两步,然后朝着一个方向旋转射击杀 bot(主要是杀 npc)就能拿到不错的分数,至少在 phase2 是这样(第三名)。
后面阶段三就不太行了,我们这种策略很大的问题是开局随机动两步很多时候没什么用,有很大概率和 npc 在一条线上然后被它秒了,,,或者是活了很久但是因为移动很低效,在中后期的地图上找不到人杀,导致活了很久得分还没一些没活多久的队伍分数高。
这个时候 Misty 师傅来了,一个很对的洞见是“开局随机移动是无意义的,倒不如选一个方向开一枪,开枪之后一定不会被那个方向的 npc 打了”,
基于这个思想,把 bot 策略改成
- 开局随机开一枪
- 随机移动,一边移动一边朝一个方向开枪
- 如果长期杀不到人(中后期)就提高移动效率找人杀。
然后我就想把这个策略实现了交到 Nu1L 上,but 这个时候 tplus 不让我上,我说我本地 benchmark 分数还可以,他让我自己开个小号交,他要感觉多改多错(
很难绷啊 我小号分数很快比大号高了(


那这个时候 tplus 肯定想让我赶紧把 bot 交到大号上,为了防止被 ban 我特意重新编译了一份,然后最搞笑的来了,同样的逻辑交到 xingmengctf 上每轮都能吃一两百份,交到 Nu1L 上每轮不超过 100 份((
tplus:许哥你是演员吧 😡
花:我靠不到啊((
花:我靠小号分数又涨了
反正很难绷得住,tplus 要去睡觉了,于是第三轮后面的 livectf 就暂时交给了 Misty、Mr.R。
我们反思了一下第三轮 bot 逻辑的缺陷,由于获取地图信息的代价太大,bot 的移动都是完全随机/一条路走到黑的,很容易卡在地图的某个角落然后一直卡到该轮结束
Misty 说既然地图是已知的,其实可以先把地图压缩一下存下来,然后用类似于 A* 的算法给 bot 设计一个比较好的寻路算法,但这个肯定在 10000 条指令里是不那么好做的,于是 Misty 大哥开始实现了一个基于 C 的编译器(之前是 python 的
这个时候距离开赛已经 24h 了,我实在扛不住,挂了一些 agent 就去睡觉了((
哦对,睡之前发现又上了两道内核的 revenge,感觉天塌了(
#day1
睡醒起来,misty 师傅还在奋战,,寻路算法效果不是特别好,有个恶性 bug 是 bot 在寻路算法之后会待在原地不动(不执行),然后一边修一边照着 replay 抄了第一名队伍的策略:
- 开局站着不动,朝四个方向一边转向一边射击(此时单向枪无 cd)
- 杀到 500 tick 左右开始用 dash syscall 游走,如果撞墙则反射到另一个方向
感觉还不赖(
这个策略在 phase 4 寻路算法恶性 bug 的时候救老命了hh
中间有个插曲,我们在交 bot 之前会先在小号上测试一下,结果经常出现同样的 bot 在小号上效果很好,换到大号就 gg...
花:是不是 Nu1L 这个号风水不好...
tplus:号风水的来了...
然后到了 phase 5,题目模式改成了占点模式,之前写的寻路算法发挥了很大作用,由于之前写的早,这一轮成功干到了第一名。misty tql
livectf 没什么好看的了,然后去看那两个内核的 revenge,第一个 revenge 之后预期解直接被 ai 秒了,第二个有两个 flag,flag1 被 ai 秒了,flag2 被大哥们用这个没在 7.0.9 上修复且出题人忘了 patch 的 🕳 又非了....
去帮 misc 看了一下一个 ocr 题目,里面全是这种逆天 hex

我作为 agent 的 harness 把这些全肉眼 ocr 了一遍,大概是个 tcp 数据包,里面有个 gzip。。由于我计网一点没听,所以 ocr 体力活干完就跑路了(
还是回来继续卷 shellcode koh,想了想发现其实没必要死磕 pop rdx; xchg esi, eax; syscall,这个的优化看起来已经到瓶颈了,于是我尝试了另外两条路:
jmp <main_addr>ret xxx调栈从而控制返回地址
第一个大概优化到 30 左右就没做了,感觉 jmp 还是太复杂了,自修改很麻烦,考虑第二个,看了看栈发现 ret 0x20 可以让程序再次 ret2main,效果还不错,可以做到 20
后面又优化了一下,可以做到 11。但是在排行榜上这个策略只能排到 16。。
调了一下 docker,发现远程栈里 ret 0xd8 也是一样的效果(那里是 _start),成功做到 10。这个时候大概猜到前两名的队伍是非预期了,赛后果然非预期就是那个打那个 pipe 设备,通过 race 先把程序原本写到 buffer 里的 shellcode_sum 读出来,再写个自己的进去,可以做到 0...
哎,✅8️⃣我当时看了眼这玩意不是只读挂载吗。。。怎么可以写啊!!

(上面这个图是赛后截的,没想到 blue water 居然在不非预期的情况下进一步压缩到了 8。。。)
当时就感觉再卷下去没有性价比了(因为要归一化),就去帮忙看 nodefs 这道题
这个题得靠 race 做 leak,然后网速超级慢,最后师傅租了个美国原生服务器解决了。。
到这大概是 5.30 晚上 10 点左右,我们把 pwn 都 ak 了。
后面就是看着 tplus 开 20+ 个 agent 围殴谜语 Misc 题,哈哈。其实今天早上还以为题要做不完了,感觉要进不了 defcon final 非常焦虑。。最后结果是好的,还不赖。
#Day2
pwn ak 之后我和 stackc00kie 就打算洗洗睡了
本来说比赛结束前 两个小时再看看有没有要帮忙的,然后根本起不来,我和 stackc00kie 一觉睡到 8 点,,,他 9 点的高铁,说起来,stackc00kie 师傅两天可能睡了不超过 2h,这个更是超人
#一些思考
这场 defcon 的 ctf 题目其实前几名的队伍都 ak 了,主要差距就在 koh 和 livectf 上。shellcode 这道 koh 其实就是因为我们人手不太够,导致这种纯 trick 的 speedrun 交的很晚,不过好在第一名非预期给大家都卷4️⃣了,归一化之后分差并不大
再就是感觉内核 1day 的积累很重要,虽然一开始放的两道内核题我很快就反应出可以打去年的 qemu nday,但是后续 revenge 之后就没什么好办法了,但是大哥们依然可以靠手里存的很多 cve 把这个打完。。
还有就是 agent 工作流的问题吧,感觉我现在的工作流还是不是很高效,应该好好思考一下怎么优化。
不过确实是很开心的一次比赛,这半年来体验最好的一场 ctf,play for fun and win~