CVE-2022-22963

https://github.com/vulhub/vulhub/blob/master/spring/CVE-2022-22963/README.zh-cn.md

https://paper.seebug.org/1977/

https://sourcegraph.com/github.com/spring-cloud/spring-cloud-function/-/commit/03db9baee65ba0ddcd2c2cbc1f4ebc3646a6872e?visible=3

概述

Spring Cloud Function SpEL表达式命令注入(CVE-2022-22963)

Spring Cloud Function 提供了一个通用的模型,用于在各种平台上部署基于函数的软件,包括像 Amazon AWS Lambda 这样的 FaaS(函数即服务,function as a service)平台。

影响版本:3.0.0 <= Spring Cloud Function <= 3.2.2

分析

org.springframework.cloud.function.context.config.RoutingFunction#route

	private Object route(Object input, boolean originalInputIsPublisher) {
		FunctionInvocationWrapper function = null;

		if (input instanceof Message) {
			Message<?> message = (Message<?>) input;
			if (this.routingCallback != null) {
				FunctionRoutingResult routingResult = this.routingCallback.routingResult(message);
				if (routingResult != null) {
					if (StringUtils.hasText(routingResult.getFunctionDefinition())) {
						function = this.functionFromDefinition(routingResult.getFunctionDefinition());
					}
					if (routingResult.getMessage() != null) {
						message = routingResult.getMessage();
					}
				}
			}
			if (function == null) {
				if (StringUtils.hasText((String) message.getHeaders().get("spring.cloud.function.definition"))) {
					function = functionFromDefinition((String) message.getHeaders().get("spring.cloud.function.definition"));
					if (function.isInputTypePublisher()) {
						this.assertOriginalInputIsNotPublisher(originalInputIsPublisher);
					}
				}
				else if (StringUtils.hasText((String) message.getHeaders().get("spring.cloud.function.routing-expression"))) {
					function = this.functionFromExpression((String) message.getHeaders().get("spring.cloud.function.routing-expression"), message);
					if (function.isInputTypePublisher()) {
						this.assertOriginalInputIsNotPublisher(originalInputIsPublisher);
					}
				}
				else if (StringUtils.hasText(functionProperties.getRoutingExpression())) {
					function = this.functionFromExpression(functionProperties.getRoutingExpression(), message);
				}
				else if (StringUtils.hasText(functionProperties.getDefinition())) {
					function = this.functionFromDefinition(functionProperties.getDefinition());
				}
				else {
					throw new IllegalStateException("Failed to establish route, since neither were provided: "
							+ "'spring.cloud.function.definition' as Message header or as application property or "
							+ "'spring.cloud.function.routing-expression' as application property. Incoming message: " + input);
				}
			}
		}
		else if (input instanceof Publisher) {
			if (function == null) {
				if (StringUtils.hasText(functionProperties.getDefinition())) {
					function = functionFromDefinition(functionProperties.getDefinition());
				}
				else if (StringUtils.hasText(functionProperties.getRoutingExpression())) {
					function = this.functionFromExpression(functionProperties.getRoutingExpression(), input);
				}
				else {
					return input instanceof Mono
							? Mono.from((Publisher<?>) input).map(v -> route(v, originalInputIsPublisher))
									: Flux.from((Publisher<?>) input).map(v -> route(v, originalInputIsPublisher));
				}
			}
		}
		else {
			this.assertOriginalInputIsNotPublisher(originalInputIsPublisher);
			if (StringUtils.hasText(functionProperties.getRoutingExpression())) {
				function = this.functionFromExpression(functionProperties.getRoutingExpression(), input);
			}
			else
			if (StringUtils.hasText(functionProperties.getDefinition())) {
				function = functionFromDefinition(functionProperties.getDefinition());
			}
			else {
				throw new IllegalStateException("Failed to establish route, since neither were provided: "
						+ "'spring.cloud.function.definition' as Message header or as application property or "
						+ "'spring.cloud.function.routing-expression' as application property.");
			}
		}

		return function.apply(input);
	}

function = this.functionFromExpression((String) message.getHeaders().get("spring.cloud.function.routing-expression"), message);

org.springframework.cloud.function.context.config.RoutingFunction#functionFromExpression

漏洞就是通过spring.cloud.function.routing-expressionheader 的值,解析成 spel 表达式,并且上下文是SpelExpressionParser,然后getValue 被执行了。

修复分析

functionFromExpression增加isViaHeader的参数,用来判断是否是用户传入的 header,如果是的话就使用SimpleEvaluationContext 进行执行。