[하루한줄] Dumping Stored Credentials with SeTrustedCredmanAccessPrivilege

URL

Dumping Stored Credentials with SeTrustedCredmanAccessPrivilege

Target

Windows

Explain

Windows에서는 Credential Manager를 통해 credential를 조작할 수 있습니다. Credential들은 DPAPI를 통해 보호되며, 시스템에 인증된 사용자만 접근할 수 있습니다.

예를 들어, Remote Desktop Client에서는 CredWrite라는 API를 통해 domain credential을 저장합니다. 이 때 CREDENTIAL 구조체에 유저명과 비밀번호를 저장하게 되며 type은 CRED_TYPE_DOMAIN_PASSWORD으로 세팅됩니다. 이렇게 저장된 credential들은 CredRead, CredEnumerate 같은 API를 통해 읽어올 수 있지만, CRED_TYPE_DOMAIN_PASSWORD로 type이 세팅되면 credential을 읽어와도 구조적으로 비밀번호를 읽을 수 없게 구현되어 있습니다. NTLM, Kerberos, TSSSP 같이 LSASS 프로세스에서 실행되는 보안 패키지들은 내부 API를 통해 이런 제약 없이 credential 비밀번호에 접근이 가능합니다.

Credential은 사용자의 DPAPI 키로 암호화되어 파일 형식으로 저장됩니다. 이를 직접적으로 복호화하여 비밀번호를 읽어올수 없는 이유는 사용자의DPAPI키를 사용하더라도 LSASS에서 실행되는 코드에서만 DPAPI를 호출하여 복호화할 수 있도록 구현되어 있기 때문입니다. 따라서Mimikatz같은 툴에서는LSASS`에 코드를 삽입하거나 메모리를 바로 읽어들이는 등 방식을 통해 credential을 읽어들입니다.

이 글에서 James Forshaw는 LSASS에 코드를 삽입하지 않고 SeTrustedCredmanAccessPrivilege 권한을 이용해 credential을 복호화하는 새로운 방법을 제안합니다.

SeTrustedCredmanAccessPrivilege권한은 사용자가 인증된 사용자로서 Credential Manager에 접근할 수 있도록 하는 권한입니다. LSASRV.dll에 구현되어 있는 코드를 보면 CredpIsRpcClientTrusted 함수에서 해당 권한을 체크하는데, 이 함수는 CredrReadByTokenHandleCredrBackupCredentials 이 두 함수에서만 호출됩니다. 이 중 CredBackupCredentials 함수는 사용자의 credential을 백업하는 기능을 제공하며 SeTrustedCredmanAccessPrivilege 권한만 가지고 있으면 호출이 가능합니다. CREDWIZ.exe 프로그램에서 해당 함수를 사용합니다. CREDWIZ.exe를 실행하면 백업할 경로를 지정하고 Winlogon 프로세스에 RPC를 호출하여 credential을 백업하는데, 이 때 백업하는 데이터에는 모든 정보가 포함되어 있습니다. 이를 다시 복구하며 모든 정보가 담겨 있는 credential을 얻을 수 있습니다.

따라서 관리자 권한으로 아래 과정을 통해 모든 사용자의 credential을 획득할 수 있습니다.

  1. WinLogon 프로세스에 접근해 토큰의 핸들을 획득합니다.
  2. 획득한 토큰을 Impersonation 토큰으로 복사하고 SeTrustedCredmanAccessPrivilege 권한을 활성화합니다.
  3. 인증된 사용자의 토큰을 Open 합니다.
  4. Impersonation된 WinLogon 토큰을 활용하여 CredBackupCredentials 함수를 호출하고 원하는 경로에 crendential을 저장합니다. 이 때 백업 시 비밀번호는 NULL로 설정할 수 있어 추가적인 복호화할 수고를 덜 수 있습니다.
  5. Impersonation 상태에서 CryptUnprotectData 함수를 통해 credential을 복호화합니다.