Skip to content

Commit

Permalink
Merge pull request #648 from bytedance/memshell-main-guoyj
Browse files Browse the repository at this point in the history
1.Resolving the issue of not being able to find the SmithProbeProxy d…
  • Loading branch information
cnguoyj-leminis authored Jul 5, 2024
2 parents 7e4a2af + 1e72834 commit 3e5557c
Show file tree
Hide file tree
Showing 5 changed files with 210 additions and 11 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package com.security.smith;

import com.security.smith.common.SmithTools;
import com.security.smith.log.SmithLogger;

import java.lang.instrument.Instrumentation;

public class SmithAgent {
Expand All @@ -19,6 +19,7 @@ public static void agentmain(String agentArgs, Instrumentation inst) {

System.setProperty("rasp.probe", "smith");

SmithTools.init();
SmithProbe.getInstance().setInst(inst);
SmithProbe.getInstance().init();
SmithProbe.getInstance().start();
Expand Down
85 changes: 83 additions & 2 deletions rasp/jvm/JVMProbe/src/main/java/com/security/smith/SmithProbe.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import com.security.smith.client.message.*;

import com.security.smith.common.SmithHandler;
import com.security.smith.common.SmithTools;
import com.security.smith.log.AttachInfo;
import com.security.smith.log.SmithLogger;
import com.security.smith.module.Patcher;
Expand Down Expand Up @@ -50,6 +51,15 @@
import java.util.stream.Collectors;
import java.util.stream.Stream;

import java.io.File;
import java.io.FileOutputStream;
import java.security.CodeSource;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.jar.JarFile;



public class SmithProbe implements ClassFileTransformer, MessageHandler, EventHandler<Trace> {
private static final SmithProbe ourInstance = new SmithProbe();
Expand Down Expand Up @@ -103,13 +113,32 @@ public void setInst(Instrumentation inst) {
this.inst = inst;
}

private boolean isBypassHookClass(String className) {

if(SmithTools.isGlassfish() && SmithTools.getMajorVersion() > 5) {
/*
* In versions after GlassFish 5 (not including GlassFish 5),
* not hooking java.io.File will cause the JVM process to crash directly if hooked.
*
*/
if(className.equals("java.io.File")) {
return true;
}
}

return false;
}

public void init() {
ObjectMapper objectMapper = new ObjectMapper(new YAMLFactory());
InputStream inputStream = this.getClass().getResourceAsStream("/class.yaml");

try {
for (SmithClass smithClass : objectMapper.readValue(inputStream, SmithClass[].class))
smithClasses.put(smithClass.getName(), smithClass);
for (SmithClass smithClass : objectMapper.readValue(inputStream, SmithClass[].class)) {
if(!isBypassHookClass(smithClass.getName())) {
smithClasses.put(smithClass.getName(), smithClass);
}
}
} catch (IOException e) {
SmithLogger.exception(e);
}
Expand Down Expand Up @@ -161,13 +190,65 @@ private void reloadClasses() {
reloadClasses(smithClasses.keySet());
}


private String getJarPath(Class<?> clazz) {
CodeSource codeSource = clazz.getProtectionDomain().getCodeSource();
if (codeSource != null) {
URL location = codeSource.getLocation();
try {
File file = new File(location.toURI());
return file.getAbsolutePath();
} catch (Exception e) {
SmithLogger.exception(e);
}
}
return null;
}

private String[] addJarclassns = {
"org.apache.felix.framework.BundleWiringImpl$BundleClassLoader"
};

private Set<String> addedJarset = Collections.synchronizedSet(new HashSet<>());

public void checkNeedAddJarPath(Class<?> clazz,Instrumentation inst) {
try {
String cn = clazz.getName();
for (String name : addJarclassns) {
if(cn.equals(name)) {
try {
String jarFile = getJarPath(clazz);
if(jarFile != null && !addedJarset.contains(jarFile)) {
SmithLogger.logger.info("add "+ name + " jarpath:"+jarFile);
inst.appendToSystemClassLoaderSearch(new JarFile(jarFile));
addedJarset.add(jarFile);
}
}catch(Exception e) {
SmithLogger.exception(e);
}
}
}
}
catch(Exception e) {
SmithLogger.exception(e);
}
}

public void checkNeedAddJarPaths(Class<?>[] cls,Instrumentation inst) {
for (Class<?> cx : cls) {
checkNeedAddJarPath(cx,inst);
}
}

private void reloadClasses(Collection<String> classes) {
Class<?>[] loadedClasses = inst.getAllLoadedClasses();
Class<?>[] cls = Arrays.stream(loadedClasses).filter(c -> classes.contains(c.getName())).toArray(Class<?>[]::new);

SmithLogger.logger.info("reload: " + Arrays.toString(cls));
//System.out.println("reload Class:"+cls.getClass().getName());

checkNeedAddJarPaths(cls,inst);

try {
inst.retransformClasses(cls);
} catch (UnmodifiableClassException e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -508,6 +508,20 @@ public void checkMemshellInitPost(int classID, int methodID, Object[] args, Obje

}

private boolean checkIsRaspClass(String classname) {

if (((classname.startsWith("com.security.smith.") ||
classname.startsWith("com.security.smithloader.") ||
classname.startsWith("rasp.io")) ||
classname.startsWith("rasp.org") ||
classname.startsWith("rasp.com") ||
classname.startsWith("rasp.javassist"))) {
return true;
}

return false;
}

/*
* used for wildfly ModuleClassLoader findClass hook
*/
Expand All @@ -516,14 +530,9 @@ public Object processWildflyClassLoaderException(int classID, int methodID, Obj
if(exceptionObject instanceof ClassNotFoundException) {
String classname = (String) args[1];

if (((classname.startsWith("com.security.smith.") ||
classname.startsWith("com.security.smithloader.") ||
classname.startsWith("rasp.io")) ||
classname.startsWith("rasp.org") ||
classname.startsWith("rasp.com") ||
classname.startsWith("rasp.javassist")))

return (Object)Class.forName(classname);
if(checkIsRaspClass(classname)) {
return (Object)Class.forName(classname);
}
}

return null;
Expand Down Expand Up @@ -592,5 +601,22 @@ public void checkWildflyaddFilterPre(int classID, int methodID, Object[] args) {
SmithLogger.exception(e);
}
}

/*
* used for glassfish org.apache.felix.framework.BundleWiringImpl$BundleClassLoader findClass loadClass hook
*/

public Object processGlassfishClassLoaderfindClassException(int classID, int methodID, Object[] args,Object exceptionObject) throws Throwable {
//SmithLogger.logger.info("processGlassfishClassLoaderfindClass Exception_hook call success");
if(exceptionObject instanceof ClassNotFoundException) {
String classname = (String) args[1];
//SmithLogger.logger.info("processGlassfishClassLoaderfindClass find class:"+classname);
if(checkIsRaspClass(classname)) {
return (Object)Class.forName(classname);
}
}

return null;
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package com.security.smith.common;

import com.security.smith.log.SmithLogger;

public class SmithTools {
enum WebMiddlewareType {
WMT_GLASSFISH,
WMT_UNKNOW
};

private static WebMiddlewareType web_mid_type = WebMiddlewareType.WMT_UNKNOW;
private static int major_version = 0;
private static int minor_version = 0;

private static boolean getGlassfishInfo() {
String serverInfo = System.getProperty("glassfish.version");
if(serverInfo != null && !serverInfo.isEmpty()) {
web_mid_type = WebMiddlewareType.WMT_GLASSFISH;

SmithLogger.logger.info("Web Middleware Info:"+serverInfo);

String[] parts = serverInfo.split(" ");
if(parts.length > 0) {

//
// version > 5
//

if(parts[0].equals("Eclipse")) {
if(!parts[1].equals("GlassFish")) {
return false;
}

String[] versionParts = parts[2].split("\\.");

major_version = Integer.parseInt(versionParts[0]);
minor_version = Integer.parseInt(versionParts[1]);

return true;
} else if(parts[0].equals("GlassFish")){
if(parts.length <7) {
return false;
}

String[] versionParts = parts[6].split("\\.");

major_version = Integer.parseInt(versionParts[0]);
minor_version = Integer.parseInt(versionParts[1]);

return true;
}
}
}

return false;
}

public static void init() {
try {
if(getGlassfishInfo()) {
return ;
}
}
catch(Exception e) {
SmithLogger.exception(e);
}
}

public static int getMajorVersion() {
return major_version;
}

public static int getMinorVersion() {
return minor_version;
}

public static boolean isGlassfish() {
return web_mid_type == WebMiddlewareType.WMT_GLASSFISH;
}
}
11 changes: 11 additions & 0 deletions rasp/jvm/JVMProbe/src/main/resources/class.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -374,3 +374,14 @@
name: <init>
desc: ""
postHook: checkMemshellInitPost
- id: 41
name: org.apache.felix.framework.BundleWiringImpl$BundleClassLoader
methods:
- id: 0
name: findClass
desc: (Ljava/lang/String;)Ljava/lang/Class;
exceptionHook: processGlassfishClassLoaderfindClassException
- id: 1
name: loadClass
desc: (Ljava/lang/String;Z)Ljava/lang/Class;
exceptionHook: processGlassfishClassLoaderfindClassException

0 comments on commit 3e5557c

Please sign in to comment.