Solaris 10 운영 체제는 새로운 보안 기능인 "최소 권한 모델"을 제공합니다.
일반적인 UNIX 운영 체제에서는 대부분의 시스템 프로세스를 루트 권한으로 실행하고 있습니다.
이 때문에 시스템 프로세스 실행을 위한 권한이 주어지는 한편, 시스템 프로세스에서 보호되고 있는 그 밖의 불필요한 액세스 권까지 주어집니다.
이러한 문제에 대응하기 위해 Solaris 10에서는 지정된 프로세스에 슈퍼유저 권한의 하위 집합만을 허용하는 "최소 권한 모델"을 제공합니다.
이번 달에는 Solaris 10에서 새롭게 추가된 보안 기능과 최소 권한 모델에 대하여 해설합니다.
머리말
대부분의 UNIX 운영 체제에서는 시스템 프로세스의 대부분이 루트 권한으로 실행되므로 프로그램에서 다른 프로세스나 메모리, I/O 장치 등에 대한 읽기나 변경이 가능합니다.
이로 인해 시스템 프로세스를 실행하기 위해 필요한 권한이 주어지는 한편, 시스템 프로세스에서 보호되고 있는 그 밖의 불필요한 부분에도 액세스가 가능해집니다.
상당수의 소프트웨어는 이렇게 확대된 권한을 악용하여 버퍼 오버플로우나 데이터의 파손 등의 결함을 이유로 슈퍼유저로서 시스템에 액세스합니다.
이러한 문제에 대응하기 위해 Solaris 10 운영 체제에서는 새로워진 최소 권한 모델을 선택하였습니다.
이 모델에서는 지정된 프로세스에 슈퍼유저 권한의 하위 집합만을 허용하고, 모든 권한을 부여하지 않습니다.
최소 권한 모델은 Sun이 Trusted Solaris로부터 얻은 경험을 진화시켜 지금까지 사용되고 있던 보안 모델을 한층 더 강화한 것입니다.
Solaris 10 OS의 최소 권한 모델에서는 일반 사용자가 파일 시스템을 마운트하거나, 하위 번호의 포트에 바인딩하는 데몬 프로세스의 실행, 파일의 소유권 변경 등이 편리해집니다.
한편, 1024 이하의 포트에 대한 바인딩이나, 사용자의 홈 디렉토리에 대한 읽기/쓰기, 이더넷 장치에 대한 액세스 등, 한정된 권한이 필요했기 때문에 이전에는 완전한 루트 권한으로 실행되었던 프로그램으로부터 시스템 프로세스를 보호합니다.
setuid를 사용한 루트 바이너리나 모든 루트 권한으로 실행되는 데몬이 최소 권한 모델에서는 거의 필요하지 않으므로 더 이상 전체 루트 권한을 사용하는 exploit는 프로그램 보안상의 약점이 아닙니다.
버퍼 오버플로우 등의 프로그래밍 오류로 인한 피해는 루트 이외의 사용자 실행은 저지되어 보호되므로 시스템 프로세스 파일의 읽기/쓰기나 시스템의 정지 등 중요한 기능에 대해 액세스 피해를 입을 우려는 없습니다.
Solaris 10 OS의 최소 권한 모델에는 권한의 기본 집합과 더불어 약 50개로 세분화된 권한이 포함되어 있습니다.
정의가 완료된 권한은 contract, cpc, dtrace, file, ipc, net, proc, sys와 같은 그룹으로 나눌 수 있습니다.
권한의 기본 집합에는 proc_fork, proc_exec, proc_session, proc_info, file_link_any 등, 종래의 보안 모델에서는 권한이 없던 프로세스에 부여하던 모든 권한이 포함됩니다.
프로세스의 권한 집합
각 프로세스는 그 커널 자격 증명에 4개의 권한 집합을 가지고 있습니다.
상속 집합(I): exec에 상속되는 권한.
허용 집합(P): 프로세스의 최대 권한 집합.
실효 집합(E): 현재 유효한 권한. P 의 하위 집합.
상한 집합(L): 프로세스 및 해당의 자식 프로세스가 취득하는 권한의 상한. 이 권한 집합 L에 대한 모든 변경 사항은 다음의 exec에 영향을 줍니다.
각 프로세스에는 권한 인식 상태 (Privilege Awareness State(PAS))가 있으며, Privilege Aware(PA) 또는 Not-Privilege Aware(NPA)로 설정할 수 있습니다.
권한의 인식이란 레거시 응용 프로그램에 종래의 모든 권한 모델과의 완전한 호환성을 유지시키기 위한 메커니즘입니다.
NPA인 레거시 응용 프로그램은 EUID, RUID 또는 SUID 중 하나가 0(루트)인 경우에 권한 집합 L의 모든 권한이 허용된다고 보면 됩니다.
프로세스가 exec(2)를 호출한 경우, 커널은 권한 인식을 파기하려고 합니다.
권한을 가지지 않는 프로세스에서는 일반적으로 I, P, E는 권한의 기본 집합과 같고, L는 일반적으로 정의가 완료된 권한의 전체 집합입니다.
구현의 배경과 이론에 대한 자세한 내용은 blogs.sun.com 에 있는 Casper Dik's weblog(영어) 및 Process Rights Management Tutorial을 참조하십시오.
프로세스는 한 번 실행되면 권한의 조작 함수를 사용해 권한 집합에 권한의 추가 및 삭제를 합니다.
권한은 임의로 삭제할 수 있지만, 허용 집합의 권한은 실효 집합 및 상속 집합에만 추가할 수 있습니다.
따라서 상속 집합은 허용 집합보다 큽니다.
상한 집합이 커지지는 않습니다.
ppriv(1) 명령
프로세스의 권한 집합 및 그 속성은 ppriv(1) 프로그램을 사용하여 표시 및 변경할 수 있습니다.
ppriv(1) 프로그램의 인수는 아래와 같은 형식입니다.
-e: 인수의 계속을 명령 줄로서 해석하고, 지정된 권한 집합과 속성을 사용해 명령 줄을 실행합니다.
-l: 현재 정의되어 있는 모든 권한을 stdout 에 목록화합니다.
-N: 지정된 프로세스 또는 명령 권한의 디버그를 OFF로 합니다.
-s spec: spec에 의해 프로세스의 권한 집합을 변경합니다.
각 권한 집합에 정확하게 대입하거나 추가 및 삭제를 몇 번씩 해야 하는 경우라면, -s 옵션을 여러 차례 사용해 같은 권한 집합을 변경할 수도 있습니다.
즉, 어떤 권한 집합에 대한 대입, 추가 또는 삭제는 상호 배타적인 관계에 있습니다.
spec는 공백 없이 [AEILP][+-=]privsetspec 형식으로 나타내는 사양입니다.
자세한 내용은 다음과 같습니다.
AEILP: 변경하는 권한 집합을 나타내는 1개 이상의 문자를 지정합니다.
대/소문자의 구별은 없습니다.
예를 들어 a 또는 A의 어느 쪽도 모든 권한 집합을 나타냅니다.
+-=: 목록화된 권한을 privsetspec로 지정된 권한 집합에 추가(+), 삭제(-), 대입(=)하는 수식자를 나타냅니다.
privsetspec: priv_str_to_set(3C)로 나타내듯이 콤마로 구분하는 권한 집합 (priv1, priv2)을 나타냅니다.
-S: 짧은 표시. 권한 집합을 가능한 한 짧은 출력 형식으로 리포트합니다.
기본값에서는 간이 형식의 출력입니다.
priv_str_to_set(3C)를 참조하십시오.
-v: 중복 표시. 권한명을 사용해 권한 집합을 리포트합니다.
프로세스 권한의 표시
프로세스가 PA인지 아닌지의 여부에 따라 어떻게 다른지, 또한 권한은 어떻게 변경되는지를 검증하기 위해 ppriv(1) 명령을 사용한 프로세스를 몇 가지 예로 듭니다.
첫 번째 예로는 Not-Privilege Aware 타사(Third Party)의 사용자 프로세스 screen에 대하여 검증합니다.
flags에는 PRIV_AWARE가 설정되지 않아서 P, I, E는 권한의 기본 집합과 완전히 같은 정의입니다.
권한 집합 L 는 모두 정의가 끝난 권한 집합입니다.
시스템 관리자는 일부 사용자에게 시스템 작업을 실행할 수 있도록 권한의 선택을 허용해 주고 싶을 것입니다.
사용자가 적절한 권한을 가지고 있지 않은 경우는 시스템에 오류가 발생해 작업을 할 수 없습니다.
일반 사용자가 사용할 수 없도록 SUID의 비트가 /usr/sbin/traceroute 파일에서 삭제되었습니다.
그러나 어느 시스템 관리자도 루트가 되지 않고도 자신의 계정을 통해 traceroute를 사용할 수 있어야 합니다.
권한을 변경하지 않고 호스트 www 에 대해서 traceroute를 시행하면, 다음과 같은 오류가 표시됩니다.
이것으로 UID 1001을 지닌 사람은 PRIV_NET_ICMPACCESS의 권한이 부족하다는 것을 알 수 있습니다.
UID 1001이 traceroute를 정상적으로 실행할 수 있도록 허용할 수 있습니다.
문제를 진단한 후에는 셸에서 디버그 기능을 반드시 OFF해 주시기 바랍니다.
ppriv -N $$j
셸 내의 각 명령을 디버그하는 대신에 하나의 프로세스를 한 번에 디버그할 수도 있습니다.
ppriv -D -e dtrace -D test.d
권한과 역할에 따른 액세스 제어(RBAC)
Solaris OS 8 이후 릴리스에 존재하는 RBAC 의 기능은 특정의 권한을 Role(역할) 또는 사용자에게 할당하기 위해 사용합니다.
Solaris에서의 RBAC 설정은 주로 4개의 파일로 관리되며 /etc/security/exec_attr, /etc/security/prof_attr, /etc/security/auth_attr, /etc/user_attr, exec_attr(4)에 프로파일 관련의 실행 속성을 지정합니다.
설정에는 일반적으로 사용자 ID 및 그룹 ID, 명령, 기본값 또는 제한되는 권한을 지정합니다.
prof_attr(4)에는 일련의 실행 프로파일명, 설명, 기타 속성을 지정합니다.
auth_attr(4)에는 승인의 정의와 설명을 지정합니다.
user_attr(4)에는 할당된 승인, 프로파일 및 프로젝트, 더불어 사용자와 Role의 정의를 지정합니다.
RBAC의 처리 방법에 대한 보다 자세한 정보는 앞서 기재한 매뉴얼 페이지와 더불어 rbac(5), policy.conf(4), chkauthattr(3SECDB)의 매뉴얼 페이지 및 Solaris 10 System Administrator Collection의 「역할, 권리 프로파일, 권한」의 항목을 참조하십시오.
어느 사용자 그룹에게 DTrace의 사용을 허용하려면, 시스템 관리자는 DTrace 권한에 액세스할 수 있는 Role을 작성하거나 사용자에게 직접 권한을 부여합니다.
다음의 예에서는 "debug" 라는 Role을 작성하여 적절한 권한을 부여하였습니다.
그 밖에 권한이 필요한 경우는 dtrace 명령에 ppriv를 사용해 다시 실행하여 필요한 권한을 특정해 주시면 됩니다.
RBAC는 권한이 필요한 포트에 바인딩해야 하는 httpd 등의 데몬을 보다 안전하게 실행하기 위해 최소 권한 모델과 함께 사용할 수도 있습니다.
이러한 프로그램의 대부분은 실제로는 1024 이하의 포트를 listen하는 것 외에는 루트로 액세스할 필요가 없기 때문에 프로세스 net_privaddr를 실행하는 Role 또는 사용자를 허용하면, 종래와 같이 EUID 0을 사용해 프로세스를 실행하지 않아도 됩니다.
정의가 완료된 권한 집합
새로운 최소 권한 모델에서 정의가 완료된 권한은 privileges(5) 매뉴얼 페이지에 기재되어 있지만, 여기에서는 시스템 관리자의 사용 빈도가 높은 사례를 몇 가지 예로 들겠습니다.
PRIV_CPC_CPU
프로세스에 각 CPU 하드웨어의 성능 카운터에 대한 액세스를 허용합니다.
PRIV_DTRACE_PROC
DTrace에 프로세스 레벨의 추적을 허용합니다.
프로세스 수준 추적의 Probe 설치를 허용하여 사용자 권한의 프로세스 내에서 유효하게 합니다.
PRIV_DTRACE_USER
DTrace에 사용자 수준의 추적을 허용합니다.
DTrace의 syscall 공급자나 profile 공급자에 사용자가 권한을 갖는 프로세스 검증을 허용합니다.
PRIV_DTRACE_KERNEL
DTrace에 커널 레벨의 추적을 허용합니다.
PRIV_FILE_CHOWN
프로세스에 파일 소유자인 사용자 ID의 변경을 허용합니다.
프로세스가 파일의 그룹 ID를 프로세스가 소유하는 유효한 그룹 ID 이외의 그룹 ID 또는 프로세스의 보조 그룹 ID 로 변경하는 것을 허용합니다.
PRIV_FILE_CHOWN_SELF
프로세스에 파일의 배포를 허용합니다.
이 권한을 가지는 프로세스는 {_POSIX_CHOWN_RESTRICTED} 가 유효하지 않은 경우와 동일하게 실행됩니다.
PRIV_FILE_DAC_READ
사용 권한 비트 또는 ACL에서 읽기 권한을 주지 않은 파일 또는 디렉토리에 대한 읽기를 허용합니다.
PRIV_FILE_DAC_SEARCH
사용 권한 비트 또는 ACL에서 검색의 권한을 주지 않은 디렉토리의 검색을 프로세스에 허용합니다.
PRIV_FILE_DAC_WRITE
사용 권한 비트 또는 ACL에서 쓰기 권한을 주지 않은 파일 또는 디렉토리에 대해 쓰기 실행을 허용합니다.
모든 권한은 유효한 UID 0이 없는 경우, UID 0으로 소유한 파일에 대해 쓰기가 필요합니다.
PRIV_FILE_OWNER
파일의 소유자가 아닌 프로세스에 파일의 액세스와 변경 시각의 수정을 허용합니다.
또한 디렉토리의 소유자가 아닌 프로세스에 디렉토리의 액세스와 변경 시각의 수정을 허용합니다.
파일 또는 디렉토리의 소유자가 아닌 프로세스 상위 디렉토리에 「실행 후 텍스트 이미지를 저장」(sticky) 비트 집합을 가지는 파일 또는 디렉토리의 삭제 또는 이름 변경을 허용합니다.
파일의 소유자가 아닌 프로세스에 해당 파일 안에 namefs의 마운트를 허용합니다.
파일 또는 디렉토리의 소유자가 아닌 프로세스에 해당 파일 또는 디렉토리의 사용 권한 비트 또는 ACL의 변경을 허용합니다.
PRIV_NET_ICMPACCESS
프로세스에 ICMP 패킷의 송수신을 허용합니다.
PRIV_NET_PRIVADDR
프로세스에 권한이 필요한 포트 번호에 대한 바인딩을 허용합니다.
"udp/tcp_extra_priv_ports" 에 나타내고 있는 포트에 더불어 NFS 사용을 위해 예약된 포트 이외에 권한이 필요한 포트 번호는 1 - 1023(종래의 UNIX에서 권한이 필요한 포트)입니다.
PRIV_PROC_SETID
프로세스에 임의의 UID 설정을 허용합니다.
UID 0의 경우는 모든 권한 행사가 필요하다고 가정합니다.
PRIV_PROC_ZONE
프로세스에 다른 영역 내의 프로세스에 대한 신호 추적 및 송신을 허용합니다.
zones(5)를 참조하십시오.
PRIV_SYS_ADMIN
프로세스에 노드명이나 도메인명의 설정, coreadm(1M)의 지정 및 nscd(1M)의 설정 등 시스템 관리자의 작업 실행을 허용합니다.
PRIV_SYS_CONFIG
프로세스에 다양한 시스템 프로세스 설정 작업의 실행을 허용합니다.
파일 시스템의 ioctl 의 설정이나, 할당량 호출, 스냅숏의 작성 및 삭제, PCFS 부팅 섹터 조작 등의 파일 시스템 고유의 관리 작업을 허용합니다.
PRIV_SYS_DEVICES
프로세스에 장치의 특별한 파일 작성을 허용합니다.
허용된 액세스를 확인하기 위해 drv_priv(9F) 함수를 호출하는 커널 모듈의 정상적인 호출을 프로세스에 허용합니다.
프로세스에 실제의 콘솔 장치를 직접 오픈할 수 있도록 허용합니다.
프로세스에 배타적으로 오픈된 장치 오픈을 허용합니다.
PRIV_SYS_MOUNT
프로세스에 제한하고 있는 파일 시스템(namefs 이외에 대부분의 파일 시스템)의 마운트/해제를 허용합니다.
프로세스에 콘솔 장치의 추가 및 삭제를 허용합니다.
권한 집합의 C 함수
권한의 표시 및 변경에는 여러 가지 C 함수가 사용됩니다.
권한 인식을 독자적인 코드에 추가하는 자세한 방법에 대해서는 다음의 매뉴얼 페이지를 참조하십시오.
getpflags(2), setpflags(2): 프로세스 플래그의 취득 또는 설정
getppriv(2), setppriv(2): 권한 집합의 취득 또는 설정
priv_addset(3C) priv_allocset(3C), priv_copyset(3C),
priv_delset(3C), priv_emptyset(3C), priv_fillset(3C), priv_freeset(3C),
priv_intersect(3C), priv_inverse(3C), priv_isemptyset(3C),
priv_isequalset(3C), priv_isfullset(3C), priv_ismember(3C),
priv_issubset(3C), priv_union(3C): 권한 집합의 조작 함수
priv_set(3C), priv_ineffect(3C): 권한 집합의 변경 및 권한 설정 여부의 확인
priv_str_to_set(3C), priv_set_to_str(3C), priv_getbyname(3C),
priv_getbynum(3C), priv_getsetbyname(3C), priv_getsetbynum(3C),
priv_gettext(3C): 권한명의 함수
priv_getbyname(9F): 권한명을 숫자로 매핑
priv_policy(9F), priv_policy_only(9F), priv_policy_choice(9F): 권한의 확인 리포트 및 감사