Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

CMDKEY fails to add credential in ssh session 0 #996

Closed
mgkuhn opened this issue Dec 18, 2017 · 18 comments
Closed

CMDKEY fails to add credential in ssh session 0 #996

mgkuhn opened this issue Dec 18, 2017 · 18 comments

Comments

@mgkuhn
Copy link

mgkuhn commented Dec 18, 2017

"OpenSSH for Windows" version
0.0.24.0

Server OperatingSystem
Windows 7 Professional (64 bit)

Client OperatingSystem
Ubuntu 16.04 (or any other, does not matter here)

What is failing
The way sshd currently sets up the login processes prevents me from saving there any Active Directory credential (Kerberos ticket) obtained using either the CMDKEY or NET USE commands. This prevents me accessing any domain-controlled network shares in an ssh session to a local user account.

I log into a local user account cheltenham\mgk25 (the Win7 PC "cheltenham" is not joined to any Active Directory domain). When I do this from the console or via rdesktop, I can then later provide in CMD an Active Directory username and password with either CMDKEY or NET USE in order to access a file share on a NetApp SMB file server "elmer", where I have an Active Directory account AD.CL.CAM.AC.UK\mgk25. However, both the "CMDKEY /add:... /user:..." and the "NET USE ... /user:..." commands fail when I run them via OpenSSH's sshd. :-( It appears that sshd is not setting up the process environment correctly to allow me to obtain and save Active Directory Kerberos credentials.

While trying to investigate what is different between ssh and rdesktop sessions, I noticed that when I type QUERY SESSION on the console or via rdesktop, it shows that I am running in session 1 or 2 (meant for users), whereas if I log in via sshd, I run in session 0 (meant for services). I had thought that (since Windows Vista) all Windows processes associated with a logged-in user must run in sessions >0 to avoid the "shatter attack". I wonder if running in the wrong session is also related to CMDKEY not working here. Both error messages do mention a "logon session" as the reason for the failure.

Expected output
Credential needed for file share access is added successfully when I login via rdesktop to call CMDKEY, and QUERY SESSION shows that I am in an "Active" session with ID > 0:

C:\>cmdkey /add:elmer.cl.cam.ac.uk /user:mgk25@AD.CL.CAM.AC.UK /pass
Enter the password for 'mgk25@AD.CL.CAM.AC.UK` to connect to 'elmer.cl.cam.ac.uk':

CMDKEY: Credential added successfully

C:\>query session
 SESSIONNAME       USERNAME                 ID  STATE   TYPE        DEVICE
 services                                    0  Disc
 console                                     1  Conn
>rdp-tcp#0         mgk25                     2  Active  rdpwd
 rdp-tcp                                 65536  Listen

C:\>net use \\elmer.cl.cam.ac.uk\userfiles\mgk25
The command completed successfully.

From the console, it looks the same, except for the active session being 1:

C:\>query session
 SESSIONNAME       USERNAME                 ID  STATE   TYPE        DEVICE
 services                                    0  Disc
>console           mgk25                     1  Active
 rdp-tcp                                 65536  Listen

Actual output
Via ssh (using either publickey or password authentication), both CMDKEY and NET USE fail and the current (">") session is shown as ID = 0 and not "Active":

C:\>cmdkey /add:elmer.cl.cam.ac.uk /user:mgk25@AD.CL.CAM.AC.UK /pass

CMDKEY: Credentials cannot be saved from this logon session.

C:\>query session
 SESSIONNAME       USERNAME                 ID  STATE   TYPE        DEVICE
>services                                    0  Disc
 console                                     1  Conn
 rdp-tcp                                 65536  Listen

C:\>net use \\elmer.cl.cam.ac.uk\userfiles\mgk25 * /user:mgk25@AD.CL.CAM.AC.UK
Type the password for \\elmer.cl.cam.ac.uk\userfiles\mgk25:
System error 1312 has occurred.

A specified logon session does not exist. It may already have been terminated.
@mgkuhn
Copy link
Author

mgkuhn commented Dec 18, 2017

Looking at the source, what sshd does to create the login process is to call in auth-passwd.c the function LogonUserExExW with

LogonUserExExW(user, domain, password, LOGON32_LOGON_NETWORK_CLEARTEXT,
               LOGON32_PROVIDER_DEFAULT, NULL, &token, NULL, NULL, NULL, NULL)

and then pass the received token in session.c to CreateProcessAsUser with

CreateProcessAsUserW(hToken, NULL, exec_command_w, NULL, NULL, TRUE,
                     DETACHED_PROCESS, NULL, pw_dir_w, &si, &pi)

