
Hackergame 2024 游记
老年选手复健
一年一次的 Hackergame 来啦~
连续玩了13个小时的 Hackergame 2024 , 真好玩~
虽然结束的时候还是被刷下去了,但是很久没有打 CTF 打得这么开心了,谢谢举办比赛的人们!
打不开的盒
openscad

flag{Dr4W_Us!nG_fR3E_C4D!!w0W}
看到有人真的去下单 3D 打印了一个🌚
每日论文太多了!
Libreoffice Draw 搜索 flag

flag{h4PpY_hAck1ng_3veRyd4y}
比大小王
flag{I-@m-tH3-h4ckEr-K!n9-Of-coMparInG-NumBER$-20z4}
PowerfulShell
即使贝壳早已破碎,也请你成为 PowerfulShell 之王。
题目逻辑:
先看看能用的环境
_
是input
~
是players
于是构建
就拿到shell了
flag{N0w_I_Adm1t_ur_tru1y_5He11_m4ster_dd3329d66e}
Node.js is Web Scale
源代码:
{"key":"__proto__","value": {"a": 114514}}
OK
呃呃呃,还有什么好说的,污染就完事了
PaoluGPT
一开始还以为是LLM题,结果...
由于 GPU 机房火灾,目前聊天功能暂不可用,预计下周恢复。
🌚
给了附件,关键函数:
sqlite 的简单 sql 注入
/view?conversation_id=e63f1024-1097-4e34-b943-457c92dc881'(urlencode "'union select 1,group_concat(sql) FROM sqlite_schema limit '1")
CREATE TABLE messages (id text primary key, title text, contents text, shown boolean)
就这一个表
'union select 1,group_concat(contents) FROM messages where shown = false limit '1
flag{enJ0y_y0uR_Sq1_&_1_would_xiaZHOU_hUI_guo_9ca5895338}
但是这个只是 "窥视未知" 的 flag, 还有一个 "千里挑一"
所以直接全搜一下
无法获得的秘密
小 A 有一台被重重限制的计算机,不仅没有联网,而且你只能通过 VNC 使用键鼠输入,看视频输出。上面有个秘密文件位于 /secret,你能帮他把文件丝毫不差地带出来吗?
让选手从一个只有键盘鼠标输入,显示器输出的vnc偷一个512k的文件
太好玩辣!
想起最近小音的一个用二维码传文件的项目 qrs
打包编译这个项目,然后写个脚本用 base64 把 .tar.zstd 传进去
firefox 会卡死,chrome 五分钟左右可以传好

然后对着手机拍照就好了 :3

