NodeJS Logging integration with Azure Log Analytics/Sentinel

If you want to send data from NodeJS application to Log Analytics/Sentinel you can do it by using the HTTP Log Collector API.

Sending data to Sentinel Connected Log Analytics WorkSpace as part of incoming request callback

Note: If your app is in Azure PaaS solution, you should check out AppInsights first before going to this route 🙂

Writing module for the Log Collector API

There we’re some existing examples to do this, but I couldn’t get them to work in quick breeze. Due to this I did my own implementation with some key differences:

Signature generation part is done in two phases to improve readability

  • Basically I separated the creation of buffer shared key to base64 into an separate variable (var)

Function is bit different with callbacks and try catch logic added

Request Module will handle the Body Payload as non stringified

I did find, that If I sent the body payload stringified, it wouldnt match with the signature. To get the signature to match with the body payload, I added the request option json:true, and sent the non-stringified JSON payload.

The module to be imported

//https://nodejs.org/api/crypto.html
//https://docs.microsoft.com/en-us/azure/azure-monitor/platform/data-collector-api
//https://stackoverflow.com/questions/44532530/encoding-encrypting-the-azure-log-analytics-authorization-header-in-node-js
const rq = require('request')
const crypto = require('crypto')
const util = require('util')
function PushToAzureLogs (content,{id,key,rfc1123date,LogType}, callback) {
    console.log(id)
    try {
        //Checking if the data can be parsed as JSON
        if ( JSON.parse(JSON.stringify(content)) ) {
            var length = Buffer.byteLength(JSON.stringify(content),'utf8')
            var binaryKey = Buffer.from(key,'base64')
            var stringToSign = 'POST\n' + length + '\napplication/json\nx-ms-date:' + rfc1123date + '\n/api/logs';
            //console.log(stringToSign)
    
            var hash = crypto.createHmac('sha256',binaryKey)
            .update(stringToSign,'utf8')
            .digest('base64')
            var authorization = "SharedKey "+id +":"+hash
            var options= {
            json:true,
            headers:{
            "content-type": "application/json", 
            "authorization":authorization,
            "Log-Type":LogType,
            "x-ms-date":rfc1123date,
            "time-generated-field":"DateValue"
            },
            body:content    
            }
            var uri = "https://"+ id + ".ods.opinsights.azure.com/api/logs?api-version=2016-04-01"
    
            rq.post(uri,options,(err,Response) => {
                //return if error inside try catch block 
                if (err) {
                    return callback(("Not data sent to LA: " + err))
                }
               callback(("Data sent to LA " +util.inspect(content) + "with status code " + Response.statusCode))
    
            })
    
        }
        //Catch error if data cant be parsed as JSON
    } catch (err) {
        callback(("Not data sent to LA: " + err))
    }
           
}
module.exports={PushToAzureLogs}

Example from ExpressJS

//Add your other dependencies before this
const logs = require('./SRC/laws')
//define workspace details
const laws = {
    id:'yourID',
  key:'yourKey',
    rfc1123date:(new Date).toUTCString(),
    LogType:'yourLogType'
}
app.get('/graph', (request,response) => {
//not related to LA, this the data I am sending to LA
    var token = mods.readToken('rt').access_token
    mods.apiCall(token,'https://graph.microsoft.com/v1.0/me?$select=displayName,givenName,onPremisesSamAccountName', (data) => {
    console.log('reading graph', data)
//LA object
    jsonObject = {
        WAFCaller:request.hostname,
        identity:data.displayName,
        datasource:request.ip
    }
    console.log(jsonObject)
//send data to LA
        logs.PushToAzureLogs(jsonObject,laws,(data)=> {
            console.log(data)
        })
//return original response
    response.send(data)
    })
})

Once the data is sent, it will take about 5-10 minutes, for the first entries to be popping up

If /when you attach the Log Analytics workspace to Sentinel, you can then use it create your own hunting queries, and combine the data you have with TI-feeds etc

Happy hunting!

HelSec Azure AD write-up: Phishing on Steroids with Azure AD Consent Extractor

Here is short summary of the Presentation slides and demo of the Azure AD Consent Extractor @HelSec

  1. Attackers sends OWA upgrade link
  2. Victim clicks the link and accepts the upgrade
  3. Victim is redirected back to OWA when hitting the attacking server
  4. Victim receives ”OWA upgrade complete” message to email
  5. Meanwhile the attacking server is enjoying its new privileges on the user account

