2026长城杯半决赛easy_time意外发现的另一种潜在解法 | WriteUp
本篇将介绍除网上zip slip漏洞外的另一种解法,针对所给附件docker-compose.yml环境与当时比赛现场环境不一致的情况 环境搭建 附件给了docker-compose.yml,直接docker-compose up -d即可,mac上要把5000改成其他,否则会和airdrop冲突 但要注意,本题直接用附件所给的docker-compose启动会和比赛时的环境不一致,也是为什么会有第二种解法的原因,具体将在攻击部分讲解 攻击 通过浏览整个项目的文件结构可以发现,有两个web部分,一个是php,一个是flask,而根据docker-compose.yml可知对外提供能访问到的是flask,所以先看flask的逻辑 先看路由,发现大部分路由都需要经过login_required 跟进这个装饰器,发现它通过另一个is_logged_in()判断是否已登录 这个is_logged_in()只会检查cookie里的visited是否为yes,以及user是否有值,所以不需要什么绕过,只要有值就行 另外,还有一个硬编码过的2层md5密码,其实明文是secret,用hashcat可以很容易跑出来 hashcat -m 2600 -a 0 hash rockyou.txt 登录逻辑大概就是这样,不过比赛时我居然在类似下面这样的好多地方纠结了好久为什么没有SSTI ?太久没碰CTF导致的…… 顺便补一下上面这样的构造并不会造成SSTI,下面这样才会,原理:https://xz.aliyun.com/news/3311 既然不存在直接的利用点,那就只能回到逻辑分析,粗略浏览路由后会发现主要路由只有/plugin/upload和/about,/board尽管有写库的功能,但是sqlite,所以先不管 先看/about,主要逻辑就是下面这段 先对上传后缀做过滤,再从数据库里拿出信息给flask渲染,其中avatar_url还会经过一个fetch_remote_avatar_info的函数,跟进 就是很简单的curl,本身没有利用点。但问题就在于它另一个php服务存在于一个环境里,由此可以引出SSRF,并且php自带了一个phpinfo.php,所以来到about页面将头像地址改成php服务地址试试 成功访问,但没有发现什么特别的东西,而且目前还没发现进一步利用到RCE的点,所以继续看另一个路由 可以看到仅支持上传.zip文件,并将上传上来的zip文件名做secure_filename防止路径穿越(注意这里只过滤上传的zip文件本身,不会检查zip文件里的文件)后,最终交给safe_upload函数,跟进一下 遍历zip文件中的文件,将文件名与dest_dir合并后赋值到target,如果是文件夹则确保或创建该文件夹存在,否则将文件写到完整的target路径里。 其实这是个很类似解压到操作,但又不是标准的解压方法,真正使用zipfile解压zip的方法应该是下面这样 with zipfile.Zipfile("example.zip","r") as zips: zipf.extractall("/tmp") 但这道题里的这种"解压"实质上是一种文件迁移,将zip的内容读出来再写入,而不是真正地去解压它 操作的空间就在这里,os.path.join对路径的处理并不会做像secure_filename那样过滤路径回退的操作,甚至会优先解析绝对路径(如下target3),如下 由此可知,可以通过让被压缩的文件名带有/或../这样的格式,达到任意目录写文件的目的。并且由于flask没开热更新,所以肯定不是覆写.py来拿webshell,只能写php webshell 所以只要构造一个文件名为’/var/www/html/shell.php’的文件就能成功写入,但linux和macos都不支持直接创建带/文件名的文件,所以我们只能用zipfile这个库直接创建一个带有这样文件的压缩包 import zipfile with zipfile.ZipFile("eval.zip","w") as f: f.writestr("/var/www/html/shell.php","<?php system('ls');?>") 赛事环境与附件所给不一致导致的利用失败 此时如果直接上传这个文件,理论上应该是可以正常解压最后利用ssrf getshell才对,但情况并不是这样。而是出现了解压失败的报错 参考网上许多赛后复盘wp后发现,当时比赛的环境确实只要上传上面生成的压缩包即可 https://rycarl.cn/index.php/2026/03/23/2026%E9%95%BF%E5%9F%8E%E6%9D%AFawdp%E5%8D%8A%E5%86%B3%E8%B5%9Bwp%E8%A5%BF%E5%8D%97%E5%9C%B0%E5%8C%BAweb/#FIX-2 https://blog.luc1f3r.top/zh-cn/posts/writeup/ciscn--ccb-%E5%8D%8A%E5%86%B3%E8%B5%9B---2026-writeup/#break-1 说明两者环境应该有区别,经过一番排查后后发现了原因 ...