Skip to content

Commit

Permalink
Version 2.1.0
Browse files Browse the repository at this point in the history
Get-MessageIDs:
Added try/catch to handle errors when attempting to download emails that have already been deleted from the mailbox.

Get-UAL Scripts:
Fixed JSON output format to ensure correct and consistent JSON formatting.

AzureADGraphLogs:
Merged pull request from @Matthijsy, adding additional details to the acquisition output for audit and sign-in logs.

Graph Sign-in Endpoint Update:
Changed to using the beta endpoint for sign-in logs, increasing the number of fields per event from 107 to 299, providing more useful data for analysis.

New Features & Enhancements:
Added -mergeoutput flag to Get-UALSpecificActivity, as suggested by @SecurityAura.
Added a warning when using the -Download flag in Get-MessageIDs without an active Graph connection, also as suggested by @SecurityAura.
  • Loading branch information
JoeyInvictus committed Oct 2, 2024
1 parent e20638d commit 64edefb
Show file tree
Hide file tree
Showing 8 changed files with 86 additions and 26 deletions.
2 changes: 1 addition & 1 deletion Microsoft-Extractor-Suite.psd1
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Author = 'Joey Rentenaar & Korstiaan Stam'
CompanyName = 'Invictus-IR'

# Version number of this module.
ModuleVersion = '2.0.3'
ModuleVersion = '2.1.0'