See the attack in action

If you want to know more about the consent attack, you can read my previous blog post from 2018

This version is the updated version to the one I did in 2018

https://securecloud.blog/2018/10/02/demonstration-illicit-consent-grant-attack-in-azure-ad-office-365

Deep Diver – Azure AD Identity Protection (IPC) Alerts

This blog is all about Azure AD Identity Protection alerts (referred to provider name ”IPC” later on the blog post) in the Microsoft cloud ecosystem.

If you want to read how IPC works I encourage you to read my blog post or navigate straight to docs.microsoft.com.

IPC is an Azure AD P2 feature that has been in general availability mode for approx. three years. Earlier this year Microsoft did ”refresh” for IPC and added new detection capabilities and enhanced UI. Azure AD P2 feature means that it’s available in most expensive license packages.

You will get a taste of its features even with a free Azure AD license but all the cool features are included in AAD P2. Practically, IPC calculates user risk (online/offline) based on Machine Learning & AI and makes decisions based on policies, is user login approved, is MFA or password change needed or is user sign-in blocked.

Gimme The Alerts – Where are Those?

Azure AD Identity Protection (IPC) is a provider for multiple security solutions which means that alerts triggered in IPC can be found from multiple places (list below). Let’s have a closer look.

  • Azure AD Identity Protection blade
  • Intelligent Security Graph (ISG)
  • Azure Sentinel
  • Cloud App Security (MCAS)
  • Azure Security Center
  • Microsoft Threat Protection suite (MTP)
  • PowerShell for management

Azure AD Identity Protection Blade

Identity Protection UI resides in Azure AD where investigation and mitigations can be done. Btw, check my demo environment Identity Secure Score, 237 out of 265. Quite impressive even I say it myself 🙂

If a risk is detected admins (or dedicated email distribution list) will receive an alert as seen below. When a link is clicked, the person who received the email will land to the Identity Protection portal in Azure AD.

Intelligent Security Graph (ISG) aka Microsoft Security Graph

Identity Provider is one of the ISG providers, the full list of available providers at the time of writing can be found here. In pictures below are ISG high-level architecture and export from ISG alert from my tenant. In the latter one, you can see the provider highlighted with yellow color.

Microsoft Intelligent Security Graph (ISG)

Azure Sentinel

If you are using Azure Sentinel (a cloud-native SIEM which is a hot topic right now) and you have configured data connectors, and activated rule properly you will get IPC alerts to Azure Sentinel as incidents.

Azure Sentinel Identity Protection template rule basically raises an incident if an alert is generated in IPC.

Microsoft Cloud App Security

The IPC alert is also found from MCAS. As you can see from the picture below MCAS adds information to the alert and makes it more useful for the investigation. Btw, MCAS is the best solution in the Microsoft ecosystem to investigate internal user suspicious activity and behavior. If you are using it, I highly encourage you to get familiar with it and especially to UEBA capabilities.

I’m sold to it, totally:) But, I’m looking it only from the technical perspective, not from a financial perspective.

Azure Security Center (ASC)

IPC alerts are also found from Azure Security Center. ASC also provides a geolocation map which can be very useful to get a bigger picture of the attack.

Microsoft Threat Protection Suite (MTP)

MTP was just launched to public preview. Unfortunately, I don’t have such an environment available where it’s enabled. In a nutshell, it is a pre -and post-breach enterprise defense suite that natively integrates across endpoints, protecting:

  • Endpoints with Microsoft Defender ATP
  • Email and collaboration with Office 365 ATP
  • Identities with Azure ATP and Azure AD Identity Protection
  • Applications with Microsoft Cloud App security

More information from here and here.

PowerShell

This has slipped out of my radar totally. Microsoft released the PowerShell module for Microsoft Security Graph in April 2019. You can read more about it from here. In a nutshell, you need to do the following:

  • PowerShell v5 or above
  • Register App to Azure AD
  • User this URI: urn:ietf:wg:oauth:2.0:oob, it’s needed for desktop app redirect to work
  • Configure permissions to the App ( SecurityEvents.ReadWrite.All )
  • Grant Admin consent to the App
  • Install the module
  • Run and enjoy 🙂

In the Technet blog, there are multiple questions about App registration guidance. My 2cents:

  • When registering the App, grant API permissions for delegated mode (interactive login is used)
  • Grant SecurityEvents.Read.All & SecurityEvents.ReadWrite.All permissions to the App
  • Grant admin consent
  • When running the PowerShell – use you userprincipalName as username and AppID as password.

