攻防世界——wife_wife

拿到靶机先看是什么服务器和框架

发现是experss框架

那么用的环境就是node,js环境了

Express 是构建在 Node.js 之上的 Web 应用框架,两者是"框架与运行时环境"的关系。简单来说:Node.js 是地基,Express 是在这地基上建造的房屋框架。

用dirsearch扫描目录

发现也就只有一个登录和注册

并且这两个在一开始的页面都给了

尝试注册一个管理员账号

但我们发现如果要注册一个管理员账号要输入一个特定的code

随便输入一个就会失败

回头看看源代码

什么也没发现

随便注册一个账号进去看看

发现出现了flag

但是是错误的

抓取注册时的包看看

发现这里控制上传的环境就是js.node(JSON)

并且以数组的方式传入了4个参数{"username":"admin","password":"admin","isAdmin":true,"inviteCode":"123"}

随便注册一个账号然后抓取登录时的包

没有什么新东西

那如果我们不勾上is admin直接注册呢

发现显示已存在

但我们发现这里也显示是is admin 不过这次是false,

但同时也发现这里没有code认证

也许可以直接修改is admin 的值为ture能实现越权访问呢

修改is admin 的值为ture

发现和先前的一样

没提示了,那就得进行fuzz测试了

(在比赛的时候这里有个himt提示)

这里我测出这里可以进行原型链污染

当我们污染 proto.isAdmin 为 true 时便可获取管理员权限

注册一个新的账号

注入

{"proto":{"isAdmin":true}

便可越权登录

页面果然不一样了

CatCTF{test_flag_h0w_c@n_I_l1ve_w1th0ut_nilou}

最后扒出源代码分析一下

javascript 复制代码
// 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里,如果相同的username就是重复用户名了
    if (users.filter(u => u.username == user.username).length) {  
        return res.json({ msg: 'username already exists', err: true })
    }
    // isAdmin是否true 与 邀请码是不是等于这个常量,所以sql注入没用,邀请码是个常量
    if (user.isAdmin && user.inviteCode != INVITE_CODE) {
        user.isAdmin = false
        return 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 })  // 设置返回信息
})

这里用了一个Object.assign 函数

这个函数可以把传入的两个参数合并成一个新的函数,并且会修改原来的参数

举个例子

javascript 复制代码
const target = { a: 1, b: 2 };
const source = { b: 3, c: 4 };

const result = Object.assign(target, source);

console.log(result); 
// 输出: { a: 1, b: 3, c: 4 }
console.log(target === result); 
// 输出: true (修改了原始target对象)

工作机制:

• 将 source 的所有可枚举属性复制到 target

• b 属性被覆盖(从 2 变为 3)

• c 属性被新增 • 返回修改后的 target 对象本身(不是新对象)

javascript 复制代码
const target = { a: 1, b: 2 };
// 攻击者构造的恶意 source
const maliciousSource = JSON.parse('{"__proto__": {"isAdmin": true}}');

console.log("攻击前:", {}.isAdmin); // undefined - 没有被污染

// 执行合并 - 原型污染发生!
const result = Object.assign(target, maliciousSource);

console.log("合并后target:", result); 
// 输出: { a: 1, b: 2 } (注意:没有 isAdmin,也没有 __proto__ 属性)
console.log("污染检查1:", {}.isAdmin);   // true! Object.prototype 被污染
console.log("污染检查2:", [].isAdmin);   // true! Array.prototype 也被影响
console.log("污染检查3:", "test".isAdmin); // true! String 也受影响

当程序没有渲染isAdmin时是不会触发原型链污染,故原型链污染的一个前提是要能够渲染我们输入的参数

在三次检查中可以知道一旦污染成功便会存在于prototype属性中,即使新建一个对象也会包含我们输入的内容

对应到本题

javascript 复制代码
let newUser = Object.assign({}, baseUser, user)
    users.push(newUser)

并且从上面的源代码中我们可以知道

javascript 复制代码
 let user = JSON.parse(req.body)

在注册页面中传入的所有参数都会传入到user中

javascript 复制代码
if (user.isAdmin && user.inviteCode != INVITE_CODE) {
        user.isAdmin = false
        return res.json({ msg: 'invalid invite code', err: true })

nodejs通过post请求体来进行解析

当isAdmin返回为false时会登录失败

因此当我们污染 proto.isAdmin 为 true 时便可注册一个获取管理员权限的账号

相关推荐
5008424 分钟前
React Native for OpenHarmony 实战:三方库 react-native-device-uptime 的鸿蒙化适配指南
javascript·分布式·react native·react.js·harmonyos
admin and root8 小时前
「AI安全篇」实战AntiDebug自动化JS逆向加解密MCP
javascript·人工智能·网络安全·自动化·漏洞挖掘·cnvd·src赏金
前端snow9 小时前
ai agent --- postgreSQL 关系型数据库
前端
卷无止境10 小时前
ECharts:把数据变成故事的可视化利器
前端
Eric_见嘉10 小时前
在职前端 Skill 和 MCP 分享
前端·后端·agent
hengdonghui10 小时前
Writeup 4 2020 - 之江杯 - 异常的工程文件
ctf·工控
liangshanbo121510 小时前
面试题:如何优化 Webpack 的打包速度?
前端·webpack·node.js
hengdonghui10 小时前
Writeup 4 2020 - 之江杯 - 注册表分析
注册表·ctf
wengad10 小时前
从 wangEditor 迁到 wangEditor-next
前端·javascript·vue.js
泛联新安11 小时前
软件定义汽车时代,如何让AI研发“可信”?——泛联新安构建汽车企业级可信AI体系的落地路径
大数据·人工智能·安全·网络安全·汽车·漏洞挖掘·代码安全