flag{SeCret_cAN_B3_Le4K3d_FrOm_R3s7RIc7Ed_Env_fad79794c5}
Docker for Everyone Plus
提供的环境会自动登录低权限的 user 用户。登录后可以通过特定的 sudo docker 命令使用 Docker,通过 sudo -l 可以查看允许提权执行的命令。读取 /flag(注意其为软链接)获取 flag。
记得以前做过旧版
OpenRC 0.54 is starting up Linux 6.6.56-0-virt (x86_64)
OpenRC 草。谁出的呀。
我们先看第一题
No Enough Privilege
没有网络但是可以 rz ,我们在本地 docker save alpine
传到远程的 /tmp
brw-rw---- 1 root disk 253, 16 Nov 7 17:09 /dev/vdb
注意到了吗? sudo 只是不让我们用 root 和 0 ,没说不让用 disk 呀。
所以可以
sudo docker run --rm -u 1000:1000 --user 1000:disk -it -v /dev/vdb:/flag --privileged alpine
flag{dONT_1OAD_uNTRusT3D_1ma6e_ace6f481a2_plz!}
感觉不像是预期解,估计是想要我们做一个自己的 suid 上去的。
来看第二小题:
Unbreakable!
先看看 sudo -l
一样的幽默黑名单,写两次 security-opt
就可以 root
当然我们先构造一个带自己的 suid 和 passwd 的 dockerfile :
docker build
好传上去,然后跑它:
sudo docker run --rm --security-opt=no-new-privileges -u 1000:1000 -it --security-opt=no-new-privileges=false -v /dev:/devv hack
su 后虽然还是不能直接操作 device ,但是我们可以 chmod 777 后回到主机,就可以 cat /dev/vdb 了。
flag{contA1N3R_R0ot_i5_4cCESsIb1e_ec962b15bf}
动画分享
为了给同学分享动画片,小 T 启动了自己之前用超安全的 Rust 语言写的 Web server,允许你访问「当前目录」的文件,当然了,flag 可不在当前目录。不过因为快到饭点了,小 T 还没来得及复制视频文件到对应的目录,于是就只在自己最常使用的、几年前编译的某祖传终端模拟器里面跑起了自己的 fileserver,然后就去锁屏吃饭了。
小 T:「诶,我不过就分享个文件,而且目录里面也没别的东西,所以没关系吧~而且我特地搞了个 chroot,就算我真写出了什么漏洞,你也休想看到我的 flag!」
请提交一个程序,题目环境会在模拟小 T 的环境运行之后,降权运行你的程序:
如果你能让小 T 的 fileserver 无法正常响应请求(例如让 fileserver 退出),你可以获得第一小题的 flag。
第二小题的 flag 在 /flag2,你需要想办法得到这个文件的内容。
环境限制总 PID 数为 64。
本题的小题名称很有趣,第一题叫 "只要不停下 HTTP 服务,响应就会不断延伸", 第二题叫 "希望的终端模拟器,连接着我们的羁绊"
前者有点误导性,其实并不是让这个单线程的web程序一直出响应,导致 DoS 攻击,而是应该把它 crash 掉。后者算是一种提示,因为确实是终端模拟器的漏洞。
本地跑了一下,可能是本地和远程的环境不同,本地 curl --path-as-is 127.0.0.1//flag2
是可以任意文件读取的,因为代码中只去掉了第一个 /
.
后来发现是远程chroot了,实际上任意文件读取还是存在的。
远程使用的终端模拟器是 zutty ,查到 CVE-2022-41138
参考了这些文章来构建 exploit
- (CVE-2022-41138) - <x11-terms/zutty-0.13: arbitrary code execution via DECRQSS (like CVE-2008-2383)
- "[31m"?! ANSI Terminal security in 2023 and finding 10 CVEs
把 fileserver kill 掉之后 可以成功触发 zutty 权限下的命令执行,可惜没能 crash 掉 fileserver.
在经过多次尝试之后,经过一段 python 爆破, fileserver 被一个 byte 给 crash 了😇笑死

