Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Cannot Create PSSession From macOS to Windows #72

Open
l33 opened this issue Feb 15, 2024 · 5 comments
Open

Cannot Create PSSession From macOS to Windows #72

l33 opened this issue Feb 15, 2024 · 5 comments

Comments

@l33
Copy link

l33 commented Feb 15, 2024

SUMMARY

Same problem as #70 but this time using SSL. Reading the README.md I think this is supposed to work:

Technically NTLM auth on macOS can work but only does when running over HTTPS.

However, it does not in my case. Attempting to connect to a Windows Server 2019 (domain joined) from my M3 Mac:

New-PSSession -ComputerName [redacted] -UseSSL -Authentication Negotiate -Credential $null
PowerShell credential request
Enter your credentials.
User: [redacted]
Password for user [redacted]: [redacted]

New-PSSession: [[redacted]] Connecting to remote server [redacted] failed with the following error message : Authorization failed For more information, see the about_Remote_Troubleshooting Help topic.

Running the identical command from a Windows 10 computer works as expected.

MODULE VERSION
Import-Module -Name PSWSMan -PassThru
ModuleType Version    PreRelease Name                                ExportedCommands
---------- -------    ---------- ----                                ----------------
Script     2.3.1                 PSWSMan                             {Disable-WSManCertVerification, Enable-WSManCertVerification, Get-WSManVersion, Install-WSMan…}
OS / ENVIRONMENT

macOS info

% system_profiler SPSoftwareDataType
Software:

    System Software Overview:

      System Version: macOS 14.1 (23B2073)
      Kernel Version: Darwin 23.1.0
      Boot Volume: Macintosh HD
      Boot Mode: Normal
      Computer Name: MacBook Pro
      User Name: [redacted]
      Secure Virtual Memory: Enabled
      System Integrity Protection: Enabled
      Time since boot: 22 days, 10 hours

PowerShell info

> $PSVersionTable

Name                           Value
----                           -----
PSVersion                      7.4.1
PSEdition                      Core
GitCommitId                    7.4.1
OS                             Darwin 23.1.0 Darwin Kernel Version 23.1.0: Mon Oct  9 21:32:11 PDT 2023; root:xnu-10002.41.9~7/RELEASE_ARM64_T6030
Platform                       Unix
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0…}
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1
WSManStackVersion              3.0

WSMan setup

> Install-WSMan -verbose
VERBOSE: Attempting to get OpenSSL info with /opt/homebrew/bin/brew --prefix openssl
STDOUT: /opt/homebrew/opt/openssl@3


STDERR:

RC: 0
VERBOSE: Checking arch information for '/opt/homebrew/opt/openssl@3/lib/libcrypto.dylib' and '/opt/homebrew/opt/openssl@3/lib/libssl.dylib'
VERBOSE: Checking if 'arm64' for '/opt/homebrew/opt/openssl@3/lib/libcrypto.dylib' is one of 'arm64'
VERBOSE: Checking if 'arm64' for '/opt/homebrew/opt/openssl@3/lib/libssl.dylib' is one of 'arm64'
VERBOSE: Brew openssl libcrypto|ssl exists and is valid at '/opt/homebrew/opt/openssl@3/lib/libcrypto.dylib' and '/opt/homebrew/opt/openssl@3/lib/libssl.dylib'
VERBOSE: Getting OpenSSL version for '/opt/homebrew/opt/openssl@3/lib/libssl.dylib'
VERBOSE: OpenSSL Version: Major 3 Minor 2 Patch 0
VERBOSE: Host Info:
{
  "Distribution": "macOS",
  "StandardLib": "macOS",
  "OpenSSL": "3",
  "LibCrypto": {
    "Source": "libcrypto.3.dylib",
    "Target": "/opt/homebrew/opt/openssl@3/lib/libcrypto.dylib"
  },
  "LibSSL": {
    "Source": "libssl.3.dylib",
    "Target": "/opt/homebrew/opt/openssl@3/lib/libssl.dylib"
  }
}
VERBOSE: Installing WSMan libs for 'macOS-3'
VERBOSE: Checking to see if libmi.dylib is installed
VERBOSE: Checking to see if libpsrpclient.dylib is installed

Excerpt from omiclient-send.trc

[Session: 7 Date: 2024-02-14 22:46:38.0877754Z]
POST /wsman?PSVersion=7.4.1 HTTP/1.1
Connection: Keep-Alive
Content-Length: 0
Content-Type: application/soap+xml;charset=UTF-8
Host: [redacted]:5986
Authorization: Negotiate YEg[redacted]


POST /wsman/ HTTP/1.1
Connection: Keep-Alive
Content-Length: 0
Content-Type: application/soap+xml;charset=UTF-8
Host: [redacted]:5986
Authorization: Negotiate oYI[redacted]

Server replies from taken from omi's debug log

HTTP/1.1 401
WWW-Authenticate: Negotiate oYI[redacted]
Server: Microsoft-HTTPAPI/2.0
Date: Wed, 14 Feb 2024 22:46:38 GMT
Content-Length: 0

