diff --git a/rasp/jvm/JVMProbe/src/main/java/com/security/smith/SmithProbe.java b/rasp/jvm/JVMProbe/src/main/java/com/security/smith/SmithProbe.java index 735a0f405..bd37cee32 100644 --- a/rasp/jvm/JVMProbe/src/main/java/com/security/smith/SmithProbe.java +++ b/rasp/jvm/JVMProbe/src/main/java/com/security/smith/SmithProbe.java @@ -151,8 +151,7 @@ public void start() { SmithLogger.logger.info("init ClassUploadTransformer"); ClassUploadTransformer.getInstance().start(client, inst); - inst.addTransformer(this, true); - reloadClasses(); + Thread clientThread = new Thread(client::start); @@ -172,6 +171,10 @@ public void run() { TimeUnit.MINUTES.toMillis(1) ); smithProxy = SmithProbeProxy.getInstance(); + SmithProbeProxy.getInstance().setReflectField(); + SmithProbeProxy.getInstance().setClient(client); + SmithProbeProxy.getInstance().setDisruptor(disruptor); + SmithProbeProxy.getInstance().setReflectMethod(); new Timer(true).schedule( new TimerTask() { @Override @@ -182,8 +185,8 @@ public void run() { 0, TimeUnit.MINUTES.toMillis(1) ); - SmithProbeProxy.getInstance().setClient(client); - SmithProbeProxy.getInstance().setDisruptor(disruptor); + inst.addTransformer(this, true); + reloadClasses(); } private void reloadClasses() { @@ -751,6 +754,7 @@ public void onScanAllClass() { } classFilter.setTransId(); classFilter.setRuleId(rule_id); + classFilter.setHashCode(clazz.hashCode()); classFilter.setStackTrace(Thread.currentThread().getStackTrace()); client.write(Operate.SCANCLASS, classFilter); diff --git a/rasp/jvm/JVMProbe/src/main/java/com/security/smith/SmithProbeProxy.java b/rasp/jvm/JVMProbe/src/main/java/com/security/smith/SmithProbeProxy.java index 95d46f2a1..cf9c65e25 100644 --- a/rasp/jvm/JVMProbe/src/main/java/com/security/smith/SmithProbeProxy.java +++ b/rasp/jvm/JVMProbe/src/main/java/com/security/smith/SmithProbeProxy.java @@ -1,6 +1,7 @@ package com.security.smith; import java.util.Arrays; +import java.util.HashMap; import java.util.Map; import java.util.Objects; import java.util.concurrent.atomic.AtomicIntegerArray; @@ -25,13 +26,15 @@ public class SmithProbeProxy { private static final SmithProbeProxy ourInstance = new SmithProbeProxy(); - private static final int CLASS_MAX_ID = 30; + private static final int CLASS_MAX_ID = 50; private static final int METHOD_MAX_ID = 20; private static final int DEFAULT_QUOTA = 12000; private final AtomicIntegerArray[] quotas; private Disruptor disruptor; private Client client; + private Map reflectField = new HashMap<>(); + private Map reflectMethod = new HashMap<>(); public static InheritableThreadLocal localfilterConfig = new InheritableThreadLocal() { @Override @@ -77,6 +80,112 @@ public void setDisruptor(Disruptor disruptor) { this.disruptor = disruptor; } + public void setReflectField() { + String[] values1 = {"theUnsafe", "unsafe", "fieldFilterMap", "methodFilterMap"}; + String[] values2 = {"launchMechanism"}; + String[] values3 = {"handlerMap", "adaptedInterceptors"}; + String[] values4 = {"context"}; + String[] values5 = {"delegate"}; + String[] values6 = {"handlerAdapters", "handlerMappings"}; + String[] values7 = {"chain"}; + String[] values8 = {"httpUpgradeProtocols"}; + String[] values9 = {"executor"}; + String[] values10 = {"connector"}; + + reflectField.put("*", values1); + reflectField.put("java.lang.UNIXProcess", values2); + reflectField.put("java.lang.ProcessImpl", values2); + reflectField.put("org.springframework.web.servlet.handler.AbstractUrlHandlerMapping", values3); + reflectField.put("org.apache.catalina.core.ApplicationContext", values4); + reflectField.put("org.springframework.context.ApplicationListener", values5); + reflectField.put("org.springframework.web.servlet.DispatcherServlet", values6); + reflectField.put("org.springframework.web.server.handler.FilteringWebHandler", values7); + reflectField.put("org.apache.coyote.http11.AbstractHttp11Protocol", values8); + reflectField.put("org.apache.tomcat.util.net.AbstractEndpoint", values9); + reflectField.put("org.apache.catalina.connector.CoyoteAdapter", values10); + } + + public void setReflectMethod() { + + String[] values1 = {"*"}; + String[] values2 = {"load"}; + String[] values3 = {"forkAndExec"}; + String[] values4 = {"create"}; + String[] values5 = {"defineClass"}; + reflectMethod.put("java.lang.Unsafe", values1); + reflectMethod.put("java.lang.ClassLoader$NativeLibrary", values2); + reflectMethod.put("java.lang.UNIXProcess", values3); + reflectMethod.put("java.lang.ProcessImpl", values4); + reflectMethod.put("java.lang.ClassLoader", values5); + } + + public Map getReflectMethod() { + return this.reflectMethod; + } + + public Map getReflectField() { + return this.reflectField; + } + + public boolean checkReflectFeildEvil(String classname, String fieldname) { + if (classname == null || fieldname == null) { + return false; + } + Map refieldMap = getReflectField(); + if (refieldMap == null) { + return false; + } + if (refieldMap.containsKey(classname)) { + String[] values = refieldMap.get(classname); + for (String value : values) { + if (value.equals(fieldname) || value.equals("*")) { + return true; + } + } + } else { + String[] values = refieldMap.get("*"); + if (values == null) { + return false; + } + for (String value : values) { + if (value.equals(fieldname) || value.equals("*")) { + return true; + } + } + } + return false; + } + + + public boolean checkReflectMethodEvil(String classname, String methodname) { + if (classname == null || methodname == null) { + return false; + } + Map refieldMap = getReflectMethod(); + if (refieldMap == null) { + return false; + } + if (refieldMap.containsKey(classname)) { + String[] values = refieldMap.get(classname); + for (String value : values) { + if (value.equals(methodname) || value.equals("*")) { + return true; + } + } + } else { + String[] values = refieldMap.get("*"); + if (values == null) { + return false; + } + for (String value : values) { + if (value.equals(methodname) || value.equals("*")) { + return true; + } + } + } + return false; + } + public void detect(int classID, int methodID, Object[] args) { Map, Block> blocks = SmithProbe.getInstance().GetBlocks(); if (blocks == null) @@ -156,6 +265,7 @@ public void sendMetadataClass(Class cla) { SmithHandler.queryClassFilter(cla, classFilter); classFilter.setTransId(); classFilter.setRuleId(-1); + classFilter.setHashCode(cla.hashCode()); classFilter.setStackTrace(Thread.currentThread().getStackTrace()); if (client != null) { client.write(Operate.SCANCLASS, classFilter); @@ -602,6 +712,45 @@ public void checkWildflyaddFilterPre(int classID, int methodID, Object[] args) { } } + public void handleReflectField(int classID, int methodID, Object[] args, Object ret, boolean blocked) { + if (args.length < 2) { + return ; + } + try { + Class clas = (Class)args[0]; + String reflectClass = clas.getName(); + String feild = (String)args[1]; + if (reflectClass.startsWith("com.security.smith") || reflectClass.startsWith("rasp.")) { + return ; + } else { + if (checkReflectFeildEvil(reflectClass, feild)) { + trace(classID, methodID, args, ret, blocked); + } + } + } catch (Throwable e) { + SmithLogger.exception(e); + } + } + + public void handleReflectMethod(int classID, int methodID, Object[] args, Object ret, boolean blocked) { + if (args.length < 2) { + return ; + } + try { + Class clas = (Class)args[0]; + String reflectClass = clas.getName(); + String feild = (String)args[1]; + if (reflectClass.startsWith("com.security.smith") || reflectClass.startsWith("rasp.")) { + return ; + } else { + if (checkReflectMethodEvil(reflectClass, feild)) { + trace(classID, methodID, args, ret, blocked); + } + } + } catch (Throwable e) { + SmithLogger.exception(e); + } + /* * used for glassfish org.apache.felix.framework.BundleWiringImpl$BundleClassLoader findClass loadClass hook */ diff --git a/rasp/jvm/JVMProbe/src/main/java/com/security/smith/client/message/ClassFilter.java b/rasp/jvm/JVMProbe/src/main/java/com/security/smith/client/message/ClassFilter.java index d74f917ce..2516e3953 100644 --- a/rasp/jvm/JVMProbe/src/main/java/com/security/smith/client/message/ClassFilter.java +++ b/rasp/jvm/JVMProbe/src/main/java/com/security/smith/client/message/ClassFilter.java @@ -16,6 +16,7 @@ public class ClassFilter { private String parentClassName = ""; private String parentClassLoaderName = ""; private long ruleId; + private int hashCode; @JsonSerialize(converter = StackTraceConverter.class) private StackTraceElement[] stackTrace = {}; @@ -84,6 +85,14 @@ public void setRuleId(long ruleId) { this.ruleId = ruleId; } + public int getHashCode() { + return hashCode; + } + + public void setHashCode(int hashCode) { + this.hashCode = hashCode; + } + public StackTraceElement[] getStackTrace() { return stackTrace; } @@ -101,6 +110,7 @@ public String toString() { ", classLoaderName: '" + classLoaderName + '\'' + ", parentClassName: '" + parentClassName + '\'' + ", parentClassLoaderName: '" + parentClassLoaderName + '\'' + + ", hashCode: '" + hashCode + '\'' + ", ruleId: " + ruleId + ", timestamp: " + Instant.now().getEpochSecond() + '}'; diff --git a/rasp/jvm/JVMProbe/src/main/resources/class.yaml b/rasp/jvm/JVMProbe/src/main/resources/class.yaml index 78cf1ecc0..671879c32 100644 --- a/rasp/jvm/JVMProbe/src/main/resources/class.yaml +++ b/rasp/jvm/JVMProbe/src/main/resources/class.yaml @@ -385,3 +385,17 @@ name: loadClass desc: (Ljava/lang/String;Z)Ljava/lang/Class; exceptionHook: processGlassfishClassLoaderfindClassException +- id: 42 + name: java.lang.reflect.Field + methods: + - id: 0 + name: + desc: "" + postHook: handleReflectField +- id: 43 + name: java.lang.reflect.Method + methods: + - id: 0 + name: + desc: "" + postHook: handleReflectMethod