MongoDB注入:如何攻击MongoDB?
来源:互联网 发布:dw软件免费吗 编辑:程序博客网 时间:2024/06/06 02:01
不管是商业项目还是个人项目,MongoDB都是一个非常好的数据库引擎,国内很多公司也开始用MongoDB。比起传统的数据库,这款数据库比较新,也有很多安全问题是大家还没有意识到的,而这些问题通常可以打得你措手不及。
本篇文章主要向大家介绍我在使用MongoDB的过程中遇到的问题,以及它是如何被用来修改数据库记录的。当然,利用过程很简单,不过其实各种方式的SQL注入技术说破了也就那么回事,但是依然有很多人容易犯这样的错误。
在我们开始前,我想先介绍下关于以下要用到的MongoDB的特性。MongoDB提供的更新机制是先定位到该文档,然后进行更新,如下例子:
{ name:"John", info:{ age:65 }}
如上面的记录,你可以通过以下语句对它进行更新:
db.people.update({"name":"John"}, {"$set":{"info.age":66}})
是不是很酷炫,好吧,知道大家早就懂了
但是,如果子键不是硬编码的,又该如何呢?我们该如何通过变量将内容传进去呢?如下:
keyName = request.form|'keyName'|keyData = request.form|'value'|db.people.update({"name":"John"}, {"$set":{"info.{}".format(keyName):keyData}})
后台程序从前端请求中获取到key和value的值以后,通过参数传入MongoDB的更新函数中。那么问题来了,如果前端输入的是一个恶意的参数呢。
以下是我在处理一个未知用户输入时候产生的问题,为了说明,接下来我们写一段用来展示这个漏洞。代码如下:
from flask import *import pymongoimport bsonimport uuid db = pymongo.MongoClient("localhost", 27017).test form = """<html><head></head><body><form method="POST"><input type="text" name="username" placeholder="Username"><input type="text" name="password" placeholder="Password"> <input type="text" name="firstname" placeholder="Firstname"><input type="text" name="lastname" placeholder="Lastname"/><input type="text" name="age" placeholder="Age"><input type="submit" value="Submit"></form></body></html> """ 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 "<h1>Search for someone</h1><form method='GET'><input name='name' type='text' placeholder='First Name'><input name='lastname' type='text' placeholder='Last Name'><input type='submit'></form>" 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 "{}<form><input name='name' type='text' placeholder='First Name'><input name='lastname' type='text' placeholder='Last Name'><input type='submit'></form>".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 "<h1>Login</h1>" + 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 "<h1>Signup</h1>" + 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 "<h1>Settings</h1>" + 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 """<h1>Search user by secret key</h1> <form method="post"><input type="text" name="secret_key" placeholder="Secret Key"/><input type="submit" value="Serach"/></form> """ app.run(debug=True)
这个网站很简单。就是一个登陆页面,一个注册页面,一个设置页面,和一个index页面,用户可以在这些页面上输入他/她们的姓名,然后返回年龄,如下图。
需要注意的是,这段代码是很容易受到注入攻击的,接下来,我们来看看是如何进行注入的。
我们的目标是获得访问admin页面的权限。从网站代码中我们可以找到,后台是根据isAdmin字段来验证用户权限的,如下图
看一下后台的数据库大概是这样的:
其中,Firstname:Lastname是直接插入姓名的,看着很奇怪。
我们先创建一个用户,然后访问下/admin/页面,返回如下:
很好……果然没有权限访问。回顾下isAdmin可以用来控制该页面,也就是说,该用户在数据库中可能是这样的:
其中,firstname:lastname这一条是我们可控的,通过settings页面输入进去的,”username”, “password”, “firstname”, 和”lastname”实际上都是我们可以输入的,firstname:lastname在查询的时候是可以搞的,看起来似乎可以搞些文章。
把fistname改成account_info.isAdmin 并且把lastname改成”1 ”,1在python中代表的就是True。
点击Submint,发现修改成功了。
访问/admin/页面:
可以访问admin页面了,:D
同样的,要想用secret key查整个内容的话,可以这么做:
输入查询:
成功:
到此处,事实上我们能做的还有很多很多。我们可以用它来修改其他用户的账号密码,并且查看其他用户。在这里不多介绍。
很显然,这个网站的所有安全措施都没用了,敏感数据也变得危险。当然,当你的网站被攻击后,回过头来看代码,也许你会觉得自己的代码很搞笑,但这是绝对不容忽视的。好吧,其实我也犯过这样的错误,还好及时发现。
和关系型数据库的SQL注入一样,我们要做的就是过滤传入的参数。
好了,就酱紫啦~
欢迎加入我的QQ交流群425783133
- MongoDB注入:如何攻击MongoDB?
- NoSQLAttack - MongoDB默认配置攻击和注入攻击工具
- php mongodb 注入
- nosql注入-mongodb
- 【MongoDB】如何停止MongoDB服务器
- 1、mongodb:如何安装mongodb
- 一个简单的MongoDB注入
- MongoDB服务器端的JavaScript注入
- php mongodb的防注入
- Mongodb
- MongoDB
- mongodb
- mongodb
- mongodb
- MongoDB
- mongodb
- MongoDB
- MongoDb
- Spring 定时器时间规则
- 09、React系列之--使用yarn包管理工具
- 【深入Java虚拟机】之四:类加载机制
- 10、React系列之--props属性
- 磁盘管理RHCE-Day4
- MongoDB注入:如何攻击MongoDB?
- Myeclipse调整虚拟内存大小
- 在自己的linux服务器上面部署ShowDoc
- 人见人爱A^B之解题思路
- php面试题
- 既使用maven编译,又使用lib下的Jar包
- ZOJ 2319 (二维的LIS)
- 约瑟夫问题
- 任务管理RHCE-Day5