Cabeceras HTTP especiales

Tip

Aprende y practica Hacking en AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica Hacking en GCP: HackTricks Training GCP Red Team Expert (GRTE) Aprende y practica Hacking en Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Apoya a HackTricks

Wordlists & Tools

Encabezados para cambiar ubicación

Reescribir IP de origen:

  • X-Originating-IP: 127.0.0.1
  • X-Forwarded-For: 127.0.0.1
  • X-Forwarded: 127.0.0.1
  • Forwarded-For: 127.0.0.1
  • X-Forwarded-Host: 127.0.0.1
  • X-Remote-IP: 127.0.0.1
  • X-Remote-Addr: 127.0.0.1
  • X-ProxyUser-Ip: 127.0.0.1
  • X-Original-URL: 127.0.0.1
  • Client-IP: 127.0.0.1
  • X-Client-IP: 127.0.0.1
  • X-Host: 127.0.0.1
  • True-Client-IP: 127.0.0.1
  • Cluster-Client-IP: 127.0.0.1
  • Via: 1.0 fred, 1.1 127.0.0.1
  • Connection: close, X-Forwarded-For (Revisar hop-by-hop headers)

Reescribir ubicación:

  • X-Original-URL: /admin/console
  • X-Rewrite-URL: /admin/console

Cabeceras hop-by-hop

Una cabecera hop-by-hop es una cabecera diseñada para ser procesada y consumida por el proxy que maneja actualmente la petición, a diferencia de una cabecera end-to-end.

  • Connection: close, X-Forwarded-For

hop-by-hop headers

HTTP Request Smuggling

  • Content-Length: 30
  • Transfer-Encoding: chunked

HTTP Request Smuggling / HTTP Desync Attack

El encabezado Expect

Es posible que el cliente envíe la cabecera Expect: 100-continue y que el servidor responda con HTTP/1.1 100 Continue para permitir que el cliente continúe enviando el body de la petición. Sin embargo, algunos proxies no manejan bien esta cabecera.

Resultados interesantes de Expect: 100-continue:

  • Enviar una petición HEAD con body: el servidor no tuvo en cuenta que las peticiones HEAD no deberían tener body y mantiene la conexión abierta hasta que expira el timeout.
  • Algunos servidores respondieron con datos extraños: datos aleatorios leídos del socket en la respuesta, claves secretas o incluso permitió evitar que el front-end eliminara valores de cabeceras.
  • También causó un desync 0.CL porque el backend respondió con un 400 en lugar de un 100, pero el proxy front-end estaba preparado para enviar el body de la petición inicial, así que lo envía y el backend lo toma como una nueva petición.
  • Enviar una variación como Expect: y 100-continue también causó el desync 0.CL.
  • Un error similar donde el backend respondió con un 404 generó un desync CL.0 porque la petición maliciosa indicaba un Content-Length, por lo que el backend envía la petición maliciosa + los bytes del Content-Length de la siguiente petición (de una víctima); esto desincroniza la cola porque el backend envía la respuesta 404 para la petición maliciosa + la respuesta de la petición de la víctima, pero el front-end pensó que solo se envió 1 petición, así que la segunda respuesta se envía a una segunda víctima y la respuesta de esa va a la siguiente…

Para más info sobre HTTP Request Smuggling consulta:

HTTP Request Smuggling / HTTP Desync Attack

Encabezados de caché

Server Cache Headers:

  • X-Cache en la respuesta puede tener el valor miss cuando la petición no estuvo en caché y el valor hit cuando está cacheada.
  • Comportamiento similar en la cabecera Cf-Cache-Status.
  • Cache-Control indica si un recurso está siendo cacheado y cuándo volverá a estarlo: Cache-Control: public, max-age=1800
  • Vary se usa a menudo en la respuesta para indicar cabeceras adicionales que se tratan como parte de la clave de caché incluso si normalmente no se consideran.
  • Age define el tiempo en segundos que el objeto ha estado en la caché del proxy.
  • Server-Timing: cdn-cache; desc=HIT también indica que un recurso fue cacheado.

Cache Poisoning and Cache Deception

