Contrebande de requĂȘtes HTTP - nouvelles approches

Le 7 octobre 2019, le directeur de la recherche de PortSwigger (producteur de BurpSuite) a publiĂ© une Ă©tude sur les nouvelles approches de la contrebande de requĂȘtes HTTP. Avec leur aide, il a gagnĂ© environ 70 000 $ en bugbounty. Dans cet article, nous dĂ©couvrons briĂšvement l'essence de l'attaque, des outils et Ă©galement des mĂ©thodes de recherche de serveurs Web vulnĂ©rables Ă  cette vulnĂ©rabilitĂ©.


Qu'est-ce que la contrebande de requĂȘtes HTTP


Contrebande de requĂȘte HTTP - une attaque visant Ă  dĂ©synchroniser le frontend du serveur web et le backend du serveur web, Ă  la suite de quoi un attaquant pourrait faire passer clandestinement une requĂȘte HTTP devant le serveur frontend. L'image de l'article original sert de bonne dĂ©monstration:


image


Une telle attaque peut entraßner diverses conséquences - introduction de XSS dans la session d'autres utilisateurs, redirection des utilisateurs vers des ressources tierces, empoisonnement du cache du serveur, similitude avec SSRF et plusieurs autres.


Dans l'Incarnation de la contrebande 2019 de 2019, James Kettle a exploitĂ© un traitement d'en-tĂȘte de serveur Web incorrect


Transfer-Encoding: chunked 

indiquant que le corps du message sera transmis par parties ( RFC ). Étant donnĂ© que certains serveurs Web ne prennent pas en charge la transmission par blocs ou ne gĂšrent pas l'en-tĂȘte diffĂ©remment, le frontend ne «verra» qu'une seule demande et le backend la reconnaĂźtra comme deux. Plus de dĂ©tails sur les dĂ©tails de l'attaque peuvent ĂȘtre trouvĂ©s dans l' article d'origine , il y a aussi une tĂąche pratique sur laquelle vous pouvez vous entraĂźner pour trouver la vulnĂ©rabilitĂ© manuellement.


Pour une recherche rapide, James a développé un plug-in pour BurpSuit, qui reçoit une demande d'entrée et crée une note sur la vulnérabilité du service (le cas échéant) à la sortie.


Exemples de serveurs Web vulnérables


Je dois dire que le problÚme de la contrebande et d'autres vulnérabilités liées au fonctionnement des serveurs Web a longtemps été traité par un autre chercheur sous le surnom de regilero . Au cours des trois derniÚres années, il a publié trois articles décrivant les vulnérabilités qu'il a trouvées dans les serveurs Web populaires, dont la plupart se voient attribuer des CVE de criticité moyenne et élevée. Parmi les serveurs vulnérables figurent Apache Traffic Server, Jetty, Apsis.


Dans le sillage de l'intĂ©rĂȘt pour le problĂšme, un autre chercheur, Nathan Davison, a dĂ©couvert une vulnĂ©rabilitĂ© dans HAProxy, qui ignorait un en-tĂȘte incorrectement formĂ©.


 Transfer-Encoding:[\x0b]chunked 

et l'a converti sous la forme suivante:


 Transfer-Encoding: chunked 

Mais le serveur principal - gunicorn, mandatant l'application sur Flask, a lu l'en-tĂȘte, ce qui a provoquĂ© la vulnĂ©rabilitĂ©.


Un peu plus tard, un certain nombre d'autres chercheurs ont dĂ©couvert une vulnĂ©rabilitĂ© (affectĂ©e CVE-2019-16276) dans la mise en Ɠuvre du serveur http golang - le serveur normalisait l'en-tĂȘte s'il y avait un espace avant le prĂ©lude.
Demande:


image


AprĂšs traitement par le serveur:


image


La vulnĂ©rabilitĂ© pourrait ĂȘtre exploitĂ©e si le serveur frontal ignorait l'en-tĂȘte avec un espace et utilisait Content-Length pour calculer la taille de la demande.


Le serveur Web Caddy Ă©crit en Go Ă©tait Ă©galement vulnĂ©rable car il utilisait la mĂȘme bibliothĂšque net / http. Les dĂ©veloppeurs ont confirmĂ© qu'aprĂšs la mise Ă  jour de GO et la reconstruction du package, le problĂšme disparaĂźt.


L'auteur de cet article a trouvĂ© un problĂšme similaire sur le serveur lighthttpd (aucun CVE n'a Ă©tĂ© attribuĂ©). La capture d'Ă©cran montre que le serveur accepte et traite l'en-tĂȘte contenant un espace:


