/*
 * vulnerable-server.c.txt
 * ========================
 * EDUCATIONAL EXAMPLE ONLY - NOT A WORKING EXPLOIT
 * For use in authorized CTF / lab environments only.
 *
 * A deliberately vulnerable TCP echo server demonstrating a classic
 * stack-based buffer overflow. The server reads user input with gets()
 * into a small 64-byte stack buffer, allowing an attacker to overwrite
 * the saved return address and redirect execution.
 *
 * Compile (with protections disabled for lab use):
 *   gcc -fno-stack-protector -z execstack -no-pie -o vuln_server vuln_server.c
 *
 * VULNERABILITY: gets() performs no bounds checking. An input longer
 * than 64 bytes overflows `buf`, overwrites the saved RBP and return
 * address on the stack, and can redirect execution to admin_shell().
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>

#define PORT 9999
#define BACKLOG 5

/* ---------------------------------------------------------------
 * HIDDEN FUNCTION: admin_shell()
 * This function is compiled into the binary but is never called
 * through normal program flow. An attacker who controls the return
 * address can redirect execution here.
 * Address can be found with: objdump -d vuln_server | grep admin_shell
 * --------------------------------------------------------------- */
void admin_shell(void) {
    printf("[!] Admin shell activated -- you should not be here!\n");
    printf("[!] In a real exploit, this would exec /bin/sh\n");
    /* system("/bin/sh");  <-- what a real exploit target would do */
    exit(0);
}

/* ---------------------------------------------------------------
 * VULNERABLE FUNCTION: handle_client()
 * BUG: gets() reads unlimited input into a 64-byte stack buffer.
 * Overflow overwrites: buf[64] -> saved_rbp[8] -> return_addr[8]
 * Offset to return address: 64 + 8 = 72 bytes on x86-64.
 * --------------------------------------------------------------- */
void handle_client(int client_fd) {
    char buf[64];  /* <-- VULNERABILITY: small stack buffer */

    /* Redirect stdin/stdout to the client socket */
    dup2(client_fd, STDIN_FILENO);
    dup2(client_fd, STDOUT_FILENO);

    printf("Welcome to EchoServer v1.0\n");
    printf("Enter your message: ");
    fflush(stdout);

    /* BUG: gets() has no length limit -- classic buffer overflow */
    gets(buf);  /* <-- VULNERABLE CALL: no bounds checking! */

    printf("You said: %s\n", buf);
    fflush(stdout);

    close(client_fd);
}

int main(int argc, char *argv[]) {
    int server_fd, client_fd;
    struct sockaddr_in addr;
    socklen_t addr_len = sizeof(addr);

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

    int opt = 1;
    setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));

    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = INADDR_ANY;
    addr.sin_port = htons(PORT);

    if (bind(server_fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
        perror("bind"); exit(1);
    }
    if (listen(server_fd, BACKLOG) < 0) {
        perror("listen"); exit(1);
    }

    printf("[*] Vulnerable server listening on port %d\n", PORT);

    while (1) {
        client_fd = accept(server_fd, (struct sockaddr *)&addr, &addr_len);
        if (client_fd < 0) { perror("accept"); continue; }
        printf("[+] Connection received\n");
        handle_client(client_fd);  /* Each connection handled in-process */
    }

    close(server_fd);
    return 0;
}