Local Cache headers:

  • Clear-Site-Data: Cabecera para indicar la caché que debe eliminarse: Clear-Site-Data: "cache", "cookies"
  • Expires: Contiene la fecha/hora cuando la respuesta debe expirar: Expires: Wed, 21 Oct 2015 07:28:00 GMT
  • Pragma: no-cache igual que Cache-Control: no-cache
  • Warning: La cabecera general HTTP Warning contiene información sobre posibles problemas con el estado del mensaje. Puede aparecer más de una cabecera Warning en una respuesta. Warning: 110 anderson/1.3.37 "Response is stale"

Condicionales

  • Las peticiones que usan las cabeceras If-Modified-Since y If-Unmodified-Since serán respondidas con datos solo si la cabecera de respuesta Last-Modified contiene una hora diferente.
  • Las peticiones condicionales usando If-Match y If-None-Match usan un valor ETag para que el servidor solo envíe el contenido si el dato (Etag) ha cambiado. El Etag se toma de la respuesta HTTP.
  • El valor Etag suele calcularse en base al contenido de la respuesta. Por ejemplo, ETag: W/"37-eL2g8DEyqntYlaLp5XLInBWsjWI" indica que el Etag es el sha1 de 37 bytes.

Solicitudes de rango

  • Accept-Ranges: Indica si el servidor soporta range requests, y si es así en qué unidad se puede expresar el rango. Accept-Ranges: <range-unit>
  • Range: Indica la parte de un documento que el servidor debe devolver. Por ejemplo, Range:80-100 devolverá los bytes 80 a 100 de la respuesta original con un código 206 Partial Content. También recuerda eliminar la cabecera Accept-Encoding de la petición.
  • Esto puede ser útil para obtener una respuesta con código JavaScript reflejado arbitrario que de otro modo podría ser escapado. Pero para abusar de esto necesitarías inyectar estas cabeceras en la petición.
  • If-Range: Crea una petición de rango condicional que solo se satisface si el etag o la fecha dada coincide con el recurso remoto. Se usa para evitar descargar dos ranges de versiones incompatibles del recurso.
  • Content-Range: Indica dónde pertenece un mensaje parcial dentro de un body completo.

Información del body del mensaje

  • Content-Length: El tamaño del recurso, en número decimal de bytes.
  • Content-Type: Indica el media type del recurso.
  • Content-Encoding: Usado para especificar el algoritmo de compresión.
  • Content-Language: Describe el(los) idioma(s) humano(s) al que va dirigido, para que el usuario pueda diferenciar según sus preferencias.
  • Content-Location: Indica una ubicación alternativa para los datos devueltos.

Desde un punto de vista de pentest esta información suele ser “inútil”, pero si el recurso está protegido por un 401 o 403 y puedes encontrar alguna forma de obtener esta info, esto podría ser interesante.
Por ejemplo, una combinación de Range y Etag en una petición HEAD puede leak the content of the page via HEAD requests:

  • Una petición con la cabecera Range: bytes=20-20 y con una respuesta que contiene ETag: W/"1-eoGvPlkaxxP4HqHv6T3PNhV9g3Y" está leaking que el SHA1 del byte 20 es ETag: eoGvPlkaxxP4HqHv6T3PNhV9g3Y

Información del servidor

  • Server: Apache/2.4.1 (Unix)
  • X-Powered-By: PHP/5.3.3

Controles

  • Allow: Esta cabecera se usa para comunicar los métodos HTTP que un recurso puede manejar. Por ejemplo, puede aparecer como Allow: GET, POST, HEAD, indicando que el recurso soporta esos métodos.
  • Expect: Utilizado por el cliente para transmitir expectativas que el servidor debe cumplir para que la petición se procese correctamente. Un caso de uso común es la cabecera Expect: 100-continue, que indica que el cliente planea enviar una gran carga de datos. El cliente espera una respuesta 100 (Continue) antes de proceder con la transmisión. Este mecanismo ayuda a optimizar el uso de la red al esperar la confirmación del servidor.

