Saltar a contenido

Escenario Vulnerable

Introducción

En este proyecto, se ha diseñado un entorno de red que simula la estructura de una organización real, con vulnerabilidades específicas en cada host desplegado para simular posibles ataques. La topología se ha implementado en GNS3 utilizando un script automatizado para asegurar la eficiencia y consistencia del proceso. Las configuraciones vulnerables se aplicarán automáticamente a través de Ansible.

El entorno consta de tres máquinas que representan distintos puntos de vulnerabilidad en una red típica de una organización. Estas máquinas están diseñadas para ser objetivos de diversas técnicas de pentesting, permitiendo a los estudiantes explorar y explotar vulnerabilidades en un entorno controlado y seguro.

Requisitos previos

Antes de iniciar el despliegue, asegúrate de cumplir con los siguientes requisitos:

Sistema operativo

El entorno puede desplegarse en cualquier sistema operativo compatible con los requisitos de software especificados a continuación.

Software necesario

  • Python: Versión 3.12.1
  • Pydantic: Versión 1.9.2
  • GNS3: Versión 2.2.43
  • GNS3Fy: Versión 0.8.0

Instalación de requisitos

En Linux (Ubuntu como ejemplo)

sudo apt update
sudo apt install -y python3.12 python3-pip
pip3 install pydantic==1.9.2 gns3fy==0.8.0

En Windows

  1. Instalar Python 3.12.1: Descarga el instalador desde Python.org y sigue las instrucciones.
  2. Instalar Pydantic y GNS3Fy: Abre PowerShell como administrador y ejecuta:

    pip install pydantic==1.9.2 gns3fy==0.8.0

  3. Instalar GNS3: Descarga e instala GNS3 desde GNS3.

En otros sistemas operativos

Asegúrate de instalar las versiones especificadas de Python, Pydantic, GNS3 y GNS3Fy utilizando los métodos correspondientes para tu sistema operativo.

ISOs para GNS3

Necesitarás descargar las siguientes ISOs para desplegarlas en GNS3:

Topología de red

La red incluye los siguientes componentes:

EscenarioPFinal

  • Nube Cloud: Representa la conexión externa a Internet.
  • Router/Firewall PFSense v2.7.0: Actúa como el dispositivo de seguridad principal, controlando el tráfico entre la nube y la red interna.
  • Ethernet Switch: Proporciona conectividad entre los diferentes hosts internos.
  • PC1 - Ubuntu Desktop Guest 22.04 (Servidor Ansible): Máquina que gestiona las configuraciones a través de Ansible.
  • PC2 - Ubuntu Desktop Guest 22.04 (Cliente): Máquina cliente con configuraciones vulnerables.
  • PC3 - Windows 10 Enterprise Evaluation (Cliente): Máquina cliente con configuraciones vulnerables.

Despliegue de la topología

Para desplegar la topología en GNS3, sigue estos pasos:

1. Descarga el script de despliegue

Para desplegar la topología en GNS3, utilizaremos un script en Python con la ayuda de la librería GNS3Fy.

2. Personalización del script

  • Asegúrate de que el servidor GNS3 esté configurado correctamente y disponible en la dirección especificada en el script (server_url).

  • Utiliza las credenciales proporcionadas en el script (username y password) para conectarte al servidor GNS3.

  • Asigna un nombre al proyecto en project_name.

3. Ejecutar el script de Python

  • Ejecuta el script con Python, por ejemplo, utilizando python nombre_archivo.py.

El script realizará las siguientes acciones:

  • Crea una conexión con el servidor GNS3.

  • Verifica si ya existe un proyecto con el nombre especificado (project_name) y lo elimina si es así.

  • Crea un nuevo proyecto con el nombre especificado (project_name).

  • Despliega los nodos especificados en la lista (nodes_to_deploy) y los almacena en el diccionario deployed_nodes.

  • Conecta los nodos entre sí para formar la topología de red.

Explicación del script

El siguiente código muestra el script de despliegue con explicaciones detalladas sobre cada bloque de código:

1. Importar las clases necesarias y establecer variables básicas:

from gns3fy import Gns3Connector, Project, Node, Link

