什么是 InfluxDB
InfluxDB 是一种流行的开源时间序列数据库,旨在处理大量带时间戳的数据。InfluxDB 广泛用于监控和分析来自传感器、应用程序和物联网设备等各种来源的指标、事件和实时数据。
初步漏洞识别
在WEB应用程序分析过程中,我在URL的查询参数中发送字符“后收到以下错误:
Java |
这看起来很像一个注入问题,在 Google 上搜索后,我得出结论,后端正在使用 InfluxDB。
此时,我开始阅读文档(https://docs.influxdata.com/influxdb/v2.7/),试图弄清楚后端发生了什么。
InfluxDB NoSQL 查询
这是 InfluxDB NoSQL 查询的一个简单示例:
Java |
给定的 InfluxDB 查询从“example-bucket”中检索过去一小时内的数据,并根据特定条件过滤数据。
以下是查询各部分的细分:
from(bucket: "example-bucket"):这部分指定将从中检索数据的源存储桶。InfluxDB 将数据组织到存储桶中,在这里,数据将从“example-bucket”中获取。存储桶就像 SQL 语言中的数据库名称。
|> range(start: -1h):该部分设置数据检索的时间范围。该range函数用于定义时间窗口。在本例中,它指定当前时间的最后一小时的数据。该参数start: -1h表示获取一小时前到当前时间的数据。
|> filter(fn: (r) => r._measurement == "example-measurement" and r.tag == "example-tag"):这部分根据某些条件对数据应用过滤器。该filter函数用于选择满足定义标准的特定数据点。执行filter()类似于类 SQL 语言中的SELECT语句和子句的操作。WHERE
总之,查询从“example-bucket”中获取过去一小时内的数据,并过滤数据以仅包含属于测量“example-measurement”并且具有带有键“tag”和值的标签的数据点“示例标签。”
构建靶场的 WEB 应用程序
了解语法后,是时候构建我们的易受攻击的应用程序,以便最终在现实应用程序上构建有效的概念证明。
以下代码是一个易受攻击的服务器示例:
Java |
在上面的示例中,服务器将用户提供的输入连接到' + req.query.data + 'InfluxDB 查询,而不进行任何清理:
Java |
通过发送包含字符“的 HTTP 请求,该字符将转义查询的字符串序列,我们可以确认它返回了之前在 Bug Bounty 计划服务器中看到的相同错误:
漏洞利用
注入漏洞利用
泄漏桶名称
如前所述,在 InfluxDB 上,存储桶名称就像其他 SQL 语言上的数据库名称一样,并且像 SQL 注入利用过程一样,找到一种方法来泄漏这些存储桶名称以访问整个数据库至关重要。
仔细阅读文档后,假设注入发生在过滤器函数处,我实现了以下基于错误的 NoSQLI 负载:
Java |
该buckets()函数列出当前数据库中的所有存储桶。
该filter()函数使用r.name表达式来过滤存储桶名称,该名称r是存储桶查询的结果,并且name是函数中返回的字段buckets()。
如您所见,InfluxDB 查询支持正则表达式操作=~,因此条件背后的逻辑r.name =~ /^a.*/是,true如果存储桶名称以字母 开头,则为该条件a。
之后,过滤器使用一个and条件来调用函数,die()并将存储桶名称的值作为参数。该die()函数会抛出一个错误,并在第一个参数中传递自定义消息,这将泄漏存储桶名称。
有效负载也在yield()存储桶查询之前使用该函数。这是在 InfluxDB 上的单个请求中执行“多个查询”所必需的。
最后,有必要用yield()一个新行将 与存储桶查询分开,并且在有效负载的末尾,我在//另一个新行后面添加了表达式,以注释注入后的所有内容。
继续来说,如果a数据库中存在以该字母开头的存储桶名称,则会触发die()错误消息中泄漏存储桶名称的函数。如果没有存储桶以发送的信件开头,服务器将返回一个空输出,没有错误。
尝试我们的易受攻击的应用程序,我们可以看到信件中没有返回任何错误a:
但是使用字母发送相同的有效负载p会泄漏存储桶名称privateBucket:
要泄漏所有存储桶名称,需要测试所有字符,在匹配后添加另一个序列(例如pa,,...)。pbpc
泄露存储桶字段名称
现在我们有了存储桶的名称,我们可以尝试获取它们的内容,但是像其他 SQL 语言一样,有时我们需要指定列名来查询特定数据,在本节中,我将展示一种泄漏这些列的技术InfluxDB 中的名称。
在动态分析过程中,我能够找到一个触发错误的有效负载,其中包含任何存储桶的数据结构:
Java |
上面的有效负载使用了类似的技术,使用该yield()函数并在有效负载的末尾添加注释:
有效负载现在使用该from()函数来获取泄漏的存储桶名称的数据,这range()是必需的,最后是filter().
在filter()函数中,我die()再次调用,但现在将整个结果 abject 作为参数发送。由于该die()函数仅接受字符串作为参数,并且结果对象包含所有存储桶数据结构,因此服务器将触发泄漏它的详细错误。
正如您在上面的屏幕截图中看到的,服务器泄漏了以下结构:
Java |
现在我们知道了查询结构,我们可以使用正则表达式比较来强制错误泄漏所有字段名称:
Java |
正如我们所看到的,存在漏洞的应用程序泄露了字段名称,sensitive_field因为它与正则表达式条件匹配r._field =~ /s.*/。
泄漏字段值
泄漏所有字段名称后,我们可以尝试泄漏字段值。字段值是 InfluxDB 的“最终节点”,它是存储数据的地方,换句话说,泄漏值是利用的最后一步。为此,我们可以使用与泄漏字段名称相同的技术,但现在指定我们要检索的字段:
Java |
通过发送上述有效负载,服务器响应一个错误:
Java |
发生这种情况是因为存储的数据r._value是整数并且该die()函数仅接受字符串。为了避免这种情况,我们可以使用该string()函数将整数值转换为字符串,并成功地将其泄漏到错误消息中:
Java |
正如我们在上面的屏幕截图中看到的, 的sensitive_field值为1337。这意味着我们能够从其他存储桶中获取任意数据!
InfluxDB 服务器端请求伪造
在阅读文档时,我注意到一些 InfluxDB 函数接受host参数,其中一个函数是from():
host通过在函数中发送参数from(),我们可以向任意 URL 发出 HTTP 请求。以下有效负载是使用 NoSQL 注入漏洞的 SSRF 示例:
Java |
这是我的 Burp 合作者收到的请求:
如果存在漏洞的应用程序使用本地 InfluxDB 数据库,则也可以获取内部端点。
这不是 InfluxDB 的漏洞,这只是由不安全的编码实践引发的 NoSQL 注入滥用的功能。
InfluxDB 跨站脚本
我们的示例服务器还容易通过 NoSQL 注入遭受反射型 XSS 攻击:
Java |
如果您像我一样有 XSS 雷达,您会注意到,当 InfluxDB 查询中发生错误时,该try{ } catch{ }语句会将错误发送回客户端,并使用Content-Typeequals to text/html,允许浏览器加载 HTML 和 JavaScript。
此外,我们可以控制这些错误中反映的一些数据,特别是通过以下die()函数:
由于查询 API 使用 GET 方法,因此可以通过发送恶意链接在受害者的浏览器上执行任意 JavaScript:
http://127.0.0.1:3000/query?data=%22)%20die(msg%3a%22%3cimg%20src%3dx%20onerror%3dalert(document.domain)%3e%22)%2f%2f
Java |
这不是 InfluxDB 漏洞,因为该问题是由不安全的编码实践和 NodeJS 不安全的默认内容类型引起的 NoSQL 注入引起的。
原文始发于微信公众号(暴暴的皮卡丘):NoSQL influxDB安全
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论