드라이버 개발자를 위한 Windows 보안 모델

Windows 보안 모델은 보안 개체를 기반으로 합니다. 운영 체제의 각 구성 요소는 책임이 있는 개체의 보안을 보장해야 합니다. 따라서 드라이버는 디바이스 및 디바이스 개체의 보안을 보호해야 합니다.

이 항목에서는 Windows 보안 모델이 커널 모드 드라이버에 적용되는 방법을 요약합니다.

Windows 보안 모델

Windows 보안 모델은 주로 개체별 권한을 기반으로 하며 시스템 전체 권한은 적습니다. 보호될 수 있는 개체에는 프로세스, 스레드, 이벤트 및 기타 동기화 개체뿐만 아니라 파일, 디렉터리 및 디바이스도 포함됩니다.

각 개체 유형에 대해 제네릭 읽기, 쓰기 및 실행 권한은 자세한 개체별 권한에 매핑됩니다. 예를 들어 파일 및 디렉터리의 경우 파일 또는 디렉터리를 읽거나 쓸 수 있는 권한, 확장 파일 특성을 읽거나 쓸 수 있는 권한, 디렉터리를 트래버스할 권리, 개체의 보안 설명자를 작성할 수 있는 권한이 있습니다.

보안 모델에는 다음과 같은 개념이 포함됩니다.

  • SID(보안 식별자)
  • 액세스 토큰
  • 보안 설명자
  • ACL(액세스 제어 목록)
  • 권한

SID(보안 식별자)

보안 식별자(보안 식별자, 보안 주체라고도 함)는 사용자, 그룹 또는 로그온 세션을 식별합니다. 각 사용자에게는 로그온 시 운영 체제에서 검색되는 고유한 SID가 있습니다.

SID는 운영 체제 또는 도메인 서버와 같은 기관에서 발급합니다. 일부 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(Access Control Lists)을 사용하면 개체에 대한 액세스를 세분화하여 제어할 수 있습니다. ACL은 각 개체에 대한 보안 설명자의 일부입니다.

각 ACL에는 ACE(Access Control 항목)가 0개 이상 포함되어 있습니다. 각 ACE에는 사용자, 그룹 또는 컴퓨터를 식별하는 단일 SID와 해당 SID에 대해 거부되거나 허용되는 권한 목록이 포함됩니다.

디바이스 개체에 대한 ACL

디바이스 개체에 대한 ACL은 다음 세 가지 방법 중에서 설정할 수 있습니다.

  • 디바이스 유형에 대한 기본 보안 설명자에서 를 설정합니다.
  • RtlCreateSecurityDescriptor 함수에 의해 프로그래밍 방식으로 생성되고 RtlSetDaclSecurityDescriptor 함수에 의해 설정됩니다.
  • 디바이스의 INF 파일 또는 IoCreateDeviceSecure 루틴에 대한 호출에서 SDDL(보안 설명자 정의 언어)에 지정됩니다.

모든 드라이버는 INF 파일에서 SDDL을 사용하여 디바이스 개체에 대한 ACL을 지정해야 합니다.

SDDL은 구성 요소가 문자열 형식으로 ACL을 만들 수 있도록 하는 확장 가능한 설명 언어입니다. SDDL은 사용자 모드 및 커널 모드 코드 모두에서 사용됩니다. 다음 그림에서는 디바이스 개체에 대한 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(Administrators 그룹)의 모든 사용자가 전체 디바이스에 액세스할 수 있지만 ACL을 변경하지는 않을 수 있습니다. 세 번째 세그먼트를 사용하면 WD(모든 사용자)가 디바이스를 읽거나 쓸 수 있으며, 네 번째 세그먼트는 신뢰할 수 없는 코드(RC)에 동일한 권한을 부여합니다. 드라이버는 미리 정의된 문자열을 있는 그대로 사용하거나 디바이스 개체별 문자열의 모델로 사용할 수 있습니다.

스택의 모든 디바이스 개체에는 동일한 ACL이 있어야 합니다. 스택의 한 디바이스 개체에서 ACL을 변경하면 전체 디바이스 스택의 ACL이 변경됩니다.

그러나 스택에 새 디바이스 개체를 추가해도 새 디바이스 개체의 ACL(ACL이 있는 경우) 또는 스택에 있는 기존 디바이스 개체의 ACL은 변경되지 않습니다. 드라이버가 새 디바이스 개체를 만들고 스택의 맨 위에 연결하면 드라이버는 다음 하위 드라이버에서 DeviceObject.Characteristics 필드를 복사하여 스택의 ACL을 새 디바이스 개체에 복사해야 합니다.

IoCreateDeviceSecure 루틴은 WD 및 SY와 같은 미리 정의된 SID를 사용하는 SDDL 문자열의 하위 집합을 지원합니다. 사용자 모드 API 및 INF 파일은 전체 SDDL 구문을 지원합니다.

ACL을 사용한 보안 검사

프로세스가 개체에 대한 액세스를 요청하는 경우 보안 검사는 개체의 ACL을 호출자의 액세스 토큰에 있는 SID와 비교합니다.

시스템은 엄격한 하향식 순서로 AES를 비교하고 첫 번째 관련 일치 항목에서 중지합니다. 따라서 ACL을 만들 때 항상 해당 권한 부여 AES보다 거부 AES를 배치해야 합니다. 다음 예제에서는 비교가 진행되는 방법을 보여 줍니다.

