Skip to content

cloudap

EvanMcBroom edited this page Jun 22, 2024 · 22 revisions

Cloud AP

Key Terms

Some terms appear a lot when analyzing cloudap which are provided here:

  • Package: Structure of information about a cloudap plugin, which will be either AzureAD or MicrosoftAccount

  • TokenBlob: A PRT, also referred to as a "Cloud TGT"

Functions

The protocol messages that cloudap or its plugins support are not documented by Microsoft. Microsoft provides a small example of calling one plugin function with little context. The remainder of the available functions and their usage were reverse engineered and documented here. It is not known on which version of NT these functions were originally introduced or if new functions have been introduced since this writting.

Id Message Type CLI Support

0x00

ReinitPlugin

✔️

0x01

GetTokenBlob

✔️

0x02

CallPluginGeneric

✔️

0x03

ProfileDeleted

Planned

0x04

GetAuthenticatingProvider

✔️

0x05

RenameAccount

0x06

RefreshTokenBlob

Planned

0x07

GenARSOPwd

✔️

0x08

SetTestParas

✔️

0x09

TransferCreds

✔️

0x0A

ProvisionNGCNode

✔️

0x0B

GetPwdExpiryInfo

✔️

0x0C

DisableOptimizedLogon

✔️

0x0D

GetUnlockKeyType

✔️

0x0E

GetPublicCachedInfo

Planned

0x0F

GetAccountInfo

Planned

0x10

GetDpApiCredKeyDecryptStatus

✔️

0x11

IsCloudToOnPremTgtPresentInCache

✔️

✏️
Function CallPluginGeneric will be called if you use a plugin function.

CallPluginGeneric

Call a CloudAP plugin function. You may not call this function directly with the tool, but it will be implicitly called when running a cloudap plugin command.

DisableOptimizedLogon

Loads a user’s CacheData from their CloudAPCache folder, updates the "cache node flags" to disable optimized logons, then saves the CacheData back to the user’s folder. Any user logon session may be specified. If no logon session is specified then optimized logons will be disabled for the logon session.

cloudap DisableOptimizedLogon [--luid {session id}]

GenARSOPwd

Generate a Winlogon Automatic Restart Sign-On (ASRO) password and store it as a pair of LSA secrets. The LSA secrets will have the following names:

  1. M$CLOUDAP_TBAL{4416F0BD-3A59-4590-9579-DA6E08AF19B3}_HASH

  2. M$CLOUDAP_TBAL{8283D8D4-55B6-466F-B7D7-17A1352D9CAB}_HASH

The value of HASH should be the sha256 hash the plugin GUID string for your logon session combined with your user’s identity name. The first secret will be the output of ext-ms-win-cloudap-tbal-l1-1-0!TbalSealBuffer. The second secret will be the value you provide which must be at least 4 bytes long.

cloudap GenARSOPwd --luid {session id} --arso-data {data}

GetAccountInfo

Needs further auditing.

GetAuthenticatingProvider

The _LOGON_SESSION structure has a GUID entry to identify which cloudap plugin was used (e.g., AzureAD or MicrosoftAccount) This function returns that GUID entry for a specified logon session.

cloudap GetAuthenticatingProvider --luid {session id}

GetDpApiCredKeyDecryptStatus

Return if the DPAPI cred key for user logon session has been decrypted.

cloudap GetDpApiCredKeyDecryptStatus --luid {session id}

GetPublicCachedInfo

Retrieve PublicCacheData from disk, deserialize, and return it. Needs further auditing.

GetPwdExpiryInfo

Get a string and time with information about when password will expire for a logon session. A client must have`SeTcbPrivilege` to specify another logon session. Otherwise, the specified session will be ignored and the current session will be used instead.

cloudap GetPwdExpiryInfo [--luid {session id}]

GetTokenBlob

The _USER_CACHE_ENTRY structure has a DPAPI protected entry named TokenBlob, also referred to as the CloudTGT. This function unprotects and returns the TokenBlob entry for a specified logon session. You may specify a specific logon session, otherwise the current logon session will be used.

