虽然截至早上(10-10)那会,笔者的心情仍然不算好,但是在下午重新尝试了(问了agent)玛德莱娜小蛋糕这道题之后,发现纯粹是自己绕waf试得不全,从而导致自己不能够破开门,心情变好了!(虽然后头的还是不会写😭
– 本blog已于10-22复盘后更新,pay attention!
Web
T1-好想玩原神
本题毕竟是第一题,看样子应该是web的签到题目,最后考察了一个不太常规的sql注入。
PART1 - 信息搜集
我们首先拿到这个页面,查看源代码,发现一个注释里有很多能用的用户信息:
1 | <!-- |
首先尝试随便一个人的信息,登进去看看回显:

可以看到该用户的信息,但是目前还看不出来有什么用。
但我们注意到源码中给出了前端的app.js,点进去看看:
1 | const loginView = document.querySelector("#login-view"); |
这里的有效信息看来只有用JSON传username和password这一条,暂时不能判断本题指纹喵。继续搜集信息吧!
打开dirsearch,开始搜索喵:

发现robots.txt可以看看提示(那本题用dirsearch看来成滚木了)
对于robots.txt,有:
1 | User-agent: * Disallow: /api/login |
也就是说,对于非刚刚的注释中的账号来说,会出现非常神奇的效果,反正肯定不会是被403再301到什么原什么神的官网的。
但是这里说render渲染这个词,很容易引起猫猫们的浮想联翩喵,会想到SSTI和sql灌注喵。❤️
尝试{{7*7}}这样的效果没有结果喵,被正常301去玩原神了喵,所以尝试sql喵❤️❤️
1 | 13874261905 |
尝试了这样,从抓的包里头看到,会被400 BAD REQUEST掉,还会报OperationalError喵,这个报错查一下就会发现是sqlite的常见报错喵(应该是这会喵,笔者刚刚复现的时候忘记截图了现在确证不了,请猫猫们谅解喵)❤️❤️❤️
PART2 - 打点
于是尝试先确证一下,顺便看看都能不能回显喵,这里笔者尝试了

也就是111' UNION SELECT 1,sqlite_version(),3,4'喵。成功确认了sqlite的事实,level up了!
那么接下来就要开始进行老几项了喵:
- 确定order数:password位:
111' UNION SELECT 1,2,3,4',需要注意这里两个参数都需要带上引号; - 表名(sqlite不能爆database()):
111' UNION SELECT name,2,3,4 FROM sqlite_master',得到的表里有一个叫secret_flags的,大概就是它了; - 列名:
111' UNION SELECT sql,2,3,4 FROM sqlite_master',或者' UNION SELECT 1, name, 3, 4 FROM pragma_table_info('secret_flags')。此时注意到**(对于前一种)**:CREATE TABLE secret_flags(id, flag_value, note),因此flag应该就在flag_value这个列里喵。 - flag:
111' UNION SELECT flag_value,2,3,4 FROM secret_flags'即可。



得到flagTSCTF-J{Y@u_c4N_9l4|_G3n5he^!}了!
这里是当时笔者的混乱思考链喵,追求真实心态请看这里喵
起初没有仔细去想,看到{item.traveler} {item.phone}这种,误以为是ssti模板注入。尝试在用户名和密码处输入``看看信息,发现无果,还被重定向到了原神的官网。用实践证明了ssti的错误
然后笔者在这里被卡了许久,然后想到应该找找提示,发现了本题存在的robots.txt爬虫文件:
1 | User-agent: * Disallow: /api/login |
不过这个/api/login显然是不能用来get的,试了一下确实也不支持这个方法,有些不明觉厉。但是我们确证了,非上面注释里名单的人登录,确实会被重定向到genshin的启动器。这时笔者猜想是sql注入,于是尝试如下:
1 | 13874261905' or 1 = 1 # |
发现仍然重定向。感觉崩溃,于是前往dsh理思路:
[!NOTE] 你问为什么要用间隔几秒钟发一个请求?当时没看懂要求,以为不能用agent爆破…
而在后续,我们继续验证这个sql,输入:13874261905' or 1 = 1; --+,发现得到403blocked by login firewall的回显,在这种的情况下,我只好让agent先一把梭一次,再给我复盘思路和知识点。(不过没让它输出flag……我真的按这个重新搞了一遍😭
首先是WAF的绕过:

题目非常神秘地拦截了有or的payload中有空格的写法,而且联合查询中前后的两个参数都做了引号的闭合,因此会有a' UNION SELECT '1的写法,但是这道题更难过的地方,在于注入点不同于常规的任意位置,而是限定在了password的地方。看上去以后得先好好定位再说了:

之后就到了我们熟悉的步骤:
- 确定order数:password位:
111' UNION SELECT 1,2,3,4',需要注意这里两个参数都需要带上引号; - 表名(sqlite不能爆database()):
111' UNION SELECT name,2,3,4 FROM sqlite_master',得到的表里有一个叫secret_flags的,大概就是它了; - 列名:
111' UNION SELECT sql,2,3,4 FROM sqlite_master',这里并没有用常规的' UNION SELECT name,NULL FROM pragma_table_info('users')-- -写法来查询列名,自己试了一下,pragma似乎也会被waf,这么看只有看所有的列名了。此时注意到:CREATE TABLE secret_flags(id, flag_value, note),因此flag应该就在flag_value这个列里。 - flag:
111' UNION SELECT flag_value,2,3,4 FROM secret_flags'即可。
总结:
- 本题利用一个不常见的sqlite数据库,补充了笔者先前只会mysql的可怜境地。且对于这种waf的拦截,可以学习ai的“最小化探针”逐步进行测试。
- 从[miso师傅的blog](TSCTF-J 2026 Web 五题 WriteUp - Miso的博客 | Miso Blog)上,可以看到另外一种sql的写法喵,+当空格是需要读者猫猫们注意的喵。
– 对于sqlmap,笔者尝试使用却一直返回假阴性,询问ai之后得知是默认测试样例的锅,第一默认的加空格的载荷会被waf拦截;第二,对于' AND '1'='1和' AND '1'='2都会返回403禁止访问,对于它的布尔判断器会失效。能看出来出题人想让大家学会sql的基本原理喵。
T2-玛德莱娜小蛋糕
PART1 - 信息收集:
本题的入口就如同标题一样善,是一个典型的文件上传入口。但是直接开始猛猛灌注很可能被拒绝喵,好猫咪不能够上来就干这种事,要尝试拉好感度牵牵手约约会再解锁特殊cg喵❤️
使用dirsearch喵:

那个storage忽略掉喵,因为笔者忘了截开始的图了,这个是后来做完才截图的喵,总之这里是没什么特别好的路由作为提示喵。
PART2 - 打点
那就直接打点喵。要朝着最弱的地方攻击喵!既然只准上传gif,我们当然希望灌注进去的一切都会被认成php喵:给cmd的木马加一个GIF98a的头,并且把CT改成image/gif,后缀也改成gif——但是看上去这是有代价的喵:
图片马被传成了storage/tmp/da85388effaa.gif,文件名被随机更改(讲道理,这个默认解析的gif怎么分辨率这么大,都快赶上我这块滚木2.5k屏了喵),自然也就按.gif解析了。尝试上传.user.ini和.htaccess,结果发现也被随机更名,走不通了喵(泣
代价就在这里了,于是在后缀不更改的情况下,笔者尝试上传了木马喵,发现:
这个后缀会弄脏茶桌。
看上去php等后缀会被黑名单拦截掉。但是经过尝试,.phtml不会被黑名单拦下,从而成功上传一句话木马。

PART3 - 立足点建立喵
上传的一句话木马默认是防止/tmp这个路由下的,很可能会被坏人清除掉喵!所以我们按说要先cp到一个隐蔽点的目录并改名喵!(比如/var/www/html/assets/fonts/.cache.php,探姬是好人喵!)但是笔者猫猫很懒,经过试验没什么问题后,直接手工cp到上一层/storage目录就完事了喵!
这样我们就建立了一个稳定的立足点。不过也可能会忽视掉上传的马被定时杀掉的情况喵,了解详情可以看下面收起来的思考链喵。
连接后尝试了env,当然是没有用的喵!😭还是先看看根目录下在干什么吧!

可以看到flag是仅root有权看的,所以需要我们进行提权喵。
PART4 - 提权,权限维持,加上乱打喵(虽然本题不用维持喵)
首先用find / -xdev -writable -type f 2>/dev/null查看当前用户/用户组可写的文件喵,因为读的反正除了直接的flag,暂时也没有什么好说的喵!

可以看到这有一个三分钟什么的,又结合temp里的文件被定时清理的现象,考虑计划任务在清理喵!于是看看cron:

事实上就是查看了两个系统级的cron,也就是:
1 | cat /etc/crontab |
所以我们直接cat /opt/teahouse/bin/clean_uploads.sh喵。

这里头的东西不就是刚刚查到的三分钟文件吗喵!而且用户可读可写喵!有救了喵!
所以对它进行一些改造,让cron的大手替我们来读flag就好了喵!

看上去挺有精神的,之前就是你杀了我的木马吗?欸嘿嘿嘿嘿嘿……
开心地等待3min即可:
1 | TSCTF-J{Cr07-In-534Rbh-0f-10sT_6@k3_@7D_fl3g40f2f86} |
这里又是当时笔者的混乱思考链喵,追求真实心态请看这里喵
我们使用蚁剑进行连接,尝试env(当然是没有flag的),考虑到去年的tsctf,我们先想到利用sudo -l查看能够用sudo运行的命令,结果发现这个后端把sudo都给阉割了。且过了一阵,蚁剑对命令无响应,检查发现是存在tmp下的木马给自动清除了。正当笔者难过于怎么给用户权限—的flag下手时,agent告诉了我们如下信息:

我的马被杀了()
于是我们再次上传木马,手工cp到/storage下,得到了一个稳定的木马连接,但是没有sudo,笔者还是不会提权。
而在上面这个回答的下面,dsh提出要“寻找定时任务”,颇为不解,于是:




也就是说,对于这种情况,我们可以先通过如下命令扫用户的文件权限:
find / -xdev -writable -type f 2>/dev/null或
find / -xdev -type f -perm -o+w 2>/dev/null | wc -l
而对于后面一种,作用只是查询当前用户的权限,但是用户www-data是在同名的用户组里的,这样查询并不妥帖,应该用前一条命令测实际的读写情况。
得到:
var/lib/teahouse/cleanup.conf可以写入,且这个会被计划任务(删除tmp目录的那个)执行。

找到计划任务后,我们直接修改它执行的外部文件cleanup.conf,给它加上一行cp /flag /var/www/html/storage/out.txt; chmod 644 /var/www/html/storage/out.txt,等待计划任务执行即可。
– 总结:
- 文件上传不要为单个后缀名的限制而气馁,可以尝试多个后缀名(如本题.phtml),对于黑名单模式很有用;
- 对于文件的“提权”,核心并不是一个死板的sudo -l,而是先找到当前文件系统最鲜明的特点(如本题的corn计划任务),以及当前用户/组可写的文件,而这个文件又能够由更高权限的用户(如root)执行。提权并非使用户chmod,而是利用root执行的最高权限夹带私货,从而绕过限制。
T3-BandInvite
本题最后只通过抓包看到的@vite等请求定位到了CVE-2026-39363这个任意文件读取的漏洞,但是笔者实在不知道那个websocket是怎么用的,先鸽掉😭
- 本题很快就会进行更新,会在周末merak跑路关站之前写好的!不然……不然笔者猫就要找出题人要容器喵!
T4-MinePortrait
PART1 - 信息搜集
本题进去之后是一个登录框。源码并没有什么有效信息,所以我们首先想到看看robots.txt,找找提示(事实上也可以dirsearch搜一下,也只有这个robots.txt有些用了喵):
1 | User-agent: * |
下载这个www.zip,可以得到login_source.py和old_note.txt两个文件,在前一个文件中包含进入题目的用户名和密码,old_note中则有如下内容:
1 | # old_note.txt |
结合网页给的图片上传转换这一操作,以及可选的svg矢量图格式,还有前端的这段js(虽然结合js某种意义上算马后炮…):
1 | if (source === "svg" && target === "png") { |
可以发现,这段正则表达式需要满足形如下面的xml格式(其实就是注意\s这个空白字符类喵):
1 | <! DOCTYPE svg [ |
又注意到提示:祝尼魔们会拦下不少本机地址,却会收下用filter包好的信。
本来猫猫们希望用127.0.0.1,也就是常见的本机地址,加上filter(这个其实不用提示,因为包含了之后会提示有sensitive keywords,第一反应就是用base64的filter过滤器包裹起来喵)来进行一个读flag喵。结果被鹈鹕镇的坏人们拦下来了喵😡😭猫猫很生气,决定要用更多的本机地址来打喵!
于是换了个0就过了,看来鹈鹕镇的大家都很喜欢0(×
最后在windows的点击以执行的帮助下,成功拿到flag,就是成功率很难评,最好还是手打喵。

解码后得到flag:
1 | TSCTF-J{Cr07-In-534Rbh-0f-10sT_6@k3_@7D_fl3g40f2f86} |
这里叕是当时笔者的混乱思考链喵,追求真实心态请看这里喵
我们可以猜想是以svg为载体的XXE漏洞,首先尝试在ENTITY字段包含外部实体flag.txt(可惜的是,笔者当时并不会正则表达式,并没有看懂这个发送到服务端的规则…)
1 |
|
提示:The Junimos found sensitive keywords within y our XML. Go refine it!,显然是撞上WAF了。由于笔者是个彩笔,首先去问了ds的网页版,给了一个hint(后来发现没有用),让我把编码换成utf-16尝试绕过——
然而只有一个Portrait conversion completed.的响应,flag并没有出现。但是发现如果直接上传一个正常的svg,题目仍然是可以解析它的,但是bp拦截后发现是在本地浏览器上解析,随后会立刻被返回的Portrait conversion completed.页面盖掉,这个方向显然是不太能够走通了。
[!NOTE] UTF-16
不过对于大多数情况下,更改编码方式可以有效绕过字面量正则搞的简单WAF,至于这题无效的原因:
感谢dsh老师
1 |
|
在思考无果后,我们转向更加聪明的dsh,得到如下回答:

这里的WAF应该还是经典但是clo不会的黑名单写法,只对于<!doctype和<!entity命中waf。对于后头的SSRF,事实上就是和前面的提权一个道理,即借更高权限的“手”来进行操作,其实核心就是用ENTITY的外部实体部分,让服务端能够进行读取flag的操作。只不过祝泥魔拦下了诸多包括127.0.0.1 localhost之类的地址,只剩下0这种可以进行访问了而已。
[!NOTE] 来自dsh老师的教诲
知识点 · 为什么本机地址黑名单必然失败
黑名单是字符串匹配,而"同一个主机"有无数种等价写法:十进制/十六进制/八进制 IP、
短写(127.1)、IPv6 映射([::ffff:127.0.0.1])、0.0.0.0、DNS 重绑定、@混淆……
更根本的是,只解析 host 也不够——还要考虑重定向、DNS 解析结果。
正确做法:白名单(只允许明确的域名/协议)+ 解析后校验目标 IP 是否落在内网段。
这样一来,我们就把抓flag这个操作,转化为了具象的服务端的LFI,从而拿到flag,具体payload如下:
1 |
|
– 总结:
- 对于常见waf的绕过,很值得试的一点就是加上/去掉空格,这看上去至少是这位出题人最喜欢用的办法。
- 后来感觉严格意义上这不算waf……因为正则都写在前端暴露的源码里了。真正算waf的,大概在于ban掉的一堆本地域名,要不是这题的话我真只知道127和localhost。
- 对于本地域名和开心地和WAF斗智斗勇的有趣探讨,可以参见[miso](TSCTF-J 2026 Web 五题 WriteUp - Miso的博客 | Miso Blog)和[maple](【补充】TSCTF-J 2026 Writeup - Map1e-Suk1的秘密基地)两只猫猫的wp!
AI
T1-Liar’s Bar
我不到哇,试了试默认给的那个规则就过去了,这才是签到题啊(大雾)
Abstract
T1-Dried Milkdragon
找了一下,地方应该是在雁北地超里头,旁边挂了个本子的地方?
但是找了半天不知道flag在哪,怕被当成小偷就跑出来了()
T2-emoji
明月松间照清泉石上流
但是太阳和上有什么关系,因为在上面吗()
正如审题的师傅和之后翻到我的小站的网友所见,在此刻,在26年刚入学的这个时候,对于这种较高难度的题目,clo仍然是一位需要用agent进行大量操作,且解释诸多知识的彩笔,对于waf的绕过也是一言难尽。但是正在雁西园3号楼的的我仍然希望着我能加入 merak ,仍然希望着自己能在计算机,网络安全和 CTF 领域大展身手,至少这是我的美好憧憬,于是clo怀着这样的心情,从而在再过10-11的中午写下这段总结 。
把这篇wp传上来时,笔者仍然不知道自己能否如愿以偿进入merak,但是笔者认为不管怎么样,自己总是得过日子的,总不能一旦失利就学FX飞人吧。因此将它上传上来,供自己日后好生回顾,并且鞭策自己在大学的日常与网安知识的学习。
本文件同时作为提交的 Writeup 和个人笔记。有未尽之处实属抱歉,因为我能在排行榜中取得名次多亏了 dsh的禁忌力量。
看上去最近得去学正则和js了,不然前端看着真的难受(泣
以及感谢来自poe大人的致谢参考尾段,和来自神秘小游戏《放松时光:与你共享Lo-Fi故事》的satone酱的亲切陪伴。(为什么聪音都会看日志但是我不会😭

– 10-22更新:写更新的时候,笔者恰好闲来无事更新了声卡驱动,然后喜提超绝电流白噪音,以为自己被来自DDLC的monika制裁了,在此敬告大家不要干这种事😭





评论