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

● CVE-2021-22960 · CVSS 6.5 · Média
Pesquisa · FlawOpen

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

Análise técnica detalhada e engenharia de mitigação do patch para vulnerabilidade: How incomplete Transfer-Encoding chunk extension parsing in deps/llhttp caused HTTP request desynchronization, enabling cache poisoning and credential theft.

💡 Explicação em Linguagem Simples (ELI5)

Analogia explicativa: 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.

Conceitos Centrais e Termos

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).

Análise de Causa Raiz

A causa raiz decorre de parâmetros de limite não validados em sistemas de código aberto, permitindo a dessincronização de estado e a evasão dos controles de segurança.

Fluxo de Ataque Passo a Paso

Step 1

Fase de ataque: Send Ambiguous Request

Mecanismo de exploração técnica: The attacker sends an HTTP request with chunk extensions containing unescaped control characters.

Step 2

Fase de ataque: Frontend Interpretation

Mecanismo de exploração técnica: The frontend proxy treats the entire payload as a single continuous request body.

Step 3

Fase de ataque: Node.js Parser Desync

Mecanismo de exploração técnica: Node.js's llhttp stops parsing prematurely, leaving the smuggled second request in the TCP buffer.

Step 4

Sequestro de fluxo : Victim Session Hijacking

Mecanismo de exploração técnica: The next innocent user's request is prepended to the smuggled request, exfiltrating their session tokens.

Código-Fonte: Vulnerável vs. Seguro

IMPLEMENTAÇÃO VULNERÁVEL
// 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;
}
PATCH SEGURO E ROBUSTO
// 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;
}

Lista de Verificação de Segurança para Engenharia

Fontes