none
PowerShell Remoting on Exchange Encrypted Data RRS feed

  • Question

  • Hi

    I've got a 3rd party library in Python that implements the MS-PSRP protocol and I've been able to use this library to successfully connect to PowerShell configuration endpoints without any issues but I'm having issues trying to use the same code to talk to a Microsoft.Exchange endpoint (I'm testing with 2013 at the moment). The issue I am coming across right now is that the CreateResponse message from the server is just a random binary data after unwrapping the message. I know that my current GSSAPI wrap and unwrap functions are working perfectly fine because they work with a normal PowerShell endpoint and the server isn't rejecting the initial Create request that is being sent by the client.

    When looking at the Windows Remote Management Analytics logs I can see that the server is receiving the Create request as sent by the client and the logs indicate it is sending a successful CreateResponse XML message back to the client. When the client goes to unwrap the encrypted response it is able to do so and the unwrapped length matches up with the Length value in the MIME data of the encrypted response but the decrypted value is still just a bunch of bytes (albiet at the expected length). This data has no valid utf-8 character sequences so I can't really determine anything in the response. Here is an example decrypted response that I get as a base64 string.

    H4sIAAAAAAAEAO29B2AcSZYlJi9tynt/SvVK1+B0oQiAYBMk2JBAEOzBiM3mkuwdaUcjKasqgcplVmVdZhZAzO2dvPfee++999577733ujudTif33/8/XGZkAWz2zkrayZ4hgKrIHz9+fB8/Ih43j06Xl3lZrfL03aJ8VGbLi88+ypfbX73+CB8sm0fNZx/N23b16O7dq6ur8dW9cVVf3N3b2bl3d+f+3abKVtu5QjBvZPaNZjrPF1kzps/Rkl+9avD2/t2dg7vZbFbnTVMsL8yr72736sO7bZ0tm/O8Ni9e9V6cLdpzeWuSL+jVRba8uys/x++amXmxbla9VxfFtK6a6rwdT6tF5/1iOasIj2ael6WB8X4QLAZHRP1v59ksr48eZ4+Op21RLY/eb/h3T+o8a/NXebOqlk3++K6FQxC/INpmF/nZ06P1upg9enDyYO/k9MnT7ftPDp5s7z99uLd9sP90d/v+zt7e0yf3T+89e/opALjXCMab6lYY+XN5t67K/G62rJbXi2rdACRBIViv8pJwbegPxufTg2d79/ceHG/f3394b3t/Z//e9vHTZ8fbJ08/vf/s9Nn9h7v3dvGye+3xXUew5tGTanZ99Pgdfd9U63qaCylmTEtBxqKe15d5vbez+3Ccv5vOicfzMUFsHx3s3H1ZXeX1a8wmE09fZGyJvvlymr/M6myRt3lNH1/Z3r56ddalTDjpKwBmNrn7hf3iVLt/fDeERIBf52U+bav6dd76f6YvqPPPPmIMz4hnHh4fHBzsfUqzuPdgZ3t/98GD7YfPdmgWTz89Odh9cHp6b+8ZoJv3j/w/GPbdgbHdjZCSpOMRd/1NSIsH7mx2y4H4b/Drlmp18UH078Ji4F9eLYm3fvLi9Pgnj2e/d/bd+28n92Y/+ImrJ09OTttyuvgO/f/hD948mT377umLs5/46v63X/3ku73f57uz69/nu/d3nn/31eXku89Wk/Kr9qvrnXfP33zVfvHTp+0XPzi+/+Wb4/0vn073vny98+6Ln367/8UPvqK/j3eev/mJvRc/OL33xQ+m1y9O6Ls3xzuvrppjer6Nf54/+6L94vXO7vM3ZwTvi6sv37y9+vLpxb0XP/22/eLN2f0vn36xS39f0bs7L356+u7FD76498VP/0T74s3pD55cAcLszfM3p4Bx5f/94vXOtfw9N3+/++InpvjgzOL+5qsPxUH6ONm1fRKcH3zx9O39L55e7L/4we9znz6//vLNxQ9evLnY/+IpvfP097n3xZvpD1784Ixoc/rui6e/z4ficF9wePc1cfjq3ZfHPl1O9+n/wOni6+M0vX71EwB5/JkwovAds+BJWeTL9uzl0Xl+sPPo0fR+Nnm0Nz349NH0wcN7j/Yf5p/+7rv35C3blF88m5X5m2KRf7luj16+ebizM97Z2XktLf3vpPFytW5ftyTmi+aoaWfFMl3V2tb/SqRi3Yatq3WreAffOPF+tV6iu6OXO0/f7Hx75wuDR/Clpw2WGRmty6K9jr/hfe99yuZAjMBd58Yc/T8Cna2e0wgAAA==

    At first I thought it was a compressed payload but the first 4 bytes (0x1F 0x8B 0x08 0x00) do not match the expected format of a normally compressed payload (the numbers are too large). One interesting aspect is that while the data changes on each request, the first 96 bytes is always the same.

    Some of the things I've tried to understand this process

    * Confirmed I can connect to the Exchange endpoint using a real PowerShell client on both v5.1 and 7
    * Tried getting a network capture of a new PSSession from a PowerShell client with the '-NoEncryption' but no matter what server and client side config I set to AllowUnencrypted this is rejected by the server (see more details below)
    * Connect to the HTTPS endpoint but this just returns nothing in the response, I believe this is expected for a default local Exchange setup
    * Using the WinRM analytics logs to get the Shell Create request generated by a proper PowerShell client and just sent that from my own client, this results in the same binary output
    * Checked the logs to compare a working connection from a PowerShell client and my own but cannot find any differences that would cause this to happen

    A quick side note about PowerShell Client with the '-NoEncryption' session option. When doing a Wireshark capture I have no idea why the server is rejecting the auth. The payload is nearly identical except for the WSMan session cookie and certain parts of the Kerb auth token but nothing else. Do you know how this is possible when 1. no data is being sent in this request yet and 2. there are no headers that tells the server subsequent requests will be in plaintext.

    I'm happy to share any other info that will be useful to track down this problem.
    • Edited by jborean93 Thursday, March 26, 2020 4:11 AM put data in codeblock
    Thursday, March 26, 2020 4:10 AM

