FlawOpen

flawopen.com/Teardowns/cve-2024-7646-ingress-nginx-annotation-code-injection

● CVE-2024-7646 · CVSS 8.8 · 높음
보안 연구 · FlawOpen

CVE-2024-7646: Ingress-NGINX 검증 우회

캐리지 리턴 검증 우회로 Ingress 생성자가 명령을 주입하고 ingress-nginx 컨트롤러 자격 증명을 얻을 수 있었습니다. 1.11.2/1.10.4에서 수정; 프로젝트 종료.

💡 알기 쉬운 설명 (ELI5)

허용된 단어가 들어 있는지만 확인하고 전체 값을 검증하지 않는 문지기를 떠올려 보세요. 캐리지 리턴은 다음 시스템이 나머지 텍스트를 다르게 읽게 할 수 있습니다. 이 문제에서는 annotation이 부분 일치 검사를 통과한 뒤 생성된 NGINX 설정에 기록됐습니다. 수정은 전체 값을 검증하고 캐리지 리턴을 안전하게 처리합니다.

핵심 개념 및 용어

Ingress 객체
호스트나 경로에서 Service로의 라우팅을 설명하는 Kubernetes API 리소스입니다. 클러스터 관리자가 아닌 사용자에게 생성 권한이 위임될 수 있습니다.
Annotation 검증 우회
annotation 값 전체가 허용 옵션과 일치하는지 확인하지 않고 허용된 부분 문자열이 있는지만 검사한 검증기를 통과한 상태입니다.
캐리지 리턴 (`\r`)
일부 형식에서 줄바꿈에 쓰이는 제어 문자입니다. 검증과 설정 생성 단계에서 다르게 해석하면 줄 경계가 바뀔 수 있습니다.
컨트롤러 ServiceAccount
ingress-nginx 컨트롤러가 사용하는 Kubernetes 신원입니다. 업스트림 공지에 따르면 기본 권한으로 클러스터의 모든 Secret에 접근할 수 있습니다.

프레임워크 매핑

  • 이 가이드에서 설명하는 약점의 CWE 참조: CWE-20

근본 원인 분석 (Root Cause)

CVE-2024-7646은 ingress-nginx의 annotation 검증 우회이며 사용자 Lua snippet을 무제한 허용하는 문제가 아닙니다. auth-tls-verify-client 검증기는 시작과 끝 anchor가 없는 Go 정규식을 사용했습니다. 따라서 MatchString은 허용 옵션이 부분 문자열로 포함된 더 긴 값도 받아들일 수 있었습니다. annotation의 캐리지 리턴은 생성된 NGINX 설정을 정리하는 과정에서 다르게 해석될 수 있었습니다. 업스트림 수정은 전체 값 일치를 요구하고 cleanConf에서 단독 캐리지 리턴을 안전하게 처리합니다. Kubernetes 보안 공지에 따르면 Ingress 생성 권한이 있는 행위자는 검증을 우회해 명령을 주입하고 컨트롤러 자격 증명을 얻을 수 있습니다. 기본 설정에서 이 자격 증명은 클러스터의 모든 Secret에 접근할 수 있습니다. 이는 높은 심각도(CVSS 8.8)의 인증된 Kubernetes API 경로이며 익명 네트워크 요청이 아닙니다. 프로젝트는 2026년 3월 종료됐으므로 과거 수정 버전으로 업그레이드하는 것은 즉각적인 차단책일 뿐입니다. 배포 환경은 유지 관리되는 컨트롤러나 Gateway API 구현으로 이전해야 합니다.

단계별 공격 실행 흐름

단계 1

사용자에게 Ingress 생성 권한이 있음

공격자는 Kubernetes API를 통해 Ingress 객체를 만들 권한이 필요합니다. 애플리케이션 팀에 그 권한을 위임한 멀티테넌트 클러스터에서 특히 문제가 됩니다.

단계 2

Annotation이 부분 일치 검사를 통과함

취약한 auth-tls-verify-client 정규식에는 anchor가 없었습니다. 따라서 Go MatchString은 정확히 허용된 값이 아니라 허용 옵션을 포함한 더 긴 값을 받아들일 수 있었습니다.

단계 3

캐리지 리턴이 설정 경계 해석을 바꿈

annotation은 생성된 NGINX 설정에 포함됩니다. 패치에서는 전체 값 검증과 설정 정리 중 단독 캐리지 리턴 처리 두 가지를 수정합니다.

단계 4

컨트롤러 신원이 노출됨

Kubernetes 공지는 명령 주입이 컨트롤러 자격 증명을 획득할 수 있다고 설명합니다. 기본적으로 ServiceAccount가 모든 Secret을 읽을 수 있지만 실제 영향은 RBAC에 달려 있습니다.

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

이 발췌는 CVE-2024-7646 업스트림 수정에서 가져왔습니다. PR #11719는 auth-tls-verify-client 허용 값에 anchor를 추가하고, PR #11721은 cleanConf에서 단독 캐리지 리턴을 처리합니다. 1.10 브랜치에도 PR #11718 및 #11722의 변경이 들어갔습니다. 관련 없는 함수 주변 코드는 생략했습니다.

취약한 구현
// internal/ingress/annotations/authtls/main.go (수정 전)
authVerifyClientRegex = regexp.MustCompile(`on|off|optional|optional_no_ca`)

// internal/ingress/controller/template/template.go (수정 전)
switch c {
case ' ', '\t':
    needOutput = lineStarted
case '\n':
    needOutput = !(!lineStarted && emptyLineWritten)
    nextLineStarted = false
}
보안 강화 패치
// internal/ingress/annotations/authtls/main.go (수정됨)
authVerifyClientRegex = regexp.MustCompile(`^(on|off|optional|optional_no_ca)$`)

// internal/ingress/controller/template/template.go (수정됨)
switch c {
case '\r':
    rest := in.Bytes()
    if len(rest) > 0 && rest[0] != '\n' {
        c = ' '
        needOutput = lineStarted
    }
case '\n':
    needOutput = !(!lineStarted && emptyLineWritten)
    nextLineStarted = false
}

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

출처