> For the complete documentation index, see [llms.txt](https://nk0.gitbook.io/dfir/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://nk0.gitbook.io/dfir/enterprise-architecture/the-cloud/azure/attacking-azure/persistence/sspr-mfa.md).

# SSPR/MFA

{% embed url="<https://support.quest.com/technical-documents/change-auditor/7.1/office-365-and-azure-active-directory-event-reference-guide/2>" %}

{% embed url="<https://learn.microsoft.com/en-us/entra/identity/authentication/howto-sspr-reporting>" %}

## What Is SSPR

## Attack

If you have control of an MFA method that is available to a user, you can reset their password without knowing their password.

## Detect

### Hunt for known bad MFA devices

Below scripts lists all MFA methods by every user and lists their properties.

```powershell
param ($Path, $UserList)

if ( ($Path -eq $null) -or ($Path -eq "") -or ($Path -eq " "))
{
	Write-Host "-Path not valid, please provide a filepath to export CSV to."
	Write-Host "-UserList, to optionally add a list of users to save time. By default grabs a list of every user in the tenant."
}
else 
{
	#Connect MgGraph
	Connect-MgGraph -Scopes 'UserAuthenticationMethod.Read.All' -NoWelcome

	if ($UserList -eq $null)
	{
		# Display the custom objects
		#Get all Azure users
		$users = get-mguser -All
	}
	else
	{
		#Provide list of users
		$users = ForEach ($mguser in $(get-content -Path $UserList)) {
		get-mguser -userid $mguser
		}
	}
	$results=@();
	Write-Host  "`nRetreived $($users.Count) users";
	#loop through each user account
	foreach ($user in $users) {

	$MFAData=Get-MgUserAuthenticationMethod -UserId $user.UserPrincipalName #-ErrorAction SilentlyContinue

		#check authentication methods for each user
		ForEach ($method in $MFAData) {
			$myObject = [PSCustomObject]@{
				user               		= "-"
				Id 				   		= "-"
				MFAstatus          		= "-"
				email              		= "-"
				fido2              		= "-"
				app                		= "-"
				password           		= "-"
				phone              		= "-"
				softwareoath       		= "-"
				tempaccess         		= "-"
				hellobusiness      		= "-"
				DeviceName         		= "-"
				PhoneAppVersion    		= "-"
				DeviceTag		  		= "-"
			}

			$myobject.user = $user.UserPrincipalName;
			Switch ($method.AdditionalProperties["@odata.type"]) {
				"#microsoft.graph.emailAuthenticationMethod"  { 
				$myObject.Id = $method.Id
				$myObject.email = $true 
				$myObject.MFAstatus = "Enabled"
			} 
				"#microsoft.graph.fido2AuthenticationMethod" { 
				$myObject.fido2 = $true 
				$myObject.MFAstatus = "Enabled"
			}    
				"#microsoft.graph.passwordAuthenticationMethod"                {              
				$myObject.password = $true 
					# When only the password is set, then MFA is disabled.
					if($myObject.MFAstatus -ne "Enabled")
					{
						$myObject.MFAstatus = "Disabled"
					}                
			}     
				"#microsoft.graph.phoneAuthenticationMethod"  { 
				$myObject.phone = $true
				$myObject.MFAstatus = "Enabled"
			}
			"#microsoft.graph.microsoftAuthenticatorAuthenticationMethod"  {
				$myObject.Id = $method.Id 
				$myObject.DeviceName = $method.AdditionalProperties.displayName
				$myObject.PhoneAppVersion = $method.AdditionalProperties.phoneAppVersion
				$myObject.deviceTag = $method.AdditionalProperties.deviceTag
				$myObject.MFAstatus = "Enabled"
			}
		
				"#microsoft.graph.softwareOathAuthenticationMethod"  {
				$myObject.Id = $method.Id 
				$myObject.softwareoath = "Oath OTP Enabled" 
				$myObject.MFAstatus = "Enabled"
			}           
				"#microsoft.graph.temporaryAccessPassAuthenticationMethod"  { 
				$myObject.tempaccess = $true 
				$myObject.MFAstatus = "Enabled"
			}           
				"#microsoft.graph.windowsHelloForBusinessAuthenticationMethod"  { 
				$myObject.hellobusiness = $true 
				$myObject.MFAstatus = "Enabled"
			}                   
			}
		$results+= $myObject;
		}
	}
	# Display the custom objects
	$results | export-csv -path $Path
}
```

{% embed url="<https://activedirectorypro.com/mfa-status-powershell/>" %}

<figure><img src="/files/KnkjO41xU9f7RUz9kn4q" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/P6aIfGtjGgK9B30pAivF" alt=""><figcaption></figcaption></figure>

## What logs are available?

### Audit Logs:<br>

Password is not required for SSPR, only an alternate authentication method.

SSPR activity flow:

1. User submitted their user ID
2. User was presented with verification options
3. User started the mobile app code verification option
4. User completed the mobile app code verification option
5. User completed all verification steps required to reset their password
6. User submitted a new password
7. Reset user password
8. Update StsRefreshTokenValidFrom Timestamp
9. Successfully completed reset.

First MFA:

<pre data-overflow="wrap"><code>OLD VALUE:

{"DeviceName":"SM-S911U","DeviceToken":"fdP4zadhT9mVkYYo_yQqEz:APA91bF61gVUucY6QWx2eWDi5IaSxCbSAM6LWsNGMmiiNXLgzCughKpLH5Nm2BetAEkl0axD2_ySPOJ24TEc0Wh-wwDeQBH-VP5c7rEme-xPTPioBPs-KsO5ftitRu4YG218wxXmII1Z",
"DeviceTag":"SoftwareTokenActivated",
"PhoneAppVersion":"6.2309.6329",
"OathTokenTimeDrift":0,
"DeviceId":"00000000-0000-0000-0000-000000000000",
"Id":"8cb20903-8109-4518-8269-a82dab749591","TimeInterval":0,
"AuthenticationType":3,
"NotificationType":4,
"LastAuthenticatedTimestamp":"2023-10-25T06:38:08.344692Z",
"AuthenticatorFlavor":null,
"HashFunction":null,
"TenantDeviceId":null,
"SecuredPartitionId":0,
"SecuredKeyId":0}

<strong>
</strong><strong>NEW VALUE:
</strong><strong>
</strong>{"DeviceName":"SM-S911U",
"DeviceToken":"fdP4zadhT9mVkYYo_yQqEz:APA91bF61gVUucY6QWx2eWDi5IaSxCbSAM6LWsNGMmiiNXLgzCughKpLH5Nm2BetAEkl0axD2_ySPOJ24TEc0Wh-wwDeQBH-VP5c7rEme-xPTPioBPs-KsO5ftitRu4YG218wxXmII1Z",
"DeviceTag":"SoftwareTokenActivated",
"PhoneAppVersion":"6.2309.6329",
"OathTokenTimeDrift":0,
"DeviceId":"00000000-0000-0000-0000-000000000000",
"Id":"8cb20903-8109-4518-8269-a82dab749591",
"TimeInterval":0,
"AuthenticationType":3,
"NotificationType":4,
"LastAuthenticatedTimestamp":"2024-12-12T12:38:08.344692Z",
"AuthenticatorFlavor":"Authenticator",
"HashFunction":"hmacsha256",
"TenantDeviceId":null,
"SecuredPartitionId":0,"SecuredKeyId":0}]
</code></pre>

AuthenticationFlavor is updated from null, to authenticator (not sure why):

* "AuthenticatorFlavor":null,
* "AuthenticatorFlavor":"Authenticator",

LastAuthenticatedTimestamp is sometimes updated (note sure when):

* "LastAuthenticatedTimestamp":"2023-10-25T06:38:08.344692Z",
* "LastAuthenticatedTimestamp":"2024-12-12T12:38:08.344692Z",

{% embed url="<https://support.quest.com/technical-documents/change-auditor/7.1/office-365-and-azure-active-directory-event-reference-guide/2>" %}

{% embed url="<https://techcommunity.microsoft.com/t5/microsoft-security-experts-blog/hunting-for-mfa-manipulations-in-entra-id-tenants-using-kql/ba-p/4154039>" %}

{% embed url="<https://www.mitiga.io/blog/advanced-bec-scam-campaign-targeting-executives-on-o365>" %}

{% embed url="<https://www.mitiga.io/blog/persistent-mfa-circumvention-in-an-advanced-bec-campaign-on-microsoft-365-targets>" %}

Get audit log details, OData queries not support for filtering. Will have to get through graph explorer and copy paste to .txt file.

{% embed url="<https://learn.microsoft.com/en-us/graph/api/directoryaudit-get?view=graph-rest-1.0&tabs=http>" %}

{% embed url="<https://learn.microsoft.com/en-us/powershell/module/microsoft.graph.reports/get-mgauditlogdirectoryaudit?view=graph-powershell-1.0>" %}

###

### Sign-In Logs:

## Mitigate
