1、NodeJS-开发环境&功能实现
2、NodeJS-安全漏洞&案例分析
3、NodeJS-开发指南&特有漏洞
➢环境搭建-NodeJS-解析安装&库安装
➢功能实现-NodeJS-数据库&文件&执行
➢安全问题-NodeJS-注入&RCE&原型链
➢案例分析-NodeJS-CTF题目&源码审计
➢开发指南-NodeJS-安全SecGuide项目
https://www.w3cschool.cn/nodejs/
https://nodejs.org/en
安装命令:
npm i express
npm i body-parser
npm i cookie-parser
npm i multer
npm i mysql
创建sql.js文件并粘贴实例代码
**npm config set registry [https://registry.npmmirror.com](https://link.zhihu.com/?target=https%3A//registry.npmmirror.com)
查看是否更换
npm config get registry**
// express_demo.js 文件
// 引入 Express 框架
var express = require('express');
// 创建 Express 应用程序实例
var app = express();
// 处理根路径的 GET 请求,返回 'Hello World'
app.get('/', function (req, res) {
res.send('Hello World');
});
// 启动服务器,监听端口 3000
var server = app.listen(3000, function () {
// 获取服务器地址和端口
var host = server.address().address;
var port = server.address().port;
// 输出服务器访问地址信息到控制台
console.log("应用实例,访问地址为 http://%s:%s", host, port);
});
// 引入 Express 框架
const express = require('express');
// 创建 Express 应用程序实例
const app = express();
// 处理 '/login' 路径的 GET 请求,返回简单的登录页面
app.get('/login', function(req, res) {
res.send('
登录页面');
});
// 处理根路径的 GET 请求,发送名为 'sql.html' 的文件
app.get('/', function(req, res) {
res.sendFile(__dirname + '/' + 'sql.html');
});
// 启动服务器,监听端口 3001
const server = app.listen(3001, function() {
console.log('Web 服务器已经启动,监听端口 3001!');
});
1、实现用户登录
req.query
用于处理 URL 查询字符串参数**GET请求
**,而 req.body
用于处理 **POST 请求
**中的表单数据。
**const bodyParser = require('body-parser');
相关库 npm i body-parser**URL编码
**的bodyParser **中间件实例**
// 引入 Express 框架
const express = require('express');
const bodyParser = require('body-parser');
// 创建 Express 应用程序实例
const app = express();
创建一个用于解析 URL 编码的 bodyParser 中间件实例
**const urlencodedParser = bodyParser.urlencoded({ extended: false });**
**// 处理 '/login' 路径的 GET 请求,返回简单的登录页面
app.get('/login', function(req, res) {**
// 从请求中获取用户名和密码
**const u = req.query.username;
const p = req.query.password;**
console.log(u);
console.log(p);
// 检查用户名和密码是否为 admin 和 123456
if (u === 'admin' && p === '123456') {
res.send('欢迎进入后台管理页面');
} else {
res.send('登录用户或密码错误');
}
});
**// 处理 '/login' 路径的 POST 请求,使用 bodyParser 解析表单数据
app.post('/login', urlencodedParser, function(req, res) {
// 从请求中获取表单提交的用户名和密码
const u = req.body.username;
const p = req.body.password;**
console.log(u);
console.log(p);
// 检查用户名和密码是否为 admin 和 123456
if (u === 'admin' && p === '123456') {
res.send('欢迎进入后台管理页面');
} else {
res.send('登录用户或密码错误');
}
});
// 处理根路径的 GET 请求,发送名为 'sql.html' 的文件
app.get('/', function(req, res) {
res.sendFile(__dirname + '/' + 'sql.html');
});
// 启动服务器,监听端口 3001
const server = app.listen(3001, function() {
console.log('Web 服务器已经启动,监听端口 3001!');
});
const mysql = require('mysql');
var connection = mysql.createConnection({
host : 'localhost',
user : 'root',
password : 'root',
database : 'dome01'
});
// 建立与 MySQL 数据库的连接
connection.connect();
// 定义从 'admin' 表中选择所有列的 SQL 查询
const sql ='select * from admin';
// 执行 SQL 查询
connection.query(sql, function(error, data){
// 检查查询执行中是否存在错误
if(error){
console.log('数据库连接失败!');
}
// 记录从查询中检索到的全部数据
console.log(data);
// 记录结果集中第一行的用户名
console.log(data[0]['username']);
// 记录结果集中第一行的密码
console.log(data[0]['password']);
});
// 处理 '/login' 路径的 POST 请求,使用 bodyParser 解析表单数据
app.post('/login', urlencodedParser, function(req, res) {
// 从请求中获取表单提交的用户名和密码
const u = req.body.username;
const p = req.body.password;
// 输出获取到的用户名和密码,用于调试
console.log(u);
console.log(p);
// 创建与 MySQL 数据库的连接
var connection = mysql.createConnection({
host : 'localhost',
user : 'root',
password : 'root',
database : 'dome01'
});
**// 建立数据库连接
connection.connect();
// 构建 SQL 查询,检查数据库中是否存在匹配的用户名和密码
const sql = 'select * from admin where username="'+u+'" and password="'+p+'"';
console.log(sql);
// 执行 SQL 查询
connection.query(sql, function(error, data){
// 检查查询执行中是否存在错误
if(error){
console.log('数据库连接失败!');
}
try {
// 检查用户名和密码是否匹配数据库中的数据
if(u == data[0]['username'] && p == data[0]['password']){
// 如果匹配,发送欢迎消息到前端
res.send('欢迎进入后台管理页面');
}
} catch {
// 捕获异常,如果没有匹配的数据或其他错误,发送错误消息到前端
res.send('错误');
};**
});
})
const fs = require('fs');
// 引入文件系统和 Express 框架
const fs = require('fs');
const express = require('express');
const app = express();
// 处理 '/file' 路径的 GET 请求
app.get('/file', function (req, res) {
// 从请求中获取目录参数
const dir = req.query.dir;
console.log(dir);
**// 调用文件管理函数,传递目录参数
filemanage(dir);**
});
// 启动 Express 应用监听在3000端口
var server = app.listen(3000, function () {
console.log('Web应用已启动在3000端口!');
});
// 文件管理函数,接收一个目录参数
function filemanage(dir) {
**// 使用 fs.readdir 读取目录下的文件
fs.readdir(dir, function (error, files) {
// 打印目录中的文件列表
console.log(files);**
});
}
1、Express开发
2、实现目录读取
3、加入传参接受
const rce=require('child_process');
// 引入child_process模块
const rce = require('child_process');
// 使用exec方法调用系统命令'notepad',打开记事本
rce.exec('notepad');
// 使用spawnSync方法调用系统命令'calc',打开计算器
rce.spawnSync('calc');
// 使用eval调用代码命令执行,将字符串当做代码解析
// 请注意:避免在生产环境中使用eval,可能存在安全风险
eval('require("child_process").exec("calc");');
1、SQL注入&文件操作
2、RCE执行&原型链污染
2、NodeJS黑盒无代码分析
- 黑盒测试(Black Box Testing):
- 黑盒测试是基于功能需求和规格说明的外部测试方法。
- 测试人员在执行黑盒测试时,对系统内部的实现细节一无所知,只关注系统的输入和输出,以及系统的功能行为。
- 测试人员将系统视为一个黑盒子,只关注输入数据、预期输出和系统行为,而不考虑内部的代码逻辑和结构。
- 黑盒测试主要关注系统的功能、界面、性能、安全性等方面,以验证系统是否符合规格说明和用户需求。
- 测试方法包括等价类划分、边界值分析、场景测试、错误推测等。
- 白盒测试(White Box Testing):
- 白盒测试是基于系统的内部实现、代码结构和逻辑的测试方法。
- 测试人员在执行白盒测试时,了解系统的内部结构和代码,可以直接检查、分析和测试系统的内部组成部分。
- 白盒测试主要关注系统的代码覆盖率、逻辑路径、错误处理、性能优化等方面,以验证代码的正确性和质量。
- 测试方法包括语句覆盖、分支覆盖、路径覆盖、条件覆盖、代码审查等。
- Payload 是指在攻击中传递的恶意代码、数据或命令。在进行 Payload 测试时,安全专家会设计和使用各种 Payload 来验证目标系统的安全性,并确定系统是否容易受到攻击或是否存在潜在的漏洞。
判断:参考前期的信息收集
黑盒:通过对各种功能和参数进行payload测试
白盒:通过对代码中写法安全进行审计分析
- 信息收集(Reconnaissance):
- 收集应用程序的基本信息,如版本号、依赖项版本等。
- 查看应用程序的公开文档,了解其工作原理和功能。
- 分析配置文件,查看是否有敏感信息泄漏的风险。
- 黑盒测试(Black Box Testing):
- 通过输入字段,**尝试注入攻击,例如 SQL 注入、XSS(跨站脚本攻击)**等。
- 测试文件上传功能,确保上传的文件受到适当的限制和验证。
- 构造恶意请求,测试是否存在拒绝服务(DoS)漏洞。
- 尝试绕过身份验证和授权,确保访问控制的有效性。
- 白盒测试(White Box Testing):
- 对代码进行审计,查找潜在的安全问题。
- 检查是否存在明文密码、硬编码的敏感信息等。
- 确保应用程序对用户输入进行适当的验证和转义,以防止注入攻击。
- 避免使用不安全的函数和方法,如
eval
、exec
等。- 确保文件上传和下载等操作受到适当的安全限制。
- 检查是否启用了适当的安全头,如 CSP(内容安全策略)、X-Frame-Options、X-Content-Type-Options 等。
- 依赖项安全:
- 定期审查依赖项的更新和安全漏洞。
- 使用安全审计工具,如 npm audit,来检查依赖项的安全性。
- 使用仅允许信任的依赖项,并确保避免使用已弃用或存在漏洞的依赖项。
如果攻击者控制并修改了一个对象的原型,(proto)
那么将可以影响所有和这个对象来自同一个类、父祖类的对象。
// foo是一个简单的JavaScript对象
let foo = {bar: 1} //1=1 0 __proto__= x
// 原型链污染
// foo.bar 此时为1
console.log(foo.bar)//输出为1
// 修改foo的原型(即Object)
foo.__proto__.bar = '2'
// // 由于查找顺序的原因,foo.bar仍然是1
console.log(foo.bar)//输出为1
// // 此时再用Object创建一个空的zoo对象
let zoo = {}
// 查看zoo.bar,此时bar为2
console.log(zoo.bar)//输出为2
利用原型链污染,调用系统计算器
// 创建一个包含属性 bar 的对象 foo,并将 bar 设置为 1
let foo = {bar: 1};
// 输出 foo 对象的 bar 属性,预期输出为 1
console.log(foo.bar); // 输出: 1
**// 修改 foo 对象的原型链上的 bar 属性,将其设置为执行命令 'require(\'child_process\').execSync(\'calc\');'
//调用计算机
foo.__proto__.bar = 'require(\'child_process\').execSync(\'calc\');';**
// 输出 foo 对象的 bar 属性,预期输出仍为 1,因为直接属性优先于原型链上的属性
console.log(foo.bar); // 输出: 1
// 创建一个空对象 zoo
let zoo = {};
**// 使用 eval 执行 zoo 对象的 bar 属性,由于 zoo 对象没有 bar 属性,会导致 ReferenceError
//调用计算机
console.log(eval(zoo.bar));**
https://ctf.show/ Web334-344
https://f1veseven.github.io/2022/04/03/ctf-nodejs-zhi-yi-xie-xiao-zhi-shi/
https://blog.csdn.net/weixin_42353842/article/details/127960229
https://github.com/Tencent/secguide