Using the module

Login with userPrincipalName + App ID. After the initial login, the modern authentication prompt appears (it’s encrypted by Finnish) and interactive login is processed together with Conditional Access policies.

Managing the Alerts

MicrosoftGraphSecurity module has following available commands

With Get-GraphSecurityAlert you can get all alerts from the ISG with Identity Protection alerts included.

Secure Score information is also available with Get-GraphSecuritySecureScore command.

Set ISG Alert

ISG alerts can be managed via PowerShell with Set-MicrosoftGraphSecurity cmdlet. Extremely useful if the alerts are sent to SIEM. The downside is that there isn’t any integration to the backends (providers).

Note: This means that even you update the alert status in ISG it will remain open in the ISG providers (Identity Protection, Cloud App Security etc.)

Summary

The Microsoft cloud ecosystem is huge and organizations have multiple security solutions available by default. Keep in mind that most of the advanced tools (including IPC, MCAS) require E5/A5, G5, P2 license. As seen above, synergy advantages are obvious.

What solutions to use is more a matter of cloud logging and monitoring strategy. From which sources you want to have an audit trail & events sent and to where? Where are you processing all the alerts, in SIEM or directly in Security solutions? And lastly, how operations are built around the solutions.

Until next time!

AAD Security made easy: Check your Azure AD Security with One-Liner (AZSK.AAD)

You can now scan your AAD tenant security posture with one-liner, and get really detailed and comprehensive report of the results

https://github.com/azsk/DevOpsKit-docs/blob/master/ReleaseNotes/LatestReleaseNotes.md

Install-Module AzSK.AAD -Scope CurrentUser -AllowClobber 
Import-Module AzSK.AAD 
Get-AzSKAADSecurityStatusTenant 
<#Controls available

The following controls are available from the get go!

ControlIDDescription
AAD_Tenant_RBAC_Grant_Limited_Access_To_GuestsGuests must not be granted full access to the directory
AAD_Tenant_RBAC_Dont_Permit_Guests_To_Invite_GuestsGuests must not be allowed to invite other guests
AAD_Tenant_MFA_Required_For_AdminsAdmins must use baseline MFA policy
AAD_Tenant_Apps_Dont_Allow_Users_To_Create_AppsDo not permit users to create apps in tenant
AAD_Tenant_RBAC_Dont_Allow_Users_To_Invite_GuestsDo not permit users to invite guests to the tenant
AAD_Tenant_Misc_Set_Security_Contact_InfoSecurity compliance notification phone and email must be set
AAD_Tenant_Device_Require_MFA_For_JoinEnable ’require MFA’ for joining devices to tenant
AAD_Tenant_Device_Set_Max_Per_User_LimitSet a max device limit for users in the tenant
AAD_Tenant_MFA_Review_Bypassed_UsersReview list of current ’MFA-bypassed’ users in the tenant
AAD_Tenant_MFA_Allow_Users_To_Notify_About_FraudAllow users to send notifications about possible fraud
AAD_Tenant_Apps_Regulate_Data_Access_ApprovalDo not allow users to approve tenant data access for external apps
AAD_Tenant_RBAC_Keep_Min_Global_AdminsInclude at least three members in global admin role
AAD_Tenant_RBAC_Dont_Have_Guests_As_Global_AdminsGuest users must not be made members of global admin role
AAD_Tenant_AuthN_Use_Custom_Banned_PasswordsEnsure that custom banned passwords list is configured for use
AAD_Tenant_AuthN_Enforce_Banned_Passwords_OnPremEnsure that banned password check is enabled on-prem and set to ’Enforce’ level
AAD_Tenant_Privacy_Configure_Valid_Privacy_ContactEnsure that tenant-wide privacy contact email is set to a valid (current) non-guest user
AAD_Tenant_Privacy_Configure_Valid_Privacy_StatementEnsure that a privacy statement is configured and points to a valid URL
AAD_Application_Remove_Test_Demo_AppsOld test/demo apps should be removed from the tenant
AAD_Application_ReturnURLs_Use_HTTPSAll return URLs configured for an application must be HTTPS endpoints
AAD_Application_Review_Orphaned_AppsDo not permit orphaned apps (i.e., apps with no owners) in the tenant
AAD_Application_Require_FTE_OwnerAt least one of the owners of an app must be an FTE
AAD_Application_HomePage_Use_HTTPSThe home page URL for an application must be an HTTPS endpoint
AAD_Application_LogoutURLs_Use_HTTPSThe logout URL configured for an application must be an HTTPS endpoint
AAD_Application_Must_Have_Privacy_DisclosureAll enterprise apps must use a privacy disclosure statement
AAD_Application_Must_Restrict_To_TenantEnterprise (line of business) apps should be tenant scope only
AAD_Application_Minimize_Resource_Access_RequestedApps should request the least permissions needed to various resources
AAD_ServicePrincipal_Use_Cert_CredentialsSPNs must not use password creds – use cert creds instead
AAD_ServicePrincipal_Review_Legacy_SPNSPNs of type legacy should be carefully reviewed
AAD_ServicePrincipal_Check_Key_ExpirySPN key credentials should be renewed before expiry
AAD_Device_Review_Stale_DevicesReview and remove stale devices from the directory
AAD_User_DirSync_Setting_Should_Match_TenantA user’s dirsync-enabled setting must match the tenant level setting
AAD_User_Do_Not_Disable_Password_ExpirationDo not disable password expiration policy for users
AAD_User_Do_Not_Disable_Strong_PasswordDo not disable strong password policy for users
AAD_Group_Use_Security_EnabledAll AAD groups must be security enabled (TBD)
AAD_Group_Require_FTE_OwnerGroup must have at least one non-guest (native) owner

