作者: wh0am1i@知道創宇404實驗室
日期:2023年6月29日
0x01 GeoServer & GeoTools
GeoServer 是一個用 Java 編寫的開源軟件服務器,允許用戶共享和編輯地理空間數據,GeoServer 基于 Spring 開發,使用到了 GeoTools 庫。
GeoTools 是一個開源的 Java 庫,提供對地理數據空間工具,GeoServer 許多核心功能使用 GeoTools 實現,如:數據讀寫轉換。
0x02 漏洞介紹
GeoServer 和 GeoTools 發布了 CVE-2023-25157 和 CVE-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
后面,最后 JDBCFeatureReader
的 this.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
本文由 Seebug Paper 發布,如需轉載請注明來源。本文地址:http://www.bjnorthway.com/2087/