COM을 이용한 권한 상승 Moniker란, 사용자 계정 권한 제한(Limited User Accout : LUA )하에서 동작 해야 하는 응용 프로그램이 권한 상승을 할 수 있도록, COM 클래스의 활성화 작업을 수행하는 것입니다. LUA에 대한 더 자세한 사항은 Security in Longhorn : Focus on Least Privilege을 보시기 바랍니다.
Elevation Moniker를 사용할 때 Elevation moniker란, 권한이 제한된 상태로 실행 중인 COM 클래스가 시스템 날짜 및 시간을 설정하는 것과 같이,높은 권한을 필요로 하는 경우 해당 권한을 활성화 주는 것을 말합니다. 권한 상승 작업은 COM 클래스 자체 뿐만 아니라, COM 클래스를 사용하는 클라이언트까지, 두가지다 필요합니다. 먼저 COM 클래스는 권한 상승을 하기 위한 설정 작업으로 자신의 레지스트리 항목 중 Requirements 섹션에 별도의 기록을 수행해야 합니다. 그리고, COM 클라이언트는 별두 작업을 수행하기 보다, 권한 상승 Moniker을 이용하여 권한 상승요청을 하면 됩니다. 권한 상승 Moniker 자체는 응용 프로그램 호환성을 고려하여 구성하지 않았습니다. 즉 보안을 중심으로 고려하였기 때문에, 별도의 우회적인 회피방법을 제시하진 않습니다. 그래서 과거의 COM 클래스와 클라이언트 간의 권한 상승 문제로 응용 프로그램 호환성 오류가 발생할 수 있습니다. 예를 들어, WinWord와 같이 권한 상승을 높아야 하는 기존 COM 클래스를 COM 클라이언트에서 실행하려면, COM 클래스 뿐만 아니라, COM 클래스를 이용하는 클라이언트도 권한 상승 Moniker로 활성화 시켜야 합니다. 단, 기존 COM 클래스의 CLSID로 CoCreateInstance를 호출해 COM 클라이언트의 권한을 상승 시켰어도, COM 클라이언트의 권한은 COM 서버 프로세스의 권한을 따라가게 됩니다. 물론, 모든 COM 자체의 기능 수행에 반드시 권한 상승이 필요한 것은 아니지만, 다음과 같은 제한들로 정상적으로 동작하지 않을 것입니다.
COM 클라이언트의 권한이 높더라도 원격 COM 서버의 권한까지 높아지는 것은 아닙니다. 클라이언트가 권한 상승 Moniker로 권한 상승을 했다고 하더라도, COM 서버 자체가 자동적으로 권한 상승되진 않습니다.
만일 권한 상승된 COM 클래스가 COM 호출 시 impersonation(가장화)를 사용할 때, impersonation(가장화) 중에 상승된 권한을 잃게 될지 모릅니다.
만일 권한 상승된 COM 서버가 Running Object Table(ROT)상에 클래스를 등록할 때, 권한 상승되지 않은 클라이언트에서는 그 클래스를 활용하지 못합니다.
중간(Medium) 보다 높은 통합 레벨(Integraity Level : IL )로 동작하는 프로세스는 COM 활성화 중에 사용자 별 클래스를 적재 할 수 없습니다. 만일 COM 응용 프로그램이 Administrators 급 계정이던 아니던 간에 사용하게 하려면, HKEY_LOCAL_MACHINE 레지스트리 상에 응용 프로그램의 COM 클래스가 설치되어 있어야 합니다. 만일 Administrators 급 계정에서만 응용 프로그램을 사용하게 된다면 응용 프로그램 COM 클래스는 반드시 HKEY_USERS 쪽에 설치하셔야 합니다.
권한 상승되지 않은 응용 프로그램에서 상승된 응용 프로그램쪽으로 드래그 앤 드랍을 지원하지 않습니다.
필요사항 COM 클래스를 활성화 하기 위해 권한 상승 Moniker를 사용하기 앞서 클래스는 반드시 실행 사용자 또는 '활성자로써 활성화(Activate as Activator)'의 응용 프로그램 ID로 실행 할 수 있도록 설정되어 있어야 합니다. 만일 클래스가 여타 다른 ID하에서 실행되도록 설정하려면, Activation에서는 CO_E_RUNAS_VALUE_MUST_BE_AAA 에러를 돌려주게 됩니다. 클래스에서는 반드시 다중 언어 사용자 인터페이스(MUI) 호환이 되는 "친숙한" 표시 이름으로 되어 있어야 합니다. 여기서는 다음과 같은 레지스트리 항목이 필요하게 됩니다.:
HKEY_LOCAL_MACHINE\Software\Classes\CLSID\
{CLSID}\LocalizedString = <displayname>
만일 항목이 빠진 경우, Activation에서는 CO_E_MISSING_DISPLAYNAME 에러를 돌려주게 됩니다. 만일 MUI 파일이 빠진 경우 RegLoadMUIStringW API에서 에러 코드를 돌려주게 됩니다. 추가적으로, LUA 사용자 인터페이스에서 보여주게 될 응용 프로그램 아이콘을 표시하려면 다음 레지스트리 키를 추가해 줍니다.:
HKEY_LOCAL_MACHINE\Software\Classes\CLSID\
{CLSID}\IconReference = <applicationicon>
COM 클래스에서는 LUA-Enabled 와 같은 표시가 반드시 필요합니다. 이 사항을 적용하려면 다음과 같은 레지스트리 항목을 추가하시면 됩니다.
HKEY_LOCAL_MACHINE\Software\Classes\CLSID\
{CLSID}\Elevation\Enabled = 1
만일 항목이 빠져 있는 경우 Activation에서는 CO_E_ELEVATION_DISABLED이라는 에러를 돌려주게 됩니다. HKEY_LOCAL_MACHINE 항목 상에 이들 항목이 있는 경우, HKEY_CURRENT_USER 및 HKEY_USERS 항목에서는 없어야 합니다. 이는 COM 클래스의 권한 상승을 레지스트리 등록 권한이 없는 사용자가 멋대로 등록하는 경우를 방지하기 위해서 입니다.
권한 상승 Moniker 및 권한상승 UI 만일 클라이언트가 이미 권한 상승 Moniker로 권한 상승이 된 경우, 권한 상승 UI를 보여주지 않게 합니다.
권한 상승 Moniker를 사용하는 방법 권한 상승 Moniker는 표준 COM Moniker이며, 세션, 파티션 또는 큐 형태의 Moniker들과 유사합니다. 특정 권한 레벨을 특정 서버에 활성 요청을 관리합니다.Moniker 문자열에서 활성화 할 CLISID를 나타냅니다. 권한 상승 Moniker에서는 다음과 같은 실행 레벨 토큰들을 지원합니다.
앞의 문법 중에서 해당 GUID의 COM 클래스의 새로운 인스탄스를 받으려면 "new" Moniker를 사용하면 됩니다. 여기서 "new" Monker에서는 클래스 객체를 탑재한 후 IClassFactory::CreateInstance를 호출하기 위해 IClassFactory interface 를 내부적으로 사용한다는 것에 주의해주시기 바랍니다. 또한 권한 상승 Moniker가 IClassFactory를 구현하기 위해 클래스 객체를 얻을 때 이용 될 수 있습니다.그리고 호출자에서는 객체 인스탄스를 얻기 위해 IClassFactory::CreateInstance 를 호출하게 됩니다. 이 사항에 대한 문법은 다음과 같습니다.
한가지 추가적인 사항은 HWND 필드, hwnd가 있습니다.이 핸들은 대부분의 경우 권한 상승 UI의 부모가 될 윈도우를 나타내게 됩니다. 만일 hwnd가 NULL인 경우 COM은 현재 스레드에 관련된 Window Handle을 찾기 위해 GetActiveWindow를 호출하게 됩니다. 클라이언트가 스크립트로 구성되어, 발생되는 경우로 BIND_OPT3 구조체의 정보가 불완전하게 담기게 됩니다. 이 경우, COM에서는 스크립트 스레드와 관련된 Window를 사용하도록 시도하게 됩니다.
Over-The-Shoulder 권한 상승(OTS) Over-the-shoulder 권한 상승 (Over-the-shoulder elevation : OTS)은 사용자 자체 권한 이라기 보다 관리자 권한을 가진 사용자의 권한으로 COM 서버가 동작하는 클라이언트에서 볼 수 있는 시나리오 상황 입니다.(Over-the-shoulder 의 의미는 사전적으로 훔쳐보다로써, 클라이언트가 서버를 동작시키는 것과 같이 클라이언트 권한 밖에서 관리자 처럼 동작시키는 것을 의미합니다.) 이 시나리오에서는 서버로 COM을 호출하는 문제를 발생시킬 수 있습니다. 그 이유로는 서버가 명확하거나(대부분 프로그램 로직상으로), 무조건적으로(정확히 말하자면, 레지스트리를 이용하여) CoInitializeSecurity를 호출하지 못하기 때문입니다. 그런 서버들 때문에, COM에서는 서버로 COM을 호출 할 수 있도록 SELF, SYSTEM 및 Builtin\Administrators를 나타내는 보안 명세서를 산정하게 됩니다.이 명세서는 OTS 시나리오에서 동작하지 않습니다. 대신에 서버는 INTERACTIVE SID 및 System Group을 포함하는 ACL을 명시에 명확하고 무조건적적으로 방법을 벗어나 CoInitializeSecurity를 반드시 호출하게 해줍니다. 다음 예제 코드에서는 INTERACTIVE group SID로 보안 명세서(security descriptor : SD)를 어떻게 생성하는지 보여주게 됩니다.
[CODE] BOOL GetAccessPermissionsForLUAServer(SECURITY_DESCRIPTOR **ppSD) { // Local call permissions to IU, SY LPWSTR lpszSDDL = L"O:BAG:BAD:(A;;0x3;;;IU)(A;;0x3;;;SY)"; SECURITY_DESCRIPTOR *pSD; *ppSD = NULL; if (ConvertStringSecurityDescriptorToSecurityDescriptorW(lpszSDDL, SDDL_REVISION_1, (PSECURITY_DESCRIPTOR *)&pSD, NULL)) { *ppSD = pSD; return TRUE; } return FALSE; } [/CODE]
다음 예제 코드는 이전 예제 코드에서 SD로 명확하게 CoInitializeSecurity를 호출하는 방법을 보여줍니다.
COM 권한 및 위임 접근 라벨(COM Permissions and Mandatory Access Labels) Windows Vista에서 보안 상세서(security descriptors : SD)에 있는 위임 접근 라벨에 대한기본적인 내용을 소개하였습니다.라벨에서는 클라이언트가 COM 객체로 접근 실행할 수 있도록 지시하게 됩니다. 라벨에는 보안 명세서의 시스템 접근 제어 리스트(system access control list : SACL)내에 명시되어 있습니다. Windows Vista에서는 COM 자체적으로 SYSTEM_MANDATORY_LABEL_NO_EXECUTE_UP 라벨을 지원합니다. Windows Vista 이전 운영체제에서는 COM 권한 내의 SACLs들의 내용이 무시되었습니다. Windows Vista에서는 dcomcnfg.exe가 COM 권한 내에서 더 이상 통합 레벨(IL) 변경을 지원하지 않습니다. 반드시 프로그렘 적으로 설정하게끔 되어 있습니다. 다음 예제 코드에서는 모든 낮은 IL 클라이언트에서 실행/활성화 요청을 할 수 있도록 라벨을 이용하여 COM 보안 명세서를 어떻게 생성하는지에 대해 나타내고 있습니다. 이렇게 하면, 일정한 IL을 가진 클라이언트에서 실행, 활성화 또는 호출에서 실패된 COM 서버를 쓸 수 있게 됩니다.통합 레벨(IL)에 대한 더 자세한 사항은 Understanding and Working in Protected Mode Internet Explorer 안에 있는 "Understanding Windows Vista's Integrity Mechanism" 섹션을 보시기 바랍니다.
[CODE] BOOL GetLaunchActPermissionsWithIL (SECURITY_DESCRIPTOR **ppSD) { // Allow World Local Launch/Activation permissions. Label the SD for LOW IL Execute UP LPWSTR lpszSDDL = L"O:BAG:BAD:(A;;0xb;;;WD)S:(ML;;NX;;;LW)"; if (ConvertStringSecurityDescriptorToSecurityDescriptorW(lpszSDDL, SDDL_REVISION_1, (PSECURITY_DESCRIPTOR *)&pSD, NULL)) { *ppSD = pSD; return TRUE; } } BOOL SetLaunchActPermissions(HKEY hkey, PSECURITY_DESCRIPTOR pSD) { BOOL bResult = FALSE; DWORD dwLen = GetSecurityDescriptorLength(pSD); LONG lResult; lResult = RegSetValueExA(hkey, "LaunchPermission", 0, REG_BINARY, (BYTE*)pSD, dwLen); if (lResult != ERROR_SUCCESS) goto done; bResult = TRUE; done: return bResult; }; [/CODE]
CoCreateInstance 및 통합 레벨(IL) CoCreateInstance의 기능은 Windows Vista에 이르러 낮은IL 클라이언트에서 기본적으로 COM 서버를 연결하는 것을 방지하게 끔 변경되었습니다. 서버는 반드시 SASL로 명시하여 연결해야 명확하게 연결되게 됩니다.CoCreateInstance의 변화된 사항은 다음과 같습니다.
COM 서버 프로세스를 실행할 때, 서버 프로세스 토큰 내 IL이 클라이언트 또는 서버 토큰 IL으로 설정되어 있어야 하며, 무엇보다 IL이 낮아야 합니다.
기본적으로, COM은 어떠한 COM 서버의 인스탄스를 실행하기 위해 낮은 IL 클라이언트이 연결하는 작업 자체를 배제합니다.연결을 허용하려면, COM 서버의 실행/활성화 보안 명세서(Launch/Activation security descriptor)가 낮은 IL 라벨 상에 명시되어 있는 SACL이 담겨 있어야 합니다.(이와 같은 보안 명세서를 생성하기 위한 예제 코드를 이전 섹션에서 보실 수 있습니다.)
권한 상승된 서버 및 ROT 등록 만일 COM 서버에서 실행 객체 테이블(Running Object Table : ROT)에 등록하는 경우나 기타 클라이언트 상에서 등록을 할 수 있도록 하려면, 제일 먼저 을 원하는 경우 ROTFLAGS_ALLOWANYCLIENT 플래그를 사용하셔야 합니다. 단, '활성자로써 활성화(Activate as Activator)' 형태의 COM 서버에서는 ROTFLAGS_ALLOWANYCLIENT를 명시해줄 수 없는데 그 이유는 DCOM 서비스 컨트롤 관리자(DCOMSCM)에서 강제적으로 이 플래그에 대한 속임수 체크를 수행하기 때문입니다. 그러므로 Windows Vista에서는 COM에서 새로운 레지스트리 항목에 대한 지원을 추가해야 합니다. 새로운 레지스트리 항목은 클라이언트에 가능하게 만들어주는 ROT 등록을 명시적으로 할 수 있도록 서버를 허용하는 항목입니다.
HKEY_LOCAL_MACHINE\Software\Classes\AppID\
{ APPID }
REG_DWORD_ROTFlags
단 한개의 이 항목에 대해 적용가능한 값은 다음과 같습니다.
[CODE] ROTREGFLAGS_ALLOWANYCLIENT 0x1 [/CODE]
이 항목은 HKEY_LOCAL_MACHINE 영역에 있어야 합니다. 그리고 ROTFLAGS_ALLOWANYCLIENT 로 RunAs server가 제공되는 기능을 '활성자로써 활성화(Activate as Activator)'와 동일하게 동작하기 위한 사항입니다.
추가적인 사항 Reference BIND_OPTS3
기타 자료 Understanding and Working in Protected Mode Internet Explorer