드라이버 개발자를 위한 Windows 보안 모델
Windows 보안 모델은 보안 개체를 기반으로 합니다. 운영 체제의 각 구성 요소는 운영 체제가 담당하는 개체의 보안을 보장해야 합니다. 따라서 드라이버는 디바이스 및 디바이스 개체의 보안을 보호해야 합니다.
이 항목에서는 Windows 보안 모델이 커널 모드 드라이버에 적용되는 방법을 요약합니다.
Windows 보안 모델
Windows 보안 모델은 주로 개체별 권한을 기반으로 하며 시스템 전체 권한은 적습니다. 보안을 설정할 수 있는 개체에는 프로세스, 스레드, 이벤트 및 기타 동기화 개체뿐만 아니라 파일, 디렉터리 및 디바이스도 포함됩니다.
각 개체 유형에 대해 제네릭 읽기, 쓰기 및 실행 권한은 자세한 개체별 권한에 매핑됩니다. 예를 들어 파일 및 디렉터리의 경우 파일 또는 디렉터리를 읽거나 쓸 수 있는 권한, 확장 파일 특성을 읽거나 쓸 수 있는 권한, 디렉터리를 트래버스할 수 있는 권한, 개체의 보안 설명자를 쓸 수 있는 권한이 있습니다.
보안 모델에는 다음과 같은 개념이 포함됩니다.
- SID(보안 식별자)
- 액세스 토큰
- 보안 설명자
- ACL(액세스 제어 목록)
- 권한
SID(보안 식별자)
보안 식별자(보안 식별자, 보안 주체라고도 함)는 사용자, 그룹 또는 로그온 세션을 식별합니다. 각 사용자에게는 로그온 시 운영 체제에서 검색되는 고유한 SID가 있습니다.
SID는 운영 체제 또는 do기본 서버와 같은 기관에서 발급합니다. 일부 SID는 잘 알려져 있으며 이름 및 식별자를 갖습니다. 예를 들어 SID S-1-1-0은 모든 사람(또는 세계)을 식별합니다.
액세스 토큰
모든 프로세스에는 액세스 토큰이 있습니다. 액세스 토큰은 프로세스의 전체 보안 컨텍스트를 설명합니다. 여기에는 사용자의 SID, 사용자가 속한 그룹의 SID 및 로그온 세션의 SID뿐만 아니라 사용자에게 부여된 시스템 수준 권한 목록이 포함됩니다.
기본적으로 시스템은 프로세스의 스레드가 보안 개체와 상호 작용할 때마다 프로세스에 기본 액세스 토큰을 사용합니다. 그러나 스레드는 클라이언트 계정을 가장할 수 있습니다. 스레드가 가장하는 경우 자체 기본 토큰 외에도 가장 토큰이 있습니다. 가장 토큰은 스레드가 가장하는 사용자 계정의 보안 컨텍스트를 설명합니다. 가장은 RPC(원격 프로시저 호출) 처리에서 특히 일반적입니다.
스레드 또는 프로세스에 대한 제한된 보안 컨텍스트를 설명하는 액세스 토큰을 제한된 토큰이라고 합니다. 제한된 토큰의 SID는 액세스를 허용하지 않고 보안 개체에 대한 액세스를 거부하도록만 설정할 수 있습니다. 또한 토큰은 제한된 시스템 수준 권한 집합을 설명할 수 있습니다. 사용자의 SID 및 ID는 동일하게 기본 프로세스가 제한된 토큰을 사용하는 동안 사용자의 액세스 권한이 제한됩니다. CreateRestrictedToken 함수는 제한된 토큰을 만듭니다.
보안 설명자
명명된 모든 Windows 개체에는 보안 설명자가 있습니다. 이름 없는 개체도 있습니다. 보안 설명자는 ACL과 함께 개체의 소유자 및 그룹 SID를 설명합니다.
개체의 보안 설명자는 일반적으로 개체를 만드는 함수에 의해 생성됩니다. 드라이버가 IoCreateDevice 또는 IoCreateDeviceSecure 루틴을 호출하여 디바이스 개체를 만들 때 시스템은 생성된 디바이스 개체에 보안 설명자를 적용하고 개체에 대한 ACL을 설정합니다. 대부분의 디바이스에서 ACL은 INF(디바이스 정보) 파일에 지정됩니다.
자세한 내용은 커널 드라이버 설명서의 보안 설명자 입니다.
Access Control 목록
ACL(액세스 제어 목록)을 사용하면 개체에 대한 액세스를 세밀하게 제어할 수 있습니다. ACL은 각 개체에 대한 보안 설명자의 일부입니다.
각 ACL에는 ACE(Access Control Entries)가 0개 이상 포함되어 있습니다. 각 ACE에는 사용자, 그룹 또는 컴퓨터를 식별하는 단일 SID와 해당 SID에 대해 거부되거나 허용되는 권한 목록이 포함됩니다.
디바이스 개체에 대한 ACL
디바이스 개체에 대한 ACL은 다음 세 가지 방법 중에서 설정할 수 있습니다.
- 디바이스 유형에 대한 기본 보안 설명자에서 설정합니다.
- RtlCreateSecurityDescriptor 함수에 의해 프로그래밍 방식으로 생성되고 RtlSetDaclSecurityDescriptor 함수에 의해 설정됩니다.
- 디바이스의 INF 파일 또는 IoCreateDeviceSecure 루틴에 대한 호출에서 SDDL(보안 설명자 정의 언어)에 지정됩니다.
모든 드라이버는 INF 파일에서 SDDL을 사용하여 디바이스 개체에 ACL을 지정해야 합니다.
SDDL은 구성 요소가 문자열 형식으로 ACL을 만들 수 있도록 하는 확장 가능한 설명 언어입니다. SDDL은 사용자 모드 및 커널 모드 코드 모두에서 사용됩니다. 다음 그림에서는 디바이스 개체에 대한 SDDL 문자열의 형식을 보여 줍니다.
Access 값은 허용되는 액세스 유형을 지정합니다. SID 값은 Access 값이 적용되는 대상(예: 사용자 또는 그룹)을 결정하는 보안 식별자를 지정합니다.
예를 들어 다음 SDDL 문자열을 사용하면 시스템(SY)에서 모든 항목에 액세스할 수 있으며 WD(다른 모든 사용자)는 읽기 전용으로 액세스할 수 있습니다.
“D:P(A;;GA;;;SY)(A;;GR;;;WD)”
헤더 파일 wdmsec.h에는 디바이스 개체에 적합한 미리 정의된 SDDL 문자열 집합도 포함되어 있습니다. 예를 들어 헤더 파일은 다음과 같이 SDDL_DEVOBJ_SYS_ALL_ADM_RWX_WORLD_RWX_RES_RWX 정의합니다.
"D:P(A;;GA;;;SY)(A;;GRGWGX;;;BA)(A;;GRGWGX;;;WD)(A;;GRGWGX;;;RC)"
이 문자열의 첫 번째 세그먼트를 사용하면 커널 및 운영 체제(SY)가 디바이스를 완벽하게 제어할 수 있습니다. 두 번째 세그먼트를 사용하면 기본 제공 관리 BA(istrators 그룹)의 모든 사용자가 전체 디바이스에 액세스할 수 있지만 ACL은 변경할 수 없습니다. 세 번째 세그먼트를 사용하면 WD(모든 사용자)가 디바이스를 읽거나 쓸 수 있으며, 네 번째 세그먼트는 신뢰할 수 없는 코드(RC)에 동일한 권한을 부여합니다. 드라이버는 미리 정의된 문자열을 있는 그대로 사용하거나 디바이스 개체별 문자열의 모델로 사용할 수 있습니다.
스택의 모든 디바이스 개체에는 동일한 ACL이 있어야 합니다. 스택의 한 디바이스 개체에서 ACL을 변경하면 전체 디바이스 스택의 ACL이 변경됩니다.
그러나 스택에 새 디바이스 개체를 추가해도 새 디바이스 개체(ACL이 있는 경우) 또는 스택에 있는 기존 디바이스 개체의 ACL은 변경되지 않습니다. 드라이버가 새 디바이스 개체를 만들어 스택의 맨 위에 연결하는 경우 드라이버는 다음 하위 드라이버에서 DeviceObject.Characteristics 필드를 복사하여 스택의 ACL을 새 디바이스 개체에 복사해야 합니다.
IoCreateDeviceSecure 루틴은 WD 및 SY와 같은 미리 정의된 SID를 사용하는 SDDL 문자열의 하위 집합을 지원합니다. 사용자 모드 API 및 INF 파일은 전체 SDDL 구문을 지원합니다.
ACL을 사용하는 보안 검사
프로세스가 개체에 대한 액세스를 요청하는 경우 보안 검사 호출자의 액세스 토큰에 있는 SID와 개체의 ACL을 비교합니다.
시스템은 엄격한 하향식 순서로 ACE를 비교하고 첫 번째 관련 일치에서 중지합니다. 따라서 ACL을 만들 때는 항상 해당 권한 부여 ACE보다 거부 API를 배치해야 합니다. 다음 예제에서는 비교가 진행되는 방법을 보여 줍니다.
예제 1: ACL과 액세스 토큰 비교
예제 1은 시스템이 ACL을 호출자 프로세스에 대한 액세스 토큰과 비교하는 방법을 보여 줍니다. 호출자가 다음 표에 표시된 ACL이 있는 파일을 열려고 하는 경우를 가정합니다.
샘플 파일 ACL
Permission | SID | Access |
---|---|---|
허용 | 회계업 | 쓰기, 삭제 |
허용 | Sales | Append |
Deny | Legal | 추가, 쓰기, 삭제 |
허용 | 모두 | 읽기 |
이 ACL에는 회계, 판매, 법률 및 모든 사용자 그룹에 특별히 적용되는 4개의 ACE가 있습니다.
다음으로, 요청 프로세스에 대한 액세스 토큰에 다음 순서대로 사용자 1명과 그룹 3개에 대한 SID가 포함되어 있다고 가정합니다.
사용자 짐(S-1-5-21...)
그룹 회계(S-1-5-22...)
그룹 법적(S-1-5-23...)
모든 사용자 그룹화(S-1-1-0)
파일 ACL을 액세스 토큰과 비교할 때 시스템은 먼저 파일의 ACL에서 사용자 Jim에 대한 ACE를 찾습니다. 아무도 나타나지 않으므로 다음으로 회계 그룹에 대한 ACE를 찾습니다. 이전 표에 표시된 것처럼 회계 그룹에 대한 ACE가 파일 ACL의 첫 번째 항목으로 표시되므로 Jim의 프로세스에는 파일을 쓰거나 삭제할 수 있는 권한이 부여되고 비교가 중지됩니다. 대신 법률 그룹에 대한 ACE가 ACL의 회계 그룹에 대한 ACE 앞에 있는 경우 프로세스는 파일에 대한 쓰기, 추가 및 삭제 액세스가 거부됩니다.
예제 2: ACL과 제한된 토큰 비교
시스템은 제한되지 않은 토큰에 있는 토큰과 비교하는 것과 동일한 방식으로 ACL을 제한된 토큰과 비교합니다. 그러나 제한된 토큰의 거부 SID는 ACL의 거부 ACE만 일치시킬 수 있습니다.
예제 2는 시스템이 파일의 ACL을 제한된 토큰과 비교하는 방법을 보여 줍니다. 파일에 이전 테이블에 표시된 것과 동일한 ACL이 있다고 가정합니다. 그러나 이 예제에서는 프로세스에 다음 SID를 포함하는 제한된 토큰이 있습니다.
사용자 짐(S-1-5-21...) 거부
그룹 회계(S-1-5-22...) 거부
그룹 법적(S-1-5-23...) 거부
모든 사용자 그룹화(S-1-1-0)
파일의 ACL은 Jim의 SID를 나열하지 않으므로 시스템이 회계 그룹 SID로 진행됩니다. 파일의 ACL에는 회계 그룹에 대한 ACE가 있지만 이 ACE는 액세스를 허용합니다. 따라서 액세스를 거부하는 프로세스의 제한된 토큰에서 SID와 일치하지 않습니다. 결과적으로 시스템은 법적 그룹 SID로 진행됩니다. 파일의 ACL에는 액세스를 거부하는 법적 그룹에 대한 ACE가 포함되어 있으므로 프로세스는 파일을 작성, 추가 또는 삭제할 수 없습니다.
권한
권한은 사용자가 로컬 컴퓨터에서 드라이버 로드, 시간 변경 또는 시스템 종료와 같은 시스템 관련 작업을 수행할 수 있는 권한입니다.
권한은 개체가 아닌 시스템 관련 작업 및 리소스에 적용되고 운영 체제가 아닌 시스템 관리자가 사용자 또는 그룹에 할당하기 때문에 액세스 권한과 다릅니다.
각 프로세스에 대한 액세스 토큰에는 프로세스에 부여된 권한 목록이 포함됩니다. 사용하려면 먼저 권한을 구체적으로 사용하도록 설정해야 합니다. 권한에 대한 자세한 내용은 커널 드라이버 설명서의 권한을 참조하세요.
Windows 보안 모델 시나리오: 파일 만들기
시스템은 프로세스가 파일 또는 개체에 대한 핸들을 만들 때마다 Windows 보안 모델에 설명된 보안 구문을 사용합니다.
다음 다이어그램에서는 사용자 모드 프로세스가 파일을 만들려고 할 때 트리거되는 보안 관련 작업을 보여 줍니다.
이전 다이어그램은 사용자 모드 애플리케이션이 CreateFile 함수를 호출할 때 시스템이 응답하는 방법을 보여 줍니다. 다음 노트는 그림의 원을 그리는 숫자를 참조합니다.
- 사용자 모드 애플리케이션은 CreateFile 함수를 호출하여 유효한 Microsoft Win32 파일 이름을 전달합니다.
- 사용자 모드 Kernel32.dll 요청을 Ntdll.dll 전달하여 Win32 이름을 Microsoft Windows NT 파일 이름으로 변환합니다.
- Ntdll.dll Windows 파일 이름으로 NtCreateFile 함수를 호출합니다. Ntoskrnl.exe 내에서 I/O 관리자는 NtCreateFile을 처리합니다.
- I/O 관리자는 요청을 개체 관리자 호출로 다시 패키지합니다.
- 개체 관리자는 기호 링크를 확인하고 사용자가 파일을 만들 경로에 대한 순회 권한을 갖도록 합니다. 자세한 내용은 개체 관리자의 보안 검사 참조하세요.
- 개체 관리자는 요청과 연결된 기본 개체 형식을 소유하는 시스템 구성 요소를 호출합니다. 파일 만들기 요청의 경우 이 구성 요소는 디바이스 개체를 소유하는 I/O 관리자입니다.
- I/O 관리자는 사용자가 디바이스에 필요한 액세스 권한을 갖도록 사용자 프로세스에 대한 액세스 토큰에 대해 디바이스 개체의 보안 설명자를 검사. 자세한 내용은 I/O 관리자의 보안 검사 참조하세요.
- 사용자 프로세스에 필요한 액세스 권한이 있는 경우 I/O 관리자는 핸들을 만들고 디바이스 또는 파일 시스템의 드라이버에 IRP_MJ_CREATE 요청을 보냅니다.
- 드라이버는 필요에 따라 추가 보안 검사 수행합니다. 예를 들어 요청이 디바이스의 네임스페이스에 개체를 지정하는 경우 드라이버는 호출자에게 필요한 액세스 권한이 있는지 확인해야 합니다. 자세한 내용은 드라이버의 보안 검사 참조하세요.
개체 관리자의 보안 검사
액세스 권한을 검사 책임은 이러한 검사 수행할 수 있는 최상위 구성 요소에 속합니다. 개체 관리자가 호출자의 액세스 권한을 확인할 수 있는 경우 이렇게 합니다. 그렇지 않은 경우 개체 관리자는 기본 개체 형식을 담당하는 구성 요소에 요청을 전달합니다. 해당 구성 요소는 가능한 경우 액세스를 확인합니다. 이 작업을 수행할 수 없으면 드라이버와 같이 여전히 낮은 구성 요소에 요청을 전달합니다.
개체 관리자는 이벤트 및 뮤텍스 잠금과 같은 간단한 개체 형식에 대한 ACL을 검사. 네임스페이스가 있는 개체의 경우 형식 소유자는 보안 검사 수행합니다. 예를 들어 I/O 관리자는 디바이스 개체 및 파일 개체의 형식 소유자로 간주됩니다. 개체 관리자가 이름을 구문 분석할 때 디바이스 개체 또는 파일 개체의 이름을 찾은 경우 위에서 설명한 파일 만들기 시나리오에서와 같이 이름을 I/O 관리자로 전달합니다. 그러면 I/O 관리자가 액세스 권한을 검사. 이름이 디바이스 네임스페이스 내의 개체를 지정하는 경우 I/O 관리자는 이름을 디바이스(또는 파일 시스템) 드라이버에 넘겨 줍니다. 해당 드라이버는 요청된 액세스의 유효성을 검사합니다.
I/O 관리자의 보안 검사
I/O 관리자가 핸들을 만들 때 프로세스 액세스 토큰에 대한 개체의 권한을 검사 다음 핸들과 함께 사용자에게 부여된 권한을 저장합니다. 나중에 I/O 요청이 도착하면 I/O 관리자가 핸들과 연결된 권한을 검사 프로세스에 요청된 I/O 작업을 수행할 수 있는 권한이 있는지 확인합니다. 예를 들어 프로세스에서 나중에 쓰기 작업을 요청하는 경우 I/O 관리자는 핸들과 연결된 권한을 검사 호출자가 개체에 대한 쓰기 권한을 갖도록 합니다.
핸들이 중복된 경우 복사본에서 권한을 제거할 수 있지만 추가되지는 않습니다.
I/O 관리자는 개체를 만들 때 제네릭 Win32 액세스 모드를 개체별 권한으로 변환합니다. 예를 들어 파일 및 디렉터리에는 다음 권한이 적용되어 있습니다.
Win32 액세스 모드 | 개체별 권한 |
---|---|
GENERIC_READ | ReadData |
GENERIC_WRITE | WriteData |
GENERIC_EXECUTE | ReadAttributes |
GENERIC_ALL | 모두 |
파일을 만들려면 프로세스에 대상 경로의 부모 디렉터리에 대한 순회 권한이 있어야 합니다. 예를 들어 \Device\CDROM0\Directory\File.txt 만들려면 프로세스에 \Device, \Device\CDROM0 및 \Device\CDROM0\Directory를 트래버스할 권한이 있어야 합니다. I/O 관리자는 이러한 디렉터리에 대한 순회 권한만 검사.
I/O 관리자는 파일 이름을 구문 분석할 때 순회 권한을 검사. 파일 이름이 기호 링크인 경우 I/O 관리자는 이를 전체 경로로 확인하고 루트에서 시작하여 순회 권한을 검사. 예를 들어 기호 링크 \DosDevices\D가 Windows NT 디바이스 이름 \Device\CDROM0에 매핑된다고 가정합니다. 프로세스에는 \Device 디렉터리에 대한 순회 권한이 있어야 합니다.
자세한 내용은 개체 핸들 및개체 보안을 참조하세요.
드라이버의 보안 검사
운영 체제 커널은 사실상 모든 드라이버를 자체 네임스페이스가 있는 파일 시스템으로 처리합니다. 따라서 호출자가 디바이스 네임스페이스에서 개체를 만들려고 할 때 I/O 관리자는 프로세스에 경로의 디렉터리에 대한 순회 권한이 있음을 검사.
WDM 드라이버를 사용하면 FILE_DEVICE_SECURE_OPEN 지정하는 Device Object를 만들지 않는 한 I/O 관리자가 네임스페이스에 대한 보안 검사 수행하지 않습니다. FILE_DEVICE_SECURE_OPEN 설정되지 않은 경우 드라이버는 네임스페이스의 보안을 보장해야 합니다. 자세한 내용은 디바이스 네임스페이스 액세스 제어 및 디바이스 개체 보안을 참조하세요.
WDF 드라이버의 경우 애플리케이션이 디바이스의 네임스페이스 내의 이름에 액세스할 수 있도록 허용하기 전에 디바이스의 보안 설명자가 검사 있도록 FILE_DEVICE_SECURE_OPEN 플래그가 항상 설정됩니다. 자세한 내용은 KMDF 드라이버에서 디바이스 액세스 제어를 참조 하세요.
Windows 보안 경계
서로 다른 권한 수준의 사용자 모드 호출자와 통신하는 드라이버는 트러스트 경계를 넘는 것으로 간주될 수 있습니다. 신뢰 경계는 낮은 권한 있는 프로세스에서 더 높은 권한 있는 프로세스로 교차하는 모든 코드 실행 경로입니다.
권한 수준의 차이가 높을수록 대상 드라이버 또는 프로세스에 대한 권한 상승 공격과 같은 공격을 수행하려는 공격자에게 경계가 더 흥미로울 수 있습니다.
위협 모델을 만드는 프로세스의 일부는 보안 경계를 검사하고 예기치 않은 경로를 찾는 것입니다. 자세한 내용은 드라이버에 대한 위협 모델링을 참조 하세요.
트러스트 경계를 넘어가는 모든 데이터는 신뢰할 수 없으며 유효성을 검사해야 합니다.
이 다이어그램에서는 커널 드라이버 3개와 앱 컨테이너에 하나씩, 관리자 권한으로 실행되는 앱 1개 등 2개의 앱을 보여줍니다. 빨간색 선은 예제 신뢰 경계를 나타냅니다.
앱 컨테이너는 추가 제약 조건을 제공할 수 있고 관리자 수준에서 실행되지 않으므로 신뢰 경계가 앱 컨테이너(매우 낮은 권한 프로세스)와 커널 드라이버 사이에 있기 때문에 경로(1)는 에스컬레이션 공격에 대한 위험 수준이 높습니다.
앱이 관리자 권한으로 실행되고 커널 드라이버로 직접 호출되므로 경로(2)는 위험 경로가 낮습니다. 관리 이미 시스템에 대한 매우 높은 권한이므로 관리자에서 커널로의 공격 표면은 공격자에게 흥미로운 대상이 아니지만 여전히 주목할 만한 신뢰 경계입니다.
경로(3)는 위협 모델을 만들지 않은 경우 놓칠 수 있는 여러 트러스트 경계를 넘어가는 코드 실행 경로의 예입니다. 이 예제에서는 드라이버 1이 사용자 모드 앱에서 입력을 받아 드라이버 3에 직접 전달하므로 드라이버 1과 드라이버 3 사이에 신뢰 경계가 있습니다.
사용자 모드에서 드라이버로 들어오는 모든 입력은 신뢰할 수 없으며 유효성을 검사해야 합니다. 다른 드라이버에서 들어오는 입력은 이전 드라이버가 단순한 통과인지 여부에 따라 신뢰할 수 없을 수도 있습니다(예: 앱 1에서 드라이버 1이 데이터를 수신했으며 드라이버 1이 데이터에 대한 유효성 검사를 수행하지 않고 드라이버 3에 전달한 경우). 완전한 위협 모델을 만들어 모든 공격 표면을 식별하고 경계를 신뢰하고 경계를 넘어가는 모든 데이터의 유효성을 검사해야 합니다.
Windows 보안 모델 권장 사항
- IoCreateDeviceSecure 루틴에 대한 호출에서 강력한 기본 ACL을 설정합니다.
- 각 디바이스에 대한 INF 파일에서 ACL을 지정합니다. 이러한 ACL은 필요한 경우 타이트한 기본 ACL을 느슨하게 할 수 있습니다.
- FILE_DEVICE_SECURE_OPEN 특성을 설정하여 디바이스 네임스페이스에 디바이스 개체 보안 설정을 적용합니다.
- 이러한 액세스를 악의적으로 악용할 수 없는 한 FILE_ANY_ACCESS 허용하는 IOCTL을 정의하지 마세요.
- IoValidateDeviceIoControlAccess 루틴을 사용하여 FILE_ANY_ACCESS 허용하는 기존 IOCTLS에 대한 보안을 강화합니다.
- 위협 모델을 만들어 보안 경계를 검사하고 예기치 않은 경로를 찾습니다. 자세한 내용은 드라이버에 대한 위협 모델링을 참조 하세요.
- 추가 드라이버 보안 권장 사항은 드라이버 보안 검사 목록을 참조하세요.