I wonder why the first call uses LOGON32_LOGON_NETWORK_CLEARTEXT instead of LOGON32_LOGON_INTERACTIVE, since the LogonUserExExW documentation suggests that the latter would be more appropriate for a terminal server. Could this be the problem?

Also note that the man page for CreateProcessAsUser says:

Terminal Services: The process is run in the session specified in the token. By default, this is the same session that called LogonUser. To change the session, use the SetTokenInformation function.

I don't see sshd making any attempt to use that function to set TokenSessionId, which in turn requires sshd to have the Act As Part Of the Operating System privilege (does it currently?).

If sshd wants to be a proper terminal service, how should it create a new user session?

Is the current behavior, to stay in session 0, really the right thing to do?

@mgkuhn
Copy link
Author

mgkuhn commented Dec 18, 2017

The Bitvise SSH Server User's Guide has a good summary of some of the differences between LOGON32_LOGON_NETWORK_CLEARTEXT and LOGON32_LOGON_INTERACTIVE: https://www.bitvise.com/wug-logontype

While the currently used LOGON32_LOGON_NETWORK_CLEARTEXT may be the correct form for things like SFTP access, for shell access LOGON32_LOGON_INTERACTIVE would seem much more appropriate.

@mgkuhn
Copy link
Author

mgkuhn commented Dec 18, 2017

Unfortunately, I can't find anywhere in Microsoft's API documentation any hint on how to start a new session. For example https://msdn.microsoft.com/en-us/library/aa383496(v=vs.85).aspx just explains that "When a user logs on [...] a session is started for the user. Each session is identified by a unique session ID." But it gives no hint as to what the developer of a remote-access server such as sshd should be doing to start such a new session for the user.

https://msdn.microsoft.com/en-us/library/windows/desktop/aa378338(v=vs.85).aspx

@ghost
Copy link

ghost commented Jan 2, 2018

@mgkuhn: My research indicates one must go through terminal services. With a proper license (or using RDPWrap) one can use MSTSCLib to log in programmatically. Personally, the COM controls packaged in that library appear to be broken on Windows 10.

There are poorly documented differences between the way that terminal services logs on users and the LogonUser family of functions. This may be intentional, but I do not understand why, as any access to terminal service's login mechanism could still check customer licensing.

@manojampalam
Copy link
Contributor

Thanks for the detailed report. I'll take a look and get back with my findings.

@mgkuhn
Copy link
Author

mgkuhn commented Jan 26, 2018

Thank you for looking into this. It may be a good idea to get someone in charge of the Windows Kernel and/or Terminal Services (or now Remote Desktop Services) architectures involved (i.e., whoever at Microsoft does "sessions" and "credentials" for a living these days), as from my reading of the Windows API documentation that I found (see links above), I got the impression that certainly the existing Windows API documentation, possibly even the API itself, has not yet been written with applications like sshd in mind. It would be nice if the Windows API documentation explained clearly how services like sshd should set up new command-line login sessions and how these sessions can receive new credentials.

