Skip to content
Merged

dev #117

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
aac5a43
refactor: remove useless code
ReaJason Dec 2, 2025
0799ebf
refactor: use hashset to reduce inject times
ReaJason Dec 2, 2025
5136ccd
feat: support jetty handler shell
ReaJason Dec 2, 2025
63731a3
refactor: simplify fetch context from spring
ReaJason Dec 2, 2025
f7b6917
feat: add scriptEngineBypassModule packer
ReaJason Dec 2, 2025
a447d81
chore: change jetty to undertow
ReaJason Dec 2, 2025
e140753
feat: support jetty customizer shell
ReaJason Dec 2, 2025
123e075
fix: typo
ReaJason Dec 2, 2025
00b63b0
fix(ui): hide urlPatternField for customizer
ReaJason Dec 2, 2025
347dcd1
chore: version 2.3.0-SNAPSHOT
ReaJason Dec 3, 2025
ea08435
fix: bes 9.5.1 agent shell not work
ReaJason Dec 3, 2025
16c2d49
perf: run only once
ReaJason Dec 3, 2025
38ad19c
test: add jdk11 scriptEngine test case
ReaJason Dec 3, 2025
69910ec
feat: support fumadocs
ReaJason Dec 5, 2025
8d5f1af
ci: setup node 22
ReaJason Dec 5, 2025
4c93b8b
test: fix failed cases
ReaJason Dec 5, 2025
98e7601
fix: ui not rendered
ReaJason Dec 5, 2025
78f6098
feat: support appendLambdaSuffix
ReaJason Dec 6, 2025
2b79590
feat: support probe mode
ReaJason Dec 6, 2025
b364212
perf: probe shell only run once
ReaJason Dec 6, 2025
a278e9b
feat: bytecode probe support gzip
ReaJason Dec 6, 2025
373dec0
feat: support jetty ee responseBodyProbe
ReaJason Dec 6, 2025
762b19b
fix: injector msg is empty
ReaJason Dec 6, 2025
cf75b8b
test: fix failed cases
ReaJason Dec 6, 2025
81d9cd1
feat: support GroovyTransformJar packer
ReaJason Dec 6, 2025
6d08608
test: wait for /app
ReaJason Dec 6, 2025
1e649f8
test: simplify payload
ReaJason Dec 6, 2025
b6caa04
fix: container not ready
ReaJason Dec 6, 2025
1a35067
test: add jboss eap-8.1 cases
ReaJason Dec 6, 2025
b429983
feat: support tomcat upgrade
ReaJason Dec 6, 2025
749c978
refactor: use processors
ReaJason Dec 7, 2025
a642639
fix: wrong jetty handler will disrupt service
ReaJason Dec 7, 2025
73cca36
feat: support command template
ReaJason Dec 7, 2025
6bbf275
chore: unify color theme
ReaJason Dec 7, 2025
e5aa232
feat: support command probe template
ReaJason Dec 7, 2025
487c988
feat: support probe paramName optional
ReaJason Dec 7, 2025
bece395
fix: container not ready
ReaJason Dec 7, 2025
50828ee
build: custom base path not work
ReaJason Dec 7, 2025
3e13b51
docs: move folder
ReaJason Dec 7, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
2 changes: 1 addition & 1 deletion .github/scripts/parse_changelog_of_version.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
args = parser.parse_args()
version = args.version

with open("../../CHANGELOG.md") as f:
with open("../../web/content/docs/changelog.mdx") as f:
lines = f.readlines()
for line in lines:
if line.startswith(f"## [{version}]"):
Expand Down
5 changes: 5 additions & 0 deletions .github/workflows/dev-deploy.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ jobs:
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v4

- name: Setup Node
uses: actions/setup-node@v6
with:
node-version: 22