image


Les dĂ©veloppeurs ne sont pas tout Ă  fait d'accord avec la RFC 7230 (et l'auteur aussi) et pensent que la responsabilitĂ© du traitement incorrect des en-tĂȘtes incombe aux mandataires qui transmettent les demandes sans les normaliser et les vĂ©rifier. Cependant, le bug sera corrigĂ© dans la nouvelle version:


Par dĂ©faut, lighttpd analyse (et normalise) les requĂȘtes avant de les renvoyer par proxy aux backends. Cela contrecarre les attaques mentionnĂ©es dans https://portswigger.net/research/http-desync-attacks-request-smuggling-reborn aux serveurs en amont de lighttpd.
Cependant, comme mentionné par stbuehler ci-dessus, les proxys en aval de lighttpd peuvent transmettre n'importe quoi à lighttpd.
La modification qui sera apportĂ©e dans la prochaine version de lighttpd consistera Ă  rejeter les demandes avec espace ou tabulation aprĂšs le nom du champ et avant les deux-points, mais uniquement lorsque lighttpd est configurĂ© en mode (par dĂ©faut) de l'analyse stricte de l'en-tĂȘte http.

Le mĂȘme bogue a Ă©tĂ© trouvĂ© sur le serveur Web cheroot utilisĂ© par le framework cherrypy. Ce mini-framework se retrouve dans les startups, il est souvent utilisĂ© pour Ă©crire des API. Le rapport de bogue se bloque dans l'Ă©tat ouvert.


Conditions nécessaires et suffisantes pour la vulnérabilité


Quelles sont donc les conditions nécessaires pour vérifier et exploiter la vulnérabilité:


  • Demande POST. Bien que la RFC n'interdise pas explicitement l'utilisation des en-tĂȘtes Content-Length et Transfer-Encoding pour les requĂȘtes GET, en fait, ils ne sont utilisĂ©s que dans les requĂȘtes POST.
  • La prĂ©sence de serveurs frontaux et principaux - s'il n'y en a pas, il n'y aura rien Ă  synchroniser.
  • Les serveurs Web doivent analyser diffĂ©remment l'en-tĂȘte Transfer-Encoding, c'est-Ă -dire qu'il faut le "lire" et le second doit ĂȘtre ignorĂ©.

Essais en laboratoire


Pour une meilleure compréhension et dépannage des serveurs Web et des proxys existants, il est judicieux de déployer un environnement de test localement à l'aide de Docker.


Un exemple de diagramme d'environnement de test:


image


Code d'application:


 from flask import Flask, request, jsonify app = Flask(__name__) @app.route('/', methods=['GET', 'POST']) def main(): # the next line is required for Transfer-Encoding support in the request request.environ['wsgi.input_terminated'] = True headers = {} for header in request.headers: headers[header[0]] = header[1] print (request.data) print (headers) return jsonify(body=str(request.data), headers=headers) 

Fichier avec les paramĂštres frontaux, par exemple, caddy:


 localhost:80 log ../access.log proxy / host.docker.internal:8888 

Alors tout est simple, lancez l'application:


 gunicorn --keep-alive 10 -k gevent --bind 0.0.0.0:8888 -w 4 backend:app 

Et conteneur:


 docker run -d -t --name caddy -p 80:80 -p 443:443 -v /Users/sun/work/caddyfile:/etc/Caddyfile abiosoft/caddy:latest 

À partir du magasin Burp, nous installons HTTP Request Smuggler et Logger ++ pour faciliter le dĂ©bogage. Ensuite, dans Repeater, nous formons une demande simple, par exemple ceci:


 POST / HTTP/1.1 Host: localhost Content-Length: 8 Connection: close body=123 

Et envoyez-le pour vérifier que tout est correctement configuré:


 HTTP/1.1 200 OK Content-Length: 202 Content-Type: application/json Date: Mon, 07 Oct 2019 13:17:18 GMT Server: Caddy Server: gunicorn/19.9.0 Connection: close {"body":"b'body=123'","headers":{"Accept-Encoding":"gzip","Connection":"close","Content-Length":"8","Host":"host.docker.internal:8888","User-Agent":"Go-http-client/1.1","X-Forwarded-For":"172.17.0.1"}} 

Lancez maintenant Launch Smuggle Probe et regardez les réponses.


image


Le plus intéressant commence à ce moment. Il est nécessaire d'analyser les demandes et les réponses pour comprendre si les services sont vulnérables ou non. Cette partie est laissée au lecteur curieux.

Source: https://habr.com/ru/post/fr468489/


All Articles