THM - Advent of Cyber [Day 7]
Today’s task deals with databases. I don’t know too much about databases, so I’m excited to learn something new today. The task deals mainly with NoSQL (non SQL) databases and specifically a type of NoSQL database called Mongo DB
. The naming scheme is different between SQL and NoSQL, and here’s how the definitions translate:
MySQL | MongoDB |
---|---|
Tables/Views | Collections |
Rows/Records | Documents |
Columns | Fields |
The task also provides a graph that allows us to see what the flow of a NoSQL database looks like.
Here are some equivalent basic query operations in MongoDB and MySQL:
MySQL | MongDB |
---|---|
AND | $and |
OR | $or |
= | $eq |
Practice with MongoDB
The task wants to familiarize us with a MongoDB instance, which is great because I have no experience with MongoDB. Looks like the goal is to enumerate the DB at first and then create a new DB and documents. We can ssh into the box using the credentials thm:tryhackme
on port 2222, so that full command is ssh thm@IP-ADDRESS -p 2222
and then typing the password when prompted. The first step after login is to run mongo
to connect to the DB. then we can run show databases
to get a list of databases.
That flagdb
looks promising, but let’s not get hasty. I still need to poke around MongoDB. The task lets us know if you want to connect to an existing database or create a new one, run the use DB_NAME
command. Once inside a DB, you can create collections by running db.createCollection("COLLECTION_NAME")
. We can list the collections in a database by running db.getCollectionNames()
inside a DB.
If we want to create a document and write some data to it within one of the collections that we’ve made, we can run:
db.COLLECTION_NAME.insert({id:"1", username: "USERNAME", email: "[email protected]", password: "PASSWORD"})
The command db.COLLECTION_NAME.find()
will show all the documents and data within a collection. One of the cool things about MongoDB is that is autocreates a unique ID for each document. The data entry into the document can be updated with:
db.users.update({id:"2"}, {$set: {username: "NEW_USERNAME"}})
Where the id:"2"
is the identifier of the data entry you wish to update.
Finally, we can remove documents and collections with db.users.remove({'id':'2'})
and db.users.drop()
.
Whew that was a lot of commands, but now I know enough to grab the flag for the first question. One of the interesting things I noticed about the way data was entered is that it seems to resemble python dictionary structure, so that made it easier for me to wrap my head around what was going on.
NoSQL Injection
NoSQL injection allows for an attacker to gain control over a database. This gives attackers the ability to modify data (potentially including credentials), perform DOS attacks, and make entries into DBs that allow for them to gain access to applications and information that contains sensitive data.
Login pages speak to databases in order to authenticate users. The process may be slightly different depending on what the database is, but typically when a login request is made, the username and password is packaged up as JSON or some other type of data format, and that JSON is passed into a query for the DB, something like db.users.find({username:"TEST", password:"PASSWORD"})
. If a document is returned the the entry is good and the user is authenticated, otherwise, a null reply happens and the user is not allowed to login.
The task gives a list of MongoDB operators for us to use in the task:
$eq
– matches records equal to value$ne
– matches records not equal to value$gt
– matches records greater than value$where
– matches records based on JavaScript condition$exists
– matches records that have certain field$regex
– matches records that satisfy RegEx
We can inject these operators into our login and force the logic to allow us into the application. For instance, the task gives the example of entering {"$ne": "xyz"}
into the password field so the full query looks like this:
db.users.findOne({username:{"$ne":"admin"},password:{"$ne":"xyz"}})
This tells the DB to find a user named admin and if the admin password is NOT xzy to return the document and allow us into the application. Pretty clever right?
How to exploit NoSQL Injection
The first step of exploiting a NoSQL injection, much like the LFI vulnerability, is finding an entry point. A good place to look is in user input fields that are querying a DB like a search bar or login page. If the developer didn’t program to sanitize the user input, then we may be able to perform our NoSQL Injection. Next is to figure out how the DB is being queried by the input. Is the application using HTTP methods or JSON objects? We can look to tools like BurpSuite for info like this. In this task getting NoSQL injection from GET and POST requests involves injecting the URL with an array of a MongoDB operator. They also give an example of how this looks
http://example.thm.labs/search?username=admin&role[$ne]=user
This queries the DB for a user named admin that does not have a role of user.
The Tasks
We’re tasked with logging in as the admin user into the web application via a NoSQL Injection. We can change the query to something that checks what the password is not instead of what it is. It is important to note that we are changing the query, not the password, so if your [$ne] is not blue in burpsuite then you are actually changing the password not the query to the DB.
Once in the application, the task wants us to query the gift search to get all the users with the guest
role. Here’s the URL that we can inject with a new query:
http://10.10.163.8/search?username=guest&role=user
Now we can inject [$eq]
and [$ne]
into the url and make it return all the users with guest roles. Here’s what the new URL will look like:
http://10.10.163.8/search?username[$ne]=guest&role[$eq]=guest
It wants a similar query for the specific McSkidy
user. Here’s what that URL looks like
http://10.10.163.8/search?username=mcskidy&role[$ne]=user
And here’s the ID that we can submit for the task: