How to attack Hacking MongoDB
MongoDB is a good database engine for both commercial and personal projects, and many domestic companies have begun to use MongoDB. Compared with traditional databases, this database is relatively new and has many security problems that you are not aware of yet. These problems can usually be caught off guard.
This article mainly introduces the problems I encountered when using MongoDB and how it was used to modify Database records. Of course, the process of using SQL injection is very simple, but the SQL injection technology in various ways is the same, but many people are still prone to such errors.
Before we begin, I would like to introduce the following MongoDB features. The update mechanism provided by MongoDB is to first locate this document and then update it, as shown in the following example:
{
Name: "John ",
Info :{
Age: 65
}
}
You can use the following statement to update the above record:
Db. people. update ({"name": "John" },{ "$ set": {"info. age": 66 }})
Is it really cool? Okay, you know.
But what if the sub-key is not hard-coded? How can we pass in the content through variables? As follows:
KeyName = request. form | 'keyname' |
KeyData = request. form | 'value' |
Db. people. update ({"name": "John"}, {"$ set": {"info. {}". format (keyName): keyData }})
After the background program obtains the key and value values from the front-end request, it passes the parameters to the MongoDB update function. The problem arises. What if the front-end inputs a malicious parameter.
The following is a problem I encountered when handling an unknown user input. To illustrate this problem, let's write a section to demonstrate this vulnerability. The Code is as follows:
From flask import *
Import pymongo
Import bson
Import uuid
Db = pymongo. Expose client ("localhost", 27017). test
Form = """
"""
App = Flask (_ name __)
App. secret_key = "secret"
@ App. route ("/logout /")
Def logout ():
Session. pop ("_ id ")
Return redirect ("/login /")
@ App. route ("/")
Def index ():
If "_ id" not in session:
Return redirect ("/login /")
Name = request. args. get ("name ")
Lastname = request. args. get ("lastname ")
If not name:
Return "Search for someone"
Else:
Search_results = db. members. find_one ({"{}". format (name): lastname })
If search_results:
Search_results = name + "" + lastname + "is" + search_results ['account _ info'] ['age'] + "years old ."
Return "{}". format (search_results)
@ App. route ("/login/", methods = ['get', 'post'])
Def login ():
If request. method = "POST ":
Username = request. form ['username']
Password = request. form ['Password']
Check = db. members. find_one ({"username": username, "password": password })
If check:
Session ['_ id'] = str (check)
Return rediirect ("/? Name = {} ". format)
Else:
Return "Invalid Login"
Return "Login" + form
@ App. route ("/signup/", methods = ['get', 'post'])
Def signup ():
If request. method = "POST ":
Username = request. form ['username']
Firstname = request. form ['firstname']
Lastname = request. form ['lastname']
Password = request. form ['Password']
Age = request. form ['age']
Session ['_ id'] = str (db. members. insert ({"username": username, "password": password, firstname: lastname, "account_info": {"age": age, "age": age, "isAdmin ": false, "secret_key": uuid. uuid4 (). hex }}))
Return redirect ("/")
Return "Signup" + form
@ App. route ("/settings/", methods = ['get', "POST"])
Def settings ():
If request. method = "POST ":
Username = request. form ['username']
Firstname = request. form ['firstname']
Lastname = request. form ['lastname']
Password = request. form ['Password']
Age = request. form ['age']
Db. members. update ({"_ id": bson. objectId (session ['_ id']) },{ "$ set ":{"{}". format (firstname): lastname, "account_info.age": age, "username": username }})
Return "Values have been updated! "
Return "Settings" + form
@ App. route ("/admin/", methods = ['get', 'post'])
Def admin ():
If "_ id" not in session:
Return redirect ("/login /")
TheUser = db. members. find_one ({"_ id": bson. ObjectId (session ['_ id'])})
If not theUser ['account _ info'] ['isadmin']:
Return "You do not have access to this page ."
If request. method = "POST ":
Secret = request. form ['secret _ key']
Return str (db. members. find_one ({"account_info.secret_key": secret }))
Return "" Search user by secret key
"""
App. run (debug = True)
This website is very simple. It is a login page, a registration page, a setting page, and an index page. Users can enter their/their names on these pages, and then return the age, such.
Note that this code is vulnerable to injection attacks. Next, let's take a look at how to inject it.
Our goal is to obtain the permission to access the admin page. We can find from the website code that the background verifies user permissions based on the isAdmin field, as shown in figure
Check whether the background database is like this:
Among them, Firstname: Lastname is directly inserted into the name, it looks strange.
Create a user first, and then access the/admin/page. The returned result is as follows:
Good ...... No access permission. In retrospect, isAdmin can be used to control the page, that is, the user may be in the database like this:
Among them, firstname: lastname is controllable and entered on the settings page, "username", "password", "firstname ", and "lastname" are actually all input. firstname: lastname can be used for query. It seems that some articles can be written.
Change fistname to account_info.isAdmin and lastname to "1". 1 indicates True in python.
Click Submint and the modification is successful.
Access the/admin/Page:
You can access the admin page: D
Similarly, if you want to use the secret key to query the entire content, you can do this:
Input query:
Successful:
At this point, we can actually do a lot more. We can use it to modify the account and password of other users and view other users. I will not introduce it here.
Obviously, all the security measures for this website are useless, and sensitive data is also becoming dangerous. Of course, when your website is attacked and you look back at the code, you may think your code is very funny, but this is absolutely not to be ignored. Well, in fact, I have made such a mistake and I am glad to find it in time.
Like SQL Injection in relational databases, what we need to do is filter input parameters.