dubbo框架-默认dubbo协议和hessian2反序列化的简单总结

dubbo协议

header:

1
2
3
4
5
6
7
8
9
0-7位和8-15位:Magic High和Magic Low,类似java字节码文件里的魔数,用来判断是不是dubbo协议的数据包,就是一个固定的数字
16位:Req/Res:请求还是响应标识。
17位:2way:单向还是双向
18位:Event:是否是事件
19-23位:Serialization 编号
24-31位:status状态
32-95位:id编号
96-127位:body数据长度
128-…位:body

body:

1
2
3
4
5
6
7
1.dubboVersion
2.path
3.version
4.methodName
5.methodDesc
6.paramsObject
7.map

rpc tcp报文(ascii)

1
...           .G.2.0.20,com.threedr3am.learn.server.boot.DemoService.1.0.hello0$Lcom/threedr3am/learn/server/boot/A;C0"com.threedr3am.learn.server.boot.A..name`.xxxxH.path0,com.threedr3am.learn.server.boot.DemoService.activelimit_filter_start_time 1577081623564 interface0,com.threedr3am.learn.server.boot.DemoService.version.1.0.timeout.3000Z

rpc tcp报文(hex)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
dabb c200 0000 0000 0000 0000 0000 0149
0532 2e30 2e32 302c 636f 6d2e 7468 7265
6564 7233 616d 2e6c 6561 726e 2e73 6572
7665 722e 626f 6f74 2e44 656d 6f53 6572
7669 6365 0331 2e30 0568 656c 6c6f 3024
4c63 6f6d 2f74 6872 6565 6472 3361 6d2f
6c65 6172 6e2f 7365 7276 6572 2f62 6f6f
742f 413b 4330 2263 6f6d 2e74 6872 6565
6472 3361 6d2e 6c65 6172 6e2e 7365 7276
6572 2e62 6f6f 742e 4191 046e 616d 6560
0678 7561 6e79 6848 0470 6174 6830 2c63
6f6d 2e74 6872 6565 6472 3361 6d2e 6c65
6172 6e2e 7365 7276 6572 2e62 6f6f 742e
4465 6d6f 5365 7276 6963 651d 6163 7469
7665 6c69 6d69 745f 6669 6c74 6572 5f73
7461 7274 5f74 696d 650d 3135 3737 3038
3332 3138 3432 3209 696e 7465 7266 6163
6530 2c63 6f6d 2e74 6872 6565 6472 3361
6d2e 6c65 6172 6e2e 7365 7276 6572 2e62
6f6f 742e 4465 6d6f 5365 7276 6963 6507
7665 7273 696f 6e03 312e 3007 7469 6d65
6f75 7404 3330 3030 5a

hessian2序列化

  1. 默认dubbo协议+hessian2序列化方式
  2. 序列化tcp包可随意修改方法参数反序列化的class
  3. 反序列化时先通过构造方法实例化,然后在反射设置字段值
  4. 构造方法的选择,只选择花销最小并且只有基本类型传入的构造方法
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
Constructor[] constructors = cl.getDeclaredConstructors();
long bestCost = Long.MAX_VALUE;

for (int i = 0; i < constructors.length; i++) {
Class[] param = constructors[i].getParameterTypes();
long cost = 0;

for (int j = 0; j < param.length; j++) {
cost = 4 * cost;

if (Object.class.equals(param[j]))
cost += 1;
else if (String.class.equals(param[j]))
cost += 2;
else if (int.class.equals(param[j]))
cost += 3;
else if (long.class.equals(param[j]))
cost += 4;
else if (param[j].isPrimitive())
cost += 5;
else
cost += 6;
}

if (cost < 0 || cost > (1 << 48))
cost = 1 << 48;

cost += (long) param.length << 48;

if (cost < bestCost) {
_constructor = constructors[i];
bestCost = cost;
}
}

if (_constructor != null) {
_constructor.setAccessible(true);
Class[] params = _constructor.getParameterTypes();
_constructorArgs = new Object[params.length];
for (int i = 0; i < params.length; i++) {
_constructorArgs[i] = getParamArg(params[i]);
}
}

总结:想要rce,估计得找到以下条件的exp clain

  1. 有参构造方法
  2. 参数不包含非基本类型
  3. cost最小

例外:

  1. 利用反序列化HashMap,put方法执行时触发hashCode方法,或putVal方法执行时触发equal方法