Created
February 4, 2020 09:14
-
-
Save glides/5f866268906f7176a8a8955ef9709cfc to your computer and use it in GitHub Desktop.
Find all out of country logins Office 365 Unified Audit Log
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
########## Connect to o365 ########## | |
## Change $username and $pass to match your environment | |
## See: https://blogs.technet.microsoft.com/robcost/2008/05/01/powershell-tip-storing-and-using-password-credentials/ for how to create a cred file. | |
$username = "[email protected]" | |
$pass = gc "F:\PSScripts\Office365-PowershellCreds.txt" | convertto-securestring | |
$creds = New-Object -typename System.Management.Automation.PSCredential ` | |
-argumentlist $username, $pass | |
$MESession = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://outlook.office365.com/powershell-liveid/ -Credential $Creds -Authentication Basic -AllowRedirection | |
Import-PSSession $MESession -AllowClobber | |
Connect-MsolService -Credential $creds | |
######################################## | |
########## Setup global vars ########## | |
[Array]$TotalLogins = @() | |
[Array]$OutsideIPs = @() | |
$StartDate = Get-Date (Get-Date).AddHours(-1.25) -Format g # The UAL (Unified Audit Log) is in UTC time, keep that in mind | |
$EndDate = Get-Date (Get-Date).AddHours(-1) -Format g # The UAL (Unified Audit Log) is in UTC time, keep that in mind | |
$DateStamp = Get-date -Format yyyy-MM-dd_HH-mm-ss | |
$OutputFile = "<PATH>\$DateStamp-BadLogins.csv" | |
## E-mail notifications, logging | |
$SMTPserver = "smtpout.local" | |
$SMTPNotifySender = "[email protected]" | |
[Array]$SMTPNotifyRecipients = @('[email protected]','[email protected]','[email protected]') | |
######################################## | |
## Function - Get-IPGeolocation | Takes an IP as an argument and returns geographic data for the IP | |
function Get-IPGeolocation | |
{ | |
Param | |
( | |
[string]$IPAddress | |
) | |
$request = Invoke-RestMethod -Method Get -Uri "http://geoip.nekudo.com/api/$IPAddress" | |
[PSCustomObject]@{ | |
IP = $request.IP | |
City = $request.City | |
Country = $request.Country.Name | |
Code = $request.Country.Code | |
Location = $request.Location.Latitude | |
Longitude = $request.Location.Longitude | |
TimeZone = $request.Location.Time_zone | |
} | |
} | |
# Provide feedback if ran from the console | |
Write-Host -ForegroundColor Yellow $(Get-Date -format 'G') "Gathering login information from the Unified Audit Log." | |
## This loop gathers all logins between the StartDate and EndDate then extracts the json data so we can find the IP | |
## We use -SessionCommand ReturnLargeSet because there is a 5,000 result limit on ReturnNextPreviewPage and 50,000 on ReturnLargeSet but we must use a SessionId and continue to check the results until they are null | |
Do { | |
$Logins = Search-UnifiedAuditLog -SessionId $DateStamp -SessionCommand ReturnLargeSet -StartDate $StartDate -EndDate $EndDate -Operations "MailboxLogin","UserLoggedIn","PasswordLogonInitialAuthUsingPassword" | Select-Object -ExpandProperty AuditData | ConvertFrom-Json | |
$TotalLogins += $Logins | |
} | |
until ($Logins -eq $null) # One this is true, we've found all the logins for the given time period...time to move on | |
#Remove duplicates (using ReturnLargeSet above can contain dupes) and select the fields we are interested in | |
$Data = $TotalLogins | sort CreationTime, UserId -Unique | Select-Object CreationTime, UserId, Operation, ResultStatus, ClientIPAddress, ClientIP, ClientInfoString | |
# Provide feedback if ran from the console | |
write-host -ForegroundColor Green $(Get-Date -format 'G') $Data.Count "logins to check for between" $StartDate "and" $EndDate | |
write-host -ForegroundColor Yellow $(Get-Date -format 'G') "Checking for IPs outside of the US." | |
## This loop checks the IPs against a web API @ geoip.nekudo.com to get geographic information about the IP | |
## The two IF statements contain -notlike conditions to remove known good IP subnets so they are not checked, this speeds up the script | |
## The reason there are two IF statements is because MailboxLogin,UserLoggedIn, PasswordLogonInitialAuthUsingPassword don't store the IP in the same variable. ClientIPAddress is used in some and just Client.IP in the others | |
#!#!#!#!#!#!# | |
# You will need to modify or remove the "-notlike" conditions to match your environment | |
#!#!#!#!#!#!# | |
foreach ($ip in $Data) { | |
if ($ip.ClientIPAddress -And $ip.ClientIPAddress -notlike "###.###.*" -And $ip.ClientIPAddress -notlike "###.###.###.*"){ | |
$geoInfo = Get-IPGeolocation $ip.ClientIPAddress | |
if ($geoInfo.Code -notlike "US") { | |
$ip | Add-Member -MemberType NoteProperty -Name Country -Value $geoInfo.Country | |
$ip | Add-Member -MemberType NoteProperty -Name IP -Value $geoInfo.IP | |
$OutsideIps += $ip | |
Write-Host -ForegroundColor Red $(Get-Date -format 'G') "Outside of US:" $geoInfo.IP | |
} | |
} | |
if ($ip.ClientIPAddress -And $ip.ClientIPAddress -notlike "###.###.*" -And $ip.ClientIPAddress -notlike "###.###.###.*"){ | |
$geoInfo = Get-IPGeolocation $ip.ClientIP | |
if ($geoInfo.Code -notlike "US") { | |
$ip | Add-Member -MemberType NoteProperty -Name Country -Value $geoInfo.Country | |
$ip | Add-Member -MemberType NoteProperty -Name IP -Value $geoInfo.IP | |
$OutsideIps += $ip | |
Write-Host -ForegroundColor Red $(Get-Date -format 'G') "Outside of US:" $geoInfo.IP | |
} | |
} | |
} | |
# Provide feedback if ran from the console | |
write-host -ForegroundColor Yellow $(Get-Date -format 'G') $OutsideIPs.Count "out of" $Data.Count "where found to be outside of the US." | |
# Write data to output file (specified in Global Vars) | |
$OutsideIps | sort CreationTime, UserId -Unique |select CreationTime, UserId, Operation, ResultStatus, IP, Country, ClientInfoString | Export-Csv $OutputFile -NoTypeInformation | |
# If there are any logins found outside of the US, send an email to the specified users (Email server and recipients configured in global vars) | |
if ($OutsideIPs.count -gt 0) { | |
Send-MailMessage -To $SMTPNotifyRecipients -Priority High -Subject "Report: Bad Logins | IP Audit" -Body "Report is attached. Questionable logins were found.`r`n`r`n[\\ADFSPV02\F$\PSScripts\INDYAD-IPAudit.cmd]" -SmtpServer $SMTPServer -From $SmtpNotifySender -Attachments $OutputFile | |
} | |
#TODO | |
#API is out of date now, needs updated | |
#Check the time between the last known good login and the Outside of Country one to see if it's possible to travel that quickly. If not, that's a known bad login. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment