Most of you have probably used Fiddler to troubleshoot an issue or two, and thus are familiar with it capabilities to capture and decrypt HTTP(S) traffic. In the Office 365 world, it’s a commonly used tool to investigate issues with authentication and web queries in general, including those made by applications such as Outlook. Or you can use it to understand what exactly is a given application doing, such as the recent investigation I did into the new V2 Exchange Online PowerShell module.
What had never occurred to me thus far, and I feel a bit ashamed because of, is the fact that you can actually use Fiddler to capture/examine remote PowerShell traffic, such as the one generated via the “standard” Exchange Online PowerShell cmdlets. The trick here is to make sure this traffic is routed through the Fiddler proxy, which simply means adjusting the winhttp proxy configuration on the machine:
netsh winhttp set proxy localhost:8888
where localhost:8888 is the default address used by the tool. Once you toggle this, Fiddler will start capturing the traffic generated by the Exchange Online session, and you can examine the intricacies of the MS-PSRP protocol. Let’s see a quick example.
Starting from the top, we see the establishment of a SSL tunnel to login.microsoftonline.com, where we will obtain a token from, after being redirected to the tenant-specific endpoint and presenting the credentials in a POST request. Once the token is obtained, a connection is established to outlook.office365.com and the token is passed to the /PowerShell-LiveID?BasicAuthToOAuthConversion=true endpoint in order to establish a remote PowerShell session via Modern auth. And this is where the winhttp proxy changes we made above start to take effect – without them only the token exchange traffic would’ve been captured.
Next we will have quite few requests related to negotiating the session settings and downloading the available cmdlets. What’s more interesting is how a given cmdlet looks like, and it certainly isn’t as pretty as within the PowerShell console window. For example, this is the request corresponding to me sending the Search-Mailbox cmdlet down the pipeline:
Two things are of importance here, the CommandId identifier, allowing us to find all other request related to the execution of the cmdlet, and the actual “payload”, tucked into the XML Arguments element. Now, decoding all this is an annoying task, involving converting the Base64 string to byte array, concatenating multiple parts as needed, calculating the start of the XML blob and extracting it, then getting just the elements we care about. Long story short, here’s an illustration on how you can do all this in PowerShell and how the output will look like:
The above is just an exercise and hardly gives us any information we didn’t already have – after all I was the person issuing the cmdlet, so I know which parameters I used. The output received back from the server is of course the more interesting part, so let’s try to get to it. As we know the command ID, we can locate the corresponding sessions in Fiddler, which might be quite a few depending on the actual cmdlet run and the output generated.
And we’re back to converting, decoding and whatnot. Here’s the end result in a prettified view:
PS C:\> $cmdletXML.OuterXml | Out-Default <Obj RefId="0"> <TN RefId="0"> <T>Microsoft.Exchange.InfoWorker.Common.Search.SearchMailboxResult</T> <T>System.Object</T> </TN> <ToString>Microsoft.Exchange.InfoWorker.Common.Search.SearchMailboxResult</ToString> <Props> <S N="Identity">vasil</S> <Nil N="TargetMailbox" /> <B N="Success">false</B> <Nil N="TargetFolder" /> <I32 N="ResultItemsCount">0</I32> <S N="ResultItemsSize">0 B (0 bytes)</S> </Props> </Obj>
So, the cmdlet failed and returned zero results. Too much work for such a result! But at least I’ve satisfied my curiosity 🙂
P.S. Thanks to Rahul and the entire team for the tip!
P.S.S. Some of the code shown above was “borrowed” from the RSRP_utils script available over at the PS Gallery.
Thanks for this. Might be nice to explain how to return the proxy setting back to direct access again after you’re done. For the record, the command you want is:
netsh winhttp reset proxy
Hello ,
its a good one.
Is it mandate to run this cmd netsh winhttp set proxy localhost:8888 to capture powershell traffic ?
Also, does this cmd execution also required we account has Basic Auth/MFA Enabled / MFA with federated domain.
Can you do a test for an account( which has MFA and domain is federated) and admin wants to connecting using Basic Auth?
TIA
If you want to capture the actual PS traffic, you need to update the proxy settings. As for authentication traffic, that’s usually HTTPS so it’s captured anyway.