- name: Setup Bun
uses: oven-sh/setup-bun@v2
with:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/memshell-integration-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ jobs:
- middleware: "jbossas"
depend_tasks: ":vul:vul-webapp:war"
- middleware: "jbosseap"
depend_tasks: ":vul:vul-webapp:war"
depend_tasks: ":vul:vul-webapp:war :vul:vul-webapp-jakarta:war"
- middleware: "wildfly"
depend_tasks: ":vul:vul-webapp:war :vul:vul-webapp-jakarta:war"
- middleware: "glassfish"
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/probe-integration-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ jobs:
- middleware: "jbossas"
depend_tasks: ":vul:vul-webapp:war"
- middleware: "jbosseap"
depend_tasks: ":vul:vul-webapp:war"
depend_tasks: ":vul:vul-webapp:war :vul:vul-webapp-jakarta:war"
- middleware: "wildfly"
depend_tasks: ":vul:vul-webapp:war :vul:vul-webapp-jakarta:war"
- middleware: "glassfish"
Expand Down
17 changes: 0 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,23 +78,6 @@ docker run --pull=always --rm -it -d -p 8080:8080 --name memshell-party ghcr.io/
docker run --pull=always --rm -it -d -p 8080:8080 --name memshell-party ghcr.nju.edu.cn/reajason/memshell-party:latest
```

镜像是无状态的,在需要更新最新镜像时,直接移除新建就好了

```bash
# 移除之前部署的
docker rm -f memshell-party

