악용 사례: 쿠버네티스 로그 쿼리의 명령어 인젝션
편집 및 추가 설명: 트리샤 하워드(Tricia Howard)
핵심 요약
Akamai 보안 연구원 토머 펠레드(Tomer Peled)는 최근 쿠버네티스에서 CVE-2024-9042로 지정된 취약점을 발견했습니다.
이 취약점을 악용하면 쿠버네티스 클러스터 내의 모든 Windows 엔드포인트에서 SYSTEM 권한으로 원격 코드 실행(RCE)을 할 수 있습니다. 이 취약점을 악용하려면 클러스터가 새로운 로깅 메커니즘인 '로그 쿼리'를 실행하도록 설정되어야 합니다.
이 취약점은 원격 노드에 대한 간단한 GET 요청으로 트리거될 수 있습니다.
이 취약점을 성공적으로 악용하면 클러스터의 모든 Windows 노드를 완전히 장악할 수 있습니다.
이 취약점은 베타 기능(버전 1.32.1 이전) 사용을 선택한 쿠버네티스의 기본 설치에서 악용될 수 있으며 온프레미스 배포와 Azure Kubernetes Service 모두를 대상으로 테스트되었습니다.
이 블로그 게시물에서는 개념 증명(PoC) curl 명령어를 제공하고 가능한 방어 방법을 논의합니다.
서론
일반적으로 쿠버네티스와 컨테이너가 보안 분야에서 지배적인 힘이 됨에 따라 Akamai 연구원을 비롯한 전 세계 연구원이 여기에 주목하고 있습니다. Akamai의 리서치 여정은 처음에 CVE-2023-3676으로 이어졌습니다. 이는 악성 YAML 파일을 클러스터에 적용해 악용될 수 있는 명령어 인젝션 취약점입니다. 이 리서치는 쿠버네티스 소스 코드에서 완전한 클러스터 탈취를 가능하게 하는 몇 가지 다른 문제를 발견하는 계기가 되었습니다.
Akamai는 이 취약점뿐 아니라 보조 프로젝트인 git-sync에서도 중요한 취약점을 발견했습니다. Akamai는 발견 사항을 DEF CON 32의 Red Team Village에서 발표했고, 발표를 준비하는 과정에서 이 블로그 게시물의 주제인 '명령어 인젝션의 또 다른 기회 - 대규모 로깅 프레임워크 로그 쿼리를 위한 쿠버네티스의 베타 기능을' 우연히 발견했습니다.
로그 쿼리란?
로그 쿼리를 사용하면 CLI 또는 curl을 사용해 원격 머신의 시스템 상태를 쿼리할 수 있습니다. 예를 들어, 사용자는 다음 명령어를 입력해 원격 노드에서 kubelet 서비스의 상태를 쿼리할 수 있습니다.
kubectl get --raw "/api/v1/nodes/node-1.example/proxy/logs/?query=kubelet"
위의 예제 명령어를 보았을 때 '원격 컴퓨터로 전송되는 쿼리가 검증될까요?'라는 이전 리서치가 떠올랐습니다.
그림 1은 로그 쿼리의 소스 코드의 예제입니다. 이 예제에서 여러 PowerShell 명령어가 작성되는 것을 발견했습니다.
이 명령어는 Windows 서비스 이름, 사용 시간 패턴 등과 같은 다양한 매개변수를 기반으로 특정 노드에서 로그를 검색하는 데 사용됩니다.
이전의 경험(CVE-2023-3676)을 통해 쿠버네티스가 PowerShell 명령어를 작성할 때 매개변수로 입력하기 전에 사용자 입력을 반드시 검증하지 않는다는 것을 알고 있습니다. Akamai는 이것이 로그 쿼리에서도 그런지 확인해 보고 싶었고, 실제로 서비스 이름이 미리 정의된 regex를 사용해 검증된다는 것을 발견했습니다(그림 2).
reServiceNameUnsafeCharacters라는 이름은 이 검사가 서비스에만 적용된다는 것을 암시합니다. 이 가설은 구문 분석 과정에 다른 regex가 없다는 사실에 의해 더욱 강화됩니다.
다른 변수를 살펴본 결과, 실제로 검증되는 유일한 변수는 서비스 이름이라는 것이 분명해졌습니다. 이것은 명령어 인젝션을 달성하기 위해 다른 변수를 살펴볼 수 있다는 것을 의미합니다. 로그 쿼리에는 사용자가 제공할 수 있는 여러 가지 선택적 변수가 있지만 문자열인 변수는 Pattern뿐입니다(그림 3). 위에서 언급했듯이 이 변수에 대한 검증은 없습니다(길이 제외).
이 취약점을 악용하는 것은 결코 쉬운 일이 아니었습니다. 괄호를 추가하거나 구분 기호를 사용하는 등 PowerShell 페이로드에 대해 여러 가지 다른 순열을 사용해 원격 컴퓨터에서 명령어를 트리거하려고 시도했지만 아무것도 작동하지 않는 것 같았습니다. 오류도 없었기 때문에 이 문제를 파악하기가 더욱 어려웠습니다.
페이로드가 문제가 아닙니다.
여러 가지 명령어 인젝션 방법을 시도한 끝에 결국 문제가 페이로드 자체에 있는 것이 아니라는 것을 발견했습니다. 이 취약점을 악용하기 위해서는 취약한 검사가 ETW에 로깅할 때만 존재하기 때문에 일반 klog 프레임워크가 아니라 Windows용 이벤트 추적(ETW)에 기본적으로 상태를 로깅하는 서비스를 지정해야 했습니다.
Calico(쿠버네티스를 위한 인기 있는 오픈 소스 네트워크 인터페이스)를 사용하는 쿠버네티스 환경은 NSSM(Non-Sucking Service Manager)을 통해 이 취약점을 악용하는 신뢰할 수 있는 방법을 제공합니다.
Calico 설정에서 NSSM은 일반적으로 쿠버네티스 서비스의 상태를 제어하기 위해 존재합니다. 다른 환경/설정에서는 서비스 상태를 처리하는 다른 방법을 사용합니다.
- 쿠버네티스는 NSSM의 로깅 출력을 관리하지 않으므로 klog를 통하지 않고 ETW에 직접 로그가 기록됩니다.
악용 쿼리 표시
악용 쿼리의 형식은 다음과 같습니다.
curl "<Kubernetes API Proxy server IP>/api/v1/nodes/<NODE name>/proxy/logs/?query=nssm&pattern=’\$(Start-process cmd)’"
*API 서버와 통신하는 데 필요한 인증 토큰은 삭제됩니다
눈썰미가 좋은 독자라면 악성 명령어를 피하기 위해 사용된 아포스트로피에 대해 궁금해하셨을 것입니다. 쿠버네티스가 다음 명령어를 사용해 입력을 삽입하기 때문에 아포스트로피가 필요합니다.
…Where-Object -Property Message -Match '%s'...
기존의 SQL 인젝션 공격과 마찬가지로, 아포스트로피를 추가해 패턴을 피해야 입력 내용이 별도의 명령어로 구문 분석됩니다(그림 4).
우선순위 패치
이 취약점의 영향을 받으려면 1.32.1 이전 버전의 쿠버네티스를 사용해야 합니다. 아직 이 취약점에 대해 패치를 하지 않았다면 이 패치를 우선적으로 적용하는 것이 좋습니다. 클러스터 내에 Windows 노드가 있는 기업의 경우 이 부분에 취약점이 있기 때문에 더욱 그렇습니다.
다행히도 이것은 업계 표준이 아닌 것 같습니다. 관리자는 클러스터 컨트롤러에서 다음 명령어를 실행해 기업 클러스터에 Windows 노드가 포함되어 있는지 쉽게 테스트할 수 있습니다(그림 5).
모든 쿠버네티스가 취약한가요?
취약점 여부는 쉽게 확인할 수 있습니다. “os=windows” 부분을 주목하세요. Windows 노드가 없는 경우, 이 명령어는 출력이 없으므로 취약하지 않습니다.
이 기능은 베타 기능이기 때문에 클러스터도 프레임워크 자체를 사용하도록 설정해야 합니다.
이 기능이 활성화되었는지 확인하기 위해 관리자는 “kubelet”의 “feature-gate” 시작 매개변수를 살펴볼 수 있습니다. 쿠버네티스 사이트에서 더 많은 정보를 얻을 수 있습니다.
패치 분석
이 취약점을 해결하기 위해 쿠버네티스는 값을 PowerShell 명령어 자체에 전달하기 전에 “kubelet_pattern”이라는 환경 변수를 사용하기로 결정했습니다.
그렇게 하면 사용자 입력이 평가되어야 하는 하위 표현식이 아니라 문자열 리터럴로 간주됩니다.
방어
이 취약점을 방어하기 위해 관리자는 RBAC(Role-Based Access Control) 모듈을 사용해 로그 쿼리에 접속할 수 있는 사용자를 제어하고 접속을 완전히 비활성화할 수도 있습니다. RBAC는 사용자의 신원에 따라 사용자 작업을 구분하는 방법입니다. 예를 들어, 각 사용자는 자신의 네임스페이스에서만 팟을 생성하거나 허용된 네임스페이스에 대한 정보만 볼 수 있습니다. 이렇게 하면 실행뿐 아니라 탐지에서도 RCE의 리스크를 줄일 수 있습니다.
이 취약점은 Windows 노드에만 영향을 미친다는 점에 유의하세요. 쿠버네티스 클러스터에 Windows 노드가 없다면 이 취약점에 노출되지 않습니다. 그러나 다른 알려지지 않은 취약점을 피하기 위해 패치를 가능한 한 최신 상태로 유지하는 것이 좋습니다.
이 문제는 소스 코드에 있어 위협이 계속 활성화되고 악용될 가능성이 높기 때문에 클러스터에 Windows 노드가 없더라도 패치를 적용할 것을 강력히 권장합니다.
결론
이 블로그 게시물에서는 쿼리 권한을 가진 공격자가 클러스터 내의 모든 Windows 노드에서 명령어를 실행할 수 있는 방법을 보여드렸습니다. 이 취약점은 YAML 파일을 제출하는 대신 간단한 curl 명령어를 사용해 악용될 수 있습니다. 이 사실은 악용을 방어하고 탐지하기가 더 어렵기 때문에 큰 리스크를 초래합니다. 앞서 논의한 바와 같이 쿠버네티스 위생 문제는 로그 쿼리에만 국한된 것이 아닙니다.
방어자는 기업에 들어오는 비정상적인 행동을 경계해야 합니다. 이 공격 기법은 클러스터 전체를 장악할 수 있기 때문에 보안 관리자는 잠재적인 리스크를 인식하고 대처할 수 있도록 경각심을 높여야 합니다.
Akamai Security Intelligence Group은 이와 같은 위협을 지속적으로 리서치하고 고객과 보안 커뮤니티 전반을 위해 보고서를 작성할 것입니다. Akamai가 진행 중인 작업에 대한 실시간 업데이트를 받으려면 X(기존의 Twitter)에서 Akamai를 팔로우하세요.
Akamai는 쿠버네티스 팀의 대응과 소통에 감사의 말씀을 드립니다.
타임라인
2024/06/28 - 쿠버네티스 팀에 취약점 공개
2024/07/18 - 쿠버네티스 팀이 문제 해결을 위한 작업을 시작했습니다
2024/07/30 - 쿠버네티스 팀이 CVE를 할당했습니다
2025/01/16 - 쿠버네티스가 CVE 수정 사항을 공개했습니다
2025/01/24 - 블로그 게시물 게시