当前位置: 首页 > news >正文

攻防世界 wife_wife

在这个 JavaScript 示例中,有两个对象:baseUser 和 user。
baseUser 对象定义如下:

baseUser = {
    a: 1
}

这个对象有一个属性 a,其值为 1,没有显式指定原型对象,因此它将默认继承 Object.prototype。
user 对象定义如下

user = {
    a: 2,
    b: 1,
    __proto__: {
        c: 3
    }
}

这个对象有三个属性:
a: 值为 2,覆盖了从 baseUser 继承过来的同名属性(如果有继承关系的话)。
b: 值为 1,这是 user 自身特有的属性。
__proto__: 这是一个指向原型对象的引用,这里将其设置为一个包含 c: 3 属性的对象。这意味着 user 对象会从这个新的原型对象中查找自身没有的属性。
因此,当尝试访问 user.c 时,JavaScript 引擎会在 user 对象自身找不到 c 属性时,向上搜索其原型链,最终在 user.__proto__ 找到并返回值 3。
注意:直接修改 __proto__ 属性虽然可以动态改变对象的原型,但在严格模式下不推荐这样做,现代 JavaScript 开发中更倾向于使用 Object.create() 或 class 关键字来更安全地操作原型链。

let newUser = Object.assign({}, baseUser, user);

target:作为 Object.assign() 参数提供的空对象 {}。这将作为属性复制的目的地。
source1:baseUser 对象。
source2:user 对象。
这段代码执行的操作可概括如下:
创建一个新的空对象 ({})。
将 baseUser 中的所有可枚举自有属性复制到新对象中。
将 user 中的所有可枚举自有属性复制到新对象中。如果有任何重叠的键(如本例中的 a),来自 user 的值会覆盖 baseUser 中的值。
生成的 newUser 对象: 执行 Object.assign() 调用后,newUser 对象将具有以下属性:
a:取值为 user 中的 2,因为它覆盖了 baseUser 的 a。
b:取值为 user 中的 1,因为它是 user 特有的。
一个原型链,其中包含从 user.__proto__ 继承的 c: 3 属性。
总结来说,语句 let newUser = Object.assign({}, baseUser, user); 通过合并 baseUser 和 user 的属性创建了一个新对象 newUser,当键重叠时,优先采用 user 中的属性值。生成的 newUser 对象还继承自 user.__proto__。

// 浅复制一个对象,第一个参数位是对象的内容,后面的参数位是多个对象内容叠加进去,进行复制出一个全新的对象
let newUser = Object.assign({}, baseUser, user)  

// 输出结果为{a:2,b:1},无污染
console.log(newUser)  // {a: 2, b: 1}  
console.log(newUser.__proto__)  
//{constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, hasOwnProperty: ƒ, __lookupGetter__: ƒ, …}

污染时:

baseUser = {a:1
}user = JSON.parse('  {"a" : 2 , "b" : 3 , "__proto__" : { "c" : 4 }}  ')
let newUser = Object.assign({}, baseUser, user)console.log(newUser)//输出{a: 2, b: 1}console.log(newUser.__proto__) //被污染,输出{c: 4},而__proto__没有被输出的原因是它为隐藏属性
console.log(newUser):
此行将打印合并后的newUser对象。由于Object.assign({}, baseUser, user)将baseUser和user对象的属性合并到一个新对象中,其中user对象的属性值会覆盖相同名称的baseUser属性值。所以,newUser对象应具有以下属性:
a: 值为2,来自user对象(覆盖了baseUser的a: 1)
b: 值为3,直接来自user对象
结果输出为{ "a": 2, "b": 3 }
console.log(newUser.__proto__):
此行将打印newUser对象的原型(__proto__)。由于user对象的JSON字符串中包含了__proto__键,其值为一个包含c: 4的对象,这将在创建user对象时被解析并设置其原型。当newUser通过Object.assign()继承user的属性时,也会继承其原型链。因此,newUser.__proto__应该是一个包含c: 4的对象:{ "c": 4 }

我们以知识点的利用为主,查看源代码:

// post请求的路径
app.post('/register', (req, res) => {let user = JSON.parse(req.body)  // 将输入的账号密码从json字符串转成对象// 判断有没有输入账号和密码if (!user.username || !user.password) {  return res.json({ msg: 'empty username or password', err: true })}// 判断账号是否存在总对象的username里,若注册时输入的用户名相同,则输出用户名已存在if (users.filter(u => u.username == user.username).length) {  return res.json({ msg: 'username already exists', err: true })}//如果用户是管理员但邀请码不匹配,会将 user.isAdmin 设为 false,并返回一个错误的 JSON 响应。
//由于邀请码是常量 INVITE_CODE,其值在代码执行期间不会发生变化。这意味着无论用户提交的邀请码是什么,其与 INVITE_CODE 的比较结果将在代码执行前就已经确定。因此,无论用户如何构造输入,都不能通过修改邀请码来改变条件判断的结果,防止了SQL注入。if (user.isAdmin && user.inviteCode != INVITE_CODE) {user.isAdmin = falsereturn res.json({ msg: 'invalid invite code', err: true })}// 使用系统函数复制对象,打包成一个新的对象let newUser = Object.assign({}, baseUser, user)users.push(newUser)  // 存到总对象里res.json({ msg: 'user created successfully', err: false })  // 设置返回信息
})

若isAdmin的属性是true,则它为管理员,否则为普通用户;于是我们可构造污染。

注册页面抓包:

{"username":"1","password":"1","isAdmin":true,"inviteCode":"11"}

构造为

{"username":"2","password":"1",
"__proto__":{
"isAdmin":true
}
}
//由于之前注册过username为1,若重新注册会回显exist,因此这里将username修改为2

 污染成功:

重新登录得到flag:

总结

该题考察JavaScript 原型链污染Nodejs原型链污染

http://www.lryc.cn/news/332695.html

相关文章:

  • Visual Studio安装下载进度为零已解决
  • 矩阵空间秩1矩阵小世界图
  • 《QT实用小工具·十三》FlatUI辅助类之各种炫酷的控件集合
  • dm8 备份与恢复
  • Vue项目中引入html页面(vue.js中引入echarts数据大屏html [静态非数据传递!] )
  • ASTM C1186-22 纤维水泥平板
  • NoSQL概述
  • 爬虫实战一、Scrapy开发环境(Win10+Anaconda3)搭建
  • llama.cpp运行qwen0.5B
  • 【接口】HTTP(3) |GET和POST两种基本请求方法有什么区别
  • 金陵科技学院软件工程学院软件工程专业
  • Android 关于apk反编译d2j-dex2jar classes.dex失败的几种方法
  • Django--admin 后台管理站点
  • JavaScript(六)---【回调、异步、promise、Async】
  • vue2+elementUi的两个el-date-picker日期组件进行联动
  • GIN实例讲解
  • 开源充电桩设备监控系统技术解决方案
  • 环形链表--极致的简便
  • WPF中TextWrapping
  • Win10 下 git error unable to create file Invalid argument 踩坑实录
  • 简化备案域名查询的最新API接口
  • 基于SpringBoot和Vue的校园周边美食探索以及分享系统
  • TiDB单机版安装和连接访问
  • Spark-Scala语言实战(13)
  • Android compose 使用指纹验证
  • 开源模型应用落地-chatglm3-6b模型小试-入门篇(一)
  • C++实现单例模式
  • 虚幻UE5智慧城市全流程开发教学
  • docker的安装及入门指令
  • 聚能共创下一代智能终端操作系统 软通动力荣膺“OpenHarmony优秀贡献单位”