现在问题来了:尽管我们可以命令执行,但是在chroot里,怎么办呢?
exit也不管用,因为后续命令都会被忽略。只能想办法逃逸了。
看了眼chroot环境里甚至没有shell,只能用 python 写了:
写好了才想起来,不对呀,fileserver crash 之后就是在chroot外面了...
所以直接打就好啦:
因为 / 不可写,就把 flag 复制到 /tmp 去了。
flag{wa1t_no0O0oooO_mY_b1azIngfA5t_raust_f11r5erVer_0213c96566} flag{xterm_&_DECRQSS_in_2008_0NcE_morE_b6d3273318}
禁止内卷
提示:助教部署的时候偷懒了,直接用了 flask run(当然了,助教也读过 Flask 的文档,所以 DEBUG 是关了的)。而且有的时候助教想改改代码,又懒得手动重启,所以还开了 --reload。启动的完整命令为 flask run --reload --host 0。网站代码运行在 /tmp/web。
路径穿越任意文件写入,给flask加个路由就可以直接rce了。
flag{uno!!!!_esrever_now_U_run_MY_c0de51edd381aa}
链上转账助手
检查程序自动化调用 batchTransfer()
的交易失败,就给flag
看起来是在模拟某个曾经发生过的,大家的钱都被锁住出不来的事故。
转账失败
程序:
很简单,revert()就好了。
flag{Tr4nsf3r_T0_c0nTracT_MaY_R3v3rt_1c625de399}
转账又失败
没有限制 gas, 所以把gas消耗干净就行了
flag{Ple4se_L1m1t_y0uR_GAS_HaHa_1f58a5f99e}
转账再失败 (未解出)
diff 了一下发现和2的区别就是多了个 gas limit:
试了半天,不会了,本来以为是重入攻击,但是后来想想好像也不是,withdrawPending是有锁的,batchTransfer就算能重入也不会让交易挂掉。
看了官方题解,是return bomb, 原来还有这样的攻击方法!
不太分布式的软总线
当然了,上面的论述是在瞎扯淡,不过说到 DBus,小 T 最近写了一个小程序挂在了 DBus 系统总线上。你能拿到小 T 珍藏的 3 个 flag 吗?
考如何使用 dbus
Comm Say Maybe
这个其实是flag3,但是因为给了一部分代码,所以就先做了。
需要修改这么几处,1是程序名称必须是getflag3,二是返回结果写的是null,我们要把它改成(s).
dbus的部分是直接问的GPT :3
What DBus Gonna Do?
这是第一个 flag, 只需要给dbus传一个string即可。
GPT可解。
If I Could Be A File Descriptor
这是 flag2, 需要传一个文件描述符,并且里面需要是特定的内容
准备一个 fd, 然后用 g_dbus_connection_call_with_unix_fd_list_sync
传过去
神秘代码 2 (未解出)
Misc 😅
什么东西啊(掀桌子),不做了
旅行照片 4.0
一年一度的社工题~
1-2 题
问题 1: 照片拍摄的位置距离中科大的哪个校门更近?(格式:X校区Y门,均为一个汉字)
问题 2: 话说 Leo 酱上次出现在桁架上是……科大今年的 ACG 音乐会?活动日期我没记错的话是?(格式:YYYYMMDD)
20240519
【中国科大2024ACG音乐会单品】【鹿 乐队/口琴】花に亡霊·晴る_哔哩哔哩_bilibili
https://www.bilibili.com/video/BV1Ki421Q762/
2024中国科大ACG音乐会~ヨルシカ串烧 动画电影《想哭的我戴上猫的面具》主题曲:花に亡霊(花上亡灵) 番剧《葬送的芙莉莲》op2:晴る(放晴) 2024年5月19日晚19:00 东区大礼堂 主办:校学生社团管理指导委员会 承办:校学生动漫
flag{5UB5CR1B3_T0_L30_CH4N_0N_B1L1B1L1_PLZ_ab538794bd}
LEO 酱还挺可爱的耶
3-4 题
问题 3: 这个公园的名称是什么?(不需要填写公园所在市区等信息)
问题 4: 这个景观所在的景点的名字是?(三个汉字)
百度识图可知,是三峡大坝的坛子岭
猫咪问答
多年回答猫咪问答的猫咪大多目光锐利,极度自信,且智力逐年增加,最后完全变成猫咪问答高手。回答猫咪问答会优化身体结构,突破各种猫咪极限。猫咪一旦开始回答猫咪问答,就说明这只猫咪的智慧品行样貌通通都是上等,这辈子注定在猫咪界大有作为。
😺
- 在 Hackergame 2015 比赛开始前一天晚上开展的赛前讲座是在哪个教室举行的?(30 分)
https://lug.ustc.edu.cn/wiki/lug/events/
是3A204
- 众所周知,Hackergame 共约 25 道题目。近五年(不含今年)举办的 Hackergame 中,题目数量最接近这个数字的那一届比赛里有多少人注册参加?(30 分)
数了数是2019年的,所以是2682
- Hackergame 2018 让哪个热门检索词成为了科大图书馆当月热搜第一?(20 分)
- 在今年的 USENIX Security 学术会议上中国科学技术大学发表了一篇关于电子邮件伪造攻击的论文,在论文中作者提出了 6 种攻击方法,并在多少个电子邮件服务提供商及客户端的组合上进行了实验?(10 分)
https://www.usenix.org/system/files/usenixsecurity24-ma-jinrui.pdf
找不出来,我还不会爆破吗?
是336.
- 10 月 18 日 Greg Kroah-Hartman 向 Linux 邮件列表提交的一个 patch 把大量开发者从 MAINTAINERS 文件中移除。这个 patch 被合并进 Linux mainline 的 commit id 是多少?(5 分)
https://github.com/torvalds/linux/commit/6e90b675cf942e50c70e8394dfb5862975c3b3b2
- 大语言模型会把输入分解为一个一个的 token 后继续计算,请问这个网页的 HTML 源代码会被 Meta 的 Llama 3 70B 模型的 tokenizer 分解为多少个 token?(5 分)
算不出来,https://token-counter.app/meta/llama-3 的结果告诉我不对()
但是我可以burp启动
是1833
第一个flag是 flag{A_g0Od_c47_i5_THe_©47_ωh0_©an_PA$s_Th3_qu12}
,要满分才有第二个flag{TeN_¥E4Я5_oF_HαCKeЯgαME_oM3detØบ_wITH_И3KØ_Qบ1Z}
ZFS 文件恢复 (未解出)
你拿到了一份 ZFS 的磁盘镜像,里面据说有某沉迷 ZFS 的出题人刚刚删除的 flag。
「ZFS,我懂的。」这样说着,你尝试挂载了这个镜像(请注意,以下命令仅供参考,且系统需要安装 ZFS 内核模块):
binwalk 找到这个:
自己创建了一个hg2025镜像,观察文件格式:
是gzip可以搜索到(但是题目里面的解不出来,rollback后出现更多gzip数据,但是还是解不出来。)01 ?? 1F 00 01 00 FF ED 9C
是zfs压缩后的文件数据块的magic, 从这里开始 115 的 offset 是 gzip 的数据。
一大堆 FF 之前存在 metadata 块,包含数字格式的 mtime 和 atime.
比如我做了一个 flag1.txt, stat -c %X.%Y flag1.txt
为 1731050111.1731050156
于是我们找到了符合上面的文件 magic 的数据块的 atime ,是 1729690642
, 对应的文件是 flag1.txt
, 并且通过全局搜索 ?? 00 00 08 84 00 00 ?? ?? ?? ??
,搜到另一个 atime 是 1141919810
(Thu 9 March 2006 15:56:50 UTC)
似乎前面的 ?? 为 00 时为文件数据块,01 为目录结构和文件名数据块.

