Skip to content

Commit 1364185

Browse files
committed
feat memshell init hook
1 parent 597a0a0 commit 1364185

File tree

6 files changed

+169
-17
lines changed

6 files changed

+169
-17
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,3 +41,5 @@ Cargo.lock
4141
*CMakeFiles*
4242
*vcpkg_installed
4343
*node_modules
44+
*.output/
45+
build

rasp/jvm/JVMProbe/build.gradle

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ repositories {
1212

1313
dependencies {
1414
testImplementation group: 'junit', name: 'junit', version: '4.13.1'
15-
implementation group: 'org.ow2.asm', name: 'asm-tree', version: '9.3'
16-
implementation group: 'org.ow2.asm', name: 'asm-commons', version: '9.3'
15+
implementation group: 'org.ow2.asm', name: 'asm-tree', version: '9.6'
16+
implementation group: 'org.ow2.asm', name: 'asm-commons', version: '9.6'
1717
implementation group: 'io.netty', name: 'netty-all', version: '4.1.85.Final'
1818
implementation group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.14.0'
1919
implementation group: 'com.fasterxml.jackson.dataformat', name: 'jackson-dataformat-yaml', version: '2.14.0'

rasp/jvm/JVMProbe/src/main/java/com/security/smith/SmithProbe.java

Lines changed: 53 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ public void onEvent(Trace trace, long sequence, boolean endOfBatch) {
181181
Predicate<MatchRule> pred = rule -> {
182182
Object[] args = trace.getArgs();
183183

184-
if (rule.getIndex() >= args.length)
184+
if (rule.getIndex() >= args.length || rule.getRegex().isEmpty() || args[rule.getIndex()] == null)
185185
return false;
186186

187187
return Pattern.compile(rule.getRegex()).matcher(args[rule.getIndex()].toString()).find();
@@ -341,6 +341,27 @@ boolean hasExceptionHook(Map<String, SmithMethod> methodMap) {
341341
return false;
342342
}
343343

344+
public boolean checkInterfaceNeedTran(String interfaceName) {
345+
if (interfaceName == null) {
346+
return false;
347+
}
348+
boolean ret = false;
349+
switch (interfaceName) {
350+
case "org/springframework/web/servlet/HandlerInterceptor":
351+
case "javax/servlet/Servlet":
352+
case "javax/servlet/Filter":
353+
case "javax/servlet/ServletRequestListener":
354+
case "jakarta/servlet/Servlet":
355+
case "jakarta/servlet/Filter":
356+
case "jakarta/servlet/ServletRequestListener":
357+
case "javax/websocket/Endpoint":
358+
ret = true;
359+
break;
360+
default:
361+
break;
362+
}
363+
return ret;
364+
}
344365
@Override
345366
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) {
346367
if (disable)
@@ -349,18 +370,41 @@ public byte[] transform(ClassLoader loader, String className, Class<?> classBein
349370
// if(scanswitch) {
350371
// checkClassFilter(loader, className,classfileBuffer);
351372
// }
352-
353-
Type classType = Type.getObjectType(className);
354-
SmithClass smithClass = smithClasses.get(classType.getClassName());
355373

356-
if (smithClass == null)
357-
return null;
374+
Type classType = null;
375+
SmithClass smithClass = null;
376+
try {
377+
classType = Type.getObjectType(className);
378+
smithClass = smithClasses.get(classType.getClassName());
379+
} catch (Exception e) {
380+
//SmithLogger.exception(e);
381+
}
382+
383+
if (smithClass == null && className == null) {
384+
385+
ClassReader cr = new ClassReader(classfileBuffer);
386+
String[] interfaces = cr.getInterfaces();
387+
if (className == null) {
388+
className = cr.getClassName();
389+
classType = Type.getObjectType(className);
390+
}
358391

359-
SmithLogger.logger.info("transform: " + classType.getClassName());
392+
for (String interName : interfaces) {
393+
if (checkInterfaceNeedTran(interName)) {
394+
Type interfaceType = Type.getObjectType(interName);
395+
smithClass = smithClasses.get(interfaceType.getClassName());
396+
break;
397+
}
398+
}
399+
if (smithClass == null) {
400+
return null;
401+
}
402+
}
360403

361404
try {
362405
Map<String, SmithMethod> methodMap = smithClass.getMethods().stream().collect(Collectors.toMap(method -> method.getName() + method.getDesc(), method -> method));
363406

407+
SmithLogger.logger.info("transform: " + classType.getClassName());
364408
ClassReader classReader = new ClassReader(classfileBuffer);
365409

366410
ClassWriter classWriter;
@@ -372,14 +416,14 @@ public byte[] transform(ClassLoader loader, String className, Class<?> classBein
372416
}
373417

374418
ClassVisitor classVisitor = new SmithClassVisitor(
375-
Opcodes.ASM8,
419+
Opcodes.ASM9,
376420
classWriter,
377421
smithClass.getId(),
378422
classType,
379423
methodMap
380424
);
381425

382-
classReader.accept(classVisitor, ClassReader.EXPAND_FRAMES);
426+
classReader.accept(classVisitor, ClassReader.EXPAND_FRAMES);
383427
return classWriter.toByteArray();
384428
} catch (Exception e) {
385429
SmithLogger.exception(e);

rasp/jvm/JVMProbe/src/main/java/com/security/smith/SmithProbeProxy.java

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -423,4 +423,46 @@ public void checkJettyDeployPost(int classID, int methodID, Object[] args, Objec
423423
jettyDeploying.set(false);
424424
}
425425
}
426+
427+
/*
428+
* check spring controller memshell
429+
*/
430+
public void checkSpringControllerPre(int classID, int methodID, Object[] args) {
431+
if (args.length < 3) {
432+
return;
433+
}
434+
try {
435+
Object controller = args[2];
436+
sendMetadataObject(controller);
437+
} catch (Exception e) {
438+
SmithLogger.exception(e);
439+
}
440+
}
441+
442+
/*
443+
* check spring Interceptor memshell
444+
*/
445+
public void checkSpringInterceptorPre(int classID, int methodID, Object[] args) {
446+
if (args.length < 1) {
447+
return;
448+
}
449+
try {
450+
Object interceptor = args[0];
451+
sendMetadataObject(interceptor);
452+
} catch (Exception e) {
453+
SmithLogger.exception(e);
454+
}
455+
}
456+
457+
public void checkMemshellInitPost(int classID, int methodID, Object[] args, Object ret, boolean blocked) {
458+
//SmithLogger.logger.info("checkMemshellInitPost call success");
459+
if (ret != null) {
460+
try {
461+
sendMetadataObject(ret);
462+
} catch (Exception e) {
463+
SmithLogger.exception(e);
464+
}
465+
}
466+
467+
}
426468
}

rasp/jvm/JVMProbe/src/main/java/com/security/smith/common/SmithHandler.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,9 @@ private static boolean checkServletInterface(Class<?> clazz) {
217217
|| clsName.endsWith(".ServletRequestListener")) {
218218
return true;
219219
}
220-
}
220+
} else if (clsName.equals("org.springframework.web.servlet.HandlerInterceptor")) {
221+
return true;
222+
}
221223
}
222224
}
223225
}