# 使用之前的部署命令重新部署(会自动拉取最新的镜像部署)
docker run --pull=always --rm -it -d -p 8080:8080 --name memshell-party reajason/memshell-party:latest
```

## User Guide

1. [适配情况](./docs/Compatibility.md)
2. [本地构建](./docs/BuildOnLocal.md)
3. [SDK 集成](./examples/memshell-party-maven-example)
4. [代码贡献](./CONTRIBUTING.md)

## Special Thanks

- [vulhub/java-chains](https://github.com/vulhub/java-chains)
Expand Down
2 changes: 1 addition & 1 deletion boot/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ dependencies {
exclude(group = "org.springframework.boot", module = "spring-boot-starter-tomcat")
}
implementation(libs.commons.lang3)
implementation("org.springframework.boot:spring-boot-starter-jetty")
implementation("org.springframework.boot:spring-boot-starter-undertow")
compileOnly("org.projectlombok:lombok")
developmentOnly("org.springframework.boot:spring-boot-devtools")
annotationProcessor("org.springframework.boot:spring-boot-configuration-processor")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
@CrossOrigin("*")
public class ClassNameParseController {

@PostMapping("/className")
@PostMapping("/api/className")
public String className(@RequestBody String classBase64) {
return ClassNameReader.getClassName(new ClassReader(Base64.getDecoder().decode(classBase64)));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
* @since 2024/12/13
*/
@RestController
@RequestMapping("/config")
@RequestMapping("/api/config")
@CrossOrigin("*")
public class ConfigController {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
* @since 2024/12/18
*/
@RestController
@RequestMapping("/memshell/generate")
@RequestMapping("/api/memshell/generate")
@CrossOrigin("*")
public class MemShellGeneratorController {
@PostMapping
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
* @since 2025/8/10
*/
@RestController
@RequestMapping("/probe/generate")
@RequestMapping("/api/probe/generate")
@CrossOrigin("*")
public class ProbeShellGeneratorController {
@PostMapping
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
*/
@RestController
@CrossOrigin("*")
@RequestMapping("/version")
@RequestMapping("/api/version")
public class VersionController {

@Value("${spring.application.version}")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,76 @@
package com.reajason.javaweb.boot.controller;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.ClassPathResource;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;

/**
* @author ReaJason
* @since 2024/12/19
*/
@Controller
@Slf4j
public class ViewController {
@GetMapping("/")
public String index(){
return "index";
return "redirect:/ui";
}

@GetMapping({"/api/search", "/api/search.data"})
@ResponseBody
public String handleSearch(HttpServletRequest request, HttpServletResponse response) {
String fullPath = request.getRequestURI().replace(request.getContextPath(), "");
String relativePath = fullPath.substring(1);
return renderFileData(relativePath, response);
}

@GetMapping({"/ui/docs/*.data", "/ui/*.data"})
@ResponseBody
public String handleDataFile(HttpServletRequest request, HttpServletResponse response) throws IOException {
String fullPath = request.getRequestURI().replace(request.getContextPath(), "");
String relativePath = fullPath.substring(4);
return renderFileData(relativePath, response);
}


@GetMapping("/ui/**")
public String handleHtmlView(HttpServletRequest request) {
String fullPath = request.getRequestURI().replace(request.getContextPath(), "");
if ("/ui".equals(fullPath) || "/ui/".equals(fullPath)) {
return "index";
}
String viewPath = fullPath.substring(4);
return viewPath + "/index";
}

private String renderFileData(String relativePath, HttpServletResponse response) {
try {
String templatePath = "templates/" + relativePath;
ClassPathResource resource = new ClassPathResource(templatePath);
if (!resource.exists()) {
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
return "File not found: " + relativePath;
}
response.setContentType(MediaType.TEXT_PLAIN_VALUE);
response.setCharacterEncoding("UTF-8");
InputStreamReader reader = new InputStreamReader(
resource.getInputStream(),
StandardCharsets.UTF_8
);
return FileCopyUtils.copyToString(reader);
} catch (IOException e) {
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
return "Error reading file: " + e.getMessage();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ public static class ShellToolConfigDTO {
private String godzillaPass;
private String godzillaKey;
private String commandParamName;
private String commandTemplate;
private String behinderPass;
private String antSwordPass;
private String headerName;
Expand Down Expand Up @@ -50,6 +51,7 @@ public ShellToolConfig parseShellToolConfig() {
case Command -> CommandConfig.builder()
.shellClassName(shellToolConfig.getShellClassName())
.paramName(shellToolConfig.getCommandParamName())
.template(shellToolConfig.getCommandTemplate())
.encryptor(CommandConfig.Encryptor.fromString(shellToolConfig.getEncryptor()))
.implementationClass(CommandConfig.ImplementationClass.fromString(shellToolConfig.getImplementationClass()))
.build();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ static class ProbeContentConfigDTO {
private String server;
private String sleepServer;
private String reqParamName;
private String commandTemplate;
}

public ProbeContentConfig parseProbeContentConfig() {
Expand All @@ -34,6 +35,7 @@ public ProbeContentConfig parseProbeContentConfig() {
.build();
case ResponseBody -> ResponseBodyConfig.builder()
.reqParamName(probeContentConfig.reqParamName)
.commandTemplate(probeContentConfig.commandTemplate)
.server(probeContentConfig.server)
.build();
default -> throw new UnsupportedOperationException("unknown probe method: " + probeConfig.getProbeMethod());
Expand Down
5 changes: 4 additions & 1 deletion boot/src/main/resources/application.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
spring:
application:
name: boot
version: ${version}
version: ${version}
mvc:
pathmatch:
matching-strategy: ant_path_matcher
Original file line number Diff line number Diff line change
Expand Up @@ -26,21 +26,21 @@ public class ConfigControllerIntegrationTest {

@Test
public void testConfigEndpoint() {
ResponseEntity<Map> response = restTemplate.getForEntity("/config", Map.class);
ResponseEntity<Map> response = restTemplate.getForEntity("/api/config", Map.class);
assertEquals(HttpStatus.OK, response.getStatusCode());
assertNotNull(response.getBody());
}

@Test
public void testConfigServersEndpoint() {
ResponseEntity<Map> response = restTemplate.getForEntity("/config/servers", Map.class);
ResponseEntity<Map> response = restTemplate.getForEntity("/api/config/servers", Map.class);
assertEquals(HttpStatus.OK, response.getStatusCode());
assertNotNull(response.getBody());
}

@Test
public void testConfigPackersEndpoint() {
ResponseEntity<List> response = restTemplate.getForEntity("/config/packers", List.class);
ResponseEntity<List> response = restTemplate.getForEntity("/api/config/packers", List.class);
assertEquals(HttpStatus.OK, response.getStatusCode());
assertNotNull(response.getBody());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ void generateShell() {
shellToolConfigDTO.setHeaderValue("hello");
request.setShellToolConfig(shellToolConfigDTO);
ResponseEntity<MemShellGenerateResponse> response = restTemplate.postForEntity(
"/memshell/generate", request, MemShellGenerateResponse.class);
"/api/memshell/generate", request, MemShellGenerateResponse.class);
assertEquals(HttpStatus.OK, response.getStatusCode());
assertNotNull(response.getBody());
}
Expand Down
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ idea {
}
}

version = "2.2.0"
version = "2.3.0-SNAPSHOT"

tasks.register("publishAllToMavenCentral") {
dependsOn(":memshell-party-common:publishToMavenCentral")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,13 @@
import com.reajason.javaweb.memshell.config.ShellToolConfig;
import com.reajason.javaweb.memshell.generator.InjectorGenerator;
import com.reajason.javaweb.memshell.server.AbstractServer;
import com.reajason.javaweb.probe.ProbeContent;
import com.reajason.javaweb.probe.ProbeMethod;
import com.reajason.javaweb.probe.config.ProbeConfig;
import com.reajason.javaweb.probe.config.ResponseBodyConfig;
import com.reajason.javaweb.probe.generator.response.ResponseBodyGenerator;
import com.reajason.javaweb.utils.CommonUtil;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;

Expand Down Expand Up @@ -46,6 +52,11 @@ public static MemShellResult generate(ShellConfig shellConfig, InjectorConfig in
injectorConfig.setInjectorClassName(CommonUtil.generateInjectorClassName());
}

if (shellConfig.isLambdaSuffix()) {
shellToolConfig.setShellClassName(CommonUtil.appendLambdaSuffix(shellToolConfig.getShellClassName()));
injectorConfig.setInjectorClassName(CommonUtil.appendLambdaSuffix(injectorConfig.getInjectorClassName()));
}

byte[] shellBytes = ShellToolFactory.generateBytes(shellConfig, shellToolConfig);

injectorConfig.setInjectorClass(injectorClass);
Expand All @@ -54,6 +65,25 @@ public static MemShellResult generate(ShellConfig shellConfig, InjectorConfig in

InjectorGenerator injectorGenerator = new InjectorGenerator(shellConfig, injectorConfig);
byte[] injectorBytes = injectorGenerator.generate();
if (shellConfig.isProbe() && !shellConfig.getShellType().startsWith(ShellType.AGENT)) {
ProbeConfig probeConfig = ProbeConfig.builder()
.shellClassName(injectorConfig.getInjectorClassName() + "1")
.probeMethod(ProbeMethod.ResponseBody)
.probeContent(ProbeContent.Bytecode)
.targetJreVersion(shellConfig.getTargetJreVersion())
.byPassJavaModule(shellConfig.isByPassJavaModule())
.shrink(shellConfig.isShrink())
.debug(shellConfig.isDebug())
.staticInitialize(injectorConfig.isStaticInitialize())
.build();
ResponseBodyConfig responseBodyConfig = ResponseBodyConfig.builder()
.server(serverName)
.base64Bytes(Base64.encodeBase64String(CommonUtil.gzipCompress(injectorBytes)))
.build();
injectorBytes = new ResponseBodyGenerator(probeConfig, responseBodyConfig).getBytes();
injectorConfig.setInjectorClassName(probeConfig.getShellClassName());
}

Map<String, byte[]> innerClassBytes = injectorGenerator.getInnerClassBytes();

return MemShellResult.builder()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,10 @@ public class ServerFactory {
.addShellClass(NETTY_HANDLER, GodzillaNettyHandler.class)
.addShellClass(AGENT_FILTER_CHAIN, Godzilla.class)
.addShellClass(CATALINA_AGENT_CONTEXT_VALVE, Godzilla.class)
.addShellClass(JETTY_AGENT_HANDLER, GodzillaJettyHandler.class)
.addShellClass(HANDLER, GodzillaJettyHandler.class)
.addShellClass(JAKARTA_HANDLER, GodzillaJettyHandler.class)
.addShellClass(CUSTOMIZER, GodzillaJettyCustomizer.class)
.addShellClass(JETTY_AGENT_HANDLER, GodzillaJettyAgentHandler.class)
.addShellClass(UNDERTOW_AGENT_SERVLET_HANDLER, GodzillaUndertowServletHandler.class)
.addShellClass(WEBLOGIC_AGENT_SERVLET_CONTEXT, Godzilla.class)
.addShellClass(WAS_AGENT_FILTER_MANAGER, Godzilla.class)
Expand Down Expand Up @@ -129,6 +132,7 @@ public class ServerFactory {
.addShellClass(JAKARTA_PROXY_VALVE, Command.class)
.addShellClass(WEBSOCKET, CommandWebSocket.class)
.addShellClass(JAKARTA_WEBSOCKET, CommandWebSocket.class)
.addShellClass(UPGRADE, CommandUpgrade.class)
.addShellClass(SPRING_WEBMVC_INTERCEPTOR, CommandInterceptor.class)
.addShellClass(SPRING_WEBMVC_JAKARTA_INTERCEPTOR, CommandInterceptor.class)
.addShellClass(SPRING_WEBMVC_CONTROLLER_HANDLER, CommandControllerHandler.class)
Expand All @@ -140,7 +144,10 @@ public class ServerFactory {
.addShellClass(NETTY_HANDLER, CommandNettyHandler.class)
.addShellClass(AGENT_FILTER_CHAIN, Command.class)
.addShellClass(CATALINA_AGENT_CONTEXT_VALVE, Command.class)
.addShellClass(JETTY_AGENT_HANDLER, CommandJettyHandler.class)
.addShellClass(JETTY_AGENT_HANDLER, CommandJettyAgentHandler.class)
.addShellClass(HANDLER, CommandJettyHandler.class)
.addShellClass(CUSTOMIZER, CommandJettyCustomizer.class)
.addShellClass(JAKARTA_HANDLER, CommandJettyHandler.class)
.addShellClass(UNDERTOW_AGENT_SERVLET_HANDLER, CommandUndertowServletHandler.class)
.addShellClass(WEBLOGIC_AGENT_SERVLET_CONTEXT, Command.class)
.addShellClass(WAS_AGENT_FILTER_MANAGER, Command.class)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,22 @@ public class ShellType {
public static final String JAKARTA_LISTENER = JAKARTA + LISTENER;

public static final String VALVE = "Valve";
public static final String UPGRADE = "Upgrade";
public static final String JAKARTA_VALVE = JAKARTA + VALVE;
public static final String PROXY_VALVE = "Proxy" + VALVE;
public static final String JAKARTA_PROXY_VALVE = JAKARTA + PROXY_VALVE;

public static final String HANDLER = "Handler";
public static final String JAKARTA_HANDLER = JAKARTA + HANDLER;
public static final String CUSTOMIZER = "Customizer";

public static final String NETTY_HANDLER = "NettyHandler";

public static final String AGENT = "Agent";

public static final String AGENT_FILTER_CHAIN = AGENT + "FilterChain";
public static final String CATALINA_AGENT_CONTEXT_VALVE = AGENT + "ContextValve";
public static final String JETTY_AGENT_HANDLER = AGENT + "Handler";
public static final String JETTY_AGENT_HANDLER = AGENT + HANDLER;
public static final String UNDERTOW_AGENT_SERVLET_HANDLER = AGENT + "ServletHandler";
public static final String WAS_AGENT_FILTER_MANAGER = AGENT + "FilterManager";
public static final String WEBLOGIC_AGENT_SERVLET_CONTEXT = AGENT + "ServletContext";
Expand Down
Loading