Fonctionnement de l'entête X-Content-Type-Options - Contournement de CSP
17 Mars 2023
L'entête X-Content-Type-Options est un incontournable des résultats de scan des outils automatisés. Mais à quoi sert-il réellement et contre quoi protège-t-il ?
Le type MIME
Le type MIME (Multipurpose Internet Mail Extensions) est un identifiant en deux parties, un type et un sous-type, qui peut également posséder des options. Il permet de spécifier le type de contenu échangé, par exemple une image, une vidéo, un document audio ou encore un simple texte.
La syntaxe est la suivante :
dont voici quelques exemples :
Le type MIME application/octet-stream
est la valeur par défaut pour un fichier binaire. Un fichier ayant ce type MIME ne sera pas exécuté au sein du navigateur, mais plutôt proposé en téléchargement. Le type MIME text/plain
est la valeur par défaut pour les fichiers texte. En général, un navigateur tentera d'afficher un tel fichier.
Bien qu'il puisse sembler non problématique de déterminer le type d'un fichier en fonction de son extension, cette dernière n'est pas fiable : l'utilisateur peut s'être trompé en la renseignant par exemple. En général, un navigateur va plutôt se reposer sur le type MIME afin de déterminer la nature d'un fichier. En raison de ce mécanisme, il est nécessaire que le serveur fournissant la ressource renseigne correctement cette information grâce à l'entête HTTP Content-Type
. Si cet entête n'est pas correctement renseigné voir absent, alors le navigateur va tenter de déterminer lui même la nature du fichier en analysant son contenu : c'est ce qu'on nomme le MIME Sniffing. Bien que ce mécanisme possède des avantages elle amène aussi certaines vulnérabilités.
Le MIME Sniffing est présent sur tous les navigateurs mais il était encore plus agressif sur les versions Internet Explorer.
Contournement de politiques CSP avec upload de fichiers
Présentation de l'application vulnérable
L'application suivante permet à l'utilisateur d'uploader des fichiers sur un serveur distant et également d'effectuer une recherche par mot-clé pour retrouver plus facilement ses documents :
L'utilisateur peut rechercher un document de la façon suivante :
Voici le code source associé :
Le développeur étant sensibilisé aux vulnérabilités Cross-Site Scripting il décide de se protéger de manière stricte en utilisant les directives Content-Security-Policy (CSP) suivantes :
Le développeur valide également la directive avec l'outil d'évaluation de Google :
L'application proposant en effet la possibilité de déposer des fichiers, il décide de durcir son formulaire d'upload :
Exploitation de la vulnérabilité
Exploitation d'une Injection Cross-Site Scripting (XSS)
Un utilisateur malicieux découvre la possibilité d'une XSS au niveau du paramètre de recherche search
mais CSP semble protéger correctement son exécution :
L'attaquant tente alors d'uploader un fichier de type Javascript xss.js
puis de l'appeler directement via la paramètre src
de la balise <script></script>
:
Mais le durcissement de la fonctionnalité par le développeur l'en empêche :
L'attaquant ayant déjà réussi à uploader avec succès un fichier texte simple, il effectue à nouveau son attaque mais en intégrant la payload XSS dans un fichier ayant l'extension txt
:
Et référence le fichier précédemment uploadé :
Le fichier étant bien hébergé sur le même domaine d'exécution, la politique CSP n'est pas déclenchée et la payload XSS est exécutée :
Et cela, bien que le Content-Type
retourné par le serveur ne soit pas de type text/javascript
mais bien text/plain
:
Il peut arriver que le serveur, suivant sa configuration, retourne un Content-Type de type application/octet-stream
. Si tel est le cas, l'attaque reste fonctionnelle :
En revanche, faire passer un fichier Javascript pour une image ne fonctionnera pas :
Exploitation d'une Injection Cascading Style Sheets (CSS)
Le développeur, étant maintenant au courant de la vulnérabilité permettant d'exploiter l'injection XSS a décidé de bannir complètement l'utilisation de Javascript. La politique CSP devient alors la suivante :
L'outil de test de Google confirme la bonne protection concernant l'exécution de script :
Et l'injection ne semble en effet plus possible :
Comme déjà évoqué dans plusieurs articles, l'injection CSS peut permettre de récupérer des informations grâce à l'utilisation des sélecteurs, par exemple. L'injection va se faire grâce à la balise <link>
. L'attaquant va devoir uploader un fichier CSS qui aura une extension autre que css
, car interdite par l'application :
Il s'agit juste d'une preuve de concept, une seule requête vers l'URL de l'attaquant suffira donc ici afin de prouver son bon fonctionnement.
Bien que le Content-Type
retourné par le serveur soit text/plain
et non text/css
comme attendu :
Le navigateur exécute tout de même le code malicieux :
Cette attaque n'est possible seulement parce que la CSP permet le chargement d'image distante. Dans le cas contraire, l'impact de cette injection sera sans doute réduite.
Ici l'attaque fonctionnera également dans le cas où le serveur renvoie un Content-Type
de type application/octet-stream
. Et plus intéressant, l'attaque fonctionnera même si le Content-Type retourné par le serveur n'est pas exécutable par exemple avec image/jpeg
:
L'entête X-Content-Type-Options
X-Content-Type-Options est un entête HTTP de sécurité qui peut être présent dans les réponses HTTP et qui indique au navigateur de suivre et ne de pas modifier les type MIME indiqués dans l'entête Content-Type
. Cela permet de se protéger contre les vulnérabilités liées au MIME sniffing. L'entête est supporté par tous les navigateurs principaux :
Syntaxe
La syntaxe de l'entête est la suivante :
Directives
nosniff
Bloque une requête si la destination de la requête est :
"
style
" et le MIME n'est pas de typetext/css
"
script
" et le MIME n'est pas de type JavaScript MIME type (donttext/javascript
par exemple)
Protection de l'application
Le développeur ayant maintenant connaissance de cet entête de sécurité, il décide d'appliquer cette bonne pratique et modifie la configuration de son serveur en conséquence. Par exemple pour Nginx :
L'attaquant tente à nouveau d'exploiter la vulnérabilité afin d'exécuter une XSS, mais cette fois le navigateur refuse de charger le fichier contenant le script malicieux :
La réponse du serveur contenant effet l'entête de protection :
Il en va de même pour l'injection CSS :
Références
Dernière mise à jour