CVE-2018-1273

https://github.com/vulhub/vulhub/tree/master/spring/CVE-2018-1273

https://sourcegraph.com/search?q=context:global+repo:%5Egithub%5C.com/spring-projects/spring-data-commons%24%402.0.6.RELEASE:%5E2.0.5.RELEASE+type:diff+spel&patternType=standard&sm=1&groupBy=path

https://sourcegraph.com/github.com/spring-projects/spring-data-commons/-/commit/ae1dd2741ce06d44a0966ecbd6f47beabde2b653?visible=1

概述

Spring Data Commons 远程命令执行漏洞(CVE-2018-1273)

Spring Data是一个用于简化数据库访问,并支持云服务的开源框架,Spring Data Commons是Spring Data下所有子项目共享的基础框架。Spring Data Commons 在2.0.5及以前版本中,存在一处SpEL表达式注入漏洞,攻击者可以注入恶意SpEL表达式以执行任意命令。

影响版本:

Spring Data Commons 1.13 - 1.13.10 (Ingalls SR10)

Spring Data REST 2.6 - 2.6.10 (Ingalls SR10)

Spring Data Commons 2.0 to 2.0.5 (Kay SR5)

Spring Data REST 3.0 - 3.0.5 (Kay SR5)

分析

搜索SpelExpressionParser可以定位到org.springframework.data.web.MapDataBinder.MapPropertyAccessor#setPropertyValue,但是无法往上追路径。

        @Override
        public void setPropertyValue(String propertyName, @Nullable Object value) throws BeansException {

            if (!isWritableProperty(propertyName)) {
                throw new NotWritablePropertyException(type, propertyName);
            }

            StandardEvaluationContext context = new StandardEvaluationContext();
            context.addPropertyAccessor(new PropertyTraversingMapAccessor(type, conversionService));
            context.setTypeConverter(new StandardTypeConverter(conversionService));
            context.setTypeLocator(typeName -> {
                throw new SpelEvaluationException(SpelMessage.TYPE_NOT_FOUND, typeName);
            });
            context.setRootObject(map);

            Expression expression = PARSER.parseExpression(propertyName);

            PropertyPath leafProperty = getPropertyPath(propertyName).getLeafProperty();
            TypeInformation<?> owningType = leafProperty.getOwningType();
            TypeInformation<?> propertyType = leafProperty.getTypeInformation();

            propertyType = propertyName.endsWith("]") ? propertyType.getActualType() : propertyType;

            if (propertyType != null && conversionRequired(value, propertyType.getType())) {

                PropertyDescriptor descriptor = BeanUtils.getPropertyDescriptor(owningType.getType(),
                        leafProperty.getSegment());

                if (descriptor == null) {
                    throw new IllegalStateException(String.format("Couldn't find PropertyDescriptor for %s on %s!",
                            leafProperty.getSegment(), owningType.getType()));
                }

                MethodParameter methodParameter = new MethodParameter(descriptor.getReadMethod(), -1);
                TypeDescriptor typeDescriptor = TypeDescriptor.nested(methodParameter, 0);

                if (typeDescriptor == null) {
                    throw new IllegalStateException(
                            String.format("Couldn't obtain type descriptor for method parameter %s!", methodParameter));
                }

                value = conversionService.convert(value, TypeDescriptor.forObject(value), typeDescriptor);
            }

            try {
                expression.setValue(context, value);
            } catch (SpelEvaluationException o_O) {
                throw new NotWritablePropertyException(type, propertyName, "Could not write property!", o_O);
            }
        }

修复分析

修复实际上就是将StandardEvaluationContext变成SimpleEvaluationContext。