Descargas

  • La cabecera Content-Disposition en las respuestas HTTP indica si un archivo debe mostrarse inline (dentro de la página) o tratarse como un attachment (descargado). Por ejemplo:
Content-Disposition: attachment; filename="filename.jpg"

Esto significa que el archivo llamado “filename.jpg” está destinado a ser descargado y guardado.

Encabezados de seguridad

Política de Seguridad de Contenido (CSP)

Content Security Policy (CSP) Bypass

Trusted Types

Al aplicar Trusted Types mediante CSP, las aplicaciones pueden protegerse contra ataques DOM XSS. Trusted Types garantizan que solo objetos específicamente creados, conformes con políticas de seguridad establecidas, puedan usarse en llamadas a APIs web peligrosas, asegurando así el código JavaScript por defecto.

// Feature detection
if (window.trustedTypes && trustedTypes.createPolicy) {
// Name and create a policy
const policy = trustedTypes.createPolicy('escapePolicy', {
createHTML: str => str.replace(/\</g, '&lt;').replace(/>/g, '&gt;');
});
}
// Assignment of raw strings is blocked, ensuring safety.
el.innerHTML = "some string" // Throws an exception.
const escaped = policy.createHTML("<img src=x onerror=alert(1)>")
el.innerHTML = escaped // Results in safe assignment.

X-Content-Type-Options

Este header previene el sniffing de tipos MIME, una práctica que podría llevar a vulnerabilidades XSS. Asegura que los navegadores respeten los tipos MIME especificados por el servidor.

X-Content-Type-Options: nosniff

X-Frame-Options

Para combatir el clickjacking, esta cabecera restringe cómo se pueden incrustar los documentos en las etiquetas <frame>, <iframe>, <embed> o <object>, recomendando que todos los documentos especifiquen explícitamente sus permisos de inclusión.

X-Frame-Options: DENY

Cross-Origin Resource Policy (CORP) and Cross-Origin Resource Sharing (CORS)

CORP es crucial para especificar qué recursos pueden ser cargados por los sitios web, mitigando los cross-site leaks. CORS, por otro lado, permite un mecanismo más flexible de compartición de recursos entre orígenes, relajando la política de mismo origen bajo ciertas condiciones.

Cross-Origin-Resource-Policy: same-origin
Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Credentials: true

Cross-Origin Embedder Policy (COEP) y Cross-Origin Opener Policy (COOP)

COEP y COOP son esenciales para habilitar el aislamiento entre orígenes, reduciendo significativamente el riesgo de ataques tipo Spectre. Controlan, respectivamente, la carga de recursos entre orígenes y la interacción con ventanas entre orígenes.

Cross-Origin-Embedder-Policy: require-corp
Cross-Origin-Opener-Policy: same-origin-allow-popups

HTTP Strict Transport Security (HSTS)

Por último, HSTS es una característica de seguridad que obliga a los navegadores a comunicarse con los servidores únicamente a través de conexiones HTTPS seguras, mejorando así la privacidad y la seguridad.

Strict-Transport-Security: max-age=3153600

Permissions-Policy (formerly Feature-Policy)

Permissions-Policy permite a los desarrolladores web habilitar, deshabilitar o modificar selectivamente el comportamiento de ciertas características del navegador y APIs dentro de un documento. Es el sucesor del encabezado Feature-Policy, ahora obsoleto. Este encabezado ayuda a reducir la superficie de ataque al restringir el acceso a funciones potentes que podrían ser abusadas.

Permissions-Policy: geolocation=(), camera=(), microphone=()

Directivas comunes:

DirectiveDescripción
accelerometerControla el acceso al sensor de acelerómetro
cameraControla el acceso a dispositivos de entrada de vídeo (cámara web)
geolocationControla el acceso a la API de Geolocation
gyroscopeControla el acceso al sensor de giroscopio
magnetometerControla el acceso al sensor de magnetómetro
microphoneControla el acceso a dispositivos de entrada de audio
paymentControla el acceso a la Payment Request API
usbControla el acceso a la WebUSB API
fullscreenControla el acceso a la Fullscreen API
autoplayControla si los medios pueden reproducirse automáticamente
clipboard-readControla el acceso para leer el contenido del portapapeles
clipboard-writeControla el acceso para escribir en el portapapeles