예제 1: ACL과 액세스 토큰 비교

예제 1에서는 시스템이 ACL을 호출자 프로세스에 대한 액세스 토큰과 비교하는 방법을 보여 줍니다. 호출자가 다음 표에 표시된 ACL이 있는 파일을 열려고 하는 것으로 가정합니다.

샘플 파일 ACL

사용 권한 SID Access
허용 회계 쓰기, 삭제
허용 Sales Append
거부 Legal 추가, 쓰기, 삭제
허용 모든 사람 읽기

이 ACL에는 회계, 판매, 법률 및 모든 사용자 그룹에 특별히 적용되는 4개의 AE가 있습니다.

다음으로, 요청 프로세스에 대한 액세스 토큰에 다음 순서대로 사용자 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의 Deny 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가 포함되어 있으므로 프로세스에서 파일을 작성, 추가 또는 삭제할 수 없습니다.

권한

권한은 사용자가 로컬 컴퓨터에서 드라이버 로드, 시간 변경 또는 시스템 종료와 같은 시스템 관련 작업을 수행할 수 있는 권한입니다.

권한은 개체가 아닌 시스템 관련 작업 및 리소스에 적용되고 운영 체제가 아닌 시스템 관리자가 사용자 또는 그룹에 할당하기 때문에 액세스 권한과 다릅니다.

각 프로세스에 대한 액세스 토큰에는 프로세스에 부여된 권한 목록이 포함됩니다. 사용 전에 권한을 구체적으로 사용하도록 설정해야 합니다. privilges에 대한 자세한 내용은 커널 드라이버 설명서의 권한을 참조하세요.

Windows 보안 모델 시나리오: 파일 만들기

시스템은 프로세스가 파일 또는 개체에 대한 핸들을 만들 때마다 Windows 보안 모델에 설명된 보안 구문을 사용합니다.

다음 다이어그램은 사용자 모드 프로세스가 파일을 만들려고 할 때 트리거되는 보안 관련 작업을 보여 줍니다.

사용자 모드 프로세스가 파일을 만들려고 할 때 보안 관련 작업을 보여 주는 순서도입니다.

이전 다이어그램은 사용자 모드 애플리케이션이 CreateFile 함수를 호출할 때 시스템이 응답하는 방법을 보여 줍니다. 다음 노트는 그림의 원을 그리는 숫자를 참조합니다.

  1. 사용자 모드 애플리케이션은 CreateFile 함수를 호출하여 유효한 Microsoft Win32 파일 이름을 전달합니다.
  2. 사용자 모드 Kernel32.dll 요청을 Ntdll.dll 전달하여 Win32 이름을 Microsoft Windows NT 파일 이름으로 변환합니다.
  3. Ntdll.dll Windows 파일 이름으로 NtCreateFile 함수를 호출합니다. Ntoskrnl.exe 내에서 I/O 관리자는 NtCreateFile을 처리합니다.
  4. I/O 관리자는 요청을 개체 관리자 호출로 다시 패키징합니다.
  5. 개체 관리자는 기호 링크를 확인하고 사용자가 파일을 만들 경로에 대한 순회 권한을 갖도록 합니다. 자세한 내용은 개체 관리자의 보안 검사를 참조하세요.
  6. 개체 관리자는 요청과 연결된 기본 개체 형식을 소유하는 시스템 구성 요소를 호출합니다. 파일 만들기 요청의 경우 이 구성 요소는 디바이스 개체를 소유하는 I/O 관리자입니다.
  7. I/O 관리자는 디바이스 개체의 보안 설명자를 사용자 프로세스에 대한 액세스 토큰에 대해 확인하여 사용자에게 디바이스에 필요한 액세스 권한이 있는지 확인합니다. 자세한 내용은 I/O 관리자의 보안 검사를 참조하세요.
  8. 사용자 프로세스에 필요한 액세스 권한이 있는 경우 I/O 관리자는 핸들을 만들고 디바이스 또는 파일 시스템의 드라이버에 IRP_MJ_CREATE 요청을 보냅니다.
  9. 드라이버는 필요에 따라 추가 보안 검사를 수행합니다. 예를 들어 요청이 디바이스의 네임스페이스에 개체를 지정하는 경우 드라이버는 호출자에게 필요한 액세스 권한이 있는지 확인해야 합니다. 자세한 내용은 드라이버의 보안 검사를 참조하세요.

개체 관리자의 보안 검사

액세스 권한을 확인하는 책임은 이러한 검사를 수행할 수 있는 최상위 구성 요소에 속합니다. 개체 관리자가 호출자의 액세스 권한을 확인할 수 있는 경우 이렇게 합니다. 그렇지 않은 경우 개체 관리자는 기본 개체 형식을 담당하는 구성 요소에 요청을 전달합니다. 이 구성 요소는 가능한 경우 액세스를 확인합니다. 이렇게 할 수 없으면 드라이버와 같이 여전히 낮은 구성 요소에 요청을 전달합니다.

개체 관리자는 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에 대한 보안을 강화합니다.
  • 보안 경계를 검사하고 예기치 않은 경로를 찾는 위협 모델을 만듭니다. 자세한 내용은 드라이버에 대한 위협 모델링을 참조하세요.
  • 추가 드라이버 보안 권장 사항은 드라이버 보안 검사 목록을 참조하세요.

참고 항목

디바이스 개체 보안

드라이버 보안 검사 목록