Last Update: Sep 04, 2024 | Published: Aug 02, 2018
Last month, I posted a description of an email extortion scam to my personal blog. The scammer used my Gmail address, possibly as a result a gigantic leak of millions of Linkedin.com. In any case, the scam failed with me, even though there’s evidence that it has successfully relieved others of thousands of dollars.
Inevitably, thoughts turned to Office 365. I don’t use Office 365 email addresses to sign into other services, so the only way that a hacker could recover an address/password combination would be to penetrate Azure Active Directory. So far, there’s no evidence that any such attempt has been successful.
But others use their Office 365 email addresses to sign into other services and those services might be penetrated. The question therefore arises how to check addresses used by Office 365 mailboxes against the Have I been Pwned service maintained by security researcher and MVP Troy Hunt.
Commercial products like Quadrotech Nova include reports for compromised accounts, but a post by Elliott Munro caught my eye because it used PowerShell to check Office 365 tenant accounts.
The beauty of PowerShell is that you can take code and “improve” it. Beauty is in the eye of the beholder, and a PowerShell improvement is in the eye of a coder. I asked Elliott if I could make some changes to his code. He had done all the heavy lifting and I just wanted to tweak it a tad.
Connect-MsolService [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 $headers = @{ "User-Agent" = "$((Get-MsolCompanyInformation).DisplayName) Account Check" "api-version" = 2 } $baseUri = "https://haveibeenpwned.com/api" # To check for admin status $RoleId = (Get-MsolRole -RoleName "Company Administrator").ObjectId $Admins = (Get-MsolRoleMember -RoleObjectId $RoleId | Select EmailAddress) $Report = @() $Breaches=0 Write-Host "Fetching mailboxes to check..." $Users = (Get-Mailbox -RecipientTypeDetails UserMailbox -ResultSize Unlimited | Select UserPrincipalName, EmailAddresses, DisplayName) Write-Host "Processing" $Users.count "mailboxes..." ForEach ($user in $users) { $Emails = $User.emailaddresses | Where-Object {$_ -match "smtp:" -and $_ -notmatch ".onmicrosoft.com"} $IsAdmin = $False $MFAUsed = $False $emails | ForEach-Object { $Email = ($_ -split ":")[1] $uriEncodeEmail = [uri]::EscapeDataString($Email) $uri = "$baseUri/breachedaccount/$uriEncodeEmail" $BreachResult = $null Try { [array]$breachResult = Invoke-RestMethod -Uri $uri -Headers $headers -ErrorAction SilentlyContinue } Catch { if($error[0].Exception.response.StatusCode -match "NotFound"){ Write-Host "No Breach detected for $email" }else{ Write-Host "Cannot retrieve results due to rate limiting or suspect IP. You may need to try a different computer" } } if ($BreachResult) { $MSOUser = Get-MsolUser -UserPrincipalName $User.UserPrincipalName If ($Admins -Match $User.UserPrincipalName) {$IsAdmin = $True} If ($MSOUser.StrongAuthenticationMethods -ne $Null) {$MFAUsed = $True} ForEach ($Breach in $BreachResult) { $ReportLine = [PSCustomObject][ordered]@{ Email = $email UserPrincipalName = $User.UserPrincipalName Name = $User.DisplayName LastPasswordChange = $MSOUser.LastPasswordChangeTimestamp BreachName = $breach.Name BreachTitle = $breach.Title BreachDate = $breach.BreachDate BreachAdded = $breach.AddedDate BreachDescription = $breach.Description BreachDataClasses = ($breach.dataclasses -join ", ") IsVerified = $breach.IsVerified IsFabricated = $breach.IsFabricated IsActive = $breach.IsActive IsRetired = $breach.IsRetired IsSpamList = $breach.IsSpamList IsTenantAdmin = $IsAdmin MFAUsed = $MFAUsed } $Report += $ReportLine Write-Host "Breach detected for $email - $($breach.name)" -ForegroundColor Red If ($IsAdmin -eq $True) {Write-Host "This is a tenant administrator account" -ForeGroundColor DarkRed} $Breaches++ Write-Host $breach.Description -ForegroundColor Yellow } } Start-sleep -Milliseconds 2000 } } If ($Breaches -gt 0) { $Report | Export-CSV c:tempBreaches.csv -NoTypeInformation Write-Host "Total breaches found: " $Breaches " You can find a report in c:tempBreaches.csv" } Else { Write-Host "Hurray - no breaches found for your Office 365 mailboxes" }
The code uses cmdlets in the Exchange Online and Microsoft Online Services modules to do the following.
You could improve the code further. For instance, it would be easy to add a check for the password age and flag accounts that haven’t changed their password in years.
When I ran the code, I only account in my tenant that was highlighted was my own. In this case, the problem was due to the 711 million record spambot incident from August 2017 (Figure 1).
After reading Troy Hunt’s analysis of spambot, I concluded that I didn’t have a problem. Someone included my email address in one of the sources that form the data; it’s only an email address and my account is protected by multi-factor authentication. I’ll leave Exchange Online Protection to deal with the spam sent to my address.
For the record, I should point out that Microsoft has a Flow template to check an email address against HIBP. Apart from the fact that the flow relies on an RSS feed to tell it about new breaches (which might not affect your tenant), I prefer PowerShell in this instance. PowerShell can process thousands of mailboxes, each of which might have several proxy addresses, and can deal with other checks like those for administrator status and multi-factor authentication enablement. But if Flow’s your thing, you can do it that way too.
The ongoing popularity of email makes it a continuing target for hackers and scammers. If it’s not Business Email Compromise attacks, it’ll be another attempt to make people do something they shouldn’t, like pay money after a threat. Given that Outlook.com is used by many scammers, I asked Microsoft if they could do something to make their consumer email platform a little less friendly to attackers. According to Greg Taylor, Director of Marketing for Exchange, Microsoft is aware of the new threats and is looking into how to suppress them. It would be good if Microsoft can do something to repel scammers, but given that the years-old Nigerian 419 fraud (you know, send me your details and I’ll send you $10 million I have in this account) continues to flourish, it’s a challenge to find a mechanism to stop scams while allowing legitimate business email to flow.
Going back to the point of this article, scripts like Elliott’s help the community by showing administrators how they can use publicly-available sources to check whether their tenants are compromised. It also underlines the value of PowerShell in filling gaps that Microsoft can’t ever hope to close in a suite like Office 365.
Follow Tony on Twitter @12Knocksinna.
Want to know more about how to manage Office 365? Find what you need to know in “Office 365 for IT Pros”, the most comprehensive eBook covering all aspects of Office 365. Available in PDF and EPUB formats (suitable for iBooks) or for Amazon Kindle.