LSA Whisperer’s implementation of GetTokenBlob is believed to be correct, but only the following errors have been observed during testing:

  • 0xc0000022 - Access is denied.

  • 0xc000005f - A specified logon session does not exist. It may already have been terminated.

It is still unknown what setup and access is needed for the command to return successfully.

cloudap GetTokenBlob [--luid {session id}]

GetUnlockKeyType

Returns the UnlockKeyType entry of the the _USER_CACHE_ENTRY structure for a logon session. The value will between 1 and 6 inclusively. Internally, GetUnlockKeyType remaps value 5 to 2, value 6 to 5, and value 7 to 6. The meaning of each of these values is currently unknown.

A client must have`SeTcbPrivilege` to specify another logon session. Otherwise, the specified session will be ignored and the current session will be used instead.

cloudap GetUnlockKeyType [--luid {session id}]

IsCloudToOnPremTgtPresentInCache

Inspects the TicketCache inside the _USER_CACHE_ENTRY structure for a logon session to see if it contains a "cloud to on-prem TGT." A client must have`SeTcbPrivilege` to specify another logon session. Otherwise, the specified session will be ignored and the current session will be used instead.

cloudap IsCloudToOnPremTgtPresentInCache [--luid {session id}]

ProfileDeleted

Adds a provided SID as a subkey under HKLM\Software\Microsoft\IdentityStore\DeferredCacheCleanup.

ProvisionNGCNode

Provision an NGC node in the CloudAPCache for the current logon session. Needs further auditing.

cloudap ProvisionNGCNode

RefreshTokenBlob

Refresh a logon session’s TokenBlob using the RefreshToken cloudap function plugin.

ReinitPlugin

Unloads then reloads all cloudap plugins.

cloudap ReinitPlugin

RenameAccount

Will update the account name in the Security Accounts Manager (SAM). Needs further auditing.

SetTestParas

Sets an internal TestFlags value used by cloudap. The following is the value for each currently used TestFlags bit:

TestFlags

Description

1

Disable the internal FlushIdentityCache function

2

Disable the use of the internal *PreRS2 functions

cloudap SetTestParas --flags {value}

TransferCreds

Transfer data between two cloudap logon sessions. The specific data that is transferred and privileges that may be required are still being determined. Will generate a new logon session for dst if needed. The function does not take any flags.

cloudap TransferCreds --sluid {session id} --dluid {session id}

Plugins

Cloudap currently only supports 2 plugins to facilitate user logons with Azure AD (AAD) and Microsoft Accounts (MSA). The AAD plugin also facilitates logins with AD FS. The internal names and IDs for interacting with these plugins may be found in the registry and are provided here for convenience.

Table 1. Plugins (HKLM\SOFTWARE\Microsoft\IdentityStore\Providers)
Plugin Name GUID File

AadGlobalId (AAD)

B16898C6-A148-4967-9171-64D755DA8520

aadcloudap.dll

Windows Live ID (MSA)

D7F9888F-E3FC-49b0-9EA6-A85B5F392A4F

MicrosoftAccountCloudAP.dll

Cloudap allows each plugin to implement a number of functions for cloudap to call. The full list of functions, their call ID, and the plugins that support them are listed here.

Table 2. Plugin Functions
Id Message Type Plugins

0x00

PluginUninitialize

AAD, MSA

0x01

ValidateUserInfo

AAD, MSA

0x02

GetUnlockKey

AAD, MSA

0x03

Reserved

0x04

GetDefaultCredentialComplexity

MSA

0x05

IsConnected

MSA

0x06

AcceptPeerCertificate

AAD, MSA

0x07

AssembleOpaqueData

AAD

0x08

DisassembleOpaqueData

AAD

0x09

GetToken

AAD, MSA

0x0a

RefreshToken

AAD

0x0b

GetKeys

AAD, MSA

0x0c

LookupSIDFromIdentityName

AAD

0x0d

LookupIdentityFromSIDName

AAD

0x0e

UserProfileLoaded

MSA

0x0f

ConnectIdentity

MSA

0x10

DisconnectIdentity

MSA

0x11

RenewCertificate

MSA

0x12

GetCertificateFromCred

AAD

0x13

