Push to Verify Using the Microsoft Authenticator App
Posted by cheesehead1996@reddit | sysadmin | View on Reddit | 42 comments
I'm looking for a good way for our helpdesk to verify a user's identity prior to completing a password reset. In my past life, we had Duo, and this was a native feature.
At my current gig, we use Microsoft Authenticator. I'm trying to find a way to send push notifications via the Microsoft Authenticator app. I spent a good bit of time trying to replicate the approach shown here (https://www.cyberdrain.com/automating-with-powershell-sending-mfa-push-messages-to-users/), but it's a few years old and relies on a lot of deprecated methods. Also, it seems more geared towards MSPs with delegated tenant access, which I am not.
Has anyone found a way to implement something like this lately? Or if not, does anyone have suggestions for a better way to go about the key goal of verifying end users prior to password resets?
LT_Solutions@reddit
I actually wrote a PowerShell script that can be pushed out with an RMM or Intune that sends a 4 digit popup (randomly generated) and gives them 4 options to select the right code. You then put in a Webhook to Slack, Teams, Zoom, etc. that lets you know if the person verified it was them by stating Success, Failure or No Response. I've attached an example of the message popup
cheesehead1996@reddit (OP)
Would you be willing to share that script?
LT_Solutions@reddit
I added notes on each section so you know what variables do what. However, some of the Write-Output will be different for each system. This one is meant for Teams chat. Others like Slack, Discord, and so on will use different variables. Mainly, for this one I used for Intune as we have a hybrid environment. I created a Remediation Script in Intune because you can run those on random to computers (FYI this is only for Windows machines). I set the Remediation script to detect if the computer has C:\Users folder (remediation scripts have to verify if something is there before it runs). Then I put this script in. FYI, if you use for Intune, the logs for the Remediation with successful execution will say Recurse in the Intune logs. Mainly because you didn't do anything in the Detection section, which was the C:\Users section. For my own sanity on this, I will only keep this script here for 48 hours and then will remove. Use in the right way this was made for.
# =========================================================
# LOAD WINDOWS FORM LIBRARIES
# =========================================================
Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing
# =========================================================
# WEBHOOK SETTINGS
# =========================================================
# Replace with your webhook URL
# Examples:
# - Power Automate
# - Teams
# - Slack
# - Discord
# - Custom API endpoint
$WebhookUrl = "WEBHOOK URL"
# =========================================================
# MFA NUMBER GENERATION
# =========================================================
# Generate the correct MFA number
$CorrectNumber = Get-Random -Minimum 1000 -Maximum 9999
# Create array containing selectable numbers
$Numbers = @($CorrectNumber)
# Generate additional random numbers until there are 4 total
while ($Numbers.Count -lt 4) {
$num = Get-Random -Minimum 1000 -Maximum 9999
# Prevent duplicate numbers
if ($Numbers -notcontains $num) {
$Numbers += $num
}
}
# Shuffle/randomize button order
$Numbers = $Numbers | Sort-Object { Get-Random }
# =========================================================
# RESPONSE VARIABLES
# =========================================================
# Result codes:
# 0 = Success
# 1 = Failure / No Response
$Result = $null
# Human-readable status
$Status = "NO RESPONSE"
# Stores selected button value
$selectedValue = ""
# Stores the exact time the button was clicked
$ClickTime = ""
# =========================================================
# CREATE MAIN FORM
# =========================================================
$form = New-Object System.Windows.Forms.Form
# Window title
$form.Text = "MFA Verification"
# Window size
$form.Size = New-Object System.Drawing.Size(420,320)
# Open centered on screen
$form.StartPosition = "CenterScreen"
# Keep popup above all windows
$form.TopMost = $true
# Prevent resizing
$form.FormBorderStyle = "FixedDialog"
$form.MaximizeBox = $false
# =========================================================
# MESSAGE LABEL
# =========================================================
$label = New-Object System.Windows.Forms.Label
# CUSTOMIZE THIS MESSAGE
$label.Text = "Please verify your sign-in request by selecting the matching number below."
# Label size and position
$label.Size = New-Object System.Drawing.Size(360,80)
$label.Location = New-Object System.Drawing.Point(30,20)
# Font settings
$label.Font = New-Object System.Drawing.Font("Segoe UI",10)
# Prevent auto-resizing
$label.AutoSize = $false
$form.Controls.Add($label)
# =========================================================
# DISPLAY MFA NUMBER
# =========================================================
$numberLabel = New-Object System.Windows.Forms.Label
# Display correct MFA number
$numberLabel.Text = $CorrectNumber
# Center the number above the buttons
$numberLabel.Size = New-Object System.Drawing.Size(360,40)
$numberLabel.Location = New-Object System.Drawing.Point(20,110)
# Center text inside label
$numberLabel.TextAlign = [System.Drawing.ContentAlignment]::MiddleCenter
# Large bold font
$numberLabel.Font = New-Object System.Drawing.Font(
"Segoe UI",
18,
[System.Drawing.FontStyle]::Bold
)
$form.Controls.Add($numberLabel)
# =========================================================
# CREATE BUTTONS
# =========================================================
$x = 30
foreach ($Number in $Numbers) {
$button = New-Object System.Windows.Forms.Button
# Button text
$button.Text = $Number
# Button size
$button.Size = New-Object System.Drawing.Size(80,35)
# Button position
$button.Location = New-Object System.Drawing.Point($x,180)
# =====================================================
# BUTTON CLICK EVENT
# =====================================================
$button.Add_Click({
# Save selected number
$script:selectedValue = $this.Text
# Save exact click time
$script:ClickTime = (Get-Date).ToString("yyyy-MM-dd HH:mm:ss UTC")
# Check if correct number selected
if ($script:selectedValue -eq $CorrectNumber.ToString()) {
$script:Result = 0
$script:Status = "SUCCESS"
}
else {
$script:Result = 1
$script:Status = "FAILURE"
}
# Close popup
$form.Close()
})
# Add button to form
$form.Controls.Add($button)
# Move next button to the right
$x += 90
}
# =========================================================
# SHOW POPUP
# =========================================================
$form.ShowDialog()
# =========================================================
# HANDLE NO RESPONSE
# =========================================================
# User closed popup or did not click
if ($Result -eq $null) {
$Result = 1
$Status = "NO RESPONSE"
# Store timeout/close time
$ClickTime = (Get-Date).ToString("yyyy-MM-dd HH:mm:ss UTC")
}
# =========================================================
# JSON PAYLOAD
# =========================================================
# Data sent to webhook
$Body = @{
User = $env:USERNAME
Computer = $env:COMPUTERNAME
ClickTime = $ClickTime
Status = $Status
Selected = $selectedValue
Correct = $CorrectNumber
ReportTime = (Get-Date).ToString("yyyy-MM-dd HH:mm:ss UTC")
} | ConvertTo-Json
# =========================================================
# SEND WEBHOOK
# =========================================================
try {
Invoke-RestMethod `
-Uri $WebhookUrl `
-Method POST `
-Body $Body `
-ContentType "application/json"
Write-Output "Webhook sent successfully."
}
catch {
Write-Output "Webhook failed: $_"
}
# =========================================================
# LOCAL OUTPUT / INTUNE LOGGING
# =========================================================
Write-Output ""
Write-Output "====================================="
Write-Output "User : $env:USERNAME"
Write-Output "Computer : $env:COMPUTERNAME"
Write-Output "Status : $Status"
Write-Output "Selected : $selectedValue"
Write-Output "Correct : $CorrectNumber"
Write-Output "Click Time : $ClickTime"
Write-Output "====================================="
# =========================================================
# EXIT CODES
# =========================================================
# Exit 0 = Success
# Exit 1 = Failure / No Response
if ($Result -eq 0) {
exit 0
}
else {
exit 1
}
certified_rebooter@reddit
Look into Traceless. Our help desk uses it for this exact use case. It allows us to push MFA's to our O365 end users using via MSFT Authenticator as well as various other authentication methods. We've been using it for about 3 years and haven't had any issues.
JwCS8pjrh3QBWfL@reddit
This is an anti-pattern. This trains users to accept MFA push requests when someone on the phone asks them to. You should not do this.
cheesehead1996@reddit (OP)
What would you recommend instead?
Asleep_Spray274@reddit
As a side note, have you ever investigated why you have so many password reset requests?
Most of the time I've done this with orgs, it's because their password has expired and they didn't change it in time. It's a tiny percentage of actually forgot.
Moving them to non expire passwords fixed those requests. Non expire is recommended by all cyber frameworks and even required by NIST. So worth looking into how you do it for your environment
cheesehead1996@reddit (OP)
We did recently eliminate password expiration. So hopefully that cuts it down.
We do have a lot of seasonal employees who come back during spring/summer and don’t know their passwords anymore.
St0nywall@reddit
An observation, ignoring the budgetary and training mandates needed, If you know it works with Duo why not get Duo?
thortgot@reddit
Duo's solution has other weaknesses.
DeathTropper69@reddit
I'd be interested to hear what you think those are.
thortgot@reddit
Duo's push verification number match is a significantly worse from a security stance.
Their defaults are also wildly less secure (non rotating totp?!).
While Duo can be used securely it isnt an objectively better platform.
DeathTropper69@reddit
Yes but how is it worse?
thortgot@reddit
Their defaults are less secure, their verified number match is worse. Its additional attack space against your IAM.
DeathTropper69@reddit
I would guess you haven’t used the platform in some time. The verified number match is much better overall, their defaults are in many cases better than Entra and Google IAM, and definitely not an additional attack space if properly configured and all apps are federated to Duo.
thortgot@reddit
I haven't set up a new client in years. Ive been converting clients for over 5. From SMS being used to non rotating TOTP keys the defaults are just terrible.
How is verified match better with Duo?
DeathTropper69@reddit
They don’t roll either of those by default. SMS and fixed TOTP codes are offered but haven’t been defaults for forever and are listed as the least secure auth methods and advices against.
As for the verified match, user experience is better, number length is configurable, autofill is available, and for true phishing resistance proximity verification can be required.
Duo is fantastic if you are using it as your IDP and leveraging all its features ( many of which can be achieved with MS authenticator ). If you are just using it for EAM then you are better off saving some cash and using MS authenticator.
DeathTropper69@reddit
Probs not worth moving to Duo for just this. While I personally find Duo to be far superior to anything MS is offering it only is so if you are leveraging the full service and everything it has to offer.
ihaveabs@reddit
Why not use SSPR?
cheesehead1996@reddit (OP)
We do have SSPR, and try to funnel as many users to it as we can. But we do have a decent amount of end users who can't (or don't want to), figure it out. We can try to take a more aggressive stance on SSPR, but we still want something for the leftovers.
baaaahbpls@reddit
Without getting mfa push from Microsoft and having leftovers refusing to use SSPR get the good ol' leadership gets verified and then verified you.
Your orga leadership absolutely had to be accountable, so when their direct reports need help and won't use any security methods, they get to take time out of their day to verify themselves and the end user, that way they are incentivised to follow security guidelines.
hihcadore@reddit
This is the way
It’ll also motivate some users to figure out SSPR vs engaging their manager.
baaaahbpls@reddit
But my manager isn't available, but my manager is in a meeting, yeah now how can we avoid needing them I wonder
hihcadore@reddit
Hahahaha exactly. I have a presentation due to the ceo in an hour. Do you wanna tell him why I can’t complete it?
….. no but your manager can
baaaahbpls@reddit
One of the perks of having a major security event is that you get so much more authority to deny people when they don't want to comply.
hihcadore@reddit
Hahahaha feel this one!
And more funding. Miraculously accounting and the c suite see value in EDR subscriptions and server hardware upgrades too.
8BFF4fpThY@reddit
How do you verify identity for SSPR? Just the push is only one factor, we need at least two.
JwCS8pjrh3QBWfL@reddit
This is configurable in the settings. You can require 2 different factors for SSPR.
CashBoxBandit@reddit
My brother in helpdesk tickets, enable password reset in Microsoft Authenticator!
Then the phone call becomes:
User: I need my password reset!
Tech: Open Microsoft authenticator on your phone, tap your work email address, and select reset password.
Then setup passkeys, platform SSO, conditional access rules, migrate everyone to edge and slowly lift and shift the org to passwordless logins. Bearded365Guy has great tips on YouTube but there's a lot of grunt work to do in M365 configs.
Temporary Access Passes are going to be critical, we've started doing our onboardings via zoom.
sryan2k1@reddit
This is to verify the user is who they say, not the other way around
highroller038@reddit
Speaking from prior experience, we had end-users enroll in some kind of self-service password reset during onboarding and they had to set up three challenge-response questions for this exact purpose. I think it might have been Manage Engine, and that's how we validated their identity over the phone. But anyway, if you can't do that, I would simply call their supervisor to confirm the employee is who they say they are and get approval before going back to the end-user. Another option is asking the end-user to send you a copy of their drivers license / government ID as a way to validate them. But nowadays, with AI image generation, anything can be faked.
Ihaveasmallwang@reddit
Use self service options rather than having help desk perform password resets. It will verify the users. There’s really no good reason for help desk to perform routine password resets.
progenrule@reddit
have you looked into using Temporary Access Pass instead? lets helpdesk generate a one-time code for the user after verifying them through some other channel, skips the whole push problem. for the actual push approach the graph api has /users/{id}/authentication/microsoftAuthenticatorMethods but triggering a verification push programmatically through it is still janky last i checked
shortstuf888@reddit
We use MSP process, it does SMS, email, phone call, Duo, and MS Authenticator.
MontereysCoast@reddit
I haven't used it, but there is Microsoft Entra Verified ID
disclosure5@reddit
This is a different thing, with a cost and a substantive political requirement round what users have to do.
cheesehead1996@reddit (OP)
Could you elaborate? I've heard of it, but really know nothing about it. I can find the Microsoft Learn article. But would be really curious about your take, if you'd implemented it.
disclosure5@reddit
We've looked into it but not implemented beyond a pilot. Have a look at the FGAQ:
https://learn.microsoft.com/en-us/entra/identity/authentication/concept-account-recovery-overview
The specific workflow is people use Government ID to reset an account.
You'll also see there a reference to needing to purchase a third party IDV.
Zestyclose-Bread-146@reddit
We recently moved from help-desk password reset to “ users can change their own password”. I work in 24/7 environment and Password reset requests were crazy. We used users ph numbers for authentication rather than authenticator app because lots of employees weren’t agreed to download app. We used SSRP group and now users can reset their own passwords and it send code to their phone number when they login for authentication.
rodder678@reddit
A quick Google search for the URL that azure function was hitting came up with this: https://github.com/tmontney/SendAzureMFARequest
Looks reasonably modern. Haven't tried it myself yet. Looks like they are all using the private API endpoint that's used by the Azure MFA plugin for Network Policy Sever (NPS).
elpollodiablox@reddit
I wish I'd seen this before I undertook a similar project and fought with it for weeks before getting it to work.
ben_zachary@reddit
CIPP.app which is primarily a multi tenant 365 mgmt tool, can do this I believe.
They have a free self hosted in azure or 99 bucks for them to host it. Many people in the MSP space know and use it
We use an azure runbook from our ticketing system and you could also do this with power app ( I've seen YouTubes on it, but never needed it)