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

● CVE-2021-22960 · CVSS 6.5 · 보통
보안 연구 · FlawOpen

심층 기술 분석: CVE-2021-22960: Node.js llhttp HTTP Request Smuggling Teardown

vulnerabilidade 소스 코드 심층 기술 분석 및 시스템 보안 강화 가이드: 취약점 근본 원인과 패치 메커니즘 분석.

💡 알기 쉬운 설명 (ELI5)

직관적인 현실 비유 설명: 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.

핵심 개념 및 용어

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

근본 원인 분석 (Root Cause)

근본 원인은 오픈 소스 시스템의 검증되지 않은 경계 매개변수로 인해 상태 비동기화 및 보안 제어 우회가 발생한 데 있습니다.

단계별 공격 실행 흐름

Step 1

공격 실행 단계: Send Ambiguous Request

기술적 취약점 악용 메커니즘 및 상세 실행 경로: The attacker sends an HTTP request with chunk extensions containing unescaped control characters.

Step 2

공격 실행 단계: Frontend Interpretation

기술적 취약점 악용 메커니즘 및 상세 실행 경로: The frontend proxy treats the entire payload as a single continuous request body.

Step 3

공격 실행 단계: Node.js Parser Desync

기술적 취약점 악용 메커니즘 및 상세 실행 경로: Node.js's llhttp stops parsing prematurely, leaving the smuggled second request in the TCP buffer.

Step 4

제어 흐름 하이재킹(Victim Session Hijacking)

기술적 취약점 악용 메커니즘 및 상세 실행 경로: The next innocent user's request is prepended to the smuggled request, exfiltrating their session tokens.

소스 코드 비교: 취약한 구현 vs 보안 패치

취약한 구현
// 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;
}
보안 강화 패치
// 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;
}

엔지니어링 및 시스템 보안 강화 체크리스트

출처