GenericCallPkg

AAD, MSA

0x14

PostLogonProcessing

AAD

✏️
Functions 0x00-0x08 are available offline and functions 0x09-0x14 require online connectivity.

AAD Functions

The Azure AD (AAD) plugin supports additional calls through the GenericCallPkg plugin function. The full list and their call IDs are listed here. The version numbers are anecdotal and will not account for all NT builds for which a function may be present.

Id Message Type NT Build CLI Support

0x01

SignPayload

>=19045

Planned

0x02

CreateSSOCookie

>=19045

✔️

0x03

GetPrtAuthority

>=19045

✔️

0x04

CheckDeviceKeysHealth

>=19045

✔️

0x05

DeviceAuth

>=19045

Planned

0x06

RefreshP2PCACert

>=19045

✔️

0x07

DeviceValidityCheck

>=19045

✔️

0x08

CreateDeviceSSOCookie

>=19045

✔️

0x09

CreateNonce

>=19045

✔️

0x0a

ValidateRdpAssertionRequest

>=19045

✔️

0x0b

RefreshP2PCerts

>=19045

✔️

0x0c

CreateBindingKey

>=22621

0x0d

GenerateBindingClaims

>=22621

0x0e

Reserved

0x0f

CreateEnterpriseSSOCookie

>=19045

✔️

✏️
Reserved fields are likely for functions that are only present in debug builds.

CheckDeviceKeysHealth

Will perform the following actions:

  1. Attempt to acquire the private key for the enterprise Device Registration Service (DRS) certificate in the current user’s certificate store

  2. Attempt to acquire the NGC symmetric PoP key transport key

  3. Check if either action returned an error code matching a predefined list of error codes

  4. Set the RunRecovery value in the HKLMSOFTWARE\Microsoft\IdentityStore\LoadParameters{B16898C6-A148-4967-9171-64D755DA8520} to true if an error code does match the list

  5. Return the error codes for the first two actions

CreateBindingKey

Always returns E_NOTIMPL.

CreateDeviceSSOCookie

Create a signed JWT for the current device which may be specified in web requests using the x-ms-DeviceCredential header. The JWT is used to authenticate the client device and its contents are described here. The host must be cloud domain joined for the call to succeed.

CreateEnterpriseSSOCookie

The CreateEnterpriseSSOCookie command has not been fully tested, but should provide an Enterprise PRT cookie for the current logon session to use for single sign on (SSO) with AD FS. The host device must be authenticated with AD FS for the call to succeed.

CreateNonce

Create a Server Nonce PDU as defined in the RDS AAD Auth Connection Sequence section of the MS-RDPBCGR documentation. The call is also listed as a protocol example in the section "Generating a Server Nonce." The caller must be System and the host must be cloud domain joined for the call to succeed. If the call succeeds the returned nonce may be used when creating an Authentication Request PDU to use with the ValidateRdpAssertion command.

CreateSSOCookie

Create a proof of possession (PoP) cookie for the current logon session to use for single sign on (SSO) with Azure AD. The command requires a nonce value which may be acquired with the .nonce command or with roadrecon and it’s auth --prt-init command. The returned assertion (e.g., the cookie) may be used with several roadrecon and roadtx commands by specifying the assertion with the --prt-cookie argument.

DeviceAuth

Planned.

DeviceValidityCheck

Issues a device token request to Azure AD and validates that a bearer token was successfully recieved. An empty json dictionary is returned on success and an error on failure. Although the API does not return the bearer token it may be viewed with the assistance of an HTTPS proxy such as mitmproxy.

GenerateBindingClaim

Always returns E_NOTIMPL.

GetPrtAuthority

Get information about any PRT authorities the current device may be registered with. The current device may be registered with Azure AD (use --authority 1), an AD FS instance (e.g., "Enterprise" [use --authority 2]), or both.

cloudap GetPrtAuthority --authority 1 ## Authority values: AzureAd (1), Enterprise (2)

RefreshP2PCACert

Updates the workplace CA certificate for the current user, if any.

RefreshP2PCerts

Updates the workplace CA certificate for the current user, if any, in the same way as the RefreshP2PCACert command. Also updates the current device’s P2P certificate if the current user is an administrator.

