freeBuf
主站

分类

漏洞 工具 极客 Web安全 系统安全 网络安全 无线安全 设备/客户端安全 数据安全 安全管理 企业安全 工控安全

特色

头条 人物志 活动 视频 观点 招聘 报告 资讯 区块链安全 标准与合规 容器安全 公开课

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

安全审计案例:绕过Apache Superset限制执行SQL注入
2024-11-20 15:12:42
所属地 广东省

前言

在现代数据驱动的世界中,数据安全和隐私保护变得越来越重要。Apache Superset 作为一个广泛使用的开源数据探索和可视化平台,其安全性尤其受到关注。本文将详细介绍我们在一次审计过程中发现的一个严重漏洞,以及如何利用这一漏洞绕过 Apache Superset 的安全措施,执行任意 SQL 查询。

什么是 Apache Superset?

Apache Superset 是一个开源平台,用于数据探索和可视化。它提供了一个无需编码的界面,用于快速图表制作,使用户能够在不编写复杂 SQL 查询的情况下探索数据。此外,Superset 还提供了一个基于 Web 的 SQL 编辑器,用于更高级的分析。尽管可以执行 SQL 查询,但并非所有操作都对用户开放,因为安全性和数据隔离是考虑的重要因素。

背景

在一次针对某企业 Web 应用的安全审计过程中,发现某企业的应用程序使用了Apache Superset(版本4.0.1,撰写本文时的最新版本)来展示数据图表和分析结果。通过分析应用程序与Burp之间的交互,发现可以与Apache Superset的API进行交互。

在进一步的测试中,发现可以通过以下API路径控制DBMS执行某些 SQL 查询:

/superset/explore_json/(使用 xpath_exists(xpath, xml [, nsarray]) 将基于时间的注入转换为基于错误的注入,该函数评估XPath 1.0表达式)

/api/v1/chart/data

1732086227_673d89d3de643d07b3d24.png!small?1732086228655

1732086238_673d89de560f1d55c20de.png!small?1732086238892

需要注意的是,在Apache Superset中执行 SQL 查询是正常的,因为这是该应用程序的主要目的,并不被视为漏洞。这篇文章的目的是展示已识别的关于防止攻击者执行任意 SQL 请求的安全措施的弱点。

一旦用户(因此也是攻击者)试图执行任意请求,这些请求就会被安全机制阻止。

1732086256_673d89f09b86db6c83fad.png!small?1732086257026

查看代码

为了确定阻塞的原因,只需从GitHub获取源代码。经过快速的代码审查,以下代码片段似乎检查查询是否包含任何子查询。

文件:superset/models/helpers.py

函数:validate_adhoc_subquery()

def validate_adhoc_subquery(

sql: str,

database_id: int,

default_schema: str,

) -> str:

"""

Check if adhoc SQL contains sub-queries or nested sub-queries with table.

If sub-queries are allowed, the adhoc SQL is modified to insert any applicable RLS

predicates to it.


:param sql: adhoc sql expression

:raise SupersetSecurityException if sql contains sub-queries or

nested sub-queries with table

"""

statements = []

for statement in sqlparse.parse(sql):

if has_table_query(statement):

if not is_feature_enabled("ALLOW_ADHOC_SUBQUERY"):

raise SupersetSecurityException(

SupersetError(

error_type=SupersetErrorType.ADHOC_SUBQUERY_NOT_ALLOWED_ERROR,

message=_("Custom SQL fields cannot contain sub-queries."),

level=ErrorLevel.ERROR,

)

)

statement = insert_rls_in_predicate(statement, database_id, default_schema)

statements.append(statement)


return ";\n".join(str(statement) for statement in statements)


如上所示,validate_adhoc_subquery() 函数调用了 has_table_query() 函数。

文件:superset/sql_parse.py

函数:has_table_query()

def has_table_query(token_list: TokenList) -> bool:

"""

Return if a statement has a query reading from a table.


>>> has_table_query(sqlparse.parse("COUNT(*)")[0])

False

>>> has_table_query(sqlparse.parse("SELECT * FROM table")[0])

True


Note that queries reading from constant values return false:

>>> has_table_query(sqlparse.parse("SELECT * FROM (SELECT 1)")[0])

False

"""

state = InsertRLSState.SCANNING

for token in token_list.tokens:

# Ignore comments

if isinstance(token, sqlparse.sql.Comment):

continue


# Recurse into child token list

if isinstance(token, TokenList) and has_table_query(token):

return True


# Found a source keyword (FROM/JOIN)

if imt(token, m=[(Keyword, "FROM"), (Keyword, "JOIN")]):

state = InsertRLSState.SEEN_SOURCE


# Found identifier/keyword after FROM/JOIN

elif state == InsertRLSState.SEEN_SOURCE and (

isinstance(token, sqlparse.sql.Identifier) or token.ttype == Keyword

):

return True


# Found nothing, leaving source

elif state == InsertRLSState.SEEN_SOURCE and token.ttype != Whitespace:

state = InsertRLSState.SCANNING


return False

has_table_query() 函数使用 sqlparse 库解析将要执行的 SQL 查询,以在执行前验证或拒绝查询。该功能的工作原理如下:查询元素被标记化,如果查询包含禁止的元素,则查询被拒绝。我们发现,可能是FROM子句的使用触发了安全机制。

阅读文档并找到绕过方法

在参考了文档中的几个命令设置实验环境后,发现默认的DBMS是PostgreSQL,于是开始研究如何绕过安全措施以执行任意查询。。

git clone https://github.com/apache/superset

cd superset

docker compose -f docker-compose-image-tag.yml up

查看了PostgreSQL的文档,并识别了以下函数:

  • query_to_xml(query text, nulls boolean, tableforest boolean, targetns text):将关系表的内容映射为 XML 值。
  • query_to_xml_and_xmlschema(query text, nulls boolean, tableforest boolean, targetns text):在一个文档(或森林)中生成 XML 数据映射及其对应的 XML Schema,并将其链接在一起。
  • table_to_xml(tbl regclass, nulls boolean, tableforest boolean, targetns text):将关系表的内容映射为 XML 值。
  • table_to_xml_and_xmlschema(tbl regclass, nulls boolean, tableforest boolean, targetns text):在一个文档(或森林)中生成 XML 数据映射及其对应的 XML Schema,并将其链接在一起。
  • database_to_xml(nulls boolean, tableforest boolean, targetns text):生成整个模式或当前数据库的类似映射。

这些函数接受字符串作为参数,将其作为 SQL 查询执行,并将结果格式化为预期的输出(XML)。因此,我们可以通过调用这些函数来执行任意请求。在解析过程中(由 sqlparse 进行),我们的恶意查询被视为字符串(函数参数),并被“标记化”为字符串,这就是为什么 has_table_query 函数无法检测到注入的原因。

1732086412_673d8a8c3637ac2206aa9.png!small?1732086412994

结论

通过这次审计,不仅发现了Apache Superset中的一个严重漏洞,还展示了如何通过深入研究和文档分析找到绕过安全措施的方法。这一发现提醒我们,即使是最成熟的数据平台也可能存在安全漏洞,因此持续的安全审计和及时的漏洞修复至关重要。希望这篇文章能帮助大家更好地理解Apache Superset的安全机制及其潜在的漏洞,并采取相应的防护措施,确保数据的安全性和完整性。

# SQL注入 # web安全 # 数据安全 # 网络安全技术 # 安全审计
本文为 独立观点,未经允许不得转载,授权请联系FreeBuf客服小蜜蜂,微信:freebee2022
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
相关推荐
  • 0 文章数
  • 0 关注者
文章目录