VNCTF2022公开赛

GameV4.0

耐心
在这里插入图片描述

在这里插入图片描述

gocalc0

00x1非预期解

点击
在这里插入图片描述
在这里插入图片描述

把session拿去解码一下(末尾有==base64解码一下)
在这里插入图片描述
在这里插入图片描述
两次编码就出来了(本来我以为)
在这里插入图片描述

00x2预期解

此方法不大清楚
讲解处

package main

import (
	_ "embed"
	"fmt"
	"os"

	"github.com/gin-contrib/sessions"
	"github.com/gin-contrib/sessions/cookie"
	"github.com/gin-gonic/gin"
)

func main() {
	port := os.Getenv("PORT")
	if port == "" {
		port = "8088"
	}
	r := gin.Default()
	store := cookie.NewStore([]byte("woW_you-g0t_sourcE_co6e"))
	r.Use(sessions.Sessions("session", store))
	r.GET("/flag", func(c *gin.Context) {
		session := sessions.Default(c)
		c.String(200, session.Get("FLAG").(string))
	})
	r.Run(fmt.Sprintf(":%s", port))
}

newcalc0

原型链污染:

function Foo() {
    this.bar = 1
}

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

let foo = new Foo()
foo.show()

我们可以认为原型prototype是类Foo的一个属性,而所有用Foo类实例化的对象,都将拥有这个属性中的所有内容,包括变量和方法。比如上图中的foo对象,其天生就具有foo.show()方法。

我们可以通过Foo.prototype来访问Foo类的原型,但Foo实例化出来的对象,是不能通过prototype访问原型的。这时候,就该__proto__登场了。

一个Foo类实例化出来的foo对象,可以通过foo.__proto__属性来访问Foo类的原型,也就是说:

foo.__proto__ == Foo.prototype

总结:
1、prototype是一个类的属性,所有类对象在实例化的时候将会拥有prototype中的属性和方法
2、一个对象的__proto__属性,指向这个对象所在的类的prototype属性
并且:
所有类对象在实例化的时候将会拥有prototype中的属性和方法

而原型链污染就是通过对prototype的改变,控制并修改了一个对象的原型,那么将可以影响所有和这个对象来自同一个类、父祖类的对象。
详细讲解

源码:
const express = require("express");//require用于从外部获取一个模块的接口
const path = require("path");
const vm2 = require("vm2");

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

app.use(express.static("static"));

const vm = new vm2.NodeVM();//VM 模块是 NodeJS 里面的核心模块,支撑了 require 方法和 NodeJS 的运行机制

app.use("/eval", (req, res) => {
  const e = req.body.e;//req.body通常用来解析POST请求中的数据
  //这里的e获取输入框中的内容
  if (!e) {//如果不存在则向模板写入一个数据wrong
    res.send("wrong?");
    return;
  }
  try {
    res.send(vm.run("module.exports="+e)?.toString() ?? "no");
    //module.exports把一个对象封装到模块中,这样在其他的文件中就可以以调用模块的方式调用它
  } catch (e) {
    console.log(e)
    res.send("wrong?");//向模板发送数据
  }
});

//console.table([{a:1}],['__proto__'])

app.use("/flag", (req, res) => {
  if(Object.keys(Object.prototype).length > 0) {
    //Object.keys方法会返回一个由一个给定对象的自身可枚举属性组成的数组,数组中属性名的排列顺序和正常循环遍历该对象时返回的顺序一致 。
    //这边是要object类的属性个数要大于0
    Object.keys(Object.prototype).forEach(k => delete Object.prototype[k]);//k为键名,删除属性的值
    res.send(process.env.FLAG);// process.env属性返回包含用户环境的对象
  } else {
    res.send(Object.keys(Object.prototype));
  }
})

app.use("/source", (req, res) => {
  let p = req.query.path || "/src/index.js";
  p = path.join(path.resolve("."), path.resolve(p));
  console.log(p);
  res.sendFile(p);
});

app.use((err, req, res, next) => {
  console.log(err)
  res.redirect("index.html");
});

app.listen(process.env.PORT || 8888);

payload:

console.table([{a:1}],['__proto__'])
console.table(data, properties);

参数:该方法接受上述和以下所述的两个参数:
data:表格数据。每行数据的数组,其中包含该特定行的每一列的值。
properties:它指定用于构造表的属性。

此方法不会返回任何内容,但会打印构造的表并记录下来。如果无法将参数解析到表中,则仅记录参数。
使用 console.table 方法将它以一个漂亮的表格的形式打印出来。会根据数组中包含的对象的所有属性

console.table源码:

// tabularData 是第一个参数 [{a:1}]
// properties 是第二个参数 ["__proto__"]
const map = ObjectCreate(null);
//ObjectCreate创建新对象,第一个参数是要继承的原型,这里没有要继承的原型
let hasPrimitives = false;
const valuesKeyArray = [];
const indexKeyArray = ObjectKeys(tabularData);//表格数据,也就是[{a:1}]

for (; i < indexKeyArray.length; i++) {
  const item = tabularData[indexKeyArray[i]];
  const primitive = item === null ||
      (typeof item !== 'function' && typeof item !== 'object');
  if (properties === undefined && primitive) {//因为我们的properties键名设置了,所以properties !== undefined
    hasPrimitives = true;
    valuesKeyArray[i] = _inspect(item);
  } else {
    const keys = properties || ObjectKeys(item);
	
    //key 是 __proto__ 
    for (const key of keys) {
      if (map[key] === undefined)
        map[key] = [];
      
      // !ObjectPrototypeHasOwnProperty(item, key) 成立
      if ((primitive && properties) ||
           !ObjectPrototypeHasOwnProperty(item, key))

        // 因此 map[__proto__][0] 是空字串
        map[key][i] = '';
      else
        map[key][i] = _inspect(item[key]);
    }
  }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值