server_url = "http://192.168.1.74:80"
username = 'username'
password = 'password'
project_name = "project_name"

2. Crear una instancia de Gns3Connector:

# Creando el conector con autenticación
server = Gns3Connector(server_url, user=username, cred=password)

3. Eliminar proyectos existentes con el mismo nombre:

# Verificar si el proyecto ya existe y eliminarlo si es así
existing_projects = server.get_projects()
for proj in existing_projects:
    if proj['name'] == project_name:
        project = Project(project_id=proj['project_id'], connector=server)
        project.delete()
        print(f"Proyecto existente '{project_name}' eliminado.")

4. Crear un nuevo proyecto:

# Crear un nuevo proyecto
project = Project(name=project_name, connector=server)
project.create()
print(f"Nuevo proyecto '{project_name}' creado.")

5. Lista de plantillas a desplegar:

# Lista de plantillas a desplegar y sus nombres
nodes_to_deploy = [
    {"template_id": "39e257dc-8412-3174-b6b3-0ee3ed6a43e9", "name": "Nube_Cloud"},
    {"template_id": "abd8c506-2f57-4b1a-b0cf-447cbbec79ee", "name": "R1_PFSense"},
    {"template_id": "1966b864-93e7-32d5-965f-001384eec461", "name": "Switch"},
    {"template_id": "3f8652a2-2260-432a-8702-759db0c13c51", "name": "PC1"},
    {"template_id": "3f8652a2-2260-432a-8702-759db0c13c51", "name": "PC2"},
    {"template_id": "b84f5c78-5611-488f-8173-16dfefe83349", "name": "PC3"}
]

Nota: Para conocer la ID de todas las plantillas del servidor de GNS3, utilizamos otro script que adjuntaremos a este proyecto.

6. Función para desplegar los nodos:

# Desplegando nodos y almacenando sus node_id
deployed_nodes = {}

def deploy_nodes():
    for node_info in nodes_to_deploy:
        node = Node(project_id=project.project_id, connector=server, name=node_info["name"], template_id=node_info["template_id"])
        node.create()
        deployed_nodes[node.name] = node.node_id
        print(f"Nodo '{node.name}' creado con éxito en el proyecto '{project.name}' usando la plantilla ID {node_info['template_id']}")

try:
    deploy_nodes()
except Exception as e:
    print(f"Error al desplegar nodos: {e}")

7. Crear enlaces entre los nodos:

# Conectar Nube_Cloud con R1_PFSense
try:
    link1 = Link(project_id=project.project_id, connector=server, nodes=[
        {"node_id": deployed_nodes["Nube_Cloud"], "adapter_number": 0, "port_number": 0},
        {"node_id": deployed_nodes["R1_PFSense"], "adapter_number": 0, "port_number": 0}
    ])
    link1.create()
    print("Enlace creado entre Nube_Cloud y R1_PFSense.")
except Exception as e:
    print(f"Error al crear el enlace entre Nube_Cloud y R1_PFSense: {e}")

# Conectar R1_PFSense con Switch
try:
    link2 = Link(project_id=project.project_id, connector=server, nodes=[
        {"node_id": deployed_nodes["R1_PFSense"], "adapter_number": 1, "port_number": 0},
        {"node_id": deployed_nodes["Switch"], "adapter_number": 0, "port_number": 0}
    ])
    link2.create()
    print("Enlace creado entre R1_PFSense y Switch.")
except Exception as e:
    print(f"Error al crear el enlace entre R1_PFSense y Switch: {e}")

try:
# Conectar Switch (Ethernet1) con PC1
    link_pc1 = Link(project_id=project.project_id, connector=server, nodes=[
        {"node_id": deployed_nodes["Switch"], "adapter_number": 0, "port_number": 1},
        {"node_id": deployed_nodes["PC1"], "adapter_number": 0, "port_number": 0}
    ])
    link_pc1.create()
    print("Enlace creado entre Switch (Ethernet1) y PC1.")

