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 进行执行。