
Framework de tests différentiels pour implémentations HTTP
Le HTTP Garden est un ensemble de serveurs et de proxys HTTP configurés pour être composables, accompagné de scripts permettant d'interagir avec eux d'une manière qui rend la recherche de vulnérabilités beaucoup, beaucoup plus facile. Pour quelques démos sympas des vulnérabilités que vous pouvez trouver avec le HTTP Garden, regardez notre conférence ShmooCon 2024.
Nous tenons à remercier nos amis de Galois, Trail of Bits, Narf Industries et Dartmouth College pour avoir rendu ce projet possible.
Ce travail a été réalisé grâce au soutien de la Defense Advanced Research Projects Agency (DARPA) dans le cadre du contrat n° HR0011-19-C-0076.
pip) ou depuis le gestionnaire de paquets de votre système :docker
pyyaml
tqdm
Si vous installez les paquets Python avec le gestionnaire de paquets de votre système, sachez que les noms des paquets peuvent nécessiter d'être préfixés par py3-, python3- ou python-, selon le système.
./garden.sh start --build gunicorn hyper nginx haproxy
./garden.sh repl
garden> payload 'GET / HTTP/1.1\r\nHOST: a\r\n\r\n' | transduce haproxy | fanout | grid
'GET / HTTP/1.1\r\nHOST: a\r\n\r\n'
⬇️ haproxy
'GET / HTTP/1.1\r\nhost: a\r\n\r\n'
gunicorn: [
HTTPRequest(
method=b'GET', uri=b'/', version=b'1.1',
headers=[
(b'host', b'a'),
],
body=b'',
),
]
hyper: [
HTTPRequest(
method=b'GET', uri=b'/', version=b'1.1',
headers=[
(b'host', b'a'),
],
body=b'',
),
]
nginx: [
HTTPRequest(
method=b'GET', uri=b'/', version=b'1.1',
headers=[
(b'host', b'a'),
(b'content-length', b''),
(b'content-type', b''),
],
body=b'',
),
]
g
u
n
i h n
c y g
o p i
r e n
n r x
+-----
gunicorn|✓ ✓ ✓
hyper | ✓ ✓
nginx | ✓
Il semble qu'ils soient tous d'accord. (Notez que même si Nginx a ajouté les en-têtes content-length et content-type, le Garden en est conscient et ne laisse pas cette divergence insignifiante apparaître dans la sortie grid.)
Essayons une charge utile qui utilise une fin de ligne LF nue dans un corps de message fragmenté (chunked). C'est interdit par la spécification.
garden> payload 'POST / HTTP/1.1\r\nHost: a\r\nTransfer-Encoding: chunked\r\n\r\n0\n\r\n' | fanout | grid
gunicorn: [
HTTPResponse(version=b'1.1', method=b'400', reason=b'Bad Request'),
]
hyper: [
]
nginx: [
HTTPRequest(
method=b'POST', uri=b'/', version=b'1.1',
headers=[
(b'transfer-encoding', b'chunked'),
(b'host', b'a'),
(b'content-length', b'0'),
(b'content-type', b''),
],
body=b'',
),
]
g
u
n
i h n
c y g
o p i
r e n
n r x
+-----
gunicorn|✓ ✓ X
hyper | ✓ X
nginx | ✓
Bon, Gunicorn a répondu 400, Hyper n'a pas répondu, et Nginx a accepté. C'est une violation de la spécification par les auteurs de Nginx, qu'ils ne se soucient pas de corriger.
Vous avez peut-être aussi remarqué que même si Gunicorn et Hyper n'avaient pas exactement la même réponse, ils apparaissaient comme étant d'accord dans la sortie grid précédente.
C'est parce que leurs réponses sont essentiellement équivalentes (un rejet du message), et le Garden en tient compte.
imagesLe répertoire images contient un sous-répertoire pour chaque serveur HTTP et transducteur du Garden.
Chaque cible possède sa propre image Docker.
Tous les programmes sont compilés à partir des sources lorsque c'est possible.
Afin de pouvoir facilement construire plusieurs versions de chaque cible, toutes les cibles sont paramétrées avec une URL de dépôt (APP_REPO), un nom de branche (APP_BRANCH) et un hash de commit (APP_VERSION).
toolsLe répertoire tools contient les scripts utilisés pour interagir avec les serveurs. Vous y trouverez :
probe_quirks.py : un script pour énumérer les particularités bénignes du parsing HTTP des systèmes testés, à ignorer lors du fuzzing,repl.py : l'interface utilisateur principale du HTTP Garden,update.py : un script pour mettre à jour les hash de commit dans docker-compose.yml,|-| | aiohttp | | apache_httpd | | apache_tomcat | | appweb | | aws_c_http | | cpp_httplib | | eclipse_grizzly | | eclipse_jetty | | fasthttp | | go_stdlib | | gunicorn | | h2o | | haproxy_fcgi | | hyper | | hypercorn | | ktor | | libevent | | libmicrohttpd | | libsoup | | lighttpd | | mongoose | | netty | | nginx | | node_stdlib | | openbsd_httpd | | openlitespeed | | openwrt_uhttpd | | protocol_http1 | | puma | | tornado | | | | | | | | | | | | |
|-| | apache_httpd_proxy | | apache_traffic_server | | envoy | | go_stdlib_proxy | | h2o_proxy | | haproxy | | lighttpd_proxy | | nghttpx | | nginx_proxy | | openlitespeed_proxy | | pound | | squid | | varnish | | yahns_proxy |
Voici les explications pour quelques omissions notables du Garden :
Voir TROPHIES.md pour une liste complète des bogues que le Garden a trouvés.
| Nom | Justification |
|---|
| Tout ce qui vient de Microsoft | MSRC nous a dit que « HTTP smuggling n'est pas considéré comme une vulnérabilité », et je ne ressens pas particulièrement le besoin d'aider Microsoft. |
| unicorn | Utilise le même parseur HTTP que yahns. |
| SwiftNIO | Utilise llhttp pour le parsing HTTP, qui est déjà couvert par node_stdlib. |
| Bun | Utilise picohttpparser pour le parsing HTTP, qui est déjà couvert par h2o. |
| Deno | Utilise hyper pour le parsing HTTP, qui est déjà dans le Garden. |
| Daphne | Utilise twisted pour le parsing HTTP, qui est déjà dans le Garden. |
| pitchfork | Utilise le même parseur que yahns. |
| nghttpx | Utilise lhttp pour le parsing HTTP, qui est déjà couvert par node_stdlib. |
| Cheroot | Ignore nos signalements. |
| CherryPy | Utilise cheroot pour le parsing HTTP. |
| libhttpserver | Utilise libmicrohttpd pour le parsing HTTP, qui est déjà dans le Garden. |
| Werkzeug | Utilise la bibliothèque standard CPython pour le parsing HTTP, qui est déjà dans le Garden. |
| Caddy | Utilise la bibliothèque standard Go pour le parsing HTTP, qui est déjà dans le Garden. |
| Tengine | Utilise le parseur HTTP de Nginx. |
| OpenResty | Utilise le parseur HTTP de Nginx. |
| Google Cloud Global External Application Load Balancer | Basé sur Envoy. |
| Google Cloud Regional External Application Load Balancer | Basé sur Envoy. |
| Phusion Passenger | Utilise llhttpd pour le parsing HTTP, qui est déjà couvert par node_stdlib. |
| passim | Utilise libsoup pour le parsing HTTP, qui est déjà dans le Garden. |
| boa | Non maintenu. |
| Ulfius | Utilise libmicrohttpd, qui est déjà dans le Garden. |
| Vultr Load Balancer | C'est tout simplement HAProxy, qui est déjà dans le Garden. |
| VMWare Avi Load Balancer | C'est tout simplement Nginx, qui est déjà dans le Garden. |
| Sanic | Utilise httptools, qui est déjà couvert par Uvicorn. |
| CPython http.server | Non destiné à une utilisation en production. |
| openjdk_stdlib | Ne fournit pas de canal cohérent de divulgation de vulnérabilités. |
| dart_stdlib | A ignoré les signalements précédents. |
| eventlet | La bibliothèque HTTP n'est qu'un fork de celle de la bibliothèque standard CPython. |
| uwsgi | Ne prend pas en charge les corps de message fragmentés (chunked). |