Advisories 1-2: Azure AD and Common WS-Trust MFA Bypass explained

If there is single post I’ve been delaying for a good while, then it’s gotta be this one. This blog details a common oversight in MFA enforcement regarding federation implementations where MFA is invoked and required in the 3rd party IDP only. This oversight become effective when several by- design features, and implementation decisions align in ”wrong” way

Well how actionable it is? I’ve been exploiting this oversight in Red Teaming assignments, so in my experience its been really popular in deployments where the MFA is not checked on cloud side.

The reason of the delay is advisory 1. I’ve been discussing the ramifications with a major vendor providing Federation solutions about mitigating the configuration risks with WS-Trust when used in conjunction with Azure AD

Advisory 1 is related to how WS-Trust protocol is used in conjunction with Azure AD where clear text username and password are forwarded in TLS protected transport using the active endpoints to provide access for so-called non modern clients (Rich /Active endpoint consuming clients)

The scope is protocol implementation related, not vendor related! List of third 3rd party vendors providing WS-Federation/Trust support for Azure AD is long (some 15 last time I checked), so I am not highlighting any vendors here. I am assuming this affects most of the vendors implementing the WS-Trust with Azure AD without knowledge of the Azure AD OAuth2 Grant Types. Obviously I can’t say anything on any of the vendors behalf.

Microsoft’s AD FS can be also considered applicable in this context. Especially advisory 2

Advisory 2 is already documented, but not well communicated, and the existing documentation is AD FS specific. How is advisory 2 related to advisory 1? The existence of advisory 2 makes advisory 1 possible in the described scope.

Scope

