/* * 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 #include #include #include #include #include #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; }