HTTP/1.1 401
Server: Microsoft-HTTPAPI/2.0
WWW-Authenticate: Negotiate
WWW-Authenticate: Kerberos
WWW-Authenticate: http://schemas.dmtf.org/wbem/wsman/1/wsman/secprofile/https/mutual
Date: Wed, 14 Feb 2024 22:46:38 GMT
Connection: close
Content-Length: 0

Some other things I noticed:

  • Using username in UPN format introduces a ~35 s delay until the error pops up. Using its down-level logon name immediately returns the login failure. From the debug log it looks as if the server takes its time to reply to the first POST but the first request's content is always identical no matter what username is chosen.
  • The debug log shows MI_Result = MI_RESULT_ACCESS_DENIED but the error message does not show the error code.
@jborean93
Copy link
Owner

Is -Credential $null actually what you used or is it just a placeholder?

Using username in UPN format introduces a ~35 s delay until the error pops up. Using its down-level logon name immediately returns the login failure. From the debug log it looks as if the server takes its time to reply to the first POST but the first request's content is always identical no matter what username is chosen.

Most likely this is because it will try and do a Kerberos KDC lookup and that's the time it takes for dns to return with a failure.

@l33
Copy link
Author

l33 commented Feb 15, 2024

Is -Credential $null actually what you used or is it just a placeholder?

It's what I actually used to compile everything for this report. It was the only way to get New-PSSession to ask for credentials. Normally I use some variable containing the output of Get-Credential. To my knowledge the result is identical.

Using username in UPN format introduces a ~35 s delay until the error pops up. Using its down-level logon name immediately returns the login failure. From the debug log it looks as if the server takes its time to reply to the first POST but the first request's content is always identical no matter what username is chosen.

Most likely this is because it will try and do a Kerberos KDC lookup and that's the time it takes for dns to return with a failure.

That makes sense. I can try to confirm this later by looking into DNS network traffic.

@jborean93
Copy link
Owner

As for the reasons why it's failing I've really given up on this approach unfortunately because of problems like this. GSSAPI authentication is extremely complicated on macOS and super hard to debug. I know I tested NTLM over HTTPS originally on an Intel mac but I don't have access to an arm based Mac right now to try it out again.

As for why it's failing you could look into the network traffic and see if it's actually authenticating and the server responds with a 200 at any point. If it's always 401 then the authentication doesn't work at all and there's another problem at hand.

@l33
Copy link
Author

l33 commented Feb 15, 2024

Using username in UPN format introduces a ~35 s delay until the error pops up. Using its down-level logon name immediately returns the login failure. From the debug log it looks as if the server takes its time to reply to the first POST but the first request's content is always identical no matter what username is chosen.

Most likely this is because it will try and do a Kerberos KDC lookup and that's the time it takes for dns to return with a failure.

That makes sense. I can try to confirm this later by looking into DNS network traffic.

You were right. I can see how SRV records are looked up for the KDC and data is sent to the KDC (which never responds).

As for why it's failing you could look into the network traffic and see if it's actually authenticating and the server responds with a 200 at any point. If it's always 401 then the authentication doesn't work at all and there's another problem at hand.

I dont have the means to decrypt the traffic I captured. The TLS uses a ECDHE cypher so I can't easily decrypt it. However, I do see two encrypted responses from the server and I have two decoded replies in the logs (as I included in the problem description). Assuming those encrypted responses and decoded replies match, there are no HTTP/200 replies. They are all 401.

I would dig depper into the issue but I think I will need some help on what to look at next.

@jborean93
Copy link
Owner

I dont have the means to decrypt the traffic I captured

The omi trace logs should show you the messages being sent and the replies, you even mentioned it in your original comment.

I dont have the means to decrypt the traffic I captured. The TLS uses a ECDHE cypher so I can't easily decrypt it.

That is unfortunately, OpenSSL does have the ability to create a keylogfile that Wireshark can use to decrypt the TLS traffic but I believe you need to opt into the callback in the C code which isn't currently being done. If you are interested you can run https://gist.github.com/jborean93/6c1f1b3130f2675f1618da56633eb1fa on the Windows host to produce the same file that Wireshark can use to decrypt the traffic. Keep in mind it is pretty invasive and requires a reboot to undo the hooks it places in lsass so it's mostly just for development purposes only.

However, I do see two encrypted responses from the server and I have two decoded replies in the logs (as I included in the problem description). Assuming those encrypted responses and decoded replies match, there are no HTTP/200 replies. They are all 401.

This is the key part to figure out unfortunately. NTLM auth on macOS was problematic due to how the gss_wrap_iov functions worked IIRC. So knowing whether the authentication phase failed (all 401 replies) or whether it failed on the first encrypted message would be good to know.

Unfortunately I don't really have any recommendations for you as this isn't something simple you can fix. What you can try is

  • Run the code in a Linux container with gss-ntlmssp so you can use NTLM over HTTP or at least avoid the problematic macOS NTLM stack
  • Use basic auth over HTTPS (no NTLM at all and encryption is only through HTTPS itself), unfortunately this is local accounts only
  • If it's a domain account, look into setting up a krb5.conf so you can use Kerberos auth

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants