作者: wh0am1i@知道創宇404實驗室
日期:2023年6月29日

0x01 GeoServer & GeoTools

GeoServer 是一個用 Java 編寫的開源軟件服務器,允許用戶共享和編輯地理空間數據,GeoServer 基于 Spring 開發,使用到了 GeoTools 庫。

GeoTools 是一個開源的 Java 庫,提供對地理數據空間工具,GeoServer 許多核心功能使用 GeoTools 實現,如:數據讀寫轉換。

0x02 漏洞介紹

GeoServer 和 GeoTools 發布了 CVE-2023-25157CVE-2023-25158,OGC 查詢存在 SQL 注入漏洞。GeoServer 支持 OGC 過濾器表達式語言和 OGC 通用查詢語言 (CQL),主要影響 Web 要素服務 (WFS) 、Web 地圖服務 (WMS) 和 用于 ImageMosaic 覆蓋的 Web 覆蓋服務 (WCS) 協議,已知以下情況會觸發此漏洞:

  • PropertyIsLike 與帶有字符串字段的任何數據庫一起使用時,或者與啟用了編碼功能的 PostGIS 數據存儲一起使用時
  • strEndsWith 啟用了編碼功能的 PostGIS DataStore 一起使用時
  • strStartsWith 啟用了編碼功能的 PostGIS DataStore 一起使用時
  • FeatureId 與具有字符串主鍵列的任何數據庫表一起使用并禁用預編譯時
  • jsonArrayContains 字符串或 JSON 字段以及 PostGIS 或 Oracle DataStore 一起使用時(僅 GeoServer 2.22.0 以上版本受影響)
  • DWithin 與 Oracle DataStore 一起使用時

對于 GeoTools 在使用 JDBCDataStore 實現執行 OGC 過濾器時存在 SQL 注入漏洞:

  • PropertyIsLike 啟用“編碼功能”的 PostGIS DataStore 或者任何帶有字符串字段的 JDBCDataStore
  • strEndsWith 啟用“編碼功能”的 PostGIS DataStore
  • strStartsWith 啟用“編碼功能”的 PostGIS DataStore
  • FeatureId JDBCDataStore禁用預編譯并且有字符串主鍵(Oracle 不受影響,SQL Server 和 MySQL 沒有啟用預準備語句的設置,PostGIS 則受影響)
  • jsonArrayContains 帶有字符串或 JSON 字段的 PostGIS 和 Oracle DataStore
  • DWithin 僅在 Oracle DataStore 中

0x03 影響版本

GeoServer <2.21.4,<2.22.2

GeoTools <28.2、<27.4、<26.7、<25.7、<24.7

官方已發布補丁,請及時更新。

0x04 環境搭建

在這里使用 GeoServer 2.21.3,下載完成后解壓:

unzip geoserver-2.21.3-bin.zip

進入到 geoserver-2.21.3-bin/bin 目錄下,執行啟動程序

sh startup.sh

啟動成功后,訪問 http[:]//x.x.x.x:8080/geoserver/web/ 即可。

使用 Docker 搭建 PostgreSQL

docker run -e POSTGRES_PASSWORD=password -d -p 5433:5432  postgres:latest

進入容器,安裝 postgis 拓展

apt search postgis

apt install postgis postgresql-14-postgis-3-scripts

postgresql-14-postgis-3-scripts 要根據你 PostgreSQL 來安裝,本次使用到的 PostgreSQL 為 PostgreSQL 14.1

此時數據可參考官方文檔:https://docs.geoserver.org/latest/en/user/gettingstarted/postgis-quickstart/index.html

編輯 startup.sh 啟動腳本添加遠程調試參數:

exec "${_RUNJAVA}" ${JAVA_OPTS:--DNoJavaOpts -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005} "${MARLIN_ENABLER:--DMarlinDisabled}" "${RENDERER:--DDefaultrenderer}" "-Djetty.base=${GEOSERVER_HOME}" "-DGEOSERVER_DATA_DIR=${GEOSERVER_DATA_DIR}" -Djava.awt.headless=true -DSTOP.PORT=8079 -DSTOP.KEY=geoserver -jar "${GEOSERVER_HOME}/start.jar"

至此環境搭建結束。

0x05 漏洞分析

由于存在多個注入點,在這里以 strStartsWith 作為案例進行分析,將項目導入 IDEA,開啟 DEBUG 調試,下斷點定位到 ogr.geotools.jdbc 下的 getReaderInternal 函數

在查詢之前 this.getDataStore().getConnection(this.getState()); 會執行 select now() 判斷是否能正常連接數據庫。

繼續跟進到 selectSQL

selectSQL 函數中 selectColumns 會對數據庫中的字段進行遍歷,并拼接出 SQL 語句

拼接相關函數如下:

拼接完成后 SQL 語句如下:

SELECT "gid","bin",encode(ST_AsEWKB("the_geom"), 'base64') as "the_geom" FROM "public"."nyc_buildings" WHERE

接下來是對 filter 的處理

filter 中將我們輸入的 CQL_FILTER 轉換成 SQL 后語句后拼接到 WHERE 后面

因此最后拼接出來的 SQL 語句如下:

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 語句

總結一下:org.geotools.jdbc 下的 getReaderInternal() 函數對用戶輸入的查詢進出處理,進一步調用 selectSQL 生成對應數據庫的 SQL 查詢語句,生成數據庫的查詢語句后,會對判斷是否存在 CQL_FILTER 查詢條件,如果是存在則開始處理用戶輸入的 CQL_FILTER 條件,由 encodeToString(Filter filter)CQL_FILTER 轉換為 SQL 語句,再由 FilterToSQL filter 拼接到 WHETE 后面,最后 JDBCFeatureReaderthis.runQuery 執行帶有注入的 SQL 語句,完成注入。

最終的整個漏洞的調用棧如下:

<init>:153, JDBCFeatureReader (org.geotools.jdbc)
getReaderInternal:607, JDBCFeatureSource (org.geotools.jdbc)
getReaderInternal:218, JDBCFeatureStore (org.geotools.jdbc)
getReader:636, ContentFeatureSource (org.geotools.data.store)
features:173, ContentFeatureCollection (org.geotools.data.store)
features:52, ContentFeatureCollection (org.geotools.data.store)
features:40, SecuredFeatureCollection (org.geoserver.security.decorators)
features:75, SecuredSimpleFeatureCollection (org.geoserver.security.decorators)
features:93, DecoratingSimpleFeatureCollection (org.geotools.feature.collection)
encode:572, FeatureTransformer$FeatureTranslator (org.geotools.gml.producer)
parse:1054, TransformerBase$XMLReaderSupport (org.geotools.xml.transform)
transform:485, TransformerIdentityImpl (org.apache.xalan.transformer)
run:287, TransformerBase$Task (org.geotools.xml.transform)
transform:121, TransformerBase (org.geotools.xml.transform)
transform:103, TransformerBase (org.geotools.xml.transform)
encode:247, GML2OutputFormat (org.geoserver.wfs.xml)
write:261, GML2OutputFormat (org.geoserver.wfs.xml)
write:199, WFSGetFeatureOutputFormat (org.geoserver.wfs)
response:1018, Dispatcher (org.geoserver.ows)
handleRequestInternal:272, Dispatcher (org.geoserver.ows)

0x06 修復

目前 GeoServer 和 Geotools 官方均已發布修復版本,查看 GeoServer 官方提交的補丁,在 src/community/jdbcconfig/src/main/java/org/geoserver/jdbcconfig/internal/ConfigDatabase.java 中添加了模塊org.geoserver.jdbcloader.JDBCLoaderProperties 模塊用于配置文件 jdbcconfig/jdbcconfig.properties中的 JDBCConfig 模塊屬性字段并更改了構造函數以包含此屬性字段。

還修改了 src/community/jdbcconfig/src/main/java/org/geoserver/jdbcconfig/internal/OracleDialect.java 中的插入語法

而在 GeoTools 提交的補丁中,修改 modules/library/jdbc/src/main/java/org/geotools/data/jdbc/FilterToSQL.java 添加了EscapeSql 模塊和 escapeBackslash 字段對 SQL 注入進行防御

0x07References

https://github.com/murataydemir/CVE-2023-25157-and-CVE-2023-25158

https://docs.geoserver.org/latest/en/user/introduction/overview.html


Paper 本文由 Seebug Paper 發布,如需轉載請注明來源。本文地址:http://www.bjnorthway.com/2087/