前言

从大一开始我每年都打 NCTF,除了恰烂钱,感觉每次都可以学到点不一样的东西。今年的 web 题有点不一样,感觉挺有意思的,加深了我对 JavaScript 相关的一些安全问题的理解。

profile

JS-world

problem1-1.png

这道题涉及到的是 ejs 模板的注入问题,同时传入的后端的信息会先经过前端过滤一次。可以通过 DevTool 的断点调试功能,找到相关的过滤关键字的代码如下,删除后即可绕过。

_0x23132f = _0x23132f[_0x1bef85("0x5")](
  /[\/\*\'\"\`\<\\\>\-\(\)\[\]\=\%\.]/g,
  ""
);

这里的输入存在模板注入问题,通过 payload > <%= global.process.mainModule.constructor._load("fs"). readdirSync("/") %> <> <%= global.process.mainModule.constructor._load("fs"). readFileSync("/flag.txt") %> < 即可读取目录并获得 flag

problem1-1.png

PackageManager_v1.0

这道题可以获取到源码,通过审计代码发现了一个问题,这里的鉴权使用的是 JWT token,签名时使用的是 RS256,但是验证时使用的是 RS256 和 HS256,同时将公钥加到了 payload 中。RS256 是非对称加密算法,HS256 是对称加密算法。因此我们可以解析 token 后获取到公钥,并使用公钥和 HS256 生成自己的 token,绕过鉴权。

problem2-1

代码中存在着对象 clone 的代码,有原型链污染的漏洞

problem2-2

problem2-3

这里当第 9 行的 key 为__proto__时就会造成原型链污染,修改变量a的原型(即 Object.prototype)上的属性。

同时,这里使用的模板引擎是 nunjucks,其源代码中存在着一些new Function和字符串拼接,有被注入的可能性。

构造 payload 如下,即可成功获取 flag

{
  "author": "111",
  "__proto__": {
    "description": "global.process.mainModule.require('fs').readFileSync('/w0w_Congrats_Th1s_1s_y0ur_flaaag')"
  }
}

problem2-5

-------------------------时间分割线---------------------------

2020 年 11 月 25 日

payload

后面排查发现这个是nunjucks的一个漏洞,目前已经发起 Pull Request 修复了nunjucks/pull/1330/。感谢出题人@baiyecha404的题发现了这个漏洞。

经过排查,问题出在nunjucks/src/runtime.js文件中Frame.prototype.variables变量中,错误地使用普通的 object 作为 Map 使用,导致读取变量时可能会从 Object.prototype 中读取变量。当 npm 包外发生 Object.prototype 被污染时,会导致读取 variables 上的属性时得到意料之外的值,同时模板引擎存在着大量字符串拼接,这导致 payload 被执行。

使用Object.create(null)替代{}作为 Map 会更为安全,同时也可以对原型使用Object.freeze避免原型被意外修改。