/* * legacy-auth.c.txt * ================= * INTENTIONALLY VULNERABLE C authentication module for CTF / code-auditing practice. * DO NOT compile or deploy in production. All vulnerabilities are educational. */ #include #include #include #define MAX_USERS 100 #define TOKEN_LEN 32 struct User { char username[32]; char password[64]; int privilege_level; int is_active; }; static struct User user_db[MAX_USERS]; static int user_count = 0; /* VULNERABILITY: Buffer Overflow -- strcpy with no bounds checking */ int register_user(const char *username, const char *password, int privilege) { if (user_count >= MAX_USERS) return -1; struct User *u = &user_db[user_count]; /* Vulnerable: username could exceed 32-byte buffer */ strcpy(u->username, username); /* TODO: add bounds check */ strcpy(u->password, password); /* TODO: add bounds check */ u->privilege_level = privilege; u->is_active = 1; user_count++; return 0; } /* VULNERABILITY: Format String -- printf with user-controlled format */ void log_login_attempt(const char *username) { char log_msg[256]; snprintf(log_msg, sizeof(log_msg), "Login attempt: %s", username); /* Vulnerable: log_msg is user-controlled and used as format string */ printf(log_msg); /* TODO: should be printf("%s", log_msg) */ printf("\n"); } /* VULNERABILITY: Use-After-Free */ struct User *find_and_deactivate(const char *username) { struct User *found = NULL; for (int i = 0; i < user_count; i++) { if (strcmp(user_db[i].username, username) == 0) { found = malloc(sizeof(struct User)); memcpy(found, &user_db[i], sizeof(struct User)); break; } } if (found) { found->is_active = 0; /* Vulnerable: freeing the struct, then returning the dangling pointer */ free(found); /* TODO: do not free before returning */ } return found; /* caller receives a dangling pointer */ } /* VULNERABILITY: Integer Overflow in token allocation */ char *generate_tokens(unsigned int count) { /* Vulnerable: count * TOKEN_LEN can wrap around to a small value. e.g., count = 0x08000001 => 0x08000001 * 32 = 0x100000020, which truncates to 0x00000020 (32) on 32-bit size_t. */ size_t total_size = count * TOKEN_LEN; /* TODO: check for overflow */ char *tokens = malloc(total_size); if (!tokens) return NULL; for (unsigned int i = 0; i < count; i++) { /* Writes far beyond allocated buffer when overflow occurred */ memset(tokens + (i * TOKEN_LEN), 'A' + (i % 26), TOKEN_LEN); } return tokens; } /* VULNERABILITY: Stack-based Buffer Overflow via gets() */ int authenticate(void) { char username[32]; char password[64]; printf("Username: "); gets(username); /* TODO: never use gets() */ printf("Password: "); gets(password); /* TODO: never use gets() */ log_login_attempt(username); for (int i = 0; i < user_count; i++) { if (strcmp(user_db[i].username, username) == 0 && strcmp(user_db[i].password, password) == 0) { if (!user_db[i].is_active) { printf("Account deactivated.\n"); return -1; } printf("Welcome, %s (privilege %d)\n", user_db[i].username, user_db[i].privilege_level); return user_db[i].privilege_level; } } printf("Authentication failed.\n"); return -1; } int main(void) { register_user("admin", "correcthorsebatterystaple", 9); register_user("guest", "guest", 0); int level = authenticate(); if (level > 0) { printf("Elevated access granted.\n"); } return 0; }