# ID used to uniquely identify this module
GUID = '4376306b-0078-4b4d-b565-e22804e3be01'
Expand Down
14 changes: 11 additions & 3 deletions Microsoft-Extractor-Suite.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,10 @@ function Get-GraphAuthType {
$joinedScopes = $RequiredScopes -join ","
switch ($authType) {
"delegated" {
if ($missingScopes.Count -gt 0) {
if ($RequiredScopes -contains "Mail.ReadWrite") {
Write-LogFile -Message "[WARNING] 'Mail.ReadWrite' is being requested under a delegated authentication type. 'Mail.ReadWrite' permissions only work when authenticating with an application." -Color "Yellow"
}
elseif ($missingScopes.Count -gt 0) {
foreach ($missingScope in $missingScopes) {
Write-LogFile -Message "[INFO] Missing Graph scope detected: $missingScope" -Color "Yellow"
}
Expand All @@ -145,8 +148,13 @@ function Get-GraphAuthType {
}
}
"none" {
Write-LogFile -Message "[INFO] No active Connect-MgGraph session found. Attempting to connect with the appropriate scope(s): $joinedScopes" -Color "Green"
Connect-MgGraph -NoWelcome -Scopes $joinedScopes
if ($RequiredScopes -contains "Mail.ReadWrite") {
Write-LogFile -Message "[WARNING] 'Mail.ReadWrite' is being requested under a delegated authentication type. 'Mail.ReadWrite' permissions only work when authenticating with an application." -Color "Yellow"
}
else {
Write-LogFile -Message "[INFO] No active Connect-MgGraph session found. Attempting to connect with the appropriate scope(s): $joinedScopes" -Color "Green"
Connect-MgGraph -NoWelcome -Scopes $joinedScopes
}
}
}

Expand Down
4 changes: 2 additions & 2 deletions Scripts/Get-AzureADGraphLogs.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ function Get-ADSignInLogsGraph {
}

$encodedFilterQuery = [System.Web.HttpUtility]::UrlEncode($filterQuery)
$apiUrl = "https://graph.microsoft.com/v1.0/auditLogs/signIns?`$filter=$encodedFilterQuery"
$apiUrl = "https://graph.microsoft.com/beta/auditLogs/signIns?`$filter=$encodedFilterQuery"

try {
Do {
Expand Down Expand Up @@ -232,7 +232,7 @@ function Get-ADAuditLogsGraph {
$fromstr = $from.ToString('yyyy-MM-ddTHH:mmZ')
$to = ($dates | Select-Object -Last 1).ToString('yyyy-MM-ddTHH:mmZ')
$count = ($responseJson.value | measure).Count
Write-Host "[INFO] Audit logs written to $filePath ($count records between $fromstr and $to)" -ForegroundColor Green
Write-Host "[INFO] Audit logs written to $filePath ($count records between $fromstr and $to)" -ForegroundColor Green

$progress = [Math]::Round(($script:EndDate-$from).Ticks / $TotalTicks * 100, 2)
Write-Progress -Activity "Collecting Audit logs" -Status "$progress% Complete" -PercentComplete $progress
Expand Down
22 changes: 17 additions & 5 deletions Scripts/Get-MailItemsAccessed.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,11 @@ function Get-MessageIDs {
Write-logFile -Message "[INFO] Running Get-MessageIDs" -Color "Green"

$results=@();

if ($Download.IsPresent) {
$requiredScopes = @("Mail.ReadWrite")
$graphAuth = Get-GraphAuthType -RequiredScopes $requiredScopes
}

if (!$Sessions -And !$IP){

Expand Down Expand Up @@ -670,15 +675,23 @@ function DownloadMails($iMessageID,$UserIds){
$ReceivedDateTime = $getMessage.ReceivedDateTime.ToString("yyyyMMdd_HHmmss")
} else {
$ReceivedDateTime = "unabletogetdate" # Fallback to custom string
write-logFile -Message "[WARNING] ReceivedDateTime is not a valid DateTime object, using 'unabletogetdate'" -Color "Yellow"
#write-logFile -Message "[WARNING] ReceivedDateTime is not a valid DateTime object, using 'unabletogetdate'" -Color "Yellow"
}

$subject = $getMessage.Subject
$subject = $subject -replace '[\\/:*?"<>|]', '_'
$filePath = "$outputDir\$ReceivedDateTime-$subject.elm"

Get-MgUserMessageContent -MessageId $messageId -UserId $userId -OutFile $filePath
Write-logFile -Message "[INFO] Output written to $filePath" -Color "Green"
try {
Get-MgUserMessageContent -MessageId $messageId -UserId $userId -OutFile $filePath
Write-logFile -Message "[INFO] Output written to $filePath" -Color "Green"
} catch {
if ($_.Exception.Message -like "*Cannot bind argument to parameter 'MessageId' because it is an empty string*") {
Write-logFile -Message "[WARNING] Unable to download message with ID '$iMessageID' was likely deleted." -Color "Red"
} else {
throw
}
}

if ($attachment -eq "True"){
Write-logFile -Message "[INFO] Found Attachment file!"
Expand All @@ -700,8 +713,7 @@ function DownloadMails($iMessageID,$UserIds){
}
}
catch {
write-logFile -Message "[INFO] Ensure you are connected to Microsoft Graph by running the Connect-MgGraph -Scopes Mail.ReadBasic.All command before executing this script" -Color "Yellow"
Write-logFile -Message "[WARNING] The 'Mail.ReadBasic.All' is an application-level permission, requiring an application-based connection through the 'Connect-MgGraph' command for its use." -Color "Red"
Write-logFile -Message "[WARNING] The 'Mail.ReadWrite' is an application-level permission, requiring an application-based connection through the 'Connect-MgGraph' command for its use." -Color "Red"
Write-Host "[WARNING] Error Message: $($_.Exception.Message)"
throw
}
Expand Down
61 changes: 49 additions & 12 deletions Scripts/Get-UAL.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -201,12 +201,18 @@ function Get-UALAll
if ($currentTotal -eq $results[$results.Count - 1].ResultIndex) {
$message = "[INFO] Successfully retrieved $($currentCount) records out of total $($currentTotal) for the current time range. Moving on!"

if ($Output -eq "JSON") {
$results = $results | Select-Object AuditData -ExpandProperty AuditData
$results | Out-File -Append "$OutputDir/UAL-$sessionID.json" -Encoding $Encoding
Write-LogFile -Message $message -Color "Green"
}
if ($Output -eq "JSON")
{
$results = $results | ForEach-Object {
$_.AuditData = $_.AuditData | ConvertFrom-Json
$_
}

$json = $results | ConvertTo-Json -Depth 100
$json | Out-File -Append "$OutputDir/UAL-$sessionID.json" -Encoding $Encoding
Add-Content "$OutputDir/UAL-$sessionID.json" "`n"
Write-LogFile -Message $message
}
elseif ($Output -eq "CSV") {
$results | export-CSV "$OutputDir/UAL-$sessionID.csv" -NoTypeInformation -Append -Encoding $Encoding
Write-LogFile -Message $message -Color "Green"
Expand Down Expand Up @@ -466,8 +472,14 @@ function Get-UALGroup

if ($Output -eq "JSON")
{
$results = $results|Select-Object AuditData -ExpandProperty AuditData
$results | Out-File -Append "$OutputDir/UAL-$sessionID.json" -Encoding $Encoding
$results = $results | ForEach-Object {
$_.AuditData = $_.AuditData | ConvertFrom-Json
$_
}

$json = $results | ConvertTo-Json -Depth 100
$json | Out-File -Append "$OutputDir/UAL-$sessionID.json" -Encoding $Encoding
Add-Content "$OutputDir/UAL-$sessionID.json" "`n"
Write-LogFile -Message $message
}
elseif ($Output -eq "CSV")
Expand Down Expand Up @@ -715,8 +727,14 @@ function Get-UALSpecific

if ($Output -eq "JSON")
{
$results = $results|Select-Object AuditData -ExpandProperty AuditData
$results | Out-File -Append "$OutputDir/UAL-$sessionID.json" -Encoding $Encoding
$results = $results | ForEach-Object {
$_.AuditData = $_.AuditData | ConvertFrom-Json
$_
}

$json = $results | ConvertTo-Json -Depth 100
$json | Out-File -Append "$OutputDir/UAL-$sessionID.json" -Encoding $Encoding
Add-Content "$OutputDir/UAL-$sessionID.json" "`n"
Write-LogFile -Message $message
}
elseif ($Output -eq "CSV")
Expand Down Expand Up @@ -783,6 +801,9 @@ function Get-UALSpecificActivity
OutputDir is the parameter specifying the output directory.
Default: Output\UnifiedAuditLog
.PARAMETER MergeOutput
MergeOutput is the parameter specifying if you wish to merge CSV/JSON outputs into a single file at the end of the acquisition.
.PARAMETER Encoding
Encoding is the parameter specifying the encoding of the CSV/JSON output file.
Default: UTF8
Expand Down Expand Up @@ -816,7 +837,8 @@ function Get-UALSpecificActivity
[Parameter(Mandatory=$true)]$ActivityType,
[string]$Output = "CSV",
[string]$OutputDir,
[string]$Encoding = "UTF8"
[string]$Encoding = "UTF8",
[switch]$MergeOutput
)

try {
Expand Down Expand Up @@ -942,8 +964,14 @@ function Get-UALSpecificActivity

if ($Output -eq "JSON")
{
$results = $results | Select-Object AuditData -ExpandProperty AuditData
$results | Out-File -Append "$OutputDir/UAL-$sessionID.json" -Encoding $Encoding
$results = $results | ForEach-Object {
$_.AuditData = $_.AuditData | ConvertFrom-Json
$_
}

$json = $results | ConvertTo-Json -Depth 100
$json | Out-File -Append "$OutputDir/UAL-$sessionID.json" -Encoding $Encoding
Add-Content "$OutputDir/UAL-$sessionID.json" "`n"
Write-LogFile -Message $message
}
elseif ($Output -eq "CSV")
Expand All @@ -963,5 +991,14 @@ function Get-UALSpecificActivity
Write-LogFile -Message "[INFO] No Records found for $record"
}
}
if ($Output -eq "CSV" -and ($MergeOutput.IsPresent)) {
Write-LogFile -Message "[INFO] Merging output files into one file"
Merge-OutputFiles -OutputDir $OutputDir -OutputType "CSV" -MergedFileName "UAL-Combined.csv"
}
elseif ($Output -eq "JSON" -and ($MergeOutput.IsPresent)) {
Write-LogFile -Message "[INFO] Merging output files into one file"
Merge-OutputFiles -OutputDir $OutputDir -OutputType "JSON" -MergedFileName "UAL-Combined.json"
}

Write-LogFile -Message "[INFO] Acquisition complete, check the Output directory for your files.." -Color "Green"
}
4 changes: 2 additions & 2 deletions docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
copyright = 'Copyright 2024 Invictus Incident Response'
author = 'Joey Rentenaar & Korstiaan Stam'

release = '2.0.3'
version = '2.0.3'
release = '2.1.0'
version = '2.1.0'

# -- General configuration

Expand Down
2 changes: 1 addition & 1 deletion docs/source/functionality/AzureAuditLogsGraph.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Use **Get-ADAuditLogsGraph** to collect the contents of the Azure Active Directo

Usage
""""""""""""""""""""""""""
Running the script without any parameters will gather the Azure Active Directory Audit Log for the last 90 days:
Running the script without any parameters will gather the Azure Active Directory Audit Log for the last 30 days:
::

Get-ADAuditLogsGraph
Expand Down
3 changes: 3 additions & 0 deletions docs/source/functionality/UnifiedAuditLog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -666,6 +666,9 @@ Parameters
- EndDate is the parameter specifying the end date of the date range.
- Default: Now

-MergeOutput (optional)
- MergeOutput is the parameter specifying if you wish to merge CSV outputs to a single file.

-Interval (optional)
- Interval is the parameter specifying the interval in which the logs are being gathered.
- Default: 60 minutes
Expand Down

0 comments on commit 64edefb

Please sign in to comment.