rasp/jvm/JVMProbe/src/main/resources/class.yaml

Lines changed: 67 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -250,10 +250,72 @@
250250
desc: (Ljava/util/EventListener;)V
251251
preHook: checkJettyListenerPre
252252
- id: 23
253-
name: org.eclipse.jetty.deploy.bindings.StandardDeployer
253+
name: org.springframework.web.servlet.handler.AbstractUrlHandlerMapping
254254
methods:
255255
- id: 0
256-
name: processBinding
257-
desc: (Lorg/eclipse/jetty/deploy/graph/Node;Lorg/eclipse/jetty/deploy/App;)V
258-
preHook: checkJettyDeployPre
259-
postHook: checkJettyDeployPost
256+
name: registerHandler
257+
desc: (Ljava/lang/String;Ljava/lang/Object;)V
258+
preHook: checkSpringControllerPre
259+
- id: 24
260+
name: org.springframework.web.servlet.handler.AbstractHandlerMethodMapping$MappingRegistry
261+
methods:
262+
- id: 0
263+
name: register
264+
desc: (Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/reflect/Method;)V
265+
preHook: checkSpringControllerPre
266+
- id: 25
267+
name: org.springframework.web.servlet.HandlerInterceptor
268+
methods:
269+
- id: 0
270+
name: <init>
271+
desc: ()V
272+
postHook: checkMemshellInitPost
273+
- id: 26
274+
name: javax.servlet.Filter
275+
methods:
276+
- id: 0
277+
name: <init>
278+
desc: ()V
279+
postHook: checkMemshellInitPost
280+
- id: 27
281+
name: javax.servlet.Servlet
282+
methods:
283+
- id: 0
284+
name: <init>
285+
desc: ()V
286+
postHook: checkMemshellInitPost
287+
- id: 28
288+
name: javax.servlet.ServletRequestListener
289+
methods:
290+
- id: 0
291+
name: <init>
292+
desc: ()V
293+
postHook: checkMemshellInitPost
294+
- id: 29
295+
name: javax.websocket.Endpoint
296+
methods:
297+
- id: 0
298+
name: <init>
299+
desc: ()V
300+
postHook: checkMemshellInitPost
301+
- id: 30
302+
name: jakarta.servlet.Filter
303+
methods:
304+
- id: 0
305+
name: <init>
306+
desc: ()V
307+
postHook: checkMemshellInitPost
308+
- id: 31
309+
name: jakarta.servlet.Servlet
310+
methods:
311+
- id: 0
312+
name: <init>
313+
desc: ()V
314+
postHook: checkMemshellInitPost
315+
- id: 32
316+
name: jakarta.servlet.ServletRequestListener
317+
methods:
318+
- id: 0
319+
name: <init>
320+
desc: ()V
321+
postHook: checkMemshellInitPost

0 commit comments

Comments
 (0)