let lista = [10,20];
lista.push(30); // añade al final
lista.pop(); // elimina último
lista.unshift(5); // añade al inicio
lista.shift(); // elimina primero
Buscar elementos
let numeros = [10,20,30];
numeros.includes(20); // true
numeros.indexOf(30); // 2
Convertir a texto
let colores = ["rojo","verde","azul"];
alert(colores.join(" - "));
Resultado:
rojo - verde - azul
Extraer partes
let datos = [1,2,3,4,5];
let sub = datos.slice(1,4); // [2,3,4]
slice no modifica el original.
Modificar el array
let datos = [1,2,3,4];
datos.splice(1,2); // elimina desde posición 1 → elimina 2 elementos
Resultado:
[1,4]
Video Arrays
Tabla completa de métodos importantes
Método
Qué hace
Ejemplo
length
Tamaño del array
[1,2].length
push(x)
Añade al final
arr.push(5)
pop()
Elimina último
arr.pop()
shift()
Elimina primero
arr.shift()
unshift(x)
Añade al inicio
arr.unshift(0)
includes(x)
Comprueba existencia
arr.includes(10)
indexOf(x)
Posición del valor
arr.indexOf(20)
join(sep)
Convierte a texto
arr.join(",")
slice(a,b)
Subarray sin modificar
arr.slice(1,3)
splice(a,b)
Modifica/elimina/añade
arr.splice(1,1)
reverse()
Invierte array
arr.reverse()
sort()
Ordena
arr.sort()
concat()
Une arrays
a.concat(b)
forEach()
Recorre array
arr.forEach(f)
map()
Transforma elementos
arr.map(f)
filter()
Filtra elementos
arr.filter(f)
find()
Encuentra elemento
arr.find(f)
Recorrer arrays
Método clásico
let numeros = [10,20,30];
for (let i = 0; i < numeros.length; i++) {
console.log(numeros[i]);
}
forEach
numeros.forEach(function(n) {
console.log(n);
});
map (transformar)
let dobles = numeros.map(n => n * 2);
filter (filtrar)
let mayores = numeros.filter(n => n > 15);
Arrays con objetos
let alumnos = [
{nombre:"Ana", nota:8},
{nombre:"Luis", nota:5}
];
console.log(alumnos[0].nombre);
Esto es el paso previo al JSON del backend → DOM
Conceptos clave
Los arrays pueden crecer dinámicamente
Pueden contener cualquier tipo
Son objetos (typeof array → "object")
map/filter/find son la base del JavaScript moderno
Ejercicios para alumnos
Ejercicio 1
Crear un array con 5 números y mostrar el tamaño.
Ejercicio 2
Añadir un número y eliminar el primero.
Ejercicio 3
Mostrar solo los números mayores que 10.
Ejercicio 4
Crear un array de nombres y convertirlos a mayúsculas con map.
Ejercicio 5
Crear un array de objetos alumno {nombre, nota} y mostrar solo los aprobados.
JSON (JavaScript Object Notation) es un formato de texto basado en la estructura de objetos de JavaScript. Más moderno y ligero que XML, se utiliza ampliamente tanto para la transmisión de datos entre aplicaciones como para su almacenamiento.
Este modelo de datos se ha popularizado porque prioriza el contenido sobre la estructura, reduciendo la cantidad de sintaxis necesaria y facilitando la lectura por parte de humanos y máquinas.
Estructura básica
Un archivo JSON es una cadena de texto que debe parsearse (analizarse sintácticamente) para acceder a sus datos. Este proceso se denomina parsing cuando convertimos una cadena en un objeto, y stringification cuando hacemos la operación inversa (objeto → texto).
Los principales elementos de la estructura JSON son:
{}: delimitan un objeto.
[]: delimitan un array (lista ordenada de elementos).
:: separa las claves de sus valores.
,: separa los diferentes pares de clave-valor o elementos.
JSON y XML son formatos ampliamente usados para intercambiar información entre sistemas y almacenar configuraciones o datos estructurados.
Aunque JSON suele ser más ligero y fácil de leer, XML ofrece ventajas en casos donde se necesita validación mediante esquemas (XSD) o metadatos complejos.
En general, JSON es ideal para intercambio rápido de datos entre aplicaciones web, mientras que XML puede ser preferible en entornos donde se requiera validación formal o compatibilidad con sistemas antiguos.
Los 31 mejores sitios web oscuros y enlaces Onion en Tor (2026)
Tu guía para los mejores enlaces de la dark web. Encuentra acceso seguro y anónimo a correo electrónico seguro, wikis ocultas, herramientas de Bitcoin y mercados ocultos de internet.
btenga noticias de ciberseguridad, guías detalladas y conocimientos de expertos sobre Tor, herramientas de privacidad y seguridad digital de profesionales de la industria.
Tor.link es, dicho sin dramatismos, un directorio y monitor de servicios .onion. No es una web “de la deep web” en sí, sino un catálogo que observa la deep web desde fuera.
Tor.link es un sitio web (accesible desde la web normal y desde Tor) que:
cataloga direcciones .onion
comprueba si están vivas o muertas
muestra metadatos básicos del servicio
NO aloja el contenido del .onion
Es como una ficha técnica o una ITV de servicios Tor.
OnionShare es una pequeña criatura elegante del ecosistema de la privacidad. Un programa libre que permite compartir archivos, chatear o incluso alojar una web temporal de forma anónima usando la red Tor. Nada de servidores centrales, nada de intermediarios curiosos mirando por la cerradura digital.
La idea esencial es esta: cuando usas OnionShare, tu propio ordenador se convierte en un mini-servidor oculto dentro de Tor (lo que se llama servicio onion). Genera una dirección .onion única y solo quien tenga ese enlace puede acceder. El archivo no se sube a “la nube”, viaja directamente de tu máquina a la del receptor, cifrado y envuelto en capas como una cebolla criptográfica —de ahí lo de Onion.
Funciones principales, en lenguaje humano:
Compartir archivos anónimamente Envías un enlace .onion, el receptor descarga directamente desde tu equipo.
Recibir archivos Puedes crear un buzón seguro para que otros te envíen cosas sin revelar identidades.
Chat privado Conversaciones cifradas sin servidores centrales.
Modo sitio web Hospedar temporalmente una página accesible solo por Tor.
Detalles curiosos del universo técnico: OnionShare usa los onion services de Tor, que evitan exponer tu IP real porque el tráfico nunca sale directamente a Internet “normal”. Todo va dentro de la red Tor. Además, puedes hacer que el enlace sea de un solo uso, que se cierre al descargar, o mantenerlo abierto como un pequeño faro oculto en el océano oscuro.
Ahora, realidad práctica (la ciencia ama la honestidad): No es magia. Si el equipo está comprometido, si compartes datos sensibles sin cuidado, o si el receptor guarda el archivo y lo difunde… la privacidad desaparece. Tor protege el transporte, no las decisiones humanas. La criptografía no arregla imprudencias.
En el ecosistema de ciberseguridad educativa —que tú sueles cultivar con tus alumnos— OnionShare es perfecto para enseñar:
anonimato vs privacidad
transferencia directa vs nube
modelo de amenaza (threat model)
OPSEC básica (seguridad operacional)
Es una herramienta simple, pero conceptualmente profunda. Una cebolla pequeña que abre puertas enormes hacia el pensamiento crítico sobre identidad, confianza y control en la red.
Hay conceptos que, una vez se ven, el cerebro hace clic y ya no vuelve atrás. La diferencia entre máquinas virtuales y contenedores es uno de esos momentos fundacionales en la vida de cualquier persona que empieza a pensar como ingeniero de sistemas.
La metáfora clásica —y sorprendentemente precisa— es esta:
👉 Las máquinas virtuales son casas completas. 👉 Los contenedores son apartamentos dentro del mismo edificio.
La diferencia que cambia la forma de diseñar sistemas
Esto es lo verdaderamente importante —y lo que merece que tus alumnos lo entiendan bien:
Con VMs piensas en:
«Voy a crear servidores.»
Con contenedores empiezas a pensar:
«Voy a desplegar servicios.»
Instalación de Docker Desktop y Portainer en Windows
En los entornos tecnológicos actuales, la virtualización ligera mediante contenedores se ha convertido en un estándar para el desarrollo, despliegue y administración de aplicaciones.
Docker es una plataforma que permite empaquetar aplicaciones junto con todas sus dependencias dentro de contenedores, garantizando que funcionen de forma idéntica en cualquier sistema.
En este tema aprenderemos a preparar un equipo Windows para trabajar con Docker Desktop y a instalar Portainer, una herramienta gráfica que facilita la gestión de contenedores.
Esta instalación será la base de todos los proyectos que realizaremos posteriormente.
1. ¿Por qué Docker necesita Linux en Windows?
Docker utiliza tecnologías propias del kernel de Linux como:
namespaces → aislamiento de procesos
cgroups → control de recursos
union filesystems → capas de almacenamiento
Windows no dispone de estas tecnologías de forma nativa.
La solución es WSL2.
¿Qué es WSL?
WSL (Windows Subsystem for Linux) es una característica de Windows que permite ejecutar un kernel real de Linux dentro del sistema operativo sin necesidad de usar una máquina virtual tradicional.
No es un emulador.
No es una traducción de comandos.
Es Linux funcionando dentro de Windows.
Ventajas de WSL2 frente a una VM clásica:
Arranque casi instantáneo
Menor consumo de memoria
Mejor rendimiento de disco
Integración directa con el sistema
Docker Desktop utiliza WSL2 como motor de virtualización.
👉 Sin WSL2, Docker simplemente no puede funcionar correctamente en Windows moderno.
3. Activar la virtualización
La virtualización debe estar habilitada en la BIOS/UEFI. Si has estado trabajando con maquinas virtuales con Virtual Box o VMWare seguro que ya lo tienes.
Vamos a creae una base de datos naciendo en un contenedor, y desde fuera un cliente elegante (Workbench) hablando con ella a través del vacío digital. Eso es red, puertos y aislamiento en acción.
Crear contenedor MySQL.
Publicar puerto al host.
Conectarse desde MySQL Workbench.
Ver que el contenedor es “otro sistema”, pero accesible.
Arquitectura:
Workbench (Host) → localhost:3306 → Contenedor MySQL
Qué significa cada parte (esto es lo que debes explicar)
-d → modo daemon (segundo plano)
--name mysql-demo → nombre del contenedor
MYSQL_ROOT_PASSWORD → password del root (obligatorio)
MYSQL_DATABASE → crea BD inicial
-p 3306:3306 → publica puerto MySQL al host
mysql:8 → imagen oficial
Paso 2 — Verificar que el contenedor está vivo
docker ps
Debe aparecer algo como:
mysql-demo mysql:8 Up ... 0.0.0.0:3306->3306/tcp
Si no arranca:
docker logs mysql-demo
MySQL tarda unos segundos en inicializar. Paciencia científica.
Paso 3 — Conectar desde MySQL Workbench
En Workbench → New Connection
Parámetros:
Host: 127.0.0.1
Port: 3306
User: root
Password: 1234
Test Connection → Connect.
Si todo va bien, verás la BD demo.
Paso 4 — Prueba real
En Workbench ejecuta:
CREATE TABLE alumnos (
id INT AUTO_INCREMENT PRIMARY KEY,
nombre VARCHAR(50)
);
INSERT INTO alumnos (nombre) VALUES ('Neo'), ('Trinity');
SELECT * FROM alumnos;
Luego demuestra algo mágico:
Entra al contenedor
docker exec -it mysql-demo mysql -uroot-p1234
Dentro:
USE demo;
SELECT * FROM alumnos;
Los datos están ahí → Workbench y contenedor hablan con la misma base.
Eso hace que los alumnos comprendan el concepto de servicio expuesto por red.
Problemas típicos (para que no te sabotee el universo)
Puerto ocupado
Si tienes MySQL local:
lsof -i :3306
Cambia puerto:
-p3307:3306
Y en Workbench → puerto 3307.
No conecta
Comprobar:
docker ps
docker logs mysql-demo
Esperar inicialización (MySQL tarda).
Workbench no conecta pero CLI sí
A veces el plugin de auth:
docker exec -it mysql-demo mysql -uroot-p1234
En SQL
ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY '1234';
FLUSH PRIVILEGES;
Agrupa las instalaciones en una sola instrucción RUN para reducir el tamaño de la imagen.
Usa .dockerignore para no copiar archivos innecesarios.
Define variables con ENV si hay configuraciones reutilizables.
Usa ENTRYPOINT cuando quieras ejecutar siempre el mismo comando, incluso si el usuario añade argumentos extra.
Instrucción WORKDIR
WORKDIR establece el directorio de trabajo dentro del contenedor. Equivale a hacer un cd /app dentro del entorno del contenedor antes de ejecutar los siguientes comandos.
Por ejemplo:
FROM python:3.11-slim
WORKDIR /app
COPY . .
RUN pip install -r requirements.txt
CMD ["python", "app.py"]
Qué hace realmente:
Crea el directorio si no existe (/app en este caso).
Cambia el contexto: a partir de esa línea, todos los comandos (COPY, RUN, CMD, etc.) se ejecutan dentro de /app.
Así, COPY . . copia el contenido del proyecto local dentro del contenedor en /app, y python app.py se ejecutará desde ahí.
Sin WORKDIR
Si no la usas, Docker ejecuta todo desde / (la raíz del contenedor). Ejemplo:
FROM python:3.11-slim
COPY . .
CMD ["python", "app.py"]
Esto también funcionará, pero el código quedará desperdigado en / — algo poco limpio y poco profesional.
¿Qué son las variables de entorno en Docker?
Las variables de entorno (ENV) son valores que se inyectan en el entorno del contenedor y que las aplicaciones pueden usar para configurarse.
Por ejemplo:
Contraseña del root
Nombre de la base de datos
Usuario y contraseña de aplicación
Docker las pasa al contenedor con la instrucción ENV en el Dockerfile o con la opción -e en el docker run.
Ejemplo básico de Dockerfile con MySQL
# Imagen base oficial de MySQL
FROM mysql:8.0
# Variables de entorno
ENV MYSQL_ROOT_PASSWORD=supersegura
ENV MYSQL_DATABASE=tienda
ENV MYSQL_USER=usuario
ENV MYSQL_PASSWORD=1234
# Exponer el puerto de MySQL
EXPOSE 3306
Explicación:
MYSQL_ROOT_PASSWORD: establece la contraseña del usuario root.
MYSQL_DATABASE: crea automáticamente una base de datos llamada tienda.
MYSQL_USER y MYSQL_PASSWORD: crean un usuario adicional con permisos sobre esa base.
EXPOSE 3306: indica el puerto por defecto del servicio.
Construcción y ejecución
Construir la imagen:
docker build -t mysql-demo .
Ejecutar el contenedor:
docker run -d -p 3306:3306 --name contmysql mysql-demo
Con eso, MySQL arrancará con la configuración establecida en las variables del Dockerfile.
Alternativa más flexible (sin tocar el Dockerfile)
También se pueden pasar las variables en tiempo de ejecución, lo que se recomienda para producción (para no dejar contraseñas dentro del Dockerfile):
docker run -d --env-file .env -p 3306:3306 --name mysql-demo mysql:8.0
LABORATORIO – TAREA
Montar una infraestructura de laboratorio Dockerizada donde cada contenedor representa una parte de una red vulnerable, simulando un pequeño entorno que deben administrar, securizar o incluso “atacar” de forma controlada.
Cada alumno desplegará una red interna en su máquina virtual Ubuntu Server, con varios contenedores Docker que simulen los componentes de una empresa ficticia hackeable llamada:
«CyberCorp Ltd.»
El propósito es:
Divertirse con un entorno “ethical hacking friendly”.
Aprender a crear y gestionar contenedores.
Comprender la comunicación entre ellos
Aplicar conceptos de seguridad: contraseñas, puertos, logs, aislamiento, backups.
Infraestructura propuesta
Servicio
Imagen base
Rol / Descripción
Puertos
nginx-web
nginx:latest
Página corporativa vulnerable (HTML + PHP)
8080
db-server
mysql:8.0
Base de datos de empleados con credenciales débiles
3306
ftp-server
delfer/alpine-ftp-server
Servidor FTP para intercambio de archivos
21
mail-server
maildev/maildev
Servidor SMTP simulado (visualización de correos en web)
1080
monitor
grafana/grafana
Panel de monitorización interno
3000
attacker
kalilinux/kali-rolling
Contenedor con herramientas ofensivas
shell interactiva
logger
fluentd
Centralización de l
1) Preparación en la VM (comandos iniciales)
# Actualizar y asegurarnos de tener Docker
sudo apt update && sudo apt install -y docker.io
# Iniciar y activar Docker
sudo systemctl enable --now docker
# Añadir tu usuario al grupo docker (opcional, cerrar sesión/reiniciar)
sudo usermod -aG docker $USER
# Crear red y volumenes
docker network create cybernet
docker volume create mysql_data
docker volume create web_html
2) Estructura de carpetas (ejemplo) /home/usuario/hack-containers/
Usamos la imagen oficial de MySQL como base, y añadimos un init SQL.
FROM mysql:8.0
# Copiamos scripts de inicialización (se ejecutan al primer arranque)
COPY init-db/ /docker-entrypoint-initdb.d/ VOLUME ["/var/lib/mysql"]
EXPOSE 3306
mysql/init-db/init.sql (ejemplo con credenciales débiles y tabla)
CREATE DATABASE empleados;
USE empleados;
CREATE TABLE usuarios ( id INT AUTO_INCREMENT PRIMARY KEY, usuario VARCHAR(50), password VARCHAR(50) );
INSERT INTO usuarios (usuario, password) VALUES ('admin','admin123');
Construir y ejecutar:
cd mysql
docker build -t ctf-mysql:1.0 . docker run -d --name mysql --network cybernet \
-e MYSQL_ROOT_PASSWORD=rootroot \
-v mysql_data:/var/lib/mysql \
ctf-mysql:1.0
B) Web vulnerable (PHP + Apache) (web/Dockerfile)
FROM php:8.2-apache
# Copiamos el código vulnerable
COPY html/ /var/www/html/
# Habilitamos mod_rewrite por si hace falta
RUN a2enmod rewrite
EXPOSE 80
web/html/index.php (vulnerable ejemplo: login sin sanitizar — para SQLi)
cd web
docker build -t ctf-web:1.0 .
docker run -d --name web --network cybernet \
-p 8080:80 \
-v web_html:/var/www/html \
ctf-web:1.0
# Copiar el html local al volumen (una sola vez si quieres)
docker cp html/. web:/var/www/html/
Nota: en index.php se conecta a host mysql (nombre del contenedor) — así los containers se resuelven por nombre dentro de la red cybernet.
C) FTP (ftp/Dockerfile) — ejemplo simple con vsftpd