Answers

  • Just posting back here in case anything in the future comes across the same problem.

    After much trial and error the issue was the Python client that was creating and sending the HTTP requests was automatically adding the 'Accept-Encoding: gzip, default' header to the request. Normally on a vanilla WinRM endpoint wouldn't be an issue as it just ignores this value but because the Exchange PowerShell endpoint is hosted by IIS and that is handling the HTTP requests it's honoring that value.

    The response it sends back is compressed, once it exceeds a certain size, using one of those 2 algorithms as we (the client) stated it accepts those encodings but never did anything with it. The fix was to ensure the client sent 'Accept-Encoding: identity' instead which tells IIS not to compress/transform the data. Once that is added to the request the response once decrypted is the proper WSMan envelop which the client is now able to process properly.

    Big thanks to Tom for helping with this process and looking into various avenues.

    • Marked as answer by jborean93 Tuesday, June 16, 2020 10:54 PM
    Tuesday, June 16, 2020 10:54 PM

All replies

  • Hi Jordan,

    Thank you for your question. One of the Open Specifications support team members will reply shortly to assist you with this issue.


    HungChun Yu (MSFT)



    Thursday, March 26, 2020 6:29 AM
  • Hi jborean93, 

    Since you are using a library, can you refer to the section containing the method in the MS-PSRP document which you're using and in which this binary data is being return from Exchange? This would help us narrow down on the server side where to look. 

    Best regards,
    Tom Jebo
    Sr Escalation Engineer
    Microsoft Open Specifications

    Thursday, March 26, 2020 11:33 PM
    Moderator
  • Hi Tom

    This is just the first step in creating the RunspacePool as per step 1 on https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-psrp/9a660ea2-0c01-4523-9555-89ad6977c48f. The actual XML Create payload I'm sending (encrypted over the wire) is

    <s:Envelope xmlns:rsp="http://schemas.microsoft.com/wbem/wsman/1/windows/shell" xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:wsman="http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd" xmlns:wsmv="http://schemas.microsoft.com/wbem/wsman/1/wsman.xsd">
      <s:Header>
        <wsa:Action s:mustUnderstand="true">http://schemas.xmlsoap.org/ws/2004/09/transfer/Create</wsa:Action>
        <wsmv:DataLocale s:mustUnderstand="false" xml:lang="en-US"/>
        <wsman:Locale s:mustUnderstand="false" xml:lang="en-US"/>
        <wsman:MaxEnvelopeSize s:mustUnderstand="true">153600</wsman:MaxEnvelopeSize>
        <wsa:MessageID>uuid:AAD7BEA7-752F-4388-880C-06FF374AAE7C</wsa:MessageID>
        <wsman:OperationTimeout>PT20S</wsman:OperationTimeout>
        <wsa:ReplyTo>
          <wsa:Address s:mustUnderstand="true">http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</wsa:Address>
        </wsa:ReplyTo>
        <wsman:ResourceURI s:mustUnderstand="true">http://schemas.microsoft.com/powershell/Microsoft.Exchange</wsman:ResourceURI>
        <wsmv:SessionId s:mustUnderstand="false">uuid:6BC0F13C-0027-4931-A4E2-328273A83FDE</wsmv:SessionId>
        <wsa:To>http://server2019.exchange.test:80/PowerShell</wsa:To>
        <wsman:OptionSet s:mustUnderstand="true">
          <wsman:Option MustComply="true" Name="protocolversion">2.3</wsman:Option>
        </wsman:OptionSet>
      </s:Header>
      <s:Body>
        <rsp:Shell ShellId="07D33DFC-E7DA-4289-9E7F-B54222583D61">
          <rsp:InputStreams>stdin pr</rsp:InputStreams>
          <rsp:OutputStreams>stdout</rsp:OutputStreams>
          <creationXml xmlns="http://schemas.microsoft.com/powershell">AAAAAAAAAAEAAAAAAAAAAAMAAADHAgAAAAIAAQD8PdMH2ueJQp5/tUIiWD1hAAAAAAAAAAAAAAAAAAAAADxPYmogUmVmSWQ9IjAiPjxNUz48VmVyc2lvbiBOPSJwcm90b2NvbHZlcnNpb24iPjIuMzwvVmVyc2lvbj48VmVyc2lvbiBOPSJQU1ZlcnNpb24iPjIuMDwvVmVyc2lvbj48VmVyc2lvbiBOPSJTZXJpYWxpemF0aW9uVmVyc2lvbiI+MS4xLjAuMTwvVmVyc2lvbj48L01TPjwvT2JqPgAAAAAAAAACAAAAAAAAAAADAAAC/QIAAAAEAAEA/D3TB9rniUKef7VCIlg9YQAAAAAAAAAAAAAAAAAAAAA8T2JqIFJlZklkPSIwIj48TVM+PEkzMiBOPSJNaW5SdW5zcGFjZXMiPjE8L0kzMj48STMyIE49Ik1heFJ1bnNwYWNlcyI+MTwvSTMyPjxPYmogTj0iUFNUaHJlYWRPcHRpb25zIiBSZWZJZD0iMSI+PFROIFJlZklkPSIwIj48VD5TeXN0ZW0uTWFuYWdlbWVudC5BdXRvbWF0aW9uLlJ1bnNwYWNlcy5QU1RocmVhZE9wdGlvbnM8L1Q+PFQ+U3lzdGVtLkVudW08L1Q+PFQ+U3lzdGVtLlZhbHVlVHlwZTwvVD48VD5TeXN0ZW0uT2JqZWN0PC9UPjwvVE4+PFRvU3RyaW5nPkRlZmF1bHQ8L1RvU3RyaW5nPjxJMzI+MDwvSTMyPjwvT2JqPjxPYmogTj0iQXBhcnRtZW50U3RhdGUiIFJlZklkPSIyIj48VE4gUmVmSWQ9IjEiPjxUPlN5c3RlbS5NYW5hZ2VtZW50LkF1dG9tYXRpb24uUnVuc3BhY2VzLkFwYXJ0bWVudFN0YXRlPC9UPjxUPlN5c3RlbS5FbnVtPC9UPjxUPlN5c3RlbS5WYWx1ZVR5cGU8L1Q+PFQ+U3lzdGVtLk9iamVjdDwvVD48L1ROPjxUb1N0cmluZz5VTktOT1dOPC9Ub1N0cmluZz48STMyPjI8L0kzMj48L09iaj48T2JqIE49Ikhvc3RJbmZvIiBSZWZJZD0iMyI+PE1TPjxCIE49Il9pc0hvc3ROdWxsIj50cnVlPC9CPjxCIE49Il9pc0hvc3RVSU51bGwiPnRydWU8L0I+PEIgTj0iX2lzSG9zdFJhd1VJTnVsbCI+dHJ1ZTwvQj48QiBOPSJfdXNlUnVuc3BhY2VIb3N0Ij50cnVlPC9CPjwvTVM+PC9PYmo+PE5pbCBOPSJBcHBsaWNhdGlvbkFyZ3VtZW50cyIgLz48L01TPjwvT2JqPg==</creationXml>
        </rsp:Shell>
      </s:Body>
    </s:Envelope>

    This works just fine against an actual Microsoft.PowerShell wsman endpoint it's just that this exchange endpoint sends back data that isn't a WSMan payload.

    I've verified in the WinRM analytics logs that the payload is coming through as expected and it says that it's sending the CreateResponse as an XML back but that's somehow being encoded/encrypted outside of the standard MS-WSMV encryption process. I've got the event logs saved as an .evtx which I've uploaded to https://file.io/2sH4tU. If you need me to send this any other way please let me know.

    Friday, March 27, 2020 12:41 AM
  • Hi jborean93,

    Thanks for the clarification. I'm looking into this and will follow up shortly.

    Tom

    Saturday, March 28, 2020 7:45 PM
    Moderator
  • Just thought it best to update the thread, I've since installed Exchange 2016 and 2019 on separate environments to test out the script and still come across the same problem. I can connect without any issues to the Microsoft.PowerShell configuration but as soon as I try the Microsoft.Exchange configuration over http://host:80/PowerShell' I get that random binary data back post decryption.

    Just to try and rule out a bad decryption implementation I've purposefully changed the 'wsa:Action' field to be 'wsa:Actio' to see whether I get a failure message back. The error is encrypted when sent back from the server and the same code I am using for a proper message is decrypting the correctly.

    Tuesday, March 31, 2020 6:04 AM
  • jborean93, 

    Does your Exchange endpoint work with PowerShell remoting using these guides: 

     

    https://docs.microsoft.com/en-us/powershell/exchange/exchange-server/control-remote-powershell-access-to-exchange-servers?view=exchange-ps

    https://docs.microsoft.com/en-us/powershell/exchange/exchange-server/connect-to-exchange-servers-using-remote-powershell?view=exchange-ps

     

    Are you part of the part of the management role group on the Exchange server? I'm still tracking down the content of that binary data and will let you know what I find. 

    Tom

    Thursday, April 2, 2020 6:06 AM
    Moderator
  • I’m away from my test environment now but I am able to use Enter-PSSession using the same test account in my application. PowerShell as a client connects just fine it just seems to transparently handle the data whereas I’m missing that step in my app.
    Thursday, April 2, 2020 11:29 AM
  • jborean93, 

    Can you send email to dochelp at microsoft.com, referencing the URL for this thread and my name? We will need to arrange for some data sharing to gather information on this and email will be the best way.

    Thanks,

    Tom

    Monday, April 6, 2020 11:41 PM
    Moderator
  • Just posting back here in case anything in the future comes across the same problem.

    After much trial and error the issue was the Python client that was creating and sending the HTTP requests was automatically adding the 'Accept-Encoding: gzip, default' header to the request. Normally on a vanilla WinRM endpoint wouldn't be an issue as it just ignores this value but because the Exchange PowerShell endpoint is hosted by IIS and that is handling the HTTP requests it's honoring that value.

    The response it sends back is compressed, once it exceeds a certain size, using one of those 2 algorithms as we (the client) stated it accepts those encodings but never did anything with it. The fix was to ensure the client sent 'Accept-Encoding: identity' instead which tells IIS not to compress/transform the data. Once that is added to the request the response once decrypted is the proper WSMan envelop which the client is now able to process properly.

    Big thanks to Tom for helping with this process and looking into various avenues.

    • Marked as answer by jborean93 Tuesday, June 16, 2020 10:54 PM
    Tuesday, June 16, 2020 10:54 PM
  • That's great news Jordan! Glad you figured it out.

    Tom

    Tuesday, June 16, 2020 11:28 PM
    Moderator