Smash The Stack: IO Level 6 Walkthrough

Level 6 on the Smash The Stack IO wargame takes two command-line arguments (username and password) and prints a greeting: level6@io:/levels$ ./level06 user pass Hi user Notice that the application checks the LANG environment variable to determine which greeting to print: level6@io:/levels$ export LANG=fr level6@io:/levels$ ./level06 user pass Bienvenue user level6@io:/levels$ export LANG=de level6@io:/levels$ ./level06 user pass Willkommen user Vulnerability Analysis The program structure internally organizes credentials into a record: ...

December 5, 2014 · 2 min · 312 words · Ahmad Mahfouz

Smash The Stack: IO Level 5 Walkthrough

Level 5 of the Smash The Stack IO wargame presents a classic stack-based buffer overflow scenario. Executing the binary simply echoes the supplied command-line argument: level5@io:/levels$ ./level05 test test Analyzing the Source Code The source file level05.c shows an unbounded strcpy into a fixed 128-byte stack buffer: #include <stdio.h> #include <string.h> int main(int argc, char **argv) { char buf[128]; if (argc < 2) return 1; strcpy(buf, argv[1]); printf("%s\n", buf); return 0; } Because strcpy() copies until it hits a null byte without checking the destination bounds of buf[128], an argument exceeding 128 bytes overwrites adjacent stack data, including the saved base pointer (EBP) and return address (EIP). ...

December 3, 2014 · 2 min · 344 words · Ahmad Mahfouz

Smash The Stack: IO Level 4 Walkthrough

In Level 4 of the Smash The Stack IO wargame, executing the binary prints a static welcome message regardless of input arguments: level4@io:/levels$ ./level04 Welcome level5 level4@io:/levels$ ./level04 $(python -c "print 'A' * 1024") Welcome level5 Analyzing the Source Code Inspecting level04.c: #include <stdio.h> #include <stdlib.h> int main() { char username[1024]; FILE* f = popen("whoami", "r"); fgets(username, sizeof(username), f); printf("Welcome %s", username); return 0; } Vulnerability Analysis: Insecure PATH Resolution Notice the popen call: FILE* f = popen("whoami", "r"); The author called whoami as a bare command name rather than specifying an absolute binary path (such as /usr/bin/whoami). When popen() spawns /bin/sh -c whoami, the shell searches for the whoami executable in the directories listed in the current user’s PATH environment variable from left to right. ...

December 3, 2014 · 1 min · 206 words · Ahmad Mahfouz

Smash The Stack: IO Level 3 Walkthrough

In Level 3 of the Smash The Stack IO wargame, passing a large argument quickly causes a segmentation fault: level3@io:/levels$ ./level03 $(python -c "print 'A' * 1000") Segmentation fault Analyzing the Source Code The source file level03.c is provided in /levels: #include <stdio.h> #include <string.h> #include <unistd.h> void good() { puts("Win."); execl("/bin/sh", "sh", NULL); } void bad() { printf("I'm so sorry, you're at %p and you want to be at %p\n", bad, good); } int main(int argc, char **argv, char **envp) { void (*functionpointer)(void) = bad; char buffer[50]; if (argc != 2 || strlen(argv[1]) < 4) return 0; memcpy(buffer, argv[1], strlen(argv[1])); memset(buffer, 0, strlen(argv[1]) - 4); printf("This is exciting we're going to %p\n", functionpointer); functionpointer(); return 0; } Vulnerability Analysis Target Function: good() spawns a privileged shell via execl("/bin/sh", ...). Buffer and Function Pointer: main() allocates a 50-byte buffer (char buffer[50]) and initializes a function pointer pointing to bad(). Unbounded Copy: memcpy(buffer, argv[1], strlen(argv[1])) copies the entire input into buffer without checking against its 50-byte bound. Partial Clear: memset(buffer, 0, strlen(argv[1]) - 4) zeroes out buffer up to strlen(argv[1]) - 4. The last 4 bytes of our input remain untouched in memory. Execution: The program invokes functionpointer(). If we overflow buffer such that the trailing 4 bytes align precisely over functionpointer, we redirect execution to good(). Finding Addresses and Offset in GDB Disassemble and locate the address of good(): ...

December 1, 2014 · 2 min · 352 words · Ahmad Mahfouz

Smash The Stack: IO Level 2 Walkthrough

In Level 2 of the Smash The Stack IO wargame, source code is provided directly in level02.c: level2@io:/levels$ cat level02.c #include <stdio.h> #include <stdlib.h> #include <signal.h> #include <setjmp.h> void catcher(int a) { setresuid(geteuid(), geteuid(), geteuid()); printf("WIN!\n"); system("/bin/sh"); exit(0); } int main(int argc, char **argv) { puts("source code is available in level02.c\n"); if (argc != 3 || !atoi(argv[2])) return 1; signal(SIGFPE, catcher); return abs(atoi(argv[1])) / atoi(argv[2]); } Analyzing the Code The Target (catcher): The catcher function sets the real, effective, and saved UID to the effective UID (geteuid()) and drops into /bin/sh. This triggers when the program receives a SIGFPE signal. Input Validation: The check if (argc != 3 || !atoi(argv[2])) ensures two arguments are passed and argv[2] does not evaluate to 0. This explicitly prevents standard division-by-zero errors. The Division: The function returns abs(atoi(argv[1])) / atoi(argv[2]). Understanding SIGFPE and Two’s Complement Overflow In C on 32-bit x86 systems, a signed 32-bit integer ranges from -2,147,483,648 (INT_MIN / 0x80000000) to +2,147,483,647 (INT_MAX / 0x7FFFFFFF). ...

December 1, 2014 · 2 min · 261 words · Ahmad Mahfouz

Smash The Stack: IO Level 1 Walkthrough

In this challenge on the Smash The Stack IO wargame, the binaries are located under /levels. Let’s inspect the target binary for Level 1: level1@io:/levels$ ls -alh level01 -r-sr-x--- 1 level2 level1 1.2K Jan 13 2014 level01 Notice the permissions: -r-sr-x--- with the SUID bit set for level2. Executing this binary successfully will spawn a process with level2 privileges. Initial Execution Running the program prompts for a passcode: level1@io:/levels$ ./level01 Enter the 3 digit passcode to enter: 838 Providing an arbitrary number exits silently with no output. ...

December 1, 2014 · 2 min · 287 words · Ahmad Mahfouz