mirror of
				https://github.com/HackTricks-wiki/hacktricks.git
				synced 2025-10-10 18:36:50 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			248 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
			
		
		
	
	
			248 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
| # En-têtes HTTP spéciaux
 | ||
| 
 | ||
| {{#include ../../banners/hacktricks-training.md}}
 | ||
| 
 | ||
| ## Listes de mots & Outils
 | ||
| 
 | ||
| - [https://github.com/danielmiessler/SecLists/tree/master/Miscellaneous/Web/http-request-headers](https://github.com/danielmiessler/SecLists/tree/master/Miscellaneous/Web/http-request-headers)
 | ||
| - [https://github.com/rfc-st/humble](https://github.com/rfc-st/humble)
 | ||
| 
 | ||
| ## En-têtes à modifier
 | ||
| 
 | ||
| Réécrire la **source IP** :
 | ||
| 
 | ||
| - `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` (Vérifier les en-têtes hop-by-hop)
 | ||
| 
 | ||
| Réécrire **l'emplacement** :
 | ||
| 
 | ||
| - `X-Original-URL: /admin/console`
 | ||
| - `X-Rewrite-URL: /admin/console`
 | ||
| 
 | ||
| ## En-têtes hop-by-hop
 | ||
| 
 | ||
| Un en-tête hop-by-hop est un en-tête conçu pour être traité et consommé par le proxy qui gère actuellement la requête, contrairement à un en-tête end-to-end.
 | ||
| 
 | ||
| - `Connection: close, X-Forwarded-For`
 | ||
| 
 | ||
| 
 | ||
| {{#ref}}
 | ||
| ../../pentesting-web/abusing-hop-by-hop-headers.md
 | ||
| {{#endref}}
 | ||
| 
 | ||
| ## HTTP Request Smuggling
 | ||
| 
 | ||
| - `Content-Length: 30`
 | ||
| - `Transfer-Encoding: chunked`
 | ||
| 
 | ||
| 
 | ||
| {{#ref}}
 | ||
| ../../pentesting-web/http-request-smuggling/
 | ||
| {{#endref}}
 | ||
| 
 | ||
| ## L'en-tête Expect
 | ||
| 
 | ||
| Il est possible que le client envoie l'en-tête `Expect: 100-continue` et que le serveur réponde `HTTP/1.1 100 Continue` pour permettre au client de continuer l'envoi du corps de la requête. Cependant, certains proxies n'aiment pas vraiment cet en-tête.
 | ||
| 
 | ||
| Résultats intéressants obtenus avec `Expect: 100-continue` :
 | ||
| - Envoyer une requête HEAD avec un corps : le serveur n'a pas tenu compte que les requêtes HEAD n'ont pas de corps et garde la connexion ouverte jusqu'à expiration du timeout.
 | ||
| - D'autres serveurs ont renvoyé des données étranges : des données aléatoires lues depuis le socket dans la réponse, des clés secrètes, ou cela a même permis d'empêcher le front-end de supprimer certaines valeurs d'en-tête.
 | ||
| - Cela a aussi causé une désynchronisation `0.CL` car le backend a répondu avec un 400 au lieu de 100, mais le proxy front-end était prêt à envoyer le corps de la requête initiale ; il l'envoie donc et le backend l'interprète comme une nouvelle requête.
 | ||
| - Envoyer une variation `Expect: y 100-continue` a aussi provoqué la désynchronisation `0.CL`.
 | ||
| - Une erreur similaire où le backend a répondu avec un 404 a généré une désynchronisation `CL.0` parce que la requête malveillante indiquait un `Content-Length`. Le backend envoie donc la requête malveillante + les octets correspondant au `Content-Length` de la requête suivante (d'une victim). Cela désynchronise la file : le backend envoie la réponse 404 pour la requête malveillante + la réponse de la requête de la victim, tandis que le front-end pensait qu'une seule requête avait été envoyée ; la seconde réponse est donc envoyée à une seconde requête victim et la réponse de celle-ci est envoyée à la suivante...
 | ||
| 
 | ||
| Pour plus d'infos sur HTTP Request Smuggling, consultez :
 | ||
| 
 | ||
| {{#ref}}
 | ||
| ../../pentesting-web/http-request-smuggling/
 | ||
| {{#endref}}
 | ||
| 
 | ||
| 
 | ||
| ## En-têtes de cache
 | ||
| 
 | ||
| **En-têtes de cache côté serveur** :
 | ||
| 
 | ||
| - **`X-Cache`** dans la réponse peut valoir **`miss`** lorsque la requête n'a pas été mise en cache et **`hit`** lorsqu'elle l'a été
 | ||
| - Comportement similaire pour l'en-tête **`Cf-Cache-Status`**
 | ||
| - **`Cache-Control`** indique si une ressource est mise en cache et quand elle expirera : `Cache-Control: public, max-age=1800`
 | ||
| - **`Vary`** est souvent utilisé dans la réponse pour **indiquer des en-têtes supplémentaires** qui sont traités comme **faisant partie de la clé de cache** même s'ils ne sont normalement pas pris en compte.
 | ||
| - **`Age`** définit le temps en secondes pendant lequel l'objet est resté dans le cache du proxy.
 | ||
| - **`Server-Timing: cdn-cache; desc=HIT`** indique aussi qu'une ressource a été mise en cache
 | ||
| 
 | ||
| 
 | ||
| {{#ref}}
 | ||
| ../../pentesting-web/cache-deception/
 | ||
| {{#endref}}
 | ||
| 
 | ||
| **En-têtes de cache local** :
 | ||
| 
 | ||
| - `Clear-Site-Data`: en-tête indiquant le cache à supprimer : `Clear-Site-Data: "cache", "cookies"`
 | ||
| - `Expires`: contient la date/heure à laquelle la réponse expire : `Expires: Wed, 21 Oct 2015 07:28:00 GMT`
 | ||
| - `Pragma: no-cache` identique à `Cache-Control: no-cache`
 | ||
| - `Warning`: l'en-tête HTTP générique `Warning` contient des informations sur d'éventuels problèmes liés au statut du message. Plusieurs en-têtes `Warning` peuvent apparaître dans une réponse. `Warning: 110 anderson/1.3.37 "Response is stale"`
 | ||
| 
 | ||
| ## Requêtes conditionnelles
 | ||
| 
 | ||
| - Les requêtes utilisant les en-têtes **`If-Modified-Since`** et **`If-Unmodified-Since`** recevront des données seulement si l'en-tête de réponse **`Last-Modified`** contient une heure différente.
 | ||
| - Les requêtes conditionnelles utilisant **`If-Match`** et **`If-None-Match`** se basent sur une valeur Etag : le serveur enverra le contenu si l'Etag a changé. L'`Etag` provient de la réponse HTTP.
 | ||
| - La valeur de l'**Etag** est généralement calculée à partir du **contenu** de la réponse. Par exemple, `ETag: W/"37-eL2g8DEyqntYlaLp5XLInBWsjWI"` indique que l'`Etag` est le **Sha1** de **37 octets**.
 | ||
| 
 | ||
| ## Requêtes Range
 | ||
| 
 | ||
| - **`Accept-Ranges`** : Indique si le serveur supporte les requêtes de plage, et si oui dans quelle unité la plage peut être exprimée. `Accept-Ranges: <range-unit>`
 | ||
| - **`Range`** : Indique la partie d'un document que le serveur doit renvoyer. Par exemple, `Range:80-100` renverra les octets 80 à 100 de la réponse originale avec un code 206 Partial Content. Pensez aussi à retirer l'en-tête `Accept-Encoding` de la requête.
 | ||
| - Cela peut être utile pour obtenir une réponse contenant du code javascript réfléchi arbitraire qui serait autrement échappé. Mais pour abuser de cela, il faut pouvoir injecter ces en-têtes dans la requête.
 | ||
| - **`If-Range`** : Crée une requête de plage conditionnelle qui n'est satisfaite que si l'etag ou la date fournie correspond à la ressource distante. Utilisé pour éviter de télécharger deux plages de versions incompatibles de la ressource.
 | ||
| - **`Content-Range`** : Indique où, dans un corps complet, un message partiel appartient.
 | ||
| 
 | ||
| ## Informations sur le corps du message
 | ||
| 
 | ||
| - **`Content-Length`:** La taille de la ressource, en nombre décimal d'octets.
 | ||
| - **`Content-Type`**: Indique le type media de la ressource
 | ||
| - **`Content-Encoding`**: Utilisé pour spécifier l'algorithme de compression.
 | ||
| - **`Content-Language`**: Décrit la ou les langues humaines destinées au public, permettant à un utilisateur de différencier selon ses préférences linguistiques.
 | ||
| - **`Content-Location`**: Indique un emplacement alternatif pour les données retournées.
 | ||
| 
 | ||
| D'un point de vue pentest, ces informations sont généralement « inutiles », mais si la ressource est **protégée** par un 401 ou 403 et que vous trouvez un **moyen** d'**obtenir** ces **info**, cela peut être **intéressant.**\
 | ||
| Par exemple, une combinaison de `Range` et `Etag` dans une requête HEAD peut leak le contenu de la page via des requêtes HEAD :
 | ||
| 
 | ||
| - Une requête avec l'en-tête `Range: bytes=20-20` et une réponse contenant `ETag: W/"1-eoGvPlkaxxP4HqHv6T3PNhV9g3Y"` leak que le SHA1 de l'octet 20 est `ETag: eoGvPlkaxxP4HqHv6T3PNhV9g3Y`
 | ||
| 
 | ||
| ## Infos serveur
 | ||
| 
 | ||
| - `Server: Apache/2.4.1 (Unix)`
 | ||
| - `X-Powered-By: PHP/5.3.3`
 | ||
| 
 | ||
| ## Contrôles
 | ||
| 
 | ||
| - **`Allow`**: Cet en-tête sert à communiquer les méthodes HTTP qu'une ressource peut gérer. Par exemple : `Allow: GET, POST, HEAD` indique que la ressource supporte ces méthodes.
 | ||
| - **`Expect`**: Utilisé par le client pour exprimer des attentes que le serveur doit satisfaire pour que la requête soit traitée avec succès. Un cas courant est `Expect: 100-continue`, qui signale que le client a l'intention d'envoyer une grande charge de données et attend une réponse `100 (Continue)` avant de procéder. Ce mécanisme aide à optimiser l'utilisation du réseau en attendant la confirmation du serveur.
 | ||
| 
 | ||
| ## Téléchargements
 | ||
| 
 | ||
| - L'en-tête **`Content-Disposition`** dans les réponses HTTP indique si un fichier doit être affiché **inline** (dans la page web) ou traité comme une **attachment** (téléchargé). Par exemple:
 | ||
| ```
 | ||
| Content-Disposition: attachment; filename="filename.jpg"
 | ||
| ```
 | ||
| Cela signifie que le fichier nommé "filename.jpg" est destiné à être téléchargé et enregistré.
 | ||
| 
 | ||
| ## En-têtes de sécurité
 | ||
| 
 | ||
| ### Politique de sécurité du contenu (CSP) <a href="#csp" id="csp"></a>
 | ||
| 
 | ||
| 
 | ||
| {{#ref}}
 | ||
| ../../pentesting-web/content-security-policy-csp-bypass/
 | ||
| {{#endref}}
 | ||
| 
 | ||
| ### **Trusted Types**
 | ||
| 
 | ||
| En appliquant Trusted Types via CSP, les applications peuvent être protégées contre les attaques DOM XSS. Trusted Types veillent à ce que seuls des objets spécifiquement conçus, conformes aux politiques de sécurité établies, puissent être utilisés dans des appels d'API web dangereux, sécurisant ainsi le code JavaScript par défaut.
 | ||
| ```javascript
 | ||
| // Feature detection
 | ||
| if (window.trustedTypes && trustedTypes.createPolicy) {
 | ||
| // Name and create a policy
 | ||
| const policy = trustedTypes.createPolicy('escapePolicy', {
 | ||
| createHTML: str => str.replace(/\</g, '<').replace(/>/g, '>');
 | ||
| });
 | ||
| }
 | ||
| ```
 | ||
| 
 | ||
| ```javascript
 | ||
| // 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**
 | ||
| 
 | ||
| Cet en-tête empêche le sniffing des types MIME, une pratique qui pourrait conduire à des vulnérabilités XSS. Il garantit que les navigateurs respectent les types MIME spécifiés par le serveur.
 | ||
| ```
 | ||
| X-Content-Type-Options: nosniff
 | ||
| ```
 | ||
| ### **X-Frame-Options**
 | ||
| 
 | ||
| Pour lutter contre le clickjacking, cet en-tête restreint la manière dont les documents peuvent être intégrés dans les balises `<frame>`, `<iframe>`, `<embed>` ou `<object>`, en recommandant que tous les documents spécifient explicitement leurs permissions d'intégration.
 | ||
| ```
 | ||
| X-Frame-Options: DENY
 | ||
| ```
 | ||
| ### **Cross-Origin Resource Policy (CORP) and Cross-Origin Resource Sharing (CORS)**
 | ||
| 
 | ||
| CORP est crucial pour spécifier quelles ressources peuvent être chargées par les sites web, atténuant les cross-site leaks. CORS, en revanche, permet un mécanisme de cross-origin resource sharing plus flexible, assouplissant la same-origin policy sous certaines conditions.
 | ||
| ```
 | ||
| Cross-Origin-Resource-Policy: same-origin
 | ||
| Access-Control-Allow-Origin: https://example.com
 | ||
| Access-Control-Allow-Credentials: true
 | ||
| ```
 | ||
| ### **Politique d'intégration inter-origines (COEP) et Politique d'ouverture inter-origines (COOP)**
 | ||
| 
 | ||
| COEP et COOP sont essentielles pour permettre l'isolation inter-origines, réduisant significativement le risque d'attaques de type Spectre. Elles contrôlent respectivement le chargement des ressources provenant d'autres origines et l'interaction avec les fenêtres provenant d'autres origines.
 | ||
| ```
 | ||
| Cross-Origin-Embedder-Policy: require-corp
 | ||
| Cross-Origin-Opener-Policy: same-origin-allow-popups
 | ||
| ```
 | ||
| ### **HTTP Strict Transport Security (HSTS)**
 | ||
| 
 | ||
| Enfin, HSTS est une fonctionnalité de sécurité qui oblige les navigateurs à communiquer avec les serveurs uniquement via des connexions HTTPS sécurisées, améliorant ainsi la confidentialité et la sécurité.
 | ||
| ```
 | ||
| Strict-Transport-Security: max-age=3153600
 | ||
| ```
 | ||
| ## Contournement de la casse des noms d'en-tête
 | ||
| 
 | ||
| HTTP/1.1 définit les noms de champs d'en-tête comme **insensibles à la casse** (RFC 9110 §5.1). Néanmoins, il est très courant de trouver des middlewares personnalisés, des filtres de sécurité ou de la logique métier qui comparent le nom d'en-tête *littéral* reçu sans normaliser la casse au préalable (par ex. `header.equals("CamelExecCommandExecutable")`). Si ces vérifications sont effectuées de manière **sensible à la casse**, un attaquant peut les contourner simplement en envoyant le même en-tête avec une capitalisation différente.
 | ||
| 
 | ||
| Typical situations where this mistake appears:
 | ||
| 
 | ||
| * Listes allow/deny personnalisées qui tentent de bloquer des en-têtes internes “dangereux” avant que la requête n'atteigne un composant sensible.
 | ||
| * Implémentations internes de pseudo-en-têtes de reverse-proxy (par ex. `X-Forwarded-For` sanitisation).
 | ||
| * Frameworks qui exposent des endpoints de management / debug et se reposent sur les noms d'en-tête pour l'authentification ou la sélection de commandes.
 | ||
| 
 | ||
| ### Exploiter le contournement
 | ||
| 
 | ||
| 1. Identifiez un en-tête qui est filtré ou validé côté serveur (par exemple, en lisant le code source, la documentation, ou les messages d'erreur).
 | ||
| 2. Envoyez le **même en-tête avec une casse différente** (mixte ou majuscules). Parce que les stacks HTTP canonisent généralement les en-têtes seulement *après* l'exécution du code utilisateur, la vérification vulnérable peut être ignorée.
 | ||
| 3. Si le composant en aval traite les en-têtes de façon insensible à la casse (la plupart le font), il acceptera la valeur contrôlée par l'attaquant.
 | ||
| 
 | ||
| ### Exemple : Apache Camel `exec` RCE (CVE-2025-27636)
 | ||
| 
 | ||
| Dans les versions vulnérables d'Apache Camel, les routes du *Command Center* tentent de bloquer les requêtes non fiables en supprimant les en-têtes `CamelExecCommandExecutable` et `CamelExecCommandArgs`. La comparaison était effectuée avec `equals()`, donc seuls les noms avec la casse exacte étaient supprimés.
 | ||
| ```bash
 | ||
| # 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: /"
 | ||
| ```
 | ||
| Les en-têtes atteignent le composant `exec` sans filtrage, entraînant une exécution de commandes à distance avec les privilèges du processus Camel.
 | ||
| 
 | ||
| ### Détection & atténuation
 | ||
| 
 | ||
| * Normalisez tous les noms d'en-tête sur une même casse (généralement en minuscules) **avant** d'effectuer les comparaisons allow/deny.
 | ||
| * Rejetez les doublons suspects : si `Header:` et `HeAdEr:` sont présents simultanément, considérez-le comme une anomalie.
 | ||
| * Utilisez une allow-list positive appliquée **après** la canonicalisation.
 | ||
| * Protégez les endpoints de gestion avec de l'authentification et une segmentation réseau.
 | ||
| 
 | ||
| 
 | ||
| ## Références
 | ||
| 
 | ||
| - [CVE-2025-27636 – RCE in Apache Camel via header casing bypass (OffSec blog)](https://www.offsec.com/blog/cve-2025-27636/)
 | ||
| - [https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition)
 | ||
| - [https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers)
 | ||
| - [https://web.dev/security-headers/](https://web.dev/security-headers/)
 | ||
| - [https://web.dev/articles/security-headers](https://web.dev/articles/security-headers)
 | ||
| 
 | ||
| {{#include ../../banners/hacktricks-training.md}}
 |