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。