查阅 openZFS 的源代码可知,这个 uint8 的 atime 在如下数据结构中; 但是似乎 mtime 根本没有记载,那怎么办?
另一个问题是我始终找不到 flag2.sh 的 metadata , 只有未压缩处理的其内容(为什么未压缩?)
最后实在没办法了,我甚至写了一个这样的脚本来挖掘镜像里所有的 gzip 数据, which 可以把我自己制作的 zfs 镜像中删除和没有删除的所有内容挖出来; 可惜对于题目,还是一无所获。
看不见的彼方:交换空间 (未解出)
两年过去了,今年,Alice 和 Bob 再次来到了 Hackergame 的赛场上。这一次,他们需要在各自的 chroot(2) 的限制下,将自己手头 tmpfs 里面(比较大的)文件交给对方。
好消息是,这次没有额外的 seccomp(2) 限制,但是,他们所处的容器环境的 rootfs 是只读的,并且内存也是有限的,所以如果再复制一份的话,整个容器就会被杀死。Alice 和 Bob 希望请你帮助他们解决这个难题。
对于本题的第一小题,两个文件(/home/pwn/A/space/file 和 /home/pwn/B/space/file)大小均为 128 MiB。你需要在你的程序运行完成后使两者的内容互换。
对于本题的第二小题,Alice 有一个 128 MiB 的文件(/home/pwn/A/space/file),Bob 有两个 64 MiB 的文件(/home/pwn/B/space/file1 和 /home/pwn/B/space/file2)。你需要在你的程序运行完成后实现(原始文件 -> 交换后的文件):
/home/pwn/A/space/file -> /home/pwn/B/space/file
/home/pwn/B/space/file1 -> /home/pwn/A/space/file1
/home/pwn/B/space/file2 -> /home/pwn/A/space/file2
容器内存限制 316 MiB,你提交的程序文件会复制为两份,分别占用一份内存空间。环境限制总 PID 数为 32。对于 chroot 内部的进程,只有 /space 可读写。/space(/home/pwn/A/space/ 和 /home/pwn/B/space/)为 tmpfs,使用内存空间。
看了上一次 看不见的彼方 的思路,然后实现了一个使用 SIGUSR2
握手并用 SIGRTMIN
按字节交换数据的程序:
跑起来之后发现虽然可以成功交换小文件,但是大文件的处理速度实在太慢,就没成功
后来才想起来,哎呀!这不是可以用 socket
吗....
重新用 boost
写了一个 socket
传输的版本,快是很快了,但是编译出来有 14M...
于是重新开新坑,用原版 socket
写,写到一半不想写了去玩游戏了。其实可能也可以用 python (我甚至没去看环境里有没有),想起来的时候已经不想玩了~
This work is licensed under
Creative Commons Attribution-NonCommercial 4.0 International
![]()
![]()
![]()
2025-04-24 11:25
回复
无法获得的秘密 那题,没看懂是怎么传qrs代码到远程机器里的。
2025-04-24 11:33
回复
JavaScript 模拟按键,一个一个字符把 base64 打进去的
2025-04-24 11:38
回复
window.UI = UI // 在connect打断点 UI是啥? 怎么打的断点?
2025-04-24 11:50
回复
UI 是那个 web vnc 的全局对象,断点是在 devtools (F12) 的代码选项卡里面打的,是为了把这个对象绑定到全局方便后续操作
2025-04-24 19:47
回复
懂了,不过pyautogui也可以。
想请问的是,怎么把qrs项目打包本地运行呀??
2025-04-25 16:58
回复
懂了,如何打包项目 GitHub Copilot 告诉我了。另外,你这个评论貌似不支持 emoji 呢
2025-04-25 17:10
回复
😇🙏😢
2025-04-25 17:10
回复
哦!修好了~谢谢提醒
2025-04-25 17:18
👍