# Conectar Switch (Ethernet2) con PC2
    link_pc2 = Link(project_id=project.project_id, connector=server, nodes=[
        {"node_id": deployed_nodes["Switch"], "adapter_number": 0, "port_number": 2},
        {"node_id": deployed_nodes["PC2"], "adapter_number": 0, "port_number": 0}
    ])
    link_pc2.create()
    print("Enlace creado entre Switch (Ethernet2) y PC2.")

# Conectar Switch (Ethernet3) con PC3
    link_pc3 = Link(project_id=project.project_id, connector=server, nodes=[
        {"node_id": deployed_nodes["Switch"], "adapter_number": 0, "port_number": 3},
        {"node_id": deployed_nodes["PC3"], "adapter_number": 0, "port_number": 0}
    ])
    link_pc3.create()
    print("Enlace creado entre Switch (Ethernet3) y PC3.")

except Exception as e:
    print(f"Error al crear los enlaces entre el Switch y los PCs: {e}")

Despliegue de las máquinas mediante Ansible

Después de desplegar la topología en GNS3, configuraremos las máquinas utilizando playbooks de Ansible.

Ansible es una herramienta de automatización que nos permite gestionar configuraciones y despliegues de manera eficiente. Utilizando playbooks de Ansible, podemos aplicar configuraciones y desplegar aplicaciones en múltiples nodos de forma automática y repetible.

Configuración del PC1 (Servidor Ansible)

En primer lugar vamos a configurar nuestro servidor Ansible (PC1), para ello seguiremos los siguientes pasos:

1. Conexión al PC1 (Servidor Ansible)

Nos conectamos a la máquina que se utilizará como servidor Ansible (PC1) y abrimos un terminal.

2. Instalación de Ansible

Instalamos Ansible utilizando el gestor de paquetes correspondiente.

sudo apt update
sudo apt install software-properties-common
sudo add-apt-repository --yes --update ppa:ansible/ansible
sudo apt install ansible

Ejecutamos el comando ansible --version en la terminal para verficar que ansible se ha instalado correctamente. Debe mostrar la versión de Ansible instalada.

ansible --version

2. Creación del archivo de configuración de Ansible

Una vez que Ansible está instalado, generalmente se crea automáticamente un archivo de configuración en la ruta /etc/ansible/ansible.cfg. Comprobamos si el archivo existe:

ls /etc/ansible/ansible.cfg

Si no encuentras el archivo predeterminado, puedes generar un nuevo archivo de configuración con todas las opciones comentadas para facilitar su configuración. Para hacerlo, ejecuta el siguiente comando:

ansible-config init --disabled > ansible.cfg

Estructura del archivo

El archivo de configuración contiene varias variables de configuración importantes, como:

  • inventory: Ruta del archivo de inventario.
  • forks: Número máximo de conexiones simultáneas.
  • sudo_user: Usuario con el que se hace sudo.
  • module_lang: Idioma definido.
  • timeout: Timeout del ssh.
  • remote_user: Usuario por defecto.
  • log_path: Ruta de los logs.
  • ask_sudo_pass: Si se debe solicitar una contraseña de sudo.
  • remote_port: Puerto para usar en conexiones remotas.

Aquí podemos ver un ejemplo de archivo de configuración de Ansible básico:

[defaults]
inventory = /etc/ansible/hosts
forks = 10
sudo_user = root
module_lang = C
timeout = 60
remote_user = ansible
log_path = /var/log/ansible.log
ask_sudo_pass = yes
remote_port = 22

3. Configuración del inventario

El archivo de inventario es un archivo que contiene la lista de nodos o hosts que Ansible gestionará. Debemos configurarlo para que Ansible pueda conectarse y gestionar los nodos de manera efectiva.

En la mayoría de las instalaciones de Ansible, el archivo de configuración predeterminado (/etc/ansible/ansible.cfg) no contiene la ruta del archivo de inventario (/etc/ansible/hosts) por defecto. Para verificar si la ruta está configurada, ejecuta el siguiente comando:

cat /etc/ansible/ansible.cfg

Si la ruta no está configurada, debemos añadirla. Edita el archivo de configuración de Ansible:

sudo nano /etc/ansible/ansible.cfg

Añade o modifica la línea para que incluya la ruta del archivo de inventario:

[defaults]
inventory = /etc/ansible/hosts

Guarda y cierra el archivo.

Configuración del archivo de inventario

Ahora vamos a configurar el archivo de inventario con los detalles de los nodos del proyecto (PC2 y PC3).

1. Abre el archivo de inventario:

sudo nano /etc/ansible/hosts

2. Añade las siguientes líneas para definir los nodos del proyecto:

[ubuntuclient]
192.168.1.10

[windowsclient]
192.168.1.20

Donde, 192.168.1.10, y 192.168.1.20 son las direcciones IP de los respectivos nodos en la topología de red.

Para mayor claridad, aquí podemos ver un ejemplo completo de cómo debería verse el archivo de inventario (hosts):

[ubuntuclient]
192.168.1.10

[windowsclient]
192.168.1.20

Con estas configuraciones, Ansible podrá gestionar los nodos definidos en el archivo de inventario, permitiendo ejecutar los playbooks en los hosts especificados.

Despliegue del PC2 (Máquina cliente con Moodle vulnerable)

Una vez que tenemos nuestro servidor Ansible listo y comprobado, vamos a desplegar el servidor Moodle en el PC2. Sigue estos pasos:

1. Conéctate al PC1 (servidor Ansible)

Abre una terminal en el servidor Ansible o asegúrate de tener acceso SSH.

2. Descarga el playbook de Moodle y el archivo de configuración

Descarga el playbook desde el siguiente enlace: Descargar playbook

Descarga el archivo moodle-config.php desde el siguiente enlace y asegúrate de colocarlo en el mismo directorio donde tienes el playbook. Durante la ejecución del playbook, este archivo será copiado automáticamente al directorio adecuado.

Descargar moodle-config.php

<?php  // Moodle configuration file

unset($CFG);
global $CFG;
$CFG = new stdClass();

$CFG->dbtype    = 'mysqli';
$CFG->dblibrary = 'native';
$CFG->dbhost    = 'localhost';
$CFG->dbname    = 'moodle';
$CFG->dbuser    = 'moodle_g4'; // Cambia 'moodle_g4' por el nombre de usuario deseado
$CFG->dbpass    = 'grupo4rules'; // Cambia 'grupo4rules' por la contraseña deseada
$CFG->prefix    = 'mdl_';
$CFG->dboptions = array (
  'dbpersist' => false,
  'dbport' => '',
  'dbsocket' => '',
  'dbcollation' => 'utf8mb4_unicode_ci',
);

$CFG->wwwroot   = 'http://localhost/moodle';
$CFG->dataroot  = '/var/moodledata';
$CFG->admin     = 'admin';

$CFG->directorypermissions = 0777;

Nota: Antes de ejecutar el playbook, asegúrate de revisar y configurar las siguientes variables en el archivo playbook_moodle.yml y moodle-config.php:

  • En el playbook playbook_moodle.yml: db_user, db_password, db_root_password, y cualquier otra variable que necesite ser personalizada.

  • En el archivo moodle-config.php: dbuser, dbpass, y cualquier otra configuración específica de tu entorno.

3. Ejecuta el playbook de Ansible

Navega hasta el directorio donde se encuentra el playbook y ejecuta el siguiente comando:

ansible-playbook -i /etc/ansible/hosts playbook_moodle.yml

Explicación del script

Este playbook desplegará un servidor Moodle con varias configuraciones y servicios vulnerables. A continuación, se explican los pasos que realiza cada uno de los bloques del script de Ansible:

1. Definición del objetivo del playbook y ejecución de tareas con permisos elevados

- hosts: moodleserver
  become: yes

2. Definición de variables

vars:
  ansible_python_interpreter: /usr/bin/python3
  moodle_version: "3.4.1"
  db_name: "moodle"
  db_user: "moodle_g4"
  db_password: "grupo4rules"
  db_root_password: "grupo4rules"
  moodle_www_root: "/var/www/html"
  moodle_data_root: "/var/moodledata"

3. Tasks

3.1. Añadir el repositorio de PHP 7.1

