Contexte
La contrebande de requêtes HTTP est une technique malveillante qui perturbe le traitement des requêtes HTTP reçues d'un ou plusieurs utilisateurs sur un site Web, exposant ainsi des vulnérabilités critiques. Les attaquants peuvent exploiter ces vulnérabilités pour contourner les mesures de sécurité, accéder illégalement à des données sensibles et compromettre directement d'autres utilisateurs de l'application.
Les applications Web d'aujourd'hui utilisent souvent des chaînes de serveurs HTTP entre les utilisateurs et la logique d'application finale. Les utilisateurs envoient des demandes à un serveur frontal qui les transmet à un ou plusieurs serveurs en aval. Ce type d'architecture est de plus en plus courant et, dans certains cas, inévitable dans les applications modernes basées sur le cloud.
Lorsque le serveur frontal transmet les requêtes HTTP à un serveur en aval, il envoie généralement plusieurs requêtes sur la même connexion réseau sous-jacente, car cela est beaucoup plus efficace et performant. Le protocole est simple : les requêtes HTTP sont envoyées les unes après les autres, et le serveur de réception analyse les en-têtes de requête HTTP pour déterminer où se termine une requête et où commence la suivante.
Dans cette situation, il est crucial que les systèmes front-end et back-end établissent des limites claires entre les requêtes. Sans cela, un attaquant pourrait envoyer une requête ambiguë qui serait interprétée différemment par les systèmes front-end et back-end.
Lors d'une attaque de contrebande de demandes, l'attaquant manipule une partie de sa requête front-end pour qu'elle soit interprétée par le serveur principal comme le début de la requête suivante. Cette partie est ajoutée au début de la requête suivante, ce qui peut interférer avec la manière dont l'application traite cette requête. Les conséquences peuvent être désastreuses.
La plupart des vulnérabilités de contrebande de requêtes HTTP sont dues au fait que la spécification HTTP offre deux méthodes différentes pour définir où se termine une requête dans l'en-tête : Content-Length et Transfer-Encoding.
Content-Length est simple : il spécifie la longueur du corps du message en octets. Par exemple:
POST /search HTTP/1.1
Host: website.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 12
q=smuggling
Transfer-Encoding peut être utilisé pour indiquer que le corps du message utilise un encodage fragmenté. Cela signifie que le corps du message est constitué d'un ou plusieurs blocs de données, chaque bloc étant précédé de sa taille en octets (exprimée en hexadécimal), suivie d'une nouvelle ligne, puis du contenu du bloc. Le message se termine par un bloc de taille zéro. Voici un exemple :
POST /search HTTP/1.1
Host: website.com
Content-Type: application/x-www-form-urlencoded
Transfer-Encoding: chunked
a
q=smuggling
0
Étant donné que la spécification HTTP fournit deux méthodes différentes pour spécifier la longueur des messages HTTP, il est possible qu'un seul message utilise les deux méthodes à la fois, de sorte qu'elles entrent en conflit. La spécification HTTP tente d'éviter ce problème en indiquant que si les en-têtes Content-Length et Transfer-Encoding sont présents, l'en-tête Content-Length doit être ignoré. Cela peut être suffisant pour éviter toute ambiguïté lorsqu'un seul serveur est en jeu, mais pas lorsque deux serveurs ou plus sont enchaînés. Dans cette situation, des problèmes peuvent survenir pour deux raisons :
Certains serveurs ne prennent pas en charge l'en-tête Transfer-Encoding dans les requêtes. Certains serveurs qui prennent en charge l'en-tête Transfer-Encoding peuvent être incités à ne pas le traiter si l'en-tête est masqué d'une manière ou d'une autre. Si les serveurs frontend et principaux se comportent différemment par rapport à l'en-tête Transfer-Encoding (éventuellement obscurci), ils peuvent alors ne pas être d'accord sur les limites entre les requêtes successives, ce qui entraîne des vulnérabilités de contrebande de requêtes.
Comment ça marche
Les attaques de contrebande de requêtes impliquent de placer à la fois l'en-tête Content-Length et l'en-tête Transfer-Encoding dans une seule requête HTTP et de les manipuler de sorte que les serveurs frontend et principaux traitent la requête différemment. La manière exacte dont cela se fait dépend du comportement des deux serveurs :
- CL.TE : le serveur front-end utilise l'entête Content-Length et le serveur principal utilise l'entête Transfer-Encoding.
- TE.CL : le serveur front-end utilise l'entête Transfer-Encoding et le serveur principal utilise l'entête Content-Length.
- TE.TE: les serveurs front-end et principaux prennent tous deux en charge l'en-tête Transfer-Encoding, mais l'un des serveurs peut-être incité à ne pas le traiter en masquant l'en-tête d'une manière ou d'une autre.
CL.TE vulnerabilities
Ici, le serveur front-end utilise l'entête Content-Length et le serveur principal utilise l'entête Transfer-Encoding. Nous pouvons effectuer une simple attaque de contrebande de requêtes HTTP comme suit :
POST / HTTP/1.1
Host: website.com
Content-Length: 13
Transfer-Encoding: chunked
0
SMUGGLED
Le serveur front-end traite l'en-tête Content-Length et détermine que le corps de la requête a une longueur de 13 octets, jusqu'à la fin de SMUGGLED. Cette demande est transmise au serveur principal.
Le serveur principal traite l'en-tête Transfer-Encoding et traite donc le corps du message comme utilisant un codage fragmenté. Il traite le premier bloc, qui est déclaré être de longueur nulle, et est donc traité comme mettant fin à la demande. Les octets suivants, SMUGGLED, ne sont pas traités et le serveur principal les traitera comme étant le début de la requête suivante dans la séquence.
TE.CL Vulnerabilitées
Ici, le serveur front-end utilise l'entête Transfer-Encoding et le serveur principal utilise l'entête Content-Length. Nous pouvons effectuer une simple attaque de contrebande de requêtes HTTP comme suit :
POST / HTTP/1.1
Host: website.com
Content-Length: 3
Transfer-Encoding: chunked
8
SMUGGLED
0
Le serveur frontal traite l'en-tête Transfer-Encoding et traite donc le corps du message comme utilisant un codage fragmenté. Il traite le premier bloc, qui est censé avoir une longueur de 8 octets, jusqu'au début de la ligne suivant SMUGGLED. Il traite le deuxième bloc, qui est déclaré être de longueur nulle, et est donc traité comme mettant fin à la demande. Cette demande est transmise au serveur principal.
Le serveur principal traite l'en-tête Content-Length et détermine que le corps de la requête a une longueur de 3 octets, jusqu'au début de la ligne suivant 8. Les octets suivants, commençant par SMUGGLED, ne sont pas traités et le serveur principal les traitera comme étant le début de la requête suivante dans la séquence.
TE.TE vulnerabilities
Ici, les serveurs front-end et principaux prennent tous deux en charge l'en-tête Transfer-Encoding, mais l'un des serveurs peut être incité à ne pas le traiter en masquant l'en-tête d'une manière ou d'une autre. Il existe des façons potentiellement infinies d'obscurcir l'en-tête Transfer-Encoding. Par exemple :
Transfer-Encoding: xchunked
Transfer-Encoding : chunked
Transfer-Encoding: chunked
Transfer-Encoding: x
Transfer-Encoding:[tab]chunked
[space]Transfer-Encoding: chunked
X: X[\n]Transfer-Encoding: chunked
Transfer-Encoding
: chunked
Chacune de ces techniques implique une dérogation subtile à la spécification HTTP. Dans le monde réel, l'implémentation d'une spécification de protocole adhère rarement avec une précision absolue, et il est courant que différentes implémentations tolèrent des variations par rapport à la spécification. Pour découvrir une vulnérabilité TE.TE, il est nécessaire de trouver une variation de l'en-tête Transfer-Encoding telle qu'un seul des serveurs front-end ou principaux la traite, tandis que l'autre serveur l'ignore.
En fonction de si le serveur front-end ou le serveur back-end peut être amené à ne pas traiter l'en-tête Transfer-Encoding obfusqué, la suite de l'attaque prendra la même forme que pour les vulnérabilités CL.TE ou TE.CL déjà décrites.
Contrebande alimentée par le navigateur
Les techniques de contrebande de requêtes que vous avez apprises jusqu'à présent reposent sur l'envoi de requêtes intentionnellement malformées à l'aide d'outils de piratage dédiés. En fait, il est possible d'effectuer les mêmes attaques en utilisant des requêtes entièrement compatibles avec le navigateur qui désynchronisent les deux serveurs à l'aide d'un en-tête Content-Length parfaitement normal. Cela vous permet même de lancer des variantes côté client de ces attaques, qui incitent le navigateur de la victime à empoisonner sa propre connexion au site Web vulnérable. Non seulement cela expose les sites à serveur unique à des attaques de type contrebande, mais cela vous permet même d'attaquer des sites auxquels vous n'avez pas accès directement.
Comment empêcher les vulnérabilités
Pour éviter les vulnérabilités de contrebande de requêtes HTTP, il est recommandé d'adopter les mesures de haut niveau suivantes :
-
Utiliser HTTP/2 de bout en bout et désactiver la rétrogradation HTTP si possible. HTTP/2 utilise un mécanisme robuste pour déterminer la longueur des requêtes et, lorsqu'il est utilisé de bout en bout, est intrinsèquement protégé contre la contrebande de requêtes. Si la rétrogradation HTTP ne peut pas être évitée, il est important de valider la demande réécrite par rapport à la spécification HTTP/1.1 en rejetant les requêtes qui contiennent des retours à la ligne dans les en-têtes, des deux-points dans les noms d'en-tête et des espaces dans la méthode de requête.
-
Faire en sorte que le serveur frontal normalise les demandes ambiguës et que le serveur principal rejette celles qui sont encore ambiguës, fermant la connexion TCP dans le processus.
-
Ne jamais présumer que les requêtes n'auront pas de corps, car cela est la cause fondamentale des vulnérabilités de désynchronisation CL.0 et côté client.
-
Par défaut, ignorer la connexion si des exceptions au niveau du serveur sont déclenchées lors du traitement des demandes.
-
Si le trafic est acheminé via un proxy de transfert, s'assurer que HTTP/2 en amont est activé si possible.