[A possibly closely related issue #1295 is how to implement sshd's GSSAPIDelegateCredentials option, i.e. how sshd should add to the login session's credential cache the Active Directory Kerberos ticket that it receives from "ssh -K". (Because using CMDKEY is just a workaround: what I really would prefer is "ssh -K" getting the Active Directory credential all set up for me automatically, rather than me having to type my Active Directory password into CMDKEY each time.) I would not be surprised if solving the above CMDKEY issue is also a prerequisite for implementing GSSAPIDelegateCredentials. Again, the existing Windows API documentation seems very silent on how to delegate a Kerberos/AD ticket to a sshd login session for this.]

@kad-meedel
Copy link

Is there any progress on this issue?

@mgkuhn
Copy link
Author

mgkuhn commented Nov 20, 2018

The problem still exists exactly as before in the latest release v7.7.2.0p1-Beta (tested on Windows 7 64-bit).

@mgkuhn
Copy link
Author

mgkuhn commented Nov 21, 2018

Suggestion to the Microsoft employees here: I wonder if you could consult any of the named authors or contributors of Mitigating Pass-the-Hash (PtH) Attacks and Other Credential Theft Techniques regarding this issue (see pages 2-3). Among them should be Microsoft's foremost experts regarding how credentials are stored in Windows sessions.

@jborean93
Copy link

jborean93 commented Nov 22, 2018

@mgkuhn the issue definitely relates to using network cleartext or network logon type. The API that cmdkey uses can be found here https://docs.microsoft.com/en-us/windows/desktop/api/wincred/. While I couldn't find any explicit documentation I found it will fail with ERROR_NO_SUCH_LOGON_SESSION unless I use either an interactive, remote interactive, or batch logon.

Looking at the docs for one of the functions, CredWriteW, it says that ERROR_NO_SUCH_LOGON_SESSION means

The logon session does not exist or there is no credential set associated with this logon session. Network logon sessions do not have an associated credential set.

It doesn't explicitly call out network cleartext but you could assume that it is lumped together with the generic network logon type.

The issue doesn't relate to Windows sessions as they are separate from a logon session created by LSA. As an example you could run a scheduled task job with explicit credentials which runs in session 0 as the user you specified. This is run with a batch logon type so you are you able to read/write to the credential store with this.

Unfortunately you can't really do much about this when using SSH, it uses a network logon because you are in fact authenticating from a remote network location. The same can be said for WinRM logons like PSRemoting and so on. The main ways I know how to get around this are;

  • Create a scheduled task to run the process with explicit credentials; Run whether user is logged on or not
  • Call a tool like psexec with explicit credentials to run your process
  • Manually call LogonUser with the logon type you desire and then pass that token to CreateProcessAsUser or CreateProcessWithToken

Putting all that aside, the credential manager isn't the most secure as the credentials are stored in a reversible format. The secret blob is supposed to be only readable by authentication providers registered with LSA but I am able to use a tool like mimikatz to dump this info as just a standard administrator.

@masaeedu
Copy link

@jborean93 Do you know of some shell setup that can be used on the remote machine so that the commands we run over SSH effectively have the same permissions that you would have with psexec (even though we're using public key authentication)?

@jborean93
Copy link

runas.exe is the closest I know off, should be fine if you are using an interactive console but non-interactive commands make this a bit more difficult. You can use PInvoke in a PowerShell script to call the underlying Win32 APIs yourself but that's quite advanced. Technically sshd could change the flag when it itself calls LogonUser (password auth only) to use a batch or "interactive" logon but I assume this violates standard Windows principals as a logon from SSH is truly a network not batch or "interactive" logon.

@masaeedu
Copy link

When you mention "interactive" here, do you mean in the sense of having a stdin stream or in terms of the process actually being visible in some Windows desktop session?

@jborean93
Copy link

When I mention interactive in the context of a logon type I am talking about LOGON32_LOGON_INTERACTIVE as specified by the dwLogonType. AFAIK it doesn't literally mean it is the only one that allows interactive operations like reading from the console stdin but it is certainly meant for interactive logons like a RDP session or a direct console logon where a user has a UI.

Other logons like batch, network are typically used in non-interactive scenarios but there is nothing that would stop me from creating one manually but there really isn't any purpose for this.

When I said runas.exe with an interactive console I'm just talking about how it prompts for the user's password but theoretically it should be possible to run in a non-interactive process by passing the password through the stdin stream.

@mgkuhn
Copy link
Author

mgkuhn commented Dec 17, 2018

Thanks to the recently submitted patch in #1295 to support GSSAPIDelegateCredentials, this issue may be becoming much less urgent for many users, as they can now get the required Kerberos credentials into their session far more conveniently via Kerberos ticket delegation. An that delegation works fine for me in the current LOGON32_LOGON_NETWORK_CLEARTEXT logon type. (Nevertheless, the ability to switch sshd to use logon type LOGON32_LOGON_INTERACTIVE instead may still be useful for other reasons.)

@psz2036
Copy link

psz2036 commented Oct 8, 2019

I think the above mention of #1088 does not belong here... but is for #966 (which should NOT be closed).

@maertendMSFT
Copy link
Collaborator

This is primarily due to Windows behavior, LOGON32_LOGON_NETWORK_CLEARTEXT is sufficient.

@mgkuhn
Copy link
Author

mgkuhn commented Aug 5, 2022

For the record: @jborean93 gave here a concise explanation for why cmdkey can't possibly work in an ssh session that didn't use password authentication:

if you authenticate to the server without providing the password for the user then you cannot unlock the DPAPI store for that user and access it's secrets. Any workarounds would require the password to be stored in a reversible fashion that the system could use or to provide enough information to be able to delegate the credentials to the remote host during the authentication phase.

(I wonder about the second half of the last sentence, i.e. what delegated credentials could open the DPAPI store? Kerberos authentication with GSSAPIDelegation does not appear to open the DPAPI credentials store used by cmdkey for me. Are there any other credentials that might work? I have heard that Kerberos tokens obtained via PKINIT smartcard authentication contain the the PAC the user's NTLM hash. Would that unlock the DPAPI store for that user?)

See also #452

# for free to join this conversation on GitHub. Already have an account? # to comment
Projects
None yet
Development

No branches or pull requests

7 participants