Security Forem

7mo
7mo

Posted on

Race to the Bottom: Weaponizing Concurrency , PART 1 . #THREADING

btw im learning while creating this blog so if there is any mistake please tell me, and i will fix it and learn , THANKS !

HI i like to dive into things immediately so take a look at this code sample here :

CHAPTER 1 : THREADS ?

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>

#define PORT 8080

void handle_request(int client_socket) {
    char response[2048];

    strcpy(response, "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n");
    strcat(response, "<html><body><h1>Hi</h1>");
    write(client_socket, response, strlen(response));

    sleep(3);

    memset(response, 0, sizeof(response));  
    strcat(response, "<h1>Hi again!</h1></body></html>");
    write(client_socket, response, strlen(response));

    close(client_socket);
}

/*-------------------------------------------------------------------------------------------*/

int main() {
    int server_socket, client_socket;
    struct sockaddr_in server_addr, client_addr;
    socklen_t client_len = sizeof(client_addr);

    server_socket = socket(AF_INET, SOCK_STREAM, 0);
    if (server_socket < 0) {
        perror("Error creating socket");
        exit(1);
    }

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

    if (bind(server_socket, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
        perror("Error binding");
        exit(1);
    }

    if (listen(server_socket, 5) < 0) {
        perror("Error listening");
        exit(1);
    }

    printf("Server listening on port %d...\n", PORT);

    while (1) {
        client_socket = accept(server_socket, (struct sockaddr *)&client_addr, &client_len);
        if (client_socket < 0) {
            perror("Error accepting connection");
            continue;
        }

        handle_request(client_socket);
    }

    close(server_socket);
    return 0;
}

Enter fullscreen mode Exit fullscreen mode
  1. in the handle function ,
  2. it has a response buffer that holds 2048 bytes ,
  3. then it copies 200 ok and Content type into the response array after that it adds a message that says HI in the web page then writes it .
  4. sleep 3 means wait 3 seconds and then show me another message that simply says hi again after that it closes the connection .

--- # ---
What could go wrong? The main issue with this code is that it is not threaded. This means the server processes each request sequentially — it handles one request at a time. The server blocks on each request, meaning it cannot process a new request until the current one is fully completed. As a result, the server essentially "locks itself up" while waiting for each request to finish. This approach becomes very inefficient, especially under heavy load, leading to poor performance when multiple clients try to connect at the same time. This is slow!

and also can be exploited to cause a DOS and brick the server ? how lets get into it !

CHAPTER 2 :CAUSING THE DOS

AFTER compiling the code as you can go to :
**

http://127.0.0.1:8080

**

1

yeah its working cool !
but as you saw when you went it takes 3 seconds then prints hello again but the real question is how can we see the no thread thing ?
open multiple tabs instances of the web app on the left and one on the right click them all and as you see the one on the right doesnt only take 3 seconds it takes much more time ?
why ? ?? ?????
welp simply because the server waits up until it process each one of them then goes to the last requested one

if your too into it you can debug and see how does it like pause like wait until it process the first one

but no need running man accept tells you that

The accept() system call is used with connection-based socket types (SOCK_STREAM, SOCK_SEQPACKET). It extracts the
first connection request on the queue of pending connections for the listening socket

as you see it has a queue takes one process then close . yeah pretty slow !

CHAPTER 3 : THREADING IT !

first what is threading ?

Threading in coding refers to the ability of a program to run multiple operations (or threads) concurrently. It allows a program to perform tasks in parallel, which can make it run more efficiently, especially when dealing with time-consuming operations like I/O (input/output) tasks, or heavy computations.

Thread: A thread is the smallest unit of execution in a program. A thread is part of a process and can run concurrently with other threads, but each thread has its own instruction pointer, stack, and local variables.

Multithreading: This is the technique of running multiple threads at the same time within a single program. Threads share the same memory space, which allows them to communicate easily with each other but also means that you have to manage shared data carefully to avoid conflicts.

Why use threading?

Concurrency: While a single-threaded program can do only one thing at a time, a multithreaded program can perform several tasks in parallel, improving efficiency.

Responsiveness: For GUI applications, using threads can keep the user interface responsive, even while the program is working on background tasks.

Utilizing Multi-core Processors: Modern CPUs have multiple cores, and threading allows programs to use these cores for parallel processing.
Enter fullscreen mode Exit fullscreen mode

take a look here :

this image is nice in visualizing the concept when multi threading the code all threads within the same process share the code, data, and files. This makes communication between threads very fast because they can all "see" the same global variables. and of course each one of them has its own stack and registers

before moving on to making our server multi threaded i recommend you to take a look at this blog :

Multithreading in C - GeeksforGeeks

Your All-in-One Learning Portal: GeeksforGeeks is a comprehensive educational platform that empowers learners across domains-spanning computer science and programming, school education, upskilling, commerce, software tools, competitive exams, and more.

favicon geeksforgeeks.org



written by kartik

--------- # -------------
so lets get into making our code multi threaded and explaining how does it work :

In C programming language, we use the POSIX Threads (pthreads) library to implement multithreading, which provides different components along with thread management functions that create the foundation of a multithreaded program in C.

Creating a Thread
The first step is to create a thread and give it a task. To create a new thread, we use the pthread_create() function provided by the thread library in C. It initializes and starts the thread to run the given function (which specifies its task).

Syntax

pthread_create(thread, attr, routine, arg);
where,

thread : Pointer to a pthread_t variable where the system stores the ID of the new thread.
attr : Pointer to a thread attributes object that defines thread properties. Use NULL for default attributes.
routine: Pointer to the function that the thread will execute. It must return void* and accept a void* argument.
arg: A single argument passed to the thread function. Use NULL if no argument is needed. You can pass a struct or pointer to pass multiple values.


SEEMS EASY !

we only need to simple changes :

1 -- > append the library header : #include .
2 -- > second we go back to filling the pthread_create() params

------ filling the arguments ------
looking at the man page of pthread_create the first argument is : pthread_t *restrict thread which also explained in man is :

---------------------------------------------------------------
Before  returning,  a  successful call to pthread_create() stores the ID of the new thread in the buffer pointed to by
       thread; this identifier is used to refer to the thread in subsequent calls to other pthreads functions.
-----------------------------------------------------------
Enter fullscreen mode Exit fullscreen mode

so we declare it by adding in the code : pthread_t thread_id;

second argument

 The  attr  argument  points to a pthread_attr_t structure whose contents are used at thread creation time to determine
       attributes for the new thread; this structure is initialized using pthread_attr_init(3)  and  related  functions.   If
       attr is NULL, then the thread is created with default attributes.
Enter fullscreen mode Exit fullscreen mode

so we leave our second argument as null

third argument : in the function syntax it says void (*start_routine)
so start routine most likely means the function and our function is simply the handler but looking at the blog written by kartik it says :
*
*_routine: Pointer to the function that the thread will execute. It must return void and accept a void* argument._

so first we want to return a void pointer so in the function end it with

return NULL;

2 -- > IT MUST ACCEPT A VOID ARGUMENT SO I SIMPLY DID :
void *client_socket_ptr

so after fixing things casting and calling we are done and left with :

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <pthread.h> 

#define PORT 8080

void *handle_request(void *client_socket_ptr) {
    int client_socket = *((int *)client_socket_ptr);  
    char response[2048];

    printf("Handling request...\n");

    strcpy(response, "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n");
    strcat(response, "<html><body><h1>Hi</h1>");
    printf("Response sent: Hi\n");
    write(client_socket, response, strlen(response));

    sleep(3);  

    printf("Waiting for 3 seconds...\n");

    memset(response, 0, sizeof(response));  
    strcat(response, "<h1>Hi again!</h1></body></html>");
    printf("Response sent: Hi again\n");
    write(client_socket, response, strlen(response));

    close(client_socket);
    printf("Client socket closed\n");

    return NULL;  
}

/*-------------------------------------------------------------------------------------------*/

int main() {
    int server_socket, client_socket;
    struct sockaddr_in server_addr, client_addr;
    socklen_t client_len = sizeof(client_addr);

    printf("Starting server...\n");

    server_socket = socket(AF_INET, SOCK_STREAM, 0);
    if (server_socket < 0) {
        perror("Error creating socket");
        exit(1);
    }
    printf("Server socket created\n");

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

    if (bind(server_socket, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
        perror("Error binding");
        exit(1);
    }
    printf("Socket bound to port %d\n", PORT);

    if (listen(server_socket, 5) < 0) {
        perror("Error listening");
        exit(1);
    }
    printf("Server listening on port %d...\n", PORT);

    while (1) {
        printf("Waiting for client connection...\n");

        client_socket = accept(server_socket, (struct sockaddr *)&client_addr, &client_len);
        if (client_socket < 0) {
            perror("Error accepting connection");
            continue;
        }

        printf("Client connected, handling request...\n");

        pthread_t thread_id;
        if (pthread_create(&thread_id, NULL, handle_request, (void *)&client_socket) != 0) {
            perror("Error creating thread");
        }

        pthread_detach(thread_id);
    }

    close(server_socket);
    printf("Server socket closed\n");

    return 0;
}
Enter fullscreen mode Exit fullscreen mode

as you see super simple changes !
recompile and run it
access it from multiple browsers and tabs do whatever you see it always takes 3 seconds and your hi again is there !

BUT !!!! (the way) this code has been developed has a security vulnerability in it , see you in part 2 ;) -- we will have a fun time debugging and understanding and finding such cool issues !

Top comments (0)