- name: Añadir el repositorio de PHP 7.1
  apt_repository:
    repo: ppa:ondrej/php
    state: present

Se añade un repositorio de terceros que contiene varias versiones de PHP.

3.2. Actualizar e instalar paquetes necesarios

- name: Actualizar e instalar paquetes necesarios
  apt:
    update_cache: yes
    name:
      - apache2
      - mysql-server
      - php7.1
      - libapache2-mod-php7.1
      - php7.1-mysql
      - php7.1-xml
      - php7.1-curl
      - php7.1-zip
      - php7.1-gd
      - php7.1-intl
      - php7.1-xmlrpc
      - php7.1-soap
      - php7.1-mbstring
      - php7.1-ldap
      - php7.1-bcmath
      - php7.1-opcache
      - unzip
      - python3-pip
    state: present

Actualiza la caché del paquete y luego instala Apache, MySQL y varias extensiones de PHP necesarias para Moodle.

3.3. Instalar pip para Python 3

- name: Instalar pip para Python 3
  apt:
    name: python3-pip
    state: present

Asegura que pip para Python 3 está instalado.

3.4. Instalar módulo PyMySQL

- name: Instalar módulo PyMySQL
  pip:
    name: PyMySQL
    state: present
    executable: pip3

Instala el módulo PyMySQL usando pip3, necesario para que Ansible pueda gestionar MySQL.

3.5. Iniciar y habilitar Apache

- name: Iniciar y habilitar Apache
  systemd:
    name: apache2
    state: started
    enabled: yes

Inicia el servicio Apache y asegura que se habilite para arrancar al iniciar el sistema.

3.6. Configurar contraseña root de MySQL

- name: Configurar contraseña root de MySQL
  mysql_user:
    name: root
    host: localhost
    password: "{{ db_root_password }}"
    login_user: root
    login_password: "{{ db_root_password }}"
    login_unix_socket: /var/run/mysqld/mysqld.sock
    state: present

Configura la contraseña para el usuario root de MySQL, sirviéndose de las variables mencionadas al principio del playbook.

3.7. Crear base de datos para Moodle

- name: Crear base de datos para Moodle
  mysql_db:
    name: "{{ db_name }}"
    state: present
    login_user: root
    login_password: "{{ db_root_password }}"
    login_unix_socket: /var/run/mysqld/mysqld.sock

Crea una base de datos llamada moodle, sirviéndose de las variables mencionadas al principio del playbook.

3.8. Crear usuario de base de datos para Moodle

- name: Crear usuario de base de datos para Moodle
  mysql_user:
    name: "{{ db_user }}"
    password: "{{ db_password }}"
    priv: "{{ db_name }}.*:ALL"
    state: present
    login_user: root
    login_password: "{{ db_root_password }}"
    login_unix_socket: /var/run/mysqld/mysqld.sock

Crea un usuario de MySQL (moodle_g4) con privilegios sobre la base de datos moodle.

3.9. Descargar Moodle

- name: Descargar Moodle
  get_url:
    url: "https://github.com/moodle/moodle/archive/refs/tags/v3.4.1.zip"
    dest: "/tmp/moodle-{{ moodle_version }}.zip"

Descarga el archivo zip de Moodle de la versión especificada desde GitHub.

3.10. Extraer Moodle

- name: Extraer Moodle
  unarchive:
    src: "/tmp/moodle-{{ moodle_version }}.zip"
    dest: "{{ moodle_www_root }}"
    remote_src: yes

Extrae el contenido del archivo zip en el directorio web de Apache (/var/www/html).

3.11. Establecer permisos en el directorio de Moodle

- name: Establecer permisos en el directorio de Moodle
  file:
    path: "{{ moodle_www_root }}"
    owner: www-data
    group: www-data
    recurse: yes

Establece los permisos del directorio de Moodle para que el usuario y grupo www-data (usado por Apache) tengan control sobre él.

3.12. Crear directorio de datos de Moodle

- name: Crear directorio de datos de Moodle
  file:
    path: "{{ moodle_data_root }}"
    state: directory
    owner: www-data
    group: www-data
    mode: '0770'

Crea el directorio para los datos de Moodle (/var/moodledata) con los permisos adecuados.

