easy_file
一进去发现是个登录页面,看看源代码提示了个file查看头像,估计是文件上传,先sql注入简单测试一下,没什么反应,弱口令试试,源代码说会base64加密,所以到bp爆破模块选择base64加密

然后进去admin.php页面,然后尝试上传文件,发现过滤了很多后缀,只能是jpg的,htacess和.user.ini什么的都不行,同时内容也有过滤,php标签被过滤,于是尝试短标签和script
芝士:PHP 默认开启短标签支持,<?= 等价于 <?php echo,完全绕过 <?php 过滤
可以用file包含但是我直接执行system也行


就拿到了flag
nest_js
考点:Next.js 中间件鉴权绕过漏洞 (CVE-2025-29927)
链接:
https://www.ctfiot.com/233818.html
https://github.com/vulhub/vulhub/blob/master/next.js/CVE-2025-29927/README.zh-cn.md
根据提示访问/dashboard

发现一直重定向到登录页面,根据题目,可以推测与Next.js 中间件鉴权绕过漏洞 (CVE-2025-29927)有关,搜索一下,发现可以添加 x-middleware-subrequest然后嵌套5层 middleware
即x-middleware-subrequest: middleware:middleware:middleware:middleware:middleware
然后直接访问dashboard就行了

星愿信箱
进去就是一个留言框一样的东西,输入什么就给你输出什么,,随便测试几下,发现过滤了双大括号和cat,
然后绕过方法:
{{}}->{%%},,cat->tac
发现用这个绕过没有回显,抓包看看,发现有回显,于是尝试解
{%print(''.__class__.__base__.__subclasses__())%}

发现有很多的子类
要找含有popen的,脚本:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| import re import ast
def parse_and_find_index(index_list_str, target_string): # 方法1:使用正则表达式提取类名 def extract_class_names(list_str): # 匹配 <class 'xxx'> 中的 xxx pattern = r"<class '([^']+)'>" matches = re.findall(pattern, list_str) return matches
# 方法2:使用 ast.literal_eval 但需要预处理 def clean_and_parse(list_str): # 将 <class 'xxx'> 替换为 'xxx' cleaned = re.sub(r"<class '([^']+)'>", r"'\1'", list_str) try: return ast.literal_eval(cleaned) except: return None
# 尝试解析 class_names = extract_class_names(index_list_str)
if not class_names: # 如果正则没匹配到,尝试清理后解析 parsed_list = clean_and_parse(index_list_str) if parsed_list: class_names = parsed_list
# 查找目标字符串 for i, name in enumerate(class_names): if target_string in name: return i
return -1
index_list_str = ""
targets = ['os._wrap_close'] for target in targets: index = parse_and_find_index(index_list_str, target) print(f"查找 '{target}': 索引 {index}")
|
index_list_str填上bp上返回的所有子类就行了,然后超找到在第137个


cat被过滤了,所以就用tac

多重宇宙日记
芝士:原型链污染
- 通过__proto__来修改越
- 注入 isAdmin = true 等权限标志
- 修改 hasOwnProperty 导致 typeof obj === ‘object’ 被伪造
- 重写 toString 输出敏感数据
此题注册进去发现可以直接传输json数据,同时显示/api/profile路径,题目提示原型链污染,观察源代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
| /// 更新表单的JS提交 document.getElementById('profileUpdateForm').addEventListener('submit', async function(event) { event.preventDefault(); const statusEl = document.getElementById('updateStatus'); const currentSettingsEl = document.getElementById('currentSettings'); statusEl.textContent = '正在更新...';
const formData = new FormData(event.target); const settingsPayload = {}; // 构建 settings 对象,只包含有值的字段 if (formData.get('theme')) settingsPayload.theme = formData.get('theme'); if (formData.get('language')) settingsPayload.language = formData.get('language'); // ...可以添加其他字段
try { const response = await fetch('/api/profile/update', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ settings: settingsPayload }) // 包装在 "settings"键下 }); const result = await response.json(); if (response.ok) { statusEl.textContent = '成功: ' + result.message; currentSettingsEl.textContent = JSON.stringify(result.settings, null, 2); // 刷新页面以更新导航栏(如果isAdmin状态改变) setTimeout(() => window.location.reload(), 1000); } else { statusEl.textContent = '错误: ' + result.message; } } catch (error) { statusEl.textContent = '请求失败: ' + error.toString(); } });
// 发送原始JSON的函数 async function sendRawJson() { const rawJson = document.getElementById('rawJsonSettings').value; const statusEl = document.getElementById('rawJsonStatus'); const currentSettingsEl = document.getElementById('currentSettings'); statusEl.textContent = '正在发送...'; try { const parsedJson = JSON.parse(rawJson); // 确保是合法的JSON const response = await fetch('/api/profile/update', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(parsedJson) // 直接发送用户输入的JSON }); const result = await response.json(); if (response.ok) { statusEl.textContent = '成功: ' + result.message; currentSettingsEl.textContent = JSON.stringify(result.settings, null, 2); // 刷新页面以更新导航栏(如果isAdmin状态改变) setTimeout(() => window.location.reload(), 1000); } else { statusEl.textContent = '错误: ' + result.message; } } catch (error) { statusEl.textContent = '请求失败或JSON无效: ' + error.toString(); } }
|
body: JSON.stringify({ settings: settingsPayload }),所以必须放在setting下面
同时里面包含JSON.parse函数可以解析__proto__并污染,于是直接尝试:
1 2 3 4 5 6 7 8
| "settings": { "theme": "12", "language": "1", "__proto__": { "isAdmin": true } } }
|


相关原型链污染例题解析链接:https://www.cnblogs.com/ya7q/p/19146883#%E7%A4%BA%E4%BE%8B%E9%A2%98%E7%9B%AE
君の名は 和 easy_signin
没做出来,直接看官方wp吧
链接: https://blog.csdn.net/2301_80160378/article/details/149302149