SignPayload

Planned.

ValidateRdpAssertion

Validate an Authentication Request PDU as defined in the RDS AAD Auth Connection Sequence section of the MS-RDPBCGR. The call is also listed as a protocol example in the section "Validating an Authentication Request." The Authentication Request PDU will contain an RDP Assertion (e.g., a JWT) which functions as a user credential. The caller must be System and the host must be cloud domain joined for the call to succeed. If the call succeeds the returned Base64 URL string may be used as a credential blob with LsaLogonUser to create a new logon session.

Microsoft Account Functions

The Microsoft Account (MSA) plugin supports additional functionality through the GenericCallPkg plugin function. This functionality has not been fully analyzed.

If you make an MSA request from an AppContainer, it must have the liveIdService capability. Input data is a WlidPropertyBag.

Key Structures

Reverse engineering some structures were key in understanding the internal message protocol functions that cloudap provides. A description and partial definition for each of these structures is provided here for others to use and research further. These may not be completely accurate and contributions are appreciated.

_CLOUDAP_CREDKEY_INFO

Cloudap may store the DPAPI "Cred Key" for a user profile on the file system. If it does, information about the CredKey will be stored under C:\Windows\System32\config\systemprofile\AppData\Local\Microsoft\Windows\CloudAPCache under a subfolder (AzureAD or MicrosoftAccount) in a file named [User Profile Id]\Keys\CredKeyInfo in the _CLOUDAP_CREDKEY_INFO format.

Table 3. _CLOUDAP_CREDKEY_INFO
Offset (x64) Definition NT Build Remarks

0x00

DWORD Version;

19041

Currently, should always be 1

0x04

GUID Id;

19041

The CredKey Id

0x14

DWORD Pad;

19041

0x18

DWORD Unknown;

19041

_LOGON_SESSION

Cloudap maintains a linked list of _LOGON_SESSION structures for each cloudap provided user logon session. New entries have been appended to this structure over time, but the current list of known entries and their offsets are as follows.

Table 4. _LOGON_SESSION
Offset (x64) Definition NT Build Remarks

0x00

LIST_ENTRY LogonSessions;

19041

0x1C

LUID Luid;

19041

The ID of the logon session

0x24

GUID CloudAPPackage;

19041

Microsoft’s synonym for a CloudAP plugin

0x38

USER_CACHE_ENTRY* UserCache;

19041

0x40

SCARD_PIN* SCardPin;

19041

The format of _SCARD_PIN was not researched

_USER_CACHE_ENTRY

Cloudap maintains a _USER_CACHE_ENTRY structure for each cloudap user logon session to maintain user specific information about the session.

Table 5. _USER_CACHE_ENTRY
Offset (x64) Definition NT Build Remarks

0x000

SIZE_T TicketCacheSize;

19041

0x008

LPVOID TicketCache;

19041

0x010

LPVOID UpdateCounter;

19041

A counter for how many times the cloudap updated this structure

0x01C

LPCRITICAL_SECTION CriticalSection;

19041

A synchronization primitive for accessing the structure

0x04C

LPDWORD Counter;

19041

0x060

LPWSTR IdentityName;

19041

0x0f8

GUID LogonPackageGuid;

19041

0x108

LPVOID CredKey;

19041

DPAPI masterkey for the user, protected by LSA’s DPAPI masterkey

0x110

LPVOID ProtectedMemory2;

19041

The data’s purpose is unknown

0x118

ULONG ProtectedTokenBlobSize;

19041

0x120

LPVOID ProtectedTokenBlob;

19041

The TokenBlob or "CloudTGT"

0x128

AP_BLOB CredentialData;

19041

AP_BLOB is the same as LSA_STRING with 4 byte length fields

0x148

LPWSTR PwdResetUrl;

19041

0x148

FILETIME PwdExpirationTime;

19041

0x148

LPDWORD LuidSize;

19041

0x150

LUID* Luid;

19041

0x158

LPDWORD UnlockKeyType;

19041

0x160

ULONG IsDpApiCredKeyDecrypted;

19041