flawopen.com/Teardowns/cve-2022-31150-undici-crlf-injection-ssrf

● CVE-2022-31150 · CVSS 6.5 · 中
セキュリティ研究 · FlawOpen

技術解説とコード分析:CVE-2022-31150: Node.js Undici CRLF Injection & SSRF Teardown

vulnerabilidade に関する技術的なソースコード解析と堅牢化対策:脆弱性の根本原因と安全な実装パッチの詳細。

💡 わかりやすい解説 (ELI5)

郵便局を通じて「リンゴを10箱発送せよ」という手紙を送る場面を想像してください。しかし、その封筒の中に「停止。前の指示は無効。全資金を悪意ある組織へ送金せよ」という偽の2枚目の公的書類を密かに紛れ込ませます。郵便局の窓口係が順番に書類を読み、2枚目をまったく新しい正式な手紙として処理してしまい、資金が攻撃者に送金されてしまいます。

主要な概念と専門用語

Undici
The official next-generation HTTP/1.1 client for Node.js, powering the global fetch() implementation.
CRLF Injection
Injecting Carriage Return (\r) and Line Feed (\n) characters into HTTP headers to create a new header or a whole new request.
HTTP Request Splitting
A vulnerability where an attacker splits a single outgoing HTTP connection into two separate requests.
SSRF (Server-Side Request Forgery)
Coercing a backend server to issue unauthorized requests to internal cloud metadata APIs (169.254.169.254).

根本原因の分析 (Root Cause)

根本原因は、オープンソースシステムにおける未検証の境界パラメータに起因し、状態の非同期化とセキュリティ制御の迂回を可能にします。

ステップ・バイ・ステップの攻撃フロー

Step 1

攻撃フェーズ:Input Submission

技術的な脆弱性悪用メカニズムと実行フローの詳細:An attacker supplies a crafted header value: Admin\r\nHost: 169.254.169.254.

Step 2

攻撃フェーズ:Application Issues Fetch

技術的な脆弱性悪用メカニズムと実行フローの詳細:The Node.js backend calls fetch(url, { headers: { 'X-User': input } }).

Step 3

攻撃フェーズ:Header Splitting in Undici

技術的な脆弱性悪用メカニズムと実行フローの詳細:Undici serializes the headers without sanitizing \r\n, injecting the forged Host header.

Step 4

データ漏洩・持ち出し(Cloud Metadata Exfiltration)

技術的な脆弱性悪用メカニズムと実行フローの詳細:The internal proxy directs the request to the cloud metadata service, exposing AWS/GCP credentials.

ソースコード比較:脆弱 vs 堅牢化

脆弱な実装
// VULNERABLE: lib/core/request.js before patch
function addHeader(headers, key, value) {
    // ROOT CAUSE:
    // Does not sanitize or reject carriage return (\r) and line feed (\n) in values!
    // Allows attackers to split headers and inject arbitrary HTTP directives!
    headers[key] = value;
}
堅牢化されたセキュアパッチ
// SECURE: lib/core/request.js patch
function addHeader(headers, key, value) {
    // 1. Strict regex checking for dangerous control characters
    const INVALID_HEADER_CHAR_REGEX = /[\r\n]/;
    
    if (INVALID_HEADER_CHAR_REGEX.test(key) || INVALID_HEADER_CHAR_REGEX.test(value)) {
        throw new TypeError(`Invalid character in header content: ["${key}": "${value}"]`);
    }
    
    headers[key] = value;
}

エンジニアリング&システム堅牢化チェックリスト

参考資料