Scope of this advisory are primarily customers who use WS /* -Protocols for federated domains in Azure AD, and utilize access policies to enforce and bypass MFA only in the IDP side. Not checking the status of MFA in Conditional Access, or using the -SupportsMFA option for the Microsoft MFA enabled users.

Its worth noting, that the attack can also pierce cloud MFA requirement if EAS clients can generate known bypass claims. There are unfortunately guides on web that advise doing this. In the latter scenario the attack penetrates two MFA layers, (Becomes even worse)

I won’t be providing any PoC’s, since all of the below advisories rely on by-design implementation, and can be replicated in few minutes, given you have understanding of both sides of the equation (Azure AD and WS-protocols)

Advisory 1 – Pivoting from legacy to modern auth

Background

UserName endpoints on WS-Trust are usually associated with legacy clients, thus they are often excluded from MFA. These endpoints are usually associated with legacy clients requesting access to Azure AD relying Party (Office 365 services often) – This is only true by association, as WS-Specification doesn’t define any difference between the so-called modern and legacy clients, the concept of difference only exists within Azure AD /Office 365 context, which the federation service is not aware of.

Accessing ”modern” API’s unprotected by the IDP

SAML assertion can extracted from the IDP, if the IDP is thinking it’s ActiveSync client. Once the token is received in response, it is then converted to OAuth2 Access Token with “saml1_1-bearer” OAuth2 Grant. This can be done by using many of the existing public clients.

Effectively the SAML token destined to legacy endpoint in Azure AD is converted to “Modern Auth” OAuth2 Access Token, and not being just used for legacy protocols anymore.

Root of this problem is related to the fact, that for SAML response from WS-Trust endpoint there is no ”validFor” context, which would dictate, that this request is valid for only let’s say https://graph.microsoft.com – not entire Azure AD Federation (Conditional Access solves this issue, as it binds access in cloud to different API’s)

In the picture: MFA is enabled for browser clients, and UserNameEndpoint is only allowed for ActiveSync clients without MFA /There lies the problem…

But wait, I have disabled legacy protocols in Office 365?

Disabling legacy protocols doesn’t help in this case, as the attacker is only consuming “modern API’s” (Microsoft OAuth2 parlance).

Attack in practice – On-prem MFA bypass

Example: The deployment only allows native ActiveSync to access WS-Trust’s Username bindings without MFA

What attacker does: Attacker uses ‘X-MS-Application’ header to spoof client to fetch SAML token using WS-Trust’s ’UserNameWSTrustBinding’.

The attacker then exchanges the SAML token in Azure AD to access the OAuth2 SPN (Audience). The exchange of the token is possible due to explicit support of “saml1_1-bearer” oAuth2 Grant Type, which cant be disabled on any of the ServicePrincipals in AzureAD

Documentation regarding the flow type

Link Microsoft identity platform and OAuth 2.0 SAML bearer assertion flow

Advisory 2 – Client Header Based Access Policies (Applies to WS-Federate as well)

This advisory is well documented, and is here only as reminder because it allows the first advisory to exist.

Don’t use user spoof-able headers as an basis for access policies at IDP’s controlling access to Azure AD.

Access Policies

Some vendors might implement additional checks here, but the protocol itself doesn’t dictate those to be done. This is basically where different products provide access policies to be enforced claims pipeline, to produce authorization result.

AD FS roles
https://docs.microsoft.com/en-us/windows-server/identity/ad-fs/technical-reference/the-role-of-the-claims-pipeline

Business policy claims?

Some of the claims presented in the following category should be only implemented to support business policies, not security policies, as advised in the Microsoft’s article

Client Spoof-able headers (Examples from AD FS)

Multiple claims exist which clients can modify, or set. Below are the most common ones. Read the article if you’re curious to see the list of claims in AD FS

  • X-MS-FORWARDED-CLIENT-IP
https://docs.microsoft.com/en-us/windows-server/identity/ad-fs/operations/access-control-policies-w2k12#x-ms-forwarded-client-ip
  • X-MS-CLIENT-APPLICATION
https://docs.microsoft.com/en-us/windows-server/identity/ad-fs/operations/access-control-policies-w2k12#x-ms-client-application
https://docs.microsoft.com/en-us/windows-server/identity/ad-fs/operations/access-control-policies-w2k12#scenario3

The documentation exist for AD FS 2012 R2, but it’s applicable to similar implementations including subsequent AD FS versions at least as up to 2016. Be sure to read the article as it lists very clear reasons,

Mitigations

  • a. Use Conditional Access to check whether MFA was actually performed at the 3rd party IDP for the requested API, or if there is valid reason to explicitly bypass the API
  • b. If you don’t have Conditional Access, don’t allow UserNameMixed to be used with spoof-able headers. Basically you wouldn’t allow native clients anymore for ActiveSync, as there isn’t safe header available for this decision to be made in the authorization pipeline

About spoof-able headers

  • X-MS-ADFS-Proxy-Client-IP seems to be based on the actual client IP with WAP, and should be more reliable, than the client writable header X-MS-FORWARDED-CLIENT-IP, which is advised to be used in many scenarios.
  • X-MS-FORWARDED-CLIENT-IP is often advised to be used in many guides because MS Exchange Online Connections pass multiple IP’s in headers, and thus the actual client IP hitting ADFS includes both Exchange and the Client IP’s in the header
    • as the documentation says, is best effort style header, and shouldn’t be used outside of business logic use scenarios
  • X-MS-CLIENT-APPLICATION here isn’t reliable way to inspect ActiveSync header for a legitimate client at the IDP’s side, The only way to allow it without MFA is Conditional Access

Also its worth noting that Basic Auth for Exchange, which is key reason why MFA bypasses on the WS-Trust endpoint are still used is going to be deprecated very soon