flawopen.com/Teardowns/cve-2021-22960-nodejs-llhttp-request-smuggling

● CVE-2021-22960 · CVSS 6.5 · Mittel
Sicherheitsforschung · FlawOpen

CVE-2021-22960: Node.js llhttp HTTP Request Smuggling Teardown

Detaillierte technische Quellcode-Analyse und Härtungsmaßnahmen für vulnerabilidade: How incomplete Transfer-Encoding chunk extension parsing in deps/llhttp caused HTTP request desynchronization, enabling cache poisoning and credential theft.

💡 Einfache Erklärung (ELI5)

Anschauliche Analogie: Imagine a two-window ticket booth. Window 1 reads: 'One ticket for Alice'. Window 2 reads: 'Wait, there's another ticket for Bob glued to the back'. Because Window 1 ignored the extra ticket, Bob's ticket sits in the window until Charlie walks up. Charlie gets handed Bob's ticket and private receipt, allowing an attacker to steal user sessions.

Kernkonzepte & Begriffe

llhttp
The high-performance C HTTP parser library embedded inside Node.js to parse incoming HTTP/1.1 requests.
HTTP Request Smuggling
Desynchronization between frontend reverse proxies (e.g. NGINX, Cloudflare) and backend Node.js servers regarding request boundaries.
Chunked Transfer-Encoding
An HTTP streaming mechanism where payloads are sent in numbered chunks, terminated by a 0\r\n\r\n chunk.
Chunk Extensions
Optional semicolon-delimited parameters appended to the chunk length (0;extension=value\r\n).

Ursachenanalyse

Die Grundursache liegt in nicht validierten Grenzparametern in Open-Source-Systemen, die eine Zustandsdesynchronisation und die Umgehung von Sicherheitskontrollen ermöglichen.

Schritt-für-Schritt Angriffsablauf

Step 1

Angriffsphase: Send Ambiguous Request

Technischer Ausführungsmechanismus: The attacker sends an HTTP request with chunk extensions containing unescaped control characters.

Step 2

Angriffsphase: Frontend Interpretation

Technischer Ausführungsmechanismus: The frontend proxy treats the entire payload as a single continuous request body.

Step 3

Angriffsphase: Node.js Parser Desync

Technischer Ausführungsmechanismus: Node.js's llhttp stops parsing prematurely, leaving the smuggled second request in the TCP buffer.

Step 4

Entführung : Victim Session Hijacking

Technischer Ausführungsmechanismus: The next innocent user's request is prepended to the smuggled request, exfiltrating their session tokens.

Quellcode: Verwundbar vs. Sicher

VERWUNDBARE IMPLEMENTIERUNG
// VULNERABLE: deps/llhttp/src/llhttp.c before patch
int llhttp__on_chunk_extension(llhttp_t *parser, const char *p, const char *end) {
    // ROOT CAUSE:
    // Does not enforce strict ASCII validation on chunk extension tokens!
    // Tolerates invalid whitespace and carriage return sequences, desyncing from proxies!
    while (p < end && *p != '\r' && *p != '\n') {
        p++; // Skips unvetted extension bytes
    }
    return 0;
}
GEHÄRTETER SICHERHEITS-PATCH
// SECURE: deps/llhttp/src/llhttp.c patch
int llhttp__on_chunk_extension(llhttp_t *parser, const char *p, const char *end) {
    // 1. Strictly validate characters inside chunk extensions according to RFC 9112
    while (p < end && *p != '\r' && *p != '\n') {
        uint8_t ch = (uint8_t)*p;
        // Disallow spaces, control codes, and invalid token bytes
        if (ch <= 0x20 || ch >= 0x7F || ch == ';') {
            return HPE_INVALID_CHUNK_SIZE; // Reject immediately!
        }
        p++;
    }
    return 0;
}

Checkliste für Engineering & Systemsicherheit

Quellen