1247 words
6 minutes
CVE-2022-0492

사정으로 몇 개월만에 글을 올리네요.😅 그래도 관련 활동은 멈추지 않고 계속해서 이어나가고 있답니다.🫠 잠깐의 포스팅을 쉬는 시간을 허락해주신 팀장님 감사합니다..

Intro#

TOOR 팀 활동을 하며 분석하게 된 리눅스 커널 네임스페이스 격리 우회 취약점 관련 글입니다.

이번에 알아볼 원데이 취약점은 2022년 3월 3일에 공개된 리눅스 커널 네임스페이스 격리 우회 취약점입니다.

공격자는 리눅스 커널에서 제공하는 cgroups 버전 1이 제공하는 기능에서 취약점을 악용하여 격리된 환경에서 루트 권한으로 탈출을 시도할 수 있습니다.

본 글은 선행 연구를 진행하신 다른 연구원분들의 글들을 읽고 제 나름 분석을 진행하며 취약점을 공부하며 이해하고 정리해본 결과로 작성하게된 글입니다. 나름의 분석을 해봤지만 맞지 않는 부분이 있을 수 있으며, 만약 이를 발견하셨을 시 피드백해주시면 적극 반영하도록 하겠습니다. 취약점 및 PoC 분석에 많은 도움이된 자료들은 다음과 같습니다.

Vuln#

Background#

CVE-2022-0492를 이해하기 위한 최소한의 기반 지식에 대해서 알아봅시다.

cgroups-v1#

cgroups version 1은 2007년에 리눅스 커널에 병합된 기능입니다. cgroups을 통해서 CPU, 메모리 등의 자원 사용량등을 제한할 수 있습니다. 동일한 그룹으로 묶인 프로세스, 프로세스 계층들은 같은 리소스 제한 정책을 갖게 됩니다.

notify_on_release#

notify_on_release는 cgroups 서브 시스템에 지정할 수 있는 플래그입니다. 해당 플래그가 활성화되어 있을 경우 cgroup으로 묶인 마지막 태스크가 없어질 때(종료 혹은 다른 cgroup으로 이동될 때), 커널에서는 해당 cgroup 계층의 루트 디렉터리에 존재하는 release_agent에 작성된 명령을 루트 권한으로 실행하게 됩니다. 이를 통해서 cgroup은 비어버린 해당 cgroup에 대한 정리 혹은 후 처리 작업을 진행할 수 있게 됩니다.

RCA#

취약점은 컨테이너와 같은 격리된 환경의 사용자가 capability 제약이 있는 상태의 루트 권한을 갖고 있거나 또는 CAP_DAC_OVERRIDE caability를 갖고 있을 경우 악용이 가능합니다.

이는 해당 커밋 디스크립션에서도 확인할 수 있습니다.

cgroup-v1: Require capabilities to set release_agent
The cgroup release_agent is called with call_usermodehelper. The function
call_usermodehelper starts the release_agent with a full set fo capabilities.
Therefore require capabilities when setting the release_agaent.
Reported-by: Tabitha Sable <tabitha.c.sable@gmail.com>
Tested-by: Tabitha Sable <tabitha.c.sable@gmail.com>
Fixes: 81a6a5cdd2c5 ("Task Control Groups: automatic userspace notification of idle cgroups")
Cc: stable@vger.kernel.org # v2.6.24+
Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
Signed-off-by: Tejun Heo <tj@kernel.org>

컨테이너가 존재하는 cgroup의 루트 경로에 release_agent가 있는 경우 루트 권한을 갖고 있는 컨테이너 내의 사용자가 해당 파일을 수정하는 과정에서 다음 취약점 패치에서 보는 것과 같이 capability 체크가 미흡합니다. 즉, release_agent로 인해 실행되는 프로세스는 모든 capability를 갖지만, 이를 실행시킬 수 있는 수정 기능에는 capability 제약이 누락되어있습니다.

diff --git a/kernel/cgroup/cgroup-v1.c b/kernel/cgroup/cgroup-v1.c
index 41e0837a5a0bda..0e877dbcfeea9c 100644
--- a/kernel/cgroup/cgroup-v1.c
+++ b/kernel/cgroup/cgroup-v1.c
@@ -549,6 +549,14 @@ static ssize_t cgroup_release_agent_write(struct kernfs_open_file *of,
BUILD_BUG_ON(sizeof(cgrp->root->release_agent_path) < PATH_MAX);
+ /*
+ * Release agent gets called with all capabilities,
+ * require capabilities to set release agent.
+ */
+ if ((of->file->f_cred->user_ns != &init_user_ns) ||
+ !capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
cgrp = cgroup_kn_lock_live(of->kn, false);
if (!cgrp)
return -ENODEV;

이로 인해 컨테이너 내에서 모든 capability(CAP_SYS_ADMIN)를 갖고 있지 않은 root 혹은 CAP_DAC_OVERRIDE capability만 갖는 공격자는 release_agent를 수정하여 모든 capability(CAP_SYS_ADMIN)를 갖는 루트 권한으로 임의의 명령을 사용하여 격리된 환경을 탈출하여 명령어를 실행시킬 수 있습니다.

PoC#

열심히 작성중 😵‍💫

Video#

열심히 작성중 😵‍💫

Patch#

앞선 패치에서 봤 듯, release_agent를 수정하기 위한 권한을 체크합니다. 이로써 공격자는 패치 이전처럼 제한된 Capability를 가지고 release_agent를 수정하는 것이 불가능해집니다.

diff --git a/kernel/cgroup/cgroup-v1.c b/kernel/cgroup/cgroup-v1.c
index 41e0837a5a0bda..0e877dbcfeea9c 100644
--- a/kernel/cgroup/cgroup-v1.c
+++ b/kernel/cgroup/cgroup-v1.c
@@ -549,6 +549,14 @@ static ssize_t cgroup_release_agent_write(struct kernfs_open_file *of,
BUILD_BUG_ON(sizeof(cgrp->root->release_agent_path) < PATH_MAX);
+ /*
+ * Release agent gets called with all capabilities,
+ * require capabilities to set release agent.
+ */
+ if ((of->file->f_cred->user_ns != &init_user_ns) ||
+ !capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
cgrp = cgroup_kn_lock_live(of->kn, false);
if (!cgrp)
return -ENODEV;

Mitigation#

  • 취약점에 대한 패치가 적용된 커널을 사용합니다.
  • cgroup-v1을 비활성화 합니다.
  • 컨테이너에 대한 Capability을 제한합니다.
  • 커널이 제공하는 보안 기능등을 활성화 시킵니다. (Apparmor, SELinux, Seccmop)

References#