Hosts virtuales
Un servidor puede alojar varias aplicaciones en la misma dirección IP. El nombre solicitado decide qué certificado y contenido recibe el cliente. Enumerar hosts virtuales exige comprender dos selecciones distintas: TLS puede elegir una configuración mediante SNI y HTTP puede elegir una aplicación mediante la autoridad de la petición.
De la URL a la aplicación
Sección titulada «De la URL a la aplicación»En https://portal.DOMAIN:8443/login, el origen está formado por el esquema https, el hostname portal.DOMAIN y el puerto 8443. El navegador resuelve el nombre, abre una conexión a una dirección y envía:
portal.DOMAINcomo SNI durante el handshake TLSportal.DOMAIN:8443como autoridad HTTP una vez establecido TLS/logincomo destino dentro de la aplicación seleccionada
HTTP/1.1 representa la autoridad mediante la cabecera Host. HTTP/2 y HTTP/3 utilizan la pseudo-cabecera :authority. Un proxy inverso puede combinar esa autoridad con la dirección local, el puerto, la ruta o reglas propias para elegir el servicio de destino.
Un subdominio es un nombre dentro del espacio DNS. Un host virtual es una configuración del servidor. A menudo coinciden, pero no siempre:
- un nombre puede existir en DNS y no tener una aplicación propia
- un host virtual puede funcionar sin un registro DNS público
- dominios distintos pueden compartir IP y servidor
- una misma autoridad puede entregar aplicaciones diferentes según el puerto
Construir una respuesta de referencia
Sección titulada «Construir una respuesta de referencia»Antes de probar candidatos, observa qué responde el servidor ante un nombre improbable. curl permite fijar manualmente la cabecera Host. -sS oculta el progreso, pero conserva los errores. -D - escribe las cabeceras de respuesta en la terminal. -o /dev/null descarta el cuerpo:
curl -sS -D - -o /dev/null \ -H 'Host: unlikely-name.DOMAIN' \ http://TARGET_IP/Conserva el código, Location, título, longitud, hash del cuerpo y cabeceras estables. El tamaño por sí solo es una referencia débil. Tokens, fechas, identificadores de petición y páginas de error dinámicas pueden cambiar en cada respuesta.
En HTTPS, cambiar Host después del handshake no modifica el Server Name Indication (SNI) ya enviado. --resolve indica a curl que conecte un nombre y puerto con una dirección concreta. La URL mantiene el hostname, por lo que curl envía el SNI y la autoridad coherentes:
curl -sS -D candidate-headers.txt -o candidate-body.html \ --resolve CANDIDATE.DOMAIN:443:TARGET_IP \ https://CANDIDATE.DOMAIN/La entrada de --resolve tiene el formato host:puerto:dirección. -D candidate-headers.txt guarda las cabeceras y -o candidate-body.html conserva el cuerpo. Compara ambos archivos con la respuesta de referencia. Un certificado rechazado puede indicar que el nombre no está cubierto o que existe otra terminación TLS. No demuestra que el host virtual HTTP sea inexistente.
Probar una lista de nombres
Sección titulada «Probar una lista de nombres»Las listas generales aportan nombres comunes. Una lista dirigida añade convenciones observadas en certificados, HTML, JavaScript, repositorios y nombres ya confirmados. Antes de automatizar, decide si cada palabra se probará como nombre completo o se combinará con un dominio base.
ffuf sustituye FUZZ por cada línea de la wordlist. -w selecciona el archivo, -u fija la URL y -H construye la cabecera Host:
ffuf -w vhosts.txt \ -u http://TARGET_IP/ \ -H 'Host: FUZZ.DOMAIN'Ejecuta primero una muestra pequeña y observa qué propiedad separa una respuesta real del host por defecto. Después aplica un filtro explícito. Por ejemplo, -fs 4242 excluye cuerpos de 4242 bytes:
ffuf -w vhosts.txt \ -u http://TARGET_IP/ \ -H 'Host: FUZZ.DOMAIN' \ -fs 4242Un filtro demasiado amplio elimina hallazgos. Revisa los valores cercanos y valida cada candidato con curl.
Gobuster dispone de un modo específico. vhost selecciona ese modo, -u indica la URL, -w la wordlist y --append-domain convierte cada palabra en palabra.DOMAIN a partir del dominio de la URL:
gobuster vhost \ -u https://DOMAIN/ \ -w vhosts.txt \ --append-domainLa semántica de --append-domain cambió entre versiones antiguas. Comprueba gobuster vhost --help y registra la versión utilizada. La salida de la herramienta sigue necesitando comparación con la respuesta por defecto.
En Gobuster 3.8.2, --domain DOMAIN permite suministrar el sufijo cuando -u contiene una IP. --exclude-length descarta longitudes conocidas y --exclude-status descarta códigos. Cuando el servidor refleja el hostname solicitado, la longitud varía con cada palabra. --exclude-hostname-length intenta compensar esa variación y exige que también se defina --exclude-length. Sin esa referencia, Gobuster detiene la ejecución. Valida el cálculo con varios nombres aleatorios antes de confiar en él.
Los controles de ejecución son los mismos que en el modo dir. --threads fija concurrencia, --delay añade una espera por hilo y --timeout limita cada petición. --proxy permite observar los candidatos a través de HTTP(S) o SOCKS5. El siguiente perfil parte de una respuesta negativa ya medida:
gobuster vhost \ --url https://TARGET_IP/ \ --wordlist vhosts.txt \ --domain DOMAIN \ --append-domain \ --threads 8 \ --delay 250ms \ --timeout 10s \ --exclude-status 404 \ --exclude-length BASELINE_LENGTH \ --exclude-hostname-length \ --output evidence/gobuster-vhosts.txtLa URL por IP hace que el SNI inicial sea la IP. Si la infraestructura selecciona el certificado o la ruta antes de HTTP, esta prueba puede perder virtual hosts que funcionan con SNI correcto. Reproduce cada candidato mediante curl --resolve y compara esa respuesta con la que obtiene Gobuster. Si necesitas inspeccionar las peticiones, añade --proxy http://127.0.0.1:8080 después de preparar la escucha.
TLS, CDN y otros límites
Sección titulada «TLS, CDN y otros límites»Una conexión por IP puede llegar a una CDN o a un alojamiento compartido con miles de clientes. La respuesta predeterminada pertenece al intermediario, no necesariamente al sistema que buscas. También pueden aparecer:
- certificados wildcard que cubren muchos nombres sin confirmar aplicaciones
- backends que solo son alcanzables mediante una ruta o proxy concreto
- respuestas
421 Misdirected Requestcuando la conexión TLS no corresponde a la autoridad - WAF y rate limiting que cambian código o cuerpo después de varias peticiones
- DNS wildcard que hace resolver cualquier candidato
Compara una variable cada vez. Si cambia el nombre, conserva la dirección, el puerto, el esquema, la ruta y el origen. Cuando un candidato sea válido, añádelo al inventario con su resolución y continúa por fingerprinting y crawling.