Valores de sintaxis:

  • () - Desactiva la característica por completo
  • (self) - Permite la característica solo para el mismo origen
  • * - Permite la característica para todos los orígenes
  • (self "https://example.com") - Permite para el mismo origen y el dominio especificado

Configuraciones de ejemplo:

# Restrictive policy - disable most features
Permissions-Policy: geolocation=(), camera=(), microphone=(), payment=(), usb=()

# Allow camera only from same origin
Permissions-Policy: camera=(self)

# Allow geolocation for same origin and a trusted partner
Permissions-Policy: geolocation=(self "https://maps.example.com")

Desde una perspectiva de seguridad, la ausencia o una configuración demasiado permisiva de la cabecera Permissions-Policy puede permitir a atacantes (por ejemplo, mediante XSS o iframes embebidos) abusar de funciones potentes del navegador. Restringe siempre las funciones al mínimo necesario para tu aplicación.

Bypass por mayúsculas/minúsculas en nombres de cabecera

HTTP/1.1 define los nombres de campo de cabecera como insensibles a mayúsculas/minúsculas (RFC 9110 §5.1). No obstante, es muy común encontrar middleware personalizado, filtros de seguridad o lógica de negocio que comparan el nombre literal de la cabecera recibida sin normalizar primero el uso de mayúsculas/minúsculas (p. ej., header.equals("CamelExecCommandExecutable")). Si esas comprobaciones se realizan de forma sensible a mayúsculas/minúsculas, un atacante puede eludirlas simplemente enviando la misma cabecera con una capitalización diferente.

Situaciones típicas en las que aparece este error:

  • Listas personalizadas de allow/deny que intentan bloquear cabeceras internas “peligrosas” antes de que la petición alcance un componente sensible.
  • Implementaciones internas de pseudo-cabeceras de reverse-proxy (p. ej., saneamiento de X-Forwarded-For).
  • Frameworks que exponen endpoints de gestión/depuración y que confían en los nombres de cabecera para autenticación o selección de comandos.

Explotación del bypass

  1. Identifica una cabecera que sea filtrada o validada en el servidor (por ejemplo, leyendo código fuente, documentación o mensajes de error).
  2. Envía la misma cabecera con una capitalización diferente (con mezcla de mayúsculas/minúsculas o todo en mayúsculas). Debido a que las pilas HTTP suelen canonizar las cabeceras solo después de que se ejecute el código del usuario, la comprobación vulnerable puede ser evitada.
  3. Si el componente aguas abajo trata las cabeceras de forma insensible a mayúsculas/minúsculas (la mayoría lo hace), aceptará el valor controlado por el atacante.

Ejemplo: Apache Camel exec RCE (CVE-2025-27636)

En versiones vulnerables de Apache Camel, las rutas Command Center intentan bloquear solicitudes no confiables eliminando las cabeceras CamelExecCommandExecutable y CamelExecCommandArgs. La comparación se hacía con equals(), por lo que solo se eliminaban los nombres exactamente en minúsculas.

# Bypass the filter by using mixed-case header names and execute `ls /` on the host
curl "http://<IP>/command-center" \
-H "CAmelExecCommandExecutable: ls" \
-H "CAmelExecCommandArgs: /"

Los encabezados llegan al componente exec sin filtrarse, resultando en ejecución remota de comandos con los privilegios del proceso Camel.

Detección & Mitigación

  • Normalizar todos los nombres de encabezado a un único caso (usualmente lowercase) antes de realizar comparaciones allow/deny.
  • Rechazar duplicados sospechosos: si tanto Header: como HeAdEr: están presentes, considerarlo una anomalía.
  • Usar una allow-list positiva aplicada después de la canonicalisation.
  • Proteger los endpoints de gestión con autenticación y segmentación de red.

Referencias

Tip

Aprende y practica Hacking en AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica Hacking en GCP: HackTricks Training GCP Red Team Expert (GRTE) Aprende y practica Hacking en Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Apoya a HackTricks