FalconFriday — Stealing and detecting Azure PRT cookies — 0xFF18
TL;DR: There is a lot of great research available on how to obtain an Azure Primary Refresh Token (PRT) cookie, post-exploitation. This post outlines a way to bypass the default detection in MDE and how to detect this bypass.

Azure PRTs have been covered extensively in research from @_dirkjan, but also by Lee Christensen in this post. In essence, there are two ways to make Windows give you a PRT cookie. The ‘easy’ way is to use browsercore.exe. This executable reads the nonce from stdin and gives back the PRT cookie on stdout. This is how, for example, the Chrome plugin can do SSO with your AzureAD account. The tool ROADToken from @_dirkjan does exactly this.

The second way to get the PRT cookie is by interfacing with the right COM object. This COM object lives inside MicrosoftAccountTokenProvider.dll. By activating this COM object and calling the right functions, you can achieve the same. In fact, this is exactly what browsercore.exe does for you.

There is of course a third way, which is replicating the behavior of this COM object yourself, but we leave this story for another time.

Red

The least sophisticated approach of the two ways to obtain the PRT cookie is the browsercore route. Just starting the process, providing the nonce on stdin and receiving the PRT cookie on stdout. Unfortunately, this is flagged by MDE as ‘Possible attempt to access Primary Refresh Token (PRT)’.

MDE alert when generating a PRT cookie with browsercore.exe

After some experimenting, we were able to overcome this detection with a bypass. We’re not sure what exactly triggered this alert, but we suspect that using browsercore directly from the commandline is what trips the alarm. So instead, we opted for a solution to create the two named pipes which Chrome also uses:

cmd.exe /d /c "C:\Program Files\Windows Security\BrowserCore\BrowserCore.exe" chrome-extension://ppnbnpeolgkicgegkbkbjmhlideopiji/ --parent-window=0 < \\.\pipe\chrome.nativeMessaging.in.RANDOMNUMBERHERE > \\.\pipe\chrome.nativeMessaging.out.SAMERANDOMNUMBERHERE

This is by far the most common commandline used to invoke browsercore.exe. The oddity here is that it redirects stdin and stdout to two different named pipes. Just replicating this behavior is sufficient to bypass the MDE rule.

  1. Create two named pipes with a similar name/structure.
  2. Start browsercore.exe from cmd.exe with the specific commandline used by Chrome.
  3. Job done.

There are likely more ways to avoid tripping this built-in MDE detection, but one is enough for now.

The second bypass is to create a COM object and interact with that object to obtain the PRT cookie; this is more stealthy. The implementation of Lee Christensen here is sufficient.

Blue

Obviously, this blog post series is about detecting attacks, so we’ll provide you with two queries to detect the above-mentioned two bypasses.

Assuming an attacker has bypassed the most basic detection against tampering with browsercore, the following rule detects more advanced abuse of browsercore— as mentioned in the first bypass above. In essence, the detection is fairly simple. We want to detect when the (grand)parent of browsercore is not a reputable process (i.e. Chrome, Teams, etc.) or is a LOLBin that can execute arbitrary commands. Due to some MDE limitations however, the query has become pretty big. The limitation here is that MDE doesn’t log the hash of a grandparent process. Since the normal process genealogy is Chrome.exe -> cmd.exe -> browsercore.exe and we need to check the prevalence of the grandparent of browsercore, we need to do some magic to get that info.

You can find the detailed query here.

As for the second bypass, where the attacker utilizes the COM object to obtain a PRT cookie, we’re significantly hindered by the throttling of logs by MDE. We can fairly easily detect basic abuse of the COM object. Normally, only highly trusted processes such as backgroundtaskhost.exe , browsercore.exe , msedge.exe , etc. activate this COM object. When a malicious process tries to do that, it triggers an ImageLoad of MicrosoftAccountTokenProvider.dll. Using the FileProfile feature in MDE, we can easily check for that. Unfortunately, here’s where the limitation comes in. MDE only logs a tiny number of ImageLoads. The majority of ImageLoads are not logged by MDE, hence, this detection only works one way . If the rule provides a hit, it’s guaranteed that a suspicious process has loaded this DLL. However, you’re likely to have a large number of false negatives.

Since the rule is very imprecise, we’re not going to include it the FalconFriday GitHub repo. For the few readers that actually would be happy with such a ‘False Negative’-biased rule, we’ll provide it here.

DeviceImageLoadEvents
| where FileName =~ "MicrosoftAccountTokenProvider.dll"
| summarize by InitiatingProcessSHA1
| invoke FileProfile(InitiatingProcessSHA1, 1000)
| where GlobalPrevalence < 250

As a side note, you could build a detection based off Sysmon which does log DLL loads correctly. However, it then becomes more difficult to determine if a process loading this DLL is suspicious or not, due to a lack of the MDE-only FileProfile function. You could base it on the signature status and ‘OriginalFilename’ of the executable loading this DLL.


For a future blog post, we’re planning to detail out the inner working of MicrosoftAccountTokenProvider.dll, separate from the FalconFriday blog post. Keep an eye out for this in-depth analysis post!

Knowledge center

Other articles

BloodHound — Calculating AD metrics 0x02

BloodHound — Calculating AD metrics 0x02

[dsm_breadcrumbs show_home_icon="off" separator_icon="K||divi||400" admin_label="Supreme Breadcrumbs" _builder_version="4.18.0" _module_preset="default" items_font="||||||||" items_text_color="rgba(255,255,255,0.6)" custom_css_main_element="color:...

BloodHound — Calculating AD metrics 0x01

BloodHound — Calculating AD metrics 0x01

[dsm_breadcrumbs show_home_icon="off" separator_icon="K||divi||400" admin_label="Supreme Breadcrumbs" _builder_version="4.18.0" _module_preset="default" items_font="||||||||" items_text_color="rgba(255,255,255,0.6)" custom_css_main_element="color:...

Together. Secure. Today.

Stay in the loop and sign up to our newsletter

FalconForce realizes ambitions by working closely with its customers in a methodical manner, improving their security in the digital domain.

Energieweg 3
3542 DZ Utrecht
The Netherlands

FalconForce B.V.
[email protected]
(+31) 85 044 93 34

KVK 76682307
BTW NL860745314B01