Windows XP introduced the ability to use Fast User Switching (FUS from here on), which is implemented using Terminal Services.

But in some cases (i.e. when FUS is not enabled, or when you connect to the console in Windows 2003 server), the Winlogon process in an RDP session needs to transfer credentials to Session 0.

Although not documented in MSDN, the process of transferring credentials is described by Keith Brown in the June 2005 issue of MSDN magazine: Customizing GINA, Part 2.

WlxQueryConsoleSwitchCredentials and WlxGetConsoleSwitchCredentials are used in the transfer with the semi-documented WLX_SAS_TYPE_AUTHENTICATED SAS code constant.

Internally, winlogon.exe uses a Named Pipe, \\.\Pipe\TerminalServer\AutoReconnect, to implement both of these functions.

The pipe format is described in this structure:

The structure mostly repeats WLX_CONSOLESWITCH_CREDENTIALS_INFO_V1_0, but you can see some changes in ordering and there are additional fields: SourceProcessId (which is used to duplicate the handle) and TotalLength (which shows the total length of the structure) have been added.

All pointers within the structure should be normalized, i.e. should be not pointers, but offsets from the beginning of the structure. This structure is valid for both 32 and 64 bit windows (of course, with alignment and correct sizes respected).

As you can see, there are some strange things, like declaring pointers as DWORD (PrivateData), declaring UserFlags as SIZE_T, which is platform dependent, while in the original structure it’s just ULONG, and so on.

You might think that the DynamicData should be really dynamic, but it isn’t: Winlogon always creates a variable of AUTOLOGON_BUFFER type in it’s stack or globally. It’s size is always 0x2000, regardless of platform.

That’s why I’ve made a conditional switch for the DynamicData size. So never do like Microsoft guys – hardcode the size of the variable – use sizeof operator instead :-).

When the credentials have been transferred to the pipe, session 0 Winlogon needs to get a notification about it. This happens with a WM_LOGONNOTIFY message with WPARAM_AUTHENTICATED = 14 as WParam.

When Winlogon recieves this message, it just translates it to WLX_SAS_TYPE_AUTHENTICATED SAS code and sends it to GINA, forcing it to query the credentials.

In case of a failure with packing the pipe content or sending it, Winlogon uses the undocumented _WinstationNotifyDisconnectPipe function which first verifies the privileges of the calling process and doing the termsrv.dll ->winsrv.dll -> win32k.sys -> winlogon.exe chain, just posts WM_LOGONNOTIFY message with WPARAM_DISCONNECT_PIPE = 20 as WParam.

This message forces the pipe to be disconnected and start an asynchronous reconnection to the new client.

So, at this point we know everything which is necessary to write our own program, which can simulate credentials transfer from a different session instance to zero session instance, enabling us to logon any user to session 0!

A list of issues and workarounds that I found while writing the program will be described in part 2.

Parts of the source code and the application itself will be published in part 3.