# 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


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://nk0.gitbook.io/dfir/enterprise-architecture/the-cloud/azure/attacking-azure/persistence/sspr-mfa.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
