复现
0.源码下载和环境配置
在github上down下存在漏洞的源码:https://github.com/spring-cloud/spring-cloud-function/releases/tag/v3.2.0
在spring-cloud-function-3.2.0\spring-cloud-function-3.2.0\spring-cloud-function-samples目录下使用idea直接打开function-sample
1.使用默认配置下functionRouter路由复现
直接运行src/main/java/com/example/SampleApplication.java
默认端口为8080,可在src/main/resources/application.properties中添加server.port = 8888
进行端口修改。
默认页面为:
burp对存在漏洞的路由functionRouter进行post发包可执行任意命令。
payload为spring.cloud.function.routing-expression: T(java.lang.Runtime).getRuntime().exec("calc")
2.修改默认设置使任意路由可触发:
在src/main/resources/application.properties中添加spring.cloud.function.definition:functionRouter
造成任意路由定义至functionRouter从而导致任意路由可触发
分析
查看补丁:
https://github.com/spring-cloud/spring-cloud-function/commit/dc5128b80c6c04232a081458f637c81a64fa9b52?diff=split
可以看见修改了spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/config/RoutingFunction.java文件中如下
添加了true。
在idea中查找functionFromExpression
可查看其定义
private FunctionInvocationWrapper functionFromExpression(String routingExpression, Object input) {
Expression expression = this.spelParser.parseExpression(routingExpression);
String functionName = (String)expression.getValue(this.evalContext, input, String.class);
Assert.hasText(functionName, "Failed to resolve function name based on routing expression '" + this.functionProperties.getRoutingExpression() + "'");
FunctionInvocationWrapper function = (FunctionInvocationWrapper)this.functionCatalog.lookup(functionName);
Assert.notNull(function, "Failed to lookup function to route to based on the expression '" + this.functionProperties.getRoutingExpression() + "' whcih resolved to '" + functionName + "' function name.");
if (logger.isInfoEnabled()) {
logger.info("Resolved function from provided [routing-expression] " + routingExpression);
}
return function;
}
可以发现存在expression.getValue();
在此处添加断点并debug,之后再次发包可发现:
单独拿出getvalue:
果然是该处出现问题。
往上查找发现spring.cloud.function.routing-expression
该语句意为如果存在spring.cloud.function.routing-expression字段就将该字段加入function对象,最后由方法functionFromExpression返回一个function对象。而在加入的过程中使用了getvalue(),当程序在运行的时候会解析其中的SpEL的表达式来填充value值得内容。而指定functionRouter路由是因为function会根据这个字段来通过目录获取对应功能接口的实例。