3.13. Configurar Apache para Moodle

- name: Configurar Apache para Moodle
  copy:
    content: |
      <VirtualHost *:80>
          ServerAdmin webmaster@localhost
          DocumentRoot {{ moodle_www_root }}
          <Directory {{ moodle_www_root }}>
              Options FollowSymLinks
              AllowOverride All
              Require all granted
          </Directory>
          ErrorLog ${APACHE_LOG_DIR}/error.log
          CustomLog ${APACHE_LOG_DIR}/access.log combined
      </VirtualHost>
    dest: /etc/apache2/sites-available/moodle.conf

Copia una configuración de Apache para Moodle en el directorio de sitios disponibles.

3.14. Deshabilitar el sitio por defecto de Apache

- name: Deshabilitar el sitio por defecto de Apache
  command: a2dissite 000-default.conf

Deshabilita el sitio por defecto de Apache para evitar conflictos.

3.15. Habilitar sitio Moodle en Apache

- name: Habilitar sitio Moodle en Apache
  command: a2ensite moodle.conf

Habilita la nueva configuración de sitio de Moodle en Apache.

3.16. Habilitar módulo rewrite de Apache

- name: Habilitar módulo rewrite de Apache
  command: a2enmod rewrite

Habilita el módulo rewrite de Apache, necesario para las URLs amigables en Moodle.

3.17. Reiniciar Apache para aplicar cambios

- name: Reiniciar Apache para aplicar cambios
  systemd:
    name: apache2
    state: restarted

Reinicia Apache para que los cambios en la configuración surtan efecto.

3.18. Ajustar configuración de PHP para Moodle

- name: Ajustar configuración de PHP para Moodle
  lineinfile:
    path: /etc/php/7.1/apache2/php.ini
    regexp: "{{ item.regexp }}"
    line: "{{ item.line }}"
  with_items:
    - { regexp: '^post_max_size', line: 'post_max_size = 50M' }
    - { regexp: '^upload_max_filesize', line: 'upload_max_filesize = 50M' }
    - { regexp: '^max_execution_time', line: 'max_execution_time = 300' }
    - { regexp: '^max_input_time', line: 'max_input_time = 300' }

3.19. Reiniciar Apache para aplicar cambios de PHP

- name: Reiniciar Apache para aplicar cambios de PHP
  systemd:
    name: apache2
    state: restarted

Reinicia Apache para aplicar cambios de configuración de PHP.

3.20. Configurar Moodle

- name: Configurar Moodle
  template:
    src: moodle-config.php
    dest: "{{ moodle_www_root }}/config.php"
    owner: www-data
    group: www-data
    mode: '0644'

Copia el archivo de configuración de Moodle al directorio adecuado.

4. Handlers

handlers:
  - name: reiniciar apache
    systemd:
      name: apache2
      state: restarted

Define un handler que reinicia Apache cuando es necesario.

Despliegue del PC3 (Máquina cliente con Wordpress vulnerable)

Por último, vamos a desplegar el servidor Wordpress en el PC3. Sigue estos pasos:

1. Conéctate al PC1 (servidor Ansible)

Abre una terminal en el servidor Ansible o asegúrate de tener acceso SSH.

2. Descarga el playbook de Moodle

Descarga el playbook desde el siguiente enlace: Descargar playbook

3. Ejecuta el playbook de Ansible

Navega hasta el directorio donde se encuentra el playbook y ejecuta el siguiente comando:

ansible-playbook -i /etc/ansible/hosts playbook_wordpress.yml

Explicación del script

Conclusión

En este apartado se ha detallado cómo desplegar un entorno vulnerable utilizando GNS3 y Ansible. Se ha proporcionado un script para la configuración de la topología en GNS3 y un playbook de Ansible para configurar un servidor Moodle vulnerable. Los playbooks adicionales para los clientes Ubuntu y Windows estarán disponibles en futuras actualizaciones del proyecto.

Este entorno permite a los estudiantes practicar habilidades de pentesting en un entorno controlado, explorando y explotando diversas vulnerabilidades para aprender a proteger sistemas reales.